Module:CargoUtil

From Rocket League Esports Wiki
Jump to: navigation, search

To edit the documentation or categories for this module, click here.


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