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 applyLimit(sequence, limit)
	local limit = limit and tonumber(limit)
	if limit then
		while #sequence > limit do
			table.remove(sequence)
		end
	end
	return sequence
end

local function IsInLanguage(snak, lang)
	if snak.datatype ~= 'monolingualtext' then
		return error(lib.formatError('invalid-datatype', snak.property, snak.datatype, 'monolingualtext'))
	end
	if lib.IsSnakValue(snak) then
		if snak.datavalue.value.language == lang then
			return true
		end
	end
	return false
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)
	if not entity.claims[property] then
		return {}
	end

	return p.filterStatements(entity.claims[property], options)
end

function p.filterStatements(statements, options)
	local options = lib.common.cleanArgs(options)
	local Statements, oldStatements = statements, {}
	-- apply filter by rank
	if not options.rank or options.rank ~= "all" then
		oldStatements, Statements = Statements, {}
		if not options.rank or options.rank == "best" or options.rank == "valid" then
			if options.rank == "best" then
				for _, statement in pairs(oldStatements) do
					if statement.rank == "preferred" then
						table.insert(Statements, statement)
					end
				end
				if #Statements == 0 then
					for _, statement in pairs(oldStatements) do
						if statement.rank == "normal" then
							table.insert(Statements, statement)
						end
					end
				end
			else
				for _, statement in pairs(oldStatements) do
					if statement.rank ~= "deprecated" then
						table.insert(Statements, statement)
					end
				end
			end
		else
			for _, statement in pairs(oldStatements) do
				if statement.rank == options.rank then
					table.insert(Statements, statement)
				end
			end
		end
		if #Statements == 0 then return {} end
	end
	-- apply filter by source
	if options.ref then
		oldStatements, Statements = Statements, {}
		for _, statement in pairs(oldStatements) do
			if statement.references then
				if #p.filterReferences(statement.references, options) > 0 then
					table.insert(Statements, statement)
				end
			end
		end
		if #Statements == 0 then return {} end
	end
	-- apply filter by snak type
	if not lib.IsOptionTrue(options, 'showspecial') then
		oldStatements, Statements = Statements, {}
		for _, statement in pairs(oldStatements) do
			if lib.IsSnakValue(statement.mainsnak) then
				table.insert(Statements, statement)
			end
		end
		if #Statements == 0 then return {} end
	end
	-- apply filter by qualifier property
	if options.withqualifier then
		oldStatements, Statements = Statements, {}
		for _, statement in pairs(oldStatements) do
			if statement.qualifiers and statement.qualifiers[options.withqualifier:upper()] then
				table.insert(Statements, statement)
			end
		end
		if #Statements == 0 then return {} end
	end
	-- apply filter by class
	if options.class then -- TODO: separate function or handler
		local datatype = Statements[math.random(1, #Statements)].mainsnak.datatype
		if datatype == 'wikibase-item' or datatype == 'wikibase-property' then
			local class = options.class:upper()
			oldStatements, Statements = Statements, {}
			for _, statement in pairs(oldStatements) do
				if lib.IsSnakValue(statement.mainsnak) then
					local function IsInClass(id)
						local entity = mw.wikibase.getEntity(id)
						local Classes = entity:getBestStatements('P279')
						if Classes then
							for _, class in pairs(Classes) do
								if lib.IsSnakValue(class.mainsnak) then
									local id = lib.getEntityIdFromValue(class.mainsnak.datavalue.value)
									if class == id or IsInClass(id) then
										return true
									end
								end
							end
						end
						return false
					end
					local entity = mw.wikibase.getEntity(lib.getEntityIdFromValue(statement.mainsnak.datavalue.value))
					local Instances = entity:getBestStatements('P31')
					if Instances then
						for _, instance in pairs(Instances) do
							if lib.IsSnakValue(instance.mainsnak) then
								local id = lib.getEntityIdFromValue(instance.mainsnak.datavalue.value)
								if class == id or IsInClass(id) then
									table.insert(Statements, statement)
									break
								end
							end
						end
					end
				end
			end
			if #Statements == 0 then return {} end
		else
			return error(lib.formatError('invalid-datatype', options.property, datatype, 'wikibase-item/wikibase-property'))
		end
	end
	-- apply filter by language
	if options.withlang then
		oldStatements, Statements = Statements, {}
		for _, statement in pairs(oldStatements) do
			if IsInLanguage(statement.mainsnak, options.withlang) then
				table.insert(Statements, statement)
			end
		end
		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
			local Time = require 'Modul:Time'
			date = Time.newFromIso8601(options.date)
		end
		if date then
			oldStatements, Statements = Statements, {}
			local temp_value
			local Formatters = require 'Modul:Wikidata/Formatters'
			local Date = require 'Modul:Wikidata/datum'
			for _, statement in pairs(oldStatements) do
				if statement.qualifiers then
					local Values = {}
					for key, array in pairs(lib.props) do
						for _, prop in pairs(array) do
							if statement.qualifiers[prop] then
								for _, snak in pairs(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
		else
			return error(lib.formatError('invalid-date', options.date))
		end
	end
	-- sort statements if needed
	if options.sort then
		local Sorters = require "Modul:Wikidata/Sorters"
		Statements = Sorters.sortStatements(Statements, options)
	end
	-- apply filter by limit
	Statements = applyLimit(Statements, options.limit)
	return Statements
end

function p.filterQualifiers(qualifiers, options)
	local options = lib.common.cleanArgs(options)
	local Qualifiers, oldQualifiers = qualifiers, {}
	if options['withlang qualifiers'] then
		oldQualifiers, Qualifiers = Qualifiers, {}
		for _, snak in pairs(oldQualifiers) do
			if IsInLanguage(snak, options['qualifier withlang']) then
				table.insert(Qualifiers, snak)
			end
		end
	end
	if options['class qualifiers'] then
		-- TODO: wait for separate function or handler
	end
	if options['sort qualifiers'] then
		local Sorters = require "Modul:Wikidata/Sorters"
		Qualifiers = Sorters.sortQualifiers(Qualifiers, options)
	end
	Qualifiers = applyLimit(Qualifiers, options['limit qualifiers'])
	return Qualifiers
end

function p.filterReferences(references, options)
	local options = lib.common.cleanArgs(options)
	local References, oldReferences = references, {}
	if options.ref == '#any' then
		return references
	else
		oldReferences, References = References, {}
		for _, snaks in pairs(oldReferences.snaks) do
			-- TODO
		end
	end
	return References
end

function p.test()
	local time1 = os.clock()
	local entity = mw.wikibase.getEntity('Q183')
	local time2 = os.clock() - time1
	return time2, #entity.claims.P1082, #p.filterStatements(entity.claims.P1082, {})
end

return p