Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
kind: Features
body: Add Snowflake Semantic View as materialization
time: 2025-09-03T13:33:04.958749-07:00
custom:
Author: sfc-gh-yutliu
Issue: "1260"
6 changes: 6 additions & 0 deletions dbt-snowflake/src/dbt/adapters/snowflake/relation.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ class SnowflakeRelation(BaseRelation):
SnowflakeRelationType.Table, # type: ignore
SnowflakeRelationType.View, # type: ignore
SnowflakeRelationType.DynamicTable, # type: ignore
SnowflakeRelationType.SemanticView, # type: ignore
}
)
)
Expand All @@ -53,6 +54,7 @@ class SnowflakeRelation(BaseRelation):
SnowflakeRelationType.DynamicTable, # type: ignore
SnowflakeRelationType.Table, # type: ignore
SnowflakeRelationType.View, # type: ignore
SnowflakeRelationType.SemanticView, # type: ignore
}
)
)
Expand All @@ -69,6 +71,10 @@ def is_materialized_view(self) -> bool:
def is_iceberg_format(self) -> bool:
return self.table_format == constants.ICEBERG_TABLE_FORMAT

@property
def is_semantic_view(self) -> bool:
return self.type == SnowflakeRelationType.SemanticView

@classproperty
def DynamicTable(cls) -> str:
return str(SnowflakeRelationType.DynamicTable)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ class SnowflakeRelationType(StrEnum):
CTE = "cte"
External = "external"
DynamicTable = "dynamic_table"
SemanticView = "semantic_view"


class SnowflakeIncludePolicy(Policy):
Expand Down
4 changes: 4 additions & 0 deletions dbt-snowflake/src/dbt/include/snowflake/macros/adapters.sql
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,8 @@
{% macro snowflake__alter_relation_comment(relation, relation_comment) -%}
{%- if relation.is_dynamic_table -%}
{%- set relation_type = 'dynamic table' -%}
{% elif relation.is_semantic_view -%}
{%- set relation_type = 'semantic view' -%}
{%- else -%}
{%- set relation_type = relation.type -%}
{%- endif -%}
Expand All @@ -111,6 +113,8 @@
{% set existing_columns = adapter.get_columns_in_relation(relation) | map(attribute="name") | list %}
{% if relation.is_dynamic_table -%}
{% set relation_type = "table" %}
{% elif relation.is_semantic_view -%}
{%- set relation_type = "semantic view" -%}
{% else -%}
{% set relation_type = relation.type %}
{% endif %}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{% materialization semantic_view, adapter='snowflake' -%}

{% set original_query_tag = set_query_tag() %}
{% set to_return = snowflake__create_or_replace_semantic_view() %}

{% set target_relation = this.incorporate(type='semantic_view') %}

-- COMMENT ON SEMANTIC VIEW support
{% do persist_docs(target_relation, model, for_columns=false) %}

{% do unset_query_tag(original_query_tag) %}

{% do return(to_return) %}

{%- endmaterialization %}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
{% if relation.is_dynamic_table %}
{{ snowflake__get_create_dynamic_table_as_sql(relation, sql) }}

{% elif relation.is_semantic_view %}
{{ snowflake__get_create_semantic_view_sql(relation, sql) }}

{% else %}
{{ default__get_create_sql(relation, sql) }}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
{% macro snowflake__get_create_semantic_view_sql(relation, sql) -%}
{#-
-- Produce DDL that creates a semantic view
--
-- Args:
-- - relation: Union[SnowflakeRelation, str]
-- - SnowflakeRelation - required for relation.render()
-- - str - is already the rendered relation name
-- - sql: str - the code defining the model
-- Returns:
-- A valid DDL statement which will result in a new semantic view.
-#}

create or replace semantic view {{ relation }}
{{ sql }}

{%- endmacro %}


{% macro snowflake__create_or_replace_semantic_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_semantic_view) -%}
{%- set copy_grants = config.get('copy_grants', default=false) -%}

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

{%- if copy_grants -%}
{#- Normalize SQL and append COPY GRANTS if not already present (case-insensitive) -#}
{%- set _sql_norm = sql | trim -%}
{%- set _sql_norm = _sql_norm[:-1] if _sql_norm[-1:] == ';' else _sql_norm -%}
{%- set _sql_norm = _sql_norm | trim -%}
{%- set _ends = (_sql_norm | lower)[-11:] -%}
{%- if _ends != 'copy grants' -%}
{%- set sql = sql ~ '\nCOPY GRANTS' -%}
{%- endif -%}
{%- endif -%}

{{ run_hooks(pre_hooks) }}

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

{{ run_hooks(post_hooks) }}

{{ return({'relations': [target_relation]}) }}

{% endmacro %}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{% macro snowflake__get_drop_semantic_view_sql(relation) %}
drop semantic view if exists {{ relation }}
{% endmacro %}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{%- macro snowflake__get_semantic_view_rename_sql(relation, new_name) -%}
/*
Rename or move a semantic view to the new name.
Args:
relation: SnowflakeRelation - relation to be renamed
new_name: Union[str, SnowflakeRelation] - new name for `relation`
Returns: templated string
*/
alter semantic view if exists {{ relation }} rename to {{ new_name }}
{%- endmacro -%}
Loading
Loading