2828from dbt .artifacts .resources import (
2929 CatalogWriteIntegrationConfig ,
3030 FileHash ,
31+ MetricInput ,
3132 NodeRelation ,
3233 NodeVersion ,
3334)
@@ -1930,14 +1931,14 @@ def _process_refs(
19301931 node .depends_on .add_node (target_model_id )
19311932
19321933
1933- def _process_metric_depends_on (
1934+ def _process_metric_depends_on_semantic_models_for_measures (
19341935 manifest : Manifest ,
19351936 current_project : str ,
19361937 metric : Metric ,
19371938) -> None :
19381939 """For a given metric, set the `depends_on` property"""
19391940
1940- assert len (metric .type_params .input_measures ) > 0
1941+ # assert len(metric.type_params.input_measures) > 0 or metric.type_params.metric_aggregation_params is not None, f"{metric} should have a measure or agg type defined, but it does not."
19411942 for input_measure in metric .type_params .input_measures :
19421943 target_semantic_model = manifest .resolve_semantic_model_for_measure (
19431944 target_measure_name = input_measure .name ,
@@ -1958,6 +1959,39 @@ def _process_metric_depends_on(
19581959 metric .depends_on .add_node (target_semantic_model .unique_id )
19591960
19601961
1962+ def _process_multiple_metric_inputs (
1963+ manifest : Manifest ,
1964+ current_project : str ,
1965+ metric : Metric ,
1966+ metric_inputs : List [MetricInput ],
1967+ ) -> None :
1968+ for input_metric in metric_inputs :
1969+ target_metric = manifest .resolve_metric (
1970+ target_metric_name = input_metric .name ,
1971+ target_metric_package = None ,
1972+ current_project = current_project ,
1973+ node_package = metric .package_name ,
1974+ )
1975+
1976+ if target_metric is None :
1977+ raise dbt .exceptions .ParsingError (
1978+ f"The metric `{ input_metric .name } ` does not exist but was referenced." ,
1979+ node = metric ,
1980+ )
1981+ elif isinstance (target_metric , Disabled ):
1982+ raise dbt .exceptions .ParsingError (
1983+ f"The metric `{ input_metric .name } ` is disabled and thus cannot be referenced." ,
1984+ node = metric ,
1985+ )
1986+
1987+ _process_metric_node (
1988+ manifest = manifest , current_project = current_project , metric = target_metric
1989+ )
1990+ for input_measure in target_metric .type_params .input_measures :
1991+ metric .add_input_measure (input_measure )
1992+ metric .depends_on .add_node (target_metric .unique_id )
1993+
1994+
19611995def _process_metric_node (
19621996 manifest : Manifest ,
19631997 current_project : str ,
@@ -1973,22 +2007,51 @@ def _process_metric_node(
19732007 return
19742008
19752009 if metric .type is MetricType .SIMPLE or metric .type is MetricType .CUMULATIVE :
1976- assert (
1977- metric .type_params .measure is not None
1978- ), f"{ metric } should have a measure defined, but it does not."
1979- metric .add_input_measure (metric .type_params .measure )
1980- _process_metric_depends_on (
1981- manifest = manifest , current_project = current_project , metric = metric
1982- )
2010+ if (
2011+ metric .type_params .measure is None
2012+ and metric .type_params .metric_aggregation_params is None
2013+ ):
2014+ # This should be caught earlier, but just in case, we assert here to avoid
2015+ # any unexpected behaviors.
2016+ raise dbt .exceptions .ParsingError (
2017+ f"Metric { metric } should have a measure or agg type defined, but it does not." ,
2018+ node = metric ,
2019+ )
2020+ if metric .type_params .measure is not None :
2021+ metric .add_input_measure (metric .type_params .measure )
2022+ _process_metric_depends_on_semantic_models_for_measures (
2023+ manifest = manifest , current_project = current_project , metric = metric
2024+ )
2025+ # TODO DI-4415: Once we can process simple metric merged into a model directly,
2026+ # we need to add a 'depends on' for the semantic model
19832027 elif metric .type is MetricType .CONVERSION :
19842028 conversion_type_params = metric .type_params .conversion_type_params
19852029 assert (
19862030 conversion_type_params
19872031 ), f"{ metric .name } is a conversion metric and must have conversion_type_params defined."
1988- metric .add_input_measure (conversion_type_params .base_measure )
1989- metric .add_input_measure (conversion_type_params .conversion_measure )
1990- _process_metric_depends_on (
1991- manifest = manifest , current_project = current_project , metric = metric
2032+ # Handle old-style YAML measure inputs
2033+ if conversion_type_params .base_measure is not None :
2034+ # TODO: add test for base_measure
2035+ metric .add_input_measure (conversion_type_params .base_measure )
2036+ if conversion_type_params .conversion_measure is not None :
2037+ # TODO: add test for conversion_measure
2038+ metric .add_input_measure (conversion_type_params .conversion_measure )
2039+ _process_metric_depends_on_semantic_models_for_measures (
2040+ manifest = manifest ,
2041+ current_project = current_project ,
2042+ metric = metric ,
2043+ )
2044+ # Recursively process input metrics' input measures for blended v2 & old-style YAML inputs
2045+ metric_inputs = []
2046+ if conversion_type_params .base_metric is not None :
2047+ metric_inputs .append (conversion_type_params .base_metric )
2048+ if conversion_type_params .conversion_metric is not None :
2049+ metric_inputs .append (conversion_type_params .conversion_metric )
2050+ _process_multiple_metric_inputs (
2051+ manifest = manifest ,
2052+ current_project = current_project ,
2053+ metric = metric ,
2054+ metric_inputs = metric_inputs ,
19922055 )
19932056 elif metric .type is MetricType .DERIVED or metric .type is MetricType .RATIO :
19942057 input_metrics = metric .input_metrics
@@ -2000,31 +2063,12 @@ def _process_metric_node(
20002063 )
20012064 input_metrics = [metric .type_params .numerator , metric .type_params .denominator ]
20022065
2003- for input_metric in input_metrics :
2004- target_metric = manifest .resolve_metric (
2005- target_metric_name = input_metric .name ,
2006- target_metric_package = None ,
2007- current_project = current_project ,
2008- node_package = metric .package_name ,
2009- )
2010-
2011- if target_metric is None :
2012- raise dbt .exceptions .ParsingError (
2013- f"The metric `{ input_metric .name } ` does not exist but was referenced by metric `{ metric .name } `." ,
2014- node = metric ,
2015- )
2016- elif isinstance (target_metric , Disabled ):
2017- raise dbt .exceptions .ParsingError (
2018- f"The metric `{ input_metric .name } ` is disabled and thus cannot be referenced." ,
2019- node = metric ,
2020- )
2021-
2022- _process_metric_node (
2023- manifest = manifest , current_project = current_project , metric = target_metric
2024- )
2025- for input_measure in target_metric .type_params .input_measures :
2026- metric .add_input_measure (input_measure )
2027- metric .depends_on .add_node (target_metric .unique_id )
2066+ _process_multiple_metric_inputs (
2067+ manifest = manifest ,
2068+ current_project = current_project ,
2069+ metric = metric ,
2070+ metric_inputs = input_metrics ,
2071+ )
20282072 else :
20292073 assert_values_exhausted (metric .type )
20302074
0 commit comments