Modul:Wikidata/Sorters
Vzhled
require "Modul:No globals"
local p = {}
local lib = require 'Modul:Wikidata/lib'
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 sortAlphabetically(first, second)
if not (first and second) then
return checkInvert(second)
end
if not (first.mainsnak.snaktype == "value" and second.mainsnak.snaktype == "value") then
return checkInvert(second.mainsnak.snaktype == "value")
end
local first_label = mw.wikibase.label(lib.getEntityIdFromValue(first.mainsnak.datavalue.value))
local second_label = mw.wikibase.label(lib.getEntityIdFromValue(second.mainsnak.datavalue.value))
if not (first_label and second_label) then
return checkInvert(second_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 = " .,:-/'0123456789aábcčdďeéěfghiíjklmnňoópqrřsštťuúůvwxyýzž"
local function charValue(char)
return mw.ustring.match(chars, '()' .. char) or (mw.ustring.len(chars) + 1)
end
local i = 1
while i <= 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
i = i + 1
end
return checkInvert(mw.ustring.len(second_label) == min_length)
end
local function sortByDate(first, second)
local Date = require 'Modul:Wikidata/datum'
local FirstValues, SecondValues
if first and first.qualifiers then
FirstValues = {}
local Time = require 'Modul:Time'
for key, array in pairs(lib.props) do
for _, prop in pairs(array) do
if first.qualifiers[prop] then
for _, qualData in pairs(first.qualifiers[prop]) do
if qualData.snaktype == "value" then
FirstValues[key] = Time.newFromWikidataValue(qualData.datavalue.value)
break
end
end
end
end
end
end
if second and second.qualifiers then
SecondValues = {}
local Time = require 'Modul:Time'
for key, array in pairs(lib.props) do
for _, prop in pairs(array) do
if second.qualifiers[prop] then
for _, qualData in pairs(second.qualifiers[prop]) do
if qualData.snaktype == "value" then
SecondValues[key] = Time.newFromWikidataValue(qualData.datavalue.value)
break
end
end
end
end
end
end
if not FirstValues or not SecondValues then
if not FirstValues and not SecondValues then
return checkInvert(false)
else
return checkInvert(not SecondValues)
end
end
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
else
if FirstValues.begin or SecondValues.begin then
if FirstValues.begin and SecondValues.begin then
return checkInvert(Date.IsSecondLaterThanFirst(FirstValues.begin, SecondValues.begin))
else
return checkInvert(not FirstValues.begin)
end
elseif 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
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 (first.mainsnak.snaktype == "value" and second.mainsnak.snaktype == "value") then
return checkInvert(second.mainsnak.snaktype == "value")
end
local first_quantity = tonumber(first.mainsnak.datavalue.value.amount)
local second_quantity = tonumber(second.mainsnak.datavalue.value.amount)
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 = sortAlphabetically,
},
date = {
sorter = sortByDate
},
number = {
datatypes = { 'quantity' },
sorter = sortByQuantity,
},
rank = {
sorter = sortByRank
},
}
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
function p.test()
local Module = require 'Modul:Wikidata'
local entity = mw.wikibase.getEntity('Q183')
local Statements = Module.filterStatementsFromLua(entity, { property = 'P1082' })
return p.sortStatements(Statements, { sort = 'rank,number,date' }) and true
end
return p