Module:Constraints

local wd       = require('Module:Wikidata') local fb       = require('Module:Fallback') local dtype    = require('Module:Datatype') local TableTools= require('Module:TableTools') local SPARQL   = require('Module:Constraints/SPARQL') local search   = require('Module:Constraints/search') local i18n_msgs = mw.loadData('Module:i18n/constraints')

local defaultlang = mw.getCurrentFrame:preprocess("")

local pConstraint         = "P142" local pFormatPattern      = "P148" local pProperty           = "P341" local pItems              = "P340" local pClasses            = "P237" local pRelation           = "P238" local pMinQuantity        = "P543" local pMaxQuantity        = "P544" local pMinDate            = "P545" local pMaxDate            = "P546" local pNamespace          = "P471" local pMandatory          = "P286" local pGroupBy            = "P547" local pExceptions         = "P349" local pInstanceOf         = "P3" local pSubclassOf         = "P12" local pComment            = "P347" local pComment2           = "P346" local pSeparator          = "P348" local pConstraintScope    = "P339" local pPropertyScope      = "P338" local pLanguageCode       = "P334"

local pReplacementProperty = "P396" local pReplacementValue = "P395"

local cMandatory          = "Q678" local cSuggested          = "Q669"

local cInstanceOf         = "Q788" local cSubclassOf         = "Q1737" local cInstanceOfSubclassOf= "Q1739"

local cSingleValue        = "Q794" local cSingleBestValue    = "Q803" local cFormat             = "Q673" local cUniqueValue        = "Q776" local cConflictsWith      = "Q798" local cItem               = "Q668" local cType               = "Q620" local cQualifiers         = "Q795" local cCommonsLink        = "Q1042" local cDiffWithinRange    = "Q1740" --local cDiffWithinRangeWithLink = "Q1740" local cInverse            = "Q885" local cMultiValue         = "Q797" local cOneOf              = "Q782" local cRange              = "Q1736" local cSymmetric          = "Q814" local cTargetRequiredClaim = "Q796" local cValueType          = "Q789" local cUnits              = "Q1741" local cMandatoryQualifiers = "Q804" local cContemporary       = "Q834" local cNoBounds           = "Q1742" local cInteger            = "Q1743" local cNoneOf             = "Q942" local cScope              = "Q779" local cEntityType         = "Q1735" local cCitationNeeded     = "Q841" local cOneofQualifierValue = "Q1744" -- test local cLexemeCategory     = "Q1745" local cLexemeValueCategory = "Q1746" local cLexemeLanguage     = "Q1750" local cLabelLanguage      = "Q1751"

local cSomevalue          = 'somevalue' local cNovalue            = 'novalue'

local cAllConstraints = {	cSingleValue, cSingleBestValue, cFormat, cUniqueValue, cConflictsWith, cItem, cType, cQualifiers, cCommonsLink, cDiffWithinRange, --	cDiffWithinRangeWithLink, cInverse, cMultiValue, cOneOf, cRange, cSymmetric, cTargetRequiredClaim, cValueType, cUnits, cMandatoryQualifiers, cContemporary, cNoBounds, cInteger, cNoneOf, cScope, cEntityType, cCitationNeeded, cLexemeCategory, cLexemeValueCategory, cLexemeLanguage, cLabelLanguage, cOneofQualifierValue, }

local cItemonlyConstraints    = { cContemporary } local cItemOrPropertyonlyConstraints    = {cInverse, cOneOf, cSymmetric, cValueType, cTargetRequiredClaim, cNoneOf} local cQuantityonlyConstraints = { cUnits, cNoBounds, cInteger }

local cFormatapplicable = {"math","commonsMedia","string","external-id","url","monolingualtext","tabular-data","geo-shape","musical-notation"} local cCommonsLinkapplicable = {"commonsMedia","geo-shape","string","tabular-data"} local cRangeapplicable = {"quantity","time"} -- also cDiffWithinRange

local function i18n(str) return fb._langSwitch(i18n_msgs[str], defaultlang) end

local function throw(error_type, ...) error(string.format(i18n(error_type), ...), 0); end

