Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,7 @@ def _get_measures_for_metric(
) -> Set[PydanticMetricInputMeasure]:
"""Returns a unique set of input measures for a given metric."""
measures: Set = set()
matched_metric = next(
iter((metric for metric in semantic_manifest.metrics if metric.name == metric_name)), None
)
matched_metric = next((metric for metric in semantic_manifest.metrics if metric.name == metric_name), None)
if matched_metric:
if matched_metric.type is MetricType.SIMPLE or matched_metric.type is MetricType.CUMULATIVE:
if matched_metric.type_params.measure is not None:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from dbt_semantic_interfaces.implementations.elements.measure import PydanticMeasure
from dbt_semantic_interfaces.implementations.metric import (
PydanticMetric,
PydanticMetricInputMeasure,
PydanticMetricTypeParams,
)
from dbt_semantic_interfaces.implementations.semantic_manifest import (
Expand Down Expand Up @@ -65,12 +66,29 @@ def _find_metric_clone_in_manifest(
but let's not prematurely optimize.
"""
search_metric = metric.copy(deep=True)
original_input_measures = search_metric.type_params.input_measures
original_measure = search_metric.type_params.measure
for existing_metric in manifest.metrics:
# this allows us to a straight equality comparison, which is safer in the future
# than implementing a custom comparison function.
search_metric.name = existing_metric.name
search_metric.description = existing_metric.description
search_metric.label = existing_metric.label
search_metric.metadata = existing_metric.metadata
search_metric.type_params.is_private = existing_metric.type_params.is_private
search_metric.config = existing_metric.config
# this is used for compatibility between new and old style metrics; we need to
# match if the search input measures are empty (new-style) or if they match
# the old-style input measures.
if len(existing_metric.type_params.input_measures) == 0:
search_metric.type_params.input_measures = []
else:
search_metric.type_params.input_measures = original_input_measures
if existing_metric.type_params.measure is None:
search_metric.type_params.measure = None
else:
search_metric.type_params.measure = original_measure

if search_metric == existing_metric:
return existing_metric
print("provided metric", search_metric)
Expand Down Expand Up @@ -177,6 +195,10 @@ def get_or_create_metric_for_measure(
fill_nulls_with=fill_nulls_with,
join_to_timespine=join_to_timespine,
)
# supporting legacy cases. Remove when we can remove input measures.
built_metric.type_params.measure = PydanticMetricInputMeasure(name=measure.name)
built_metric.type_params.input_measures = [PydanticMetricInputMeasure(name=measure.name)]

metric = self._find_metric_clone_in_manifest(
metric=built_metric,
manifest=manifest,
Expand All @@ -193,6 +215,9 @@ def get_or_create_metric_for_measure(
)
metric = built_metric
metric.name = metric_name
# TODO: remove this line when MF can support no-measure metrics
metric.type_params.measure = PydanticMetricInputMeasure(name=measure.name)
metric.type_params.input_measures.append(metric.type_params.measure)
manifest.metrics.append(metric)
existing_metric_names.add(metric_name)

Expand Down
1 change: 1 addition & 0 deletions dbt_semantic_interfaces/transformations/proxy_measure.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ def transform_model(semantic_manifest: PydanticSemanticManifest) -> PydanticSema
)
metric.name = measure.name
metric.type_params.measure = PydanticMetricInputMeasure(name=measure.name)
# metric.type_params.input_measures.append(metric.type_params.measure)
semantic_manifest.metrics.append(metric)

return semantic_manifest
13 changes: 7 additions & 6 deletions tests/parsing/test_metric_parsing_with_custom_grain.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ def test_cumulative_metric_with_custom_grain_to_date() -> None: # noqa: D
type_params:
measure:
name: bookings
fill_nulls_with: 15
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

de-duplicating cut the number of metrics down by 1, but I wanted to make sure we had variety in our tests so I made this one require a new metric.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what a silly metric!

cumulative_type_params:
grain_to_date: martian_week
"""
Expand Down Expand Up @@ -121,9 +122,9 @@ def test_cumulative_metric_with_custom_window() -> None: # noqa: D
)
assert not model.issues.has_blocking_issues
semantic_manifest = model.semantic_manifest
# 2 explicit ones and one that is created for the measure input for the
# cumulative metric's params
assert len(semantic_manifest.metrics) == 3
# 2 explicit metrics. The cumulative metric's input metric should be deduplicated
# so it will match.
assert len(semantic_manifest.metrics) == 2

metric = next((m for m in semantic_manifest.metrics if m.name == "test_cumulative_metric_with_custom_window"), None)
assert metric is not None, "Can't find metric"
Expand Down Expand Up @@ -185,9 +186,9 @@ def test_conversion_metric_with_custom_grain_window() -> None: # noqa: D
)
assert not model.issues.has_blocking_issues
semantic_manifest = model.semantic_manifest
# 2 explicit ones and one that is created for the measure input for the
# cumulative metric's params
assert len(semantic_manifest.metrics) == 3
# 2 explicitly created metrics. The conversion measure -> metric transformation
# should not need to create a new metric since the existing one already matches.
assert len(semantic_manifest.metrics) == 2

metric = next(
(m for m in semantic_manifest.metrics if m.name == "test_conversion_metric_with_custom_grain_window"), None
Expand Down
Loading