Lua
CodeDiscussionLinksLink count SubpagesDocumentationTestsResultsSandboxLive code All modules

Code

local sparql = require "Module:SPARQL" 
local ppath = require "Module:PropertyPath" 
local tool = require "Module:Tools"
local func = require "Module:Luafun"


-- Module that generate queries for classes items.
-- especially queries to find instances of those classes


-- lua tuple (pair) implementation, see http://lua-users.org/wiki/FunctionalTuples
local function Def(_class, _stmts)
  return function(fn) return fn(_class, _stmts) end
end
local function class(_class, _stmts) return _class end
local function stmts(_class, _stmts) return _stmts end


-- generates a truthy statement pattern for a property value pair
local function truthy_pair_gp(prop, val)
	return " wdt:" .. prop .. " wd:" .. val
end

local walk = ppath.iterate

-- buildding a graph pattern for truthy staetements
local function truthy_stmt_gp_atom(item, prop, val)
	return item .. truthy_pair_gp(prop, val)
end

-- buildding a graph pattern for qualifier snaks
local function qualifier_snak_gp(prop, val)
	return "pq:" .. prop .. " wd:" .. val
end


local function truthy_stmt_gp(item, propval_pairs)
	return item .. table.concat(
			propval_pairs, 
		", ")
end

local p = {}

-- generates a partial query to find any instance item of one class or its subclasses
-- that are explicitely linked to a class 
p.query_explicit_instances = function (class_id, var)
	local init = var or ""
	return init .. " wdt:P31/wdt:P279* " .. "wd:".. class_id
end
	
p.query_implicit_instances = function(class, var_name)
	if not var_name or var_name == "" then
		var_name = "item"
	end
	
	var_name = sparql.create_var(var_name)
	
	local stmts = {}
	
	if not class then error("the class_id provided to generate the query in query implicit instances is nil") end
	
	for has_quality_stmt in walk(class,"wdt:P279*/p:P1552") do
        if has_quality_stmt:item_value() == "Q47524457" then -- only statements with "instances statements as qualifiers" special value
            for qualifier_snak in walk(has_quality_stmt, (">!()")) do
            	if qualifier_snak:has_an_item() then -- TODO: manage other datatypes restrictions
					stmts[#stmts + 1] = truthy_stmt_gp_atom(var_name, qualifier_snak.property, qualifier_snak:item_value())
				end
			end
		end
	end
	local vars = {}
	vars[1] = var_name 
	return sparql.pi(vars, sparql.intersect(stmts))
end

-- testing with « Q38043002 »

-- function to find explicit instances of a class, as well as « implicit instances » ( see documentation, eg. [[Template:query all instances]] )
p.query_any_instances = function(class_id, var_name)
	if not var_name or var_name == "" then
		var_name = "item"
	end
	local class_stmts_pairs = {}
	var_name = sparql.create_var(var_name)
	
	for has_quality_stmt in walk(class_id, "wdt:P279*/p:P1552") do
	    if has_quality_stmt:item_value() == "Q47524457" then -- only statements with "instances statements as qualifiers" special value
	    	local instances_snak_gp = {}
            for qualifier_snak in walk(has_quality_stmt, ">!()") do
            	if qualifier_snak:has_an_item() then -- TODO: manage other datatypes restrictions
					instances_snak_gp[#instances_snak_gp + 1] = truthy_pair_gp(qualifier_snak.property, qualifier_snak:item_value())
				end
			end
			class_stmts_pairs[#class_stmts_pairs + 1] = Def(
				has_quality_stmt.parent:item_value(), 
				instances_snak_gp
			)
		end
	end
	
	local last = class_stmts_pairs[#class_stmts_pairs]
	return func.iter(class_stmts_pairs):take_n(#class_stmts_pairs - 1):reduce(
		function(acc, nextcp) 
			return sparql.union({ 
				p.query_explicit_instances(nextcp(class), var_name), 
				sparql.intersect({
					truthy_stmt_gp(var_name, nextcp(stmts)),
					acc
				}),
			})
		end,
		sparql.union({ 
			p.query_explicit_instances(last(class), var_name), 
			truthy_stmt_gp(var_name, last(stmts))
		})
	)
end

--[[ 
     functions to generate a query that finds items with statements with a certain main snak, 
     either because they actually have a statement with that main snak 
     or because they are explicit instances of a class that bears it in « has quality »
     
     WIP
     
--]]
p.item_by_statement = function(var_name, property, value)
	if not var_name or var_name == "" then
		var_name = "item"
	end	
	
	var_name = sparql.create_var(var_name)
	
	return sparql.union{
		var_name .. truthy_pair_gp(property, value), 
		var_name .. " wdt:P31/wdt:P279*/p:P1552 " .. "[ps:P1552 wd:Q47524457 ;" .. qualifier_snak_gp(property, value) .. "]"
	}
end


p.query_implicit_instance_template = function(frame)
	return p.query_implicit_instances(frame.args[1], frame.args[2])
end

p.query_any_instance_template = function(frame)
	return p.query_any_instances(frame.args[1], frame.args[2])
end

p.query_any_statement_template = function(frame)
	return p.item_by_statement(frame.args[1], frame.args[2], frame.args[3])
end

return p