Skip to content

Transformer

A Transformer is the pure mapping bridge from a DataContract's sources to an Entity's target schema. Each target column gets one mapping expression that reads from the source columns.

Mappings are DuckDB expressions

A mapping is a DuckDB SQL expression, compiled through SQLGlot's AST. Examples:

Kind Example
Passthrough "Konto"
Transform LPAD(TRIM("Konto"), 6, '0')
Type cast CAST(REPLACE("Betrag", ',', '.') AS DECIMAL(18,4))
Dictionary lookup (SELECT "name" FROM dict_kontenplan WHERE "code" = ...)
Context injection CAST("Betrag" AS DECIMAL) * (SELECT rate FROM session_context)
Context table lookup (SELECT "name" FROM ctx_objektname WHERE "code" = "Objekt" LIMIT 1) — a table from the session context (e.g. fetched by a context source), same ctx_<name> the rules see

Quoted identifiers ("Konto") are the supplier's actual column headers from the contract source.

Editing in the UI. Every mapping field and every row filter has an Open in SQL editor button. The editor lists src (this role's columns), src_<role> for the other roles of the revision, the project's catalogs (cat_*) and context (session_context, ctx_<name>), and autocompletes their names; click a table or column to insert it.

Safe by construction

Expressions are never concatenated as strings. They are parsed into a typed AST, checked against a function allowlist (string, math, type-cast, null-handling, and date functions), and rejected at author time if they use anything outside it. File-system and environment functions are blocked. This means an invalid or unsafe mapping fails when you save the transformer — not at runtime against real data.

Row filters — keep only the rows you want

By default every source row is mapped. A transformer can also carry an optional row filter per source role — a boolean DuckDB predicate. A row is kept when the predicate is true; rows that evaluate false are dropped before mapping, so they never reach the entity data, validation, reconciliation, or the export package.

The typical use is excluding accounts you deliberately do not map to SAP ("explicit not mapped"):

"Konto" NOT IN (SELECT "code" FROM cat_kontenplan__provider WHERE "mapping_type" = 'ignore')

Set it on the transformer's Row Filter tab — one predicate per role. The filter is validated the same way as a mapping (AST + function allowlist), so a broken predicate is rejected when you save. When a session runs, dropped rows are reported on the Transformed stage — "N rows excluded by row filter", with the per-role count and the predicate — so the exclusion is auditable, never silent.

Pure mappers

Transformers only map one contract onto one entity. They do not carry cross-file logic — reconciliation between multiple entities lives on the Project, keeping transformers simple and reusable across revisions.