Data Hub Gandalf
Python library for Databricks data pipelines — SCD Types 0/1/2/3/4/6, upserts, surrogate keys, checksums, and schema validations. You shall not pass... bad data.
Installation
Published on PyPI as data-hub-gandalf (imported as gandalf):
pip install data-hub-gandalf
In a Databricks notebook or cluster:
%pip install data-hub-gandalf
For an offline / air-gapped install, build the wheel with Poetry and install it from a Unity Catalog volume:
poetry build # -> dist/data_hub_gandalf-<version>-py3-none-any.whl
%pip install /Volumes/<catalog>/<schema>/<volume>/data_hub_gandalf-<version>-py3-none-any.whl
Quickstart
from gandalf import merge_delta_table
merge_delta_table(
spark=spark,
df=df,
path="main.gold.dim_client",
ids=["id_client"],
merge_type="scd", # SCD Type 2, full snapshot — see Capabilities
sk_type="dim",
sk_name="sk_client",
)
Capabilities
A scan-map of the merge strategies and helpers gandalf provides. Legend: ✅ supported · ⚙️ automatic · ⚠️ supported with a caveat · — not applicable.
| Capability | merge_type (legacy alias) |
Status | History | Deletes | Notes |
|---|---|---|---|---|---|
| SCD Type 2 — full snapshot | scd2 (scd) |
✅ | row versions | logical | requires all source rows each run; row count validated |
| SCD Type 2 — incremental | scd2_no_delete (scd_no_delete) |
✅ | row versions | — | incremental source; absent keys are not closed |
| SCD Type 2 — CDC | scd2_cdc |
⚠️ blocked | — | — | event-ordering semantics not implemented; raises NotImplementedError |
| SCD Type 1 — upsert | scd1 (upsert) |
✅ | — | — | overwrite current value |
| SCD Type 1 — upsert + delete | scd1_delete (upsert-delete) |
✅ | — | hard | also deletes rows absent from source |
| SCD Type 0 — insert-only | scd0 |
✅ | — | — | insert new keys only; protected columns cannot change |
| SCD Type 3 — previous values | scd3 |
✅ | previous-value columns | — | requires previous_columns |
| SCD Type 4 — history table | scd4 |
✅ | separate history table | configurable | requires history_path |
| SCD Type 6 — hybrid | scd6 |
✅ | row versions + prev columns | configurable | requires previous_columns |
| Full overwrite | overwrite |
✅ | — | — | replaces the whole table |
| Partition overwrite | overwrite-partition |
✅ | — | — | replaceWhere-scoped replacement |
| Checksum change detection | — | ⚙️ | — | — | generate_check_sum over business columns; powers SCD2/4/6 |
| Surrogate keys | — | ✅ | — | — | generate_dim_sk (SHA-256, unique per version) / generate_fact_sk (xxhash64, deterministic) |
| Schema & duplicate guards | — | ⚙️ | — | — | column_check, check_duplicates, table_check, row_count run inside merge_delta_table |
| Auto column-type casting | — | ⚙️ | — | — | source columns cast to the target schema before merge |
SCD history strategies manage four control columns — scd_start_dt, scd_end_dt, scd_is_current, and scd_checksum — automatically. Point gandalf at a table that uses different names by passing scd_columns=SCDColumns(is_current="current_flag", checksum="check_sum").
See COMPARISON.md for how gandalf compares to other SCD libraries (mack, koheesio, hydro, fabricks, dbt, Databricks DLT…) — SCD-type coverage, test rigor (real-engine E2E / Spark / Databricks), and where gandalf is, and isn't, distinctive.
What it does
merge_delta_table
Persists a Spark DataFrame into a Delta table. Internally it:
- Validates the target Delta table exists
- Filters incoming data incrementally via
delta_col_filter(optional) - Detects duplicates in the source
- Validates column schema against the target
- Generates checksum for change detection
- Generates surrogate key (if
sk_typeis set) - Auto-casts column types to match target schema
- Executes the chosen merge strategy
- Validates row count after merge
from gandalf import merge_delta_table
merge_delta_table(
spark=spark,
df=df,
path="main.gold.dim_client",
ids=["id_client"],
merge_type="scd", # see strategies below
sk_type="dim",
sk_name="sk_client",
)
Merge strategies — canonical names (legacy aliases accepted):
merge_type |
Legacy alias | SCD type | History | Deletes | Notes |
|---|---|---|---|---|---|
scd2 |
scd |
Type 2 | Row versions | Logical | Full snapshot; requires all source rows |
scd2_no_delete |
scd_no_delete |
Type 2 | Row versions | No | Incremental source |
scd2_cdc |
— | Type 2 | Row versions | Yes | CDC event ordering — explicitly blocked, raises NotImplementedError |
scd1 |
upsert |
Type 1 | No | No | Overwrite current value |
scd1_delete |
upsert-delete |
Type 1 | No | Hard | Overwrite + delete absent rows |
scd0 |
— | Type 0 | No | No | Insert new keys only; protected columns cannot change |
scd3 |
— | Type 3 | Previous value columns | No | Requires previous_columns config |
scd4 |
— | Type 4 | Separate history table | Configurable | Requires history_path config |
scd6 |
— | Type 6 | Row versions + prev columns | Configurable | Requires previous_columns config |
overwrite |
— | — | No | N/A | Full table replacement |
overwrite-partition |
— | — | No | N/A | Partition-scoped replacement |
Advanced strategies (scd0/scd3/scd4/scd6) are configured through SCDConfig:
from gandalf import SCDColumns, SCDConfig, merge_delta_table
# SCD Type 3 — previous-value columns
merge_delta_table(
spark, df, "catalog.schema.dim_client", ["id_client"],
scd_config=SCDConfig(scd_type="scd3", ids=["id_client"],
previous_columns={"address": "previous_address"}),
)
# SCD Type 4 — current table + history table
merge_delta_table(
spark, df, "catalog.schema.current_client", ["id_client"],
scd_config=SCDConfig(scd_type="scd4", ids=["id_client"],
history_path="catalog.schema.hist_client"),
)
# SCD Type 6 — Type 2 rows + previous-value columns
merge_delta_table(
spark, df, "catalog.schema.dim_client", ["id_client"],
scd_config=SCDConfig(scd_type="scd6", ids=["id_client"],
previous_columns={"address": "previous_address"}),
)
SCDConfig also carries the control-column names (columns=SCDColumns(...)), return_metrics, and tracked_columns. Pass either scd_columns or scd_config — not both.
Utilities
from gandalf import generate_check_sum, generate_dim_sk, generate_fact_sk, hash_columns
hash_columns(*cols) # SHA-256 Column expr for withColumn/select/when
generate_check_sum(df, control_cols) # adds scd_checksum over all business columns
generate_dim_sk(df, ids, sk_name) # SHA-256 surrogate key (unique per SCD version)
generate_fact_sk(df, ids, sk_name) # xxhash64 surrogate key (deterministic)
| Function | Description |
|---|---|
hash_columns(*cols) |
SHA-256 Column expression — use inside withColumn, select, when |
generate_check_sum(df, control_cols) |
Adds the scd_checksum column over all business columns |
generate_dim_sk(df, ids, sk_name) |
SHA-256 surrogate key — unique per SCD version |
generate_fact_sk(df, ids, sk_name) |
xxhash64 surrogate key — deterministic across runs |
Data protection guidance
- Prefer checksum comparisons over blind updates so reruns remain idempotent.
- Validate source-vs-target schemas before Delta
MERGE. - Use deterministic surrogate keys for dimensions and facts.
- Keep partition overwrites constrained by explicit predicates.
- Avoid embedding notebook-only globals inside core library logic; pass dependencies as function arguments.
Metadata
Release files for data-hub-gandalf 0.1.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| data_hub_gandalf-0.1.1.tar.gz | 31.6 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| data_hub_gandalf-0.1.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 66.5 kB
Release files / data_hub_gandalf-0.1.1.tar.gz
| Download URL | data_hub_gandalf-0.1.1.tar.gz |
|---|---|
| Size | 31.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
c1661252d633105f09fd28fac016940779269263fb0cac75c97a0dae55b8b8c9
|
|
BLAKE2b-256 checksum How to use checksums |
e1c6252ea2e3d181fd95d7093f949c7a81e7b5b2da5683d66097464a5c99f9f6
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
poetry/2.4.1 CPython/3.12.13 Linux/6.17.0-1018-azure
|
Release files / data_hub_gandalf-0.1.1-py3-none-any.whl
| Download URL | data_hub_gandalf-0.1.1-py3-none-any.whl |
|---|---|
| Size | 34.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
0d95ce378a5b9c7c5c1471c189ce84a3223ca9b31642c748b6a29624fc33d328
|
|
BLAKE2b-256 checksum How to use checksums |
91548f750c6a41c1da490d191d68ddd816c2d50586bb50fb2a9b829feefb8c4f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
poetry/2.4.1 CPython/3.12.13 Linux/6.17.0-1018-azure
|