Логика работы универсального фильтра

Содержание

Логика работы универсального фильтра#

В документации описано, как универсальный фильтр определяет доступные поля, формирует условия фильтрации и генерирует SQL-выражения.

Общая схема работы#

EntityAvi — это мастер-выборка, от которой наследуются другие выборки. Операция универсального фильтра находится в EntityAvi, поэтому она доступна на всех выборках.

Фильтрация реализована через объекты Scala-классов, которые формируются и хранятся в памяти. Настройки фильтра сохраняются в базе данных в виде JSON.

Управление фильтрацией выполняется через объект fltManager. Каждый экземпляр отображения создает собственный экземпляр менеджера фильтра.

По умолчанию фильтрация доступна:

  • по атрибутам выборки;

  • по атрибутам класса, определяемого через Avi-функцию thisApi();

  • по коллекциям класса, добавленным из ODM или из вкладки Коллекции универсального фильтра в карточке класса.

Сохраненная настройка фильтра не обновляется автоматически при изменении свойств атрибутов. Она использует состояние атрибутов на момент их добавления. Для изменения поведения атрибута необходимо удалить его из фильтра и добавить заново.

Связь выборки и класса#

Контекст фильтрации определяется через функцию thisApi(), которая связывает выборку с классом.

За счет этого фильтр получает доступ к:

  • атрибутам класса;

  • характеристикам;

  • коллекциям.

Связь атрибута выборки и атрибута класса#

Атрибуты выборки сопоставляются с атрибутами класса по системному имени.

Если у выборки указан класс, то:

  • атрибут выборки связывается с атрибутом класса с тем же именем;

  • метаданные объединяются (тип редактора, ссылочность и т.д.).

Тип редактора определяется следующим образом:

  • для атрибутов выборки — как указано в выборке;

  • для атрибутов класса:

    • если задан в ODM — используется он;

    • иначе определяется по типу данных.

Особенности редакторов:

  • выпадающие списки — редактор с тремя точками;

  • даты — интерфейс Фильтрации по периоду;

  • ссылочные атрибуты — редактор с тремя точками;

  • множественные сравнения — также через редактор с тремя точками;

  • числовые признаки — редактор чекбокс;

Внимание

Если числовой атрибут должен отображаться в универсальном фильтре как чекбокс, в odm.xml необходимо явно указать тег <booleanColumn/>.

Одного attribute-type="Number" и editorType="check" недостаточно. Без <booleanColumn/> универсальный фильтр может определить атрибут как числовой, из-за чего в значении фильтра будет отображаться поле ввода числа, а не чекбокс.

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

<attr name="bRoundTheClockWork"
      attribute-type="Number"
      caption="Круглосуточная работа"
      editorType="check"
      type="basic"
      isObjectAttr="true">
    <booleanColumn/>
</attr>

Доступные элементы фильтра#

Атрибуты выборки#

Атрибутами выборки считаются все поля, присутствующие в дата-сете.

  • формируются только при активной выборке;

  • тип данных определяется типом в дата-сете;

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

Атрибуты класса#

Для класса в универсальный фильтр по умолчанию попадают все атрибуты, кроме idClass.

При необходимости отдельные атрибуты можно отключить для универсального фильтра:

<attr name="bError">
    <uniFilter isActive="false"/>
</attr>

Коллекции#

Коллекции добавляются:

  • из ODM;

  • из вкладки Коллекции универсального фильтра в карточке класса.

Фильтрация выполняется через exists / not exists.

Объектные характеристики#

Объектные характеристики хранятся в JSON (jObjAttrs_dz) и отображаются в универсальном фильтре как отдельные атрибуты.

Фильтрация по объектным характеристикам выполняется через SQL-выражение.

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

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

  • через вкладку «Объектные характеристики» в настройках типа объекта класса.

Если характеристика подключена через тип объекта, она доступна для объектов соответствующего типа. Если характеристика подключена через группировку, она доступна для объектов, которые относятся к этой группе.

Универсальные характеристики#

Универсальные характеристики отображаются в универсальном фильтре как отдельные атрибуты.

