Перейти к основному содержимому
Версия: 7.0

Rules: integration

Правила: импорт данных (IMPORT)​

  1. Ассистент ОБЯЗАН осознанно выбирать стиль импорта:

    • плоские файлы (CSV, XLS, DBF, TABLE) -> предпочесть IMPORT ... TO или FIELDS
    • вложенные JSON / XML, структуры родитель-потомок, пространства имён или сопоставление EXTID -> предпочесть импорт через форму
    • построчные интеграционные ответы -> предпочесть FIELDS ... DO
  2. Для плоских импортов, требующих валидации, дедупликации, многопроходной обработки или постобработки, ассистенту СЛЕДУЕТ сначала складывать данные в LOCAL-свойства, обычно по INTEGER-строке, а затем обрабатывать их отдельным проходом FOR imported(INTEGER i).

  3. Ассистенту СЛЕДУЕТ использовать FIELDS ... DO, когда импортируемые значения используются лишь однажды и введение переиспользуемых локальных свойств добавило бы шум.

  4. Ассистенту СЛЕДУЕТ указывать сопоставление колонок явно, когда внешний шаблон фиксирован или разрежен.

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

  5. Для импорта через форму ассистент ОБЯЗАН объявить выделенную форму импорта до использования.

    Форма ОБЯЗАНА использовать один объект на группу объектов с числовыми или конкретными пользовательскими классами.

    Форме СЛЕДУЕТ отражать внешнюю структуру через:

    • FILTERS для связей родитель-потомок
    • EXTID, FORMEXTID, группы и ATTR только там, где этого требует внешняя схема — массив на корневом уровне JSON как раз такое место (правило 6)

    Ассистент ОБЯЗАН помнить, что импорт в форму отменяет ожидающие изменения импортируемых свойств формы в текущей сессии.

  6. Для массива на корневом уровне JSON ассистент ОБЯЗАН задать группе объектов формы импорта имя экспорта / импорта value (OBJECTS receipts = INTEGER EXTID 'value'): такой файл платформа читает как { "value" : [ ... ] } (см. предопределенное значение).

    Группа объектов, чьему имени экспорта / импорта не соответствует ни один ключ файла, импортирует ноль записей без ошибки и без предупреждения, поэтому новую форму импорта ассистент ОБЯЗАН проверить на непустом примере.

  7. После импорта формы ассистент НЕ ДОЛЖЕН итерировать по imported[INTEGER], если на форме нет фильтра с ним (FILTERS imported(receipts)): импорт формы записывает данные только в свойства и фильтры формы. Без фильтра эту роль играет промежуточное свойство, которое заполнено всегда.

    Ассистент НЕ ДОЛЖЕН указывать одно свойство-признак в фильтрах нескольких групп объектов: каждая группа нумерует свои записи с 0, и признаки смешиваются. Каждой следующей группе нужно собственное LOCAL-свойство-признак.

  8. Ассистент ОБЯЗАН явно выбирать опции формата, когда от них зависит внешний контракт:

    • HEADER / NOHEADER
    • SHEET
    • CHARSET

    Ассистенту СЛЕДУЕТ предпочитать HEADER для стабильных шаблонов CSV / XLS, потому что NOHEADER может незаметно сопоставить отсутствующие или неверно типизированные колонки в NULL.

  9. Ассистент ОБЯЗАН валидировать ссылочные бизнес-ключи до создания или обновления постоянных объектов.

    Типичные ключи — id, number, коды партнёров или товаров и внешние ссылки.

    Каждая ссылка ДОЛЖНА проверяться в отдельном FOR через GROUP SUM 1 BY по импортируемым значениям ключей.

    По возможности ассистенту НЕ СЛЕДУЕТ записывать разрешённые ссылки в отдельный LOCAL до основной логики импорта.

    Отсутствующие мастер-данные или некорректные данные ДОЛЖНЫ останавливать импорт или выдавать понятную ошибку.

  10. Ассистенту СЛЕДУЕТ разделять сырой импорт и доменное разрешение:

    • сначала разобрать файл или данные в локальные свойства или форму импорта
    • затем проверить ссылки, такие как товар, партнёр, статус, тип или другие справочники
    • только потом создавать или обновлять доменные объекты
  11. Для запускаемых пользователем пакетных импортов и внешних интеграций ассистенту СЛЕДУЕТ изолировать сохранение в NEWSESSION и СЛЕДУЕТ выполнять APPLY; после доменных записей одного импорта.

    В какой сессии выполняется импорт, как в неё попадает буфер верхней сессии и что следует за APPLY;, определяют правила сессий изменений из статьи о доменной логике (lsfusion_get_guidance(rules='logic')).

  12. Ассистент НЕ ДОЛЖЕН частично сохранять неудавшийся импорт молча. Для ошибок, которые ассистент обнаруживает сам (отсутствующие ссылки, некорректные данные, валидация до APPLY), ему СЛЕДУЕТ использовать MESSAGE, RETURN, throwException или явный флаг неудачи, согласованно с вызывающей стороной:

    • интерактивный импорт -> MESSAGE
    • API или фоновая интеграция -> исключение или явное состояние неудачи
  13. Для импортов-синхронизаций «создать-или-обновить» ассистент ОБЯЗАН разделять создание объектов и обновление свойств.

    Ассистент ОБЯЗАН делать один отдельный проход, только создающий недостающие объекты. FOR — один из способов его записать; множественная форма NEW ... WHERE ... TO создает объект на каждый подходящий набор одной операцией и предпочтительна везде, где подходит.

    Если импортируемые значения ключей могут быть неуникальны, проход создания СЛЕДУЕТ итерировать по сгруппированным ключам через GROUP SUM ... BY, а не по сырым импортируемым строкам.

    Затем ассистент ОБЯЗАН обновить свойства найденных объектов вторым отдельным проходом — прямое <- ... WHERE меняет все подходящие наборы разом, а FOR нужен только там, где тело делает то, чего множественное изменение не умеет.

    Ассистент НЕ ДОЛЖЕН смешивать создание объектов и обновление свойств в одном проходе для импортов-синхронизаций.

    Если требуется полная синхронизация, ассистенту СЛЕДУЕТ добавить явный шаг удаления.

  14. LOCAL-свойства промежуточного хранения, используемые одним действием импорта, ДОЛЖНЫ объявляться внутри этого действия; уровень модуля — для LOCAL, который использует форма импорта или разделяют несколько связанных действий.

Правила: экспорт данных (EXPORT)​

Выбор источника экспорта​

Данные экспортируются оператором EXPORT.

  1. Экспорт списка свойств (EXPORT FROM ...) СЛЕДУЕТ использовать, когда результат — одна плоская таблица колонок и структура выгрузки не совпадает ни с одной формой.

  2. Экспорт формы (EXPORT formName ...) СЛЕДУЕТ использовать, когда выгрузка повторяет уже существующую форму или когда в результате нужна иерархия групп объектов. Иерархия сохраняется только в JSON и XML; в плоских форматах каждая группа объектов дает отдельный файл, поэтому для них приемники перечисляются по группам в блоке TO — только для нужных групп: не попавшая в список группа просто не экспортируется.

  3. Форму, созданную исключительно ради выгрузки, СЛЕДУЕТ объявлять рядом с действием экспорта и НЕ СЛЕДУЕТ добавлять в навигатор.

Явное указание того, что влияет на результат​

  1. Формат СЛЕДУЕТ указывать явно даже тогда, когда нужен JSON: умолчание делает выгрузку зависимой от того, что читающий код помнит про умолчание.

  2. Условие WHERE СЛЕДУЕТ указывать явно. Без него условием считается дизъюнкция всех экспортируемых свойств, то есть в выгрузку попадут наборы объектов, у которых заполнено хотя бы одно поле, — это почти никогда не совпадает с нужным набором строк.

  3. Идентификаторы колонок СЛЕДУЕТ задавать явно (columnId = expr). Умолчание expr1, ..., exprN привязывает имена полей во внешнем формате к порядку выражений, поэтому вставка колонки в середину списка молча меняет контракт выгрузки.

  4. ORDER СЛЕДУЕТ указывать явно всегда, когда принимающая сторона зависит от порядка строк. Выражения в нем произвольны и не обязаны входить в список экспортируемых — выражение сортировки добавляется во внутренний запрос скрытой колонкой и в результат не попадает, — поэтому колонку СЛЕДУЕТ включать в выгрузку только тогда, когда она нужна получателю, а не ради того, чтобы по ней отсортировать.

  5. В иерархических форматах свойство со значением NULL пропускается в записи (в JSON отсутствует ключ, в XML — элемент), а плоские форматы (CSV, XLS, XLSX, DBF) сохраняют колонку и записывают пустую ячейку. Поэтому в JSON отсутствующий ключ означает NULL, а не сбой выгрузки (для свойств формы со SHOWIF включение определяется значением SHOWIF: не-NULL значение может быть пропущено, а NULL — выгружено).

  6. Когда одной выгрузкой возвращается несколько скалярных значений (результаты проверок, диагностика), отдельные колонки EXPORT FROM a = ..., b = ... СЛЕДУЕТ предпочитать одной склеенной строке: NULL убирает только свой ключ, тогда как в конкатенации через + он обнуляет весь результат. Чтобы ключ присутствовал всегда, значение оборачивается в OVERRIDE ..., <умолчание> (при экспорте формы МОЖЕТ использоваться опция свойства EXTNULL). Выгрузка выражений без параметров сохраняет свою единственную запись, даже когда все значения NULL; для строк, порождаемых параметрами выгрузки, умолчание WHERE (дизъюнкция) выбрасывает полностью NULL-запись — условие WHERE СЛЕДУЕТ задать явно или добавить константную колонку.

