File tree Expand file tree Collapse file tree 3 files changed +53
-19
lines changed
engine_adapter/integration Expand file tree Collapse file tree 3 files changed +53
-19
lines changed Original file line number Diff line number Diff line change @@ -1876,6 +1876,9 @@ def insert(
18761876 )
18771877 snapshot = kwargs ["snapshot" ]
18781878 snapshots = kwargs ["snapshots" ]
1879+
1880+ # We must replace a materialized view if its query has changed or if it depends on a table.
1881+ # The latter is because if the underlying table is replaced, the materialized view is invalidated in some of the engines.
18791882 if (
18801883 (
18811884 isinstance (query_or_df , exp .Expression )
@@ -1887,6 +1890,7 @@ def insert(
18871890 engine_adapter = self .adapter ,
18881891 )
18891892 == query_or_df
1893+ and not model .depends_on
18901894 )
18911895 or self .adapter .HAS_VIEW_BINDING
18921896 ) and self .adapter .table_exists (table_name ):
Original file line number Diff line number Diff 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
Original file line number Diff line number Diff 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
540523def test_evaluate_materialized_view_with_partitioned_by_cluster_by (
You can’t perform that action at this time.
0 commit comments