Фильтрация выполняется следующим образом:

  • единичные характеристики фильтруются через выражения;

  • множественные характеристики фильтруются через exists / not exists.

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

  • через группировку объектов;

  • через вкладку «Объектные характеристики» в настройках типа объекта класса.

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

Примечание

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

Технические атрибуты#

Технические атрибуты формируются при наличии связи выборки с классом.

Доступные технические атрибуты:

  • sHeadLine#;

  • sMnemoCode#;

  • dModifyDate#;

  • dCreateDate#;

  • sModifyUser#;

  • sCreateUser#;

  • IdGroup# — доступен только при включенном сервисе группировки;

  • idObject#.

Инициализация атрибутов фильтра#

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

Инициализация по выборке#

В lazyInitFilter:

  • формируются атрибуты выборки;

  • дополняются метаданными класса;

  • выполняется только при наличии дата-сета.

Инициализация по классу#

Дополнительно формируются:

  • атрибуты класса;

  • характеристики;

  • коллекции;

  • технические атрибуты.

Для управления инициализацией атрибутов фильтра используется точка расширения фильтра.

Примеры см. в документе:
[Практические сценарии настройки и расширения универсального фильтра.](/040_selection/010_Универсальный_фильтр/030_Практические_сценарии_настройки_универсального_фильтра.md)

Атрибуты переменной ссылочности#

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

Правила раскрытия зависят от настройки ссылочности:

  • если атрибут ссылается на mixin, при раскрытии дерева формируется подуровень со всеми классами, к которым подключен этот mixin;

  • если атрибут ссылается на один класс, при раскрытии отображаются атрибуты этого ссылочного класса;

  • если в odm.xml или avm.xml указан список классов, при раскрытии дерева формируется подуровень со всеми классами из этого списка;

  • если ссылочность не определена, атрибут не раскрывается в дереве и ведет себя как строковый атрибут. В качестве значения фильтрации указывается gid.

Пример настройки списка классов для атрибута переменной ссылочности:

<attr name="gidRefDocument" type="refAnyObject">
    <uniFilter>
        <refAnyObject>
            <ref name="Wf_Doc"/>
            <ref name="Cnt_Contract"/>
        </refAnyObject>
    </uniFilter>
</attr>

Приоритет определения ссылочности:

  1. avm.xml > attr > uniFilter.refClass;

  2. avm.xml > attr > uniFilter.refAnyObject;

  3. avm.xml > attr > ref class;

  4. odm.xml > attr > uniFilter.refClass;

  5. odm.xml > attr > uniFilter.refAnyObject;

  6. odm.xml > attr > ref.class.

Примечание

Настройки ссылочности из avm.xml имеют приоритет над настройками из odm.xml.

Например, если в avm.xml для атрибута указан refClass, а в odm.xml для этого же атрибута задан список классов через refAnyObject, универсальный фильтр будет использовать ссылочность из avm.xml.

Особенности атрибутов#

Выражения фильтрации#

Позволяют задавать SQL-логику:

  • используются для JSON;

  • позволяют вычислять значения атрибутов.

HL-атрибуты#

HL – атрибуты (далее IdAttrHL) считаются ссылочными атрибутами и в фильтрации не участвуют. Фильтрация осуществляется по их id-атрибутам (далее IdAttr).

Ссылочность определяется:

  • Через тег <ref>, например: <ref class="Rpl_IntOutSession"/>.

  • Через одноименный атрибут класса этой выборки.

Формирование условий фильтрации#

Фильтр преобразует настройку, заданную пользователем в интерфейсе, в SQL-условие.

При построении условия используется главная группа MainGroup. В результате формируется макрос onlyWhere, то есть фрагмент условия без полного SQL-запроса.

При формировании макроса учитываются:

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

  • логические группы «И» и «ИЛИ», которые определяют порядок объединения условий;

  • условия по коллекциям, которые преобразуются в exists / not exists.

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

Использование физических имен атрибутов при формировании макроса#

При формировании SQL-макроса универсальный фильтр использует физические имена атрибутов. Физическое имя определяет, какое поле или выражение будет подставлено в SQL-условие.

