dbt 部分macro 中namespace的使用简单说明
比如在dbt adapter 中的snapshot_check_all_get_existing_columns 中就使用了namepace 这个对象,以下简单说明下
namespace 对象的作用
实际上就是进行跨scope 的数据共享,因为jinja2 每个block 中的设置的变量是不能跨范围共享,解决方法就是使用namespace
参考使用
{% set ns = namespace(found=false) %}
{% for item in items %}
{% if item.check_something() %}
{% set ns.found = true %}
{% endif %}
* {{ item.title }}
{% endfor %}
Found item having something: {{ ns.found }}
dbt snapshot_check_all_get_existing_columns 内部处理
{% macro snapshot_check_all_get_existing_columns(node, target_exists, check_cols_config) -%}
{%- if not target_exists -%}
{#-- no table yet -> return whatever the query does --#}
{{ return((false, query_columns)) }}
{%- endif -%}
{#-- handle any schema changes --#}
{%- set target_relation = adapter.get_relation(database=node.database, schema=node.schema, identifier=node.alias) -%}
{% if check_cols_config == 'all' %}
{%- set query_columns = get_columns_in_query(node['compiled_code']) -%}
{% elif check_cols_config is iterable and (check_cols_config | length) > 0 %}
{#-- query for proper casing/quoting, to support comparison below --#}
{%- set select_check_cols_from_target -%}
{#-- N.B. The whitespace below is necessary to avoid edge case issue with comments --#}
{#-- See: https://github.com/dbt-labs/dbt-core/issues/6781 --#}
select {{ check_cols_config | join(', ') }} from (
{{ node['compiled_code'] }}
) subq
{%- endset -%}
{% set query_columns = get_columns_in_query(select_check_cols_from_target) %}
{% else %}
{% do exceptions.raise_compiler_error("Invalid value for 'check_cols': " ~ check_cols_config) %}
{% endif %}
{%- set existing_cols = adapter.get_columns_in_relation(target_relation) | map(attribute = 'name') | list -%}
# 定义namespace 实现跨block 功能的复用
{%- set ns = namespace() -%} {#-- handle for-loop scoping with a namespace --#}
{%- set ns.column_added = false -%}
{%- set intersection = [] -%}
{%- for col in query_columns -%}
{%- if col in existing_cols -%}
{%- do intersection.append(adapter.quote(col)) -%}
{%- else -%}
{% set ns.column_added = true %}
{%- endif -%}
{%- endfor -%}
{{ return((ns.column_added, intersection)) }}
{%- endmacro %}
说明
namespace 实际属于jinja2 的特性,只是dbt 使用了此特性而已,所以看到部分dbt macro 使用此定义不应该陌生
参考资料
dbt/include/global_project/macros/materializations/snapshots/strategies.sql
https://jinja.palletsprojects.com/en/3.0.x/templates/