RQL-выражения для работы с объектами доменов

В данном разделе описано, как использовать язык RQL в политиках доступа и правилах данных схем доменов. Описано создание RQL-выражений, которые включают получение данных, фильтрацию и обогащение, а также управление выводом данных.

В данном разделе при описании RQL-выражений приняты следующие соглашения:

  • Необязательные компоненты выражений заключаются в квадратные скобки.

  • Под обозначением <expression> понимается выражение, то есть применение оператора, функция, идентификатор, литерал, арифметическое выражение или выражение в скобках.

  • Имена функций и операторов RQL могут использоваться как в верхнем, так и в нижнем регистре. В этом разделе имена функций приведены в верхнем регистре, если они являются обертками или имеют прямой аналог среди нативных функций SQL.

Синтаксис RQL-выражений

Описанный в этом разделе синтаксис RQL-выражений используется для описания условий в политиках доступа, а также в правилах данных схем доменов. В правилах данных RQL-выражения используются в блоках rql:

  • для описания условий срабатывания правил;

  • для вычисления значений при эффектах default и allowed;

  • для валидации данных при эффекте allowed.

В RQL не указывается имя таблицы, так как контекст выполнения всегда задается текущим доменом:

Сводный синтаксис RQL-выражения
SELECT
  field_name [AS alias_name],
  field_name_2 [AS alias_name_2],
  [with(@subquery_alias, select(<expression>))],
  [from('domain.id', @source_id, @source_alias)],
  [join('domain.id', @source_id, @source_alias, on(eq(<expression>)))]
[(INNER | LEFT | RIGHT | FULL) JOIN other_entity_name [AS join_alias_name]
  ON <expression>]
[WHERE <expression>]
[ORDER BY field_name [ASC | DESC]]
[LIMIT <m> [OFFSET <n>]]

В RQL-выражениях могут опускаться компонент SELECT * и оператор WHERE при указании условия:

Примеры соответствия выражений RQL и SQL
RQL SQL Комментарий
SELECT organizationId WHERE LENGTH(organizationId) = 5
SELECT organizationId FROM table WHERE LENGTH(organizationId) = 5

Указывать имя таблицы не нужно.

В RQL-выражении можно вызывать встроенную функцию с аргументами.

id = 'abcdef'
SELECT * FROM table WHERE id = 'abcdef'

При фильтрации оператор WHERE можно не указывать.

@doc.id = 42
SELECT * FROM table AS doc WHERE doc.id = 42

Используется системный псевдоним @doc.

@CurrentTimestamp
@CurrentDateTime
CURRENT_TIMESTAMP

Используются системные псевдонимы @CurrentTimestamp и @CurrentDateTime.

@CurrentDate
CURRENT_DATE

Используется системный псевдоним @CurrentDate.

@CurrentTime
CURRENT_TIME

Используется системный псевдоним @CurrentTime.

NOT attr BETWEEN 1245 AND 2345
attr NOT BETWEEN 1245 AND 2345

Проверка нахождения вне диапазона.

ARRAY(x, y)
ARRAY[x, y]

Для создания массива используется функция ARRAY().

join(@Person, @p, on(and(eq(@doc.catOwner, @p.id), or(eq(@doc.createdBy, @p.id), eq(@doc.assignedTo, @p.id)))))
INNER JOIN @Person as @p ON @doc.catOwner = @p.id AND (@doc.createdBy = @p.id OR @doc.assignedTo = @p.id)

Использование функции соединения.

Обращение к сущностям и связям

Обращение к атрибутам сущностей

Чтобы обратиться к атрибуту сущности, используйте один из следующих способов:

  • Указание только названия поля. При обращении к полям таблицы без указания ее названия система автоматически начинает поиск поля только в основной сущности.

    Синтаксис
    <field_id>
    Рекомендуется использовать данный способ, только если в выражении используется лишь одна сущность.
    Пример

    Условие выполняется, если значение поле login текущей сущности User равно some_name. Условие можно записать так:

    condition: !rql login = 'some_name'
  • Указание идентификатора сущности и названия поля.

    Синтаксис
    @<entity_id>.<field_id>

    Обращения вида @<entity_id>.<field_id> допустимы только в следующих случаях:

    • Сущность явно присоединена через JOIN.

    • Сущность описана в выражении с with() или from().

    Для текущей сущности можно использовать специальный псевдоним @doc.

    Примеры
    • Сущность Category присоединена конструкцией вида JOIN Category. К полю name сущности Category можно обратиться так: @Category.name.

    • Условие выполняется, если значение поле username текущей сущности SystemUser равно some_name. Условие можно записать так:

      condition: !rql @doc.username = 'some_name'
  • Указание псевдонима сущности и названия поля.

    Синтаксис
    @<entity_alias>.<field_id>
    Примеры

    Сущность Category присоединена конструкцией вида JOIN Category AS cat. К полю name сущности Category можно обратиться так: cat.name.