В большинстве случаев физическое имя совпадает с системным именем атрибута. Исключения возможны для технических и специальных атрибутов.

Например:

  • для IdObject# в макрос может подставляться физическое поле ID;

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

За счет этого пользователь работает с логическим именем атрибута в интерфейсе фильтра, а при построении макроса система преобразует его в поле или выражение, которое можно использовать в SQL.

Объектные и реляционные запросы#

Универсальный фильтр работает в двух сценариях.

Фильтрация ROP-объектов#

Фильтрация ROP-объектов — это отдельный программный сценарий работы универсального фильтра. Он не применяется автоматически в UI-выборках и используется только в прикладном коде, когда разработчик явно передает в механизм фильтрации коллекцию ROP-объектов.

Механизм работает следующим образом:

  1. Коллекция ROP-объектов преобразуется во временное JSON-представление.

  2. По настройке универсального фильтра формируется SQL-выражение для работы с этим JSON-представлением.

  3. Условие фильтрации применяется к JSON-представлению объектов.

  4. Возвращается отфильтрованная коллекция ROP-объектов.

Ограничения такого сценария:

  • универсальный фильтр не работает автоматически в выборках, построенных на объектном запросе;

  • фильтрация не учитывает изменения, которые находятся только в сессионном кеше;

  • не учитываются изменения в коллекциях фильтруемых объектов, если эти изменения не попали в JSON-представление;

  • не учитываются изменения в ссылочных объектах, если они не были отражены в JSON-представлении;

  • результат фильтрации зависит от состава данных, которые разработчик передал в коллекции ROP-объектов.

Пример программного применения см. в разделе Применение к объектным данным.

Реляционные запросы#

  1. Анализируется модель данных;

  2. Формируются атрибуты фильтра:

    • ссылочные;

    • переменной ссылочности;

    • значимые;

  3. Строится SQL-условие.

  4. Для коллекций используется exists.

Преобразование условий в SQL#

Система формирует SQL на основе:

  • атрибута;

  • типа сравнения;

  • значения.

Строковый атрибут

Условие

Пример

Содержит

upper(<атрибут>) like upper('%value%')

Равно

upper(<атрибут>) = upper('value')

Не равно

upper(<атрибут>) <> upper('value')

В списке

upper(<атрибут>) in (upper('value1'), upper('value2'))

Заполнено

is not null

Для строковых атрибутов сравнение выполняется в верхнем регистре, поэтому фильтрация не учитывает регистр символов.

Числовой атрибут

Условие

Пример

Равно

=

Больше

>

Меньше

<

Интервал

>= <значение_с> and <= <значение_по>

Подробные примеры SQL-макросов для числовых атрибутов, включая интервал с одной или двумя границами, приведены в разделе Примеры формируемых SQL-макросов.

Булевый атрибут

  • = 1;

  • <> 1;

  • is null;

  • is not null.

Дата

Используется to_timestamp.

JSON

  • is null;

  • is not null.

BLOB / CLOB

  • аналогично JSON или строкам.

Ссылочные атрибуты

  • аналогично числовым.

Примеры формируемых SQL-макросов#

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

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

Строковый атрибут#

Содержит — накладывает условие на регистронезависимое вхождение строки.

upper(t.sCaption) like upper('%'||'value'||'%')

Начинается с — накладывает условие на регистронезависимое начало строки.

upper(t.sCaption) like upper('value'||'%')

Заканчивается на — накладывает условие на регистронезависимое окончание строки.

upper(t.sCaption) like upper('%'||'value')

Равно — накладывает условие на регистронезависимое совпадение строки.

upper(t.sCaption) = upper('value')

Не равно — накладывает условие на регистронезависимое несовпадение строки.

upper(t.sCaption) <> upper('value')

В списке — накладывает условие на регистронезависимое вхождение в список.

upper(t.sCaption) in (upper('value'))

Не в списке — накладывает условие на регистронезависимое отсутствие в списке.

upper(t.sCaption) not in (upper('value'))

Заполнено — накладывает условие на наличие значения.

t.sCaption is not null

Не заполнено — накладывает условие на отсутствие значения.

t.sCaption is null

Не содержит — накладывает условие на регистронезависимое отсутствие подстроки.

upper(t.sCaption) not like upper('%'||'value'||'%')

В интервале — накладывает условие на вхождение строки в заданный интервал.

upper(t.sCaption) >= upper('valueFrom') and upper(t.sCaption) <= upper('valueTo')

Если одна из границ интервала не задана, формируется только одно условие:

upper(t.sCaption) >= upper('valueFrom')

или:

upper(t.sCaption) <= upper('valueTo')

Числовой атрибут#

Равно — накладывает условие на точное совпадение числового значения.

t.nNumber = value

Не равно — накладывает условие на несовпадение числового значения.

t.nNumber <> value

В списке — накладывает условие на вхождение числового значения в список.

t.nNumber in (value)

Не в списке — накладывает условие на отсутствие числового значения в списке.

t.nNumber not in (value)

Заполнено — накладывает условие на наличие числового значения.

t.nNumber is not null

Не заполнено — накладывает условие на отсутствие числового значения.

t.nNumber is null

В интервале — накладывает условие на вхождение числового значения в заданный интервал.

t.nNumber >= valueFrom and t.nNumber <= valueTo

Для интервала не используется between. Условие формируется через отдельные сравнения по нижней и верхней границе.

Если задана только одна граница интервала, формируется только соответствующее условие:

t.nNumber >= valueFrom

или:

t.nNumber <= valueTo

Меньше — накладывает условие на то, что числовое значение меньше заданного.

t.nNumber < 1

Меньше или равно — накладывает условие на то, что числовое значение меньше или равно заданному.

t.nNumber <= 1

Больше — накладывает условие на то, что числовое значение больше заданного.

t.nNumber > 1

Больше или равно — накладывает условие на то, что числовое значение больше или равно заданному.

t.nNumber >= 1

Внимание

Для типа Long виды сравнения «Меньше», «Меньше или равно», «Больше», «Больше или равно» недоступны.

Булевый атрибут#

Равно — накладывает условие на точное совпадение булевого значения.

t.bBool = 1

Не равно — накладывает условие на несовпадение булевого значения.

t.bBool <> 1

Заполнено — накладывает условие на наличие значения.

t.bBool is not null

Не заполнено — накладывает условие на отсутствие значения.

t.bBool is null

Дата#

Равно — накладывает условие на точное совпадение даты.

t.dDate = to_timestamp('31.12.2000 00:00:00','DD.MM.YYYY HH24:MI:SS')

Не равно — накладывает условие на несовпадение даты.

t.dDate <> to_timestamp('31.12.2000 00:00:00','DD.MM.YYYY HH24:MI:SS')

Заполнено — накладывает условие на наличие даты.

t.dDate is not null

Не заполнено — накладывает условие на отсутствие даты.

t.dDate is null

В интервале — накладывает условие на вхождение даты в заданный интервал.

t.dDate >= to_timestamp('31.12.2000 00:00:00','DD.MM.YYYY HH24:MI:SS') 
and t.dDate <= to_timestamp('31.12.2000 00:00:00','DD.MM.YYYY HH24:MI:SS')

Если одна из границ интервала не задана, формируется только соответствующее условие.

Меньше — накладывает условие на то, что дата меньше заданной.

t.dDate < to_timestamp('31.12.2000 00:00:00','DD.MM.YYYY HH24:MI:SS')

Меньше или равно — накладывает условие на то, что дата меньше или равна заданной.

t.dDate <= to_timestamp('31.12.2000 00:00:00','DD.MM.YYYY HH24:MI:SS')

Больше — накладывает условие на то, что дата больше заданной.

t.dDate > to_timestamp('31.12.2000 00:00:00','DD.MM.YYYY HH24:MI:SS')

Больше или равно — накладывает условие на то, что дата больше или равна заданной.

t.dDate >= to_timestamp('31.12.2000 00:00:00','DD.MM.YYYY HH24:MI:SS')

