Modul:SimpleDataAccess

Dies ist eine alte Version dieser Seite, zuletzt bearbeitet am 15. November 2022 um 02:03 Uhr durch Vollbracht (Diskussion | Beiträge). Sie kann sich erheblich von der aktuellen Version unterscheiden.
Vorlagenprogrammierung Diskussionen Lua Unterseiten
Modul Deutsch English

Modul: Dokumentation

Diese Seite enthält Code in der Programmiersprache Lua. Einbindungszahl Cirrus


--[=[ SimpleDataAccess 2022-07-03
Data Management Module for simplified Access from Within Other Modules:
All functions return first values only.

Author: Vollbracht
* qualifyingValue(statement, propQual)		wikiData first qualifier value
* statementQualOrMainSnack(qualifier, property, propQual)	first value
* MainSnakValue(qualifier, property)		wikiData first main snack value
* indirectMSValue(qualifier, properties)	wikiData first main snack value
* qualifiersLineup(qualifier, property)		sequence of wikiData qualifiers
* 
]=]
	
--Module globals

local _, GeneralTime = pcall(require, "Modul:Wikidata/Time")
local Time = GeneralTime.service

local service = {}

--------------------------- local functions -----------------------------

--[[
	statements(object, property, all)
	Have calling functions work with all of:
		params to call an mw.wikibase statement fetch function,
		wikibase entity and param to call its statement fetch method
		allready fetched statement table.
	Functions that are known to have one properties set type only should use the
	applying statement fetch function or method directly instead!
]]
local statements = function(object, property, all)
	if type(object) == 'string' then
		if not property then return nil end
		if all then return mw.wikibase.getAllStatements(object, property) end
		return mw.wikibase.getBestStatements(object, property)
	end
	if object.getBestStatements then
		if not property then return nil end
		if all then return object:getAllStatements(property) end
		return object:getBestStatements(property)
	end
	return object
end

--[[
	unwrap(<source>)
	object value of a given source: this function simplifies by ignoring a lot
	like language e.g.
	this function drops all object values if table and not
		* time
		* text
		* id
	enhance this function at will:
		process additional table object values as follows:
				return <return object>, 'f'
				have <return object>:format(fmtString)
			or
				return <return object>, <new type>
				enhance getSimple(...) and getList(...) then as well
	parameters:
		source	mainsnak, mainsnak.datavalue, mainsnak.datavalue.value or
				qualifier item
	returns:	(value text, value time, value id, simple type value or nil) and
				type of value:
					f	if formatable
					id	if Q123... - string
					result of format(value) in all other cases
]]
local unwrap = function(source)
	if not source then return nil end
	if type(source) == 'table' then
		if source.datavalue then source = source.datavalue end
		if source.value then source = source.value end
		if source.text then return source.text, 'string' end
		if source.time then return Time:new(source.time), 'f' end
		if source.id then return source.id, 'id' end
		return nil
	end
	return source, type(source)
end

--[[
	getSimple
	text value of a given value
	parameters:
		value as of mainsnak.datavalue.value
	returns:	simple data value:
				value (if no table), value.text, or label of value.id
]]
local function getSimple(value, t)
	if not t then value, t = unwrap(value) end
	if not value then return '' end
	if t == 'f' then return value:format() end
	if t == 'id' then
		local label = mw.wikibase.getLabel(value)
		if label then return label
		else
			mw.log('result entity w/o label')
			mw.logObject(mw.wikibase.getEntity(value))
			return value
		end
	end
	return value
end

local get1stStatement = function(qualifier, property, test)
	if qualifier == nil or qualifier == "" then
		mw.log('no qualifier given for statement retrival')
		return ""
	end
	local statementList = statements(qualifier, property)
	if test then
		if not statementList or #statementList == 0 then
			mw.logObject(statementList, qualifier .. '.' .. property)
			local all = nil
			if type(qualifier) == "table" then
				all = qualifier:getAllStatements(property)
				mw.logObject(all, 'all of this')
			else
				all = mw.wikibase.getAllStatements(qualifier, property)
				mw.logObject(all, 'all of ' .. qualifier)
			end
			if not all or #all == 0 then
				all = mw.wikibase.getEntity(qualifier)
				mw.logObject(all, 'all of entity: ' .. qualifier)
			end
		else mw.logObject(statementList) end
	end
	if statementList and type(statementList) == "table" then
		local result = statementList[1]
		if type(result) == "table" then
			return result
		end
	end
	mw.log('no data: (' .. qualifier .. '.' .. property .. '):')
	return ""
end

-- obsolete, use Modul:Wikidata/Time or Modul:Time instead -->
service.time = { MATCHING = Time.MATCHING, PRECISIONLEVEL = Time.PRECISIONLEVEL,
	DEFAULTFORMAT = Time.DEFAULTFORMAT, lessthan = Time.lessthan,
	format = Time.format, timify = Time.timify
}
function service.time:new(source)
	mw.log('indirect (avoid!)')
	return Time:new(source)
end
-- <--obsolete--

--[[
	snacks(object, <P...>, <all>)
	snak values table:
		either all main snaks of a wikidata object defined by property
		or all snaks of a statement qualifying its mainsnak by property
	parameters:
		object:		wikidata source:
						qualifier string <Q...> of a wikidata object or
						statement table as of mw.wikibase.getBestStatements or
						single statement beeing source for qualifying snaks
		property:	defining source statement qualifier string <P...> for
						getBestStatements or
						filtering qualifying snaks
					ignored if source object is table {[1]=..., [2]= ..., ...}
		all:		use getAllStatements instead of getBestStatements
					ignored if source object is table
]]
service.getSnaks = function(object, property, all)
	if not object then return nil end
	if type(object) == 'string' then
		object = object:match('Q%d+')
		if not object then return nil end
		if not property then return nil end
		if all then object = mw.wikibase.getAllStatements(object, property)
		else object = mw.wikibase.getBestStatements(object, property) end
	elseif type(object) == 'table' then
		if object.qualifiers and object.qualifiers[property] then
			object = object.qualifiers[property]
		elseif object[property] then
			object = object[property]
		end
		if not object[1] then return nil end
	else return nil end
	local result = {}
	if object[1].mainsnak then
		for _, v in ipairs(object) do
			local r = unwrap(v.mainsnak)
			if r then table.insert(result, r) end
		end
	else
		for _, v in ipairs(object) do
			local r = unwrap(v)
			if r then table.insert(result, r) end
		end
	end
	return result
end

--[[
	getList(<object>, <property>, <all>, <value type>, <separator string>)
	statement mainsnak values comma or separator string separated
	parameters:
		object:		wikidata source:
						qualifier string <Q...> of a wikidata object or
						statement table as of mw.wikibase.getBestStatements or
						single statement beeing source for qualifying snaks
		property:	defining source statement qualifier string <P...> for
						getBestStatements or
						filtering qualifying snaks
					ignored if source object is table {[1]=..., [2]= ..., ...}
		all:		use getAllStatements instead of getBestStatements
					ignored if source object is table
		vType:		additional process information
		sep:		separator string
	returns:	string
]]
service.SnakList = function(object, property, all, vType, fmtString, sep)
	local source = service.getSnaks(object, property, all)
	if not source then return '' end
	if not sep then sep = ', ' end
	if not vType then return table.concat(source, sep) end
	local result = {}
	if vType == 'f' then
		for _, v in ipairs(source) do
			table.insert(result, v:format(fmtString))
		end
	elseif vType == 'id' then
		for _, v in ipairs(source) do
			local label = mw.wikibase.getLabel(v)
			if label then table.insert(result,label)
			else
				mw.log('result entity w/o label')
				mw.logObject(mw.wikibase.getEntity(value))
				table.insert(result, v)
			end
		end
	else result = source end
	return table.concat(result, sep)
