Module:CargoQuery: Difference between revisions

From Caves of Qud Wiki
Jump to navigation Jump to search
(update to most recent version in leaguepedia (one to many support))
No edit summary
 
(53 intermediate revisions by 2 users not shown)
Line 12: Line 12:
local args = h.merge()
local args = h.merge()
local intro = frame:preprocess(args.intro or '')
local outro = frame:preprocess(args.outro or '')
local template = frame:preprocess(args.template or 'single query result')
local delimiter = args.delimiter or ''
local colcount = args.columns or nil
local format = args.format or nil
result = p.query(args)
if (result == args.default or result == '') then
return result
end
local tbl = {}
if format == "table" then
return (intro .. tostring(h.makeTable(result)) .. outro)
else
for i, row in ipairs(result) do
row.index = i
tbl[#tbl+1] = frame:expandTemplate{ title = template, args = row }
end
if colcount ~= nil then
intro = (intro .. '<div style="-webkit-column-count:' ..
    colcount .. '; -moz-column-count:' ..
colcount .. '; column-count:' .. colcount .. ';">')
outro = '</div>' ..outro
end
if format == "ul" then
intro = intro .. "<ul><li>"
outro = "</ul>" .. outro
delimiter = "<li>"
end
return intro .. table.concat(tbl, delimiter) .. outro
end
end
function p.query(args)
local frame = mw.getCurrentFrame()
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)
local key = string.sub(k, 3)
query[PARAM_LOOKUP[key] or key] = v
query[PARAM_LOOKUP[key] or key] = v
elseif PARAM_LOOKUP[k] then
elseif PARAM_LOOKUP[k] then
query[PARAM_LOOKUP[k]] = v
query[PARAM_LOOKUP[k]] = v
Line 36: Line 73:
h.concatOneToManyFieldsInEachRow(result, args.one_to_many_sep or ',')
h.concatOneToManyFieldsInEachRow(result, args.one_to_many_sep or ',')
end
end
local tbl = {}
return result
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
end


-- This function on Leaguepedia is part of Module:ArgsUtil but is copied here to avoid dependencies
-- This function on Leaguepedia is part of Module:ArgsUtil but is copied here to avoid dependencies
function h.merge()
function h.merge(mergeParent)
    mergeParent = mergeParent or true
local f = mw.getCurrentFrame()
local f = mw.getCurrentFrame()
local origArgs = f.args
local origArgs = f.args
local parentArgs = f:getParent().args


local args = {}
local args = {}
if mergeParent then
local parentArgs = f:getParent().args
    for k, v in pairs(parentArgs) do
v = mw.text.trim(tostring(v))
if v ~= '' then
args[k] = v
end
    end
end
for k, v in pairs(origArgs) do
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)
v = mw.text.trim(v)
if v ~= '' then
if v ~= '' then
Line 141: Line 171:
end
end
end
end
end
function p.compound(frame)
local util_args = require('Module:Args Utility')
local util_table = require('Module:Table Utility')
local args = h.merge(false)
template = frame:preprocess(args['template'] or '')
if template == nil or template == '' then
    template='single query result'
end
delimiter = frame:preprocess(args['delimiter'] or '')
metasep = frame:preprocess(args['metaseparator'] or ';')
local splitargs = {}
for a, b in ipairs(args) do
    splitargs[a] = util_args.splitNamedArgs(frame:preprocess(b), '%s*' .. metasep .. '%s*')
