Skip to content

Commit

Permalink
Add tests
Browse files Browse the repository at this point in the history
  • Loading branch information
courtneyholcomb committed Jan 29, 2025
1 parent ac325b5 commit e188894
Show file tree
Hide file tree
Showing 10 changed files with 1,315 additions and 39 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -132,3 +132,13 @@ metric:
measure:
name: archived_users
join_to_timespine: true
---
metric:
name: archived_users_offset_3_martian_days
description: archived_users offset by 3 martian_days
type: derived
type_params:
expr: archived_users
metrics:
- name: archived_users
offset_window: 3 martian_days
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,12 @@ def test_multiple_time_spines( # noqa: D103
) -> None:
query_result = it_helpers.mf_engine.query(
MetricFlowQueryRequest.create_with_random_request_id(
metric_names=["subdaily_join_to_time_spine_metric", "subdaily_cumulative_window_metric"],
metric_names=[
"subdaily_join_to_time_spine_metric",
"subdaily_cumulative_window_metric",
# TODO: this output won't look right until we adjust values for metric_time__hour to include multiple martian days
"archived_users_offset_3_martian_days",
],
group_by_names=["metric_time__martian_day", "metric_time__hour"],
order_by_names=["metric_time__martian_day", "metric_time__hour"],
)
Expand Down
30 changes: 30 additions & 0 deletions tests_metricflow/plan_conversion/test_dataflow_to_sql_plan.py
Original file line number Diff line number Diff line change
Expand Up @@ -724,6 +724,35 @@ def test_offset_by_custom_granularity_node( # noqa: D103
DataSet.metric_time_dimension_spec(ExpandedTimeGranularity.from_time_granularity(TimeGranularity.MONTH)),
),
use_offset_custom_granularity_node=False,
required_time_spine_sources=(),
)

convert_and_check(
request=request,
mf_test_configuration=mf_test_configuration,
dataflow_to_sql_converter=dataflow_to_sql_converter,
sql_client=sql_client,
node=offset_base_grain_by_custom_grain_node,
)


@pytest.mark.sql_engine_snapshot
@pytest.mark.duckdb_only
def test_offset_by_custom_granularity_node_with_smaller_grain( # noqa: D103
request: FixtureRequest,
mf_test_configuration: MetricFlowTestConfiguration,
dataflow_to_sql_converter: DataflowToSqlPlanConverter,
dataflow_plan_builder: DataflowPlanBuilder,
sql_client: SqlClient,
) -> None:
time_spine_specs = (
DataSet.metric_time_dimension_spec(ExpandedTimeGranularity.from_time_granularity(TimeGranularity.HOUR)),
)
offset_base_grain_by_custom_grain_node = dataflow_plan_builder.build_custom_offset_time_spine_node(
offset_window=PydanticMetricTimeWindow(count=5, granularity="martian_day"),
required_time_spine_specs=time_spine_specs,
use_offset_custom_granularity_node=False,
required_time_spine_sources=dataflow_plan_builder.choose_time_spine_sources(time_spine_specs),
)

convert_and_check(
Expand Down Expand Up @@ -752,6 +781,7 @@ def test_offset_custom_granularity_node( # noqa: D103
),
),
use_offset_custom_granularity_node=True,
required_time_spine_sources=(),
)