end

--[[
	WD:qualifiedSnaks(Object, property, {{}})
	limit a list of statements
	parameters:
		target	either a table containing a list of statements
				or an object name (Q1234, e.g.)
		claim	name of a property to get a statement list if target is name
		qualificators	struct of elements by which list of statements may be
						qualified
						currently knowing qualificators.time only:
						if given only those statements are returned that share
						the same time (not before start = P580 e.g.)
]]
service.qualifiedSnaks = function(this, target, claim, qualificators)
	local result = {}
	condInclude = function(statement)
		if not statement then return nil, false end
		if not statement.qualifiers then
			return statement.datavalue.value, false
		end
	end
	if not target then return nil end
	if type(target) == 'string' then
		target = target:match('Q%d+')
		if not target then return nil end
		if not claim then return nil end
		claim = claim:match('P%d+')
		if not pName then return nil end
		target = mw.wikibase.getBestStatements(target, claim)
	end
	if type(target) ~= 'table' then return nil end
	if qualificators then
		if qualificators.time then
			target = Time.filtered(target, qualificators.time)
		end
	else return target end
end


--[[
	qualifyingValue(statement, propQual)
	simplified view on data
	Parameters:
		statement:	statement given for an entity
		propQual:	qualifier for a statement value, defaults to MainSnack
	returns: a string value of MainSnack or property qualifier if available
]]
service.qualifyingValue = function(statement, propQual)
	if statement == nil or statement == "" then
		mw.log('no qualifier in pQV')
		return ""
	end
	local result = ""
	if propQual and propQual ~= "" then
		local q = statement["qualifiers"]
	    if q and type(q[propQual]) == "table" then
			-- no fall back to main snak if property value empty!
			return getSimple(q[propQual][1]["datavalue"]["value"])
	    end
		-- no fall back to main snak if property inavailable!
		return ''
	end
	return getSimple(statement["mainsnak"]["datavalue"]["value"])
end

--[[
	statementQualOrMainSnack
	simple value of a statement with priority on qualifying value and fall back
	to main snak value
	parameters:
		qualifier:	string of Q[0-9]+ type for an entity with statements
		property:	string of P[0-9]+ type for usage of first statement
		propQual:	string of P[0-9]+ type for qualifying this statement
	returns:	simple value (no table)
]]
service.statementQualOrMainSnack = function(qualifier, property, propQual, test)
	local statement = get1stStatement(qualifier, property, test)
	if statement == "" then return "" end
	local result = ''
	local q = statement["qualifiers"]
	if q and type(q[propQual]) == "table" then
		result = getSimple(q[propQual][1]["datavalue"]["value"])
	end
	if result == '' then
		return getSimple(statement["mainsnak"]["datavalue"]["value"])
	end
	return result
end

--[[
	MainSnakValue(qualifier, property)
	simplified view on data
	Parameters:
		qualifier:	case 1: wikiData qualifier of an element with a property
					case 2: wikiData element with a property
		property:	Property of the element having result as value
	returns:	a wikiData qualifier or a string value of MainSnack if available
				limited: no regard of anything but first statement
				limited: only label if id
				limited: no regard of text language if text
]]
service.MainSnakValue = function(qualifier, property, test)
	local result = get1stStatement(qualifier, property, test)
	if result == "" then return "" end
	local ms = result["mainsnak"]
	if ms and ms["datavalue"] then
		return getSimple(ms["datavalue"]["value"])
	end
	-- fallback: qualifier P1932 "object named as"
	local q = result["qualifiers"]
	if not q or type(q['P1932']) ~= 'table' then return '' end
	return q['P1932'][1]["datavalue"]["value"]
end
service.MainSnackValue = service.MainSnakValue

