Skip to content

Commit 09b6318

Browse files
committed
Fix: Model kind change should not be categorized as forward-only (#2551)
1 parent 6bcb5ee commit 09b6318

File tree

2 files changed

+55
-7
lines changed

2 files changed

+55
-7
lines changed

sqlmesh/core/plan/builder.py

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -432,7 +432,7 @@ def _categorize_snapshots(
432432
snapshot.categorize_as(SnapshotChangeCategory.FORWARD_ONLY)
433433
else:
434434
snapshot.categorize_as(SnapshotChangeCategory.NON_BREAKING)
435-
elif self._is_forward_only_model(s_id) and is_directly_modified:
435+
elif self._is_forward_only_change(s_id) and is_directly_modified:
436436
self._set_choice(
437437
snapshot,
438438
SnapshotChangeCategory.FORWARD_ONLY,
@@ -486,14 +486,14 @@ def _categorize_snapshots(
486486
):
487487
snapshot.categorize_as(
488488
SnapshotChangeCategory.FORWARD_ONLY
489-
if self._is_forward_only_model(s_id)
489+
if self._is_forward_only_change(s_id)
490490
else SnapshotChangeCategory.INDIRECT_BREAKING
491491
)
492492

493493
elif s_id in self._context_diff.added and self._is_new_snapshot(snapshot):
494494
snapshot.categorize_as(
495495
SnapshotChangeCategory.FORWARD_ONLY
496-
if self._is_forward_only_model(s_id)
496+
if self._is_forward_only_change(s_id)
497497
else SnapshotChangeCategory.BREAKING
498498
)
499499

@@ -525,7 +525,7 @@ def _set_choice(
525525
if not self._is_new_snapshot(child_snapshot):
526526
continue
527527

528-
is_forward_only_child = self._is_forward_only_model(child_s_id)
528+
is_forward_only_child = self._is_forward_only_change(child_s_id)
529529

530530
if is_breaking_choice:
531531
child_snapshot.categorize_as(
@@ -573,8 +573,13 @@ def _apply_effective_from(self) -> None:
573573
if not snapshot.disable_restatement:
574574
snapshot.effective_from = self._effective_from
575575

576-
def _is_forward_only_model(self, s_id: SnapshotId) -> bool:
576+
def _is_forward_only_change(self, s_id: SnapshotId) -> bool:
577577
snapshot = self._context_diff.snapshots[s_id]
578+
if snapshot.name in self._context_diff.modified_snapshots:
579+
_, old = self._context_diff.modified_snapshots[snapshot.name]
580+
# If the model kind has changed, then we should not consider this to be a forward-only change.
581+
if snapshot.is_model and old.model.kind.name != snapshot.model.kind.name:
582+
return False
578583
return (
579584
snapshot.is_model
580585
and snapshot.model.forward_only

tests/core/test_plan.py

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,13 @@
99
from sqlmesh.core.context import Context
1010
from sqlmesh.core.context_diff import ContextDiff
1111
from sqlmesh.core.environment import EnvironmentNamingInfo
12-
from sqlmesh.core.model import IncrementalByTimeRangeKind, SeedKind, SeedModel, SqlModel
12+
from sqlmesh.core.model import (
13+
FullKind,
14+
IncrementalByTimeRangeKind,
15+
SeedKind,
16+
SeedModel,
17+
SqlModel,
18+
)
1319
from sqlmesh.core.model.seed import Seed
1420
from sqlmesh.core.plan import Plan, PlanBuilder, SnapshotIntervals
1521
from sqlmesh.core.snapshot import (
@@ -858,7 +864,13 @@ def test_new_environment_with_changes(make_snapshot, mocker: MockerFixture):
858864

859865

860866
def test_forward_only_models(make_snapshot, mocker: MockerFixture):
861-
snapshot = make_snapshot(SqlModel(name="a", query=parse_one("select 1, ds")))
867+
snapshot = make_snapshot(
868+
SqlModel(
869+
name="a",
870+
query=parse_one("select 1, ds"),
871+
kind=IncrementalByTimeRangeKind(time_column="ds", forward_only=True),
872+
)
873+
)
862874
snapshot.categorize_as(SnapshotChangeCategory.BREAKING)
863875
updated_snapshot = make_snapshot(
864876
SqlModel(
@@ -898,6 +910,37 @@ def test_forward_only_models(make_snapshot, mocker: MockerFixture):
898910
assert updated_snapshot.change_category == SnapshotChangeCategory.FORWARD_ONLY
899911

900912

913+
def test_forward_only_models_model_kind_changed(make_snapshot, mocker: MockerFixture):
914+
snapshot = make_snapshot(SqlModel(name="a", query=parse_one("select 1, ds"), kind=FullKind()))
915+
snapshot.categorize_as(SnapshotChangeCategory.BREAKING)
916+
updated_snapshot = make_snapshot(
917+
SqlModel(
918+
name="a",
919+
query=parse_one("select 3, ds"),
920+
kind=IncrementalByTimeRangeKind(time_column="ds", forward_only=True),
921+
)
922+
)
923+
updated_snapshot.previous_versions = snapshot.all_versions
924+
925+
context_diff = ContextDiff(
926+
environment="test_environment",
927+
is_new_environment=True,
928+
is_unfinalized_environment=False,
929+
create_from="prod",
930+
added=set(),
931+
removed_snapshots={},
932+
modified_snapshots={updated_snapshot.name: (updated_snapshot, snapshot)},
933+
snapshots={updated_snapshot.snapshot_id: updated_snapshot},
934+
new_snapshots={updated_snapshot.snapshot_id: updated_snapshot},
935+
previous_plan_id=None,
936+
previously_promoted_snapshot_ids=set(),
937+
previous_finalized_snapshots=None,
938+
)
939+
940+
PlanBuilder(context_diff, is_dev=True).build()
941+
assert updated_snapshot.change_category == SnapshotChangeCategory.BREAKING
942+
943+
901944
def test_indirectly_modified_forward_only_model(make_snapshot, mocker: MockerFixture):
902945
snapshot_a = make_snapshot(SqlModel(name="a", query=parse_one("select 1 as a, ds")))
903946
snapshot_a.categorize_as(SnapshotChangeCategory.BREAKING)

0 commit comments

Comments
 (0)