Skip to content

snowflake: add snowflake_adapter for table/column comments and tags#3964

Open
usbrandon wants to merge 1 commit into
dlt-hub:develfrom
usbrandon:feature/snowflake-adapter
Open

snowflake: add snowflake_adapter for table/column comments and tags#3964
usbrandon wants to merge 1 commit into
dlt-hub:develfrom
usbrandon:feature/snowflake-adapter

Conversation

@usbrandon

Copy link
Copy Markdown

Summary

Adds snowflake_adapter mirroring the pattern shipped for Databricks in #2625. Closes the gap where the dlt-Snowflake destination only honored column-level COMMENT (via the description column hint) β€” tables, table tags, and column tags had no documented path.

What's included

  • dlt/destinations/impl/snowflake/snowflake_adapter.py β€” new adapter with table_comment, table_tags, column_comments, column_tags arguments. Mirrors the databricks_adapter / bigquery_adapter API shape.
  • dlt/destinations/impl/snowflake/snowflake.py β€” new _add_comment_and_tag_sql() helper called from _get_table_update_sql. Emits:
    • COMMENT ON TABLE <name> IS '…' from the x-snowflake-table-comment hint, with fallback to the generic description table hint (matches the existing column-level fallback).
    • ALTER TABLE <name> SET TAG <k> = '<v>' per pair from x-snowflake-table-tags.
    • ALTER TABLE <name> ALTER COLUMN <c> SET TAG <k> = '<v>' from x-snowflake-column-tags.
  • dlt/destinations/adapters.py β€” exports snowflake_adapter alongside the others.
  • Tests (14 new):
    • tests/load/snowflake/test_snowflake_adapter.py β€” 9 unit tests for the adapter API (shape validation, fallback behavior, chaining with existing hints).
    • tests/load/snowflake/test_snowflake_table_builder.py β€” 5 SQL emission tests (table_comment, description fallback, table_tags, column_tags, literal-escape).
  • Docs β€” docs/website/docs/dlt-ecosystem/destinations/snowflake.md gains a "Snowflake adapter" section before the existing Query tagging section.

Differences from databricks_adapter

  • Tags are dicts ({name: value}), not the Databricks list-of-strings shape. Snowflake tags are first-class catalog objects with values; the loose-string form doesn't map.
  • No table_properties / cluster / partition arguments. Snowflake doesn't have TBLPROPERTIES; clustering is configured via the destination-level create_indexes + cluster column hint; iceberg tables live behind a separate catalog integration not a CREATE TABLE option.
  • Adapter does NOT create tag objects. CREATE TAG <name> must already have been run by governance/Terraform tooling. Keeps the loader role's privilege footprint small (no CREATE TAG ACCOUNT-level grant needed).

Test plan

  • 9 unit tests for the adapter API pass (test_snowflake_adapter.py).
  • 5 new SQL-emission tests + 24 existing tests pass (test_snowflake_table_builder.py).
  • Integration tests against a live Snowflake account (I don't have CI access; happy to provide the databricks_adapter-style `@pytest.mark.parametrize("destination_config", destinations_configs(default_sql_configs=True, subset=["snowflake"]))` pipeline test if you'd like it before merge).

Context

Originally surfaced by a downstream user needing per-table cost-allocation tags on a Snowflake warehouse + table-level documentation that PowerBI / Snowsight can surface via DESCRIBE TABLE. The Databricks pattern from #2625 fit cleanly; this PR ports it.

πŸ€– Generated with Claude Code

Mirrors the pattern shipped for Databricks in dlt-hub#2625 (table_comment +
table_tags + column_tags adapter hints + post-CREATE DDL emission).
Closes a gap reported repeatedly when comparing dlt-Snowflake against
Databricks/BigQuery β€” until now the only way to land COMMENTs on
Snowflake was the column-level `description` hint; tables and tag
objects had no path.

New API (mirrors `databricks_adapter` / `bigquery_adapter` shape):

    from dlt.destinations.adapters import snowflake_adapter

    snowflake_adapter(
        resource,
        table_comment="Shopify orders β€” one row per checkout",
        table_tags={"governance.domain": "commerce"},
        column_comments={"customer_email": "Buyer's email (PII)"},
        column_tags={"customer_email": {"governance.pii_class": "internal"}},
    )

Hints applied by the adapter:
  - x-snowflake-table-comment   β†’ COMMENT ON TABLE <name> IS '...'
                                  (falls back to the generic `description`
                                   table hint, matching the existing
                                   column-level fallback at
                                   `_get_column_def_sql`)
  - x-snowflake-table-tags      β†’ ALTER TABLE <name> SET TAG <k> = '<v>'
                                  per pair
  - x-snowflake-column-tags     β†’ ALTER TABLE <name> ALTER COLUMN <c>
                                  SET TAG <k> = '<v>' per (col, tag) pair
  - x-snowflake-column-comment  β†’ already existed; the adapter exposes
                                  it via `column_comments=` for symmetry

Differences from databricks_adapter:
  - Tags are dicts ({name: value}), not the Databricks list-of-strings
    shape β€” Snowflake tags are first-class catalog objects with values
    and the loose-string form doesn't map.
  - No `table_properties` / `cluster` / `partition` knobs. Snowflake
    doesn't have TBLPROPERTIES; clustering is configured via the
    destination-level `create_indexes` knob; iceberg tables live behind
    a catalog integration not a CREATE TABLE option.
  - Adapter does NOT create tag objects β€” `CREATE TAG <name>` must
    already have been run by governance tooling. Keeps the loader role's
    privilege footprint small (no CREATE TAG ACCOUNT-level grant needed).

SQL emission integrated into `SnowflakeClient._get_table_update_sql` via
a new `_add_comment_and_tag_sql()` helper that runs after the existing
`_add_cluster_sql()`. Each comment/tag becomes its own statement so
attribution stays clean on partial failures (a single bad tag doesn't
invalidate the CREATE/ALTER).

Tests:
  - tests/load/snowflake/test_snowflake_adapter.py β€” adapter API
    validation (9 cases) covering shape rejection, fallback behavior,
    chaining with existing hints.
  - tests/load/snowflake/test_snowflake_table_builder.py β€” 5 new SQL
    emission tests covering table_comment, description-fallback,
    table_tags, column_tags, and Snowflake literal-escape on quotes.
  - All 29 tests in test_snowflake_table_builder.py + test_snowflake_adapter.py
    pass.

Docs: `docs/website/docs/dlt-ecosystem/destinations/snowflake.md` gains
a "Snowflake adapter" section under "Additional destination options"
showing the adapter call, argument semantics, and the Databricks-divergence
list.
@zilto zilto added the destination Issue with a specific destination label May 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

destination Issue with a specific destination

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants