Skip to content

Commit

Permalink
Support materialized view replacement
Browse files Browse the repository at this point in the history
  • Loading branch information
mdesmet committed Mar 6, 2023
1 parent 1f4690a commit 7f72784
Show file tree
Hide file tree
Showing 3 changed files with 98 additions and 10 deletions.
7 changes: 7 additions & 0 deletions .changes/unreleased/Features-20230304-002708.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
kind: Features
body: Support Materialized view replacement
time: 2023-03-04T00:27:08.158991+01:00
custom:
Author: mdesmet
Issue: ""
PR: "256"
59 changes: 49 additions & 10 deletions dbt/include/trino/macros/adapters.sql
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,20 @@
{% macro trino__list_relations_without_caching(relation) %}
{% call statement('list_relations_without_caching', fetch_result=True) -%}
select
table_catalog as database,
table_name as name,
table_schema as schema,
case when table_type = 'BASE TABLE' then 'table'
when table_type = 'VIEW' then 'view'
else table_type
t.table_catalog as database,
t.table_name as name,
t.table_schema as schema,
case when mv.name is not null then 'materializedview'
when t.table_type = 'BASE TABLE' then 'table'
when t.table_type = 'VIEW' then 'view'
else t.table_type
end as table_type
from {{ relation.information_schema() }}.tables
where table_schema = '{{ relation.schema | lower }}'
from {{ relation.information_schema() }}.tables t
left join system.metadata.materialized_views mv
on mv.catalog_name = t.table_catalog and mv.schema_name = t.table_schema and mv.name = t.table_name
where t.table_schema = '{{ relation.schema | lower }}'
and (mv.catalog_name is null or mv.catalog_name = '{{ relation.database | lower }}')
and (mv.schema_name is null or mv.schema_name = '{{ relation.schema | lower }}')
{% endcall %}
{{ return(load_result('list_relations_without_caching').table) }}
{% endmacro %}
Expand Down Expand Up @@ -111,8 +116,9 @@


{% macro trino__drop_relation(relation) -%}
{% set relation_type = 'materialized view' if relation.type == 'materializedview' else relation.type %}
{% call statement('drop_relation', auto_begin=False) -%}
drop {{ relation.type }} if exists {{ relation }}
drop {{ relation_type }} if exists {{ relation }}
{%- endcall %}
{% endmacro %}

Expand Down Expand Up @@ -144,8 +150,9 @@


{% macro trino__rename_relation(from_relation, to_relation) -%}
{% set from_relation_type = 'materialized view' if from_relation.type == 'materializedview' else from_relation.type %}
{% call statement('rename_relation') -%}
alter {{ from_relation.type }} {{ from_relation }} rename to {{ to_relation }}
alter {{ from_relation_type }} {{ from_relation }} rename to {{ to_relation }}
{%- endcall %}
{% endmacro %}

Expand Down Expand Up @@ -218,3 +225,35 @@
{% do run_query(sql) %}
{% endfor %}
{% endmacro %}


{% macro create_or_replace_view() %}
{%- set identifier = model['alias'] -%}

{%- set old_relation = adapter.get_relation(database=database, schema=schema, identifier=identifier) -%}
{%- set exists_as_view = (old_relation is not none and old_relation.is_view) -%}

{%- set target_relation = api.Relation.create(
identifier=identifier, schema=schema, database=database,
type='view') -%}
{% set grant_config = config.get('grants') %}

{{ run_hooks(pre_hooks) }}

-- If there is another object delete it
{%- if old_relation is not none and not old_relation.is_view -%}
{{ handle_existing_table(should_full_refresh(), old_relation) }}
{%- endif -%}

-- build model
{% call statement('main') -%}
{{ get_create_view_as_sql(target_relation, sql) }}
{%- endcall %}

{% set should_revoke = should_revoke(exists_as_view, full_refresh_mode=True) %}
{% do apply_grants(target_relation, grant_config, should_revoke=True) %}

{{ run_hooks(post_hooks) }}

{{ return({'relations': [target_relation]}) }}
{% endmacro %}
42 changes: 42 additions & 0 deletions tests/functional/adapter/materialization/test_materialized_view.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import pytest
from dbt.tests.util import check_relation_types, run_dbt


@pytest.mark.iceberg
class TestIcebergMaterializedViewExists:
@pytest.fixture(scope="class")
def project_config_update(self):
return {
"name": "materializedview",
}

@pytest.fixture(scope="class")
def models(self):
return {
"my_view.sql": "select 1 a",
"my_table.sql": """ {{
config(materialized='table')
}}
select 1 a""",
}

def test_mv_is_dropped_when_model_runs_view(self, project):
project.adapter.execute("CREATE OR REPLACE MATERIALIZED VIEW my_view AS SELECT 2 b")
project.adapter.execute("CREATE OR REPLACE MATERIALIZED VIEW my_table AS SELECT 2 b")

# check relation types
expected = {
"my_table": "materializedview",
"my_view": "materializedview",
}
check_relation_types(project.adapter, expected)

model_count = len(run_dbt(["run"]))
assert model_count == 2

# check relation types
expected = {
"my_view": "view",
"my_table": "table",
}
check_relation_types(project.adapter, expected)

0 comments on commit 7f72784

Please sign in to comment.