Skip to main content

Сервис LegacyXml2Select

LegacyXml2Select – это сервис, который предоставляет возможность парсить XML-запросы, сформированные в стиле «формальных выборок», и генерировать соответствующие SQL SELECT-запросы к документам в БД. Основное назначение – обеспечить обратную совместимость со старыми механизмами поиска.

Сервис состоит из нескольких компонентов:

  • LegacyXml2Select – фасад, предоставляющий внешние методы.
  • LegacyXml2SelectDb – сервис‑помощник для доступа к базе данных (получение метаданных, выполнение функций).
  • LegacyXml2SelectInnerPg – ядро парсинга XML и построения SQL.
  • PropertyBuilder – построитель условий для свойств документов.
  • MacroParser – парсер макросов (функции, литералы).
  • SqlQuery / WhereCondition – утилиты для программного конструирования SQL-выражений и оптимизации WHERE-условий.

Все компоненты располагаются в одном модуле и экспортируются как единое целое.

Сервис LegacyXml2Select

Назначение: Принимает XML‑строку, параметры режима запроса и прав доступа, преобразует её в объект SqlQuery (или сразу в SQL‑строку) и возвращает результат.

Зависимости

  • QueriesHelper – обязательный (указан в requirements), предоставляет доступ к выполнению запросов к PostgreSQL.
  • LegacyXml2SelectDb – обязательный (добавляется как вложенный сервис в конструкторе).

Методы (запросы)

parseToObj({ session, xml, queryMode=0, permissions=1 })

Преобразует XML в объект SqlQuery (без построения финального SQL‑текста).

Параметры:

  • session (объект, опционально) – должен содержать userId, используется для фильтрации прав.
  • xml (string) – XML‑строка запроса.
  • queryMode (number, по умолчанию 0) – режим запроса:
    • 0 – полный запрос (выбирает поля документа),
    • 1 – подсчёт количества (COUNT),
    • 2 – только идентификаторы документов,
    • 3‑6 – специальные режимы (логика меняется).
  • permissions (number, по умолчанию 1) – уровень проверки прав доступа (-1 – без проверки, 1 – стандартная).

Возвращает: экземпляр SqlQuery.

parseToSql({ session, xml, queryMode=0, permissions=1 })

Выполняет parseToObj, а затем вызывает sql.build(), возвращая готовый SQL‑запрос.

Параметры: те же, что у parseToObj.

Возвращает: строку SQL.

macroParse({ macro })

Парсит строку‑макрос в абстрактное синтаксическое дерево.

Параметры:

  • macro (string) – строка, содержащая вызов функции, литерал или идентификатор.

Возвращает: объект с полем tree – AST макроса (например, { type: 'function', value: 'NOW', args: [] }).

Формат XML‑запроса для LegacyXml2Select

Сервис LegacyXml2Select преобразует XML‑описание выборки документов в SQL‑запрос SELECT.
Корневой элемент — <query>, внутри которого обязательно присутствует элемент <formal>, задающий условия фильтрации.


1. Корневая структура

<?xml version="1.0"?>
<query>
  <formal dockind_id="ID_ВИДА_ДОКУМЕНТА" [name="and|or"]>
     <!-- набор условий -->
  </formal>
</query>

Атрибуты <formal>:

Атрибут Обязательный Тип Описание
dockind_id да integer Идентификатор вида документа (dockind_id) целевой таблицы
name нет and/or Логическая операция, объединяющая все условия верхнего уровня (по умолчанию and)

2. Элементы внутри <formal> и <reference>

Допускаются следующие элементы (в любом порядке и в любых сочетаниях):

Элемент Назначение
<reference> Ссылка на другой документ / тип документа (JOIN / EXISTS)
<property> Условие на значение свойства документа
<status> Фильтр по статусу (виду события) документа
<operation> Логическая группа условий (AND / OR)
<select> (Зарезервирован; влияет на логику outer join, но вывод не меняет)

Все они могут вкладываться внутрь <reference> и <operation>.


3. Элемент <reference>

Описывает переход к связанному документу через свойство‑ссылку. Реализуется либо как EXISTS/NOT EXISTS, либо как JOIN (в зависимости от атрибута referencing и режима запроса).

