Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature: use adapter.dispatch #267

Merged
merged 8 commits into from
Aug 21, 2020
Merged
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
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@

## Features

* Switch usage of `adapter_macro` to `adapter.dispatch`, and define `dbt_utils_dispatch_list`,
enabling users of community-supported database plugins to add or override macro implementations
specific to their database (#267)
* Use `add_ephemeral_prefix` instead of hard-coding a string literal, to support
database adapters that use different prefixes (#267)

## Quality of life

# dbt-utils v0.5.1
Expand Down
36 changes: 36 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -777,6 +777,42 @@ We welcome contributions to this repo! To contribute a new feature or a fix, ple

----

### Dispatch macros

**Note:** This is primarily relevant to users and maintainers of community-supported
database plugins. If you use Postgres, Redshift, Snowflake, or Bigquery, this likely
does not apply to you.

dbt v0.18.0 introduces `adapter.dispatch()`, a reliable way to define different implementations of the same macro
across different databases.

All dispatched macros in `dbt_utils` have an override setting: a `var` named
`dbt_utils_dispatch_list` that accepts a list of package names. If you set this
variable in your project, when dbt searches for implementations of a dispatched
`dbt_utils` macro, it will search through your listed packages _before_ using
the implementations defined in `dbt_utils`.

Set the variable:
```yml
vars:
dbt_utils_dispatch_list:
- first_package_to_search # likely the name of your root project
- second_package_to_search # likely an "add-on" package, such as spark_utils
# dbt_utils is always the last place searched
```

When running on Spark, if dbt needs to dispatch `dbt_utils.datediff`, it will search for the following in order:
```
first_package_to_search.spark__datediff
first_package_to_search.default__datediff
second_package_to_search.spark__datediff
second_package_to_search.default__datediff
dbt_utils.spark__datediff
dbt_utils.default__datediff
```

----

### Getting started with dbt

- [What is dbt]?
Expand Down
2 changes: 1 addition & 1 deletion dbt_project.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name: 'dbt_utils'
version: '0.1.0'

require-dbt-version: [">=0.17.0", "<0.18.0"]
require-dbt-version: [">=0.18.0", "<0.19.0"]
config-version: 2

target-path: "target"
Expand Down
3 changes: 1 addition & 2 deletions integration_tests/models/datetime/test_date_spine.sql
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,7 @@
with date_spine as (

{% if target.type == 'postgres' %}
{{ log("WARNING: Not testing - datediff macro is unsupported on Postgres", info=True) }}
select * from {{ ref('data_date_spine') }}
{{ dbt_utils.date_spine("day", "'2018-01-01'::date", "'2018-01-10'::date") }}

{% elif target.type == 'bigquery' %}
select cast(date_day as date) as date_day
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{{ config(materialized = 'table') }}

{% set relations = dbt_utils.get_relations_by_pattern(target.schema, 'data_events_') %}
{% set relations = dbt_utils.get_relations_by_pattern(target.schema, 'data_events_%') %}
{{ dbt_utils.union_relations(relations) }}
4 changes: 4 additions & 0 deletions macros/cross_db_utils/_get_utils_namespaces.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{% macro _get_utils_namespaces() %}
{% set override_namespaces = var('dbt_utils_dispatch_list', []) %}
{% do return(override_namespaces + ['dbt_utils']) %}
{% endmacro %}
5 changes: 3 additions & 2 deletions macros/cross_db_utils/_is_ephemeral.sql
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
{% macro _is_ephemeral(obj, macro) %}
{%- if obj.is_cte -%}
{% if obj.name.startswith('__dbt__CTE__') %}
{% set model_name = obj.name[12:] %}
{% set ephemeral_prefix = api.Relation.add_ephemeral_prefix('') %}
clrcrl marked this conversation as resolved.
Show resolved Hide resolved
{% if obj.name.startswith(ephemeral_prefix) %}
{% set model_name = obj.name[(ephemeral_prefix|length):] %}
{% else %}
{% set model_name = obj.name %}
{%- endif -%}
Expand Down
10 changes: 5 additions & 5 deletions macros/cross_db_utils/concat.sql
Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@


{% macro concat(fields) -%}
{{ adapter_macro('dbt_utils.concat', fields) }}
{{ adapter.dispatch('concat', packages = dbt_utils._get_utils_namespaces())(fields) }}
{%- endmacro %}


{% macro default__concat(fields) -%}
concat({{ fields|join(', ') }})
{%- endmacro %}


{% macro alternative_concat(fields) %}
{{ fields|join(' || ') }}
{% endmacro %}


{% macro redshift__concat(fields) %}
{{dbt_utils.alternative_concat(fields)}}
{{ dbt_utils.alternative_concat(fields) }}
{% endmacro %}


{% macro snowflake__concat(fields) %}
{{dbt_utils.alternative_concat(fields)}}
{{ dbt_utils.alternative_concat(fields) }}
{% endmacro %}
4 changes: 2 additions & 2 deletions macros/cross_db_utils/current_timestamp.sql
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{% macro current_timestamp() -%}
{{ adapter_macro('dbt_utils.current_timestamp') }}
{{ adapter.dispatch('current_timestamp', packages = dbt_utils._get_utils_namespaces())() }}
{%- endmacro %}

{% macro default__current_timestamp() %}
Expand All @@ -17,7 +17,7 @@


{% macro current_timestamp_in_utc() -%}
{{ adapter_macro('dbt_utils.current_timestamp_in_utc') }}
{{ adapter.dispatch('current_timestamp_in_utc', packages = dbt_utils._get_utils_namespaces())() }}
{%- endmacro %}

{% macro default__current_timestamp_in_utc() %}
Expand Down
12 changes: 6 additions & 6 deletions macros/cross_db_utils/datatypes.sql
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{# string ------------------------------------------------- #}

{%- macro type_string() -%}
{{ adapter_macro('dbt_utils.type_string') }}
{{ adapter.dispatch('type_string', packages = dbt_utils._get_utils_namespaces())() }}
{%- endmacro -%}

{% macro default__type_string() %}
Expand All @@ -25,7 +25,7 @@
{# timestamp ------------------------------------------------- #}

{%- macro type_timestamp() -%}
{{ adapter_macro('dbt_utils.type_timestamp') }}
{{ adapter.dispatch('type_timestamp', packages = dbt_utils._get_utils_namespaces())() }}
{%- endmacro -%}

{% macro default__type_timestamp() %}
Expand All @@ -40,7 +40,7 @@
{# float ------------------------------------------------- #}

{%- macro type_float() -%}
{{ adapter_macro('dbt_utils.type_float') }}
{{ adapter.dispatch('type_float', packages = dbt_utils._get_utils_namespaces())() }}
{%- endmacro -%}

{% macro default__type_float() %}
Expand All @@ -54,7 +54,7 @@
{# numeric ------------------------------------------------ #}

{%- macro type_numeric() -%}
{{ adapter_macro('dbt_utils.type_numeric') }}
{{ adapter.dispatch('type_numeric', packages = dbt_utils._get_utils_namespaces())() }}
{%- endmacro -%}

{% macro default__type_numeric() %}
Expand All @@ -69,7 +69,7 @@
{# bigint ------------------------------------------------- #}

{%- macro type_bigint() -%}
{{ adapter_macro('dbt_utils.type_bigint') }}
{{ adapter.dispatch('type_bigint', packages = dbt_utils._get_utils_namespaces())() }}
{%- endmacro -%}

{% macro default__type_bigint() %}
Expand All @@ -83,7 +83,7 @@
{# int ------------------------------------------------- #}

{%- macro type_int() -%}
{{ adapter_macro('dbt_utils.type_int') }}
{{ adapter.dispatch('type_int', packages = dbt_utils._get_utils_namespaces())() }}
{%- endmacro -%}

{% macro default__type_int() %}
Expand Down
2 changes: 1 addition & 1 deletion macros/cross_db_utils/date_trunc.sql
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{% macro date_trunc(datepart, date) -%}
{{ adapter_macro('dbt_utils.date_trunc', datepart, date) }}
{{ adapter.dispatch('date_trunc', packages = dbt_utils._get_utils_namespaces()) (datepart, date) }}
{%- endmacro %}

{% macro default__date_trunc(datepart, date) %}
Expand Down
3 changes: 1 addition & 2 deletions macros/cross_db_utils/dateadd.sql
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{% macro dateadd(datepart, interval, from_date_or_timestamp) %}
{{ adapter_macro('dbt_utils.dateadd', datepart, interval, from_date_or_timestamp) }}
{{ adapter.dispatch('dateadd', packages = dbt_utils._get_utils_namespaces())(datepart, interval, from_date_or_timestamp) }}
{% endmacro %}


Expand All @@ -23,7 +23,6 @@

{% endmacro %}


{% macro postgres__dateadd(datepart, interval, from_date_or_timestamp) %}

{{ from_date_or_timestamp }} + ((interval '1 {{ datepart }}') * ({{ interval }}))
Expand Down
3 changes: 1 addition & 2 deletions macros/cross_db_utils/datediff.sql
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{% macro datediff(first_date, second_date, datepart) %}
{{ adapter_macro('dbt_utils.datediff', first_date, second_date, datepart) }}
{{ adapter.dispatch('datediff', packages = dbt_utils._get_utils_namespaces())(first_date, second_date, datepart) }}
{% endmacro %}


Expand All @@ -24,7 +24,6 @@

{% endmacro %}


{% macro postgres__datediff(first_date, second_date, datepart) %}

{% if datepart == 'year' %}
Expand Down
2 changes: 1 addition & 1 deletion macros/cross_db_utils/except.sql
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{% macro except() %}
{{ adapter_macro('dbt_utils.except') }}
{{ adapter.dispatch('except', packages = dbt_utils._get_utils_namespaces())() }}
{% endmacro %}


Expand Down
2 changes: 1 addition & 1 deletion macros/cross_db_utils/hash.sql
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{% macro hash(field) -%}
{{ adapter_macro('dbt_utils.hash', field) }}
{{ adapter.dispatch('hash', packages = dbt_utils._get_utils_namespaces()) (field) }}
{%- endmacro %}


Expand Down
2 changes: 1 addition & 1 deletion macros/cross_db_utils/identifier.sql
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
Use `adapter.quote` instead. The {}.{} model triggered this warning. \
'.format(model.package_name, model.name) -%}
{%- do exceptions.warn(error_message) -%}
{{ adapter_macro('dbt_utils.identifier', value) }}
{{ adapter.dispatch('identifier', packages = dbt_utils._get_utils_namespaces()) (value) }}
{% endmacro %}

{% macro default__identifier(value) -%}
Expand Down
2 changes: 1 addition & 1 deletion macros/cross_db_utils/intersect.sql
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{% macro intersect() %}
{{ adapter_macro('dbt_utils.intersect') }}
{{ adapter.dispatch('intersect', packages = dbt_utils._get_utils_namespaces())() }}
{% endmacro %}


Expand Down
2 changes: 1 addition & 1 deletion macros/cross_db_utils/last_day.sql
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ testing is required to validate that it will work on other dateparts.
*/

{% macro last_day(date, datepart) %}
{{ adapter_macro('dbt_utils.last_day', date, datepart) }}
{{ adapter.dispatch('last_day', packages = dbt_utils._get_utils_namespaces()) (date, datepart) }}
{% endmacro %}


Expand Down
2 changes: 1 addition & 1 deletion macros/cross_db_utils/length.sql
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{% macro length(expression) -%}
{{ adapter_macro('dbt_utils.length', expression) }}
{{ adapter.dispatch('length', packages = dbt_utils._get_utils_namespaces()) (expression) }}
{% endmacro %}


Expand Down
2 changes: 1 addition & 1 deletion macros/cross_db_utils/literal.sql
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@

{%- macro string_literal(value) -%}
{{ adapter_macro('dbt_utils.string_literal', value) }}
{{ adapter.dispatch('string_literal', packages = dbt_utils._get_utils_namespaces()) (value) }}
{%- endmacro -%}

{% macro default__string_literal(value) -%}
Expand Down
2 changes: 1 addition & 1 deletion macros/cross_db_utils/position.sql
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{% macro position(substring_text, string_text) -%}
{{ adapter_macro('dbt_utils.position', substring_text, string_text) }}
{{ adapter.dispatch('position', packages = dbt_utils._get_utils_namespaces()) (substring_text, string_text) }}
{% endmacro %}


Expand Down
2 changes: 1 addition & 1 deletion macros/cross_db_utils/replace.sql
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{% macro replace(field, old_chars, new_chars) -%}
{{ adapter_macro('dbt_utils.replace', field, old_chars, new_chars) }}
{{ adapter.dispatch('replace', packages = dbt_utils._get_utils_namespaces()) (field, old_chars, new_chars) }}
{% endmacro %}


Expand Down
2 changes: 1 addition & 1 deletion macros/cross_db_utils/right.sql
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{% macro right(string_text, length_expression) -%}
{{ adapter_macro('dbt_utils.right', string_text, length_expression) }}
{{ adapter.dispatch('right', packages = dbt_utils._get_utils_namespaces()) (string_text, length_expression) }}
{% endmacro %}

{% macro default__right(string_text, length_expression) %}
Expand Down
2 changes: 1 addition & 1 deletion macros/cross_db_utils/safe_cast.sql
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{% macro safe_cast(field, type) %}
{{ adapter_macro('dbt_utils.safe_cast', field, type) }}
{{ adapter.dispatch('safe_cast', packages = dbt_utils._get_utils_namespaces()) (field, type) }}
{% endmacro %}


Expand Down
2 changes: 1 addition & 1 deletion macros/cross_db_utils/split_part.sql
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{% macro split_part(string_text, delimiter_text, part_number) %}
{{ adapter_macro('dbt_utils.split_part', string_text, delimiter_text, part_number) }}
{{ adapter.dispatch('split_part', packages = dbt_utils._get_utils_namespaces()) (string_text, delimiter_text, part_number) }}
{% endmacro %}


Expand Down
2 changes: 1 addition & 1 deletion macros/cross_db_utils/width_bucket.sql
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{% macro width_bucket(expr, min_value, max_value, num_buckets) %}
{{ adapter_macro('dbt_utils.width_bucket', expr, min_value, max_value, num_buckets) }}
{{ adapter.dispatch('width_bucket', packages = dbt_utils._get_utils_namespaces()) (expr, min_value, max_value, num_buckets) }}
{% endmacro %}


Expand Down
16 changes: 14 additions & 2 deletions macros/sql/get_relations_by_pattern.sql
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

{%- call statement('get_tables', fetch_result=True) %}

{{ dbt_utils.get_tables_by_pattern(schema_pattern, table_pattern, exclude, database) }}
{{ dbt_utils.get_tables_by_pattern_sql(schema_pattern, table_pattern, exclude, database) }}

{%- endcall -%}

Expand All @@ -20,4 +20,16 @@
{{ return([]) }}
{%- endif -%}

{% endmacro %}
{% endmacro %}

{% macro get_tables_by_pattern(schema_pattern, table_pattern, exclude='', database=target.database) %}
{%- set error_message = '
Warning: the `get_tables_by_pattern` macro is no longer supported and will be deprecated in a future release of dbt-utils. \
Use the `get_relations_by_prefix` macro instead. \
The {}.{} model triggered this warning. \
'.format(model.package_name, model.name) -%}
{%- do exceptions.warn(error_message) -%}

{{ return(dbt_utils.get_relations_by_pattern(schema_pattern, table_pattern, exclude='', database=target.database)) }}
Copy link
Contributor

@clrcrl clrcrl Aug 20, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So this was some bad code that I merged previously. However, I think this is a breaking change, the previous get_tables_by_pattern returned SQL (here)

Suggested change
{{ return(dbt_utils.get_relations_by_pattern(schema_pattern, table_pattern, exclude='', database=target.database)) }}
{{ return(dbt_utils.get_tables_by_pattern_sql(schema_pattern, table_pattern, exclude='', database=target.database)) }}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given that:

  • the only place that the get_tables_by_prefix macro was used is in get_relations_by_pattern macro
  • AND, I doubt anyone was using get_tables_by_prefix independently of get_relations_by_pattern

I'd be happy to just straight-out remove the get_tables_by_prefix macro

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you want to remove it, we can do so in #268

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah let's do it


{% endmacro %}
12 changes: 0 additions & 12 deletions macros/sql/get_tables_by_pattern.sql

This file was deleted.

28 changes: 28 additions & 0 deletions macros/sql/get_tables_by_pattern_sql.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{% macro get_tables_by_pattern_sql(schema_pattern, table_pattern, exclude='', database=target.database) %}
{{ adapter.dispatch('get_tables_by_pattern_sql', packages = dbt_utils._get_utils_namespaces())
(schema_pattern, table_pattern, exclude='', database=target.database) }}
{% endmacro %}

{% macro default__get_tables_by_pattern_sql(schema_pattern, table_pattern, exclude='', database=target.database) %}

select distinct
table_schema as "table_schema", table_name as "table_name"
from {{database}}.information_schema.tables
where table_schema ilike '{{ schema_pattern }}'
and table_name ilike '{{ table_pattern }}'
and table_name not ilike '{{ exclude }}'

{% endmacro %}


{% macro bigquery__get_tables_by_pattern_sql(schema_pattern, table_pattern, exclude='', database=target.database) %}

select distinct
table_schema, table_name

from {{adapter.quote(database)}}.{{schema}}.INFORMATION_SCHEMA.TABLES
where table_schema = '{{schema_pattern}}'
and lower(table_name) like lower ('{{table_pattern}}')
and lower(table_name) not like lower ('{{exclude}}')

{% endmacro %}
Loading