Module:Sequences

local p = {} local h = {}

local utilsArg = require('Module:UtilsArg') local utilsCargo = require('Module:UtilsCargo') local utilsMarkup = require('Module:UtilsMarkup') local utilsTable = require('Module:UtilsTable')

local cargoTable = "UniverseOrder" -- "Order" can't be used because it's an SQL keyword

function p.CargoDeclare(frame) return utilsCargo.declare(cargoTable, {		media = "String",		universeOrder = "String",		name = "String",		ordinality = "Integer",	}) end

function p.CargoStore(frame) local args = frame:getParent.args return h.store({		media = args.media or mw.title.getCurrentTitle.subpageText,		order = args[1],		names = utilsTable.slice(2)(args),	}) end

function p.SortValue(frame) local media = frame.args.media local order = frame.args.order local name = frame.args.name if order == "" then order = nil end local sortValue, sortValues, err = p.getSortValue(media, order)(name) if err then return "" .. err end if #sortValues == 0 then local warn = ("Sort value not found for  in game  . Defaulting to alphabetical. See Data:Sort Values/%s for list of valid sort values.") :format(name, media, media) mw.addWarning(warn) return "" end if #sortValues > 1 then local warn = ("More than one possible sort order exists for  in game  . Defaulting to  . Use   to specify an alternative.") :format(term, media, sortValue.universeOrder) mw.addWarning(warn) end local dataSortValue = string.format('data-sort-value="%s"|', sortValue) return dataSortValue end

--@return a function that sorts @names according to the given @order for the given @media defined at `Data:Orders` function p.sort(media, order) utilsArg.nonEmpty(media, "media") utilsArg.nonEmpty(order, "order") -- @return sorted names, minus those that were not defined for the given sort order -- @return names not defined for the given sort order return function(names) local fields = "name" local queryResults = utilsCargo.query(cargoTable, fields, {			where= ("media='%s' AND universeOrder='%s'"):format(media, order),			orderBy= "ordinality",		}) local validNames = utilsTable.map("name")(queryResults) local sorted = utilsTable.intersection(validNames)(names) local unsorted = utilsTable.difference(names)(sorted) return sorted, unsorted end end

function p.getSortValue(media, order) return function(name) local validate = utilsArg.validator({			media = { nonEmpty = true },			name = { nonEmpty = true },		}) local err = validate({media = media, name = name}) if err then return nil, nil, utilsMarkup.categories(err) end local fields = "name, universeOrder=order, ordinality" local queryResults = utilsCargo.query(cargoTable, fields, {			where= utilsCargo.allOf({ media = media, name = name, order = order, }),			orderBy= "ordinality",		}) local sortValue = queryResults[1] and tonumber(queryResults[1].ordinality) local sortValues = {} for _, v in ipairs(queryResults) do			table.insert(sortValues, {				[v.order] = tonumber(v.ordinality)			}) end return sortValue, sortValues end end

function h.store(args) local validator = utilsArg.validator({		media = { nonEmpty = true },		order = { nonEmpty = true },		names = { nonEmpty = true },	}) local err = validator(args) if err then return utilsMarkup.categories(err) end for i, v in ipairs(args.names) do		utilsCargo.store(cargoTable, {			media = args.media,			universeOrder = args.order,			ordinality = i,			name = v,		}) end end

p.Documentation = { description = "This module is used for storing data at Special:CargoTables/" .. cargoTable .. ", and leveraging that data to sort strings according to some in-universe order. See Template:Sort Value for further documentation on usage.", {		name = "sort", order = 2, params = { {				{					name = "media", description = "A string representing a game or other published media." },				{					name = "order", description = "A string identifiying some sort order." },			},			{				{					name = "names", description = "An array of strings to sort according to the given sort order." }			},		},		returns = { "The array of names, sorted according to the given order for the given media, minus those that aren't defined for that sort order.", "An array of the names that were not sorted." },		cases = { {				args = { { "ST", "Realm" }, { {"Fire Realm", "Sand Realm", "💩Realm", "Ocean Realm", "Forest Realm", "Fire Realm" } }, },				expected = { { "Forest Realm", "Ocean Realm", "Fire Realm", "Sand Realm" }, { "💩Realm" }, },			},		},	},	{		name = "getSortValue", order = 2, params = { {				{					name = "media", description = "String initiliasm of a game or other published media.", },				{					name = "order", optional = true, description = "The order to get the sort value for (e.g. the Snow Realm is #2 in the  order."				},			},			{				{					name = "name",					description = "Name to get sort value for.",				},			},		},		returns = {			"Integer sort value, or   if none found.",			"  or key-value pairs. Size is equal to 0 when name is not found in the given order; equal to 1 when one result was found, greater than 1 when   is null and the name exists in multiple orders.",		},		cases = {			{				args = {					{ "ST" },					{ "Snow Realm" },				},				expected = { 					2, 					{						{							Realm = 2						}					}				}			},			{				args = {					{ "ST" },					{ "💩 Realm" },				},				expected = { nil, {} }			},		}	} }

return p