Modulo:Wikidata2/Filterers
Aspekto
Dokumentado por ĉi tiu modulo povas esti kreata ĉe Modulo:Wikidata2/Filterers/dokumentado
require('strict')
local p = {}
local lib = require 'Modulo:Wikidata2/lib'
local function in_array(value, array)
for _, val in ipairs(array) do
if val == value then
return true
end
end
return false
end
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, langs)
local langs = lib.textToTable(langs)
if snak.datatype ~= 'monolingualtext' then
return error(lib.raiseInvalidDatatype('isInLanguage', snak.datatype, 'monolingualtext'))
else
return lib.IsSnakValue(snak) and in_array(snak.datavalue.value.language, langs)
end
end
local function hasSnaktype(snak, somevalue, novalue)
local snaktype = snak.snaktype
if snaktype == 'somevalue' then
return somevalue or false
elseif snaktype == 'novalue' then
return novalue or false
end
return lib.IsSnakValue(snak)
end
local function hasTarget(snak, target)
local Formatters = require 'Modulo:Wikidata2/Formatters'
return tostring(Formatters.getRawValue(snak)) == tostring(target)
end
local function hasQualifier(statement, prop, value)
if statement.qualifiers then
prop = prop:upper()
for _, snak in ipairs(statement.qualifiers[prop] or {}) do
if not value or hasTarget(snak, value) then
return true
end
end
end
return false
end
local function hasRanks(statement, ranks)
return in_array(statement.rank, ranks)
end
local function hasReferences(statement, options)
if statement.references then
if #p.filterReferences(statement.references, options) > 0 then
return true
end
end
return false
end
local function hasLabel(snak)
local datatype = snak.datatype
if datatype ~= 'wikibase-item' and datatype ~= 'wikibase-property' then
return error(lib.raiseInvalidDatatype('hasLabel', datatype, { 'wikibase-item', 'wikibase-property' }))
end
if lib.IsSnakValue(snak) then
local langs = { 'cs', 'sk', 'en' }
local Formatters = require 'Modulo:Wikidata2/Formatters'
if lib.getLabelInLanguage(Formatters.getRawValue(snak), langs) then
return true
end
end
return false
end
local function hasSitelink(statement)
local datatype = statement.mainsnak.datatype
if datatype ~= 'wikibase-item' then
return error(lib.raiseInvalidDatatype('hasSitelink', datatype, { 'wikibase-item' }))
end
if lib.IsSnakValue(statement.mainsnak) then
if mw.wikibase.sitelink(Formatters.getRawValue(statement.mainsnak)) then
return true
end
end
return false
end
local function isInstance(snak, instance)
local datatype = snak.datatype
if datatype ~= 'wikibase-item' and datatype ~= 'wikibase-property' then
return error(lib.raiseInvalidDatatype('isInstance', datatype, { 'wikibase-item', 'wikibase-property' }))
end
if lib.IsSnakValue(snak) then
local Formatters = require 'Modulo:Wikidata2/Formatters'
local item = Formatters.getRawValue(snak)
if mw.wikibase.getReferencedEntityId(item, 'P279', lib.textToTable(instance)) then
return true
end
end
return false
end
local function hasUnit(statement, unit)
local datatype = statement.mainsnak.datatype
if datatype ~= 'quantity' then
return error(lib.raiseInvalidDatatype('hasUnit', datatype, { 'quantity' }))
end
if lib.IsSnakValue(statement.mainsnak) then
return (lib.getItemIdFromURI(statement.mainsnak.datavalue.value.unit) or 'Q199') == unit
else
return false
end
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 filterMainsnak(statements, callback, ...)
filter(statements, function (statement, ...)
return callback(statement.mainsnak, ...)
end, ...)
end
local function getValuesFromQualifiers(qualifiers)
local Values = {}
local Formatters = require 'Modulo:Wikidata2/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, hasRanks, { "normal", "preferred" })
if rank == "best" and #statements > 0 then
for _, statement in ipairs(statements) do
if statement.rank == "preferred" then
filter(statements, hasRanks, { "preferred" })
break
end
end
end
else
filter(statements, hasRanks, { rank })
end
if #statements == 0 then return end
end
-- apply filter by source
if options.ref then
filter(statements, hasReferences, options)
if #statements == 0 then return end
end
-- apply filter by snak type
filterMainsnak(statements, hasSnaktype, options.somevalue and true, options.novalue and true)
if #statements == 0 then return end
-- apply filter by target value
if options.withtarget then
filterMainsnak(statements, hasTarget, options.withtarget)
if #statements == 0 then return end
end
-- apply filter by qualifier property
if options.withqualifier then
filter(statements, hasQualifier, options.withqualifier, options.withqualifiervalue)
if #statements == 0 then return end
end
-- apply filter by language
if options.withlang then
filterMainsnak(statements, isInLanguage, options.withlang)
if #statements == 0 then return end
end
-- apply filter by unit
if options.withunit then
filter(statements, hasUnit, options.withunit)
if #statements == 0 then return end
end
-- apply filter by time
if options.date then
local date
local Time = require 'Modulo:Time'
if type(options.date) == 'table' then
date = options.date
elseif options.date == '#now' then
date = Time.new(os.date('!*t'))
else
date = Time.newFromIso8601(options.date)
end
if not date then
return error(lib.formatError('invalid-date', tostring(options.date)))
end
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
if date == Values.point then
filter(statements, function(st)
local val = getValuesFromQualifiers(st.qualifiers).point
if val then
return val == Values.point
end
return true
end)
table.insert(statements, statement)
elseif 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 == Values.point then
same = true
break
end
if val == Values.point or 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
return not val or val == Values.point
end)
table.insert(statements, statement)
end
end
end
else
if Values.begin then
if Values.begin < date then
if not Values.ending then
table.insert(statements, statement)
elseif date < Values.ending then
table.insert(statements, statement)
end
end
elseif Values.ending then
if date < Values.ending then
if not Values.begin then
table.insert(statements, statement)
elseif 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
filterMainsnak(statements, hasLabel)
if #statements == 0 then return end
end
if lib.IsOptionTrue(options, 'withsitelink') then
filter(statements, hasSitelink)
if #statements == 0 then return end
end
-- apply filter by class
if options.instance then
filterMainsnak(statements, isInstance, options.instance)
if #statements == 0 then return end
end
-- sort statements if needed
if options.sort then -- patří to sem?
local Sorters = require 'Modulo:Wikidata2/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)
filter(qualifiers, hasSnaktype, options['qualifiers somevalue'] and true, options['qualifiers novalue'] and true)
if #qualifiers == 0 then return end
if options['qualifiers withlang'] then
filter(qualifiers, isInLanguage, options['qualifiers withlang'])
if #qualifiers == 0 then return end
end
if lib.IsOptionTrue(options, 'qualifiers withlabel') then
filter(qualifiers, hasLabel)
if #qualifiers == 0 then return end
end
if options['qualifiers instance'] then
filter(qualifiers, isInstance, options['qualifiers instance'])
if #qualifiers == 0 then return end
end
if options['qualifiers sort'] then
local Sorters = require 'Modulo:Wikidata2/Sorters'
Sorters.sortQualifiers(qualifiers, options)
end
applyLimit(qualifiers, options['qualifiers limit'])
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 'Modulo:Wikidata2/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