Skip to content

Commit e94f9ec

Browse files
Merge pull request #123 from dbt-labs/version_3_adding_order_by
Adding Order By and Fixing Case When
2 parents 38d4e25 + 9a8f6f2 commit e94f9ec

5 files changed

Lines changed: 191 additions & 60 deletions

File tree

macros/get_metric_sql.sql

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -87,16 +87,31 @@ metrics there are #}
8787

8888
{{ metrics.gen_joined_metrics_cte(metric_tree["parent_set"], metric_tree["expression_set"], metric_tree["ordered_expression_set"], grain, non_calendar_dimensions, calendar_dimensions, secondary_calculations, relevant_periods) }}
8989
{{ metrics.gen_secondary_calculation_cte(metric_tree["base_set"], non_calendar_dimensions, grain, metric_tree["full_set"], secondary_calculations, calendar_dimensions) }}
90-
{{ metrics.gen_final_cte(metric_tree["base_set"], grain, metric_tree["full_set"], secondary_calculations,where) }}
91-
90+
{{ metrics.gen_final_cte(
91+
metric_tree=metric_tree,
92+
grain=grain,
93+
dimensions=non_calendar_dimensions,
94+
calendar_dimensions=calendar_dimensions,
95+
relevant_periods=relevant_periods,
96+
secondary_calculations=secondary_calculations,
97+
where=where)
98+
}}
9299

