Модуль:Wikidata/Boundaries

Материал из Википедии — свободной энциклопедии
Перейти к навигации Перейти к поиску
Документация
local WDS = require( 'Module:WikidataSelectors' );
local p = {};

local function min( prev, next )
	if ( prev == nil ) then return next;
	elseif ( prev > next ) then return next;
	else return prev; end
end

local function max( prev, next )
	if ( prev == nil ) then return next;
	elseif ( prev < next ) then return next;
	else return prev; end
end

function p.getTimeBoundariesFromProperty( frame, context, propertyId )
	mw.log( 'Get time boundaries for ' .. propertyId .. '...');

	local dateClaims = WDS.filter( context.entity.claims, propertyId );
	if ( not dateClaims or #dateClaims == 0 ) then return nil; end
	mw.log( 'Get time boundaries for ' .. propertyId .. '... Got ' .. #dateClaims .. ' date claim(s)');

	-- only support exact date so far, but need improvment
	local left = nil;
	local right = nil;
	for _, claim in pairs( dateClaims ) do
		if ( not claim.mainsnak ) then return nil; end
		local boundaries = context.parseTimeBoundariesFromSnak( claim.mainsnak );
		if ( not boundaries ) then return nil; end
		left = min( left, boundaries[1] );
		right = max( right, boundaries[2] );
	end

	if ( not left or not right ) then return nil; end

	mw.log( 'Time boundaries for ' .. propertyId .. ' are ' .. left .. ' and ' .. right );
	return { left, right };
end

function p.getTimeBoundariesFromProperties( frame, context, propertyIds )
	for _, propertyId in ipairs( propertyIds ) do
		local result = p.getTimeBoundariesFromProperty( frame, context, propertyId );
		if result then
			return result;
		end
	end

	return nil;
end

function p.getTimeBoundariesFromQualifier( frame, context, statement, qualifierId )
	-- only support exact date so far, but need improvment
	local left = nil;
	local right = nil;
	mw.logObject( statement, 'statement' )
	mw.logObject( qualifierId, 'qualifierId' )
	if ( statement.qualifiers and statement.qualifiers[qualifierId] ) then
		mw.logObject( statement.qualifiers[qualifierId], 'statement.qualifiers[qualifierId]' )
		for _, qualifier in pairs( statement.qualifiers[qualifierId] ) do
			local boundaries = context.parseTimeBoundariesFromSnak( qualifier );
			mw.logObject( qualifier, 'qualifier' )
			mw.logObject( boundaries, 'boundaries' )
			if ( not boundaries ) then return nil; end
			left = min( left, boundaries[1] );
			right = max( right, boundaries[2] );
		end
	end

	if ( not left or not right ) then
		return nil;
	end

	return { left, right };
end

function p.getTimeBoundariesFromQualifiers( frame, context, statement, qualifierIds )
	for _, qualifierId in ipairs( qualifierIds ) do
		local result = p.getTimeBoundariesFromQualifier( frame, context, statement, qualifierId );
		if result then
			return result;
		end
	end

	return nil;
end

function p.getParentsInBoundariesSnakImpl( frame, context, entity, boundaries, propertyIds )
	local results = {};

	if not propertyIds or #propertyIds == 0 then
		return results;
	end

	if entity.claims then
		for _, propertyId in ipairs( propertyIds ) do
			local filteredClaims = WDS.filter( entity.claims, propertyId .. '[rank:preferred, rank:normal]' );
			if filteredClaims then
				for _, claim in pairs( filteredClaims ) do
					if not boundaries or not propertyIds or #propertyIds == 0 then
						table.insert( results, claim.mainsnak );
					else
						local startBoundaries = getTimeBoundariesFromQualifiers( context, claim, 'P580' );
						local endBoundaries = getTimeBoundariesFromQualifiers( context, claim, 'P582' );
			
						if ( (startBoundaries == nil or startBoundaries[2] <= boundaries[1] )
								and ( endBoundaries == nil or endBoundaries[1] >= boundaries[2] ) ) then
							table.insert( results, claim.mainsnak );
						end 
					end
				end
			end

			if #results > 0 then
				break;
			end
		end
	end

	return results;
end

function p.getParentsInBoundariesSnak( frame, context, entity, boundaries )
	if ( not entity ) then error('entity must be specified'); end
	if ( type(entity) ~= 'table' ) then error('entity must be table'); end
	if ( not boundaries ) then error('boundaries must be specified'); end
	if ( type(boundaries) ~= 'table' ) then error('boundaries must be table'); end

	local results = p.getParentsInBoundariesSnakImpl( frame, context, entity, boundaries, {'P131'} ) -- located in
	if not results or #results == 0 then
		results = p.getParentsInBoundariesSnakImpl( frame, context, entity, boundaries, {'P17'} ) -- country
	end

	for r, result in pairs( results ) do
		if result.snaktype ~= 'value' then
			return nil;
		end
		local resultId = 'Q' .. result.datavalue.value['numeric-id'];
		if ( resultId == entity.id ) then
			return nil;
		end
	end
	return results;
end

-- get current of historic name of place
function p.getLabel( frame, context, entity, boundaries )
	if not entity then
		return nil;
	end

	local lang = mw.language.getContentLanguage();
	local langCode = lang:getCode();

	-- name from label
	-- TODO: lang:getFallbackLanguages()
	local label = nil;
	if entity.labels then
		if entity.labels[langCode] and entity.labels[langCode].value then
			label = entity.labels[langCode].value;
		elseif entity.labels.en and entity.labels.en.value then
			label = entity.labels.en.value;
		end
	end

	-- name from properties
	local results = p.getParentsInBoundariesSnakImpl( frame, context, entity, boundaries, {
		'P1813[language:' .. langCode .. ']',
		'P1448[language:' .. langCode .. ']',
		'P1705[language:' .. langCode .. ']'
	} );

	for r, result in pairs( results ) do
		if result.datavalue
				and result.datavalue.value
				and result.datavalue.value.text then
			label = result.datavalue.value.text;
			break;
		end
	end

	return label;
end

return p;