模块:Query

從 WikiFur
跳到: 導覽搜尋
local p = {} local OrderedTable = require('Module:OrderedTable') ------------------------------------------------------ -------------------SMongo v0.1.13---------------------- -----------Semantic-Style MongoDB Query--------------- ------------------------------------------------------ local getArgs = require('Module:Arguments').getArgs ------------------------------------------------------ function p._ask(frame) local args = getArgs(frame) local template_args_debug = {} local namedArgs_debug = 'unkown' local q_string = mw.text.split(args['query'],';') local c_string = '' local query, options = {}, {} local scode1, scode2 = '0' ,'0' local res = '' local addClass = args['class'] or '' ------------------import data table and schema------------------ local schema_table = {} if args['table'] then -------------------方法1------------------------- -------读取指定tab/tabx文件的schema确定字段类型 local db_title = mw.title.makeTitle('Data', args['table']) local json = mw.text.jsonDecode(db_title:getContent()) schema_table = json['schema']['fields'] ------指定的table查询---- query['_id'] = { ["$regex"] = 'Data:'..args['table']..'\\#.*', } else --------------------方法2---------------------- -------使用在query/data的'schema'确定字段类型 local json = mw.loadData('module:Query/data') schema_table = json['schema'] end ------------------ Query-------------------- for i,v in ipairs(q_string) do c_string = mw.text.split(v,'::') if #c_string == 2 then local c_1 = mw.ustring.sub(c_string[2],1,1) local c_2 = c_string[2] local special_enums = { ['!'] = 'not', ['+'] = 'any', ['>'] = 'gt', ['<'] = 'lt', ['@'] = 'regex', ['~'] = 'not exist', ['&'] = 'between', } if special_enums[c_1] then ------------处理特殊的查询条件----------------- c_2 = mw.ustring.sub(c_string[2],2,-1) end ------------根据schema来处理字段的类型 -------------- local s_key ='' local s_type = 'string' if args['table'] then ----------方法1-------------------------- s_key = mw.ustring.gsub(c_string[1]," ","") s_key = mw.ustring.lower(s_key) s_type = 'string' for _i, item in ipairs(schema_table) do if item['name'] == s_key then s_type = item['type'] end end scode1 = '101' -------------------------------------- else ------------方法2------------ s_key = c_string[1] s_type = 'string' for k in pairs(schema_table) do if k == s_key then s_type = schema_table[k] end end scode1 = '201' --------------------------- end -----handle type ------------ c_4 = mw.text.split(c_2,",") c_3 = {} if s_type == 'number' then for _i,v in ipairs(c_4)do table.insert(c_3, tonumber(v)) end scode2 = '101' elseif s_type == 'boolean' then for _i,v in ipairs(c_4)do if v == "true" then table.insert(c_3,true) table.insert(c_3,1) else table.insert(c_3,false) table.insert(c_3,0) end end scode2 = '201' elseif s_type == 'string' then for _i,v in ipairs(c_4)do if tonumber(v) ~= nil then table.insert(c_3, tonumber(v)) scode2 = scode2..'('.._i..v..'303'..')' else table.insert(c_3, v) scode2 = scode2..'('.._i..v..'301'..')' end end end -----assemble conditon------------ ------------!------------- if c_1 == "!" then query[c_string[1]] = { ['$exists'] = true, ['$nin'] = c_3, } ------------+------------- elseif c_1 == "+" then query[c_string[1]] = { ['$exists'] = true, } ------------>------------- elseif c_1 == ">" then query[c_string[1]] = { ['$gte'] = c_3[1], } ------------<------------- elseif c_1 == "<" then query[c_string[1]] = { ['$lte'] = c_3[1], } ------------&在两个值中间------------- elseif c_1 == "&" then local min_max = mw.text.split(c_2,"~") local min = min_max[1] local max = min_max[2] query[c_string[1]] = { ['$gte'] = tonumber(min), } if max then query[c_string[1]]['$lte'] = tonumber(max) end ------------@------------ elseif c_1 == "@" then query[c_string[1]] = { ["$regex"] = c_2, } elseif c_1 == "~" then if args['table'] then query[c_string[1]] = null else query[c_string[1]] = { ["$exists"] = false, } end else query[c_string[1]] = { ['$in'] = c_3, } end end end ---------------Options---------------------------- local order_enum = { ['asc'] = 1, ['ascending'] = 1, ['1'] = 1, ['desc'] = -1, ['descending'] = -1, ['revers'] = -1, ['reverse'] = -1, ['-1'] = -1 } if args['format'] ~= 'count' then options['limit'] = 200 end if args['limit'] and (args['format'] ~= 'count') then options['limit'] = tonumber(args['limit']) end ------------------sort-------------------------- if args['sort'] then options['sort'] = OrderedTable() local sorts = mw.text.split(args['sort'],',') local orders = {} if args['order'] then orders = mw.text.split(args['order'],',') else orders = {'1'} end for _i,v in ipairs(sorts) do ------有与 sort 匹配的order参数------- local order = 1 if orders[_i] then order = order_enum[orders[_i]] or 1 ------------------------------------------------ else --------没有与 sort 匹配的order参数,补全 1--- order = 1 end --------------------------------------------------- if options['sort'] then options['sort'][tostring(v)] = order else options['sort']={ [tostring(v)] = order } end -------------------------------- end else options['sort'] = { ['_id'] = 1 } end --------------offset--------------------------------------- if args['offset'] then options['skip'] = tonumber(args['offset']) or 0 end ------------------------------------------------------------ --mw.logObject(query) data = mw.huiji.db.find(query,options) --mw.logObject(data) -------if result is empty, return "default" -------- if #data == 0 then res = (args['default'] or '') else ------------------------handle result----------------------------- local display = {} for key in pairs(args) do if mw.ustring.sub(key,1,1) == "?" then local new_key = mw.ustring.sub(key,2,-1) table.insert(display, new_key) end end -------------------------handle format--------------------- if #display == 0 then res = 'error:无效的查询字段,正确格式:|?参数=xxx,查询条件不能是空值' elseif args['format'] == 'template' then if args['template'] then local template = args['template'] local namedArgs = args['named args'] or args['named_args'] or false local userparam = args['userparam'] or '' -----------------------intro template--------------------- if args['introtemplate'] then local intro_template = '{{'..args['introtemplate']..'}}' res = res .. frame:preprocess(intro_template) end ----------------- template -------------------------- for _i, d in ipairs(data) do local template_args = {} local title = mw.title.makeTitle('template', template) if title['id'] == 0 then res = res .. '[[template:'..template..']]' else if namedArgs then ---------------命名参---------------- for _i,k in ipairs(display) do local args_key = "?"..k template_args[args_key] = d[k] end else -----------------序号参--------------- -------{{{1}}}----------------- template_args[1] = d['_id'] for _i,k in ipairs(display) do local args_key = _i+1 template_args[args_key] = d[k] end end ------{{{userparam}}}-------------- template_args['userparam'] = userparam ------------------------------------------------------------------------- res = res ..frame:expandTemplate{ title = template, args = template_args } end template_args_debug = template_args namedArgs_debug = namedArgs end ---------------outrotemplate----------------------------------- if args['outrotemplate'] then local outro_template = '{{'..args['outrotemplate']..'}}' res = res .. frame:preprocess(outro_template) end -------------------------------------------------------------- else res = res .. 'error:没有指定template' end elseif args['format'] == 'count' then res = mw.huiji.db.count(query,options) else --------------- format = table -------------------------- local intro = args['intro'] or '' local outro = args['outro'] or '' local headers = '' local header1 = '<th>'..(args['mainlabel'] or '')..'</th>' if args['mainlabel'] then if args['mainlabel'] == '-' then header1 = '' end end res = res .. intro .. '<table class="wikitable '..addClass..'">' headers = headers ..'<tr>'..header1 for _i, k in ipairs(display) do local key = '?'..k headers = headers ..'<th>'.. (args[key] or k) ..'</th>' end headers = headers ..'</tr>' if args['headers'] then if args['headers'] == 'hide' then headers = '' end end res = res .. headers for _i,d in ipairs(data) do local row1 ='<td>'.. d['_id']..'</td>' if args['mainlabel'] then if args['mainlabel'] == '-' then row1 = '' end end res = res..'<tr>'..row1 for _i, k in ipairs(display) do local v = type(d[k])=='table' and table.concat(d[k],';') or d[k] or '' res = res ..'<td>'.. v ..'</td>' end res = res .. '</tr>' end res = res .. '</table>' ..outro end ----------------------------------------------------------- end --------------------------------------------------------------- ------------------------------debug---------------------------------------- if args['debug'] then res = res .. '<div style = "border:2px dashed #000;padding:0px 12px;"><div style="padding:12px;text-align:center;">DEBUG信息</div>' res = res..p._collapse('查询条件(query)', mw.dumpObject(query), '1') res = res..p._collapse('查询选项(options)', mw.dumpObject(options), '2') res = res..p._collapse('查询返回数据(nil为空)', mw.dumpObject(data), '3') res = res..p._collapse('传入的参数(args)', mw.dumpObject(args), '4') res = res..p._collapse('传入的模板参数(format=template)', mw.dumpObject(template_args_debug), '5') res = res..p._collapse('模板参数是否为命名参(namedArgs)', mw.dumpObject(namedArgs_debug), '5') res = res..p._collapse('Schema Table', mw.dumpObject(schema_table), '6') res = res..p._collapse('检查代码1', mw.dumpObject(scode1), '7') res = res..p._collapse('检查代码2', mw.dumpObject(scode2), '7') res = res..'</div>' end return res end function p._collapse(title,content,id) local html = mw.html.create() local res_html = html :tag('div'):addClass('mw-customtoggle-'..id or ''..' mw-customtoggle'):cssText('overflow:hidden;margin-bottom:12px;font-size:12px') :tag('div'):addClass('bg-primary'):cssText('text-align:center;padding:12px;overflow:auto;'):wikitext(title):done() :tag('div'):addClass('darken mw-collapsible mw-collapsed'):attr('id','mw-customcollapsible-'..id or ''):cssText('text-align: left; padding: 1em 1em 2em;'):wikitext(content):done() :done() return tostring(res_html) end return p