diff --git a/core/dbt/parser/manifest.py b/core/dbt/parser/manifest.py index fd94d34b098..3251be82928 100644 --- a/core/dbt/parser/manifest.py +++ b/core/dbt/parser/manifest.py @@ -1527,43 +1527,66 @@ def _process_refs( node.depends_on.add_node(target_model_id) -def _process_metric_node( +def _process_metric_depends_on( manifest: Manifest, current_project: str, metric: Metric, ) -> None: - """Sets a metric's `input_measures` and `depends_on` properties""" - - # This ensures that if this metrics input_measures have already been set - # we skip the work. This could happen either due to recursion or if multiple - # metrics derive from another given metric. - # NOTE: This does not protect against infinite loops - if len(metric.type_params.input_measures) > 0: - return + """For a given metric, set the `depends_on` property""" - if metric.type is MetricType.SIMPLE or metric.type is MetricType.CUMULATIVE: - assert ( - metric.type_params.measure is not None - ), f"{metric} should have a measure defined, but it does not." - metric.type_params.input_measures.append(metric.type_params.measure) + assert len(metric.type_params.input_measures) > 0 + for input_measure in metric.type_params.input_measures: target_semantic_model = manifest.resolve_semantic_model_for_measure( - target_measure_name=metric.type_params.measure.name, + target_measure_name=input_measure.name, current_project=current_project, node_package=metric.package_name, ) if target_semantic_model is None: raise dbt.exceptions.ParsingError( - f"A semantic model having a measure `{metric.type_params.measure.name}` does not exist but was referenced.", + f"A semantic model having a measure `{input_measure.name}` does not exist but was referenced.", node=metric, ) if target_semantic_model.config.enabled is False: raise dbt.exceptions.ParsingError( - f"The measure `{metric.type_params.measure.name}` is referenced on disabled semantic model `{target_semantic_model.name}`.", + f"The measure `{input_measure.name}` is referenced on disabled semantic model `{target_semantic_model.name}`.", node=metric, ) metric.depends_on.add_node(target_semantic_model.unique_id) + +def _process_metric_node( + manifest: Manifest, + current_project: str, + metric: Metric, +) -> None: + """Sets a metric's `input_measures` and `depends_on` properties""" + + # This ensures that if this metrics input_measures have already been set + # we skip the work. This could happen either due to recursion or if multiple + # metrics derive from another given metric. + # NOTE: This does not protect against infinite loops + if len(metric.type_params.input_measures) > 0: + return + + if metric.type is MetricType.SIMPLE or metric.type is MetricType.CUMULATIVE: + assert ( + metric.type_params.measure is not None + ), f"{metric} should have a measure defined, but it does not." + metric.type_params.input_measures.append(metric.type_params.measure) + _process_metric_depends_on( + manifest=manifest, current_project=current_project, metric=metric + ) + elif metric.type is MetricType.CONVERSION: + conversion_type_params = metric.type_params.conversion_type_params + assert ( + conversion_type_params + ), f"{metric.name} is a conversion metric and must have conversion_type_params defined." + metric.type_params.input_measures.append(conversion_type_params.base_measure) + metric.type_params.input_measures.append(conversion_type_params.conversion_measure) + _process_metric_depends_on( + manifest=manifest, current_project=current_project, metric=metric + ) elif metric.type is MetricType.DERIVED or metric.type is MetricType.RATIO: input_metrics = metric.input_metrics if metric.type is MetricType.RATIO: