Skip to content

Commit 3b97096

Browse files
committed
Fix: Make sure that physical tables exist for promoted snapshots (#3798)
1 parent 679c0fd commit 3b97096

File tree

2 files changed

+46
-5
lines changed

2 files changed

+46
-5
lines changed

sqlmesh/core/plan/evaluator.py

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -219,11 +219,23 @@ def _push(
219219
plan: The plan to source snapshots from.
220220
deployability_index: Indicates which snapshots are deployable in the context of this creation.
221221
"""
222-
snapshots_to_create = [
223-
s
224-
for s in snapshots.values()
225-
if s.is_model and not s.is_symbolic and plan.is_selected_for_backfill(s.name)
226-
]
222+
promoted_snapshot_ids = (
223+
set(plan.environment.promoted_snapshot_ids)
224+
if plan.environment.promoted_snapshot_ids is not None
225+
else None
226+
)
227+
228+
def _should_create(s: Snapshot) -> bool:
229+
if not s.is_model or s.is_symbolic:
230+
return False
231+
# Only create tables for snapshots that we're planning to promote or that were selected for backfill
232+
return (
233+
plan.is_selected_for_backfill(s.name)
234+
or promoted_snapshot_ids is None
235+
or s.snapshot_id in promoted_snapshot_ids
236+
)
237+
238+
snapshots_to_create = [s for s in snapshots.values() if _should_create(s)]
227239

228240
completed = False
229241
try:

tests/core/test_integration.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2855,6 +2855,35 @@ def test_prod_restatement_plan_missing_model_in_dev(
28552855
)
28562856

28572857

2858+
@time_machine.travel("2023-01-08 15:00:00 UTC")
2859+
def test_plan_snapshot_table_exists_for_promoted_snapshot(init_and_plan_context: t.Callable):
2860+
context, plan = init_and_plan_context("examples/sushi")
2861+
context.apply(plan)
2862+
2863+
model = context.get_model("sushi.waiter_revenue_by_day")
2864+
context.upsert_model(add_projection_to_model(t.cast(SqlModel, model)))
2865+
2866+
context.plan("dev", auto_apply=True, no_prompts=True, skip_tests=True)
2867+
2868+
# Drop the views and make sure SQLMesh recreates them later
2869+
top_waiters_snapshot = context.get_snapshot("sushi.top_waiters", raise_if_missing=True)
2870+
context.engine_adapter.drop_view(top_waiters_snapshot.table_name())
2871+
context.engine_adapter.drop_view(top_waiters_snapshot.table_name(False))
2872+
2873+
# Make the environment unfinalized to force recreation of all views in the virtual layer
2874+
context.state_sync.state_sync.engine_adapter.execute(
2875+
"UPDATE sqlmesh._environments SET finalized_ts = NULL WHERE name = 'dev'"
2876+
)
2877+
2878+
model = context.get_model("sushi.customers")
2879+
context.upsert_model(add_projection_to_model(t.cast(SqlModel, model)))
2880+
2881+
context.plan(
2882+
"dev", select_models=["sushi.customers"], auto_apply=True, no_prompts=True, skip_tests=True
2883+
)
2884+
assert context.engine_adapter.table_exists(top_waiters_snapshot.table_name())
2885+
2886+
28582887
@time_machine.travel("2023-01-08 15:00:00 UTC")
28592888
def test_plan_against_expired_environment(init_and_plan_context: t.Callable):
28602889
context, plan = init_and_plan_context("examples/sushi")

0 commit comments

Comments
 (0)