Skip to content

feat: support TRIGGER ON UPDATE and SCHEDULE EVERY for MV and ST#1434

Merged
sd-db merged 9 commits into
1.12.latestfrom
sd-db/feature/mv-st-trigger-schedule-syntax
May 13, 2026
Merged

feat: support TRIGGER ON UPDATE and SCHEDULE EVERY for MV and ST#1434
sd-db merged 9 commits into
1.12.latestfrom
sd-db/feature/mv-st-trigger-schedule-syntax

Conversation

@sd-db
Copy link
Copy Markdown
Collaborator

@sd-db sd-db commented Apr 30, 2026

Summary

Adds the full Databricks refresh-schedule grammar on materialized views and streaming tables: `SCHEDULE CRON`, `SCHEDULE EVERY`, and `TRIGGER ON UPDATE [AT MOST EVERY INTERVAL ...]`.

Closes #1293.

User-facing config:

config:
  schedule:
    cron: '0 0 * * * ? *'
    time_zone_value: 'America/Los_Angeles'
    # OR
    every: '2 HOURS'
    # OR
    on_update: true
    at_most_every: '15 MINUTES'

Test plan

  • Unit tests for parser, validator, diff, and refresh-schedule macros (873 unit tests passing).
  • Functional round-trip tests per mode for both MV and ST against live UC SQL endpoint.
  • Functional lifecycle tests walking each relation through MANUAL → CRON → ON_UPDATE → EVERY → (non-refresh component change) → MANUAL.
  • `pre-commit run --all-files` clean (ruff, ruff-format, mypy).

Adds the full Databricks refresh-schedule grammar on materialized
views and streaming tables: SCHEDULE CRON, SCHEDULE EVERY, and
TRIGGER ON UPDATE [AT MOST EVERY INTERVAL ...].

- RefreshConfig is a discriminated config with parse-time validation
  on the new modes.
- Idempotent runs no longer emit spurious ALTERs across user/server
  unit differences.
- Auto-REFRESH is suppressed for every/on_update modes.

Coverage:
- Unit tests for parser, validator, diff, and refresh-schedule macros.
- Functional round-trip tests per mode for both MV and ST.
- Functional lifecycle tests walking each relation through every mode
  transition plus a non-refresh-component change.
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Apr 30, 2026

Coverage report

Click to see where and how coverage changed

FileStatementsMissingCoverageCoverage
(new stmts)
Lines missing
  dbt/adapters/databricks/relation_configs
  refresh.py 54, 63, 74, 142, 194, 225, 234
  streaming_table.py
Project Total  

This report was generated by python-coverage-comment-action

Drop log-line and SQL-emission assertions, keep only mode-value checks
on the resulting relation. Remove tests that only inspected dbt logs.
@tejassp-db

This comment was marked as duplicate.

1 similar comment
@tejassp-db
Copy link
Copy Markdown
Collaborator

/integration-test

@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 4, 2026

Integration tests dispatched for PR #1434 by @tejassp-db. Track progress in the Actions tab.

@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 4, 2026

Integration results for PR #1434 — UC cluster ❌ cancelled · SQL warehouse ❌ cancelled · All-purpose cluster ❌ failure

Run details.

@sd-db
Copy link
Copy Markdown
Collaborator Author

sd-db commented May 8, 2026

/integration-test

@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 8, 2026

Integration tests dispatched for PR #1434 by @sd-db. Track progress in the Actions tab.

@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 8, 2026

Integration results for PR #1434 — UC cluster ⏩ skipped · SQL warehouse ⏩ skipped · All-purpose cluster ⏩ skipped · Shard coverage ⏩ skipped

Run details.

@sd-db
Copy link
Copy Markdown
Collaborator Author

sd-db commented May 11, 2026

/integration-test

@github-actions
Copy link
Copy Markdown

Integration tests dispatched for PR #1434 by @sd-db. Track progress in the Actions tab.

