Нет описания правки |
Нет описания правки |
||
Строка 148: | Строка 148: | ||
search_param = 'item_name_exact' |
search_param = 'item_name_exact' |
||
else |
else |
||
+ | --[[ |
||
+ | Cargo's implementation of HOLDS breaks when there is a properly |
||
+ | escaped quotation mark at the end of a string literal. |
||
+ | |||
+ | Example of a WHERE clause that results in an error: |
||
+ | items.name_list HOLDS "\"O\' Eternal\"" |
||
+ | |||
+ | Instead, we avoid using HOLDS by explicitly joining the child table |
||
+ | and then comparing using a native operator. |
||
+ | --]] |
||
+ | tables[#tables+1] = 'items__name_list' |
||
+ | query.join = query.join .. ', items._ID = items__name_list._rowID' |
||
query.where = query.where .. string.format( |
query.where = query.where .. string.format( |
||
− | ' AND |
+ | ' AND items__name_list._value = "%s"', |
m_cargo.addslashes(args.item_name) |
m_cargo.addslashes(args.item_name) |
||
) |
) |
Версия от 10:21, 23 января 2022
Это мета-модуль, который предназначен для использования только другими модулями. Он не должен вызываться в викитексте. |
Этот модуль зависит от следующих других модулей: |
Этот мета-модуль предоставляет служебные функции для модулей, которые имеют дело с предметами.
Использование
Этот модуль должен быть загружен с помощью require()
.
Вышеприведенная документация извлекается из Модуль:Item util/doc.
Редакторы могут экспериментировать в sandbox этого модуля и в testcases страницах.
Подстраницы этого модуля.
Редакторы могут экспериментировать в sandbox этого модуля и в testcases страницах.
Подстраницы этого модуля.
-------------------------------------------------------------------------------
--
-- Module:Item util
--
-- This meta module contains utility functions for modules that deal with items
-------------------------------------------------------------------------------
local m_util = require('Module:Util')
local m_cargo -- Lazy load require('Module:Cargo')
-- Should we use the sandbox version of our submodules?
local use_sandbox = m_util.misc.maybe_sandbox('Item util')
-- The cfg table contains all localisable strings and configuration, to make it
-- easier to port this module to another wiki.
local cfg = use_sandbox and mw.loadData('Module:Item util/config/sandbox') or mw.loadData('Module:Item util/config')
local i18n = cfg.i18n
-- ----------------------------------------------------------------------------
-- Exported functions
-- ----------------------------------------------------------------------------
local m = {}
function m.format_value(tpl_args, value, options)
-- value: table
-- min:
-- max:
-- options: table
-- func: Function to transform the value retrieved from the database
-- fmt: Format string (or function that returns format string) to use for the value. Default: '%s'
-- fmt_range: Format string to use for the value range. Default: '(%s-%s)'
-- color: poe_color code to use for the value range. False for no color. Default: 'mod'
-- class: Additional css class added to color tag
-- inline: Format string to use for the output
-- inline_color: poe_color code to use for the output. False for no color. Default: 'default'
-- inline_class: Additional css class added to inline color tag
-- no_color: (Deprecated; use color=false instead)
-- return_color: (Deprecated; returns both value.out and value without this)
if options.color ~= false and options.no_color == nil then
local base = {
min = value.base_min or value.base,
max = value.base_max or value.base,
}
if options.color then
value.color = options.color
elseif value.min ~= base.min or value.max ~= base.max then
value.color = 'mod'
else
value.color = 'value'
end
end
if options.func then
value.min = options.func(tpl_args, value.min)
value.max = options.func(tpl_args, value.max)
end
options.fmt = options.fmt or '%s'
if type(options.fmt) == 'function' then -- Function that returns the format string
options.fmt = options.fmt(tpl_args, value)
end
if value.min == value.max then -- Static value
value.out = string.format(options.fmt, value.min)
else -- Range value
options.fmt_range = options.fmt_range or i18n.range
value.out = string.format(
string.format(options.fmt_range, options.fmt, options.fmt),
value.min,
value.max
)
end
if value.color then
value.out = m_util.html.poe_color(value.color, value.out, options.class)
end
if type(options.inline) == 'function' then
options.inline = options.inline(tpl_args, value)
end
if options.inline and options.inline ~= '' then
value.out = string.format(options.inline, value.out)
if options.inline_color ~= false then
options.inline_color = options.inline_color or 'default'
value.out = m_util.html.poe_color(options.inline_color, value.out, options.inline_class)
end
end
local return_color = options.return_color and value.color or nil
if return_color then
return value.out, return_color
end
return value.out, value
end
function m.get_item_namespaces(args)
-- Returns item namespaces from config as a table or as a comma-separated string
args.format = args.format or 'table'
if args.format == 'list' then
return cfg.item_namespaces_list
end
return cfg.item_namespaces
end
function m.query_item(args, qargs)
qargs = qargs or {}
m_cargo = m_cargo or require('Module:Cargo')
if not m_util.table.has_any_key(args, cfg.search_terms) then
error(i18n.errors.missing_search_term)
end
local tables = {'items'}
local fields = {
'items._pageName=_pageName',
'items.drop_enabled=drop_enabled',
'items.class_id=class_id',
}
local query = {
groupBy = 'items._pageID',
orderBy = 'items.drop_enabled DESC',
}
local search_param
local results
if args.metadata_id then
query.where = string.format(
'items.metadata_id = "%s"',
args.metadata_id
)
search_param = 'metadata_id'
elseif args.page then
-- Join with _pageData in order to check for page redirect
tables[#tables+1] = '_pageData'
query.join = 'items._pageName = _pageData._pageNameOrRedirect'
query.where = string.format(
'_pageData._pageName = "%s"',
m_cargo.addslashes(args.page)
)
search_param = 'page'
else
tables[#tables+1] = 'maps'
tables[#tables+1] = 'map_series'
query.join = 'items._pageID = maps._pageID, maps.series = map_series.name'
query.where = string.format(
'items._pageNamespace IN (%s)',
m.get_item_namespaces{format = 'list'}
)
query.orderBy = 'map_series.ordinal DESC, ' .. query.orderBy
if args.item_name_exact then
query.where = query.where .. string.format(
' AND items.name = "%s"',
m_cargo.addslashes(args.item_name_exact)
)
search_param = 'item_name_exact'
else
--[[
Cargo's implementation of HOLDS breaks when there is a properly
escaped quotation mark at the end of a string literal.
Example of a WHERE clause that results in an error:
items.name_list HOLDS "\"O\' Eternal\""
Instead, we avoid using HOLDS by explicitly joining the child table
and then comparing using a native operator.
--]]
tables[#tables+1] = 'items__name_list'
query.join = query.join .. ', items._ID = items__name_list._rowID'
query.where = query.where .. string.format(
' AND items__name_list._value = "%s"',
m_cargo.addslashes(args.item_name)
)
search_param = 'item_name'
end
end
-- Append additional tables and fields
if type(qargs.tables) == 'table' and #qargs.tables > 0 then
tables = m_util.table.merge(tables, qargs.tables)
end
if type(qargs.fields) == 'table' and #qargs.fields > 0 then
fields = m_util.table.merge(fields, qargs.fields)
end
-- Append to join, where and orderBy clauses
if qargs.join then
query.join = table.concat({query.join, qargs.join}, ', ')
end
if qargs.where then
query.where = table.concat({query.where, qargs.where}, ' AND ')
end
if qargs.orderBy then
query.orderBy = table.concat({qargs.orderBy, query.orderBy}, ', ')
end
results = m_cargo.query(tables, fields, query)
local err
if #results == 0 then
-- No results found
err = m_util.misc.raise_error_or_return{
raise_required = true,
args = args,
msg = string.format(
i18n.errors.no_results_found,
search_param,
args[search_param]
)
}
elseif #results > 1 then
-- More than one result found
--
-- If results are all maps, use the one from the most recent map
-- series, regardless of whether it's drop enabled. Otherwise,
-- if only one of the results is drop enabled then use that one.
local map_count = 0
local drop_enabled_count = 0
for i, v in ipairs(results) do
if v.class_id == 'Map' then
map_count = map_count + 1
end
if m_util.cast.boolean(v.drop_enabled) then
drop_enabled_count = drop_enabled_count + 1
end
end
if (map_count == 0 or map_count ~= #results) and drop_enabled_count ~= 1 then
err = m_util.misc.raise_error_or_return{
raise_required = true,
args = args,
msg = string.format(
i18n.errors.many_results_found,
search_param,
args[search_param]
)
}
end
end
if args.debug then
mw.logObject(results)
end
if err ~= nil then
if not m_util.cast.boolean(args.nocat) then
err = err .. m_util.misc.add_category({args.error_category or i18n.categories.failed_query})
end
return {error = err}
end
return results[1] -- orderBy ensures that the first result is the one we want
end
return m