Modul:CargoUtil: Unterschied zwischen den Versionen
Keine Bearbeitungszusammenfassung |
Noémi (Diskussion | Beiträge) Keine Bearbeitungszusammenfassung |
||
| Zeile 204: | Zeile 204: | ||
local ret = false | local ret = false | ||
if type(data) == "table" then | 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() | local frame = mw.getCurrentFrame() | ||
ret = frame:callParserFunction{name = '#cargo_store:_table=' .. dbtable, args = data} | ret = frame:callParserFunction{name = '#cargo_store:_table=' .. dbtable, args = data} | ||
Version vom 13. Februar 2016, 23:36 Uhr
| This module is subject to page protection. It is a highly visible module in use by a very large number of pages, or is substituted very frequently. Because vandalism or mistakes would affect many pages, and even trivial editing might cause substantial load on the servers, it is protected from editing. |
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.
| Warning: The declaration must be done on the template page and cannot be placed inside a <includeonly>-tag because in template space it creates a link in the toolbox (where you can also find "move" and "protect" buttons) to create the table. You have to do this in order to store data. |
- 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
retainBlanksto 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)
Warning: If you want to do anything other with the result than passing it to the output stream, you have to encapsulate it with mw.text.unstrip(), otherwise you only get a strip marker as result! |
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
retainBlanksto 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.
| Note: For security reasons, the data stored will be html-encoded. If you manually retrieve data from it (without using any of the query function), you have to decode manually. |
- 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 cfg = {
fieldSeparator = '###~~~@@@~~~###',
helperTemplate = 'CargoUtilQueryParserHelper',
resultSeparator = '#####~~~****~~~#####',
}
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
-- now try to ascertain the headline
local tmpfields = query.fields
local headlines = {}
if type(tmpfields) ~= 'table' then
tmpfields = mw.text.split(tmpfields, ',')
end
for num, hl in pairs(tmpfields) do
if mw.ustring.find(hl, '=', 1, true) then
hl = mw.ustring.match(hl, '^.+=(.+)$')
end
headlines[num] = hl
end
classDebug:log(23, ' having headlines: ' .. _TT.printTable(headlines))
attributes.default = ''
attributes.intro = nil
attributes.format = 'template'
attributes['more results text'] = ''
attributes.outro = nil
attributes.template = cfg.helperTemplate
local ret = nil
local result = mw.text.trim(p.rawquery(query, attributes))
if result and mw.ustring.len(result) > 0 then
classDebug:log(24, ' result is: ' .. result)
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
table.insert(ret, array)
end
end
end
end
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
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 tables = query.tables
local joins = query.joins or query.join
local fields = query.fields
local where = query.where
local group = query.group
local having = query.having
local order = query.order
if tables and #tables > 0 and fields and #fields > 0 then
local frame = mw.getCurrentFrame()
if type(tables) == 'table' then
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
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