From 7e65636c9de62d0ea51b88122c5497d29bb33d8c Mon Sep 17 00:00:00 2001 From: Courtney Holcomb Date: Wed, 3 Jul 2024 08:20:20 -0700 Subject: [PATCH] Set `default_granularity` properly for nested metrics (#304) ### Description Previously, this transformation was not setting default granularity properly for metrics with input metrics (i.e., derived & ratio metrics). This is because `Metric.measure_references` only gets the top-level measures, not nested measures from input metrics. This PR fixes that bug by utilizing `PydanticMetric.all_input_measures_for_metric()` instead. Note that this feature (`default_granularity`) has not been released yet so no customers should be impacted by this bug. ### Checklist - [x] I have read [the contributing guide](https://github.com/dbt-labs/dbt-semantic-interfaces/blob/main/CONTRIBUTING.md) and understand what's expected of me - [x] I have signed the [CLA](https://docs.getdbt.com/docs/contributor-license-agreements) - [x] This PR includes tests, or tests are not required/relevant for this PR - [ ] I have run `changie new` to [create a changelog entry](https://github.com/dbt-labs/dbt-semantic-interfaces/blob/main/CONTRIBUTING.md#adding-a-changelog-entry) --- .../transformations/default_granularity.py | 14 +++++++-- pyproject.toml | 2 +- .../simple_semantic_manifest/metrics.yaml | 29 +++++++++++++++++++ .../semantic_models/bookings_source.yaml | 19 +++++++++++- .../test_configurable_transform_rules.py | 2 ++ 5 files changed, 62 insertions(+), 4 deletions(-) diff --git a/dbt_semantic_interfaces/transformations/default_granularity.py b/dbt_semantic_interfaces/transformations/default_granularity.py index 92a4de9c..5e712eef 100644 --- a/dbt_semantic_interfaces/transformations/default_granularity.py +++ b/dbt_semantic_interfaces/transformations/default_granularity.py @@ -1,13 +1,16 @@ -from typing import Set +from typing import Dict, Set from typing_extensions import override +from dbt_semantic_interfaces.implementations.metric import PydanticMetric from dbt_semantic_interfaces.implementations.semantic_manifest import ( PydanticSemanticManifest, ) from dbt_semantic_interfaces.protocols import ProtocolHint +from dbt_semantic_interfaces.protocols.metric import Metric from dbt_semantic_interfaces.references import ( DimensionReference, + MetricReference, TimeDimensionReference, ) from dbt_semantic_interfaces.transformations.transform_rule import ( @@ -32,8 +35,15 @@ def transform_model(semantic_manifest: PydanticSemanticManifest) -> PydanticSema default_granularity = TimeGranularity.DAY seen_agg_time_dimensions: Set[TimeDimensionReference] = set() + + metric_index: Dict[MetricReference, Metric] = { + MetricReference(metric.name): metric for metric in semantic_manifest.metrics + } + for semantic_model in semantic_manifest.semantic_models: - for measure_ref in set(metric.measure_references).intersection(semantic_model.measure_references): + for measure_ref in set( + PydanticMetric.all_input_measures_for_metric(metric=metric, metric_index=metric_index) + ).intersection(semantic_model.measure_references): try: agg_time_dimension_ref = semantic_model.checked_agg_time_dimension_for_measure(measure_ref) except AssertionError: diff --git a/pyproject.toml b/pyproject.toml index 274356e4..8918e3ca 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "dbt-semantic-interfaces" -version = "0.6.2" +version = "0.6.3" description = 'The shared semantic layer definitions that dbt-core and MetricFlow use' readme = "README.md" requires-python = ">=3.8" diff --git a/tests/fixtures/semantic_manifest_yamls/simple_semantic_manifest/metrics.yaml b/tests/fixtures/semantic_manifest_yamls/simple_semantic_manifest/metrics.yaml index 0d8eea31..d2b92628 100644 --- a/tests/fixtures/semantic_manifest_yamls/simple_semantic_manifest/metrics.yaml +++ b/tests/fixtures/semantic_manifest_yamls/simple_semantic_manifest/metrics.yaml @@ -559,3 +559,32 @@ metric: measure: name: listings filter: "{{ Metric('bookings', group_by=['listing', 'metric_time']) }} > 2" +--- +metric: + name: monthly_bookings + description: bookings by month + label: bookings by month + type: simple + type_params: + measure: + name: monthly_bookings +--- +metric: + name: yearly_bookings + description: bookings by year + label: bookings by year + type: simple + type_params: + measure: + name: yearly_bookings +--- +metric: + name: monthly_times_yearly_bookings + description: monthly times yearly bookings + label: monthly times yearly bookings + type: derived + type_params: + expr: monthly_bookings * yearly_bookings + metrics: + - name: monthly_bookings + - name: yearly_bookings diff --git a/tests/fixtures/semantic_manifest_yamls/simple_semantic_manifest/semantic_models/bookings_source.yaml b/tests/fixtures/semantic_manifest_yamls/simple_semantic_manifest/semantic_models/bookings_source.yaml index b53ee36d..fb263f7c 100644 --- a/tests/fixtures/semantic_manifest_yamls/simple_semantic_manifest/semantic_models/bookings_source.yaml +++ b/tests/fixtures/semantic_manifest_yamls/simple_semantic_manifest/semantic_models/bookings_source.yaml @@ -65,7 +65,14 @@ semantic_model: percentile: 0.99 use_discrete_percentile: true use_approximate_percentile: true - + - name: monthly_bookings + expr: "1" + agg: sum + agg_time_dimension: ds_monthly + - name: yearly_bookings + expr: "1" + agg: sum + agg_time_dimension: ds_yearly dimensions: - name: is_instant @@ -83,6 +90,16 @@ semantic_model: type: time type_params: time_granularity: day + - name: ds_monthly + type: time + expr: ds + type_params: + time_granularity: month + - name: ds_yearly + type: time + expr: ds + type_params: + time_granularity: year primary_entity: booking diff --git a/tests/transformations/test_configurable_transform_rules.py b/tests/transformations/test_configurable_transform_rules.py index bdd5fefc..c60f5dba 100644 --- a/tests/transformations/test_configurable_transform_rules.py +++ b/tests/transformations/test_configurable_transform_rules.py @@ -65,3 +65,5 @@ def test_set_default_granularity_rule( # noqa: D assert ( metric.default_granularity == configured_default_granularities[metric.name] ), f"Default granularity was unexpected changed during transformation for metric '{metric.name}" + if metric.name == "monthly_times_yearly_bookings": + assert metric.default_granularity == TimeGranularity.YEAR