end
splitargs['default'] = ''
local result = {}
for a, b in ipairs(splitargs) do
    tempresult = p.query(b)
    if tempresult ~= nil and tempresult ~= '' then
        result[#result+1] = tempresult
    end
end
if result == args.default or result == '' then
return result
end
resulttbl = util_table.mergeArrays(nil, unpack(result))
local tbl = {}
for i, row in ipairs(resulttbl) do
row.index = i
tbl[#tbl+1] = frame:expandTemplate{title = args['template'], args = row}
end
        if #tbl == 0 then
          return frame:preprocess(args['default'] or 'no results')
        end
local intro = frame:preprocess(args['intro'] or '')
local outro = frame:preprocess(args['outro'] or '')
return intro  .. table.concat(tbl, delimiter) .. outro
end
function h.getColNames(row)
cols = {}
for colname, _ in pairs(row)do
table.insert(cols, colname)
end
return cols
end
function h.makeTable(result)
local util_html = require'Module:HTML Utility'
    local tbl = mw.html.create('table')
        :addClass('wikitable')
    colNames = h.getColNames(result[1])
    util_html.printHeader(tbl, colNames)
    util_html.printRowsByList(tbl, result, colNames)
    return tbl
end
end


return p
return p

Latest revision as of 01:03, 4 February 2024

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 specifying metaseparator 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 intro = frame:preprocess(args.intro or '')
	local outro = frame:preprocess(args.outro or '')
	local template = frame:preprocess(args.template or 'single query result')
	local delimiter = args.delimiter or ''
	
	local colcount = args.columns or nil
	local format = args.format or nil
	
	result = p.query(args)
	if (result == args.default or result == '') then
		return result
	end
	local tbl = {}
	if format == "table" then
		return (intro .. tostring(h.makeTable(result)) .. outro)
	else
		for i, row in ipairs(result) do
			row.index = i
			tbl[#tbl+1] = frame:expandTemplate{ title = template, args = row }
		end
		if colcount ~= nil then
			intro = (intro .. '<div style="-webkit-column-count:' .. 
			     colcount .. '; -moz-column-count:' .. 
				 colcount .. '; column-count:' .. colcount .. ';">')
			outro = '</div>' ..outro
		end
		if format == "ul" then
			intro = intro .. "<ul><li>"
			outro = "</ul>" .. outro
			delimiter = "<li>"
		end
		return intro .. table.concat(tbl, delimiter) .. outro
	end
end

function p.query(args)
	local frame = mw.getCurrentFrame()
	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
	return result
end

-- This function on Leaguepedia is part of Module:ArgsUtil but is copied here to avoid dependencies
function h.merge(mergeParent)
    mergeParent = mergeParent or true
	local f = mw.getCurrentFrame()
	local origArgs = f.args

	local args = {}
	if mergeParent then
		local parentArgs = f:getParent().args
	    for k, v in pairs(parentArgs) do
			v = mw.text.trim(tostring(v))
			if v ~= '' then
				args[k] = v
			end
	    end
	end
	for k, v in pairs(origArgs) 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

function p.compound(frame)
	local util_args = require('Module:Args Utility')
	local util_table = require('Module:Table Utility')

	local args = h.merge(false)

	template = frame:preprocess(args['template'] or '')
	if template == nil or template == '' then
    		template='single query result'
	end
	delimiter = frame:preprocess(args['delimiter'] or '')
	metasep = frame:preprocess(args['metaseparator'] or ';')

	local splitargs = {}
	for a, b in ipairs(args) do
    		splitargs[a] = util_args.splitNamedArgs(frame:preprocess(b), '%s*' .. metasep .. '%s*')
	end
	
	splitargs['default'] = ''

	local result = {}
	for a, b in ipairs(splitargs) do
    		tempresult = p.query(b)
    		if tempresult ~= nil and tempresult ~= '' then
        		result[#result+1] = tempresult
    		end
	end
	if result == args.default or result == '' then
		return result
	end
	
	resulttbl = util_table.mergeArrays(nil, unpack(result))
	local tbl = {}
	for i, row in ipairs(resulttbl) do
		row.index = i
		tbl[#tbl+1] = frame:expandTemplate{title = args['template'], args = row}
	end
        if #tbl == 0 then
           return frame:preprocess(args['default'] or 'no results')
        end
	local intro = frame:preprocess(args['intro'] or '')
	local outro = frame:preprocess(args['outro'] or '')
	return intro  .. table.concat(tbl, delimiter) .. outro
end

function h.getColNames(row)
	cols = {}
	for colname, _ in pairs(row)do
		table.insert(cols, colname)
	end
	return cols
end

function h.makeTable(result)
	local util_html = require'Module:HTML Utility'
    local tbl = mw.html.create('table')
        :addClass('wikitable')
    colNames = h.getColNames(result[1])
    util_html.printHeader(tbl, colNames)
    util_html.printRowsByList(tbl, result, colNames)
    return tbl
end

return p