<reference
  docprop_id="ID_СВОЙСТВА_ССЫЛКИ"
  referencing="join|is null"
  dockind_id="ID_ЦЕЛЕВОГО_ВИДА"
  [condition="l|nl|g|ng|e|ne"]
  [count="целое_число"]
  [valuevar="строка"]
  [leftp="строка"]
  [rightp="строка"]
>
  <!-- вложенные reference, property, status, operation -->
</reference>
Атрибут Обязат. Тип Значения / Описание
docprop_id да integer Идентификатор свойства‑ссылки (из model_documents.doc_kind_properties)
referencing да строка join – обычная связь, проверяется существование связанного документа;
is null – анти‑связь, условие NOT EXISTS (связанного документа нет)
dockind_id да integer Идентификатор вида документа, на который ссылаемся
condition нет l,nl,g,ng,e,ne Условие сравнения количества связанных документов (используется вместе с count; реализовано частично – вызывает ошибку)
count нет integer Ожидаемое количество документов для сравнения (см. condition)
valuevar нет строка Зарезервировано; в текущей реализации не используется
leftp нет строка Зарезервировано; не используется
rightp нет строка Зарезервировано; не используется

Логика работы:

  • Если внутри <reference> нет ни вложенных <reference>, <property>, <status>, <operation>, ни <select>, и режим запроса = 4–6, то такой элемент при referencing="join" или внешнем соединении превращается в условие 1=1.
  • В остальных случаях для <reference> генерируется подзапрос EXISTS (или NOT EXISTS при referencing="is null"), в котором проверяется наличие связанных документов и дополнительно накладываются вложенные условия (свойства, статусы, другие ссылки).
  • При referencing="join" и режимах 4–6 (специальные режимы отчётов) возможен сценарий с OUTER JOIN, но детали определяются вложенными условиями.

4. Элемент <property>

Задаёт фильтр по значению конкретного свойства документа (или по служебному идентификатору).

<property
  docprop_id="ID_СВОЙСТВА"
  condition="код_операции"
  [doc_prop_value="значение"]
  [valuevar="макрос"]
  [value="значение"]
  [type="s|t|n|d|v"]
  [kindtype="число"]
/>
Атрибут Обязат. Тип Описание / Возможные значения
docprop_id да integer Идентификатор свойства документа. Особые значения:
-2 – ID документа (прямая выборка по document_id);
-4 – дата события (event_date);
-5, -6 – пользователь, породивший событие (event_user);
-7 – описание документа (doc_descr). Остальные числа – обычные свойства из doc_kind_properties
condition да строка Код операции сравнения (см. таблицу ниже)
doc_prop_value нет* строка Непосредственное значение для сравнения. Допускается использование макросов (см. раздел 6). *Обязательно, если только не используется IS NULL/IS NOT NULL.
valuevar нет строка Ссылка на переменную или макрос; если задана и condition != 'DIRECT', подменяет собой doc_prop_value.
value нет строка Альтернативное значение (например, для работы со словарями; приоритет ниже doc_prop_value).
type нет символ Тип свойства (берётся из БД, если не указан):
s – строка, t – текст, n – число, d – дата, v – ссылка на словарь и т.п.
kindtype нет integer Подтип свойства (берётся из БД). Влияет на построение условия (например, 4 – иерархический словарь, 10 – мультизначное свойство).

Коды операций (condition) и их SQL‑эквиваленты:

Код SQL оператор Примечание
e = или IN IN используется для свойств типа v, t и kindtype=4 (словарь)
ne <> или NOT IN аналогично
l <
nl >=
g >
ng <=
like LIKE
not like NOT LIKE
in IN Только для строковых типов (s, t), если kindtype != 4
d DIRECT Специальный режим: прямое присоединение таблицы свойств без EXISTS (используется для docprop_id=-2)
is null IS NULL
is not null IS NOT NULL
min MIN (зарезервировано, используется в агрегациях)
max MAX (зарезервировано)

Особые docprop_id:

  • -2 (DIRECT): фильтр по идентификаторам документов.
    • doc_prop_value – список ID через запятую, например "10,20,30".
    • valuevar – имя функции, возвращающей массив ID (вызывается через Xml2SelectDb.execFunc).
  • -4: фильтр по дате события (event_date). Для condition='<=...' значение автоматически корректируется на конец дня.
  • -5, -6: фильтр по пользователю события (event_user).
  • -7: фильтр по текстовому описанию (doc_descr). Для операторов LIKE/NOT LIKE – сравнение без учёта регистра.

5. Элемент <status>

Фильтрация по статусу (виду события) документа.

<status doceventkind_id="ID_СОБЫТИЯ" />

Может встречаться многократно. Каждый экземпляр задаёт одно значение doceventkind_id.
В SQL формируется условие:
dt_{level}.doceventkind_id IN (0, список_ID_событий)

Если список событий в XML совпадает с полным набором событий для данного вида документа (или полный набор пуст), условие не добавляется (чтобы не перегружать запрос избыточным перечислением).


6. Элемент <operation>

Группирует несколько условий с заданной логической связкой.

<operation name="and|or">
   <!-- reference, property, status, другие operation -->
</operation>
  • name="and" – все вложенные условия объединяются через AND.
  • name="or" – через OR.
  • Атрибут name можно опустить; тогда элемент становится прозрачным контейнером (вложенные условия просто передаются на уровень выше без добавления собственной группы).

7. Элемент <select> (зарезервирован)

Присутствует в коде, но не влияет на итоговый SQL. Его наличие/отсутствие используется только во внутренней логике определения, нужно ли создавать OUTER JOIN.
Пример:

<select />

В текущей реализации его содержимое игнорируется.


8. Подстановка макросов в значениях

В атрибутах doc_prop_value, valuevar, value (а также @_valuevar у <reference>) могут использоваться макросы.
Поддерживаются следующие макросы (регистр важен):

Макрос Подстановка
@USERID ID текущего пользователя (documents.get_user_id)
@USERNAME Полное имя пользователя (Фамилия Имя Отчество)
@ROLEID ID текущей роли пользователя (documents.get_role_id)
@ROLENAME Название роли
@DEPARTID Идентификатор подразделения пользователя
@DATE Текущая дата/время (SYSDATE); может комбинироваться с функциями: @DATE+1, @DATE-7 и т.п.
GET_USER_FILIALS Вызов функции GET_USER_FILIALS (и другие подобные)
NOW, TODAY, WORKDAY, MONTHDAY, *YEAR* Вызов соответствующей функции БД, возвращающей дату

Макросы распознаются по точному совпадению (@USERID) или по вхождению в строку (например, TO_DATE('@DATE','DD.MM.YYYY') приводит к подстановке SYSDATE).

Если значение начинается с буквы и содержит скобки (например, my_func(1,2)), то оно рассматривается как вызов функции БД и выполняется через Xml2SelectDb.execFunc или execDate.


9. Примеры

Простейший запрос (получить все документы вида 10)

<query>
  <formal dockind_id="10" />
</query>

Фильтр по свойствам и статусу

<query>
  <formal dockind_id="10" name="and">
    <property docprop_id="100" condition="e" doc_prop_value="Иванов"/>
    <property docprop_id="101" condition="g" doc_prop_value="1000"/>
    <status doceventkind_id="3"/>
    <status doceventkind_id="5"/>
  </formal>
</query>

Ссылка на связанный документ

<query>
  <formal dockind_id="10">
    <reference docprop_id="200" referencing="join" dockind_id="20">
      <property docprop_id="201" condition="like" doc_prop_value="%утверждён%"/>
    </reference>
  </formal>
</query>

Анти‑ссылка (NOT EXISTS)

<reference docprop_id="200" referencing="is null" dockind_id="20"/>

Использование макроса

<property docprop_id="102" condition="e" doc_prop_value="@USERID"/>

Группировка условий с OR

<operation name="or">
  <property docprop_id="100" condition="e" doc_prop_value="A"/>
  <property docprop_id="100" condition="e" doc_prop_value="B"/>
</operation>

Выборка по списку ID

<property docprop_id="-2" condition="d" doc_prop_value="101,205,330"/>

или через функцию:

<property docprop_id="-2" condition="d" valuevar="my_package.get_docs(55)"/>