@github-actions
Copy link
Copy Markdown

Integration results for PR #1434 — UC cluster ✅ success · SQL warehouse ✅ success · All-purpose cluster ✅ success · Shard coverage ✅ success

Run details.

Comment thread dbt/adapters/databricks/relation_configs/refresh.py
Comment thread dbt/adapters/databricks/relation_configs/refresh.py
Comment thread dbt/adapters/databricks/relation_configs/refresh.py
sd-db added 5 commits May 13, 2026 14:39
When a user sets `schedule = {'cron': '...'}` without `time_zone_value`,
the warehouse stores it as `Etc/UTC` in `DESCRIBE EXTENDED`. Previously
`RefreshConfig.__eq__` compared `"UTC" != "ETC/UTC"`, so dbt emitted a
no-op `ALTER` on every subsequent run.

Adds `_canonical_tz()` mapping None / UTC / Etc/UTC to the same value;
`__eq__` and `__hash__` use it on the CRON branch.

Test coverage:
- New EVERY-input matrix test per file (MV + ST) walks one relation
  through HOUR / DAY / WEEK via `on_configuration_change: apply`,
  asserting each round-trips against the warehouse.
- The existing CRON lifecycle step now uses a no-TZ fixture so the
  `Etc/UTC` round-trip is exercised on the existing CRON path.
- Unit tests cover the equivalence + parametrized server-emitted shapes
  (TRIGGER intervals normalized to SECOND, EVERY plural forms).
…trigger-schedule-syntax

# Conflicts:
#	tests/functional/adapter/materialized_view_tests/fixtures.py
The schedule-mode test files inlined six SQL constants each
(ST_EVERY_2_HOURS, ST_ON_UPDATE_BARE, ST_CRON, etc.) — out of line with
the convention used elsewhere in `streaming_tables/fixtures.py` and
`materialized_view_tests/fixtures.py` (`streaming_table`,
`complex_streaming_table`, `materialized_view`).

Moved each to its respective fixtures.py with snake_case names and
deduped two cases:
  - `ST_NO_SCHEDULE` is now the pre-existing `fixtures.streaming_table`.
  - `ST_EVERY_2_HOURS` / `MV_EVERY_2_HOURS` are now defined via the
    `streaming_table_with_every("2 HOURS")` / `materialized_view_with_every`
    helper added in the previous commit.
  - Added `materialized_view_no_schedule` (the existing `materialized_view`
    fixture has cron + tblproperties, so it can't double as the no-schedule
    case).

No behavioral change to the tests.
`test_every_mode_roundtrip` only asserted `refresh.mode.value == "every"`
for `EVERY 2 HOURS`. The `TestStreamingTableEveryAcceptedInputs` matrix
test (added previously) now walks HOUR / DAY / WEEK with strict equality
+ no-diff checks — strictly stronger coverage.

Remove the redundant test and the `streaming_table_every_2_hours` /
`materialized_view_every_2_hours` fixtures; the few remaining call sites
in the lifecycle and drop-and-readd tests use the
`streaming_table_with_every("2 HOURS")` / `materialized_view_with_every`
helper inline.
Both removed cases assert exactly what the lifecycle test already does:

- `TestStreamingTableManualMode` / `TestMaterializedViewManualMode` —
  identical to lifecycle's first step (CREATE no-schedule → assert manual).
- `test_on_update_rate_limited_mode_roundtrip` — same `"900" in
  refresh.at_most_every` assertion as the lifecycle ON_UPDATE step.

Leaves `test_on_update_bare_mode_roundtrip` (only coverage for bare
TRIGGER ON UPDATE on fresh CREATE; lifecycle doesn't include a bare
on_update transition).
@sd-db sd-db merged commit 3d210a6 into 1.12.latest May 13, 2026
7 checks passed
@sd-db sd-db deleted the sd-db/feature/mv-st-trigger-schedule-syntax branch May 13, 2026 11:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants