О конфигурации dispatch
dbt может расширять функциональность на поддерживаемых платформах данных через систему множественной диспетчеризации. Поскольку синтаксис SQL, типы данных и поддержка / различаются в зависимости от адаптеров, dbt может определять и вызывать универсальные функциональные макросы, а затем "диспетчеризировать" этот макрос к соответствующей реализации для текущего адаптера.
Синтаксис
Аргументы:
macro_name
[обязательный]: Имя макроса для диспетчеризации. Должно быть строковым литералом.macro_namespace
[необязательный]: Пространство имен (пакет) макроса для диспетчеризации. Должно быть строковым литералом.
Использование:
{% macro my_macro(arg1, arg2) -%}
{{ return(adapter.dispatch('my_macro')(arg1, arg2)) }}
{%- endmacro %}
dbt использует два критерия при поиске подходящего макроса-кандидата:
- Префикс адаптера
- Пространство имен (пакет)
Префикс адаптера: Макросы, специфичные для адаптера, имеют префикс с именем адаптера в нижнем регистре и двумя подчеркиваниями. Учитывая макрос с именем my_macro
, dbt будет искать:
- Postgres:
postgres__my_macro
- Redshift:
redshift__my_macro
- Snowflake:
snowflake__my_macro
- BigQuery:
bigquery__my_macro
- OtherAdapter:
otheradapter__my_macro
- по умолчанию:
default__my_macro
Если dbt не найдет реализацию, специфичную для адаптера, он диспетчеризирует к реализации по умолчанию.
Пространство имен: Обычно dbt будет искать реализации в корневом проекте и внутренних проектах (например, dbt
, dbt_postgres
). Если аргумент macro_namespace
предоставлен, он вместо этого ищет в указанном пространстве имен (пакете) подходящие реализации. Также возможно динамически маршрутизировать поиск по пространствам имен, определяя конфигурацию проекта dispatch
; см. примеры ниже для подробностей.
Примеры
Простой пример
Предположим, я хочу определить макрос concat
, который компилируется в SQL-функцию concat()
как его поведение по умолчанию. Однако на Redshift и Snowflake я хочу использовать оператор ||
.
{% macro concat(fields) -%}
{{ return(adapter.dispatch('concat')(fields)) }}
{%- endmacro %}
{% macro default__concat(fields) -%}
concat({{ fields|join(', ') }})
{%- endmacro %}
{% macro redshift__concat(fields) %}
{{ fields|join(' || ') }}
{% endmacro %}
{% macro snowflake__concat(fields) %}
{{ fields|join(' || ') }}
{% endmacro %}
Верхний макрос concat
следует специальной, жесткой формуле: он назван с "основным именем" макроса, concat
, которое будет использоваться для вызова макроса в других местах. Он принимает один аргумент, названный fields
. Единственная функция этого макроса — диспетчеризация, то есть поиск и возврат, используя основное имя макроса (concat
) в качестве поискового термина. Он также хочет передать, в свою конечную реализацию, все переданные ему аргументы. В данном случае есть только один аргумент, названный fields
.
Ниже этого макроса я определил три возможные реализации макроса concat
: одну для Redshift, одну для Snowflake и одну для использования по умолчанию на всех других адаптерах. В зависимости от адаптера, с которым я работаю, будет выбран один из этих макросов, ему будут пе реданы указанные аргументы в качестве входных данных, он выполнит операции над этими аргументами и вернет результат исходному диспетчеризующему макросу.
Более сложный пример
Я нашел существующую реализацию макроса concat
в пакете dbt-utils. Однако я хочу переопределить его реализацию макроса concat
на Redshift в частности. Во всех других случаях, включая реализацию по умолчанию, я полностью доволен использованием реализаций, определенных в dbt_utils.concat
.
{% macro concat(fields) -%}
{{ return(adapter.dispatch('concat')(fields)) }}
{%- endmacro %}
{% macro default__concat(fields) -%}
{{ return(dbt_utils.concat(fields)) }}
{%- endmacro %}
{% macro redshift__concat(fields) %}
{% for field in fields %}
nullif({{ field }},'') {{ ' || ' if not loop.last }}
{% endfor %}
{% endmacro %}
Если я работаю на Redshift, dbt будет использовать мою версию; если я работаю на любой другой базе данных, макрос concat()
будет использовать версию, определенную в dbt_utils
.