Skip to content

dbt Project Generation

Runnable example: 27_integrations_mcp_langchain_dbt.ipynb — all three integrations end-to-end, offline, executed with outputs.

Turn a Portiere mapping into a runnable dbt project — one SQL model per target table (select → rename → concept-lookup join), a schema.yml with tests, and a source_to_concept_map seed. Like Portiere's standalone ETL scripts, the generated project runs on any dbt adapter with no Portiere runtime and no lock-in.

No extra needed — generation is pure text (pip install "portiere-health[polars]").

portiere dbt \
    --schema-mapping schema_mapping_reviewed.json \
    --concepts concept_mapping.json \
    -o dbt_omop/ \
    --source-schema raw --standard omop_cdm_v5.4

What you get

dbt_omop/
  dbt_project.yml
  models/
    person.sql                 # one per mapped target table
    condition_occurrence.sql
    schema.yml                 # not_null tests on required standard fields
  seeds/
    source_to_concept_map.csv  # from your concept mapping
  README.md

A generated models/person.sql:

-- Generated by Portiere — target: person (omop_cdm_v5.4)
with source as (select * from {{ source('raw', 'kcis_patient') }}),
renamed as (
    select
        patient_no as person_id,
        sex        as gender_source_value
        -- UNMAPPED source column (needs review): mystery
    from source
),
mapped as (
    select
        renamed.*,
        coalesce(scm_0.target_concept_id, 0) as gender_source_value_concept_id
    from renamed
    left join {{ ref('source_to_concept_map') }} scm_0
        on scm_0.source_code = renamed.gender_source_value
       and scm_0.source_vocabulary_id = 'sex'
)
select * from mapped
  • Unmapped columns are visible, not silently dropped — they appear as -- UNMAPPED stubs (the review work queue, in the SQL).
  • not_null tests are attached to columns that map to required fields of the standard (read from the standard YAML — never drifts from the CDM version).

Run it

cd dbt_omop
# configure a `raw` source + a profile pointing at your warehouse
dbt seed && dbt run && dbt test

Python API

from portiere.integrations.dbt import build_dbt_project
build_dbt_project(schema_mapping, concept_mapping, "dbt_omop/", standard="omop_cdm_v5.4")

Regenerate whenever the mapping changes — treat the project as a build artifact, not source you hand-edit. Related: the Custom EHR → OMOP tutorial produces the mappings this consumes.