MassChange

Материал из DevelopmenOnTheEdge
Перейти к: навигация, поиск
Класс
MassChange
Поддерживает документацию
да
Поддерживает extras
нет


MassChange (массовое изменение) — возможность применить однотипное изменение к различным элементам дерева проекта по условию. В дереве проекта хранятся в коллекции Mass changes в модуле приложения. На файловой системе хранятся по умолчанию в src/massChanges.yaml. Пример:

- select: Entity#messages Query
  roles: []

Данное массовое изменение выбирает все представления сущности messages и устанавливает им пустой список ролей.

Каждый элемент списка содержит селектор (select) и определение элемента. Для всех элементов, которые соответствуют селектору, производится переопределение указанных свойств точно так же, как в приложении кастомизируется элемент из модуля. В принципе селектор может соответствовать элементам разного типа, в некоторых случаях это сработает. Например:

- select: Entity#blahblah Query, Entity#blahblah Operation
  roles: []

Удалит все роли у всех представлений и операций сущности blahblah. Но лучше разносить подобное на отдельные селекторы.

Селектор пока может выбирать Query, Operation или Entity. Если селектор выбрал что-то другое, будет ошибка.

Селекторы

Синтаксис селекторов похож на CSS. Спецсимволы обрабатываются в соответствии со стандартом CSS. Поддерживаются следующие возможности:

  • Выбор по классу (аналог CSS type selector). Указывается просто название типа элементов. Пока поддерживаются Module, Entity, Query, Operation. Например:
Operation
Такой селектор просто выберет все представления.
  • Выбор по атрибуту (аналог CSS attribute value selectors). Поддерживаются формы [attr=val], [attr^=val], [attr$=val], [attr*=val] для точного совпадения значения, префикса, суффикса и подстроки. Список доступных атрибутов зависит от типа данных и обычно похож на список полей при сериализации в yaml. Например:
[name="messages"]
Такой селектор выберет все элементы с именем messages.
  • Выбор имени. Для сокращения предыдущий селектор можно написать так:
#messages
Но при этом значение уже должно удовлетворять свойствам идентификатора, а не строки (например, нужно экранировать пробелы).
  • Выбор типа. У Entity, Query и Operation бывает тип. Его можно выбрать через [type="..."], но короче через точку:
.table
Выберет все элементы с типом table. Доступные типы:
  • Для Entity: table, dictionary, collection, genericCollection, metadata
  • Для Query: 1D, 1D_unknown, 2D, static, custom, container, javascript
  • Для Operation: java, sql, javafunction, js (=javascript), jsserver (=javascriptserver), dotnet, javadotnet
  • Сложный селектор (CSS: compound selector). Несколько правил, написанных слитно. Выбирается элемент, удовлетворяющий всем правилам. Например:
Entity#messages
Тут два правила: выбрать элементы по классу Entity (то есть сущности) и выбрать элементы с именем messages. В результате будет выбрана сущность с именем messages.
  • Комбинатор-потомок (CSS: descendant combinator). Если перечислить несколько селекторов через пробел, будут выбраны элементы, удовлетворяющие последнему селектору, у которых есть родитель (не обязательно непосредственный), удовлетворяющий предпоследнему, и т. д. Например:
Entity#messages Query
Выберет все представления сущности с именем messages. Другие CSS-комбинаторы (>, +, ~) не поддерживаются.
  • Список селекторов (CSS: selector list). Можно перечислить через запятую несколько селекторов, тогда элемент будет выбран, если он подходит под любой из селекторов. Например:
Query, Operation
Выберет все представления и все операции.
  • Псевдокласс :not (CSS: negation). Выберет элементы, которые не удовлетворяют заданному в скобках селектору. Например:
Entity:not(.table)
Выберет все сущности, тип которых не table.
  • Псевдокласс :matches (CSS: matches). Выберет элементы, которые удовлетворяют хотя бы одному из заданных в скобках селекторов. Например:
