Module:CommonData/Join

-- CommonData

-- bor, bxor, band = 1, 3, 4 local function _bit(oper, a, b)  local result, bitval, s = 0, 2147483648 --2^31 repeat s,a,b = a + b + bitval, a % bitval, b % bitval result = result + bitval * oper % (s-a-b) bitval = bitval / 2 until bitval < 1 return result end

local p = {}

local function dummy end

local function band(frame, value, flags) value, flags = tonumber(value) or 0, tonumber(flags) or 0 return _bit(4, value, flags) end

local function AnyFlag(frame, value, flags) value = band(frame, value, flags) return value ~= 0 and value or nil end

p["&"] = band p["&~"] = AnyFlag

local function _GetBind(frame, a, data) local bind = a[data] if bind then return bind end local tableModule = require('Module:CommonData/'..data) local cols = tableModule.GetRawColumns(frame) local rows = tableModule.GetRawTable(frame)

bind = { data, tableModule, cols, rows } a[data] = bind return bind end -- process wiki code per row matching the query -- data1, data2, joinKey, id, value, id, value, id, value, ... -- data1,data2 on MapID local function GetTranscludeRowsJoin(frame, binds, result, keyNames, keyVals,   limit, count, data, joinCount, code, vars)

local tableData, data = data:match("([^,]+),(.*)") data = data and data ~= "" and data or nil

local bind,has = _GetBind(frame, binds, tableData) local _, tableModule, cols, rows = unpack(bind) local colsR = bind.colsR       -- reverse cols local colsCode = bind.colsCode -- cols in code local colsVar = bind.colsVar   -- compiled var define start local expsCode = bind.expsCode -- exps colId, cmd, arg, expsVar local keyIds = bind.keyIds if not colsR then              -- compile query colsR, colsCode, colsVar, expsCode, keyIds = {}, {}, {}, {}, {}       bind.colsR, bind.colsCode, bind.colsVar, bind.expsCode, bind.keyIds = colsR, colsCode, colsVar, expsCode, keyIds for i,v in ipairs(cols) do           local found = false colsR[v] = i           if code and code:find(v) then if code:find("{{#var:[!]?"..v.."[}|]") then found = true colsCode[#colsCode + 1] = i                   colsVar[#colsCode] = '{{#vardefine:'..v..'|' end if code:find("{{#var:[!]?"..tableData.."."..v.."[}|]") then colsCode[#colsCode + 1] = i                   colsVar[#colsCode] = '{{#vardefine:'..tableData..'.'..v..'|' end for k2,v2,y2 in code:gmatch("{{#var:[!]?("..v.."%s*([&^][~]?)%s*(%w+))[}|]") do                   expsCode[#expsCode + 1] = { i, v2, y2, '{{#vardefine:'..k2..'|' } end end if not found and vars and vars:find(v) and vars:find(","..v..",") then colsCode[#colsCode + 1] = i               colsVar[#colsCode] = '{{#vardefine:'..v..'|' end end

local s = "^"..tableData..".(.+)" for i,v in pairs(keyNames) do           v = v:match(s) or v            keyIds[i] = colsR[v] end end

local resulti = #result while rows do       for _,v in ipairs(rows) do            local found, value, value2 = true for i3,v3 in pairs(keyIds) do               value, value2 = v[v3] or "", keyVals[i3] if value ~= value2 and value ~= tonumber(value2) then if i3 > joinCount then found = false; break end keyVals[i3] = value end end

if found then local resultiMark = resulti + 1

for _,v2 in pairs(expsCode) do -- add exps value = (p[v2[2]] or dummy)(frame, v[v2[1]], v2[3]) resulti = resulti + 1 result[resulti] = v2[4] .. (value or "") .. '}}'               end for i2,v2 in pairs(colsCode) do -- add cols value = v[v2] resulti = resulti + 1 result[resulti] = colsVar[i2] .. (value or "") .. '}}'               end if data then local lastCount = count count = GetTranscludeRowsJoin(frame, binds, result, keyNames, keyVals,                       limit, count, data, 0, code, vars) if count <= lastCount then -- rewind the stack for j = #result, resultiMark, -1 do                           result[j] = nil end end resulti = #result else if code then   -- we are the last data set, add code if any resulti = resulti + 1 result[resulti] = code end count = count + 1 end

if limit and count >= limit then break end end end if limit and count >= limit then break end rows = tableModule.GetNextRawTable(frame, rows) or nil end return count end

-- let two or more data sets iterate without an intermediate wiki code layer -- data = "Instances,Maps on InstanceID" local function GetTranscludeEachRowJoin(frame, limit) local args = frame.args local data, code, vars, istable, source = args[1], args.wiki, args.vars, args.istable, args.source

code = code and code ~= "" and code or nil istable = istable and istable ~= "" and istable or nil source = tonumber(source) or 0

limit = limit or tonumber(args.limit) or 8000 limit = limit ~= 0 and limit or nil vars = vars and vars ~= "" and (","..vars..",") or nil

local data, keys = data:match("%s*([^%s]+)%s+on%s+([^%s]+)") if not (data or keys) or data == "" or keys == "" then return "Bad or missing join data or keys" end local keyNames, keyVals, count = {}, {}, 0 for v in (keys .. ","):gmatch("%s*([^%s^,]+)%s*,") do       count = count + 1 keyNames[count], keyVals[count] = v, nil end local joinCount = count for i = 2,10,2 do       local v = args[i] if not v or v == "" then break end count = count + 1 keyNames[count], keyVals[count] = v, args[i + 1] or "" end

if code then code = mw.text.unstripNoWiki(code) -- go ahead and remove the nowiki end if code and istable then               -- table or alternate other markup code = code :gsub("@([^#^%s^!^@]+)@", "<%1>")-- unescape any wraped tags :gsub("@!([^@]+)@!", "@%1@")   -- unescape next tag layer :gsub("%^%^", "@##@")          -- escape our table markup :gsub("%^([%s%{%}%-%+])", "@#%1@")-- escape our table markup end local result, binds = {}, {} GetTranscludeRowsJoin(frame, binds, result, keyNames, keyVals,       limit, 0, data..",", joinCount, code, vars) result = #result > 0 and table.concat(result) or ""

if result ~= "" and (code or source == 0) and source < 2 then result = frame:preprocess(result) or "" end if result == "" then result = mw.text.unstripNoWiki(args.default or "") or "" result = frame:preprocess(result) or "" end

if code and istable then result = result :gsub("@##@", "||") :gsub("@# @", "| ") :gsub("@#%+@", "\n|") :gsub("@#%-@", "\n|-") :gsub("@#%{@", "\n{|") :gsub("@#%}@", "\n|}") end if source > 0 then result = " 2 and           " style=\"white-space:pre-wrap;\"" or "")..">"..result.." " end

return result end

-- CommonData

function p.GetJoins(frame) return GetTranscludeEachRowJoin(frame) end

function p.GetJoin(frame) return GetTranscludeEachRowJoin(frame, 1) end

return p