convert_and_check(
Expand Down
24 changes: 24 additions & 0 deletions tests_metricflow/query_rendering/test_custom_granularity.py
Original file line number Diff line number Diff line change
Expand Up @@ -741,3 +741,27 @@ def test_multiple_time_spines_in_query_for_cumulative_metric( # noqa: D103
dataflow_plan_builder=dataflow_plan_builder,
query_spec=query_spec,
)


@pytest.mark.sql_engine_snapshot
def test_custom_offset_window_with_multiple_time_spines( # noqa: D103
request: FixtureRequest,
mf_test_configuration: MetricFlowTestConfiguration,
dataflow_plan_builder: DataflowPlanBuilder,
dataflow_to_sql_converter: DataflowToSqlPlanConverter,
sql_client: SqlClient,
query_parser: MetricFlowQueryParser,
) -> None:
query_spec = query_parser.parse_and_validate_query(
metric_names=("archived_users_offset_3_martian_days",),
group_by_names=("metric_time__hour",),
).query_spec

render_and_check(
request=request,
mf_test_configuration=mf_test_configuration,
dataflow_to_sql_converter=dataflow_to_sql_converter,
sql_client=sql_client,
dataflow_plan_builder=dataflow_plan_builder,
query_spec=query_spec,
)

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
test_name: test_custom_offset_window_with_multiple_time_spines
test_filename: test_custom_granularity.py
sql_engine: DuckDB
---
-- Compute Metrics via Expressions
SELECT
metric_time__hour
, archived_users AS archived_users_offset_3_martian_days
FROM (
-- Join to Time Spine Dataset
-- Pass Only Elements: ['archived_users', 'metric_time__hour']
-- Aggregate Measures
-- Compute Metrics via Expressions
SELECT
subq_29.ts__hour__lead AS metric_time__hour
, SUM(subq_24.archived_users) AS archived_users
FROM (
-- Offset Base Granularity By Custom Granularity Period(s)
WITH cte_6 AS (
-- Get Custom Granularity Bounds
SELECT
time_spine_src_28005.ts AS ts__hour
, time_spine_src_28006.martian_day AS ds__martian_day
, FIRST_VALUE(time_spine_src_28005.ts) OVER (
PARTITION BY time_spine_src_28006.martian_day
ORDER BY time_spine_src_28005.ts
ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
) AS ts__hour__first_value
, LAST_VALUE(time_spine_src_28005.ts) OVER (
PARTITION BY time_spine_src_28006.martian_day
ORDER BY time_spine_src_28005.ts
ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
) AS ts__hour__last_value
, ROW_NUMBER() OVER (
PARTITION BY time_spine_src_28006.martian_day
ORDER BY time_spine_src_28005.ts
) AS ts__hour__row_number
FROM ***************************.mf_time_spine time_spine_src_28006
INNER JOIN
***************************.mf_time_spine_hour time_spine_src_28005
ON
time_spine_src_28006.ds = DATE_TRUNC('day', time_spine_src_28005.ts)
)

SELECT
cte_6.ts__hour AS ts__hour
, CASE
WHEN subq_28.ts__hour__first_value__lead + INTERVAL (cte_6.ts__hour__row_number - 1) hour <= subq_28.ts__hour__last_value__lead
THEN subq_28.ts__hour__first_value__lead + INTERVAL (cte_6.ts__hour__row_number - 1) hour
ELSE NULL
END AS ts__hour__lead
FROM cte_6 cte_6
INNER JOIN (
-- Offset Custom Granularity Bounds
SELECT
ds__martian_day
, LEAD(ts__hour__first_value, 3) OVER (ORDER BY ds__martian_day) AS ts__hour__first_value__lead
, LEAD(ts__hour__last_value, 3) OVER (ORDER BY ds__martian_day) AS ts__hour__last_value__lead
FROM (
-- Get Unique Rows for Custom Granularity Bounds
SELECT
ds__martian_day
, ts__hour__first_value
, ts__hour__last_value
FROM cte_6 cte_6
GROUP BY
ds__martian_day
, ts__hour__first_value
, ts__hour__last_value
) subq_27
) subq_28
ON
cte_6.ds__martian_day = subq_28.ds__martian_day
) subq_29
INNER JOIN (
-- Read Elements From Semantic Model 'users_ds_source'
-- Metric Time Dimension 'archived_at'
SELECT
DATE_TRUNC('hour', archived_at) AS metric_time__hour
, 1 AS archived_users
FROM ***************************.dim_users users_ds_source_src_28000
) subq_24
ON
subq_29.ts__hour = subq_24.metric_time__hour
GROUP BY
subq_29.ts__hour__lead
) subq_35
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
test_name: test_offset_by_custom_granularity_node_with_smaller_grain
test_filename: test_dataflow_to_sql_plan.py
sql_engine: DuckDB
---
-- Apply Requested Granularities
SELECT
subq_4.ts__hour
, subq_4.ts__hour__lead AS metric_time__hour
FROM (
-- Offset Base Granularity By Custom Granularity Period(s)
WITH cte_0 AS (
-- Get Custom Granularity Bounds
SELECT
subq_1.ts__hour AS ts__hour
, subq_0.ds__martian_day AS ds__martian_day
, FIRST_VALUE(subq_1.ts__hour) OVER (
PARTITION BY subq_0.ds__martian_day
ORDER BY subq_1.ts__hour
ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
) AS ts__hour__first_value
, LAST_VALUE(subq_1.ts__hour) OVER (
PARTITION BY subq_0.ds__martian_day
ORDER BY subq_1.ts__hour
ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
) AS ts__hour__last_value
, ROW_NUMBER() OVER (
PARTITION BY subq_0.ds__martian_day
ORDER BY subq_1.ts__hour
) AS ts__hour__row_number
FROM (
-- Read From Time Spine 'mf_time_spine'
SELECT
time_spine_src_28006.ds AS ds__day
, DATE_TRUNC('week', time_spine_src_28006.ds) AS ds__week
, DATE_TRUNC('month', time_spine_src_28006.ds) AS ds__month
, DATE_TRUNC('quarter', time_spine_src_28006.ds) AS ds__quarter
, DATE_TRUNC('year', time_spine_src_28006.ds) AS ds__year
, EXTRACT(year FROM time_spine_src_28006.ds) AS ds__extract_year
, EXTRACT(quarter FROM time_spine_src_28006.ds) AS ds__extract_quarter
, EXTRACT(month FROM time_spine_src_28006.ds) AS ds__extract_month
, EXTRACT(day FROM time_spine_src_28006.ds) AS ds__extract_day
, EXTRACT(isodow FROM time_spine_src_28006.ds) AS ds__extract_dow
, EXTRACT(doy FROM time_spine_src_28006.ds) AS ds__extract_doy
, time_spine_src_28006.martian_day AS ds__martian_day
FROM ***************************.mf_time_spine time_spine_src_28006
) subq_0
INNER JOIN (
-- Read From Time Spine 'mf_time_spine_hour'
SELECT
time_spine_src_28005.ts AS ts__hour
, DATE_TRUNC('day', time_spine_src_28005.ts) AS ts__day
, DATE_TRUNC('week', time_spine_src_28005.ts) AS ts__week
, DATE_TRUNC('month', time_spine_src_28005.ts) AS ts__month
, DATE_TRUNC('quarter', time_spine_src_28005.ts) AS ts__quarter
, DATE_TRUNC('year', time_spine_src_28005.ts) AS ts__year
, EXTRACT(year FROM time_spine_src_28005.ts) AS ts__extract_year
, EXTRACT(quarter FROM time_spine_src_28005.ts) AS ts__extract_quarter
, EXTRACT(month FROM time_spine_src_28005.ts) AS ts__extract_month
, EXTRACT(day FROM time_spine_src_28005.ts) AS ts__extract_day
, EXTRACT(isodow FROM time_spine_src_28005.ts) AS ts__extract_dow
, EXTRACT(doy FROM time_spine_src_28005.ts) AS ts__extract_doy
FROM ***************************.mf_time_spine_hour time_spine_src_28005
) subq_1
ON
subq_0.ds__day = subq_1.ts__day
)

SELECT
cte_0.ts__hour AS ts__hour
, CASE
WHEN subq_3.ts__hour__first_value__lead + INTERVAL (cte_0.ts__hour__row_number - 1) hour <= subq_3.ts__hour__last_value__lead
THEN subq_3.ts__hour__first_value__lead + INTERVAL (cte_0.ts__hour__row_number - 1) hour
ELSE NULL
END AS ts__hour__lead
FROM cte_0 cte_0
INNER JOIN (
-- Offset Custom Granularity Bounds
SELECT
subq_2.ds__martian_day
, LEAD(subq_2.ts__hour__first_value, 5) OVER (ORDER BY subq_2.ds__martian_day) AS ts__hour__first_value__lead
, LEAD(subq_2.ts__hour__last_value, 5) OVER (ORDER BY subq_2.ds__martian_day) AS ts__hour__last_value__lead
FROM (
-- Get Unique Rows for Custom Granularity Bounds
SELECT
cte_0.ds__martian_day
, cte_0.ts__hour__first_value
, cte_0.ts__hour__last_value
FROM cte_0 cte_0
GROUP BY
cte_0.ds__martian_day
, cte_0.ts__hour__first_value
, cte_0.ts__hour__last_value
) subq_2
) subq_3
ON
cte_0.ds__martian_day = subq_3.ds__martian_day
) subq_4
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
test_name: test_offset_by_custom_granularity_node_with_smaller_grain
test_filename: test_dataflow_to_sql_plan.py
sql_engine: DuckDB
---
-- Apply Requested Granularities
SELECT
ts__hour
, ts__hour__lead AS metric_time__hour
FROM (
-- Offset Base Granularity By Custom Granularity Period(s)
WITH cte_2 AS (
-- Get Custom Granularity Bounds
SELECT
time_spine_src_28005.ts AS ts__hour
, time_spine_src_28006.martian_day AS ds__martian_day
, FIRST_VALUE(time_spine_src_28005.ts) OVER (
PARTITION BY time_spine_src_28006.martian_day
ORDER BY time_spine_src_28005.ts
ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
) AS ts__hour__first_value
, LAST_VALUE(time_spine_src_28005.ts) OVER (
PARTITION BY time_spine_src_28006.martian_day
ORDER BY time_spine_src_28005.ts
ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
) AS ts__hour__last_value
, ROW_NUMBER() OVER (
PARTITION BY time_spine_src_28006.martian_day
ORDER BY time_spine_src_28005.ts
) AS ts__hour__row_number
FROM ***************************.mf_time_spine time_spine_src_28006
INNER JOIN
***************************.mf_time_spine_hour time_spine_src_28005
ON
time_spine_src_28006.ds = DATE_TRUNC('day', time_spine_src_28005.ts)
)

SELECT
cte_2.ts__hour AS ts__hour
, CASE
WHEN subq_8.ts__hour__first_value__lead + INTERVAL (cte_2.ts__hour__row_number - 1) hour <= subq_8.ts__hour__last_value__lead
THEN subq_8.ts__hour__first_value__lead + INTERVAL (cte_2.ts__hour__row_number - 1) hour
ELSE NULL
END AS ts__hour__lead
FROM cte_2 cte_2
INNER JOIN (
-- Offset Custom Granularity Bounds
SELECT
ds__martian_day
, LEAD(ts__hour__first_value, 5) OVER (ORDER BY ds__martian_day) AS ts__hour__first_value__lead
, LEAD(ts__hour__last_value, 5) OVER (ORDER BY ds__martian_day) AS ts__hour__last_value__lead
FROM (
-- Get Unique Rows for Custom Granularity Bounds
SELECT
ds__martian_day
, ts__hour__first_value
, ts__hour__last_value
FROM cte_2 cte_2
GROUP BY
ds__martian_day
, ts__hour__first_value
, ts__hour__last_value
) subq_7
) subq_8
ON
cte_2.ds__martian_day = subq_8.ds__martian_day
) subq_9
Loading

0 comments on commit e188894

Please sign in to comment.