Здесь:

  • <entity_id> — идентификатор сущности из схемы домена;

  • <field_id> — идентификатор атрибута сущности из схемы домена;

  • <entity_alias> — псевдоним сущности, заданный в RQL-выражении конструкцией AS …​

Обращение к элементам массива

Индексы элементов массива указываются в квадратных скобках. Нумерация элементов массива начинается с 1. Таким образом, в массиве из n элементов первый элемент имеет индекс array[1], а последний — array[n].

Пример
constraint: !rql relatives IS NULL OR (@doc.relatives[1] LIKE '%строка'
AND CAST(@doc.relatives[2], 'INTEGER') = 42)

Данное RQL-выражение задает ограничение для атрибута relatives:

  • Если значение атрибута отсутствует (NULL), ограничение считается выполненным.

  • В противном случае:

    • Из массива relatives берется первый элемент и проверяется, что его строковое значение оканчивается на подстроку "строка".

    • Из того же массива берется второй элемент, приводится к типу INTEGER и сравнивается с числом 42.

Таким образом, атрибут relatives либо не должен быть задан, либо должен содержать массив, в котором первый и второй элементы удовлетворяют указанным условиям.

Обращение к атрибутам таблицы

Обращаться к столбцам таблицы в текущей строке можно с помощью псевдонима @row:

Синтаксис
@row.<table_field>

Здесь <table_field> — идентификатор атрибута внутри атрибута-таблицы в схеме домена.

Извлечение компонентов значений

Получить значение поля из метаданных атрибута типа Файл (Attachment) можно с помощью функции extract(), например:

extract(@doc.attachment, 'filename')

С помощью этого выражения мы извлекаем имя файла из атрибута attachment текущего объекта.

Извлечь компоненты из даты и времени можно с помощью функции DATE_PART(), например:

DATE_PART('hour', @CurrentTimestamp)

В этом выражении мы извлекаем значение часа из текущей метки времени.

Обращение к связи

Чтобы обратиться к связи, используйте ее псевдоним @<linkage_alias>, заданный одним из следующих способов:

  • Связь явно присоединена через JOIN.

  • Связь описана в выражении с with() или from().

В рамках связи можно обратиться:

  • К сторонам связи: @<linkage_alias>.<sideN>.

  • К атрибутам связи, в том числе системным: @<linkage_alias>.<field_id>.

Здесь:

  • <linkage_alias> — псевдоним связи, заданный в RQL-выражении;

  • <field_id> — идентификатор атрибута сущности из схемы домена;

  • <sideN> — сторона связи:

    • side1 — сторона 1;

    • side2 — сторона 2.

Пример
SELECT @links.side2, from('current', @linkages_allattributes, @links) WHERE @links.side1 = @doc.id

В этом примере связь linkages_allattributes в текущем домене указывается как источник данных с псевдонимом links. Затем применяется фильтрация по стороне 1 связи и выбирается сторона 2.

Указание возвращаемых полей (оператор SELECT)

Контекстом выполнения RQL-выражений являются объекты сущностей и связей, для которых в схеме домена определена структура данных в виде атрибутов.

Оператор SELECT используется для указания определенных полей, которые будут включены в результат RQL-выражения. Имена полей отделяются друг от друга запятыми.

SELECT <expression>[, <expression>]
Не ставьте разделитель после последнего поля, включенного в выражение.

Если в RQL-выражении нет оператора SELECT или указана конструкция SELECT *, то оно вернет все атрибуты, описанные для сущности в схеме домена. Поэтому, если не требуется четкое определение формата данных, оператор SELECT может опускаться.

Пример
expression: !rql SELECT 'заданное имя' AS defaultName

В данном RQL-выражении задается значение по умолчанию для атрибута defaultName — "заданное имя".

В случаях, когда в выражении нужно использовать промежуточные вычисления, используйте функцию SELECT().

Формирование массивов

Массивы в выражениях используются для формирования списков значений. Массив можно задать одним из двух способов:

  • Перечисление значений в квадратных скобках. Этот способ подходит для конструкции с SELECT, если массив состоит из чисел или строк:

    Выборка массива чисел
    SELECT [1, 2, 3, 4] as items
  • Создание массива через функцию ARRAY(). Этот способ используется:

    • если проверяются вхождения значения в какое-либо множество с помощью функции ANY() или оператора IN;

    • если в массиве есть ссылки на атрибуты сущностей или псевдонимы.