Entity:matches(#users,#persons) Query
Выберет все представления из сущностей с именами users и persons.

Примеры

Примеры старого SQL-кода и соответствующего массового изменения:

Изменение кода операций

UPDATE operations SET code = 'com.beanexplorer.enterprise.operations.SilentEditOperation'
 WHERE code = 'com.beanexplorer.enterprise.operations.EditOperation' AND table_name != 'colorSchemes';
select: Entity:not(#colorSchemes) Operation[code="com.beanexplorer.enterprise.operations.EditOperation"]
code: com.beanexplorer.enterprise.operations.SilentEditOperation

Специальная операция для редактирования словарей

UPDATE operations SET code = 'com.beanexplorer.ru.social.operations.DictionaryEdit'
WHERE table_name IN ( SELECT name FROM entities WHERE type = 'dictionary' )
AND code = 'com.beanexplorer.enterprise.operations.EditOperation'
AND name = 'Edit';
select: Entity.dictionary Operation#Edit[code="com.beanexplorer.enterprise.operations.EditOperation"]
code: com.beanexplorer.ru.social.operations.DictionaryEdit

Удаление ролей для нескольких таблиц

DELETE FROM queries_per_role
WHERE queryID IN ( SELECT q.ID FROM queries q WHERE q.name IN ( 'All records' ) AND q.table_name IN ( 'gpsDeviceTypes', 'gpsDevices' ) );
select: Entity:matches(#gpsDevices,#gpsDeviceTypes) Query[name="All records"]
roles: []

Или

select: Entity[name^=gpsDevice] Query[name="All records"]
roles: []

Удаление ролей для всех операций по имени

DELETE FROM operations_per_role
WHERE operID IN ( SELECT o.ID FROM operations o WHERE o.name IN ( 'Explain Plan', 'Parent Record' ) );
select: Operation[name="Explain Plan"], Operation[name="Parent Record"]
roles: []

Или

select: Operation:matches([name="Explain Plan"], [name="Parent Record"])
roles: []

Разрешить фильтровать словари всем

INSERT INTO operations_per_role
  SELECT o.ID, r.role_name
  FROM operations o, roles r
  WHERE o.table_name IN (
SELECT  name FROM entities WHERE type = 'dictionary'
  ) AND o.name IN ( 'Filter' ) AND r.role_name IN (  r.role_name   ) ;
select: Entity.dictionary Operation#Filter
roles: '@AllRoles'

Администратору базы данных разрешить менять все словари

DELETE FROM operations_per_role
  WHERE role_name IN ( SELECT r.role_name FROM roles r WHERE r.role_name IN ( 'DbAdmin'  ) ) 
  AND operID IN ( SELECT o.ID FROM operations o WHERE o.table_name IN 
  ( SELECT name FROM entities WHERE type='dictionary' AND origin IN ('ru.mfc') ) AND o.name in (  o.name  ) );
INSERT INTO operations_per_role
  SELECT o.ID, r.role_name
  FROM operations o, roles r
  WHERE o.table_name IN ( SELECT name FROM entities WHERE type='dictionary' AND origin IN ('ru.mfc') ) 
  AND o.name IN (  o.name  ) AND r.role_name IN ( 'DbAdmin'  ) ;
select: Module#ru\.mfc Entity.dictionary Operation
roles: +DbAdmin

Добавить специальный запрос во все сущности кроме dummy

INSERT_INTO(queries) table_name, name, isInvisible, query )
SELECT name, 'Exchange: Modified Data', 'yes',
  _DBMS_CONCAT( 'SELECT * FROM ', name, '<if parameter="dateFrom"> WHERE modificationDate___ >= ''<parameter:dateFrom /> 00:00:00''</if>' )
FROM entities WHERE SUBSTRING(name,1,1) != '_';
select: Entity:not([name^=_])
queries:
 - 'Exchange: Modified Data':
         code: SELECT * FROM ${entity.getName()} <if parameter="dateFrom"> WHERE modificationDate___ >= '<parameter:dateFrom /> 00:00:00'</if>
         invisible: true

Добавить запрос Table definition в сущности, primary key которых не является dummy

-- add missing table defs in one powerful stroke ;-)
INSERT INTO queries( table_name, name, query, type )
SELECT e.name, 'Table definition', ' ', '1D'
FROM entities e
WHERE e.primaryKeyColumn != '_dummy_'
 AND NOT EXISTS( SELECT 1 FROM queries q 
WHERE q.table_name = e.name AND q.name = 'Table definition' );
select: Entity:not([primaryKey="_dummy_"])
queries:
 - Table definition: {}