diff --git a/metricflow-semantics/metricflow_semantics/model/semantics/metric_lookup.py b/metricflow-semantics/metricflow_semantics/model/semantics/metric_lookup.py index b46be1214a..2cd88a1ba7 100644 --- a/metricflow-semantics/metricflow_semantics/model/semantics/metric_lookup.py +++ b/metricflow-semantics/metricflow_semantics/model/semantics/metric_lookup.py @@ -188,7 +188,7 @@ def get_valid_agg_time_dimensions_for_metric( ) return valid_agg_time_dimension_specs - def get_min_queryable_time_granularity(self, metric_reference: MetricReference) -> TimeGranularity: + def get_min_queryable_base_time_granularity(self, metric_reference: MetricReference) -> TimeGranularity: """The minimum grain that can be queried with this metric. Maps to the largest granularity defined for any of the metric's agg_time_dimensions. diff --git a/metricflow-semantics/metricflow_semantics/query/group_by_item/candidate_push_down/push_down_visitor.py b/metricflow-semantics/metricflow_semantics/query/group_by_item/candidate_push_down/push_down_visitor.py index 5f5b691146..a9ff3229dd 100644 --- a/metricflow-semantics/metricflow_semantics/query/group_by_item/candidate_push_down/push_down_visitor.py +++ b/metricflow-semantics/metricflow_semantics/query/group_by_item/candidate_push_down/push_down_visitor.py @@ -394,7 +394,7 @@ def visit_metric_node(self, node: MetricGroupByItemResolutionNode) -> PushDownRe # Note: ignores any granularity set on input metrics. metric_default_time_granularity = metric_to_use_for_time_granularity_resolution.time_granularity or max( TimeGranularity.DAY, - self._semantic_manifest_lookup.metric_lookup.get_min_queryable_time_granularity( + self._semantic_manifest_lookup.metric_lookup.get_min_queryable_base_time_granularity( MetricReference(metric_to_use_for_time_granularity_resolution.name) ), ) diff --git a/metricflow/dataflow/builder/dataflow_plan_builder.py b/metricflow/dataflow/builder/dataflow_plan_builder.py index edbe4e0fce..22b2903134 100644 --- a/metricflow/dataflow/builder/dataflow_plan_builder.py +++ b/metricflow/dataflow/builder/dataflow_plan_builder.py @@ -443,7 +443,7 @@ def _build_cumulative_metric_output_node( ) -> DataflowPlanNode: # TODO: [custom granularity] Figure out how to support custom granularities as defaults default_granularity = ExpandedTimeGranularity.from_time_granularity( - self._metric_lookup.get_min_queryable_time_granularity(metric_spec.reference) + self._metric_lookup.get_min_queryable_base_time_granularity(metric_spec.reference) ) queried_agg_time_dimensions = queried_linkable_specs.included_agg_time_dimension_specs_for_metric( @@ -1562,12 +1562,12 @@ def _build_aggregated_measure_from_measure_source_node( non_additive_dimension_grain = self._semantic_model_lookup.get_defined_time_granularity( TimeDimensionReference(non_additive_dimension_spec.name) ) - queried_time_dimension_spec: Optional[ - TimeDimensionSpec - ] = self._find_non_additive_dimension_in_linkable_specs( - agg_time_dimension=agg_time_dimension, - linkable_specs=queried_linkable_specs.as_tuple, - non_additive_dimension_spec=non_additive_dimension_spec, + queried_time_dimension_spec: Optional[TimeDimensionSpec] = ( + self._find_non_additive_dimension_in_linkable_specs( + agg_time_dimension=agg_time_dimension, + linkable_specs=queried_linkable_specs.as_tuple, + non_additive_dimension_spec=non_additive_dimension_spec, + ) ) time_dimension_spec = TimeDimensionSpec( # The NonAdditiveDimensionSpec name property is a plain element name diff --git a/metricflow/engine/metricflow_engine.py b/metricflow/engine/metricflow_engine.py index 2b25a79b8b..32946454a4 100644 --- a/metricflow/engine/metricflow_engine.py +++ b/metricflow/engine/metricflow_engine.py @@ -9,7 +9,12 @@ from dbt_semantic_interfaces.implementations.elements.dimension import PydanticDimensionTypeParams from dbt_semantic_interfaces.implementations.filters.where_filter import PydanticWhereFilter -from dbt_semantic_interfaces.references import EntityReference, MeasureReference, MetricReference +from dbt_semantic_interfaces.references import ( + EntityReference, + MeasureReference, + MetricReference, + TimeDimensionReference, +) from dbt_semantic_interfaces.type_enums import DimensionType from metricflow_semantics.dag.sequential_id import SequentialIdGenerator from metricflow_semantics.errors.error_classes import ExecutionException @@ -33,6 +38,7 @@ from metricflow_semantics.sql.sql_table import SqlTable from metricflow_semantics.time.time_source import TimeSource from metricflow_semantics.time.time_spine_source import TimeSpineSource +from dbt_semantic_interfaces.type_enums.time_granularity import TimeGranularity from metricflow.data_table.mf_table import MetricFlowDataTable from metricflow.dataflow.builder.dataflow_plan_builder import DataflowPlanBuilder @@ -552,6 +558,28 @@ def get_measures_for_metrics(self, metric_names: List[str]) -> List[Measure]: # ) return list(measures) + def get_min_queryable_base_granularity_for_metrics( + self, metric_references: Sequence[MetricReference] + ) -> Optional[TimeGranularity]: + """Get the minimum queryable standard granularity that can be queried with all selected metrics.""" + min_granularity_per_metric = { + self._semantic_manifest_lookup.metric_lookup.get_min_queryable_base_time_granularity(metric_reference) + for metric_reference in metric_references + } + # TODO: test that MAX works on enum values + return max(min_granularity_per_metric) if min_granularity_per_metric else None + + def get_min_queryable_base_granularity_for_dimensions( + self, time_dimension_references: Sequence[TimeDimensionReference] + ) -> Optional[TimeGranularity]: + """Get the minimum queryable standard granularity that can be queried with all selected time dimensions.""" + min_granularity_per_dimension = { + self._semantic_manifest_lookup.semantic_model_lookup.get_defined_time_granularity(time_dimension_reference) + for time_dimension_reference in time_dimension_references + } + # TODO: test that MAX works on enum values + return max(min_granularity_per_metric) if min_granularity_per_metric else None + def simple_dimensions_for_metrics( # noqa: D102 self, metric_names: List[str],