Skip to content

Commit

Permalink
Add date_spine macro (and macros it depends on) from dbt-utils to core
Browse files Browse the repository at this point in the history
The macros added are
- date_spine
- get_intervals_between
- generate_series
- get_powers_of_two

We're adding these to core because they are becoming more prevalently used
with the increase usage in the semantic layer. Basically if you are
using the semantic layer currently, then it is almost a requirement
to use dbt-utils, which is undesireable given the SL is supported directly
in core. The primary focus of this was to just add `date_spine`. However,
because `date_spine` depends on other macros, these other macros were
also moved.
  • Loading branch information
QMalcolm committed Sep 8, 2023
1 parent b39eeb3 commit 661d006
Show file tree
Hide file tree
Showing 2 changed files with 128 additions and 0 deletions.
75 changes: 75 additions & 0 deletions core/dbt/include/global_project/macros/utils/date_spine.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
{% macro get_intervals_between(start_date, end_date, datepart) -%}
{{ return(adapter.dispatch('get_intervals_between', 'dbt')(start_date, end_date, datepart)) }}
{%- endmacro %}

{% macro default__get_intervals_between(start_date, end_date, datepart) -%}
{%- call statement('get_intervals_between', fetch_result=True) %}

select {{ dbt.datediff(start_date, end_date, datepart) }}

{%- endcall -%}

{%- set value_list = load_result('get_intervals_between') -%}

{%- if value_list and value_list['data'] -%}
{%- set values = value_list['data'] | map(attribute=0) | list %}
{{ return(values[0]) }}
{%- else -%}
{{ return(1) }}
{%- endif -%}

{%- endmacro %}




{% macro date_spine(datepart, start_date, end_date) %}
{{ return(adapter.dispatch('date_spine', 'dbt')(datepart, start_date, end_date)) }}
{%- endmacro %}

{% macro default__date_spine(datepart, start_date, end_date) %}


{# call as follows:

date_spine(
"day",
"to_date('01/01/2016', 'mm/dd/yyyy')",
"dbt.dateadd(week, 1, current_date)"
) #}


with rawdata as (

{{dbt.generate_series(
dbt.get_intervals_between(start_date, end_date, datepart)
)}}

),

all_periods as (

select (
{{
dbt.dateadd(
datepart,
"row_number() over (order by 1) - 1",
start_date
)
}}
) as date_{{datepart}}
from rawdata

),

filtered as (

select *
from all_periods
where date_{{datepart}} <= {{ end_date }}

)

select * from filtered

{% endmacro %}
53 changes: 53 additions & 0 deletions core/dbt/include/global_project/macros/utils/generate_series.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
{% macro get_powers_of_two(upper_bound) %}
{{ return(adapter.dispatch('get_powers_of_two', 'dbt')(upper_bound)) }}
{% endmacro %}

{% macro default__get_powers_of_two(upper_bound) %}

{% if upper_bound <= 0 %}
{{ exceptions.raise_compiler_error("upper bound must be positive") }}
{% endif %}

{% for _ in range(1, 100) %}
{% if upper_bound <= 2 ** loop.index %}{{ return(loop.index) }}{% endif %}
{% endfor %}

{% endmacro %}


{% macro generate_series(upper_bound) %}
{{ return(adapter.dispatch('generate_series', 'dbt')(upper_bound)) }}
{% endmacro %}

{% macro default__generate_series(upper_bound) %}

{% set n = dbt.get_powers_of_two(upper_bound) %}

with p as (
select 0 as generated_number union all select 1
), unioned as (

select

{% for i in range(n) %}
p{{i}}.generated_number * power(2, {{i}})
{% if not loop.last %} + {% endif %}
{% endfor %}
+ 1
as generated_number

from

{% for i in range(n) %}
p as p{{i}}
{% if not loop.last %} cross join {% endif %}
{% endfor %}

)

select *
from unioned
where generated_number <= {{upper_bound}}
order by generated_number

{% endmacro %}

0 comments on commit 661d006

Please sign in to comment.