Modul:Wikidata/Sorters
Dokumentaciju za ovaj modul možete napraviti na stranici Modul:Wikidata/Sorters/dok
require "Modul:No globals"
local p = {}
local lib = require 'Modul:Wikidata/lib'
local Formatters = require 'Modul:Wikidata/Formatters'
local inverted = false
local sorters = {}
local current_sorter = 1
local function checkInvert(value)
if inverted then
return not value
end
return value and true
end
local function sortSame(first, second)
current_sorter = current_sorter + 1
if sorters[current_sorter] then
return sorters[current_sorter](first, second)
end
current_sorter = 1
return checkInvert(false)
end
local function sortBySnaktype(first, second)
if not (first and second) then
return checkInvert(false)
end
if first.mainsnak.snaktype == second.mainsnak.snaktype then
return sortSame(first, second)
end
if first.mainsnak.snaktype == 'value' and second.mainsnak.snaktype ~= 'value' then
return checkInvert(true)
elseif first.mainsnak.snaktype == 'somevalue' and second.mainsnak.snaktype == 'novalue' then
return checkInvert(true)
end
return checkInvert(false)
end
local function alphaSort(first, second)
if not (first and second) then
return checkInvert(second)
end
if not (lib.IsSnakValue(first.mainsnak) and lib.IsSnakValue(second.mainsnak)) then
return sortBySnaktype(first, second)
end
local first_value = Formatters.getRawValue(first.mainsnak)
local second_value = Formatters.getRawValue(second.mainsnak)
if first_value == second_value then
return sortSame(first, second)
end
local first_label = mw.wikibase.label(first_value)
local second_label = mw.wikibase.label(second_value)
if not (first_label and second_label) then
return checkInvert(first_label)
end
if first_label == second_label then
return sortSame(first, second)
end
local min_length = mw.ustring.len(first_label)
if mw.ustring.len(second_label) < mw.ustring.len(first_label) then
min_length = mw.ustring.len(second_label)
end
--
local chars = " .,:-/'0123456789abcčćdđefghijklmnoprsštuvzž"
local function charValue(char)
return mw.ustring.match(chars, '()' .. char) or (mw.ustring.len(chars) + 1)
end
for i = 1, min_length do
local first_char = mw.ustring.sub(mw.ustring.lower(first_label), i, i)
local second_char = mw.ustring.sub(mw.ustring.lower(second_label), i, i)
if charValue(first_char) ~= charValue(second_char) then
return checkInvert(charValue(first_char) < charValue(second_char))
end
end
return checkInvert(mw.ustring.len(second_label) == min_length)
end
local function sortHasLabel(first, second)
if not (first and second) then
return checkInvert(second)
end
if not (lib.IsSnakValue(first.mainsnak) and lib.IsSnakValue(second.mainsnak)) then
return sortBySnaktype(first, second)
end
local first_value = Formatters.getRawValue(first.mainsnak)
local second_value = Formatters.getRawValue(second.mainsnak)
if first_value == second_value then
return sortSame(first, second)
end
local first_label = mw.wikibase.label(first_value)
local second_label = mw.wikibase.label(second_value)
if first_label and second_label then
return sortSame(first, second)
end
return checkInvert(first_label)
end
local function sortByDate(first, second)
local FirstValues, SecondValues
if first and first.qualifiers then
FirstValues = {}
for key, array in pairs(lib.props) do
for _, prop in pairs(array) do
if first.qualifiers[prop] then
for _, snak in pairs(first.qualifiers[prop]) do
if lib.IsSnakValue(snak) then
FirstValues[key] = Formatters.getRawValue(snak)
break
end
end
end
end
end
end
if second and second.qualifiers then
SecondValues = {}
for key, array in pairs(lib.props) do
for _, prop in pairs(array) do
if second.qualifiers[prop] then
for _, snak in pairs(second.qualifiers[prop]) do
if lib.IsSnakValue(snak) then
SecondValues[key] = Formatters.getRawValue(snak)
break
end
end
end
end
end
end
if not (FirstValues and SecondValues) then
return checkInvert(FirstValues)
end
local Date = require 'Modul:Wikidata/datum'
if FirstValues.point or SecondValues.point then
if FirstValues.point and SecondValues.point then
if Date.AreDatesSame(FirstValues.point, SecondValues.point) then
return sortSame(first, second)
else
return checkInvert(Date.IsSecondLaterThanFirst(FirstValues.point, SecondValues.point))
end
else
return checkInvert(not FirstValues.point)
end
end
if FirstValues.begin or SecondValues.begin then
if FirstValues.begin and SecondValues.begin then
if Date.AreDatesSame(FirstValues.begin, SecondValues.begin) then
if FirstValues.ending or SecondValues.ending then
if FirstValues.ending and SecondValues.ending then
if Date.AreDatesSame(FirstValues.ending, SecondValues.ending) then
return sortSame(first, second)
else
return checkInvert(Date.IsSecondLaterThanFirst(FirstValues.ending, SecondValues.ending))
end
else
return checkInvert(FirstValues.ending)
end
else
return sortSame(first, second)
end
else
return checkInvert(Date.IsSecondLaterThanFirst(FirstValues.begin, SecondValues.begin))
end
else
return checkInvert(FirstValues.begin)
end
end
if FirstValues.ending or SecondValues.ending then
if FirstValues.ending and SecondValues.ending then
return checkInvert(Date.IsSecondLaterThanFirst(FirstValues.ending, SecondValues.ending))
else
return checkInvert(not FirstValues.ending)
end
end
return checkInvert(false)
end
local function sortByRank(first, second)
if not (first and second) then
return checkInvert(false)
end
if first.rank == second.rank then
return sortSame(first, second)
end
if first.rank == 'preferred' and second.rank ~= 'preferred' then
return checkInvert(true)
elseif first.rank == 'normal' and second.rank == 'deprecated' then
return checkInvert(true)
end
return checkInvert(false)
end
local function sortByQuantity(first, second)
if not (first and second) then
return checkInvert(second)
end
if not (lib.IsSnakValue(first.mainsnak) and lib.IsSnakValue(second.mainsnak)) then
return sortBySnaktype(first, second)
end
local first_quantity = Formatters.getRawValue(first.mainsnak)
local second_quantity = Formatters.getRawValue(second.mainsnak)
if first_quantity == second_quantity then
return sortSame(first, second)
end
return checkInvert(first_quantity > second_quantity)
end
local Methods = {
alpha = {
datatypes = { 'wikibase-item', 'wikibase-property' },
sorter = alphaSort,
},
date = {
sorter = sortByDate
},
hasLabel = {
datatypes = { 'wikibase-item', 'wikibase-property' },
sorter = sortHasLabel
},
number = {
datatypes = { 'quantity' },
sorter = sortByQuantity,
},
rank = {
sorter = sortByRank
},
snaktype = {
sorter = sortBySnaktype
},
}
local function getSorter(method, curr_datatype)
if Methods[method] then
if Methods[method].datatypes then
for _, datatype in pairs(Methods[method].datatypes) do
if curr_datatype == datatype then
return Methods[method].sorter
end
end
return error(lib.formatError('invalid-datatype', method))
end
return Methods[method].sorter
end
return error(lib.formatError('invalid-sort', method))
end
function p.sortStatements(statements, options)
if lib.IsOptionTrue(options, 'invert') then
inverted = true
end
local datatype = statements[math.random(1, #statements)].mainsnak.datatype
local methods = lib.textToTable(options.sort)
for key, method in pairs(methods) do
table.insert(sorters, getSorter(method, datatype))
end
table.sort(statements, sorters[1])
return statements
end
return p