forked from repo-mirrors/dbt-core
Compare commits
2 Commits
main
...
jerco/util
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8952617f61 | ||
|
|
ce88aba97d |
7
.changes/unreleased/Features-20220518-114604.yaml
Normal file
7
.changes/unreleased/Features-20220518-114604.yaml
Normal file
@@ -0,0 +1,7 @@
|
||||
kind: Features
|
||||
body: Move cross-db macros from dbt-utils into dbt-core global project
|
||||
time: 2022-05-18T11:46:04.557104+02:00
|
||||
custom:
|
||||
Author: jtcohen6
|
||||
Issue: "4813"
|
||||
PR: "5265"
|
||||
14
core/dbt/include/global_project/macros/utils/dateadd.sql
Normal file
14
core/dbt/include/global_project/macros/utils/dateadd.sql
Normal file
@@ -0,0 +1,14 @@
|
||||
{% macro dateadd(datepart, interval, from_date_or_timestamp) %}
|
||||
{{ return(adapter.dispatch('dateadd', 'dbt')(datepart, interval, from_date_or_timestamp)) }}
|
||||
{% endmacro %}
|
||||
|
||||
|
||||
{% macro default__dateadd(datepart, interval, from_date_or_timestamp) %}
|
||||
|
||||
dateadd(
|
||||
{{ datepart }},
|
||||
{{ interval }},
|
||||
{{ from_date_or_timestamp }}
|
||||
)
|
||||
|
||||
{% endmacro %}
|
||||
14
core/dbt/include/global_project/macros/utils/datediff.sql
Normal file
14
core/dbt/include/global_project/macros/utils/datediff.sql
Normal file
@@ -0,0 +1,14 @@
|
||||
{% macro datediff(first_date, second_date, datepart) %}
|
||||
{{ return(adapter.dispatch('datediff', 'dbt')(first_date, second_date, datepart)) }}
|
||||
{% endmacro %}
|
||||
|
||||
|
||||
{% macro default__datediff(first_date, second_date, datepart) -%}
|
||||
|
||||
datediff(
|
||||
{{ datepart }},
|
||||
{{ first_date }},
|
||||
{{ second_date }}
|
||||
)
|
||||
|
||||
{%- endmacro %}
|
||||
@@ -0,0 +1,5 @@
|
||||
{% macro postgres__dateadd(datepart, interval, from_date_or_timestamp) %}
|
||||
|
||||
{{ from_date_or_timestamp }} + ((interval '1 {{ datepart }}') * ({{ interval }}))
|
||||
|
||||
{% endmacro %}
|
||||
@@ -0,0 +1,32 @@
|
||||
{% macro postgres__datediff(first_date, second_date, datepart) -%}
|
||||
|
||||
{% if datepart == 'year' %}
|
||||
(date_part('year', ({{second_date}})::date) - date_part('year', ({{first_date}})::date))
|
||||
{% elif datepart == 'quarter' %}
|
||||
({{ datediff(first_date, second_date, 'year') }} * 4 + date_part('quarter', ({{second_date}})::date) - date_part('quarter', ({{first_date}})::date))
|
||||
{% elif datepart == 'month' %}
|
||||
({{ datediff(first_date, second_date, 'year') }} * 12 + date_part('month', ({{second_date}})::date) - date_part('month', ({{first_date}})::date))
|
||||
{% elif datepart == 'day' %}
|
||||
(({{second_date}})::date - ({{first_date}})::date)
|
||||
{% elif datepart == 'week' %}
|
||||
({{ datediff(first_date, second_date, 'day') }} / 7 + case
|
||||
when date_part('dow', ({{first_date}})::timestamp) <= date_part('dow', ({{second_date}})::timestamp) then
|
||||
case when {{first_date}} <= {{second_date}} then 0 else -1 end
|
||||
else
|
||||
case when {{first_date}} <= {{second_date}} then 1 else 0 end
|
||||
end)
|
||||
{% elif datepart == 'hour' %}
|
||||
({{ datediff(first_date, second_date, 'day') }} * 24 + date_part('hour', ({{second_date}})::timestamp) - date_part('hour', ({{first_date}})::timestamp))
|
||||
{% elif datepart == 'minute' %}
|
||||
({{ datediff(first_date, second_date, 'hour') }} * 60 + date_part('minute', ({{second_date}})::timestamp) - date_part('minute', ({{first_date}})::timestamp))
|
||||
{% elif datepart == 'second' %}
|
||||
({{ datediff(first_date, second_date, 'minute') }} * 60 + floor(date_part('second', ({{second_date}})::timestamp)) - floor(date_part('second', ({{first_date}})::timestamp)))
|
||||
{% elif datepart == 'millisecond' %}
|
||||
({{ datediff(first_date, second_date, 'minute') }} * 60000 + floor(date_part('millisecond', ({{second_date}})::timestamp)) - floor(date_part('millisecond', ({{first_date}})::timestamp)))
|
||||
{% elif datepart == 'microsecond' %}
|
||||
({{ datediff(first_date, second_date, 'minute') }} * 60000000 + floor(date_part('microsecond', ({{second_date}})::timestamp)) - floor(date_part('microsecond', ({{first_date}})::timestamp)))
|
||||
{% else %}
|
||||
{{ exceptions.raise_compiler_error("Unsupported datepart for macro datediff in postgres: {!r}".format(datepart)) }}
|
||||
{% endif %}
|
||||
|
||||
{%- endmacro %}
|
||||
34
tests/adapter/dbt/tests/adapter/utils/base_utils.py
Normal file
34
tests/adapter/dbt/tests/adapter/utils/base_utils.py
Normal file
@@ -0,0 +1,34 @@
|
||||
import os
|
||||
import pytest
|
||||
from dbt.tests.util import run_dbt
|
||||
|
||||
macros__test_assert_equal_sql = """
|
||||
{% test assert_equal(model, actual, expected) %}
|
||||
select * from {{ model }} where {{ actual }} != {{ expected }}
|
||||
|
||||
{% endtest %}
|
||||
"""
|
||||
|
||||
|
||||
class BaseUtils:
|
||||
# setup
|
||||
@pytest.fixture(scope="class")
|
||||
def macros(self):
|
||||
return {"test_assert_equal.sql": macros__test_assert_equal_sql}
|
||||
|
||||
# make it possible to dynamically update the macro call with a namespace
|
||||
# (e.g.) 'dateadd', 'dbt.dateadd', 'dbt_utils.dateadd'
|
||||
def macro_namespace(self):
|
||||
return ""
|
||||
|
||||
def interpolate_macro_namespace(self, model_sql, macro_name):
|
||||
macro_namespace = self.macro_namespace()
|
||||
return (
|
||||
model_sql.replace(f"{macro_name}(", f"{macro_namespace}.{macro_name}(")
|
||||
if macro_namespace
|
||||
else model_sql
|
||||
)
|
||||
|
||||
# actual test sequence
|
||||
def test_build_assert_equal(self, project):
|
||||
run_dbt(["build"]) # seed, model, test
|
||||
40
tests/adapter/dbt/tests/adapter/utils/fixture_dateadd.py
Normal file
40
tests/adapter/dbt/tests/adapter/utils/fixture_dateadd.py
Normal file
@@ -0,0 +1,40 @@
|
||||
# dateadd
|
||||
|
||||
seeds__data_dateadd_csv = """from_time,interval_length,datepart,result
|
||||
2018-01-01 01:00:00,1,day,2018-01-02 01:00:00
|
||||
2018-01-01 01:00:00,1,month,2018-02-01 01:00:00
|
||||
2018-01-01 01:00:00,1,year,2019-01-01 01:00:00
|
||||
2018-01-01 01:00:00,1,hour,2018-01-01 02:00:00
|
||||
,1,day,
|
||||
"""
|
||||
|
||||
|
||||
models__test_dateadd_sql = """
|
||||
with data as (
|
||||
|
||||
select * from {{ ref('data_dateadd') }}
|
||||
|
||||
)
|
||||
|
||||
select
|
||||
case
|
||||
when datepart = 'hour' then cast({{ dateadd('hour', 'interval_length', 'from_time') }} as {{ api.Column.translate_type('timestamp') }})
|
||||
when datepart = 'day' then cast({{ dateadd('day', 'interval_length', 'from_time') }} as {{ api.Column.translate_type('timestamp') }})
|
||||
when datepart = 'month' then cast({{ dateadd('month', 'interval_length', 'from_time') }} as {{ api.Column.translate_type('timestamp') }})
|
||||
when datepart = 'year' then cast({{ dateadd('year', 'interval_length', 'from_time') }} as {{ api.Column.translate_type('timestamp') }})
|
||||
else null
|
||||
end as actual,
|
||||
result as expected
|
||||
|
||||
from data
|
||||
"""
|
||||
|
||||
models__test_dateadd_yml = """
|
||||
version: 2
|
||||
models:
|
||||
- name: test_dateadd
|
||||
tests:
|
||||
- assert_equal:
|
||||
actual: actual
|
||||
expected: expected
|
||||
"""
|
||||
66
tests/adapter/dbt/tests/adapter/utils/fixture_datediff.py
Normal file
66
tests/adapter/dbt/tests/adapter/utils/fixture_datediff.py
Normal file
@@ -0,0 +1,66 @@
|
||||
|
||||
# datediff
|
||||
|
||||
seeds__data_datediff_csv = """first_date,second_date,datepart,result
|
||||
2018-01-01 01:00:00,2018-01-02 01:00:00,day,1
|
||||
2018-01-01 01:00:00,2018-02-01 01:00:00,month,1
|
||||
2018-01-01 01:00:00,2019-01-01 01:00:00,year,1
|
||||
2018-01-01 01:00:00,2018-01-01 02:00:00,hour,1
|
||||
2018-01-01 01:00:00,2018-01-01 02:01:00,minute,61
|
||||
2018-01-01 01:00:00,2018-01-01 02:00:01,second,3601
|
||||
2019-12-31 00:00:00,2019-12-27 00:00:00,week,-1
|
||||
2019-12-31 00:00:00,2019-12-30 00:00:00,week,0
|
||||
2019-12-31 00:00:00,2020-01-02 00:00:00,week,0
|
||||
2019-12-31 00:00:00,2020-01-06 02:00:00,week,1
|
||||
,2018-01-01 02:00:00,hour,
|
||||
2018-01-01 02:00:00,,hour,
|
||||
"""
|
||||
|
||||
|
||||
models__test_datediff_sql = """
|
||||
with data as (
|
||||
|
||||
select * from {{ ref('data_datediff') }}
|
||||
|
||||
)
|
||||
|
||||
select
|
||||
|
||||
case
|
||||
when datepart = 'second' then {{ datediff('first_date', 'second_date', 'second') }}
|
||||
when datepart = 'minute' then {{ datediff('first_date', 'second_date', 'minute') }}
|
||||
when datepart = 'hour' then {{ datediff('first_date', 'second_date', 'hour') }}
|
||||
when datepart = 'day' then {{ datediff('first_date', 'second_date', 'day') }}
|
||||
when datepart = 'week' then {{ datediff('first_date', 'second_date', 'week') }}
|
||||
when datepart = 'month' then {{ datediff('first_date', 'second_date', 'month') }}
|
||||
when datepart = 'year' then {{ datediff('first_date', 'second_date', 'year') }}
|
||||
else null
|
||||
end as actual,
|
||||
result as expected
|
||||
|
||||
from data
|
||||
|
||||
-- Also test correct casting of literal values.
|
||||
|
||||
union all select {{ datediff("'1999-12-31 23:59:59.999999'", "'2000-01-01 00:00:00.000000'", "microsecond") }} as actual, 1 as expected
|
||||
union all select {{ datediff("'1999-12-31 23:59:59.999999'", "'2000-01-01 00:00:00.000000'", "millisecond") }} as actual, 1 as expected
|
||||
union all select {{ datediff("'1999-12-31 23:59:59.999999'", "'2000-01-01 00:00:00.000000'", "second") }} as actual, 1 as expected
|
||||
union all select {{ datediff("'1999-12-31 23:59:59.999999'", "'2000-01-01 00:00:00.000000'", "minute") }} as actual, 1 as expected
|
||||
union all select {{ datediff("'1999-12-31 23:59:59.999999'", "'2000-01-01 00:00:00.000000'", "hour") }} as actual, 1 as expected
|
||||
union all select {{ datediff("'1999-12-31 23:59:59.999999'", "'2000-01-01 00:00:00.000000'", "day") }} as actual, 1 as expected
|
||||
union all select {{ datediff("'1999-12-31 23:59:59.999999'", "'2000-01-03 00:00:00.000000'", "week") }} as actual, 1 as expected
|
||||
union all select {{ datediff("'1999-12-31 23:59:59.999999'", "'2000-01-01 00:00:00.000000'", "month") }} as actual, 1 as expected
|
||||
union all select {{ datediff("'1999-12-31 23:59:59.999999'", "'2000-01-01 00:00:00.000000'", "quarter") }} as actual, 1 as expected
|
||||
union all select {{ datediff("'1999-12-31 23:59:59.999999'", "'2000-01-01 00:00:00.000000'", "year") }} as actual, 1 as expected
|
||||
"""
|
||||
|
||||
|
||||
models__test_datediff_yml = """
|
||||
version: 2
|
||||
models:
|
||||
- name: test_datediff
|
||||
tests:
|
||||
- assert_equal:
|
||||
actual: actual
|
||||
expected: expected
|
||||
"""
|
||||
45
tests/adapter/dbt/tests/adapter/utils/test_dateadd.py
Normal file
45
tests/adapter/dbt/tests/adapter/utils/test_dateadd.py
Normal file
@@ -0,0 +1,45 @@
|
||||
import pytest
|
||||
from dbt.tests.adapter.utils.base_utils import BaseUtils
|
||||
from dbt.tests.adapter.utils.fixture_dateadd import (
|
||||
seeds__data_dateadd_csv,
|
||||
models__test_dateadd_sql,
|
||||
models__test_dateadd_yml,
|
||||
)
|
||||
|
||||
|
||||
class BaseDateAdd(BaseUtils):
|
||||
@pytest.fixture(scope="class")
|
||||
def project_config_update(self):
|
||||
return {
|
||||
"name": "test",
|
||||
# this is only needed for BigQuery, right?
|
||||
# no harm having it here until/unless there's an adapter that doesn't support the 'timestamp' type
|
||||
"seeds": {
|
||||
"test": {
|
||||
"data_dateadd": {
|
||||
"+column_types": {
|
||||
"from_time": "timestamp",
|
||||
"result": "timestamp",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
def seeds(self):
|
||||
return {"data_dateadd.csv": seeds__data_dateadd_csv}
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
def models(self):
|
||||
macro_namespace = self.macro_namespace()
|
||||
return {
|
||||
"test_dateadd.yml": models__test_dateadd_yml,
|
||||
"test_dateadd.sql": self.interpolate_macro_namespace(
|
||||
models__test_dateadd_sql, "dateadd"
|
||||
),
|
||||
}
|
||||
|
||||
|
||||
class TestDateAdd(BaseDateAdd):
|
||||
pass
|
||||
24
tests/adapter/dbt/tests/adapter/utils/test_datediff.py
Normal file
24
tests/adapter/dbt/tests/adapter/utils/test_datediff.py
Normal file
@@ -0,0 +1,24 @@
|
||||
import pytest
|
||||
from dbt.tests.adapter.utils.base_utils import BaseUtils
|
||||
from dbt.tests.adapter.utils.fixture_datediff import (
|
||||
seeds__data_datediff_csv,
|
||||
models__test_datediff_sql,
|
||||
models__test_datediff_yml,
|
||||
)
|
||||
|
||||
|
||||
class BaseDateDiff(BaseUtils):
|
||||
@pytest.fixture(scope="class")
|
||||
def seeds(self):
|
||||
return {"data_datediff.csv": seeds__data_datediff_csv}
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
def models(self):
|
||||
return {
|
||||
"test_datediff.yml": models__test_datediff_yml,
|
||||
"test_datediff.sql": self.interpolate_macro_namespace(models__test_datediff_sql, "datediff"),
|
||||
}
|
||||
|
||||
|
||||
class TestDateDiff(BaseDateDiff):
|
||||
pass
|
||||
Reference in New Issue
Block a user