Module:CargoUtil

local List = require 'Module:ListUtil' local Hash = require 'Module:HashUtil' local escq = (require 'Module:EscQ').main1 local trim = mw.text.trim

local full_query = function (tables, fields, args) local result = {} args.limit = 5000 args.offset = 0 while true do   local part = mw.ext.cargo.query(tables, fields, args) List.concat_self(result, part) if #part < args.limit then return result end args.offset = args.offset + #part end end

local make_sort_func = function (keystr) local keys = List.map(mw.text.split(keystr, '%s*,%s*'), function (k)   local b = k:find '%s+[Aa][Ss][Cc]%s*$'    if b then      return {trim(k:sub(1, b - 1)), true}    end    b = k:find '%s+[Dd][Ee][Ss][Cc]%s*$'    if b then      return {trim(k:sub(1, b - 1)), false}    end    return {trim(k), true}  end)

return function (x, y)   for _, o in ipairs(keys) do      if x[o[1]] < y[o[1]] then return o[2] elseif x[o[1]] > y[o[1]] then return not o[2] end end return false end, List.map(keys, function (t) return t[1] end) end

local sort_by = function (r, pr) local t = List.range(1, #r) table.sort(t, function (x, y) return pr(r[x], r[y]) end) local i = 0 return function i = i + 1 return i, r[t[i]] end end

local get_fields = function (t, keys) return List.map(keys, function (k) return t[k] end) end

local equijoin = function (r1, r2, keystr) if #r1 == 0 or #r2 == 0 then return {} end

local fn, keys = make_sort_func(keystr) local sr1 = sort_by(r1, fn) local sr2 = sort_by(r2, fn) local i1, v1 = sr1 local i2, v2 = sr2 local ks1 = nil local ks2 = nil local sub1 = {} local sub2 = {}

local advance1 = function sub1 = {} if v1 then ks1 = get_fields(v1, keys) while v1 and List.equal(get_fields(v1, keys), ks1) do       sub1[#sub1 + 1] = v1        i1, v1 = sr1 end end end local advance2 = function sub2 = {} if v2 then ks2 = get_fields(v2, keys) while v2 and List.equal(get_fields(v2, keys), ks2) do       sub2[#sub2 + 1] = v2        i2, v2 = sr2 end end end

local ret = {} advance1 advance2 while #sub1 > 0 and #sub2 > 0 do   local cmp = List.compare(ks1, ks2) if cmp == 0 then for _, val1 in ipairs(sub1) do       for _, val2 in ipairs(sub2) do          ret[#ret + 1] = Hash.merge(val1, val2) end end advance1 advance2 elseif cmp < 0 then advance1 else -- cmp > 0 advance2 end end

return ret end

local order_by_self = function (t, keystr) table.sort(t, make_sort_func(keystr)) return t end

return { full_query = full_query, equijoin = equijoin, order_by_self = order_by_self, make_sql_equality_check_string = function(x) local s		if type(x) == "table" then if #x > 1 then return " IN ("..table.concat(List.map(x, function(s) return "'"..escq(s).."'" end),",")..")" elseif (getmetatable(x) or {}).__tostring then s = tostring(x) else s = x[1] end else s = x		end

if s == nil then return " IS NULL" else return "='"..escq(s).."'" end end, }