Примеры

Проверка вхождения в массив из значения атрибута и псевдонима
attr IN SELECT(UNNEST(ARRAY(users.name, @CurrentUser.id)))

В данном случае для использования элементов массива в выборке используется функция UNNEST().

Выражение с выборкой массива из элементов перечисления
expression: !rql SELECT ARRAY(@enumIocTypes.Account, @enumIocTypes.File)

В данном выражении используется ссылка на перечисление, описанное в схеме домена.

Выражение с массивом из диапазонов времени
expression: !rql SELECT ARRAY(TSRANGE('2025-04-01', '2025-05-01'), TSRANGE('2025-10-01', '2025-11-01'))

В данном выражении используется ссылка на перечисление, описанное в схеме домена.

Использование псевдонимов (оператор AS)

При описании формата результата могут использоваться различные выражения, включая арифметические операции и встроенные функции. Чтобы использовать результат такого выражения, ему нужно присвоить псевдоним:

Выражение с использованием псевдонима для функции LENGTH()
SELECT LENGTH(someString) AS len

Ознакомьтесь с описанием псевдонимов.

Указание источников данных (from())

Функция from() используется совместно с оператором SELECT и позволяет выполнять выборку из указанной сущности или связи.

Синтаксис
from(['<domain_id>', ]@<source_id>[, <source_alias>])

Здесь:

  • <domain_id> — идентификатор домена. По умолчанию — текущий домен.

    Для обращения к текущему домену можно использовать псевдоним 'current'.
  • <source_id> — идентификатор сущности или связи.

  • <source_alias> — псевдоним сущности или связи для использования в условиях. По умолчанию принимает значение имени сущности или связи.

Пример
SELECT
  @links.side2,
  from('current', @linkages_allattributes, @links)
WHERE @links.side1 = @doc.id
ORDER BY @links.side1 DESC
LIMIT 1

В данном примере:

  1. Происходит выборка из связи linkages_allattributes в текущем домене. Выборке присваивается псевдоним @links.

  2. Выборка фильтруется по значению стороны 1 — выбираются экземпляры связи, в которых на этой стороне находится текущий объект.

  3. Результат сортируется по стороне 1 в порядке возрастания.

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

  5. Запрос возвращает значение стороны 2 в результате.

Соединение данных из нескольких сущностей (оператор и функции JOIN)

Данные из нескольких сущностей можно объединять и фильтровать с помощью оператора JOIN и функций объединения. Записи можно фильтровать по наличию связи с определенной сущностью, а также по значениям атрибутов связанной сущности.

Ознакомьтесь с описанием оператора JOIN.

Использование условий (оператор WHERE)

При использовании RQL-выражений для фильтрации данных оператор WHERE можно не указывать.

При использовании проекций оператор WHERE позволяет применять к указанным полям выборку по определенному условию.

Синтаксис
SELECT <expression> WHERE <expression>
Пример выборки строк по условию
SELECT organizationId WHERE length(organizationId) = 5

Это RQL-выражение возвращает события с количеством символов в поле organizationId, равным 5.

В условиях используются операторы сравнения, работы с множествами и проверки на пустое значение. Ознакомьтесь с описанием условий.

Сортировка возвращаемых результатов (оператор ORDER BY)

Результаты запроса можно сортировать по любому полю с помощью оператора ORDER BY.

Направление сортировки задается модификаторами:

  • ASC — по возрастанию;

  • DESC — по убыванию.

Синтаксис
[SELECT <expression>]
ORDER BY
  <field_name_1> [ASC | DESC],
  <field_name_2> [ASC | DESC],
  ...,
  <field_name_N> [ASC | DESC]

Здесь:

  • <field_name_1> …​ <field_name_N> — имена полей, по которым нужно отсортировать результаты.

Пример сортировки
ORDER BY collectorId

Это выражение возвращает записи с сортировкой по полю collectorId в порядке возрастания.

Максимальное количество и пропуск возвращаемых записей (операторы LIMIT и OFFSET)

Вы можете ограничить количество возвращаемых записей с помощью оператора LIMIT.

Также можно добавить команду OFFSET, которая указывает, сколько строк необходимо пропустить перед началом вывода. Это полезно, если вы хотите начать вывод данных с определенной строки.

Синтаксис
LIMIT <m> [OFFSET <n>]

Здесь:

  • <m> — число записей, до которого нужно сократить выборку;

  • <n> — число пропускаемых записей.

Пример

Пример ограничения количества записей
LIMIT 20

Это выражение ограничивает выборку 20 записями.

Пример пропуска записей
LIMIT 20 OFFSET 10

