Module:Constraints/SPARQL/sandbox
Documentation for this module may be created at Module:Constraints/SPARQL/sandbox/doc
Code
local _lang = 'en'
local _id
local _datatype
local _fallback
local function getDatatype()
if not _datatype then
_datatype = mw.wikibase.getEntity(_id).datatype
end
return _datatype
end
local function getLanguageFallback(lang)
if not _fallback then
_fallback = mw.language.getFallbacksFor(lang)
table.insert(_fallback, 1, lang)
end
return _fallback
end
local function getService()
return string.format('SERVICE wikibase:label { bd:serviceParam wikibase:language "%s" } .',
table.concat(getLanguageFallback(_lang), ','))
end
local function notSandbox()
return 'FILTER( ?item NOT IN ( wd:Q4115189, wd:Q13406268, wd:Q15397819 ) ) .'
end
local function getSpecificData(var)
local datatype = getDatatype()
local vars = {}
if datatype == 'monolingualtext' then
table.insert(vars, '(LANG(' .. var .. ') AS ?lang)')
end
if datatype == 'wikibase-item' or datatype == 'wikibase-property' then
table.insert(vars, var .. 'Label')
end
return table.concat(vars, ' ')
end
local function processCallback(data)
return function(param)
local split = mw.text.split(param, ';')
local param, prefix, delim = split[1], split[2] or 'wd:', split[3] or ''
if type(data[param]) == 'table' then
return prefix .. table.concat(data[param], delim .. ' ' .. prefix)
else
return data[param]
end
end
end
local function processPattern(pattern, data)
return string.gsub(pattern, '%{%{%{([^%}]+)%}%}%}', processCallback(data))
end
function queryAsURL(query, text)
return string.format('[https://query.wikidata.org/#%s %s]', mw.uri.encode(query, 'PATH'), text or 'SPARQL')
end
local p = {}
function p.buildInverse(property)
-- "property" could also be from statements?
local pattern = [[SELECT ?item ?itemLabel ?should_link_via_{{{property}}}_to ?should_link_via_{{{property}}}_toLabel
WHERE
{
?should_link_via_{{{property}}}_to wdt:{{{id}}} ?item .
FILTER NOT EXISTS { ?item wdt:{{{property}}} ?should_link_via_{{{property}}}_to } .
{{{service}}}
}
LIMIT 100]]
local query = processPattern(pattern, {
id = _id,
property = property,
service = getService(),
})
return queryAsURL(query)
end
function p.buildSingleValue()
local pattern = [[SELECT DISTINCT ?item ?itemLabel ?count ?sample1 {{{specific1}}} ?sample2 {{{specific2}}} ?exception
WITH {
SELECT ?formatter WHERE {
OPTIONAL { wd:{{{id}}} wdt:P1630 ?formatter }
} LIMIT 1
} AS %formatter
WHERE
{
{
SELECT ?item (COUNT(?value) AS ?count) (MIN(?value) AS ?sample1) (MAX(?value) AS ?sample2) {
?item p:{{{id}}} [ ps:{{{id}}} ?val; wikibase:rank ?rank ] .
FILTER( ?rank != wikibase:DeprecatedRank ) .
INCLUDE %formatter .
BIND( IF( BOUND( ?formatter ), URI( REPLACE( ?formatter, '\\$1', ?val ) ), ?val ) AS ?value ) .
} GROUP BY ?item HAVING ( ?count > 1 ) LIMIT 100
} .
OPTIONAL {
wd:{{{id}}} p:P2302 [ ps:P2302 wd:Q19474404; pq:P2303 ?exc ] .
FILTER( ?exc = ?item ) .
} .
BIND( BOUND( ?exc ) AS ?exception ) .
{{{service}}}
}
ORDER BY DESC(?count)]]
local query = processPattern(pattern, {
id = _id,
service = getService(),
specific1 = getSpecificData('?sample1'),
specific2 = getSpecificData('?sample2'),
})
return queryAsURL(query)
end
function p.buildSingleBestValue()
local pattern = [[SELECT DISTINCT ?item ?itemLabel ?count ?sample1 {{{specific1}}} ?sample2 {{{specific2}}} ?exception
WITH {
SELECT ?formatter WHERE {
OPTIONAL { wd:{{{id}}} wdt:P1630 ?formatter }
} LIMIT 1
} AS %formatter
WHERE
{
{
SELECT ?item (COUNT(?value) AS ?count) (MIN(?value) AS ?sample1) (MAX(?value) AS ?sample2) {
?item wdt:{{{id}}} ?val .
INCLUDE %formatter .
BIND( IF( BOUND( ?formatter ), URI( REPLACE( ?formatter, '\\$1', ?val ) ), ?val ) AS ?value ) .
} GROUP BY ?item HAVING ( ?count > 1 ) LIMIT 100
} .
OPTIONAL {
wd:{{{id}}} p:P2302 [ ps:P2302 wd:Q52060874; pq:P2303 ?exc ] .
FILTER( ?exc = ?item ) .
} .
BIND( BOUND( ?exc ) AS ?exception ) .
{{{service}}}
}
ORDER BY DESC(?count)]]
local query = processPattern(pattern, {
id = _id,
service = getService(),
specific1 = getSpecificData('?sample1'),
specific2 = getSpecificData('?sample2'),
})
return queryAsURL(query)
end
function p.buildSymmetric()
local pattern = [[SELECT ?item ?itemLabel ?value ?valueLabel
WHERE
{
{
SELECT DISTINCT ?item ?value {
?item p:{{{id}}}/ps:{{{id}}} ?value .
MINUS {
?value p:{{{id}}}/ps:{{{id}}} ?item .
} .
}
LIMIT 100
} .
{{{service}}}
}]]
local query = processPattern(pattern, {
id = _id,
service = getService(),
})
return queryAsURL(query)
end
function p.buildQualifiers(list)
local pattern = [[SELECT ?item ?itemLabel ?prop ?propLabel ?rank ?value {{{specific}}}
WHERE
{
?item p:{{{id}}} [ ?pq ?value; wikibase:rank ?rank ] .
?prop wikibase:qualifier ?pq .
FILTER( ?prop NOT IN ( {{{list;wd:;,}}} ) ) .
{{{service}}}
}
LIMIT 100]]
local query = processPattern(pattern, {
id = _id,
list = list,
service = getService(),
specific = getSpecificData('?value'),
})
return queryAsURL(query)
end
function p.buildMandatoryQualifiers(list)
-- todo: no qualifiers
local pattern = [[SELECT ?item ?itemLabel ?prop ?propLabel ?rank ?value {{{specific}}}
WHERE
{
?item p:{{{id}}} ?statement .
VALUES ?pq { {{{list;pq:}}} } .
OPTIONAL {
?statement ?pq ?qualif .
} .
FILTER( !BOUND( ?qualif ) ) .
?prop wikibase:qualifier ?pq .
?statement wikibase:rank ?rank; ps:{{{id}}} ?value .
{{{service}}}
}
LIMIT 100]]
local query = processPattern(pattern, {
id = _id,
list = list,
service = getService(),
specific = getSpecificData('?value'),
})
return queryAsURL(query)
end
function p.buildMultiValue()
local pattern = [[SELECT ?item ?itemLabel ?sample {{{specific}}}
WHERE
{
{
SELECT ?item (COUNT(?value) AS ?count) (SAMPLE(?value) AS ?sample) {
?item wdt:{{{id}}} ?value .
}
GROUP BY ?item
HAVING ( ?count = 1 )
}
{{{service}}}
}
LIMIT 100]]
local query = processPattern(pattern, {
id = _id,
service = getService(),
specific = getSpecificData('?sample'),
})
return queryAsURL(query)
end
function p.buildUniqueValue()
local pattern = [[#Unique value constraint report for {{{id}}}: report listing each item
SELECT DISTINCT ?item1 ?item1Label ?item2 ?item2Label ?value {{{specific}}}
{
?item1 wdt:{{{id}}} ?value .
?item2 wdt:{{{id}}} ?value .
FILTER( ?item1 != ?item2 && STR( ?item1 ) < STR( ?item2 ) ) .
{{{service}}}
}
LIMIT 100]]
local query = processPattern(pattern, {
id = _id,
service = getService(),
specific = getSpecificData('?value'),
})
return queryAsURL(query, 'SPARQL (every item)')
end
function p.buildUniqueValueByValue()
local pattern = [[# Unique value constraint report for {{{id}}}: report by value
SELECT
?value (SAMPLE(?valueLabel) AS ?valueLabel) (SAMPLE(?ct) AS ?ct)
(GROUP_CONCAT(DISTINCT(STRAFTER(STR(?item), "/entity/")); separator=", ") AS ?items)
(GROUP_CONCAT(DISTINCT(?itemLabel); separator=", ") AS ?itemLabels)
WHERE
{
{ SELECT ?value (COUNT(DISTINCT ?item) as ?ct)
WHERE
{
?item wdt:{{{id}}} ?value
}
GROUP BY ?value HAVING (?ct>1)
ORDER BY DESC(?ct)
LIMIT 100
}
?item wdt:{{{id}}} ?value .
SERVICE wikibase:label {
bd:serviceParam wikibase:language "{{{lang;;,}}}" .
?item rdfs:label ?itemLabel .
?value rdfs:label ?valueLabel .
}
}
GROUP BY ?value
ORDER BY DESC(?ct)]]
local query = processPattern(pattern, {
id = _id,
lang = getLanguageFallback(_lang),
})
return queryAsURL(query, 'SPARQL (by value)')
end
function p.buildOneOf(values, neg)
local pattern = [[SELECT ?item ?itemLabel ?value ?valueLabel ?snak ?rank ?statement
WHERE
{
{
SELECT ?item ?value ?result ?snak ?rank ?statement WHERE {
{
?item p:{{{id}}} ?statement .
?statement ps:{{{id}}} ?value; wikibase:rank ?rank .
BIND("mainsnak" AS ?snak) .
} UNION {
?statement pq:{{{id}}} ?value; wikibase:rank ?rank .
?item ?p1 ?statement .
BIND("qualifier" AS ?snak) .
} UNION {
?ref pr:{{{id}}} ?value .
?statement prov:wasDerivedFrom ?ref; wikibase:rank ?rank .
?item ?p2 ?statement .
BIND("reference" AS ?snak) .
} .
FILTER( ?value {{{NOT}}} IN ( {{{values;wd:;,}}} ) ) .
} LIMIT 100
} .
{{{service}}}
}]]
local query = processPattern(pattern, {
id = _id,
NOT = (neg and '') or 'NOT',
service = getService(),
values = values,
})
return queryAsURL(query)
end
function p.buildScope(scopes)
-- todo: ?snak -> ?aspect with detail about "parent" property
local map = {
Q54828448 = [[
?item p:{{{id}}}/ps:{{{id}}} ?value .
BIND(wd:Q54828448 AS ?scope) .
]],
Q54828449 = [[
?statement pq:{{{id}}} ?value .
?item ?p ?statement .
FILTER(?p != p:P1855) .
BIND(wd:Q54828449 AS ?scope) .
]],
Q54828450 = [[
?ref pr:{{{id}}} ?value .
?statement prov:wasDerivedFrom ?ref .
?item ?p ?statement .
BIND(wd:Q54828450 AS ?scope) .
]],
}
local pattern = [[SELECT ?item ?itemLabel ?value {{{specific}}} ?scopeLabel
WHERE
{
{
SELECT DISTINCT ?item ?value ?scope
WHERE
{
{{{inside}}}
} LIMIT 100
} .
{{{sandbox}}}
{{{service}}}
}]]
local inside = {}
local ok = {}
for _, scope in ipairs(scopes) do
ok[scope] = true
end
for scope, pattern in pairs(map) do
if not ok[scope] then
table.insert(inside, pattern)
end
end
if #inside == 1 then
inside = processPattern(inside[1], { id = _id })
else
inside = processPattern('{\n' .. table.concat(inside, '} UNION {\n') .. '}', { id = _id })
end
local query = processPattern(pattern, {
id = _id,
inside = inside,
sandbox = notSandbox(),
service = getService(),
specific = getSpecificData('?value'),
})
return queryAsURL(query)
end
function p.buildType(relationProp, classes)
local pattern = [[SELECT ?item ?itemLabel {{{relationVar}}} {{{relationVar}}}Label
WHERE
{
{
SELECT DISTINCT ?item {{{relationVar}}} {
?item wdt:{{{id}}} [] .
MINUS {
VALUES ?classes { {{{classes;wd:}}} } .
?item {{{ifInstance}}}wdt:P279* ?classes .
} .
OPTIONAL {
?item wdt:{{{relationProp}}} {{{relationVar}}} .
} .
} LIMIT 100
} .
{{{service}}}
}]]
local vars = {
P31 = '?instance',
P279 = '?class',
}
local query = processPattern(pattern, {
classes = classes,
id = _id,
ifInstance = (relationProp == 'P31' and 'wdt:P31/') or '',
relationProp = relationProp,
relationVar = vars[relationProp],
service = getService(),
})
return queryAsURL(query)
end
function p.buildValueType(relationProp, classes)
local pattern = [[SELECT ?item ?itemLabel ?value ?valueLabel {{{relationVar}}} {{{relationVar}}}Label ?snak
WHERE
{
{
SELECT DISTINCT ?item ?value {{{relationVar}}} ?snak {
{
?item wdt:{{{id}}} ?value .
BIND("mainsnak" AS ?snak) .
} UNION {
?statement0 pq:{{{id}}} ?value .
?item ?p0 ?statement0 .
BIND("qualifier" AS ?snak) .
} UNION {
?ref pr:{{{id}}} ?value .
?statement1 prov:wasDerivedFrom ?ref .
?item ?p1 ?statement1 .
BIND("reference" AS ?snak) .
} .
MINUS {
VALUES ?classes { {{{classes;wd:}}} } .
?value {{{ifInstance}}}wdt:P279* ?classes .
} .
OPTIONAL {
?value wdt:{{{relationProp}}} {{{relationVar}}} .
} .
} LIMIT 100
} .
{{{service}}}
}]]
local vars = {
P31 = '?instance',
P279 = '?class',
}
local query = processPattern(pattern, {
classes = classes,
id = _id,
ifInstance = (relationProp == 'P31' and 'wdt:P31/') or '',
relationProp = relationProp,
relationVar = vars[relationProp],
service = getService(),
})
return queryAsURL(query)
end
function p.buildRequiredClaim(property, values)
if #values > 1 then
return
end
local pattern = [[# Other properties generally found on items with {{{id}}}.
# Limited to statements with best rank (wdt:), exceptions not filtered
# query added by Jura1, 2017-08-03
SELECT ?item ?itemLabel ?itemDescription ?value ?valueLabel
WHERE
{
?item wdt:{{{id}}} ?value .
FILTER NOT EXISTS { ?item ]]
if #values == 0 then
pattern = pattern .. " p:{{{property}}} []"
else
pattern = pattern .. " wdt:{{{property}}} {{{values}}}"
end
pattern = pattern .. [[ }
{{{service}}}
}
LIMIT 1000]]
local query = processPattern(pattern, {
id = _id,
property = property,
values = values,
service = getService(),
})
return queryAsURL(query, 'SPARQL')
end
function p.buildTargetRequiredClaim(property, values)
local pattern = [[#Target required claim report for {{{id}}}: report listing each item and value
SELECT ?item ?itemLabel ?value ?valueLabel {{{export1}}}{{{export2}}}?snak
WHERE
{
{
SELECT DISTINCT ?item ?value {{{export1}}}?snak
WHERE
{
{
?item p:{{{id}}}/ps:{{{id}}} ?value .
BIND("mainsnak" AS ?snak) .
} UNION {
?statement0 pq:{{{id}}} ?value .
?item ?p0 ?statement0 .
BIND("qualifier" AS ?snak) .
} UNION {
?ref pr:{{{id}}} ?value .
?statement1 prov:wasDerivedFrom ?ref .
?item ?p1 ?statement1 .
BIND("reference" AS ?snak) .
} .
{{{block}}}
} LIMIT 100
} .
{{{service}}}
}]]
local block, export1, export2
if #values > 0 then
block = processPattern(
[[VALUES ?values { {{{values;wd:}}} } .
MINUS {
?value p:{{{property}}}/ps:{{{property}}} ?values .
} .
OPTIONAL {
?value p:{{{property}}}/ps:{{{property}}} ?target .
} .]],
{
property = property,
values = values,
})
export1 = '?target '
export2 = '?targetLabel '
else
block = processPattern('MINUS { ?value p:{{{property}}} [] } .', {
property = property
})
export1 = ''
export2 = ''
end
local query = processPattern(pattern, {
block = block,
export1 = export1,
export2 = export2,
id = _id,
property = property,
service = getService(),
values = values,
})
return queryAsURL(query)
end
function p.buildTargetRequiredClaimByValue(property, values)
if #values > 0 then
return
end
local pattern = [[#Target required claim report for {{{id}}}: report by values used
#Limited to values in best rank (wdt), exceptions not filtered
#Query added by Jura1, 2017-08-01; 2018-08-19
SELECT ?value ?valueLabel ?valueDescription ?ct
WHERE
{
{
SELECT ?value (COUNT(DISTINCT ?item) as ?ct)
WHERE
{
?item wdt:{{{id}}} ?value .
MINUS { ?value p:{{{property}}} [] }
}
GROUP BY ?value ORDER BY DESC(?ct) ?value LIMIT 1000
}
{{{service}}}
}
ORDER BY DESC(?ct) ?value]]
local query = processPattern(pattern, {
id = _id,
property = property,
service = getService(),
})
return queryAsURL(query, 'SPARQL (by value)')
end
function p.buildFormat(regex)
local pattern = [[SELECT ?item ?itemLabel ?value ?result (STRLEN(STR(?value)) AS ?stringlength) {{{specific}}} ?snak ?rank
WHERE
{
{
SELECT ?item ?value ?result ?snak ?rank
WHERE
{
{
?item p:{{{id}}} [ ps:{{{id}}} ?value; wikibase:rank ?rank ] .
BIND("mainsnak" AS ?snak) .
} UNION {
?statement1 pq:{{{id}}} ?value;
wikibase:rank ?rank .
?item ?p1 ?statement1 .
BIND("qualifier" AS ?snak) .
} UNION {
?ref pr:{{{id}}} ?value .
?statement2 prov:wasDerivedFrom ?ref;
wikibase:rank ?rank .
?item ?p2 ?statement2 .
BIND("reference" AS ?snak) .
} .
BIND( REGEX( STR( ?value ), "{{{regex}}}" ) AS ?regexresult ) .
FILTER( ?regexresult = false ) .
BIND( IF( ?regexresult = true, "pass", "fail" ) AS ?result ) .
{{{not_sandbox}}}
}
LIMIT 100
} .
{{{service}}}
}
#ORDER BY ?rank ?snak ?value
#PLEASE NOTE: This is experimental and may only work for simple patterns.
#Tests may fail due to:
#(1) differences in regex format between SPARQL (https://www.w3.org/TR/xpath-functions/#regex-syntax) and PCRE (used by constraint reports). Don't change the regex to work with SPARQL!
#(2) some bug in the link that brought you here
#Known to fail: P227 (multiple curly braces), P274, P281]]
local PatternConv = require 'Module:PatternConv'
local query = processPattern(pattern, {
id = _id,
not_sandbox = notSandbox(),
regex = PatternConv._replace2({ source = regex }),
service = getService(),
specific = getSpecificData('?value'),
})
return queryAsURL(query)
end
function p.buildConflictsWith(property, values)
local pattern
if #values > 0 then
pattern = [[SELECT ?item ?itemLabel ?property ?propertyLabel ?value ?valueLabel
WHERE
{
{
SELECT DISTINCT ?item ?property ?value {
?item wdt:{{{id}}} [] .
VALUES ?value { {{{values;wd:}}} } .
?item wdt:{{{property}}} ?value .
BIND( wd:{{{property}}} AS ?property ) .
} LIMIT 100
} .
{{{service}}}
}]]
else
pattern = [[SELECT ?item ?itemLabel ?property ?propertyLabel ?value ?valueLabel
WHERE
{
{
SELECT DISTINCT ?item ?property ?value {
?item wdt:{{{id}}} []; wdt:{{{property}}} ?value .
BIND( wd:{{{property}}} AS ?property ) .
} LIMIT 100
} .
{{{service}}}
}]]
end
local query = processPattern(pattern, {
id = _id,
property = property,
values = values,
service = getService(),
})
return queryAsURL(query)
end
function p.buildNoBounds()
-- todo: other scopes
local pattern = [[
SELECT ?item ?itemLabel ?value ?lower ?upper ?diff WHERE {
?item p:{{{id}}}/psv:{{{id}}} [
wikibase:quantityAmount ?value;
wikibase:quantityLowerBound ?lower;
wikibase:quantityUpperBound ?upper
] .
BIND( ( ?upper - ?lower ) / 2 AS ?diff ) .
{{{sandbox}}}
{{{service}}}
}]]
local query = processPattern(pattern, {
id = _id,
sandbox = notSandbox(),
service = getService(),
})
return queryAsURL(query)
end
function p.buildContemporary()
local pattern = [[
SELECT DISTINCT ?subject ?value WHERE {
?subject wdt:{{{id}}} ?value .
OPTIONAL { ?subject p:P569/psv:P569 [ wikibase:timeValue ?subject_birth ; wikibase:timePrecision "11"^^xsd:integer ] . }
OPTIONAL { ?value p:P569/psv:P569 [ wikibase:timeValue ?value_birth ; wikibase:timePrecision "11"^^xsd:integer ] . }
OPTIONAL { ?subject p:P571/psv:P571 [ wikibase:timeValue ?subject_inception ; wikibase:timePrecision "11"^^xsd:integer ] . }
OPTIONAL { ?value p:P571/psv:P571 [ wikibase:timeValue ?value_inception ; wikibase:timePrecision "11"^^xsd:integer ] . }
OPTIONAL { ?subject p:P580/psv:P580 [ wikibase:timeValue ?subject_start ; wikibase:timePrecision "11"^^xsd:integer ] . }
OPTIONAL { ?value p:P580/psv:P580 [ wikibase:timeValue ?value_start ; wikibase:timePrecision "11"^^xsd:integer ] . }
OPTIONAL { ?subject p:P570/psv:P570 [ wikibase:timeValue ?subject_death ; wikibase:timePrecision "11"^^xsd:integer ] . }
OPTIONAL { ?value p:P570/psv:P570 [ wikibase:timeValue ?value_death ; wikibase:timePrecision "11"^^xsd:integer ] . }
OPTIONAL { ?subject p:P576/psv:P576 [ wikibase:timeValue ?subject_dissolution ; wikibase:timePrecision "11"^^xsd:integer ] . }
OPTIONAL { ?value p:P576/psv:P576 [ wikibase:timeValue ?value_dissolution ; wikibase:timePrecision "11"^^xsd:integer ] . }
OPTIONAL { ?subject p:P582/psv:P582 [ wikibase:timeValue ?subject_end ; wikibase:timePrecision "11"^^xsd:integer ] . }
OPTIONAL { ?value p:P582/psv:P582 [ wikibase:timeValue ?value_end ; wikibase:timePrecision "11"^^xsd:integer ] . }
FILTER ((!BOUND(?subject_birth) || ((!BOUND(?value_death) || ?subject_birth>?value_death) && (!BOUND(?value_dissolution) || ?subject_birth>?value_dissolution) && (!BOUND(?value_end) || ?subject_birth>?value_end))) && (!BOUND(?value_birth) || ((!BOUND(?subject_death) || ?value_birth>?subject_death) && (!BOUND(?subject_dissolution) || ?value_birth>?subject_dissolution) && (!BOUND(?subject_end) || ?value_birth>?subject_end))) && (!BOUND(?subject_inception) || ((!BOUND(?value_death) || ?subject_inception>?value_death) && (!BOUND(?value_dissolution) || ?subject_inception>?value_dissolution) && (!BOUND(?value_end) || ?subject_inception>?value_end))) && (!BOUND(?value_inception) || ((!BOUND(?subject_death) || ?value_inception>?subject_death) && (!BOUND(?subject_dissolution) || ?value_inception>?subject_dissolution) && (!BOUND(?subject_end) || ?value_inception>?subject_end))) && (!BOUND(?subject_start) || ((!BOUND(?value_death) || ?subject_start>?value_death) && (!BOUND(?value_dissolution) || ?subject_start>?value_dissolution) && (!BOUND(?value_end) || ?subject_start>?value_end))) && (!BOUND(?value_start) || ((!BOUND(?subject_death) || ?value_start>?subject_death) && (!BOUND(?subject_dissolution) || ?value_start>?subject_dissolution) && (!BOUND(?subject_end) || ?value_start>?subject_end))) && ((BOUND(?subject_birth) && (BOUND(?value_death) || BOUND(?value_dissolution) || BOUND(?value_end))) || (BOUND(?value_birth) && (BOUND(?subject_death) || BOUND(?subject_dissolution) || BOUND(?subject_end))) || (BOUND(?subject_inception) && (BOUND(?value_death) || BOUND(?value_dissolution) || BOUND(?value_end))) || (BOUND(?value_inception) && (BOUND(?subject_death) || BOUND(?subject_dissolution) || BOUND(?subject_end))) || (BOUND(?subject_start) && (BOUND(?value_death) || BOUND(?value_dissolution) || BOUND(?value_end))) || (BOUND(?value_start) && (BOUND(?subject_death) || BOUND(?subject_dissolution) || BOUND(?subject_end)))))
}
LIMIT 200]]
local query = processPattern(pattern, {
id = _id,
})
return queryAsURL(query)
end
function p.buildUnits()
-- todo: other scopes
local pattern = [[
SELECT ?item ?unit ?exception
WHERE
{
{
SELECT ?item ?unit
WHERE
{
?item p:{{{id}}} ?stmnode.
?stmnode psv:{{{id}}} ?valuenode.
?valuenode wikibase:quantityUnit ?unit.
}
}.
OPTIONAL {
wd:{{{id}}} p:P2302 [ ps:P2302 wd:Q21514353; pq:P2303 ?exc ] .
FILTER( ?exc = ?item ) .
} .
BIND( BOUND( ?exc ) AS ?exception ) .
}]]
local query = processPattern(pattern, {
id = _id,
})
return queryAsURL(query)
end
function p.buildInteger()
-- todo: other scopes
local pattern = [[
SELECT ?item ?itemLabel ?value WHERE {
?item p:{{{id}}}/psv:{{{id}}}/wikibase:quantityAmount ?value .
FILTER( xsd:integer( ?value ) != ?value ) .
{{{sandbox}}}
{{{service}}}
}]]
local query = processPattern(pattern, {
id = _id,
sandbox = notSandbox(),
service = getService(),
})
return queryAsURL(query)
end
function p.buildDescriptionLanguage(property, languageCodes)
local pattern
pattern = [[SELECT ?item ?itemLabel ?value
WHERE
{
{
SELECT DISTINCT ?item ?property ?value {
?item wdt:{{{property}}} ?value .
MINUS { ?item schema:description ?description .
FILTER( {{{filter}}} ) }
} LIMIT 100
} .
{{{service}}}
}]]
local filter = ""
for i, languageCode in pairs(languageCodes) do
if i>1 then
filter = filter .. "||"
end
filter = filter .. "LANG(?description)=\"" .. languageCode .. "\""
end
local query = processPattern(pattern, {
id = _id,
property = property,
filter = filter,
service = getService(),
})
return queryAsURL(query)
end
function p.buildLabelLanguage(property, languageCodes)
local pattern
pattern = [[SELECT ?item ?itemLabel ?value
WHERE
{
{
SELECT DISTINCT ?item ?property ?value {
?item wdt:{{{property}}} ?value .
MINUS { ?item rdfs:label ?label .
FILTER( {{{filter}}} ) }
} LIMIT 100
} .
{{{service}}}
}]]
local filter = ""
for i, languageCode in pairs(languageCodes) do
if i>1 then
filter = filter .. "||"
end
filter = filter .. "LANG(?label)=\"" .. languageCode .. "\""
end
local query = processPattern(pattern, {
id = _id,
property = property,
filter = filter,
service = getService(),
})
return queryAsURL(query)
end
function p.buildNewSPARQL(uuid)
local pattern = [[
# Note: before https://phabricator.wikimedia.org/T201150 is fixed, the result will only be partial
SELECT DISTINCT ?item ?itemLabel ?value WHERE {
?statement wikibase:hasViolationForConstraint wds:{{{constraint}}} .
?item ?p ?statement .
[] wikibase:claim ?p; wikibase:statementProperty ?ps.
?statement ?ps ?value.
{{{sandbox}}}
{{{service}}}
}
]]
local query = processPattern(pattern, {
constraint = table.concat(mw.text.split(uuid, '$', true), '-'),
sandbox = notSandbox(),
service = getService(),
})
return '<span title="before T201150 is fixed, the result will only be partial.">' .. queryAsURL(query, 'SPARQL (new)') .. '</span>'
end
function p.setLanguage(lang)
_lang = lang
_fallback = nil
end
function p.setId(id)
_id = id
_datatype = nil
end
function p.setDatatype(datatype)
_datatype = datatype
end
return p