--[[
	indirectMSValue(qualifier, properties)
	Parameters:
		qualifier:	case 1: wikiData qualifier of an element with a property
					case 2: wikiData element with a property
		properties:	sequence of properties in a string, optionally separated
	returns:
		first MainSnackValue of last property of element given in seccond last
		property ... of element given in first property of given element
]]
service.indirectMSValue = function(qualifier, properties)
	if qualifier == nil or qualifier == "" then
		mw.log('no qualifier')
		return ""
	end
	local statementList = {}
	local t = type(qualifier)
	local qual = qualifier
	local result = ""
	mw.log(properties)
	local props = {}
	for prop in properties:gmatch('[pP]%d+') do
		table.insert(props, prop)
	end
	if #props == {} then return "" end
	if t == "table" then
		statementList = qual:getBestStatements(props[1])
	else
		statementList = mw.wikibase.getBestStatements(qual, props[1])
	end
	local i = 1
	-- process all but last properties
	while i < #props do
		if statementList == nil or statementList[1] == nil then
			-- revoke result
			mw.log('no ' .. props[i] .. ' in ' .. qual)
			return ""
		end
		result = statementList[1]["mainsnak"]["datavalue"]["value"]
		t = type(result)
		if t ~= 'table' then
			-- revoke result
			mw.log(result .. ' is ' .. props[1] .. ' in ' .. qual .. ' but ' .. t)
			return ""
		end
		result = result["id"]
		if result == nil or result:find('[qQ]%d+') == nil then
			mw.log(result .. ' is ' .. props[1] .. ' in ' .. qual .. ' but no id.')
			return ""
		end
		qual = result
		mw.log('next for ' .. mw.wikibase.getLabel(qual))
		i = i + 1
		statementList = mw.wikibase.getBestStatements(qual, props[i])
	end
	-- process last property
	if statementList == nil or statementList[1] == nil then
		-- revoke result
		mw.log('no ' .. props[i] .. ' in ' .. qual)
		return ""
	end
	result = statementList[1]["mainsnak"]["datavalue"]["value"]
	if type(result) == 'table' then
		if result["id"] then return mw.wikibase.getLabel(result["id"]) end
		return ""
	end
	return result
end

--[[
	qualifiersLineup(qualifier, property)
	sequence of wikiData qualifiers
	Parameters:
		qualifier:	case 1: wikiData qualifier of an element with a property
					case 2: wikiData element with a property
		property:	Property of the element having result qualifiers as values
	returns:
		best statement's values as long as they are wikiData qualifiers lined up
		in a table with respect on series ordinals if available
	constraint:
		It's in the responsibility of wikiData to provide correct data. In case
		of corruption this function might return an empty table or one that
		apears empty by starting with index ~= 1.
]]
service.qualifiersLineup = function(qualifier, property)
	if qualifier == nil or qualifier == "" then
		return {}
	end
	local statementList = {}
	local t = type(qualifier)
	if t == "table" then
		statementList = qualifier:getBestStatements(property)
	else
		statementList = mw.wikibase.getBestStatements(qualifier, property)
	end
	if statementList == nil then
		return {}
	end
	local result = {}
	for i, elm in ipairs(statementList) do
		local eVal = elm["mainsnak"]["datavalue"]["value"]
		if eVal == nil then return result end
		t = type(eVal)
		if t ~= "table" then return result end
		local eQual = eVal["id"]
		if eQual == nil then return result end
		local iQual = elm["qualifiers"]
		if iQual == nil then
			mw.log('kein qualifier in ' .. eQual)
			table.insert(result, eQual)
		else
			iQual = iQual["P1545"]
			if iQual == nil then
				mw.log('keine Ornungsnummer in ' .. eQual)
				table.insert(result, eQual)
			else
				local eNum = iQual[1]["datavalue"]["value"]
				table.insert(result, eNum, eQual)
			end
		end
	end
	return result
end

service.test = function(frame)
	return service.MainSnackValue('Q115122668', 'P577', 2)
end

return service