Rabbit-in-a-Hat integration¶
The ETL Engine consumes the JSON output of Rabbit-in-a-Hat, the OHDSI tool for designing source-to-CDM mappings. By reusing Rabbit-in-a-Hat as the front-end, the engine inherits a familiar visual modelling environment without requiring data owners to learn a new tool.

Artefacts the engine consumes¶
Rabbit-in-a-Hat provides six artefacts that the engine reads:
- Source tables — the rows on the left.
- CDM tables — the rows on the right.
- Source-to-CDM table maps — arrows from source to CDM tables.
- Source fields — fields inside source tables.
- CDM fields — fields inside CDM tables.
- Source-to-CDM field maps — arrows from source fields to CDM fields.
Each of those, plus the Comments fields on tables and fields, can carry rules from the engine's mapping language.
Where rules are placed in the model¶
| Location | Prefix | Acts as |
|---|---|---|
| Source-to-CDM table arrow logic | none | Table-level rule on a single source table. |
| CDM table Comments | logic: |
Table-level rule on the CDM table. |
| CDM table Comments | field: |
Declares a virtual field. |
| Source-to-CDM field arrow logic | none | Field-to-field rule driven by one source field (its logic may also reference sibling source columns and same-row CDM fields — see below). |
| CDM field Comments | logic: |
Field rule with all incoming maps as inputs. |
What a field-to-field rule can reference¶
A source-to-CDM field arrow is driven by its one source field, but its logic is not limited to that single value. It can also read:
- Other columns of the same source row. Name them directly — e.g. a field
arrow from
quantitywhose logic isAdd(:quantity, :refills)also reads therefillscolumn. The engine pulls every referenced column from the source row alongside the arrow's own field. - Other CDM fields of the same row being built. A field's logic can key a
lookup on a CDM value produced by another field's map. For example
GetCDMValue(@person:year_of_birth, [:person_id], [:person_id])keys the lookup on this row's CDMperson_id. The engine computes such a field after the fields it depends on; a circular dependency is rejected at configure time.
Together these make multi-key lookups expressible directly on a field arrow. A
cost_event_id, say, can key GetCDMValue on a source code and the row's
already-computed CDM person_id / visit_occurrence_id in one rule:
GetCDMValue(@procedure_occurrence:procedure_occurrence_id,
[:person_id, :visit_occurrence_id, :procedure_source_value],
[:person_id, :visit_occurrence_id, :code])
Each key value resolves independently — a source column (code) is read from
the source row, a same-row CDM field (person_id) from the value computed for
this row — so the two can be mixed freely.
What the engine does with the model¶
- Internal mapping tables — the engine builds its own internal representation, ignoring Rabbit-in-a-Hat's stem-table and completeness features.
- Validation — the engine checks that every table-to-table mapping is consistent (for example, all required CDM fields must be mapped) before loading.
- Logic blocks — anything in a Comments field starting with
logic:is parsed as a rule chain. Anything starting withfield:is interpreted as a virtual-field declaration.