93100
{# If we're calling the develop macro then we don't need to loop through the metrics because we know
94101
this is only a single metric and not an expression metric #}
95102
{%- elif is_develop_macro -%}
96103

97104
{{ metrics.build_metric_sql(metric_name, metric_type, metric_sql, metric_timestamp, metric_filters, metric_model, grain, non_calendar_dimensions, secondary_calculations, start_date, end_date, calendar_tbl, relevant_periods, calendar_dimensions, dimensions_provided) }}
98105
{{ metrics.gen_secondary_calculation_cte(metric_tree["base_set"], non_calendar_dimensions, grain, metric_tree["full_set"], secondary_calculations, calendar_dimensions) }}
99-
{{ metrics.gen_final_cte(metric_tree["base_set"], grain, metric_tree["full_set"], secondary_calculations,where) }}
106+
{{ metrics.gen_final_cte(
107+
metric_tree=metric_tree,
108+
grain=grain,
109+
dimensions=non_calendar_dimensions,
110+
calendar_dimensions=calendar_dimensions,
111+
relevant_periods=relevant_periods,
112+
secondary_calculations=secondary_calculations,
113+
where=where)
114+
}}
100115

101116
{# If it is NOT a composite metric, we run the baseline model #}
102117
{%- else -%}
@@ -123,8 +138,17 @@ this is only a single metric and not an expression metric #}
123138
{{ metrics.build_metric_sql(metric_name, metric_type, metric_sql, metric_timestamp, metric_filters, metric_model, grain, non_calendar_dimensions, secondary_calculations, start_date, end_date,calendar_tbl, relevant_periods, calendar_dimensions,dimensions_provided) }}
124139
{% endfor %}
125140
{{ metrics.gen_secondary_calculation_cte(metric_tree["base_set"], non_calendar_dimensions, grain, metric_tree["full_set"], secondary_calculations, calendar_dimensions) }}
126-
{{ metrics.gen_final_cte(metric_tree["base_set"], grain, metric_tree["full_set"], secondary_calculations,where) }}
127141

142+
{{ metrics.gen_final_cte(
143+
metric_tree=metric_tree,
144+
grain=grain,
145+
dimensions=non_calendar_dimensions,
146+
calendar_dimensions=calendar_dimensions,
147+
relevant_periods=relevant_periods,
148+
secondary_calculations=secondary_calculations,
149+
where=where)
150+
}}
151+
128152
{%- endif -%}
129153

130154
{% endmacro %}

macros/sql_gen/gen_base_query.sql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
calendar_table.{{ calendar_dim }},
2525
{%- endfor %}
2626
{%- if metric_sql and metric_sql | replace('*', '') | trim != '' -%}
27-
base_model.{{ metric_sql }} as property_to_aggregate
27+
({{ metric_sql }}) as property_to_aggregate
2828
{%- elif metric_type == 'count' -%}
2929
1 as property_to_aggregate /*a specific expression to aggregate wasn't provided, so this effectively creates count(*) */
3030
{%- else -%}

macros/sql_gen/gen_final_cte.sql

Lines changed: 32 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,72 +1,49 @@
1-
{% macro gen_final_cte(base_set,grain,full_set,secondary_calculations, where) %}
2-
{{ return(adapter.dispatch('gen_final_cte', 'metrics')(base_set,grain,full_set,secondary_calculations, where)) }}
1+
{%- macro gen_final_cte(metric_tree, grain, dimensions, calendar_dimensions, relevant_periods, secondary_calculations, where) -%}
2+
{{ return(adapter.dispatch('gen_final_cte', 'metrics')(metric_tree, grain, dimensions, calendar_dimensions, relevant_periods, secondary_calculations, where)) }}
33
{% endmacro %}
44

5-
{% macro default__gen_final_cte(base_set,grain,full_set,secondary_calculations, where) %}
5+
{% macro default__gen_final_cte(metric_tree, grain, dimensions, calendar_dimensions, relevant_periods, secondary_calculations, where) %}
66

7-
{%- if full_set | length > 1 %}
87

9-
{% if secondary_calculations | length > 0 %}
8+
{%- if secondary_calculations | length > 0 -%}
109

11-
,final as (
10+
, final as (
1211

13-
select
14-
*
15-
from secondary_calculations
16-
)
12+
select
13+
*
14+
from secondary_calculations
15+
)
1716

18-
select * from final
17+
select * from final
1918

20-
-- metric where clauses...
21-
{% if where %}
22-
where {{ where }}
23-
{% endif %}
24-
25-
{% else %}
26-
27-
select * from joined_metrics
28-
29-
-- metric where clauses...
30-
{% if where %}
31-
where {{ where }}
32-
{% endif %}
33-
34-
{% endif %}
19+
{# metric where clauses #}
20+
{%- if where %}
21+
where {{ where }}
22+
{%- endif %}
23+
{{ metrics.gen_order_by(grain, dimensions, calendar_dimensions, relevant_periods) }}
3524

3625
{% else %}
3726

38-
{% if secondary_calculations | length > 0 %}
39-
40-
-- single metric with secondary calculations
41-
42-
,final as (
43-
44-
select
45-
*
46-
from secondary_calculations
47-
)
27+
{%- if metric_tree.full_set | length > 1 %}
4828

49-
select * from final
50-
51-
-- metric where clauses...
52-
{% if where %}
53-
where {{ where }}
54-
{% endif %}
55-
56-
{% else %}
57-
58-
-- single metric without secondary calculations
59-
60-
select * from {{base_set[0]}}__final
29+
select * from joined_metrics
30+
{#- metric where clauses -#}
31+
{%- if where %}
32+
where {{ where }}
33+
{%- endif -%}
34+
{{ metrics.gen_order_by(grain, dimensions, calendar_dimensions, relevant_periods) }}
6135

36+
{% else %}
6237

63-
-- metric where clauses...
64-
{% if where %}
65-
where {{ where }}
66-
{% endif %}
38+
select * from {{metric_tree.base_set[0]}}__final
39+
{%- if where %}
40+
where {{ where }}
41+
{%- endif -%}
42+
{{ metrics.gen_order_by(grain, dimensions, calendar_dimensions, relevant_periods) }}
43+
44+
{%- endif %}
6745

68-
{% endif %}
6946

70-
{% endif %}
47+
{%- endif %}
7148

72-
{% endmacro %}
49+
{%- endmacro %}

macros/sql_gen/gen_order_by.sql

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
{%- macro gen_order_by(grain, dimensions, calendar_dimensions, relevant_periods) -%}
2+
{{ return(adapter.dispatch('gen_order_by', 'metrics')(grain, dimensions, calendar_dimensions, relevant_periods)) }}
3+
{%- endmacro -%}
4+
5+
{% macro default__gen_order_by(grain, dimensions, calendar_dimensions, relevant_periods) %}
6+
7+
{#- This macro exclusively exists because dynamic group by counts based on range
8+
were too funky when we hardcoded values for 1+1. So we're getting around it by
9+
making it its own function -#}
10+
{#- The issue arises when we have an initial date column (ie date_month) where month
11+
is also included in the relevent periods. This causes issues and so we need to
12+
remove the grain from the list of relevant periods so it isnt double counted -#}
13+
{%- set dimension_length = dimensions | length -%}
14+
{%- set calendar_dimension_length = calendar_dimensions | length -%}
15+
{%- set cleaned_relevant_periods = [] -%}
16+
{%- set period_length = relevant_periods | length -%}
17+
{%- set total_length = dimension_length + period_length + calendar_dimension_length -%}
18+
{% if grain != 'all_time' %}
19+
order by
20+
{% for number in range(1,total_length+2) -%}
21+
{{ number }} desc {%- if not loop.last -%}, {% endif -%}
22+
{% endfor -%}
23+
{% endif %}
24+
{% endmacro %}
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
from struct import pack
2+
import os
3+
import pytest
4+
from dbt.tests.util import run_dbt
5+
6+
# our file contents
7+
from tests.functional.fixtures import (
8+
fact_orders_source_csv,
9+
fact_orders_sql,
10+
fact_orders_yml,
11+
)
12+
13+
# models/case_when_metric.sql
14+
case_when_metric_sql = """
15+
select *
16+
from
17+
{{ metrics.calculate(metric('case_when_metric'),
18+
grain='month'
19+
)
20+
}}
21+
"""
22+
23+
# models/case_when_metric.yml
24+
case_when_metric_yml = """
25+
version: 2
26+
models:
27+
- name: case_when_metric
28+
tests:
29+
- dbt_utils.equality:
30+
compare_model: ref('case_when_metric__expected')
31+
metrics:
32+
- name: case_when_metric
33+
model: ref('fact_orders')
34+
label: Total Discount ($)
35+
timestamp: order_date
36+
time_grains: [day, week, month]
37+
type: sum
38+
sql: case when had_discount = true then 1 else 0 end
39+
dimensions:
40+
- order_country
41+
"""
42+
43+
# seeds/case_when_metric__expected.csv
44+
case_when_metric__expected_csv = """
45+
date_month,case_when_metric
46+
2022-01-01,2
47+
2022-02-01,1
48+
""".lstrip()
49+
50+
class TestCaseWhenMetric:
51+
52+
# configuration in dbt_project.yml
53+
@pytest.fixture(scope="class")
54+
def project_config_update(self):
55+
return {
56+
"name": "example",
57+
"models": {"+materialized": "table"}
58+
}
59+
60+
# install current repo as package
61+
@pytest.fixture(scope="class")
62+
def packages(self):
63+
return {
64+
"packages": [
65+
{"local": os.getcwd()}
66+
]
67+
}
68+
69+
70+
# everything that goes in the "seeds" directory
71+
@pytest.fixture(scope="class")
72+
def seeds(self):
73+
return {
74+
"fact_orders_source.csv": fact_orders_source_csv,
75+
"case_when_metric__expected.csv": case_when_metric__expected_csv,
76+
}
77+
78+
# everything that goes in the "models" directory
79+
@pytest.fixture(scope="class")
80+
def models(self):
81+
return {
82+
"fact_orders.sql": fact_orders_sql,
83+
"fact_orders.yml": fact_orders_yml,
84+
"case_when_metric.sql": case_when_metric_sql,
85+
"case_when_metric.yml": case_when_metric_yml
86+
}
87+
88+
def test_build_completion(self,project,):
89+
# running deps to install package
90+
results = run_dbt(["deps"])
91+
92+
# seed seeds
93+
results = run_dbt(["seed"])
94+
assert len(results) == 2
95+
96+
# initial run
97+
results = run_dbt(["run"])
98+
assert len(results) == 3
99+
100+
# test tests
101+
results = run_dbt(["test"]) # expect passing test
102+
assert len(results) == 1
103+
104+
# # # validate that the results include pass
105+
result_statuses = sorted(r.status for r in results)
106+
assert result_statuses == ["pass"]

0 commit comments

Comments
 (0)