Skip to content

Commit 7fb652e

Browse files
authored
Fix!: Always recreate materialized view (#4908)
1 parent aa21086 commit 7fb652e

File tree

3 files changed

+54
-32
lines changed

3 files changed

+54
-32
lines changed

sqlmesh/core/snapshot/evaluator.py

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1876,20 +1876,12 @@ def insert(
18761876
)
18771877
snapshot = kwargs["snapshot"]
18781878
snapshots = kwargs["snapshots"]
1879+
18791880
if (
1880-
(
1881-
isinstance(query_or_df, exp.Expression)
1882-
and snapshot.is_materialized_view
1883-
and deployability_index.is_deployable(snapshot)
1884-
and model.render_query(
1885-
snapshots=snapshots,
1886-
deployability_index=deployability_index,
1887-
engine_adapter=self.adapter,
1888-
)
1889-
== query_or_df
1890-
)
1891-
or self.adapter.HAS_VIEW_BINDING
1892-
) and self.adapter.table_exists(table_name):
1881+
not snapshot.is_materialized_view
1882+
and self.adapter.HAS_VIEW_BINDING
1883+
and self.adapter.table_exists(table_name)
1884+
):
18931885
logger.info("Skipping creation of the view '%s'", table_name)
18941886
return
18951887

tests/core/engine_adapter/integration/test_integration_bigquery.py

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -400,3 +400,50 @@ def test_table_diff_table_name_matches_column_name(ctx: TestContext):
400400

401401
assert row_diff.stats["join_count"] == 1
402402
assert row_diff.full_match_count == 1
403+
404+
405+
def test_materialized_view_evaluation(ctx: TestContext, engine_adapter: BigQueryEngineAdapter):
406+
model_name = ctx.table("test_tbl")
407+
mview_name = ctx.table("test_mview")
408+
409+
sqlmesh = ctx.create_context()
410+
411+
sqlmesh.upsert_model(
412+
load_sql_based_model(
413+
d.parse(
414+
f"""
415+
MODEL (name {model_name}, kind FULL);
416+
417+
SELECT 1 AS col
418+
"""
419+
)
420+
)
421+
)
422+
423+
sqlmesh.upsert_model(
424+
load_sql_based_model(
425+
d.parse(
426+
f"""
427+
MODEL (name {mview_name}, kind VIEW (materialized true));
428+
429+
SELECT * FROM {model_name}
430+
"""
431+
)
432+
)
433+
)
434+
435+
# Case 1: Ensure that plan is successful and we can query the materialized view
436+
sqlmesh.plan(auto_apply=True, no_prompts=True)
437+
438+
df = engine_adapter.fetchdf(f"SELECT * FROM {mview_name.sql(dialect=ctx.dialect)}")
439+
assert df["col"][0] == 1
440+
441+
# Case 2: Ensure that we can change the underlying table and the materialized view is recreated
442+
sqlmesh.upsert_model(
443+
load_sql_based_model(d.parse(f"""MODEL (name {model_name}, kind FULL); SELECT 2 AS col"""))
444+
)
445+
446+
sqlmesh.plan(auto_apply=True, no_prompts=True)
447+
448+
df = engine_adapter.fetchdf(f"SELECT * FROM {mview_name.sql(dialect=ctx.dialect)}")
449+
assert df["col"][0] == 2

tests/core/test_snapshot_evaluator.py

Lines changed: 2 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -516,25 +516,8 @@ def test_evaluate_materialized_view(
516516
snapshots={},
517517
)
518518

519-
adapter_mock.table_exists.assert_called_once_with(snapshot.table_name())
520-
521-
if view_exists:
522-
# Evaluation shouldn't take place because the rendered query hasn't changed
523-
# since the last view creation.
524-
assert not adapter_mock.create_view.called
525-
else:
526-
# If the view doesn't exist, it should be created even if the rendered query
527-
# hasn't changed since the last view creation.
528-
adapter_mock.create_view.assert_called_once_with(
529-
snapshot.table_name(),
530-
model.render_query(),
531-
model.columns_to_types,
532-
replace=True,
533-
materialized=True,
534-
view_properties={},
535-
table_description=None,
536-
column_descriptions={},
537-
)
519+
# Ensure that the materialized view is recreated even if it exists
520+
assert adapter_mock.create_view.assert_called
538521

539522

540523
def test_evaluate_materialized_view_with_partitioned_by_cluster_by(

0 commit comments

Comments
 (0)