Это выражение позволяет пропустить первые 10 строк и вывести следующие 20.

Рекомендуется использовать команду OFFSET только при необходимости, особенно с большими значениями пропуска, так как это снижает производительность.

Функции, вложенные запросы и CTE

В RQL поддерживаются функции, а также вложенные запросы и общие табличные выражения (CTE). Результат их выполнения используется в местах вызова.

Вложенные запросы и общие табличные выражения задаются с помощью специальных функций with() и SELECT(). Внутри таких выражений применяются конструкции для управления выборкой в виде функций. Они аналогичны одноименным операторам в основном запросе.

Ознакомьтесь с подробным описанием в разделах:

Примеры использования RQL-выражений в правилах данных

dataRules:
  - id: dataR_hidden_table
    name: Attribute hidden
    description: К атрибуту tableAttr применяется эффект hidden, если для текущего объекта отсутствуют экземпляры связи some_linkage.
    target: entity
    entity: SomeEntity
    condition: !rql |
      SELECT(count(id), FROM('current', @linkage_vulnerability, @link), WHERE(eq(@link.side1, @doc.id))) = 0
    rule:
      effect: hidden
      attributes:
        - attribute: tableAttr

В данном примере запрос используется для определения видимости атрибута:

  • Выполняется выборка из связи linkage_vulnerability в текущем домене.

  • Экземпляры фильтруются по соответствию стороны 1 идентификатору текущего объекта.

  • Используется агрегатная функция count() для подсчета количества экземпляров в связи linkage_vulnerability.

  • Количество экземпляров сравнивается с нулем.

  • Если результат равен нулю, атрибут tableAttr не отображается в представлениях объекта.

Таким образом, если объект не связан с уязвимостью, атрибут-таблица не отображается.

Условная обязательность атрибута

dataRules:
  - id: dataR_required_table
    name: Entity required
    description: К атрибуту someAttr применяется эффект required, если у объекта присутствуют определенные связи.
    target: entity
    entity: SomeEntity
    condition: !rql |
      SELECT(count(id), FROM('current', @some_linkage, @link), WHERE(eq(@link.side1, @doc.id))) > 0
    rule:
      effect: required
      attributes:
        - attribute: someAttr

В данном примере запрос используется для определения обязательности атрибута:

  • Выполняется выборка из связи some_linkage в текущем домене.

  • Экземпляры фильтруются по соответствию стороны 1 идентификатору текущего объекта.

  • Используется агрегатная функция count() для подсчета количества экземпляров в связи some_linkage.

  • Количество экземпляров сравнивается с нулем.

  • Если результат больше нуля, атрибут someAttr становится обязательным для заполнения.

Для обратной логики — сделать атрибут обязательным, если связи нет, используется оператор = 0:

dataRules:
  - id: dataR_required_table
    name: Entity required
    description: К атрибуту someAttr применяется эффект required, если у объекта присутствуют определенные связи.
    target: entity
    entity: SomeEntity
    condition: !rql |
      SELECT(count(id), FROM('current', @some_linkage, @link), WHERE(eq(@link.side1, @doc.id))) = 0
    rule:
      effect: required
      attributes:
        - attribute: someAttr

Динамическая фильтрация справочника

dataRules:
  - id: dataR_allowed_table
    name: Entity allowed
    description: Применение эффекта allowed к атрибуту city_id на основе выбранного значения country_id.
    target: entity
    entity: SomeEntity
    condition: !rql |
      country_id IS NOT NULL
    rule:
      effect: allowed
      attributes:
        # Атрибут типа Reference.
        - attribute: city_id
          expression: !rql |
            SELECT @city.id AS 'city_id', @city.name AS 'name', FROM('dictionaries.example.com', @cities, @city) WHERE @city.country_id = @doc.country_id ORDER BY @city.name ASC
         constraint: !rql |
           city_id IN SELECT(@city.id, FROM('dictionaries.example.com', @cities, @city), WHERE(eq(@city.country_id, @doc.country_id)))

Данное правило реализует зависимость между двумя атрибутами:

  • Условие: правило применяется только после заполнения атрибута country_id.

  • Выражение: формирует динамический список значений из внешнего домена dictionaries.example.com, фильтруя их по значению country_id в текущем объекте.

  • Ограничение: выполняет валидацию, гарантируя, что указанное пользователем значение действительно принадлежит к списку.

Таким образом, после указания страны пользователь может выбирать только города этой страны.

Фильтрация по атрибуту связанной сущности

dataRules:
  - id: dataR_required_table
    name: Entity required example
    description: Установление обязательности поля в зависимости от атрибутов связанного объекта.
    target: entity
    entity: SomeEntity
    condition: !rql |
      SELECT join('current', @some_linkage, @link, ON(eq(@link.side1, @doc.id))), join('current', @incidents, @incident, ON(eq(@link.side2, @incident.id))) WHERE @incident.weight > 100
    rule:
      effect: required
      attributes:
        - attribute: someAttr

В данном примере используется цепочка соединений через функции join():

  • Первое соединение связывает экземпляры связи some_linkage с текущим объектом. Соединение определяется равенством стороны 1 связи и идентификатора текущего объекта.

  • Второе соединение связывает сторону 2 связи с сущностью incident.

  • Фильтрация проверяет атрибут weight связанной сущности incidents.

  • Атрибут someAttr становится обязательным, если найден хотя бы один связанный инцидент с весом больше 100.

Фильтрация по атрибуту связи

dataRules:
  - id: dataR_required_link_attr
    name: Entity required example
    description: Установление обязательности поля в зависимости от атрибута связи.
    target: entity
    entity: SomeEntity
    condition: !rql |
      SELECT join('current', @some_linkage, @link, ON(eq(@link.side1, @doc.id))) WHERE @link.weight > 100
    rule:
      effect: required
      attributes:
        - attribute: someAttr

В данном примере проверяется значение атрибутов самой связи:

  • Соединение связывает экземпляры связи some_linkage с текущим объектом. Соединение определяется равенством стороны 1 связи и идентификатора текущего объекта.

  • Фильтрация проверяет атрибут weight связи.

  • Атрибут someAttr становится обязательным, если вес связи больше 100.

Фильтрация по значению атрибута объекта по ссылке

Проверка статуса пользователя
dataRules:
  - id: dataR_allowed_user
    name: Entity allowed
    description: Применение эффекта allowed к атрибуту user_id в зависимости от значения объекта по ссылке.
    target: entity
    entity: Incident
    condition: true
    rule:
      effect: allowed
      attributes:
        # Атрибут типа Reference.
        - attribute: responsible_user_id
          expression: !rql |
            SELECT @user.id AS user_id, @user.name AS name, FROM('users.example.com', @users, @user) WHERE @user.isActive = true ORDER BY @user.name ASC
          constraint: !rql |
            responsible_user_id IN SELECT(@user.id, FROM('users.example.com', @users, @user), WHERE(@user.isActive))
В данном примере предполагается, что существует домен users.example.com с сущностью user.

Пример работы с атрибутом типа Референс (Reference):

  • Производится выборка из домена users.example.com.

  • В списке доступных значений атрибута responsible_user_id допускаются идентификаторы объектов user, у которых атрибут isActive равен true.

  • При валидации проверяется, что значение responsible_user_id относится к тому же списку допустимых идентификаторов.

Таким образом, ответственным за инцидент можно назначить только пользователя с активной учетной записью.

Проверка типа ПО
dataRules:
  - id: dataR_allowed_software
    name: Entity allowed
    description: Фильтрация справочника ПО, позволяющая выбирать только записи с типом Системное.
    target: entity
    entity: OperationalSystem
    condition: true
    rule:
      effect: allowed
      attributes:
        # Атрибут типа Reference.
        - attribute: software_id
          expression: !rql |
            SELECT @software.id AS software_id, @software.name AS name, FROM('dictionaries.example.com', @software) WHERE @software.type = 'Системное' ORDER BY @software.name ASC
          constraint: !rql |
            software_id IN SELECT(@software.id, FROM('dictionaries.example.com', @software), WHERE(eq(@software.type, 'Системное')))

Здесь фильтрация справочника выполняется по заданному строковому значению атрибута type. Таким образом, при создании сущности "Операционная система" можно создать ссылку software_id только на ПО с типом "Системное".

Запрет изменения значения в зависимости от наличия связей

dataRules:
  - id: dataR_status_restriction
    name: Entity allowed example
    description: Ограничение возможности изменения атрибута.
    target: entity
    entity: Incident
    condition: !rql |
      SELECT(count(id), FROM('current', @assignies, @assignee_link), WHERE(eq(@assignee_link.side1, @doc.id))) = 0
    rule:
      effect: allowed
      attributes:
        - attribute: status
      constraint: !rql |
        status != 'Закрыт'

В данном примере эффект allowed используется для валидации значения атрибута:

  • Вложенный запрос проверяет количество экземпляров связи assignies для текущего объекта.

  • Если связей нет, применяется ограничение: значение атрибута status не должно быть равно "Закрыт".

Таким образом, инцидент нельзя закрыть, если не назначен ответственный.

Была ли полезна эта страница?

Обратная связь