Skip to content

Commit d0b31ea

Browse files
committed
fix: VIEW model with metadata-only changes in VDE=dev_only should always migrate
1 parent 906be74 commit d0b31ea

File tree

3 files changed

+85
-3
lines changed

3 files changed

+85
-3
lines changed

sqlmesh/core/plan/stages.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -270,7 +270,6 @@ def build(self, plan: EvaluatablePlan) -> t.List[PlanStage]:
270270
}
271271
after_promote_snapshots = all_selected_for_backfill_snapshots - before_promote_snapshots
272272
deployability_index = DeployabilityIndex.all_deployable()
273-
274273
snapshots_with_schema_migration = [
275274
s for s in snapshots.values() if s.requires_schema_migration_in_prod
276275
]
@@ -364,6 +363,19 @@ def build(self, plan: EvaluatablePlan) -> t.List[PlanStage]:
364363
)
365364
)
366365

366+
if snapshots_with_schema_migration:
367+
missing_ids_before = {s.snapshot_id for s in missing_intervals_before_promote}
368+
missing_ids_after = {s.snapshot_id for s in missing_intervals_after_promote}
369+
# Only skip migrate for VIEWs that are already scheduled for recreation in Backfill.
370+
snapshots_with_schema_migration = [
371+
s
372+
for s in snapshots_with_schema_migration
373+
if not s.is_view
374+
or (
375+
s.snapshot_id not in missing_ids_before
376+
and s.snapshot_id not in missing_ids_after
377+
)
378+
]
367379
if snapshots_with_schema_migration:
368380
stages.append(
369381
MigrateSchemasStage(

sqlmesh/core/snapshot/definition.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1483,7 +1483,7 @@ def requires_schema_migration_in_prod(self) -> bool:
14831483
return (
14841484
self.is_paused
14851485
and self.is_model
1486-
and self.is_materialized
1486+
and not self.is_symbolic
14871487
and (
14881488
(self.previous_version and self.previous_version.version == self.version)
14891489
or self.model.forward_only

tests/core/test_plan_stages.py

Lines changed: 71 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1658,7 +1658,7 @@ def test_build_plan_stages_indirect_non_breaking_view_migration(
16581658
# Build plan stages
16591659
stages = build_plan_stages(plan, state_reader, None)
16601660

1661-
# Verify stages
1661+
# Verify stages (no migrate for VIEW here because the view is already scheduled to be recreated in Backfill)
16621662
assert len(stages) == 8
16631663

16641664
assert isinstance(stages[0], CreateSnapshotRecordsStage)
@@ -1936,6 +1936,76 @@ def test_build_plan_stages_virtual_environment_mode_no_updates(
19361936
assert len(virtual_stages) == 0
19371937

19381938

1939+
def test_build_plan_stages_virtual_environment_mode_metadata_only_changes(
1940+
mocker: MockerFixture,
1941+
) -> None:
1942+
snapshot_view: Snapshot = Snapshot.from_node(
1943+
SqlModel(
1944+
name="dev_only_view",
1945+
query=parse_one("select 1 as id"),
1946+
kind=dict(name=ModelKindName.VIEW),
1947+
virtual_environment_mode=VirtualEnvironmentMode.DEV_ONLY,
1948+
),
1949+
nodes={},
1950+
ttl="in 1 week",
1951+
)
1952+
snapshot_view.categorize_as(SnapshotChangeCategory.METADATA)
1953+
1954+
state_reader = mocker.Mock(spec=StateReader)
1955+
state_reader.get_snapshots.return_value = {}
1956+
state_reader.get_environment.return_value = None
1957+
1958+
# Production environment with the view promoted
1959+
environment = Environment(
1960+
name="prod",
1961+
snapshots=[snapshot_view.table_info],
1962+
start_at="2023-01-01",
1963+
end_at="2023-01-02",
1964+
plan_id="test_plan",
1965+
previous_plan_id=None,
1966+
promoted_snapshot_ids=[snapshot_view.snapshot_id],
1967+
)
1968+
1969+
plan = EvaluatablePlan(
1970+
start="2023-01-01",
1971+
end="2023-01-02",
1972+
new_snapshots=[snapshot_view],
1973+
environment=environment,
1974+
no_gaps=False,
1975+
skip_backfill=True,
1976+
empty_backfill=False,
1977+
restatements={},
1978+
is_dev=False,
1979+
allow_destructive_models=set(),
1980+
allow_additive_models=set(),
1981+
forward_only=False,
1982+
end_bounded=True,
1983+
ensure_finalized_snapshots=False,
1984+
ignore_cron=False,
1985+
directly_modified_snapshots=[snapshot_view.snapshot_id],
1986+
indirectly_modified_snapshots={},
1987+
metadata_updated_snapshots=[snapshot_view.snapshot_id],
1988+
removed_snapshots=[],
1989+
requires_backfill=False,
1990+
models_to_backfill=None,
1991+
execution_time="2023-01-02",
1992+
disabled_restatement_models=set(),
1993+
environment_statements=None,
1994+
user_provided_flags=None,
1995+
)
1996+
1997+
stages = build_plan_stages(plan, state_reader, None)
1998+
1999+
migrate_stages = [s for s in stages if isinstance(s, MigrateSchemasStage)]
2000+
assert migrate_stages, (
2001+
"Expected a MigrateSchemasStage for dev_only VIEW with metadata-only change"
2002+
)
2003+
migrate_stage = migrate_stages[0]
2004+
assert snapshot_view in migrate_stage.snapshots
2005+
2006+
assert not any(isinstance(s, VirtualLayerUpdateStage) for s in stages)
2007+
2008+
19392009
def test_adjust_intervals_new_forward_only_dev_intervals(
19402010
make_snapshot, mocker: MockerFixture
19412011
) -> None:

0 commit comments

Comments
 (0)