Přeskočit na obsah

Modul:Wikidata/Filterers

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

require "Modul:No globals"

local p = {}

local lib = require 'Modul:Wikidata/lib'

local function checkLimit(array, limit)
	local limit = limit and tonumber(limit)
	if limit then
		return #array >= limit
	end
	return true
end

local function applyLimit(array, limit)
	local limit = limit and tonumber(limit)
	while limit and #array > limit do
		table.remove(array)
	end
end

local function IsInLanguage(snak, lang)
	if snak.datatype ~= 'monolingualtext' then
		return error(lib.raiseInvalidDatatype('IsInLanguage', snak.datatype, 'monolingualtext'))
	else
		return lib.IsSnakValue(snak) and snak.datavalue.value.language == lang
	end
end

local function filterBySnaktype(statement)
	return lib.IsSnakValue(statement.mainsnak)
end

local function filterHasTarget(statement, target)
	local Formatters = require 'Modul:Wikidata/Formatters'
	return Formatters.getRawValue(statement.mainsnak) == target
end

local function filterHasQualifier(statement, prop)
	return statement.qualifiers and statement.qualifiers[prop:upper()] and true
end

local function filterHasRanks(statement, ranks)
	for _, rank in ipairs(ranks) do
		if statement.rank == rank then
			return true
		end
	end
	return false
end

local function filterHasReferences(statement, options)
	if statement.references then
		if #p.filterReferences(statement.references, options) > 0 then
			return true
		end
	end
	return false
end

local function filterItemHasLabel(statement, langs)
	local datatype = statement.mainsnak.datatype
	if datatype ~= 'wikibase-item' and datatype ~= 'wikibase-property' then
		return error(lib.raiseInvalidDatatype('filterItemHasLabel', datatype, { 'wikibase-item', 'wikibase-property' }))
	end
	if lib.IsSnakValue(statement.mainsnak) then
		local Formatters = require 'Modul:Wikidata/Formatters'
		langs = langs or { 'cs', 'en', 'sk' }
		if lib.getLabelInLanguage(Formatters.getRawValue(statement.mainsnak), langs) then
			return true
		end
	end
	return false
end

local function filterItemIsInstance(statement, options)
	local datatype = statement.mainsnak.datatype
	if datatype ~= 'wikibase-item' and datatype ~= 'wikibase-property' then
		return error(lib.raiseInvalidDatatype('filterItemIsInstance', datatype, { 'wikibase-item', 'wikibase-property' }))
	end
	local Module = require 'Modul:Wikidata/Tree'
	if lib.IsSnakValue(statement.mainsnak) then
		local item = lib.getEntityIdFromValue(statement.mainsnak.datavalue.value)
		if Module.IsInstance(item, options) then
			return true
		end
	end
	return false
end

local function filterMainsnakInLanguage(statement, options)
	return IsInLanguage(statement.mainsnak, options.withlang)
end

local function filter(array, callback, ...)
	local i = #array
	while i > 0 do
		if not callback(array[i], ...) then
			table.remove(array, i)
		end
		i = i - 1
	end
end

function p.filterStatementsFromEntity(entity, options)
	if not options.property or options.property == '' then
		return error(lib.formatError('param-not-provided', 'property'))
	end
	if not entity or not entity.claims then
		return {}
	end
	local property = mw.ustring.upper(options.property)
	local statements = mw.clone(entity.claims[property])
	if not statements then
		return {}
	end

	p.filterStatements(statements, options)
	return statements
end

function p.filterStatements(statements, options)
	local options = lib.common.cleanArgs(options)
	-- apply filter by rank
	local rank = options.rank or "valid"
	if rank ~= "all" then
		if rank == "valid" or rank == "best" then
			filter(statements, filterHasRanks, { "normal", "preferred" })
			if rank == "best" and #statements > 0 then
				for _, statement in ipairs(statements) do
					if statement.rank == "preferred" then
						filter(statements, filterHasRanks, { "preferred" })
						break
					end
				end
			end
		else
			filter(statements, filterHasRanks, { rank })
		end
		if #statements == 0 then return end
	end
	-- apply filter by source
	if options.ref then
		filter(statements, filterHasReferences, options)
		if #statements == 0 then return end
	end
	-- apply filter by snak type
	if not lib.IsOptionTrue(options, 'showspecial') then
		filter(statements, filterBySnaktype)
		if #statements == 0 then return end
	end
	-- apply filter by target value
	if options.withtarget then
		filter(statements, filterHasTarget, options.withtarget)
		if #statements == 0 then return end
	end
	-- apply filter by qualifier property
	if options.withqualifier then
		filter(statements, filterHasQualifier, options.withqualifier)
		if #statements == 0 then return end
	end
	-- apply filter by language
	if options.withlang then
		filter(statements, filterMainsnakInLanguage, options)
		if #statements == 0 then return end
	end
	-- apply filter by time
	if options.date then
		local date
		local Time = require 'Modul:Time'
		if type(options.date) == 'table' then
			date = options.date
		elseif options.date == '#now' then
			date = Time.new(os.date('!*t'))
		--elseif mw.ustring.find(options.date, '^[Pp][1-9]%d-$') then TODO
		else
			date = Time.newFromIso8601(options.date)
		end
		if not date then
			return error(lib.formatError('invalid-date', tostring(options.date)))
		end

		local oldStatements = statements
		statements = {}
		local temp_value
		local Formatters = require 'Modul:Wikidata/Formatters'
		local Date = require 'Modul:Wikidata/datum'
		for _, statement in ipairs(oldStatements) do
			if statement.qualifiers then
				local Values = {}
				for key, array in pairs(lib.props) do
					for _, prop in ipairs(array) do
						if statement.qualifiers[prop] then
							for _, snak in ipairs(statement.qualifiers[prop]) do
								if lib.IsSnakValue(snak) then
									Values[key] = Formatters.getRawValue(snak)
									break
								end
							end
						end
					end
				end
				if Values.point then
					if not Date.IsSecondLaterThanFirst(date, Values.point) then
						if not temp_value then
							statements = { statement }
							temp_value = Values.point
						else
							if Date.IsSecondLaterThanFirst(Values.point, temp_value) then
								statements = { statement }
								temp_value = Values.point
							elseif Date.AreDatesSame(temp_value, Values.point) then
								table.insert(statements, statement)
							end
						end
					end
				else
					if Values.begin then
						if Date.IsSecondLaterThanFirst(Values.begin, date) then
							if not Values.ending then
								table.insert(statements, statement)
							elseif Date.IsSecondLaterThanFirst(date, Values.ending) then
								table.insert(statements, statement)
							end
						end
					elseif Values.ending then
						if Date.IsSecondLaterThanFirst(date, Values.ending) then
							if not Values.begin then
								table.insert(statements, statement)
							elseif Date.IsSecondLaterThanFirst(Values.begin, date) then
								table.insert(statements, statement)
							end
						end
					end
				end
			end
		end
		if #statements == 0 then return end
	end
	if lib.IsOptionTrue(options, 'withlabel') then
		filter(statements, filterItemHasLabel, options.withlang)
		if #statements == 0 then return end
	end
	-- apply filter by class
	if options.instance then
		filter(statements, filterItemIsInstance, options)
		if #statements == 0 then return end
	end
	-- sort statements if needed
	if options.sort then -- patří to sem?
		local Sorters = require 'Modul:Wikidata/Sorters'
		Sorters.sortStatements(statements, options)
	end
	-- apply filter by limit
	applyLimit(statements, options.limit)
end

function p.filterQualifiers(qualifiers, options)
	local options = lib.common.cleanArgs(options)
	local Qualifiers, oldQualifiers = qualifiers, {}
	if options['qualifiers withlang'] then
		oldQualifiers, Qualifiers = Qualifiers, {}
		for _, snak in ipairs(oldQualifiers) do
			if IsInLanguage(snak, options['qualifiers withlang']) then
				table.insert(Qualifiers, snak)
			end
		end
		if #Qualifiers == 0 then return {} end
	end
	if options['qualifiers class'] then
		local datatype = Qualifiers[math.random(#Qualifiers)].datatype
		if datatype == 'wikibase-item' or datatype == 'wikibase-property' then
			oldQualifiers, Qualifiers = Qualifiers, {}
			local Module = require 'Modul:Wikidata/Tree'
			for _, snak in ipairs(oldQualifiers) do
				if lib.IsSnakValue(snak) then
					local item = lib.getEntityIdFromValue(snak.datavalue.value)
					if Module.IsInTree(item, options['qualifiers class'], 'P279', 20, {}) then
						table.insert(Qualifiers, snak)
					end
				end
			end
			if #Qualifiers == 0 then return {} end
		else
			return error(lib.raiseInvalidDatatype('inClass', datatype, { 'wikibase-item', 'wikibase-property' }))
		end
	end
	--[[
	if options['sort qualifiers'] then
		local Sorters = require "Modul:Wikidata/Sorters"
		Sorters.sortQualifiers(Qualifiers, options) --fixme: undefined!
	end ]]--
	applyLimit(Qualifiers, options['qualifiers limit'])
	-- @deprecated
	return Qualifiers
end

function p.filterReferences(references, options)
	local options = lib.common.cleanArgs(options)
	if options.ref == '#any' then
		-- @deprecated
		return references
	end

	local oldReferences, References = references, {}
	if options.ref == 'valid' then
		local map = (require 'Modul:Wikidata/cite').props
		for _, ref in ipairs(oldReferences) do
			for _, props in pairs(map) do
				for _, prop in ipairs(props) do
					if ref.snaks[prop] then
						table.insert(References, ref)
					end
				end
			end
		end
	end

	if options.min_ref and not checkLimit(References, options.min_ref) then
		return {}
	end
	-- @deprecated
	return References
end

return p