Modul:Wikidata/Filterers
Vzhled
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 hasSnakTarget(snak, target)
local Formatters = require 'Modul:Wikidata/Formatters'
return Formatters.getRawValue(snak) == target
end
local function filterHasTarget(statement, target)
return hasSnakTarget(statement.mainsnak, target)
end
local function filterHasQualifier(statement, prop, value)
if statement.qualifiers then
prop = prop:upper()
for _, snak in ipairs(statement.qualifiers[prop] or {}) do
if not value or hasSnakTarget(snak, value) then
return true
end
end
end
return false
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)
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 langs = { 'cs', 'en', 'sk' }
local Formatters = require 'Modul:Wikidata/Formatters'
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
local function getValuesFromQualifiers(qualifiers)
local Values = {}
local Formatters = require 'Modul:Wikidata/Formatters'
for key, array in pairs(lib.props) do
for _, prop in ipairs(array) do
for _, snak in ipairs(qualifiers[prop] or {}) do
if lib.IsSnakValue(snak) then
Values[key] = Formatters.getRawValue(snak)
break
end
end
end
end
return Values
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, options.withqualifiervalue)
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 Date = require 'Modul:Wikidata/datum'
local oldStatements = mw.clone(statements)
while #statements > 0 do table.remove(statements) end
for _, statement in ipairs(oldStatements) do
local Values = getValuesFromQualifiers(statement.qualifiers or {})
if Values.point then
local strict = false
if Date.AreDatesSame(date, Values.point, strict) then
filter(statements, function (st)
local val = getValuesFromQualifiers(st.qualifiers).point
if val then
return Date.AreDatesSame(val, Values.point, strict)
end
return true
end)
table.insert(statements, statement)
elseif Date.IsSecondLaterThanFirst(Values.point, date) then
if #statements == 0 then
table.insert(statements, statement)
else
local same, ins
for _, st in ipairs(statements) do
local val = getValuesFromQualifiers(st.qualifiers).point
if val then
if Date.AreDatesSame(date, Values.point, strict) then
same = true
break
end
if (Date.AreDatesSame(val, Values.point, strict) or
Date.IsSecondLaterThanFirst(val, Values.point)) then
ins = true
end
end
end
if ins and not same then
filter(statements, function (st)
local val = getValuesFromQualifiers(st.qualifiers).point
if val then
return Date.AreDatesSame(val, Values.point, strict)
end
return true
end)
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
if #statements == 0 then return end
end
if lib.IsOptionTrue(options, 'withlabel') then
filter(statements, filterItemHasLabel)
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