Опции формата​

  1. Опции, у которых умолчание отличается для разных форматов, СЛЕДУЕТ задавать явно: наличие строки заголовка (HEADER / NOHEADER) в CSV, XLS, XLSX, разделитель CSV (по умолчанию ;) и кодировку (CHARSET, по умолчанию UTF-8, а для DBF — CP1251).

  2. NOESCAPE в CSV МОЖЕТ использоваться только тогда, когда разделитель гарантированно не встречается в данных; в остальных случаях СЛЕДУЕТ оставлять ESCAPE.

  3. Кодировку СЛЕДУЕТ определять требованиями принимающей стороны, а не значением по умолчанию: получатели DBF-файлов обычно ожидают однобайтовую кодировку, отличную от UTF-8.

Приемник результата​

  1. Свойство-приемник в TO СЛЕДУЕТ объявлять локальным для действия экспорта и файлового класса (FILE, RAWFILE, JSONFILE), а не использовать общее свойство: одно свойство, разделяемое несколькими выгрузками, делает результат зависящим от порядка выполнения.

  2. Умолчание System.exportFile СЛЕДУЕТ использовать только для отладочных и разовых выгрузок.

  3. При экспорте формы в плоский формат приемники СЛЕДУЕТ перечислять для всех выгружаемых групп объектов; группа объектов без имени называется root.

  4. Для возврата значения из действия, вызываемого внешней системой, ассистент ОБЯЗАН использовать RETURN, а не EXPORT: RETURN отдаёт значение из любого места действия, в том числе после APPLY и из блока NEWSESSION, тогда как результат EXPORT остаётся в той сессии, где он выполнен, и ответ приходит пустым.

Передача результата​

  1. Действие СЛЕДУЕТ разделять на подготовку данных, собственно EXPORT и передачу файла получателю — записью в файловую систему, отправкой во внешнюю систему или сохранением в свойстве. Такое разделение позволяет повторно использовать выгрузку с разными способами доставки.

  2. Для регулярных выгрузок формирование файла СЛЕДУЕТ делать в отдельном действии без взаимодействия с пользователем, чтобы его можно было вызывать и с формы, и по расписанию.

Примеры​

Первый показывает форму со списком свойств: плоский результат, чья структура не совпадает ни с одной формой, с алиасами колонок, отбором в WHERE и явным ORDER. Второй показывает форму с формой: существующая форма выгружается в иерархический формат, её внешний объект передан через OBJECTS.

exportShipments (Store store) {
LOCAL exportedFile = FILE ();
EXPORT CSV ';' HEADER FROM number = number(Shipment s), date = date(s), sum = sum(s)
WHERE store(s) = store AND shipped(s)
ORDER date(s)
TO exportedFile;
}
FORM exportOrders
OBJECTS st = Store
OBJECTS o = Order
PROPERTIES(o) number, date
FILTERS store(o) = st
;

exportOrders (Store store) {
LOCAL exportedFile = FILE ();
EXPORT exportOrders OBJECTS st = store JSON TO exportedFile;
}