Rules: integration
Data import (IMPORT)
-
Before working with
IMPORT, the assistant MUST identify elements in this order:- module and namespace that own the import flow
- target classes that will be created or updated
- staging properties used during import
- import actions
- import forms, if the payload is hierarchical
-
The assistant MUST choose the import style intentionally:
- flat files (
CSV,XLS,DBF,TABLE) -> preferIMPORT ... TOorFIELDS - nested
JSON/XML, parent-child structures, namespaces, orEXTIDmapping -> prefer form import - row-at-a-time integration responses
-> prefer
FIELDS ... DO
- flat files (
-
For flat imports that need validation, deduplication, multi-pass processing, or post-processing, the assistant SHOULD stage data into
LOCALproperties first, usually byINTEGERrow, then process it in a separateFOR imported(INTEGER i)pass. -
The assistant SHOULD use
FIELDS ... DOwhen imported values are consumed only once and introducing reusable local properties would add noise. -
The assistant SHOULD specify column mappings explicitly when the external template is fixed or sparse.
Sequential mapping without explicit column IDs is acceptable only when column order itself is the agreed interface.
-
For form import, the assistant MUST declare a dedicated import form before use.
The form MUST use one object per object group with numeric or concrete user classes.
The form SHOULD mirror the external structure with:
FILTERSfor parent-child linksEXTID,FORMEXTID, groups, andATTRonly where the external schema requires them
The assistant MUST remember that importing into a form cancels pending changes to imported form properties in the current session.
-
The assistant MUST choose format options explicitly when the external contract depends on them:
HEADER/NOHEADERSHEETCHARSET
The assistant SHOULD prefer
HEADERfor stableCSV/XLStemplates, becauseNOHEADERcan silently map missing or mistyped columns toNULL. -
The assistant MUST validate referenced business keys before creating or updating persistent objects.
Typical keys in this project are
id,number, partner or item codes, and external references.Each reference MUST be checked in a separate
FORusingGROUP SUM 1 BYover the imported key values.If possible, the assistant SHOULD NOT write resolved references to a separate
LOCALbefore the main import logic.Missing master data or malformed payloads MUST stop the import or surface a clear error.
-
The assistant SHOULD separate raw import from domain resolution:
- first parse the file or payload into locals or an import form
- then check references such as item, partner, status, type, or other lookups
- only then create or update domain objects
-
For user-started batch imports and external integrations, the assistant SHOULD isolate persistence in
NEWSESSION, and SHOULDAPPLY;after the domain writes of one import.Three of the change-session rules bite on every import, so they are stated here rather than left to a second lookup:
- a buffer filled in the upper session reaches the new one
only through
NESTED, on the operator or on theDATA LOCAL NESTEDdeclaration itself, and does not reach it at all underNEWSQL, which migrates nothing; - after
APPLY;the assistant MUST checkcanceled()before treating the import as done; - a failure raised by
APPLYitself is already shown to an interactive user, so an interactive import MUST NOT report it twice; an API or background import MUST surface it itself, throughapplyMessage()or an exception.
The rest of them are in the domain-logic article:
lsfusion_get_guidance(rules='logic'). - a buffer filled in the upper session reaches the new one
only through
-
The assistant MUST NOT partially persist a failed import silently. For failures the assistant detects on its own (missing references, malformed payload, pre-
APPLYvalidation), it SHOULD useMESSAGE,RETURN,throwException, or an explicit failure flag, consistent with the caller:- interactive import ->
MESSAGE - API or background integration -> exception or explicit failure state
- interactive import ->
-
For create-or-update synchronization imports, the assistant MUST separate object creation from property updates.
The assistant MUST make one separate pass that only creates the missing objects. A
FORis one way to write it; the bulkNEW ... WHERE ... TOform creates an object per matching set in a single operation and is the better one wherever it fits.If imported key values may be non-unique, the creation pass SHOULD iterate by grouped keys using
GROUP SUM ... BYrather than by raw imported rows.The assistant MUST then update the properties of the matched objects in a second separate pass — a direct
<- ... WHEREchanges every matching set at once, and aFORis needed only where the body does something a set-based change cannot.The assistant MUST NOT mix object creation and property updates in the same pass for synchronization imports.
If full synchronization is required, the assistant SHOULD add an explicit delete step.
-
If
LOCALstaging properties are used only in one import action, the assistant MUST declare them inside that action.The assistant SHOULD NOT lift such
LOCALproperties to module scope without need.Exception: a
LOCALproperty may be declared outside the action only when it must be used by an import form or reused by several related actions.
Data export (EXPORT)
Choosing the export source
Data is exported with the EXPORT operator.
-
Exporting a list of properties (
EXPORT FROM ...) is used when the result is a single flat table of columns and its structure matches no existing form. -
Exporting a form (
EXPORT formName ...) is used when the export repeats an already existing form or when the result needs the object group hierarchy. The hierarchy is preserved only in JSON and XML; in the flat formats each object group produces a separate file, so for them the destinations are listed per group in theTOblock — only for the groups that are wanted, since a group left out of the list is simply not exported. -
A form created solely for an export should be declared next to the export action and should not be added to the navigator.
Stating explicitly what shapes the result
-
The format should be stated explicitly even when JSON is intended: relying on the default makes the export depend on the reader remembering that default.
-
The
WHEREcondition should be stated explicitly. Without it the condition is the disjunction of all exported properties, so the export includes every object set with at least one field filled — which almost never matches the intended set of rows. -
Column identifiers should be given explicitly (
columnId = expr). The defaultexpr1, ...,exprNties the field names in the external format to the order of the expressions, so inserting a column in the middle of the list silently changes the export contract. -
ORDERshould be stated explicitly whenever the receiving side depends on the row order. Its expressions are arbitrary and need not be among the exported ones — a sorting expression is added to the internal query as a hidden column and does not reach the result — so a column should be added to the export only when the recipient needs it, not merely in order to sort by it. -
In the hierarchical formats a property with a
NULLvalue is omitted from the record (in JSON the key is absent, in XML the element), while the flat formats (CSV, XLS, XLSX, DBF) keep the column and write an empty cell. So in JSON a missing key meansNULL, not a failed export (for form properties withSHOWIFinclusion follows theSHOWIFvalue instead: a non-NULLvalue can be omitted and aNULLone emitted). -
When several scalar values are returned in one export (probe results, diagnostics), separate columns
EXPORT FROM a = ..., b = ...are preferable to one concatenated string: aNULLdrops only its own key, while in a+concatenation it nulls the whole result. To force the key's presence, wrap the value inOVERRIDE ..., <default>(when exporting a form, the property optionEXTNULLmay be used instead). An export of parameterless expressions keeps its single record even when every value isNULL; for rows generated by export parameters the defaultWHERE(disjunction) drops an all-NULLrecord — state theWHEREexplicitly or add a constant column.
Format options
-
Options whose default differs between formats should be set explicitly: the presence of a header row (
HEADER/NOHEADER) in CSV, XLS, XLSX, the CSV separator (;by default) and the encoding (CHARSET,UTF-8by default andCP1251for DBF). -
NOESCAPEin CSV may be used only when the separator is guaranteed not to occur in the data; otherwiseESCAPEshould be kept. -
The encoding should be determined by the receiving side's requirements rather than by the default: recipients of DBF files usually expect a single-byte encoding other than
UTF-8.
Result destination
-
The destination property in
TOshould be declared local to the export action and of a file class (FILE,RAWFILE,JSONFILE) rather than being a shared property: one property shared by several exports makes the result depend on the execution order. -
The
System.exportFiledefault is acceptable only for debugging and one-off exports. -
When a form is exported to a flat format, destinations should be listed for every exported object group; the group of objects without a name is called
root.
Delivering the result
-
The action should be split into preparing the data, the
EXPORTitself, and delivering the file to the recipient — writing it to the file system, sending it to an external system, or storing it in a property. This split allows the same export to be reused with different delivery methods. -
For regular exports, building the file should be done in a separate action with no user interaction, so that it can be called both from a form and on a schedule.
Examples
The first shows the property-list form: a flat result whose shape matches no
form, with the columns aliased, the selection in WHERE and an explicit
ORDER. The second shows the form form: an existing form exported to a
hierarchical format, its outer object passed with 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;
}