Skip to content

Commit 28927fe

Browse files
committed
Fix: complete lookback support for custom materializations
1 parent 37523dc commit 28927fe

File tree

3 files changed

+107
-2
lines changed

3 files changed

+107
-2
lines changed

sqlmesh/core/model/meta.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@
2929
SCDType2ByTimeKind,
3030
TimeColumn,
3131
ViewKind,
32-
_IncrementalBy,
3332
model_kind_validator,
3433
OnAdditiveChange,
3534
)
@@ -414,7 +413,7 @@ def column_descriptions(self) -> t.Dict[str, str]:
414413
@property
415414
def lookback(self) -> int:
416415
"""The incremental lookback window."""
417-
return (self.kind.lookback if isinstance(self.kind, _IncrementalBy) else 0) or 0
416+
return getattr(self.kind, "lookback", 0) or 0
418417

419418
def lookback_start(self, start: TimeLike) -> TimeLike:
420419
if self.lookback == 0:

tests/core/test_model.py

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7685,6 +7685,75 @@ class MyTestStrategy(CustomMaterialization):
76857685
)
76867686

76877687

7688+
def test_custom_kind_lookback_property():
7689+
"""Test that CustomKind's lookback property is correctly accessed via ModelMeta.lookback.
7690+
7691+
This test verifies the fix for issue #5268 where CustomKind models were not respecting
7692+
the lookback parameter because the isinstance check for _IncrementalBy failed.
7693+
"""
7694+
7695+
# Test 1: CustomKind with lookback = 3
7696+
class MyTestStrategy(CustomMaterialization):
7697+
pass
7698+
7699+
expressions = d.parse(
7700+
"""
7701+
MODEL (
7702+
name db.custom_table,
7703+
kind CUSTOM (
7704+
materialization 'MyTestStrategy',
7705+
lookback 3
7706+
)
7707+
);
7708+
SELECT a, b FROM upstream
7709+
"""
7710+
)
7711+
7712+
model = load_sql_based_model(expressions)
7713+
assert model.kind.is_custom
7714+
7715+
# Verify that the kind itself has lookback = 3
7716+
kind = t.cast(CustomKind, model.kind)
7717+
assert kind.lookback == 3
7718+
7719+
# The bug: model.lookback should return 3, but with the old implementation
7720+
# using isinstance(self.kind, _IncrementalBy), it would return 0
7721+
assert model.lookback == 3, "CustomKind lookback not accessible via model.lookback property"
7722+
7723+
# Test 2: CustomKind without lookback (should default to 0)
7724+
expressions_no_lookback = d.parse(
7725+
"""
7726+
MODEL (
7727+
name db.custom_table_no_lookback,
7728+
kind CUSTOM (
7729+
materialization 'MyTestStrategy'
7730+
)
7731+
);
7732+
SELECT a, b FROM upstream
7733+
"""
7734+
)
7735+
7736+
model_no_lookback = load_sql_based_model(expressions_no_lookback)
7737+
assert model_no_lookback.lookback == 0
7738+
7739+
# Test 3: Ensure IncrementalByTimeRangeKind still works correctly
7740+
incremental_expressions = d.parse(
7741+
"""
7742+
MODEL (
7743+
name db.incremental_table,
7744+
kind INCREMENTAL_BY_TIME_RANGE (
7745+
time_column ds,
7746+
lookback 5
7747+
)
7748+
);
7749+
SELECT ds, a, b FROM upstream
7750+
"""
7751+
)
7752+
7753+
incremental_model = load_sql_based_model(incremental_expressions)
7754+
assert incremental_model.lookback == 5
7755+
7756+
76887757
def test_time_column_format_in_custom_kind():
76897758
class TimeColumnCustomKind(CustomKind): # type: ignore[no-untyped-def]
76907759
_time_column: TimeColumn

tests/core/test_snapshot.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -679,6 +679,43 @@ def test_lookback(make_snapshot):
679679
assert snapshot.missing_intervals("2023-01-28", "2023-01-30", "2023-01-31 04:00:00") == []
680680

681681

682+
def test_lookback_custom_materialization(make_snapshot):
683+
from sqlmesh import CustomMaterialization
684+
685+
class MyTestStrategy(CustomMaterialization):
686+
pass
687+
688+
expressions = parse(
689+
"""
690+
MODEL (
691+
name name,
692+
kind CUSTOM (
693+
materialization 'MyTestStrategy',
694+
lookback 2
695+
),
696+
start '2023-01-01',
697+
cron '0 5 * * *',
698+
);
699+
700+
SELECT ds FROM parent.tbl
701+
"""
702+
)
703+
704+
snapshot = make_snapshot(load_sql_based_model(expressions))
705+
706+
assert snapshot.missing_intervals("2023-01-01", "2023-01-01") == [
707+
(to_timestamp("2023-01-01"), to_timestamp("2023-01-02")),
708+
]
709+
710+
snapshot.add_interval("2023-01-01", "2023-01-04")
711+
assert snapshot.missing_intervals("2023-01-01", "2023-01-04") == []
712+
assert snapshot.missing_intervals("2023-01-01", "2023-01-05") == [
713+
(to_timestamp("2023-01-03"), to_timestamp("2023-01-04")),
714+
(to_timestamp("2023-01-04"), to_timestamp("2023-01-05")),
715+
(to_timestamp("2023-01-05"), to_timestamp("2023-01-06")),
716+
]
717+
718+
682719
def test_seed_intervals(make_snapshot):
683720
snapshot_a = make_snapshot(
684721
SeedModel(

0 commit comments

Comments
 (0)