Modul:CargoUtil: Unterschied zwischen den Versionen

CamNet - das Wiki
Keine Bearbeitungszusammenfassung
imported>Oetterer
Keine Bearbeitungszusammenfassung
Zeile 3: Zeile 3:
local classDebug = require('Module:Debug/class')
local classDebug = require('Module:Debug/class')
local _TT = require('Module:TableTools')
local _TT = require('Module:TableTools')
local cargo
if mw.ext and mw.ext.cargo then
cargo = mw.ext.cargo
else
cargo = {}
end


local cfg = {
function prepareQueryParam(query)
fieldSeparator = '###~~~@@@~~~###',
classDebug:log(21, 'entering CargoUtil.prepareQueryParam', 'CargoUtil')
helperTemplate = 'CargoUtilQueryParserHelper',
if query.tables and #query.tables > 0 and query.fields and #query.fields > 0 then
resultSeparator = '#####~~~****~~~#####',
if type(query.tables) == 'table' then
}
query.tables = table.concat(query.tables, ', ')
end
if not query.joins then
query.joins = query.join
end
if query.joins and type(query.joins) == 'table' then
query.joins = table.concat(query.joins, ', ')
end
if type(query.fields) == 'table' then
query.fields = table.concat(query.fields, ', ')
end
if query.where and type(query.where) == 'table' then
if query.where[1] then -- sequence assumed
query.where = table.concat(query.where, ' AND ')
else
local where = ''
for k, v in pairs(query.where) do
where = where .. k .. '=' .. v .. ' AND '
end
query.where = where .. '1 '
end
end
if query.group and type(query.group) == 'table' then
query.group = table.concat(query.group, ', ')
end
if query.having and type(query.having) == 'table' then
if query.having[1] then -- sequence assumed
query.having = table.concat(query.having, ', ')
else
local having = ''
for k, v in pairs(query.having) do
having = having .. k .. '=' .. v .. ', '
end
query.having = mw.ustring.sub(having, 1, -3)
end
end
if query.order and type(query.order) == 'table' then
query.order = table.concat(query.order, ', ')
end
return query
else
if tables and #tables > 0 then
error('Argument query.tables is missing or empty! (calling from ' .. tostring(self) .. ')', 2)
else
error('Argument query.fields is missing or empty! (calling from ' .. tostring(self) .. ')', 2)
end
return nil
end
end
 
function p.attach(dbtable)
classDebug:log(21, 'entering CargoUtil.attach', 'CargoUtil.attach')
classDebug:log(22, ' with table "' .. dbtable .. '"')
local frame = mw.getCurrentFrame()
local ret = false
ret = frame:callParserFunction('#cargo_attach:_table=' .. dbtable)
return ret
end


function p.declare(dbtable, dbfields)
function p.declare(dbtable, dbfields)
Zeile 35: Zeile 98:
attributes = {attributes}
attributes = {attributes}
end
end
-- now try to ascertain the headline
-- CargoUtil.query() allows for query.paramters (like table, where, etc) to be tables. cargo.query only takes strings. remedy this here
local tmpfields = query.fields
local query = prepareQueryParam(query)
local headlines = {}
local args = {
if type(tmpfields) ~= 'table' then
where = query.where,
tmpfields = mw.text.split(tmpfields, ',')
join = query.joins,
end
groupBy = query.group,
for num, hl in pairs(tmpfields) do
having = query.having,
if mw.ustring.find(hl, '=', 1, true) then
orderBy = query.order,
hl = mw.ustring.match(hl, '^.+=(.+)$')
limit = attributes.limit
end
}
headlines[num] = hl
local result = cargo.query(query.tables, query.fields, args)
end
 
classDebug:log(23, ' having headlines: ' .. _TT.printTable(headlines))
local ret = {}
attributes.default = ''
for num, row in pairs(result) do
attributes.intro = nil
local newRow = {}
attributes.format = 'template'
for key, value in pairs(row) do
attributes['more results text'] = ''
if mw.ustring.len(mw.text.trim(value)) > 0 or retainBlanks then
attributes.outro = nil
newRow[key] = value
attributes.template = cfg.helperTemplate
-- cargo interprets underscored (_) as spaces in fieldnames (keys). so copy the entry
local ret = nil
if mw.ustring.find(key, ' ') then
local result = mw.text.trim(p.rawquery(query, attributes))
local newKey = mw.ustring.gsub(key, ' ', '_')
if result and mw.ustring.len(result) > 0 then
if not newRow[newKey] then
classDebug:log(24, ' result is: ' .. result)
newRow[newKey] = newRow[key]
ret = {}
for row in mw.text.gsplit(result, cfg.resultSeparator, true) do
if mw.ustring.len(row) > 0 then
local sequence = {}
local array = {}
local num = 1
for v in mw.text.gsplit(row, cfg.fieldSeparator, true) do
if mw.ustring.match(v, '^[0-9]+$') then
v = tonumber(v)
else
v = mw.text.decode(mw.text.decode(v))
-- we have to decode twice. first for the encoding happening through format=template encapsulation and second because of queryParserHelper's nowiki
end
table.insert(sequence, v)
if headlines[num] then
array[headlines[num]] = v
else
array[num] = v
end
num = num + 1
end
-- for k, v in pairs(sequence) do
-- array[k] = v
-- end
if  _TT.size(array) > 0 then
if not retainBlanks then
-- now delete all entries with an empty value
for k, v in pairs(array) do
if mw.ustring.len(tostring(v)) == 0 then
array[k] = nil
end
end
end
end
table.insert(ret, array)
end
end
end
end
end
end
ret[num] = newRow
end
end
return ret
return ret
end
function p.queryParserHelper(frame)
local args = getArgs(frame, { trim = false, removeBlanks = false })
local ret = ''
for _, val in pairs(args) do
ret = ret .. mw.text.nowiki(val) .. cfg.fieldSeparator
-- we need the nowiki, otherwise some the result could produce some unwanted parser results (mw's parser for instance would apply a hrefs to external links)
end
return mw.ustring.sub(ret, 1, -1 - mw.ustring.len(cfg.fieldSeparator)) .. cfg.resultSeparator
end
end


Zeile 113: Zeile 135:
classDebug:log(23, ' with query: ' .. (query and _TT.printTable(query) or 'NONE'), 'CargoUtil.rawquery')
classDebug:log(23, ' with query: ' .. (query and _TT.printTable(query) or 'NONE'), 'CargoUtil.rawquery')
classDebug:log(23, ' with attributes: ' .. (attributes and _TT.printTable(attributes) or 'NONE'), 'CargoUtil.rawquery')
classDebug:log(23, ' with attributes: ' .. (attributes and _TT.printTable(attributes) or 'NONE'), 'CargoUtil.rawquery')
local query = prepareQueryParam(query)
local frame = mw.getCurrentFrame()
local tables = query.tables
local tables = query.tables
local joins = query.joins or query.join
local arguments = attributes or {}
local fields = query.fields
arguments.fields = query.fields
local where = query.where
arguments['join on'] = query.joins
local group = query.group
arguments.where = query.where
local having = query.having
arguments['group by'] = query.group
local order = query.order
arguments.having = query.having
if tables and #tables > 0 and fields and #fields > 0 then
arguments['order by'] = query.order
local frame = mw.getCurrentFrame()
classDebug:log(24, ' calling parser function with tables: ' .. tables .. ' and arguments: ' .. _TT.printTable(arguments))
if type(tables) == 'table' then
return frame:callParserFunction{ name='#cargo_query:tables=' .. tables, args = arguments }
tables = table.concat(tables, ',')
end
local arguments = attributes or {}
if joins and #joins > 0 then
if type(joins) == 'table' then
arguments['join on'] = table.concat(joins, ',')
else
arguments['join on'] = joins
end
end
if type(fields) == 'table' then
arguments.fields = table.concat(fields, ',')
else
arguments.fields = fields
end
if where and (type(where) == 'table' or mw.ustring.len(where) > 0) then
if type(where) == 'table' then
if where[1] then -- sequence assumed
arguments.where = table.concat(where, ',')
else
arguments.where = ''
for k, v in pairs(where) do
arguments.where = arguments.where .. k .. '=' .. v .. ','
end
arguments.where = mw.ustring.sub(arguments.where, 1, -2)
end
else
arguments.where = where
end
end
if group and #group > 0 then
if type(group) == 'table' then
arguments['group by'] = table.concat(group, ',')
else
arguments['group by'] = group
end
end
if having and (type(having) == 'table' or mw.ustring.len(having) > 0) then
if type(having) == 'table' then
if having[1] then -- sequence assumed
arguments.having = table.concat(having, ',')
else
arguments.having = ''
for k, v in pairs(having) do
arguments.having = arguments.having .. k .. '=' .. v .. ','
end
arguments.having = mw.ustring.sub(arguments.having, 1, -2)
end
else
arguments.having = having
end
end
if order and #order > 0 then
if type(order) == 'table' then
arguments['order by'] = table.concat(order, ',')
else
arguments['order by'] = order
end
end
classDebug:log(24, ' calling parser function with tables: ' .. tables .. ' and arguments: ' .. _TT.printTable(arguments))
return frame:callParserFunction{ name='#cargo_query:tables=' .. tables, args = arguments }
else
if tables and #tables > 0 then
error('Argument query.tables is missing or empty! (calling from ' .. tostring(self) .. ')', 2)
else
error('Argument query.fields is missing or empty! (calling from ' .. tostring(self) .. ')', 2)
end
return nil
end
return nil
end
end



Version vom 11. März 2022, 10:48 Uhr

Documentation icon Module documentation

This module provides serveral useful function that can be used in other module to store or retrive data operating a cargo store.

Usage

local _CARGO = require('Module:CargoUtil')
if dataStore == 'cargo' and mw.title.getCurrentTitle().namespace == 10 then
	-- create table declaration, then call
	_CARGO.declare('tablename', declaration)
end
if stash then
	_CARGO.store('tablename', stash)
end
local query = {
	tables = {'table1'}
	fields = {'_pageName', '_ID', 'field1'}
	where = {'field1="hello world"', '_ID > 1'}
	order = {'_ID ASC', '_pageName DESC'}
}
local attributes = {
	limit = 1
}
local result = _CARGO.query(query, attributes)

Functions

Provided functions are as follow:

declare(dbtable, declaration)

Calls #cargo_declare with the provided parameter. Note that this parser function must be called (and therefore placed) on the template page, that later fills the table via store(dbtable, stash). See Usage-example above. Please refer to the Cargo documentation page fore more information about declaration options.

dbtable
string, mandatory
takes the name of the database table that should be declared
declaration
table or string, mandatory
holds the declaration. if provided a table, it must be formatted {fieldName : 'declaration' }
return
string, return values of the declaration call

query(query, attributes, retainBlanks)

Runs a query on the cargo store according to the parameters provided and returns the result as a lua-table. The first parameter (query) has the following mandatory fields:

tables
table or string, mandatory
the name(s) of the table(s) to query data from
fields
table or string, mandatory
the fields, you want to get data from. format is fieldname or fieldname=headline. In case of more than one table, please use tablename.fieldname or tablealias.fieldname
joins
table or string, mandatory if you have more than one table. you need one join statement for each table after the first
the list of join statements

Also, there are several optional fields:

where
table or string, optional
you can filter the results with where clauses
group
table or string, optional
the group statements
having
table or string, optional
filter your query, similar to WHERE, but applies to values computed for "groups"
order
table or string, optional
the fields, you wish to sort the result for. please use tablename.fieldname or tablealias.fieldname

Please keep in mind:

  • attributes may contain any attribute you find in the documentation, but intro and outro will be NILed, default and more results text will be set to the empty string, and format will be overwritten
  • per default, does only return fields that contain a value. that can result in an "unbalanced" result, where one row contains more elements than others. if you want to get all fields, set retainBlanks to true
query
table, mandatory
the arguments to construct the query. see above for details
attributes
table, optional
more attributes, you want to pass on to the query (like limit, for instance)
retainBlanks
boolean, optional
if set to true, result can contain entries with empty values. per default, these entries will be deleted
return
table, see the following printout as example

The result has the following format: <-- cut 1: 1 = 'Extension:Cargo' 2 = '7' 3 = '901' 4 = 'Cargo provides a lightweight way to store and query the data contained within the calls to templates, such as infoboxes in mysql tables.' 2: 1 = 'Extension:SyntaxHighlight GeSHi' 2 = '6' 3 = '911' 4 = 'The SyntaxHighlight GeSHi extension provides rich formatting of source code using the "syntaxhighlight"-tag. ...' -->

{
	1 = {
		id = '7'
		pageid = '901'
		description = 'Cargo provides a lightweight way to store and query the data contained within the calls to templates, such as infoboxes in mysql tables.'
		page = 'Extension:Cargo'
	}
	2 = {
		id = '6'
		pageid = '911'
		description = 'The SyntaxHighlight GeSHi extension provides rich formatting of source code using the "syntaxhighlight"-tag. ...'
		page = 'Extension:SyntaxHighlight GeSHi'
	}
}

As you can see, the data fields can be indexed either by number or by the provided headline in table fields. (The headline is either the fieldname or a special string you provided via fieldname=headline.

rawquery(query, attributes)

Calls the parser function #cargo_query according to the provided parameters and passes the result on directly. The format of the output is depending on attributes.format. The first parameter (query) has the following mandatory fields:

tables
table or string, mandatory
the name(s) of the table(s) to query data from
fields
table or string, mandatory
the fields, you want to get data from. format is fieldname or fieldname=headline. In case of more than one table, please use tablename.fieldname or tablealias.fieldname
joins
table or string, mandatory if you have more than one table. you need one join statement for each table after the first
the list of join statements

Also, there are several optional fields:

where
table or string, optional
you can filter the results with where clauses
group
table or string, optional
the group statements
having
table or string, optional
filter your query, similar to WHERE, but applies to values computed for "groups"
order
table or string, optional
the fields, you wish to sort the result for. please use tablename.fieldname or tablealias.fieldname

Please keep in mind:

  • attributes may contain any attribute you find in the documentation, but intro and outro will be NILed, default and more results text will be set to the empty string, and format will be overwritten
  • per default, does only return fields that contain a value. that can result in an "unbalanced" result, where one row contains more elements than others. if you want to get all fields, set retainBlanks to true
query
table, mandatory
the arguments to construct the query. see above for details
attributes
table, optional
more attributes, you want to pass on to the query (like limit, for instance)
return
string, the renderd output

store(dbtable, stash)

Calls #cargo_store with the provided parameters. Note that the table must be declared and created before you can actually store anything.

dbtable
string, mandatory
takes the name of the database table to be filled
stash
table (!), mandatory
holds the data to store. it must be formatted {fieldName : data of type string or integer }
return
string, return values of the store call

local p = {}
local getArgs = require('Module:Arguments').getArgs
local classDebug = require('Module:Debug/class')
local _TT = require('Module:TableTools')
local cargo
if mw.ext and mw.ext.cargo then
	cargo = mw.ext.cargo
else
	cargo = {}
end

function prepareQueryParam(query)
	classDebug:log(21, 'entering CargoUtil.prepareQueryParam', 'CargoUtil')
	if query.tables and #query.tables > 0 and query.fields and #query.fields > 0 then
		if type(query.tables) == 'table' then
			query.tables = table.concat(query.tables, ', ')
		end
		if not query.joins then
			query.joins = query.join
		end
		if query.joins and type(query.joins) == 'table' then
			query.joins = table.concat(query.joins, ', ')
		end
		if type(query.fields) == 'table' then
			query.fields = table.concat(query.fields, ', ')
		end
		if query.where and type(query.where) == 'table' then
			if query.where[1] then	-- sequence assumed
				query.where = table.concat(query.where, ' AND ')
			else
				local where = ''
				for k, v in pairs(query.where) do
					where = where .. k .. '=' .. v .. ' AND '
				end
				query.where = where .. '1 '
			end
		end
		if query.group and type(query.group) == 'table' then
			query.group = table.concat(query.group, ', ')
		end
		if query.having and type(query.having) == 'table' then
			if query.having[1] then	-- sequence assumed
					query.having = table.concat(query.having, ', ')
			else
				local having = ''
				for k, v in pairs(query.having) do
					having = having .. k .. '=' .. v .. ', '
				end
				query.having = mw.ustring.sub(having, 1, -3)
			end
		end
		if query.order and type(query.order) == 'table' then
			query.order = table.concat(query.order, ', ')
		end
		return query
	else
		if tables and #tables > 0 then
			error('Argument query.tables is missing or empty! (calling from ' .. tostring(self) .. ')', 2)
		else
			error('Argument query.fields is missing or empty! (calling from ' .. tostring(self) .. ')', 2)
		end
		return nil
	end	
end

function p.attach(dbtable)
	classDebug:log(21, 'entering CargoUtil.attach', 'CargoUtil.attach')
	classDebug:log(22, ' with table "' .. dbtable .. '"')
	local frame = mw.getCurrentFrame()
	local ret = false
	ret = frame:callParserFunction('#cargo_attach:_table=' .. dbtable)
	return ret
end

function p.declare(dbtable, dbfields)
	classDebug:log(21, 'entering CargoUtil.declare', 'CargoUtil.declare')
	classDebug:log(22, ' with table "' .. dbtable .. '" and fields ' ..
		(type(dbfields) == "string" and '"' .. dbfields .. '"' or 'of type ' .. type(dbfields)), 'CargoUtil.declare')
	if type(dbfields) == "table" then
		classDebug:log(23, ' datatable: ' .. _TT.printTable(dbfields), 'CargoUtil.declare')
	end
	local frame = mw.getCurrentFrame()
	local ret = false
	if type(dbfields) == "string" then
		ret = frame:callParserFunction('#cargo_declare:_table=' .. dbtable, dbfields)
	elseif type(dbfields) == "table" then
		ret = frame:callParserFunction{name = '#cargo_declare:_table=' .. dbtable, args = dbfields}
	end
	return ret
end

function p.query(query, attributes, retainBlanks)
	classDebug:log(21, 'entering CargoUtil.query', 'CargoUtil.query')
	classDebug:log(23, ' with query: ' .. (query and _TT.printTable(query) or 'NONE'), 'CargoUtil.query')
	classDebug:log(23, ' with attributes: ' .. (attributes and _TT.printTable(attributes) or 'NONE'), 'CargoUtil.query')
	local attributes = attributes or {}
	if type(attributes) ~= 'table' then
		attributes = {attributes}
	end
	-- CargoUtil.query() allows for query.paramters (like table, where, etc) to be tables. cargo.query only takes strings. remedy this here
	local query = prepareQueryParam(query)
	local args = {
		where = query.where,
		join = query.joins,
		groupBy = query.group,
		having = query.having,
		orderBy = query.order,
		limit = attributes.limit
	}
	local result = cargo.query(query.tables, query.fields, args)

	local ret = {}
	for num, row in pairs(result) do
		local newRow = {}
		for key, value in pairs(row) do
			if mw.ustring.len(mw.text.trim(value)) > 0 or retainBlanks then
				newRow[key] = value
				-- cargo interprets underscored (_) as spaces in fieldnames (keys). so copy the entry
				if mw.ustring.find(key, ' ') then
					local newKey = mw.ustring.gsub(key, ' ', '_')
					if not newRow[newKey] then
						newRow[newKey] = newRow[key]
					end
				end
			end
		end
		ret[num] = newRow
	end

	return ret
end

function p.rawquery(query, attributes)
	classDebug:log(21, 'entering CargoUtil.rawquery', 'CargoUtil.rawquery')
	classDebug:log(23, ' with query: ' .. (query and _TT.printTable(query) or 'NONE'), 'CargoUtil.rawquery')
	classDebug:log(23, ' with attributes: ' .. (attributes and _TT.printTable(attributes) or 'NONE'), 'CargoUtil.rawquery')
	local query = prepareQueryParam(query)
	local frame = mw.getCurrentFrame()
	local tables = query.tables
	local arguments = attributes or {}
	arguments.fields = query.fields
	arguments['join on'] = query.joins
	arguments.where = query.where
	arguments['group by'] = query.group
	arguments.having = query.having
	arguments['order by'] = query.order
	classDebug:log(24, ' calling parser function with tables: ' .. tables .. ' and arguments: ' .. _TT.printTable(arguments))
	return frame:callParserFunction{ name='#cargo_query:tables=' .. tables, args = arguments }
end

function p.store(dbtable, data)
	classDebug:log(21, 'entering CargoUtil.store')
	classDebug:log(22, ' with table "' .. dbtable .. '" and data ' ..
		(type(data) == "string" and '"' .. data .. '"' or 'of type ' .. type(data)))
	if type(data) == "table" then
		classDebug:log(23, ' datatable: ' .. _TT.printTable(data))
	end
	local ret = false
	if type(data) == "table" then
		for k, v in pairs(data) do
			if type(v) == 'boolean' then
				data[k] = v and 1 or 0
			end
		end
		local frame = mw.getCurrentFrame()
		ret = frame:callParserFunction{name = '#cargo_store:_table=' .. dbtable, args = data}
	end
	return ret
end

return p