<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="ru">
	<id>https://bukvica.org/w/index.php?action=history&amp;feed=atom&amp;title=%D0%9C%D0%BE%D0%B4%D1%83%D0%BB%D1%8C%3AWDBackend</id>
	<title>Модуль:WDBackend - История изменений</title>
	<link rel="self" type="application/atom+xml" href="https://bukvica.org/w/index.php?action=history&amp;feed=atom&amp;title=%D0%9C%D0%BE%D0%B4%D1%83%D0%BB%D1%8C%3AWDBackend"/>
	<link rel="alternate" type="text/html" href="https://bukvica.org/w/index.php?title=%D0%9C%D0%BE%D0%B4%D1%83%D0%BB%D1%8C:WDBackend&amp;action=history"/>
	<updated>2026-04-20T22:32:27Z</updated>
	<subtitle>История изменений этой страницы в вики</subtitle>
	<generator>MediaWiki 1.43.8</generator>
	<entry>
		<id>https://bukvica.org/w/index.php?title=%D0%9C%D0%BE%D0%B4%D1%83%D0%BB%D1%8C:WDBackend&amp;diff=238439&amp;oldid=prev</id>
		<title>Karaby: 1 версия импортирована</title>
		<link rel="alternate" type="text/html" href="https://bukvica.org/w/index.php?title=%D0%9C%D0%BE%D0%B4%D1%83%D0%BB%D1%8C:WDBackend&amp;diff=238439&amp;oldid=prev"/>
		<updated>2025-07-27T15:36:36Z</updated>

		<summary type="html">&lt;p&gt;1 версия импортирована&lt;/p&gt;
&lt;table style=&quot;background-color: #fff; color: #202122;&quot; data-mw=&quot;interface&quot;&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;tr class=&quot;diff-title&quot; lang=&quot;ru&quot;&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;← Предыдущая версия&lt;/td&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;Версия от 15:36, 27 июля 2025&lt;/td&gt;
				&lt;/tr&gt;&lt;tr&gt;&lt;td colspan=&quot;4&quot; class=&quot;diff-notice&quot; lang=&quot;ru&quot;&gt;&lt;div class=&quot;mw-diff-empty&quot;&gt;(нет различий)&lt;/div&gt;
&lt;/td&gt;&lt;/tr&gt;
&lt;!-- diff cache key wiki:diff:1.41:old-238438:rev-238439 --&gt;
&lt;/table&gt;</summary>
		<author><name>Karaby</name></author>
	</entry>
	<entry>
		<id>https://bukvica.org/w/index.php?title=%D0%9C%D0%BE%D0%B4%D1%83%D0%BB%D1%8C:WDBackend&amp;diff=238438&amp;oldid=prev</id>
		<title>Буквица&gt;The Fox Bot: Защитил страницу Модуль:WDBackend: критический шаблон или модуль: согласно Служебная:Постоянная ссылка/143835923#Промежуточный итог ([Редактирование=только автоподтверждённые] (бессрочно) [Переименование=только автоподтверждённые] (бессрочно))</title>
		<link rel="alternate" type="text/html" href="https://bukvica.org/w/index.php?title=%D0%9C%D0%BE%D0%B4%D1%83%D0%BB%D1%8C:WDBackend&amp;diff=238438&amp;oldid=prev"/>
		<updated>2025-03-05T16:12:30Z</updated>

		<summary type="html">&lt;p&gt;Защитил страницу &lt;a href=&quot;/wiki/%D0%9C%D0%BE%D0%B4%D1%83%D0%BB%D1%8C:WDBackend&quot; title=&quot;Модуль:WDBackend&quot;&gt;Модуль:WDBackend&lt;/a&gt;: &lt;a href=&quot;/w/index.php?title=%D0%92%D0%9F:%D0%9A%D0%A8&amp;amp;action=edit&amp;amp;redlink=1&quot; class=&quot;new&quot; title=&quot;ВП:КШ (страница не существует)&quot;&gt;критический шаблон или модуль&lt;/a&gt;: согласно &lt;a href=&quot;/wiki/%D0%A1%D0%BB%D1%83%D0%B6%D0%B5%D0%B1%D0%BD%D0%B0%D1%8F:%D0%9F%D0%BE%D1%81%D1%82%D0%BE%D1%8F%D0%BD%D0%BD%D0%B0%D1%8F_%D1%81%D1%81%D1%8B%D0%BB%D0%BA%D0%B0/143835923#Промежуточный_итог&quot; title=&quot;Служебная:Постоянная ссылка/143835923&quot;&gt;Служебная:Постоянная ссылка/143835923&lt;/a&gt; ([Редактирование=только автоподтверждённые] (бессрочно) [Переименование=только автоподтверждённые] (бессрочно))&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Новая страница&lt;/b&gt;&lt;/p&gt;&lt;div&gt;require(&amp;#039;strict&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
local p = {}&lt;br /&gt;
&lt;br /&gt;
local NS_MODULE = 828 --: https://www.mediawiki.org/wiki/Extension_default_namespaces&lt;br /&gt;
local moduleNamespace = mw.site.namespaces[NS_MODULE].name&lt;br /&gt;
&lt;br /&gt;
local base = require(moduleNamespace .. &amp;#039;:WDBase&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
local Backend = {}&lt;br /&gt;
&lt;br /&gt;
function Backend:new(lang)&lt;br /&gt;
	local defaultLangObj = mw.getContentLanguage()&lt;br /&gt;
	local defaultLang = defaultLangObj:getCode()&lt;br /&gt;
	local obj = {&lt;br /&gt;
		lang = lang,&lt;br /&gt;
		defaultLang = defaultLang&lt;br /&gt;
	}&lt;br /&gt;
	setmetatable(obj, self)&lt;br /&gt;
	self.__index = self&lt;br /&gt;
	&lt;br /&gt;
	return obj&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function Backend:safeField(source, fieldName, parentField)&lt;br /&gt;
	if not parentField then&lt;br /&gt;
		parentField = source&lt;br /&gt;
	end&lt;br /&gt;
	local info = parentField[fieldName]&lt;br /&gt;
	if not info then&lt;br /&gt;
		info = {}&lt;br /&gt;
	end&lt;br /&gt;
	return info&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function Backend:parseFieldPath(source, map, parentField)&lt;br /&gt;
	local fieldName = map.name&lt;br /&gt;
	local currParentComponents = source&lt;br /&gt;
	local currParentField = nil&lt;br /&gt;
	if map.isLocal or not fieldName then&lt;br /&gt;
		currParentField = parentField&lt;br /&gt;
		if parentField then&lt;br /&gt;
			currParentComponents = currParentField.components or {}&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	if type(fieldName) == &amp;#039;table&amp;#039; then&lt;br /&gt;
		local lastParentField = currParentField&lt;br /&gt;
		local lastParentComponents = currParentComponents&lt;br /&gt;
		local lastNotFound = false&lt;br /&gt;
		for i, name in ipairs(fieldName) do&lt;br /&gt;
			if i ~= 1 then&lt;br /&gt;
				-- It&amp;#039;s much easier to break at last iteration, but it&amp;#039;s a problem&lt;br /&gt;
				-- to get the count of parts if the map will be loaded by mw.loadData()&lt;br /&gt;
				if lastNotFound then&lt;br /&gt;
					return nil&lt;br /&gt;
				end&lt;br /&gt;
				currParentField = lastParentField&lt;br /&gt;
				currParentComponents = lastParentComponents&lt;br /&gt;
			end&lt;br /&gt;
			if lastParentComponents then&lt;br /&gt;
				lastParentField = lastParentComponents[name]&lt;br /&gt;
				lastParentComponents = lastParentField and lastParentField.components&lt;br /&gt;
			else&lt;br /&gt;
				lastNotFound = true&lt;br /&gt;
			end&lt;br /&gt;
			fieldName = name&lt;br /&gt;
		end&lt;br /&gt;
		currParentComponents = currParentComponents or {}&lt;br /&gt;
	end&lt;br /&gt;
	return currParentField, currParentComponents, fieldName&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function Backend:trySetField(source, fieldName, info, parentField)&lt;br /&gt;
	if info.value or info.entity then&lt;br /&gt;
		if not parentField then&lt;br /&gt;
			parentField = source&lt;br /&gt;
		end&lt;br /&gt;
		parentField[fieldName] = info&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function inArray(value, array)&lt;br /&gt;
	for _, currValue in ipairs(array) do&lt;br /&gt;
		if currValue == value then&lt;br /&gt;
			return true&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	return false&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function Backend:getLang(map)&lt;br /&gt;
	return (map.useDefaultLang and self.defaultLang) or self.lang&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function Backend:fetchFieldsByQualifiers(source, fieldMap, qualifiers, parentField)&lt;br /&gt;
	for _, map in ipairs(fieldMap) do&lt;br /&gt;
		local qualifier = qualifiers[map.property]&lt;br /&gt;
		if qualifier then&lt;br /&gt;
			if map.filter then&lt;br /&gt;
				qualifier = map.filter(qualifier, self:getLang(map))&lt;br /&gt;
			end&lt;br /&gt;
			self:fetchFieldByMap(source, map, qualifier, base.dataBySnak, parentField)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function Backend:fetchFieldItem(source, map, statementOrSnak, getData)&lt;br /&gt;
	local lang = self:getLang(map)&lt;br /&gt;
	local item = getData(statementOrSnak, lang, map.cache)&lt;br /&gt;
	if item then&lt;br /&gt;
		item.retrieved = true&lt;br /&gt;
	else&lt;br /&gt;
		item = {}&lt;br /&gt;
	end&lt;br /&gt;
	if map.mapEntity then&lt;br /&gt;
		local entity = map.mapEntity[item.entity]&lt;br /&gt;
		if not entity then&lt;br /&gt;
			return nil&lt;br /&gt;
		end&lt;br /&gt;
		item = base.dataByEntity(entity, lang, map.cache)&lt;br /&gt;
		if item then&lt;br /&gt;
			item.retrieved = true&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	if item.entity then&lt;br /&gt;
		if map.getData then&lt;br /&gt;
			item = map.getData(item.entity, lang)&lt;br /&gt;
			item.retrieved = true&lt;br /&gt;
		elseif map.getValue then&lt;br /&gt;
			item.value, item.lang = map.getValue(item.entity, lang)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	if map.allowedEntities and item.entity and not inArray(item.entity, map.allowedEntities) then&lt;br /&gt;
		return nil&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	if map.defaultUnit and not item.unitEntity then&lt;br /&gt;
		item.unitEntity = map.defaultUnit&lt;br /&gt;
	end&lt;br /&gt;
	if map.allowedUnits then&lt;br /&gt;
		if not item.unitEntity or not inArray(item.unitEntity, map.allowedUnits) then&lt;br /&gt;
			return nil&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	if not item.value and not item.entity then&lt;br /&gt;
		return nil&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	if map.exact then&lt;br /&gt;
		item.exact = true&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return item&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function skipGetIf(item, cond)&lt;br /&gt;
	if not cond then&lt;br /&gt;
		return false&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	for key, value in pairs(cond) do&lt;br /&gt;
		if item[key] == value then&lt;br /&gt;
			return true&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	return false&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function Backend:tryGet(source, map, getTable, items, currParentField)&lt;br /&gt;
	if not getTable then&lt;br /&gt;
		return&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local fieldName = map.name&lt;br /&gt;
	if fieldName then&lt;br /&gt;
		for j, item in ipairs(items) do&lt;br /&gt;
			if not skipGetIf(item, map.skipGetIf) then&lt;br /&gt;
				self:fetchFieldsByMap(source, item.entity, getTable, item)&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	else&lt;br /&gt;
		for j, item in ipairs(items) do&lt;br /&gt;
			if not skipGetIf(item, map.skipGetIf) then&lt;br /&gt;
				self:fetchFieldsByMap(source, item.entity, getTable, currParentField)&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function Backend:fetchFieldByMap(source, map, statementsOrSnaks, getData, parentField)&lt;br /&gt;
	local currParentField, currParentComponents, fieldName&lt;br /&gt;
			= self:parseFieldPath(source, map, parentField)&lt;br /&gt;
	if not currParentComponents then&lt;br /&gt;
		return&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	if fieldName then&lt;br /&gt;
		local fieldTable = self:safeField(source, fieldName, currParentField)&lt;br /&gt;
		if map.match and getData == base.dataByStatement and fieldTable.value then&lt;br /&gt;
			local statement = base.searchStatementByValue(statementsOrSnaks, fieldTable.value)&lt;br /&gt;
			if not statement then&lt;br /&gt;
				return&lt;br /&gt;
			end&lt;br /&gt;
			local item = self:fetchFieldItem(source, map, statement, getData)&lt;br /&gt;
			if item then&lt;br /&gt;
				currParentComponents[fieldName] = item&lt;br /&gt;
				if map.qualifiers and statement.qualifiers then&lt;br /&gt;
					self:fetchFieldsByQualifiers(source, map.qualifiers, statement.qualifiers, item)&lt;br /&gt;
				end&lt;br /&gt;
				local getTable = map.forceGet or map.get&lt;br /&gt;
				if getTable and not skipGetIf(item, map.skipGetIf) then&lt;br /&gt;
					self:fetchFieldsByMap(source, item.entity, getTable, currParentField)&lt;br /&gt;
				end&lt;br /&gt;
			else&lt;br /&gt;
				if map.elseGet then&lt;br /&gt;
					self:fetchFieldsByMap(source, parentField.entity, map.elseGet, currParentField)&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
			return&lt;br /&gt;
		end&lt;br /&gt;
		if fieldTable.value and not map.overwrite then&lt;br /&gt;
			if map.substInto and map.substInto.force then&lt;br /&gt;
				self:substFieldInto(source, map, parentField)&lt;br /&gt;
			end&lt;br /&gt;
			local items = fieldTable&lt;br /&gt;
			if table.getn(items) == 0 then&lt;br /&gt;
				items = { items }&lt;br /&gt;
			end&lt;br /&gt;
			self:tryGet(source, map, map.forceGet, items, currParentField)&lt;br /&gt;
			return&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local maxCount = map.max&lt;br /&gt;
	if not maxCount then&lt;br /&gt;
		maxCount = math.huge&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local items = {}&lt;br /&gt;
	local indices = {}&lt;br /&gt;
	for i, statementOrSnak in ipairs(statementsOrSnaks) do&lt;br /&gt;
		if i &amp;gt; maxCount then&lt;br /&gt;
			break&lt;br /&gt;
		end&lt;br /&gt;
		if statementOrSnak ~= nil then&lt;br /&gt;
			local item = self:fetchFieldItem(source, map, statementOrSnak, getData)&lt;br /&gt;
			if item then&lt;br /&gt;
				table.insert(items, item)&lt;br /&gt;
				indices[i] = table.getn(items)&lt;br /&gt;
			else&lt;br /&gt;
				indices[i] = 0&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local triggerElseGet = false&lt;br /&gt;
	if fieldName then&lt;br /&gt;
		if table.getn(items) == 1 and not map.isArray then&lt;br /&gt;
			currParentComponents[fieldName] = items[1]&lt;br /&gt;
		elseif next(items) ~= nil then&lt;br /&gt;
			currParentComponents[fieldName] = items&lt;br /&gt;
		else&lt;br /&gt;
			triggerElseGet = true&lt;br /&gt;
		end&lt;br /&gt;
	elseif next(items) ~= nil then&lt;br /&gt;
		if map.overwriteValue then&lt;br /&gt;
			parentField.value = items[1].value&lt;br /&gt;
			parentField.exact = map.exact&lt;br /&gt;
		end&lt;br /&gt;
		if map.overwriteEntity then&lt;br /&gt;
			parentField.entity = items[1].entity&lt;br /&gt;
		end&lt;br /&gt;
	else&lt;br /&gt;
		triggerElseGet = true&lt;br /&gt;
	end&lt;br /&gt;
	if currParentField and next(currParentComponents) ~= nil then&lt;br /&gt;
		currParentField.components = currParentComponents&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	if map.substInto then&lt;br /&gt;
		self:substFieldInto(source, map, parentField)&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	for i, statementOrSnak in ipairs(statementsOrSnaks) do&lt;br /&gt;
		if i &amp;gt; maxCount then&lt;br /&gt;
			break&lt;br /&gt;
		end&lt;br /&gt;
		local item = items[indices[i]]&lt;br /&gt;
		if map.qualifiers and statementOrSnak.qualifiers then&lt;br /&gt;
			self:fetchFieldsByQualifiers(source, map.qualifiers, statementOrSnak.qualifiers, item)&lt;br /&gt;
		end				&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	self:tryGet(source, map, map.forceGet or map.get, items, currParentField)&lt;br /&gt;
&lt;br /&gt;
	if triggerElseGet and map.elseGet then&lt;br /&gt;
		self:fetchFieldsByMap(source, parentField.entity, map.elseGet, parentField)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function Backend:fetchFieldByCustomFunc(source, entity, map, parentField)&lt;br /&gt;
	local currParentField, currParentComponents, fieldName&lt;br /&gt;
			= self:parseFieldPath(source, map, parentField)&lt;br /&gt;
	if not currParentComponents then&lt;br /&gt;
		return&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local fieldTable = currParentComponents[fieldName]&lt;br /&gt;
	if fieldTable and fieldTable.value and not map.overwrite then&lt;br /&gt;
		return&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local lang = self:getLang(map)&lt;br /&gt;
	if map.getData then&lt;br /&gt;
		fieldTable = map.getData(entity, lang)&lt;br /&gt;
	else&lt;br /&gt;
		fieldTable = fieldTable or {}&lt;br /&gt;
		fieldTable.value = map.getValue(entity, lang)&lt;br /&gt;
	end&lt;br /&gt;
	fieldTable.retrieved = true&lt;br /&gt;
	self:trySetField(source, fieldName, fieldTable, currParentComponents)&lt;br /&gt;
	if currParentField and next(currParentComponents) ~= nil then&lt;br /&gt;
		currParentField.components = currParentComponents&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function Backend:fetchFieldLabel(source, map, parentField)&lt;br /&gt;
	local currParentField, currParentComponents, fieldName&lt;br /&gt;
			= self:parseFieldPath(source, map, parentField)&lt;br /&gt;
	if not currParentComponents then&lt;br /&gt;
		return&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local fieldTable = currParentComponents[fieldName]&lt;br /&gt;
	local entity&lt;br /&gt;
	if fieldTable then&lt;br /&gt;
		if fieldTable.value then&lt;br /&gt;
			return&lt;br /&gt;
		end&lt;br /&gt;
		entity = fieldTable.entity&lt;br /&gt;
	end&lt;br /&gt;
	entity = map.entity or fieldTable.entity&lt;br /&gt;
	if not entity then&lt;br /&gt;
		return&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local components = fieldTable and fieldTable.components&lt;br /&gt;
	fieldTable = base.dataByEntity(entity, self:getLang(map), map.cache)&lt;br /&gt;
	fieldTable.components = components&lt;br /&gt;
	currParentComponents[fieldName] = fieldTable&lt;br /&gt;
&lt;br /&gt;
	if currParentField and next(currParentComponents) ~= nil then&lt;br /&gt;
		currParentField.components = currParentComponents&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function getPropertyByPath(source, propertyPath)&lt;br /&gt;
	local currField = source&lt;br /&gt;
	for _, pathEntry in ipairs(propertyPath) do&lt;br /&gt;
		currField = currField[pathEntry]&lt;br /&gt;
		if not currField then&lt;br /&gt;
			return nil&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	return currField&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function filterStatementsByPropertiesAndValues(statements, properties)&lt;br /&gt;
	local filtered = {}&lt;br /&gt;
	local propsCount = table.getn(properties)&lt;br /&gt;
	for _, statement in ipairs(statements) do&lt;br /&gt;
		local matched = 0&lt;br /&gt;
		local qualifiers = statement.qualifiers&lt;br /&gt;
		if qualifiers then&lt;br /&gt;
			for _, propInfo in ipairs(properties) do&lt;br /&gt;
				local propQualifiers = qualifiers[propInfo.property]&lt;br /&gt;
				if propQualifiers then&lt;br /&gt;
					for _, propQualifier in ipairs(propQualifiers) do&lt;br /&gt;
						if propInfo.value then&lt;br /&gt;
							local value = base.valueBySnak(propQualifier)&lt;br /&gt;
							if value == propInfo.value then&lt;br /&gt;
								matched = matched + 1&lt;br /&gt;
							else&lt;br /&gt;
								break&lt;br /&gt;
							end&lt;br /&gt;
						else&lt;br /&gt;
							matched = matched + 1&lt;br /&gt;
						end&lt;br /&gt;
					end&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
		if matched == propsCount then&lt;br /&gt;
			table.insert(filtered, statement)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	if not next(filtered) then&lt;br /&gt;
		return nil&lt;br /&gt;
	end&lt;br /&gt;
	return filtered&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function Backend:tryForceGetByMap(source, map, parentField)&lt;br /&gt;
	local currParentField, currParentComponents, fieldName&lt;br /&gt;
			= self:parseFieldPath(source, map, parentField)&lt;br /&gt;
	if not currParentComponents then&lt;br /&gt;
		return&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local fieldTable = self:safeField(source, fieldName, currParentComponents)&lt;br /&gt;
	local items = fieldTable&lt;br /&gt;
	if table.getn(items) == 0 then&lt;br /&gt;
		items = { fieldTable }&lt;br /&gt;
	end&lt;br /&gt;
	self:tryGet(source, map, map.forceGet, items, currParentField)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function Backend:substFieldInto(source, map, parentField)&lt;br /&gt;
	local currParentField, currParentComponents, fieldName&lt;br /&gt;
			= self:parseFieldPath(source, map, parentField)&lt;br /&gt;
	if not currParentComponents then&lt;br /&gt;
		return&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local fieldTable = currParentComponents[fieldName]&lt;br /&gt;
	if not fieldTable then&lt;br /&gt;
		return&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local targetCurrParentField, targetCurrParentComponents, targetFieldName&lt;br /&gt;
			= self:parseFieldPath(source, map.substInto, parentField)&lt;br /&gt;
	if not targetCurrParentComponents then&lt;br /&gt;
		return&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local targetFieldTable = self:safeField(source, targetFieldName, targetCurrParentComponents)&lt;br /&gt;
&lt;br /&gt;
	local templateCurrParentField, templateCurrParentComponents, templateFieldName&lt;br /&gt;
			= self:parseFieldPath(source, map.substInto.template, parentField)&lt;br /&gt;
	if not templateCurrParentComponents then&lt;br /&gt;
		return&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local templateFieldTable = templateCurrParentComponents[templateFieldName]&lt;br /&gt;
	if not templateFieldTable then&lt;br /&gt;
		return&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	targetFieldTable.value = templateFieldTable.value:gsub(&amp;#039;%$1&amp;#039;, fieldTable.value)&lt;br /&gt;
	self:trySetField(source, targetFieldName, targetFieldTable, targetCurrParentComponents)&lt;br /&gt;
	if targetCurrParentField and next(targetCurrParentComponents) ~= nil then&lt;br /&gt;
		targetCurrParentField.components = targetCurrParentComponents&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function Backend:fetchFieldsByMap(source, entity, fieldMap, parentField)&lt;br /&gt;
	for _, map in ipairs(fieldMap) do&lt;br /&gt;
		local currEntity = entity&lt;br /&gt;
		if map.entity then&lt;br /&gt;
			currEntity = map.entity&lt;br /&gt;
		end&lt;br /&gt;
		if currEntity then&lt;br /&gt;
			local propertySpecified = false&lt;br /&gt;
			local statements&lt;br /&gt;
&lt;br /&gt;
			if map.property then&lt;br /&gt;
				statements = base.statements(currEntity, map.property, map.cache)&lt;br /&gt;
				propertySpecified = true&lt;br /&gt;
			elseif map.properties then&lt;br /&gt;
				statements = base.statementsByProperties(currEntity, map.properties)&lt;br /&gt;
				propertySpecified = true&lt;br /&gt;
			elseif map.propertyPath then&lt;br /&gt;
				local property = getPropertyByPath(source, map.propertyPath)&lt;br /&gt;
				if property then&lt;br /&gt;
					statements = base.statements(currEntity, property, map.cache)&lt;br /&gt;
				end&lt;br /&gt;
				propertySpecified = true&lt;br /&gt;
			end&lt;br /&gt;
&lt;br /&gt;
			if propertySpecified then&lt;br /&gt;
				if statements then&lt;br /&gt;
					if map.filter then&lt;br /&gt;
						statements = map.filter(statements, self:getLang(map))&lt;br /&gt;
					end&lt;br /&gt;
					if map.has then&lt;br /&gt;
						statements = filterStatementsByPropertiesAndValues(statements, map.has)&lt;br /&gt;
					end&lt;br /&gt;
					self:fetchFieldByMap(source, map, statements, base.dataByStatement, parentField)&lt;br /&gt;
				else&lt;br /&gt;
					if map.elseGet then&lt;br /&gt;
						self:fetchFieldsByMap(source, currEntity, map.elseGet, parentField)&lt;br /&gt;
					end&lt;br /&gt;
				end&lt;br /&gt;
			else&lt;br /&gt;
				if map.getData or map.getValue then&lt;br /&gt;
					self:fetchFieldByCustomFunc(source, currEntity, map, parentField)&lt;br /&gt;
				end&lt;br /&gt;
				if map.getLabel then&lt;br /&gt;
					self:fetchFieldLabel(source, map, parentField)&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
			if not propertySpecified or not statements then&lt;br /&gt;
				self:tryForceGetByMap(source, map, parentField)&lt;br /&gt;
			end&lt;br /&gt;
		else&lt;br /&gt;
			self:tryForceGetByMap(source, map, parentField)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function Backend:fetch(source, fieldsMap)&lt;br /&gt;
	for _, map in ipairs(fieldsMap) do&lt;br /&gt;
		local fieldTable = self:safeField(source, map.name)&lt;br /&gt;
		if next(fieldTable) ~= nil then&lt;br /&gt;
			if map.get then&lt;br /&gt;
				self:fetchFieldsByMap(source, fieldTable.entity, map.get, fieldTable)&lt;br /&gt;
			end&lt;br /&gt;
			if map.substInto then&lt;br /&gt;
				self:substFieldInto(source, map)&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function Backend:fetchEntity(source, entity, fieldMap)&lt;br /&gt;
	self:fetchFieldsByMap(source, entity, fieldMap)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function Backend:ensureLang()&lt;br /&gt;
	if self.lang then&lt;br /&gt;
		return&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	self.lang = self.defaultLang&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function Backend:assertLang()&lt;br /&gt;
	assert(self.lang, &amp;#039;No language selected.&amp;#039;)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.new(lang)&lt;br /&gt;
	return Backend:new(lang)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
return p&lt;/div&gt;</summary>
		<author><name>Буквица&gt;The Fox Bot</name></author>
	</entry>
</feed>