local function wikifyQKey(id) local label = wd._getLabel(id, defaultlang) return "" .. label .. " (" .. id .. ") " end

local function wikifyPKey(id) local label = wd._getLabel(id, defaultlang) return "" .. label .. " (" .. id .. ") " end

local function wikifyQKeys(ids) local values = {} for _, id in pairs(ids) do		if id == cSomevalue then table.insert(values, "somevalue") elseif id == cNovalue then table.insert(values, "novalue") elseif #ids > 100 then table.insert(values, "" .. id .. "") else table.insert(values, wikifyQKey(id)) end end return table.concat(values, ", "); end

local function wikifyPKeys(ids) local values = {} for _, id in pairs(ids) do		table.insert(values, wikifyPKey(id)) end return table.concat(values, ", "); end

local function contains(array, value) for i = 1, #array do		if array[i] == value then return true end end

return false end

local function hasQualifier(statement, qualifier_id) return (statement ~= nil) and (statement.qualifiers ~= nil) and (statement.qualifiers[qualifier_id] ~= nil) and (#(statement.qualifiers[qualifier_id]) > 0) end

local function getQualifierSingleValue( statement, qualifier_id ) if hasQualifier(statement, qualifier_id) == false then throw("error_missing_qualifier", wikifyPKey(qualifier_id)); end

local qualifiers = statement.qualifiers[qualifier_id] if (#qualifiers > 1) then error("Too many qualifiers " .. wikifyPKey(qualifier_id), 0); end

local qualifier = qualifiers[1]

if (qualifier.snaktype == "somevalue") then return cSomevalue; elseif (qualifier.snaktype == "novalue") then return cNovalue; end

if (qualifier.datavalue == nil	   or qualifier.datavalue.type == nil	    or qualifier.datavalue.value == nil) then error("Unexpected qualifier " .. wikifyPKey(qualifier_id) .. " value", 0); end

if (qualifier.datavalue.type == "wikibase-entityid") then if (qualifier.datavalue.value["entity-type"] == "property") then return "P" .. qualifier.datavalue.value["numeric-id"]; else return "Q" .. qualifier.datavalue.value["numeric-id"]; end else return wd.formatSnak(qualifier, { displayformat = 'raw' }); end end

local function getQualifierValues( statement, qualifier_id ) local result = {} if hasQualifier(statement, qualifier_id) then for _, qualifier in pairs(statement.qualifiers[qualifier_id]) do			if (qualifier.snaktype == "somevalue") then table.insert(result, cSomevalue) elseif (qualifier.snaktype == "novalue") then table.insert(result, cNovalue) elseif (qualifier.datavalue == nil			   or qualifier.datavalue.type == nil			    or qualifier.datavalue.value == nil) then table.insert(result, nil) else if ( qualifier.datavalue.type == "string" ) then table.insert(result, qualifier.datavalue.value); elseif ( qualifier.datavalue.type == "wikibase-entityid" ) then if (qualifier.datavalue.value["entity-type"] == "property") then table.insert(result, "P" .. qualifier.datavalue.value["numeric-id"]); else table.insert(result, "Q" .. qualifier.datavalue.value["numeric-id"]); end else error("Unknown qualifier type: " .. qualifier.datavalue.type, 0); end end end end return result; end

local function getQualifierAtLeastOneValue(statement, qualifier_id) local result = getQualifierValues(statement, qualifier_id) if #result == 0 then throw("error_missing_qualifier", wikifyPKey(qualifier_id)); end return result end

local function isMandatoryConstraint(constraint) if hasQualifier(constraint, pMandatory) then local value = getQualifierSingleValue(constraint, pMandatory) if value == cMandatory then return "true" elseif value ~= cSuggested then throw("error_unsupported_value", wikifyPKey(pMandatory), wikifyQKey(cMandatory)) end end return "" end

local function getOneOfQualifiers(constraint, qualifier_id1, qualifier_id2) if hasQualifier(constraint, qualifier_id1) then return getQualifierSingleValue(constraint, qualifier_id1) else return getQualifierSingleValue(constraint, qualifier_id2) end end

local function getTypeRelation(constraint) local relation = getQualifierSingleValue(constraint, pRelation)

if (relation == cInstanceOf) then return pInstanceOf elseif (relation == cSubclassOf) then return pSubclassOf elseif (relation == cInstanceOfSubclassOf) then return pInstanceOf,pSubclassOf else throw("error_unsupported_value", wikifyPKey(pRelation), wikifyQKeys({cInstanceOf, cSubclassOf})) end end

local function getConstraintDescription(constraint, constraint_entity, property_id) --TODO: if somevalue or novalue is misused, it currently displays a module error, or unrelated number 0 or 1 local type = constraint_entity.id	local res = {}

if (type == cSingleValue) then res.caption    = i18n("single_value_caption") res.description = i18n("single_value_description") res.query      = table.concat( {			SPARQL.buildSingleValue,			--SPARQL.buildNewSPARQL(constraint.id), disabled per T274982		}, ', ' ) res.category   = "Properties with single value constraints"

elseif (type == cSingleBestValue) then res.caption    = i18n("single_best_value_caption") res.description = i18n("single_best_value_description") res.query      = table.concat( {			SPARQL.buildSingleBestValue,			--SPARQL.buildNewSPARQL(constraint.id), disabled per T274982		}, ', ' ) res.category   = "Properties with single best value constraints"

elseif (type == cFormat) then res.caption    = string.format(i18n("format_caption"), 				" ") res.description = i18n("format_description") res.query      = table.concat( {			SPARQL.buildFormat(getQualifierSingleValue(constraint, pFormatPattern)),			--SPARQL.buildNewSPARQL(constraint.id), disabled per T274982		}, ', ' ) res.category   = "Properties with format constraints"

elseif (type == cUniqueValue) then res.caption    = i18n("unique_value_caption") res.description = i18n("unique_value_description") res.query      = table.concat( {			SPARQL.buildUniqueValue,			SPARQL.buildUniqueValueByValue,			--SPARQL.buildNewSPARQL(constraint.id), disabled per T274982		}, ', ' ) res.category   = "Properties with unique value constraints"

elseif (type == cConflictsWith) then local value = wikifyPKey(getQualifierSingleValue(constraint, pProperty)) if hasQualifier(constraint, pItems) then value = value .. ": " .. wikifyQKeys(getQualifierValues(constraint, pItems)) end res.caption    = string.format(i18n("conflicts_with_caption"), value) res.description = i18n("conflicts_with_description") res.query = table.concat( TableTools.compressSparseArray( { search.buildConflictsWith(				getQualifierSingleValue(constraint, pProperty),				getQualifierValues(constraint, pItems)			), SPARQL.buildConflictsWith(				getQualifierSingleValue(constraint, pProperty),				getQualifierValues(constraint, pItems)			), --SPARQL.buildNewSPARQL(constraint.id), disabled per T274982 } ), ', ' )		res.category   = "Properties with conflicts with constraints"

elseif (type == cItem) then local value = wikifyPKey(getQualifierSingleValue(constraint, pProperty)) if hasQualifier(constraint, pItems) then value = value .. ": " .. wikifyQKeys(getQualifierValues(constraint, pItems)) end res.caption    = string.format(i18n("item_caption"),     value) res.description = string.format(i18n("item_description"), value) res.query = table.concat( TableTools.compressSparseArray( { search.buildRequiredClaim(				getQualifierSingleValue(constraint, pProperty),				getQualifierValues(constraint, pItems)			), SPARQL.buildRequiredClaim(				getQualifierSingleValue(constraint, pProperty),				getQualifierValues(constraint, pItems)			), --SPARQL.buildNewSPARQL(constraint.id), disabled per T274982 } ), ', ' )		res.category   = "Properties with constraints on items using them"

elseif (type == cOneofQualifierValue) then local value = wikifyPKey(getQualifierSingleValue(constraint, pProperty)) if hasQualifier(constraint, pItems) then value = value .. ": " .. wikifyQKeys(getQualifierValues(constraint, pItems)) end res.caption    = "Qualifier:" .. string.format(i18n("item_caption"),    value) res.description = "test: qualifier should use one of the values listed" -- string.format(i18n("OneofQualifierValue_description"), value) res.category   = "Properties with constraints on for values of qualifiers being used"

elseif (type == cType) then local types = wikifyQKeys(getQualifierAtLeastOneValue(constraint, pClasses)) res.caption    = string.format(i18n("type_caption"), types) res.description = string.format(i18n("type_description"), wikifyPKey(getTypeRelation(constraint)), types) res.query      = table.concat( {			SPARQL.buildType( getTypeRelation(constraint), getQualifierAtLeastOneValue(constraint, pClasses) ),			--SPARQL.buildNewSPARQL(constraint.id), disabled per T274982		}, ', ' ) res.category   = "Properties with constraints on type"

elseif (type == cQualifiers) then local qualifiers = getQualifierValues(constraint, pProperty) if qualifiers[1] == cNovalue then res.caption    = i18n("without_qualifier_caption") res.description = i18n("without_qualifier_description") --res.query      = SPARQL.buildNewSPARQL(constraint.id) disabled per T274982 else res.caption    = string.format(i18n("qualifiers_caption"), wikifyPKeys(getQualifierValues(constraint, pProperty))) res.description = i18n("qualifiers_description") res.query      = table.concat( {				SPARQL.buildQualifiers(qualifiers),				--SPARQL.buildNewSPARQL(constraint.id), disabled per T274982			}, ', ' ) end res.category   = "Properties with qualifiers constraints" elseif (type == cCommonsLink) then res.caption    = string.format(i18n("commons_caption"), hasQualifier(constraint, pNamespace) and getQualifierSingleValue(constraint, pNamespace) or "") --Better message needed for main namespace res.description = i18n("commons_description") --res.query      = SPARQL.buildNewSPARQL(constraint.id) disabled per T274982 res.category   = "Properties with Commons link constraints"

elseif (type == cDiffWithinRange) then local prop = wikifyPKey(getQualifierSingleValue(constraint, pProperty)) local min = getQualifierSingleValue(constraint, pMinQuantity) if min == cNovalue then min = "−∞" end local max = getQualifierSingleValue(constraint, pMaxQuantity) if max == cNovalue then max = "+∞" end res.caption    = string.format(i18n("difference_caption"),     prop, min, max) res.description = string.format(i18n("difference_description"), prop, min, max) --res.query      = SPARQL.buildNewSPARQL(constraint.id) disabled per T274982 res.category   = "Properties with difference within range constraints"

--	elseif (type == cDiffWithinRangeWithLink) then --		local prop = wikifyPKey(getQualifierSingleValue(constraint, pProperty)) --		local min = getQualifierSingleValue(constraint, pMinQuantity) --		if min == cNovalue then --			min = "−∞" --		end --		local max = getQualifierSingleValue(constraint, pMaxQuantity) --		if max == cNovalue then --			max = "+∞" --		end --		local itemlinkprop = wikifyPKey(getQualifierSingleValue(constraint, pProperty)) --		res.caption    = string.format(i18n("difference_with_link_caption"),     prop, itemlinkprop, min, max) --		res.description = string.format(i18n("difference_with_link_description"), prop, itemlinkprop, min, max) --		res.query      = SPARQL.buildNewSPARQL(constraint.id) disabled per T274982

elseif (type == cInverse) then res.caption    = string.format(i18n("inverse_caption"),     wikifyPKey(getQualifierSingleValue(constraint, pProperty))) res.description = string.format(i18n("inverse_description"), wikifyPKey(property_id), wikifyPKey(getQualifierSingleValue(constraint, pProperty))) res.query      = table.concat( {			SPARQL.buildInverse(getQualifierSingleValue(constraint, pProperty)),			--SPARQL.buildNewSPARQL(constraint.id), disabled per T274982		}, ', ' ) res.category   = "Properties with inverse constraints"

elseif (type == cMultiValue) then res.caption    = i18n("multi_value_caption") res.description = i18n("multi_value_description") res.query      = table.concat( {			SPARQL.buildMultiValue,			--SPARQL.buildNewSPARQL(constraint.id), disabled per T274982		}, ', ' ) res.category   = "Properties with multi value constraints"

elseif (type == cOneOf) then res.caption    = string.format(i18n("one_of_caption"), wikifyQKeys(getQualifierValues(constraint, pItems))) res.description = i18n("one_of_description") res.query      = table.concat( TableTools.compressSparseArray( { search.buildOneOf(getQualifierValues(constraint, pItems)), SPARQL.buildOneOf(getQualifierValues(constraint, pItems)), --SPARQL.buildNewSPARQL(constraint.id), disabled per T274982 } ), ', ' )		res.category   = "Properties with one-of constraints"

elseif (type == cLexemeCategory) then res.caption    = string.format(i18n("lexeme_category_caption"), wikifyQKeys(getQualifierValues(constraint, pItems))) res.description = i18n("lexeme_category_description") --res.query      = SPARQL.buildNewSPARQL(constraint.id) disabled per T274982 res.category   = "Properties with lexical category constraints"

elseif (type == cLexemeValueCategory) then res.caption    = string.format(i18n("lexeme_value_category_caption"), wikifyQKeys(getQualifierValues(constraint, pItems))) res.description = i18n("lexeme_value_category_description") res.query      = "" -- SPARQL.buildNewSPARQL(constraint.id) disabled per T274982 res.category   = "Properties with lexical category constraints on value"

elseif (type == cLexemeLanguage) then res.caption    = string.format(i18n("lexeme_language_caption"), wikifyQKeys(getQualifierValues(constraint, pItems))) res.description = i18n("lexeme_language_description") --res.query      = SPARQL.buildNewSPARQL(constraint.id) disabled per T274982 res.category   = "Properties with lexeme language constraints"

elseif (type == cRange) then local min = getOneOfQualifiers(constraint, pMinQuantity, pMinDate) if min == cNovalue then min = "−∞" end if min == cSomevalue then min = i18n("now") end local max = getOneOfQualifiers(constraint, pMaxQuantity, pMaxDate) if max == cNovalue then max = "+∞" end if max == cSomevalue then max = i18n("now") end res.caption    = string.format(i18n("range_caption"),     min, max) res.description = string.format(i18n("range_description"), min, max) --res.query      = SPARQL.buildNewSPARQL(constraint.id) disabled per T274982 res.category   = "Properties with range constraints"

elseif (type == cSymmetric) then res.caption    = i18n("symmetric_caption") res.description = i18n("symmetric_description") res.query      = table.concat( {			SPARQL.buildSymmetric,			--SPARQL.buildNewSPARQL(constraint.id), disabled per T274982		}, ', ' ) res.category   = "Properties with symmetric constraints"

elseif (type == cTargetRequiredClaim) then local value = wikifyPKey(getQualifierSingleValue(constraint, pProperty)) if hasQualifier(constraint, pItems) then value = value .. ": " .. wikifyQKeys(getQualifierValues(constraint, pItems)) end res.caption    = string.format(i18n("target_item_caption"),     value) res.description = string.format(i18n("target_item_description"), value) res.query      = table.concat( TableTools.compressSparseArray( { SPARQL.buildTargetRequiredClaim(				getQualifierSingleValue(constraint, pProperty),				getQualifierValues(constraint, pItems)			), SPARQL.buildTargetRequiredClaimByValue(				getQualifierSingleValue(constraint, pProperty),				getQualifierValues(constraint, pItems)			), --SPARQL.buildNewSPARQL(constraint.id), disabled per T274982 } ), ', ' )		res.category   = "Properties with target required claim constraints"

elseif (type == cValueType) then local types = wikifyQKeys(getQualifierAtLeastOneValue(constraint, pClasses)) res.caption    = string.format(i18n("value_type_caption"), types) res.description = string.format(i18n("value_type_description"), wikifyPKey(getTypeRelation(constraint)), wikifyPKey(getTypeRelation(constraint)), types) res.query      = table.concat( {			SPARQL.buildValueType( getTypeRelation(constraint), getQualifierAtLeastOneValue(constraint, pClasses) ),			--SPARQL.buildNewSPARQL(constraint.id), disabled per T274982		}, ', ' ) res.category   = "Properties with constraints on type"

elseif (type == cUnits) then if hasQualifier(constraint, pItems) then local units = wikifyQKeys(getQualifierValues(constraint, pItems)) res.caption    = string.format(i18n("units_caption"),     units) res.description = string.format(i18n("units_description"), units) --res.query = SPARQL.buildNewSPARQL(constraint.id) disabled per T274982 else res.caption    = i18n("nounits_caption") res.description = i18n("nounits_description") res.query      = table.concat( {				SPARQL.buildUnits,				--SPARQL.buildNewSPARQL(constraint.id), disabled per T274982			}, ', ' ) end res.category   = "Properties with units constraints"

elseif (type == cMandatoryQualifiers) then res.caption    = string.format(i18n("mandatory_qualifier_caption"), wikifyPKey(getQualifierSingleValue(constraint, pProperty))) -- fixme: multiple? res.description = i18n("mandatory_qualifier_description") res.query      = table.concat( {			SPARQL.buildMandatoryQualifiers(getQualifierValues(constraint, pProperty)),			--SPARQL.buildNewSPARQL(constraint.id), disabled per T274982		}, ', ' ) res.category   = "Properties with required qualifiers constraints"

elseif (type == cContemporary) then res.caption    = string.format(i18n("contemporary_caption")) res.description = string.format(i18n("contemporary_description"), wikifyPKey(property_id)) res.query      = table.concat( {			SPARQL.buildContemporary,			--SPARQL.buildNewSPARQL(constraint.id), disabled per T274982		}, ', ' ) res.category   = "Properties with contemporary constraints"

elseif (type == cNoBounds) then res.caption    = string.format(i18n("nobounds_caption")) res.description = string.format(i18n("nobounds_description")) res.query      = table.concat( {			SPARQL.buildNoBounds,			--SPARQL.buildNewSPARQL(constraint.id), disabled per T274982		}, ', ' ) res.category   = "Properties with no bounds constraints"

elseif (type == cInteger) then res.caption    = string.format(i18n("integer_caption")) res.description = string.format(i18n("integer_description")) res.query      = table.concat( {			SPARQL.buildInteger,			--SPARQL.buildNewSPARQL(constraint.id), disabled per T274982		}, ', ' ) res.category   = "Properties with integer constraints"

elseif (type == cNoneOf) then res.caption    = string.format(i18n("none_of_caption"), wikifyQKeys(getQualifierValues(constraint, pItems))) res.description = i18n("none_of_description") res.description = res.description .. " " .. string.format(i18n("none_of_description2"), wikifyPKeys(getQualifierValues(constraint, pReplacementProperty))) -- fixme: skip if no pReplacementProperty res.description = res.description .. " " .. string.format(i18n("none_of_description3"), wikifyQKeys(getQualifierValues(constraint, pReplacementValue))) -- fixme: skip if no pReplacementValue res.query      = table.concat( {			SPARQL.buildOneOf(getQualifierValues(constraint, pItems), true),			--SPARQL.buildNewSPARQL(constraint.id), disabled per T274982		}, ', ' ) res.category   = "Properties with none-of constraints"

elseif (type == cScope) then res.caption    = string.format(i18n("scope_caption"), wikifyQKeys(getQualifierValues(constraint, pPropertyScope))) res.description = i18n("scope_description") res.query      = table.concat( {			SPARQL.buildScope(getQualifierValues(constraint, pPropertyScope)),			--SPARQL.buildNewSPARQL(constraint.id), disabled per T274982		}, ', ' ) res.category   = "Properties with scope constraints"

elseif (type == cEntityType) then res.caption    = string.format(i18n("entity_type_caption"), wikifyQKeys(getQualifierValues(constraint, pItems))) res.description = i18n("entity_type_description") --res.query      = SPARQL.buildNewSPARQL(constraint.id) disabled per T274982 res.category   = "Properties with entity type constraints" elseif (type == cCitationNeeded) then res.caption    = string.format(i18n("citation_needed_caption")) res.description = i18n("citation_needed_description") --res.query      = SPARQL.buildNewSPARQL(constraint.id) disabled per T274982 res.category   = "Properties with citation needed constraints" -- elseif (type == cLabelLanguage) then -- res.caption    = string.format(i18n("label_language_caption"),getQualifierValues(constraint, pLanguageCode)) -- res.description = i18n("label_language_description",getQualifierValues(constraint, pLanguageCode)) -- res.query      = SPARQL.buildNewSPARQL(constraint.id) disabled per T274982 -- res.category   = "Properties with label language constraints"

else throw("error_unsupported_value", wikifyPKey(pConstraint), wikifyQKeys(cAllConstraints));

end return res end

local function getConstraintAnchor(constraint, constraint_entity) -- "P152":[{"mainsnak":{"snaktype":"value","property":"P152","datavalue":{"value":{"text":"Format","language":"en"}

local anchor = constraint_entity.claims.P1813[1].mainsnak.datavalue.value.text for _, statement in ipairs(constraint_entity.claims.P152) do		if statement.mainsnak.datavalue.value.language == "en" then anchor = statement.mainsnak.datavalue.value.text break end end

local type = constraint_entity.id	if (type == cItem) or (type == cTargetRequiredClaim) or (type == cConflictsWith) then anchor = anchor .. " " .. getQualifierSingleValue(constraint, pProperty) elseif (type == cType) or (type == cValueType) then anchor = anchor .. " " .. table.concat(getQualifierValues(constraint, pClasses), ", ") end

return anchor end

local function getConstraintImage(constraint_entity) return constraint_entity.claims.P386[1].mainsnak.datavalue.value end

local function verifyConstraintType(type) if not contains(cAllConstraints, type) then throw("error_unsupported_value", wikifyPKey(pConstraint), wikifyQKeys(cAllConstraints)); end end

local function verifyPropertyDatatype(constraint_type, property_datatype) if (property_datatype ~= "wikibase-item") and contains(cItemonlyConstraints, constraint_type) then throw("error_only_datatype", dtype.display("wikibase-item", defaultlang)); elseif (property_datatype ~= "wikibase-item") and (property_datatype ~= "wikibase-property") and contains(cItemOrPropertyonlyConstraints, constraint_type) then throw("error_invalid_datatype", dtype.display(property_datatype, defaultlang)); elseif (property_datatype ~= "quantity") and contains(cQuantityonlyConstraints, constraint_type) then throw("error_only_datatype", dtype.display("quantity", defaultlang)); elseif (constraint_type == cCommonsLink) and (not(contains(cCommonsLinkapplicable, property_datatype))) then throw("error_invalid_datatype", dtype.display(property_datatype, defaultlang)); elseif (constraint_type == cFormat) and (not(contains(cFormatapplicable, property_datatype))) then throw("error_invalid_datatype", dtype.display(property_datatype, defaultlang)); elseif (constraint_type == cRange) and (not(contains(cRangeapplicable, property_datatype))) then throw("error_invalid_datatype", dtype.display(property_datatype, defaultlang)); elseif (constraint_type == cDiffWithinRange) and (not(contains(cRangeapplicable, property_datatype))) then throw("error_invalid_datatype", dtype.display(property_datatype, defaultlang)); end end

local function verifyConstraintQualifier(qualifier, constraint_entity) local accepted_properties = { pMandatory, pExceptions, pGroupBy, pComment, pComment2, pSeparator, pConstraintScope, pPropertyScope, pConstraintEntityType, pReplacementProperty, pReplacementValue, pLanguageCode }

if contains(accepted_properties, qualifier) then return true; end

if constraint_entity.claims.P167 ~= nil then for i, value in pairs(constraint_entity.claims.P167) do local accepted_prop = "P" .. value.mainsnak.datavalue.value["numeric-id"] if qualifier == accepted_prop then return true end table.insert(accepted_properties, accepted_prop) end end

throw("error_unsupported_qualifier", wikifyPKey(qualifier), wikifyPKeys(accepted_properties)); end

local function verifyQualifiers(constraint, constraint_entity) if (constraint.qualifiers ~= nil) then for key, value in pairs(constraint.qualifiers) do			verifyConstraintQualifier(key, constraint_entity) end end end

local function getExceptions(constraint) local exceptions -- todo: allow exception lists from several items if hasQualifier(constraint, pExceptions) then exceptions = getQualifierAtLeastOneValue(constraint, pExceptions) end local text = "" local sep = "" if exceptions ~= nil then if #exceptions<21 then for i, exception in pairs(exceptions) do text = text .. sep .. wikifyQKey(exception) if sep == "" then sep = ", " end end else for i, exception in pairs(exceptions) do text = text .. sep .. "" .. exception .. "" if sep == "" then sep = ", " end end end end return text end

local function makeConstraintDocumentation(constraint, property_id, property_datatype, add_category_to_page) local constraint_type = "Q" .. constraint.mainsnak.datavalue.value["numeric-id"] local constraint_entity = mw.wikibase.getEntity(constraint_type) local constraint_help = constraint_entity:getSitelink("wikidatawiki") local constraint_help_link if (constraint_help ~= nil) then constraint_help = "Special:MyLanguage/" .. constraint_help constraint_help_link = "(" .. constraint_help .. ")" else constraint_help = "" constraint_help_link = "" end

verifyConstraintType(constraint_type) verifyPropertyDatatype(constraint_type, property_datatype) verifyQualifiers(constraint, constraint_entity) local data = getConstraintDescription(constraint, constraint_entity, property_id) local category_text if add_category_to_page == true then category_text = "" else category_text = "" end return mw.getCurrentFrame:preprocess(		"" .. category_text) end

local function makeConstraintDocumentationSafe(constraint, property_id, property_datatype, add_category_to_page) local status, result = pcall(makeConstraintDocumentation, constraint, property_id, property_datatype, add_category_to_page) if status then return result else local constraint_type = "Q" .. constraint.mainsnak.datavalue.value["numeric-id"] return "" .. string.format(i18n("error_in_constraint"), wikifyQKey(constraint_type), result) .. " "	end end

local p = {}

function p.extractIndividualConstraintTemplate(frame) local id = frame.args['id'] local constraint_type = frame.args['constraint_type'] local propertyentity = mw.wikibase.getEntity(id) if propertyentity == nil then return "" .. "Error: " .. frame:preprocess("Property:" .. id .. "") .. " doesn't exist." ..				" "	end local property_datatype = propertyentity.datatype local constraints      = (propertyentity.claims or {})[pConstraint] local add_category_to_page = false

SPARQL.setLanguage(defaultlang) SPARQL.setId(id) SPARQL.setDatatype(property_datatype)

local text = '' if constraints ~= nil then for i, constraint in pairs(constraints) do			if constraint.mainsnak.datavalue.value["id"] == constraint_type then text = text .. makeConstraintDocumentationSafe(constraint, id, property_datatype, add_category_to_page) return text end end end

return "" .. "Error: " .. frame:preprocess("") .. " is not defined at " .. frame:preprocess(".") .. " " end

function p.makedoc(frame) local id = frame:preprocess("")

local propertyentity = mw.wikibase.getEntity(id) local property_datatype = propertyentity.datatype local constraints      = (propertyentity.claims or {})[pConstraint] local add_category_to_page = true

SPARQL.setLanguage(defaultlang) SPARQL.setId(id) SPARQL.setDatatype(property_datatype)

search.setLanguage(defaultlang) search.setId(id) search.setDatatype(property_datatype)

local text = '' if constraints ~= nil then for i, constraint in pairs(constraints) do			if constraint.rank ~= 'deprecated' then text = text .. makeConstraintDocumentationSafe(constraint, id, property_datatype, add_category_to_page) end end end

return text end

-- temporary functions for migration period

function p.getCaption(frame) return string.format(i18n(frame.args[1] .. "_caption"), frame.args[2], frame.args[3], frame.args[4], frame.args[5]) end

function p.getDescription(frame) return string.format(i18n(frame.args[1] .. "_description"), frame.args[2], frame.args[3], frame.args[4], frame.args[5]) end

return p