Skip to content

Commit

Permalink
alter generate series to fit synapse limitations and add tests
Browse files Browse the repository at this point in the history
  • Loading branch information
nszoni committed Feb 14, 2024
1 parent 5c390b3 commit 1e1c9b8
Show file tree
Hide file tree
Showing 2 changed files with 109 additions and 0 deletions.
61 changes: 61 additions & 0 deletions dbt/include/synapse/macros/utils/generate_series.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
{#
Specifying more than one WITH clause in a CTE isn't allowed. For example, if a CTE query definition contains a subquery,
that subquery can't contain a nested WITH clause that defines another CTE.
#}

{% 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 %}

),

generate_series as (
select *
from unioned
where generated_number <= {{upper_bound}}
)

select * from generate_series

{% endmacro %}
48 changes: 48 additions & 0 deletions tests/functional/adapter/test_generate_series.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import pytest
from dbt.tests.adapter.utils.base_utils import BaseUtils
from dbt.tests.adapter.utils.fixture_generate_series import models__test_generate_series_yml

# Cause of overriding fixture: Specifying more than one WITH clause in a CTE isn't allowed.
# For example, if a CTE query definition contains a subquery,
# that subquery can't contain a nested WITH clause that defines another CTE.

models__test_generate_series_sql = """
{{ dbt.generate_series(10) }}
left join (
select 1 as expected
union all
select 2 as expected
union all
select 3 as expected
union all
select 4 as expected
union all
select 5 as expected
union all
select 6 as expected
union all
select 7 as expected
union all
select 8 as expected
union all
select 9 as expected
union all
select 10 as expected
) as expected_numbers
on generate_series.generated_number = expected_numbers.expected
"""


class BaseGenerateSeries(BaseUtils):
@pytest.fixture(scope="class")
def models(self):
return {
"test_generate_series.yml": models__test_generate_series_yml,
"test_generate_series.sql": self.interpolate_macro_namespace(
models__test_generate_series_sql, "generate_series"
),
}


class TestGenerateSeries(BaseGenerateSeries):
pass

0 comments on commit 1e1c9b8

Please sign in to comment.