Přeskočit na obsah

Modul:Wikidata/Sorters

Tato stránka je zamčena
Z Wikipedie, otevřené encyklopedie

require 'Modul:No globals'

local p = {}

local lib = require 'Modul:Wikidata/lib'

local ValueTypeToDefaultMethod = {
	['monolingualtext'] = 'alpha',
	['quantity'] = 'number',
	['string'] = 'alpha',
	['time'] = 'time',
	['wikibase-entityid'] = 'alpha',
}

p.Sorters = {}
setmetatable(p.Sorters, {
	__index = function(t, key)
		t[key] = require('Modul:Wikidata/Sorters/' .. key)
		return t[key]
	end
})

local function resolveResult(result, inverted)
	if math.abs(result) > 1 then
		return result < 0
	else
		return (result < 0) ~= (inverted or false)
	end
end

local function compareIncomplete(first, second)
	if first then
		return -2
	end
	if second then
		return 2
	end
	return 0
end

local function getCallbackForQualifiers(method)
	return function(first, second)
		local sorter = p.Sorters[method]
		local first_complete = sorter.isCompleteSnak(first)
		local second_complete = sorter.isCompleteSnak(second)
		if not (first_complete and second_complete) then
			return compareIncomplete(first_complete, second_complete)
		end
		if not (sorter.mayCompareSnak(first) and sorter.mayCompareSnak(second)) then
			return error(lib.formatError('invalid-datatype', method))
		end
		return sorter.compareSnaks(first, second)
	end
end

local function getDefaultCallbackForQualifiers()
	return function(first, second)
		local default
		if lib.IsSnakValue(first) then
			default = ValueTypeToDefaultMethod[first.datavalue.type]
		elseif lib.IsSnakValue(second) then
			default = ValueTypeToDefaultMethod[second.datavalue.type]
		end
		if default then
			return getCallbackForQualifiers(default)(first, second)
		end
		return 0
	end
end

local function getQualifierToCompare(statement, prop)
	local qualifiers = statement.qualifiers and statement.qualifiers[mw.ustring.upper(prop)]
	if qualifiers then
		qualifiers = mw.clone(qualifiers)
		table.sort(qualifiers, function(first, second)
			return resolveResult(getDefaultCallbackForQualifiers()(first, second))
		end)
		if lib.IsSnakValue(qualifiers[1]) then
			return qualifiers[1]
		end
	end
	return false
end

local function getCallbackForStatements(method)
	return function(first, second)
		local sorter = p.Sorters[method]
		local first_complete = sorter.isCompleteStatement(first)
		local second_complete = sorter.isCompleteStatement(second)
		if not (first_complete and second_complete) then
			return compareIncomplete(first_complete, second_complete)
		end
		if not (sorter.mayCompareStatement(first) and sorter.mayCompareStatement(second)) then
			return error(lib.formatError('invalid-datatype', method))
		end
		return sorter.compareStatements(first, second)
	end
end

local function resolveMethodForStatements(method)
	if method == 'default' then
		return function(first, second)
			local default
			if lib.IsSnakValue(first.mainsnak) then
				default = ValueTypeToDefaultMethod[first.mainsnak.datavalue.type]
			elseif lib.IsSnakValue(second.mainsnak) then
				default = ValueTypeToDefaultMethod[second.mainsnak.datavalue.type]
			end
			if default then
				return getCallbackForStatements(default)(first, second)
			end
			return 0
		end
	elseif lib.isPropertyId(method) then
		return function(first, second)
			local first_qualifier = getQualifierToCompare(first, method)
			local second_qualifier = getQualifierToCompare(second, method)
			if not (first_qualifier and second_qualifier) then
				return compareIncomplete(not not first_qualifier, not not second_qualifier)
			end
			local default = ValueTypeToDefaultMethod[first_qualifier.datavalue.type]
			return getCallbackForQualifiers(default)(first_qualifier, second_qualifier)
		end
	end
	return getCallbackForStatements(method)
end

function p.sortStatements(statements, options)
	local methods = lib.textToTable(options.sort)
	local inverted = lib.IsOptionTrue(options, 'invert')
	local cache = {}
	table.sort(statements, function(first, second)
		local result
		for _, method in ipairs(methods) do
			if not cache[method] then
				cache[method] = resolveMethodForStatements(method)
			end
			result = cache[method](first, second)
			if result ~= 0 then
				return resolveResult(result, inverted)
			end
		end
		return false
	end)
end

local function resolveMethodForQualifiers(method)
	if method == 'default' then
		return getDefaultCallbackForQualifiers()
	end
	return getCallbackForQualifiers(method)
end

function p.sortQualifiers(qualifiers, options)
	local methods = lib.textToTable(options.sort)
	local inverted = lib.IsOptionTrue(options, 'invert')
	local cache = {}
	table.sort(qualifiers, function(first, second)
		local result
		for _, method in ipairs(methods) do
			if not cache[method] then
				cache[method] = resolveMethodForQualifiers(method)
			end
			result = cache[method](first, second)
			if result ~= 0 then
				return resolveResult(result, inverted)
			end
		end
		return false
	end)
end

return p