О конфигурации 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.