Module:CargoUtil

local util_args = require('Module:ArgsUtil') local bool_false = { ['false'] = true, ['0'] = true, ['no'] = true, [''] = true } local argPrefix = 'q?' local lang = mw.getLanguage('en') local bool_to_str = { [true] = 'Yes', [false] = 'No' }

local p = {}

function p.makeMinMaxQuery(cargoquery, field, orderby, order) -- modifies a pre-existing query to add an extra set of conditions to get the max/min value of some field -- order will be either MIN or MAX, and orderby is usually going to be a date/datetime -- example: c.makeMinMaxQuery(cargoquery, 'SP.Champion','SP.Time','MAX') --to get the most-recent played champions result = mw.ext.cargo.query(cargoquery.tables,		string.format("%s(%s)=thisvalue, %s=thisfield", order, orderby, field ),		cargoquery) local newcondition = {} if not next(result) then return cargoquery.where end for _, row in ipairs(result) do		newcondition[#newcondition+1] = string.format(			'(%s="%s" AND %s="%s")',			field,			row.thisfield,			orderby,			row.thisvalue		) end local newwhere = { string.format("(%s)",table.concat(newcondition, ' OR ')), }	if cargoquery.where and cargoquery.where ~= '' then newwhere[2] = string.format("(%s)",cargoquery.where) end local cargowhere = table.concat(newwhere, ' AND ') return cargowhere end

function p.getOneResult(query) local result = p.queryAndCast(query) if result[1] then return result[1][query.fields] end return nil end

function p.getOneRow(query) local result = p.queryAndCast(query) return result[1] or {} end

function p.getOneField(query, field) local result = p.queryAndCast(query) local tbl = {} for i, row in ipairs(result) do		tbl[#tbl+1] = row[field] end return tbl end

function p.strToBool(v) if not v then return false elseif bool_false[lang:lc(v)] then return false end return true end

function p.queryAndCast(query, dontcast) local tables = type(query.tables) == 'table' and table.concat(query.tables,',') or query.tables local fields = type(query.fields) == 'table' and table.concat(query.fields,',') or query.fields local result = mw.ext.cargo.query(tables, fields, query) if dontcast then return result else p.cast(result, query.types or {}) return result end end

function p.cast(result, types) for i, row in ipairs(result) do		for k, v in pairs(row) do			row[k] = p.castField(v, types[k]) end end end

function p.castField(v, v_type) if v == '' then return nil elseif v_type == 'boolean' then return p.strToBool(v) elseif v_type == 'number' then return tonumber(v) else return v	end end

function p.makeDict(result, key) local tbl = {} for _, row in ipairs(result) do		tbl[row[key]] = row end return tbl end

function p.makeConstDict(result, key, value) local tbl = {} for _, row in ipairs(result) do		tbl[row[key]] = row[value] end return tbl end

function p.makeOrderedDict(result, key, sortkey, increasing) --	Format the table like this:	{		a1, a2, a3, a4,		a1 = { key = value, ... },		a2 = { key = value, ... },		a3 = { key = value, ... },		a4 = { key = value, ... }	} local tbl = {} for k, row in ipairs(result) do		tbl[k] = row[key] tbl[row[key]] = mw.clone(row) end if sortkey then p.sortByValueInTable(tbl, sortkey, increasing) end return tbl end

function p.getOrderedList(query, key) local result = p.queryAndCast(query) return p.makeOrderedList(result, key) end

function p.makeOrderedList(result, key) local tbl = {} for k, row in ipairs(result) do		tbl[#tbl+1] = row[key] end return tbl end

function p.groupResultOrdered(result, key, f)	local data = {} local this local thisvalue local thistab local i = 1 for _, row in ipairs(result) do		if not row[key] then row[key] = 'Uncategorized' end if row[key] ~= thisvalue then data[#data+1] = { name = row[key], index = i } i = i + 1 thistab = data[#data] or {} thisvalue = row[key] end thistab[#thistab+1] = f and f(row) or row end return data end

function p.groupResultByValue(result, key, f)	local data = {} local this local thisvalue local i = 1 for _, row in ipairs(result) do		if row[key] ~= thisvalue then thisvalue = row[key] data[thisvalue] = { name = row[key] } i = i + 1 thistab = data[thisvalue] end thistab[#thistab+1] = f and f(row) or row end return data end

function p.sortByValueInTable(tblToSort, key, increasing) -- assume table is sorted as above table.sort(tblToSort,		function (a,b)			if increasing then				local c = a				a = b				b = c			end			local val_a = tblToSort[a] and tonumber(tblToSort[a][key])			local val_b = tblToSort[b] and tonumber(tblToSort[b][key])			if val_a and val_b then				if val_a == val_b then					return (a < b)				end				return (val_a > val_b)			end			val_a = tblToSort[a] and tblToSort[a][key] or 0			val_b = tblToSort[b] and tblToSort[b][key] or 0			if val_a == val_b then				return (a > b)			end			return val_a > val_b		end	) return end

function p.queryFromArgs(args, defaults) -- sometimes we want to specify query args in the template -- this function parses them into args that cargo will understand -- change argPrefix above to change the prefix for query params local query = mw.clone(defaults or {}) for k, v in pairs(args) do		if string.sub(k, 0, 2) == argPrefix then query[string.sub(k,3)] = v		end end return query end

function p.store(tbl) tbl[1] = '' for k, v in pairs(tbl) do		if type(v) == 'boolean' then tbl[k] = bool_to_str[v] end end mw.getCurrentFrame:callParserFunction{ name = '#cargo_store', args = tbl }	return end

function p.doWeStoreCargo(nocargo, desiredNamespace,title) local argOkay = not util_args.castAsBool(nocargo) if not desiredNamespace then return argOkay end if not title then title = mw.title.getCurrentTitle end return argOkay and title.nsText == desiredNamespace end

function p.whereFromArg(str, arg) -- if an arg is defined, formats a string with the arg to be included in a where table -- if it's not defined, returns false and NOT nil so the table can be used -- with util_table.concat if not arg then return false else return str:format(arg) end end

function p.concatWhere(tbl) local arr = {} -- pairs because maybe some entries are nil, and since it's an AND, order doesn't matter for _, v in pairs(tbl) do		if v then arr[#arr+1] = v		end end return table.concat(arr, ' AND ') end

function p.fakeHolds(field, str, sep) sep = sep or ',' return ('%s__full RLIKE ".*(^|%s)%s($|%s).*"'):format(field, sep, str, sep) end

return p