2828from dbt .artifacts .resources import (
2929 CatalogWriteIntegrationConfig ,
3030 FileHash ,
31+ MetricInput ,
3132 NodeRelation ,
3233 NodeVersion ,
3334)
@@ -1930,14 +1931,17 @@ 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 (
1942+ len (metric .type_params .input_measures ) > 0
1943+ or metric .type_params .metric_aggregation_params is not None
1944+ ), f"{ metric } should have a measure or agg type defined, but it does not."
19411945 for input_measure in metric .type_params .input_measures :
19421946 target_semantic_model = manifest .resolve_semantic_model_for_measure (
19431947 target_measure_name = input_measure .name ,
@@ -1958,6 +1962,39 @@ def _process_metric_depends_on(
19581962 metric .depends_on .add_node (target_semantic_model .unique_id )
19591963
19601964
1965+ def _process_multiple_metric_inputs (
1966+ manifest : Manifest ,
1967+ current_project : str ,
1968+ metric : Metric ,
1969+ metric_inputs : List [MetricInput ],
1970+ ) -> None :
1971+ for input_metric in metric_inputs :
1972+ target_metric = manifest .resolve_metric (
1973+ target_metric_name = input_metric .name ,
1974+ target_metric_package = None ,
1975+ current_project = current_project ,
1976+ node_package = metric .package_name ,
1977+ )
1978+
1979+ if target_metric is None :
1980+ raise dbt .exceptions .ParsingError (
1981+ f"The metric `{ input_metric .name } ` does not exist but was referenced." ,
1982+ node = metric ,
1983+ )
1984+ elif isinstance (target_metric , Disabled ):
1985+ raise dbt .exceptions .ParsingError (
1986+ f"The metric `{ input_metric .name } ` is disabled and thus cannot be referenced." ,
1987+ node = metric ,
1988+ )
1989+
1990+ _process_metric_node (
1991+ manifest = manifest , current_project = current_project , metric = target_metric
1992+ )
1993+ for input_measure in target_metric .type_params .input_measures :
1994+ metric .add_input_measure (input_measure )
1995+ metric .depends_on .add_node (target_metric .unique_id )
1996+
1997+
19611998def _process_metric_node (
19621999 manifest : Manifest ,
19632000 current_project : str ,
@@ -1973,23 +2010,40 @@ def _process_metric_node(
19732010 return
19742011
19752012 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- )
2013+ if (
2014+ metric .type_params .measure is None
2015+ and metric .type_params .metric_aggregation_params is None
2016+ ):
2017+ # This should be caught earlier, but just in case, we assert here to avoid
2018+ # any unexpected behaviors.
2019+ raise dbt .exceptions .ParsingError (
2020+ f"Metric { metric } should have a measure or agg type defined, but it does not." ,
2021+ node = metric ,
2022+ )
2023+ if metric .type_params .measure is not None :
2024+ metric .add_input_measure (metric .type_params .measure )
2025+ _process_metric_depends_on_semantic_models_for_measures (
2026+ manifest = manifest , current_project = current_project , metric = metric
2027+ )
2028+ # TODO DI-4415: Once we can process simple metric merged into a model directly,
2029+ # we need to add a 'depends on' for the semantic model
19832030 elif metric .type is MetricType .CONVERSION :
19842031 conversion_type_params = metric .type_params .conversion_type_params
19852032 assert (
19862033 conversion_type_params
19872034 ), 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
2035+ # Handle old-style YAML measure inputs
2036+ if conversion_type_params .base_measure is not None :
2037+ metric .add_input_measure (conversion_type_params .base_measure )
2038+ if conversion_type_params .conversion_measure is not None :
2039+ metric .add_input_measure (conversion_type_params .conversion_measure )
2040+ _process_metric_depends_on_semantic_models_for_measures (
2041+ manifest = manifest ,
2042+ current_project = current_project ,
2043+ metric = metric ,
19922044 )
2045+ # If we ever want to enable blended v1 and v2 manifests, we'll need to recurse through
2046+ # metric inputs here to find their measure inputs.
19932047 elif metric .type is MetricType .DERIVED or metric .type is MetricType .RATIO :
19942048 input_metrics = metric .input_metrics
19952049 if metric .type is MetricType .RATIO :
@@ -2007,7 +2061,6 @@ def _process_metric_node(
20072061 current_project = current_project ,
20082062 node_package = metric .package_name ,
20092063 )
2010-
20112064 if target_metric is None :
20122065 raise dbt .exceptions .ParsingError (
20132066 f"The metric `{ input_metric .name } ` does not exist but was referenced by metric `{ metric .name } `." ,
@@ -2018,7 +2071,6 @@ def _process_metric_node(
20182071 f"The metric `{ input_metric .name } ` is disabled and thus cannot be referenced." ,
20192072 node = metric ,
20202073 )
2021-
20222074 _process_metric_node (
20232075 manifest = manifest , current_project = current_project , metric = target_metric
20242076 )
0 commit comments