JSON-атрибут#

Заполнено — накладывает условие на наличие JSON-значения.

t.jJson is not null

Не заполнено — накладывает условие на отсутствие JSON-значения.

t.jJson is null

BLOB-атрибут#

Заполнено — накладывает условие на наличие значения.

t.lBlob is not null

Не заполнено — накладывает условие на отсутствие значения.

t.lBlob is null

CLOB-атрибут#

Для CLOB-атрибутов условия формируются по аналогии со строковыми атрибутами.

Ссылочный атрибут#

Для ссылочных атрибутов условия по идентификатору формируются по аналогии с числовыми атрибутами.

Например, при множественном выборе ссылочного значения формируется условие:

t.idMeasureItem in (102104,101954,101967,101973)

Примеры макросов для класса Bs_Goods#

В примерах показана фильтрация списка объектов класса Bs_Goods.

Собственное поле класса#

Если в фильтр добавлен значимый строковый атрибут sPartNumber, формируется условие:

upper(t.sPartNumber) like upper('%'||'abc'||'%')

Ссылочное поле класса через join#

Если пользователь раскрыл ссылочный атрибут и добавил атрибут ссылочного класса, универсальный фильтр формирует условие через exists.

exists(
select 1
  from Msr_MeasureItem t336
 where t336.id = t.idMeasureItem
   and upper(t336.sCodeGOST) = upper('10')
)

Ссылочное поле класса с множественным выбором#

Если пользователь добавил ссылочный атрибут с множественным выбором значений, формируется условие через in.

t.idMeasureItem in (102104,101954,101967,101973)

Фильтрация коллекций#

При фильтрации по коллекциям универсальный фильтр формирует условия через exists.

Коллекция первого уровня вложенности по значимому атрибуту#

Если пользователь добавил коллекцию Bs_GoodsSrc и задал условие по ее значимому атрибуту, формируется вложенное условие:

exists(
select 1
  from Bs_Goods t354
 where t354.id = t.id
   and exists(
     select 1
       from Bs_GoodsSrc t370
      where t370.idGds = t354.id
        and t370.bDefault = 1
   )
)

Коллекция первого уровня вложенности по ссылочному атрибуту через join#

Если пользователь добавил коллекцию Bs_GoodsSrc, раскрыл ссылочный атрибут и добавил атрибут ссылочного класса, формируется условие с join внутри exists.

exists(
select 1
  from Bs_Goods t354
 where t354.id = t.id
   and exists(
     select 1
       from Bs_GoodsSrc t407
       join Bs_Prj t408 on t408.id = t407.idPrj
      where t407.idGds = t354.id
        and t408.idDepOwner = 117801
   )
)

Коллекция второго уровня вложенности#

Если пользователь добавил коллекцию Bs_GoodsSrc, затем коллекцию Bs_PrjVerRange и задал условие по атрибуту вложенной коллекции, формируется несколько уровней exists.

exists(
select 1
  from Bs_Goods t354
 where t354.id = t.id
   and exists(
     select 1
       from Bs_GoodsSrc t410
      where t410.idGds = t354.id
        and exists(
          select 1
            from Bs_PrjVerRange t423
           where t423.gidSrc = t410.gid
             and t423.idPrjVerFrom = 105501
        )
   )
)

Макрос с несколькими условиями#

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

t.idMeasureItem in (102104,101967,101971,101973)
and upper(t.sPartNumber) like upper('%'||'abc'||'%')
and exists(
select 1
  from Bs_Goods t354
  join Msr_MeasureItem t447 on t447.id = t.idMeasureItem
 where t354.id = t.id
   and upper(t447.sCodeGOST) = upper('10')
   and exists(
     select 1
       from Bs_GoodsSrc t410
       join Bs_Prj t451 on t451.id = t410.idPrj
      where t410.idGds = t354.id
        and t410.bDefault = 1
        and t451.idDepOwner = 117801
        and exists(
          select 1
            from Bs_PrjVerRange t423
           where t423.gidSrc = t410.gid
             and t423.idPrjVerFrom = 105501
        )
   )
)