Module:CargoQuery: Difference between revisions
(Created page with "local p = {} function p.main(frame) local args = frame if frame == mw.getCurrentFrame() then args = require('Module:ProcessArgs').merge(true) else frame = mw.getCurrent...") |
(update to most recent version in leaguepedia (one to many support)) |
||
Line 1: | Line 1: | ||
local PARAM_LOOKUP = { | |||
['order by'] = 'orderBy', | |||
['join on'] = 'join', | |||
['group by'] = 'groupBy', | |||
table = 'tables', | |||
} | |||
local h = {} | |||
local p = {} | local p = {} | ||
function p.main(frame) | function p.main(frame) | ||
local args = | local args = h.merge() | ||
local query = {} | local query = {} | ||
for k, v in pairs(args) do | for k, v in pairs(args) do | ||
if string.sub(k, 0, 2) == 'q?' then | if string.sub(k, 0, 2) == 'q?' then | ||
local key = string.sub(k, 3) | |||
query[PARAM_LOOKUP[key] or key] = v | |||
elseif PARAM_LOOKUP[k] then | |||
query[PARAM_LOOKUP[k]] = v | |||
else | |||
query[k] = v | |||
end | end | ||
end | |||
if args.one_to_many then | |||
query.fields = query.fields .. ',' .. query.one_to_many | |||
end | end | ||
local result = mw.ext.cargo.query(query.tables, query.fields, query) | local result = mw.ext.cargo.query(query.tables, query.fields, query) | ||
if | if #result == 0 then | ||
return frame:preprocess(args.default or '') | return frame:preprocess(args.default or '') | ||
end | |||
if args.one_to_many then | |||
result = h.groupOneToManyFields(result, h.getOneToManyTableFromArgs(args)) | |||
h.concatOneToManyFieldsInEachRow(result, args.one_to_many_sep or ',') | |||
end | end | ||
local tbl = {} | local tbl = {} | ||
for | for i, row in ipairs(result) do | ||
row.index = i | |||
tbl[#tbl+1] = frame:expandTemplate{ title = args.template, args = row } | tbl[#tbl+1] = frame:expandTemplate{ title = args.template, args = row } | ||
end | end | ||
Line 28: | Line 46: | ||
end | end | ||
-- This function on Leaguepedia is part of Module:ArgsUtil but is copied here to avoid dependencies | |||
function h.merge() | |||
local f = mw.getCurrentFrame() | |||
local origArgs = f.args | |||
local parentArgs = f:getParent().args | |||
local args = {} | |||
for k, v in pairs(origArgs) do | |||
v = mw.text.trim(tostring(v)) | |||
if v ~= '' then | |||
args[k] = v | |||
end | |||
end | |||
for k, v in pairs(parentArgs) do | |||
v = mw.text.trim(v) | |||
if v ~= '' then | |||
args[k] = v | |||
end | |||
end | |||
return args | |||
end | |||
function h.getOneToManyTableFromArgs(args) | |||
local oneToMany = { | |||
fields = mw.text.split(args.one_to_many, '%s*,%s*'), | |||
groupBy = { args.one_to_many_group }, | |||
} | |||
return oneToMany | |||
end | |||
-- These functions on Leaguepedia are part of Module:CargoUtil but are copied here to avoide dependencies | |||
-- Some code is updated to avoid further dependencies | |||
function h.groupOneToManyFields(result, oneToMany) | |||
if not oneToMany then return result end | |||
local currentKey | |||
local groupedResult = {} | |||
local fields = h.parseFieldsForKeys(oneToMany.fields) | |||
for _, row in ipairs(result) do | |||
local newKey = h.getNewKey(row, oneToMany.groupBy) | |||
if newKey == currentKey then | |||
h.addRowToExistingGroup(groupedResult, row, fields) | |||
else | |||
h.addRowToNewGroup(groupedResult, row, fields) | |||
currentKey = newKey | |||
end | |||
end | |||
return groupedResult | |||
end | |||
function h.parseFieldsForKeys(fields) | |||
for i, v in ipairs(fields) do | |||
fields[i] = h.parseOneFieldForKey(v) | |||
end | |||
return fields | |||
end | |||
function h.getNewKey(row, groupBy) | |||
local toConcat = {} | |||
for _, v in ipairs(groupBy) do | |||
toConcat[#toConcat+1] = row[v] | |||
end | |||
return table.concat(toConcat) | |||
end | |||
function h.parseOneFieldForKey(str) | |||
if not str:find('=') then return str end | |||
return str:match('=(.+)') | |||
end | |||
function h.addRowToExistingGroup(groupedResult, row, fields) | |||
for _, v in ipairs(fields) do | |||
local parentRowValues = groupedResult[#groupedResult][v] | |||
parentRowValues[#parentRowValues+1] = row[v] | |||
end | |||
end | |||
function h.addRowToNewGroup(groupedResult, row, fields) | |||
for _, v in ipairs(fields) do | |||
row[v] = { row[v] } | |||
end | |||
groupedResult[#groupedResult+1] = row | |||
end | |||
function h.concatOneToManyFieldsInEachRow(result, sep) | |||
for _, row in ipairs(result) do | |||
for k, v in pairs(row) do | |||
if type(v) == 'table' then | |||
row[k] = table.concat(v, sep) | |||
end | |||
end | |||
end | |||
end | |||
return p | return p |
Revision as of 22:47, 6 March 2020
This module is taken from Leaguepedia's CargoQuery module.
This module lets you get around the |no html
bug that Cargo has by avoiding |format=template. This module implicitly assumed you ARE using named args in your template (corresponding to |named_args=yes
; you do not need to specify this.)
Unlike |format=template
, this wrapper will NOT rename parameters with underscores in them to use spaces instead.
Parameters
- You may specify all parameters the same as if they were parameters in
#cargo_query
.
One-To-Many
This template allows for one-to-many support, allowing you to specify a field to treat equivalently to a List of ...
field. Syntax is as follows:
|one_to_many=
, a list of fields you want concatenated together.|one_to_many_group=
, the thing you want our one-to-many values grouped by. UNLIKE the|group by=
parameter, this should be the FINAL name of a field, so something on the RIGHT SIDE of the equals sign in your|fields=
parameter.|one_to_many_sep=
, defaults to comma. Currently you must pick the same separator for all of your one-to-many fields.
Example
{{#invoke:CargoQuery|main |table=Teams,ListplayerCurrent=LPC |join on=Teams._pageName=LPC._pageName |where=Teams.Region="North America" AND LPC._pageName IS NOT NULL |fields=Teams._pageName=Page |one_to_many=LPC.ID=IDs |one_to_many_group=Page |one_to_many_sep=, |template=<template> |intro={{(!}} class="wikitable" |outro={{!)}} |limit=10 }}
Here, the one_to_many
is a list of players on the team in question. For each ONE team, there are MANY players, so the field IDs
that's sent to the template is a comma-separated list of players, grouped by team page.
Compound Queries
You can also run compound queries using compound
. It has the same syntax as #cargo_compound_query
but with a few exceptions:
default
for each individual query is disabled; default must be specified outside as an additional argument, which is then applied if no queries return results.- Each query must be numbered as in
|1=(query1)|2=(query2)|3=...
, etc. - Because of how compound query uses
;
as a separator, strings with this character cannot be used. This can be worked around by specifyingmetaseparator
to be another symbol, and splitting each query's arguments using that delimiter instead.
Example
{{#invoke:CargoQuery|compound |1=table=Food=F ;fields=F._pageName=Page ;where=F.CookEffect HOLDS 'heat and fire-based' AND F._pageNamespace = '0' |2=table=Liquids=L ;fields=L._pageName=Page ;where=L.CookEffect HOLDS 'simple heat and fire-based' AND L._pageNamespace = '0' |default=No Results! |template=favilink page |delimiter = <br> |metaseparator = ; }}
local PARAM_LOOKUP = {
['order by'] = 'orderBy',
['join on'] = 'join',
['group by'] = 'groupBy',
table = 'tables',
}
local h = {}
local p = {}
function p.main(frame)
local args = h.merge()
local query = {}
for k, v in pairs(args) do
if string.sub(k, 0, 2) == 'q?' then
local key = string.sub(k, 3)
query[PARAM_LOOKUP[key] or key] = v
elseif PARAM_LOOKUP[k] then
query[PARAM_LOOKUP[k]] = v
else
query[k] = v
end
end
if args.one_to_many then
query.fields = query.fields .. ',' .. query.one_to_many
end
local result = mw.ext.cargo.query(query.tables, query.fields, query)
if #result == 0 then
return frame:preprocess(args.default or '')
end
if args.one_to_many then
result = h.groupOneToManyFields(result, h.getOneToManyTableFromArgs(args))
h.concatOneToManyFieldsInEachRow(result, args.one_to_many_sep or ',')
end
local tbl = {}
for i, row in ipairs(result) do
row.index = i
tbl[#tbl+1] = frame:expandTemplate{ title = args.template, args = row }
end
local intro = frame:preprocess(args.intro or '')
local outro = frame:preprocess(args.outro or '')
return intro .. table.concat(tbl,args.delimiter or '') .. outro
end
-- This function on Leaguepedia is part of Module:ArgsUtil but is copied here to avoid dependencies
function h.merge()
local f = mw.getCurrentFrame()
local origArgs = f.args
local parentArgs = f:getParent().args
local args = {}
for k, v in pairs(origArgs) do
v = mw.text.trim(tostring(v))
if v ~= '' then
args[k] = v
end
end
for k, v in pairs(parentArgs) do
v = mw.text.trim(v)
if v ~= '' then
args[k] = v
end
end
return args
end
function h.getOneToManyTableFromArgs(args)
local oneToMany = {
fields = mw.text.split(args.one_to_many, '%s*,%s*'),
groupBy = { args.one_to_many_group },
}
return oneToMany
end
-- These functions on Leaguepedia are part of Module:CargoUtil but are copied here to avoide dependencies
-- Some code is updated to avoid further dependencies
function h.groupOneToManyFields(result, oneToMany)
if not oneToMany then return result end
local currentKey
local groupedResult = {}
local fields = h.parseFieldsForKeys(oneToMany.fields)
for _, row in ipairs(result) do
local newKey = h.getNewKey(row, oneToMany.groupBy)
if newKey == currentKey then
h.addRowToExistingGroup(groupedResult, row, fields)
else
h.addRowToNewGroup(groupedResult, row, fields)
currentKey = newKey
end
end
return groupedResult
end
function h.parseFieldsForKeys(fields)
for i, v in ipairs(fields) do
fields[i] = h.parseOneFieldForKey(v)
end
return fields
end
function h.getNewKey(row, groupBy)
local toConcat = {}
for _, v in ipairs(groupBy) do
toConcat[#toConcat+1] = row[v]
end
return table.concat(toConcat)
end
function h.parseOneFieldForKey(str)
if not str:find('=') then return str end
return str:match('=(.+)')
end
function h.addRowToExistingGroup(groupedResult, row, fields)
for _, v in ipairs(fields) do
local parentRowValues = groupedResult[#groupedResult][v]
parentRowValues[#parentRowValues+1] = row[v]
end
end
function h.addRowToNewGroup(groupedResult, row, fields)
for _, v in ipairs(fields) do
row[v] = { row[v] }
end
groupedResult[#groupedResult+1] = row
end
function h.concatOneToManyFieldsInEachRow(result, sep)
for _, row in ipairs(result) do
for k, v in pairs(row) do
if type(v) == 'table' then
row[k] = table.concat(v, sep)
end
end
end
end
return p