diff --git a/metricflow-semantics/metricflow_semantics/specs/measure_spec.py b/metricflow-semantics/metricflow_semantics/specs/measure_spec.py index 886e8ed3af..0262d72685 100644 --- a/metricflow-semantics/metricflow_semantics/specs/measure_spec.py +++ b/metricflow-semantics/metricflow_semantics/specs/measure_spec.py @@ -1,7 +1,7 @@ from __future__ import annotations from dataclasses import dataclass -from typing import Optional, Tuple +from typing import Optional from dbt_semantic_interfaces.dataclass_serialization import SerializableDataclass from dbt_semantic_interfaces.protocols import MetricTimeWindow @@ -10,7 +10,7 @@ from metricflow_semantics.specs.instance_spec import InstanceSpec, InstanceSpecVisitor from metricflow_semantics.specs.non_additive_dimension_spec import NonAdditiveDimensionSpec -from metricflow_semantics.specs.where_filter.where_filter_spec import WhereFilterSpec +from metricflow_semantics.specs.where_filter.where_filter_spec_set import WhereFilterSpecSet from metricflow_semantics.sql.sql_join_type import SqlJoinType from metricflow_semantics.visitor import VisitorOutputT @@ -62,7 +62,7 @@ class MetricInputMeasureSpec(SerializableDataclass): offset_window: Optional[MetricTimeWindow] = None offset_to_grain: Optional[TimeGranularity] = None cumulative_description: Optional[CumulativeMeasureDescription] = None - filter_specs: Tuple[WhereFilterSpec, ...] = () + filter_spec_set: WhereFilterSpecSet = WhereFilterSpecSet() alias: Optional[str] = None before_aggregation_time_spine_join_description: Optional[JoinToTimeSpineDescription] = None after_aggregation_time_spine_join_description: Optional[JoinToTimeSpineDescription] = None diff --git a/metricflow-semantics/metricflow_semantics/specs/metric_spec.py b/metricflow-semantics/metricflow_semantics/specs/metric_spec.py index cbad46285d..3e0d21a35d 100644 --- a/metricflow-semantics/metricflow_semantics/specs/metric_spec.py +++ b/metricflow-semantics/metricflow_semantics/specs/metric_spec.py @@ -1,14 +1,14 @@ from __future__ import annotations from dataclasses import dataclass -from typing import Optional, Tuple +from typing import Optional from dbt_semantic_interfaces.implementations.metric import PydanticMetricTimeWindow from dbt_semantic_interfaces.references import MetricReference from dbt_semantic_interfaces.type_enums import TimeGranularity from metricflow_semantics.specs.instance_spec import InstanceSpec, InstanceSpecVisitor -from metricflow_semantics.specs.where_filter.where_filter_spec import WhereFilterSpec +from metricflow_semantics.specs.where_filter.where_filter_spec_set import WhereFilterSpecSet from metricflow_semantics.visitor import VisitorOutputT @@ -16,7 +16,7 @@ class MetricSpec(InstanceSpec): # noqa: D101 # Time-over-time could go here element_name: str - filter_specs: Tuple[WhereFilterSpec, ...] = () + filter_spec_set: WhereFilterSpecSet = WhereFilterSpecSet() alias: Optional[str] = None offset_window: Optional[PydanticMetricTimeWindow] = None offset_to_grain: Optional[TimeGranularity] = None @@ -48,4 +48,4 @@ def has_time_offset(self) -> bool: # noqa: D102 def without_offset(self) -> MetricSpec: """Represents the metric spec with any time offsets removed.""" - return MetricSpec(element_name=self.element_name, filter_specs=self.filter_specs, alias=self.alias) + return MetricSpec(element_name=self.element_name, filter_spec_set=self.filter_spec_set, alias=self.alias) diff --git a/metricflow-semantics/metricflow_semantics/specs/where_filter/where_filter_spec_set.py b/metricflow-semantics/metricflow_semantics/specs/where_filter/where_filter_spec_set.py new file mode 100644 index 0000000000..8e039c5344 --- /dev/null +++ b/metricflow-semantics/metricflow_semantics/specs/where_filter/where_filter_spec_set.py @@ -0,0 +1,46 @@ +from __future__ import annotations + +from dataclasses import dataclass +from typing import Tuple + +from dbt_semantic_interfaces.dataclass_serialization import SerializableDataclass + +from metricflow_semantics.specs.where_filter.where_filter_spec import WhereFilterSpec + + +@dataclass(frozen=True) +class WhereFilterSpecSet(SerializableDataclass): + """Class to encapsulate filters needed at a certain point of the queried metric. + + This class splits up the filters based on where it was defined at, which can then be used to + determine where each filter should be applied during each step of the metric building process. + + measure-level: filters defined on the input_measure + metric-level: filters defined on the input_metric or metric:filter + query-level: filters defined at query time + """ + + measure_level_filter_specs: Tuple[WhereFilterSpec, ...] = () + metric_level_filter_specs: Tuple[WhereFilterSpec, ...] = () + query_level_filter_specs: Tuple[WhereFilterSpec, ...] = () + + @property + def after_measure_aggregation_filter_specs(self) -> Tuple[WhereFilterSpec, ...]: + """Returns filters relevant to post-measure aggregation.""" + return self.metric_level_filter_specs + self.query_level_filter_specs + + @property + def all_filter_specs(self) -> Tuple[WhereFilterSpec, ...]: + """Returns all the filters in this class. + + Generally, before measure aggregation, all filters should be applied. + """ + return self.measure_level_filter_specs + self.metric_level_filter_specs + self.query_level_filter_specs + + def merge(self, other: WhereFilterSpecSet) -> WhereFilterSpecSet: + """Merge 2 WhereFilterSpecSet together.""" + return WhereFilterSpecSet( + measure_level_filter_specs=self.measure_level_filter_specs + other.measure_level_filter_specs, + metric_level_filter_specs=self.metric_level_filter_specs + other.metric_level_filter_specs, + query_level_filter_specs=self.query_level_filter_specs + other.query_level_filter_specs, + ) diff --git a/metricflow-semantics/metricflow_semantics/test_helpers/semantic_manifest_yamls/simple_manifest/metrics.yaml b/metricflow-semantics/metricflow_semantics/test_helpers/semantic_manifest_yamls/simple_manifest/metrics.yaml index 6d9116f015..29a3e2f2fb 100644 --- a/metricflow-semantics/metricflow_semantics/test_helpers/semantic_manifest_yamls/simple_manifest/metrics.yaml +++ b/metricflow-semantics/metricflow_semantics/test_helpers/semantic_manifest_yamls/simple_manifest/metrics.yaml @@ -629,6 +629,17 @@ metric: fill_nulls_with: 0 time_granularity: week --- +metric: + name: instant_bookings_with_measure_filter + description: simple metric joining to time spine with measure filter + type: simple + type_params: + measure: + name: bookings + join_to_timespine: true + filter: "{{ Dimension('booking__is_instant') }}" + filter: "{{ Entity('listing') }} IS NOT NULL" +--- metric: name: every_two_days_bookers_fill_nulls_with_0 description: cumulative metric filling 0 diff --git a/metricflow-semantics/tests_metricflow_semantics/snapshots/test_linkable_spec_resolver.py/list/test_linkable_element_set_as_spec_set__set0.txt b/metricflow-semantics/tests_metricflow_semantics/snapshots/test_linkable_spec_resolver.py/list/test_linkable_element_set_as_spec_set__set0.txt index 929d1675b5..f02b3d5335 100644 --- a/metricflow-semantics/tests_metricflow_semantics/snapshots/test_linkable_spec_resolver.py/list/test_linkable_element_set_as_spec_set__set0.txt +++ b/metricflow-semantics/tests_metricflow_semantics/snapshots/test_linkable_spec_resolver.py/list/test_linkable_element_set_as_spec_set__set0.txt @@ -33,6 +33,7 @@ 'listing__booking__listing__instant_booking_value', 'listing__booking__listing__instant_booking_value_ratio', 'listing__booking__listing__instant_bookings', + 'listing__booking__listing__instant_bookings_with_measure_filter', 'listing__booking__listing__instant_lux_booking_value_rate', 'listing__booking__listing__instant_plus_non_referred_bookings_pct', 'listing__booking__listing__lux_booking_fraction_of_max_value', @@ -114,6 +115,7 @@ 'listing__instant_booking_value', 'listing__instant_booking_value_ratio', 'listing__instant_bookings', + 'listing__instant_bookings_with_measure_filter', 'listing__instant_lux_booking_value_rate', 'listing__instant_plus_non_referred_bookings_pct', 'listing__is_lux_latest', @@ -441,6 +443,7 @@ 'user__listing__user__instant_booking_value', 'user__listing__user__instant_booking_value_ratio', 'user__listing__user__instant_bookings', + 'user__listing__user__instant_bookings_with_measure_filter', 'user__listing__user__instant_lux_booking_value_rate', 'user__listing__user__instant_plus_non_referred_bookings_pct', 'user__listing__user__largest_listing', diff --git a/metricflow-semantics/tests_metricflow_semantics/snapshots/test_semantic_model_container.py/str/test_linkable_elements_for_measure__result0.txt b/metricflow-semantics/tests_metricflow_semantics/snapshots/test_semantic_model_container.py/str/test_linkable_elements_for_measure__result0.txt index e9b9f84f35..28f3736b35 100644 --- a/metricflow-semantics/tests_metricflow_semantics/snapshots/test_semantic_model_container.py/str/test_linkable_elements_for_measure__result0.txt +++ b/metricflow-semantics/tests_metricflow_semantics/snapshots/test_semantic_model_container.py/str/test_linkable_elements_for_measure__result0.txt @@ -50,6 +50,7 @@ Model Join-Path Entity Links ('listings_latest',) ("('listing',)", "('booking', 'listing')") instant_booking_value ['JOINED', 'METRIC'] ('listings_latest',) ("('listing',)", "('booking', 'listing')") instant_booking_value_ratio ['JOINED', 'METRIC'] ('listings_latest',) ("('listing',)", "('booking', 'listing')") instant_bookings ['JOINED', 'METRIC'] +('listings_latest',) ("('listing',)", "('booking', 'listing')") instant_bookings_with_measure_filter ['JOINED', 'METRIC'] ('listings_latest',) ("('listing',)", "('booking', 'listing')") instant_lux_booking_value_rate ['JOINED', 'METRIC'] ('listings_latest',) ("('listing',)", "('booking', 'listing')") instant_plus_non_referred_bookings_pct ['JOINED', 'METRIC'] ('listings_latest',) ("('listing',)", "('booking', 'listing')") lux_booking_fraction_of_max_value ['JOINED', 'METRIC'] @@ -97,6 +98,7 @@ Model Join-Path Entity Links ('listings_latest',) ("('listing',)", "('listing',)") instant_booking_value ['JOINED', 'METRIC'] ('listings_latest',) ("('listing',)", "('listing',)") instant_booking_value_ratio ['JOINED', 'METRIC'] ('listings_latest',) ("('listing',)", "('listing',)") instant_bookings ['JOINED', 'METRIC'] +('listings_latest',) ("('listing',)", "('listing',)") instant_bookings_with_measure_filter ['JOINED', 'METRIC'] ('listings_latest',) ("('listing',)", "('listing',)") instant_lux_booking_value_rate ['JOINED', 'METRIC'] ('listings_latest',) ("('listing',)", "('listing',)") instant_plus_non_referred_bookings_pct ['JOINED', 'METRIC'] ('listings_latest',) ("('listing',)", "('listing',)") largest_listing ['JOINED', 'METRIC'] @@ -157,6 +159,7 @@ Model Join-Path Entity Links ('listings_latest',) ("('user',)", "('listing', 'user')") instant_booking_value ['JOINED', 'METRIC'] ('listings_latest',) ("('user',)", "('listing', 'user')") instant_booking_value_ratio ['JOINED', 'METRIC'] ('listings_latest',) ("('user',)", "('listing', 'user')") instant_bookings ['JOINED', 'METRIC'] +('listings_latest',) ("('user',)", "('listing', 'user')") instant_bookings_with_measure_filter ['JOINED', 'METRIC'] ('listings_latest',) ("('user',)", "('listing', 'user')") instant_lux_booking_value_rate ['JOINED', 'METRIC'] ('listings_latest',) ("('user',)", "('listing', 'user')") instant_plus_non_referred_bookings_pct ['JOINED', 'METRIC'] ('listings_latest',) ("('user',)", "('listing', 'user')") largest_listing ['JOINED', 'METRIC'] diff --git a/metricflow-semantics/tests_metricflow_semantics/snapshots/test_semantic_model_container.py/tuple/test_linkable_elements_for_no_metrics_query__result0.txt b/metricflow-semantics/tests_metricflow_semantics/snapshots/test_semantic_model_container.py/tuple/test_linkable_elements_for_no_metrics_query__result0.txt index 1604d2383e..aae6858e33 100644 --- a/metricflow-semantics/tests_metricflow_semantics/snapshots/test_semantic_model_container.py/tuple/test_linkable_elements_for_no_metrics_query__result0.txt +++ b/metricflow-semantics/tests_metricflow_semantics/snapshots/test_semantic_model_container.py/tuple/test_linkable_elements_for_no_metrics_query__result0.txt @@ -77,6 +77,7 @@ 'company__listing__user__company__instant_booking_value', 'company__listing__user__company__instant_booking_value_ratio', 'company__listing__user__company__instant_bookings', + 'company__listing__user__company__instant_bookings_with_measure_filter', 'company__listing__user__company__instant_lux_booking_value_rate', 'company__listing__user__company__instant_plus_non_referred_bookings_pct', 'company__listing__user__company__lux_booking_fraction_of_max_value', @@ -148,6 +149,7 @@ 'guest__booking__guest__instant_booking_value', 'guest__booking__guest__instant_booking_value_ratio', 'guest__booking__guest__instant_bookings', + 'guest__booking__guest__instant_bookings_with_measure_filter', 'guest__booking__guest__instant_lux_booking_value_rate', 'guest__booking__guest__instant_plus_non_referred_bookings_pct', 'guest__booking__guest__lux_booking_fraction_of_max_value', @@ -181,6 +183,7 @@ 'guest__instant_booking_value', 'guest__instant_booking_value_ratio', 'guest__instant_bookings', + 'guest__instant_bookings_with_measure_filter', 'guest__instant_lux_booking_value_rate', 'guest__instant_plus_non_referred_bookings_pct', 'guest__lux_booking_fraction_of_max_value', @@ -225,6 +228,7 @@ 'host__booking__host__instant_booking_value', 'host__booking__host__instant_booking_value_ratio', 'host__booking__host__instant_bookings', + 'host__booking__host__instant_bookings_with_measure_filter', 'host__booking__host__instant_lux_booking_value_rate', 'host__booking__host__instant_plus_non_referred_bookings_pct', 'host__booking__host__lux_booking_fraction_of_max_value', @@ -258,6 +262,7 @@ 'host__instant_booking_value', 'host__instant_booking_value_ratio', 'host__instant_bookings', + 'host__instant_bookings_with_measure_filter', 'host__instant_lux_booking_value_rate', 'host__instant_plus_non_referred_bookings_pct', 'host__lux_booking_fraction_of_max_value', @@ -303,6 +308,7 @@ 'listing__booking__listing__instant_booking_value', 'listing__booking__listing__instant_booking_value_ratio', 'listing__booking__listing__instant_bookings', + 'listing__booking__listing__instant_bookings_with_measure_filter', 'listing__booking__listing__instant_lux_booking_value_rate', 'listing__booking__listing__instant_plus_non_referred_bookings_pct', 'listing__booking__listing__lux_booking_fraction_of_max_value', @@ -356,6 +362,7 @@ 'listing__instant_booking_value', 'listing__instant_booking_value_ratio', 'listing__instant_bookings', + 'listing__instant_bookings_with_measure_filter', 'listing__instant_lux_booking_value_rate', 'listing__instant_plus_non_referred_bookings_pct', 'listing__is_lux_latest', @@ -411,6 +418,7 @@ 'lux_listing__listing__lux_listing__instant_booking_value', 'lux_listing__listing__lux_listing__instant_booking_value_ratio', 'lux_listing__listing__lux_listing__instant_bookings', + 'lux_listing__listing__lux_listing__instant_bookings_with_measure_filter', 'lux_listing__listing__lux_listing__instant_lux_booking_value_rate', 'lux_listing__listing__lux_listing__instant_plus_non_referred_bookings_pct', 'lux_listing__listing__lux_listing__largest_listing', @@ -551,6 +559,7 @@ 'user__listing__user__instant_booking_value', 'user__listing__user__instant_booking_value_ratio', 'user__listing__user__instant_bookings', + 'user__listing__user__instant_bookings_with_measure_filter', 'user__listing__user__instant_lux_booking_value_rate', 'user__listing__user__instant_plus_non_referred_bookings_pct', 'user__listing__user__largest_listing', diff --git a/metricflow-semantics/tests_metricflow_semantics/test_specs.py b/metricflow-semantics/tests_metricflow_semantics/test_specs.py index 5c4ee91ec5..c3cbca75ba 100644 --- a/metricflow-semantics/tests_metricflow_semantics/test_specs.py +++ b/metricflow-semantics/tests_metricflow_semantics/test_specs.py @@ -9,10 +9,14 @@ from metricflow_semantics.specs.entity_spec import EntitySpec, LinklessEntitySpec from metricflow_semantics.specs.group_by_metric_spec import GroupByMetricSpec from metricflow_semantics.specs.instance_spec import InstanceSpec, LinkableInstanceSpec +from metricflow_semantics.specs.linkable_spec_set import LinkableSpecSet from metricflow_semantics.specs.measure_spec import MeasureSpec from metricflow_semantics.specs.metric_spec import MetricSpec from metricflow_semantics.specs.spec_set import InstanceSpecSet from metricflow_semantics.specs.time_dimension_spec import TimeDimensionSpec +from metricflow_semantics.specs.where_filter.where_filter_spec import WhereFilterSpec +from metricflow_semantics.specs.where_filter.where_filter_spec_set import WhereFilterSpecSet +from metricflow_semantics.sql.sql_bind_parameters import SqlBindParameters from metricflow_semantics.time.granularity import ExpandedTimeGranularity @@ -212,3 +216,115 @@ def test_linkless_entity() -> None: set_with_entity_spec.add(linkless_entity_spec) assert len(set_with_entity_spec) == 1 + + +@pytest.fixture +def where_filter_spec_set() -> WhereFilterSpecSet: # noqa: D103 + return WhereFilterSpecSet( + measure_level_filter_specs=( + WhereFilterSpec( + where_sql="measure is true", + bind_parameters=SqlBindParameters(), + linkable_element_unions=(), + linkable_spec_set=LinkableSpecSet(), + ), + ), + metric_level_filter_specs=( + WhereFilterSpec( + where_sql="metric is true", + bind_parameters=SqlBindParameters(), + linkable_element_unions=(), + linkable_spec_set=LinkableSpecSet(), + ), + ), + query_level_filter_specs=( + WhereFilterSpec( + where_sql="query is true", + bind_parameters=SqlBindParameters(), + linkable_element_unions=(), + linkable_spec_set=LinkableSpecSet(), + ), + ), + ) + + +def test_where_filter_spec_set_all_specs(where_filter_spec_set: WhereFilterSpecSet) -> None: # noqa: D103 + assert set(where_filter_spec_set.all_filter_specs) == { + WhereFilterSpec( + where_sql="measure is true", + bind_parameters=SqlBindParameters(), + linkable_element_unions=(), + linkable_spec_set=LinkableSpecSet(), + ), + WhereFilterSpec( + where_sql="metric is true", + bind_parameters=SqlBindParameters(), + linkable_element_unions=(), + linkable_spec_set=LinkableSpecSet(), + ), + WhereFilterSpec( + where_sql="query is true", + bind_parameters=SqlBindParameters(), + linkable_element_unions=(), + linkable_spec_set=LinkableSpecSet(), + ), + } + + +def test_where_filter_spec_set_post_aggregation_specs(where_filter_spec_set: WhereFilterSpecSet) -> None: # noqa: D103 + assert set(where_filter_spec_set.after_measure_aggregation_filter_specs) == { + WhereFilterSpec( + where_sql="metric is true", + bind_parameters=SqlBindParameters(), + linkable_element_unions=(), + linkable_spec_set=LinkableSpecSet(), + ), + WhereFilterSpec( + where_sql="query is true", + bind_parameters=SqlBindParameters(), + linkable_element_unions=(), + linkable_spec_set=LinkableSpecSet(), + ), + } + + +def test_where_filter_spec_set_merge(where_filter_spec_set: WhereFilterSpecSet) -> None: # noqa: D103 + spec_set1 = WhereFilterSpecSet( + measure_level_filter_specs=( + WhereFilterSpec( + where_sql="measure is true", + bind_parameters=SqlBindParameters(), + linkable_element_unions=(), + linkable_spec_set=LinkableSpecSet(), + ), + ), + ) + spec_set2 = WhereFilterSpecSet( + metric_level_filter_specs=( + WhereFilterSpec( + where_sql="metric is true", + bind_parameters=SqlBindParameters(), + linkable_element_unions=(), + linkable_spec_set=LinkableSpecSet(), + ), + ), + ) + + assert spec_set1.merge(spec_set2) == WhereFilterSpecSet( + measure_level_filter_specs=( + WhereFilterSpec( + where_sql="measure is true", + bind_parameters=SqlBindParameters(), + linkable_element_unions=(), + linkable_spec_set=LinkableSpecSet(), + ), + ), + metric_level_filter_specs=( + WhereFilterSpec( + where_sql="metric is true", + bind_parameters=SqlBindParameters(), + linkable_element_unions=(), + linkable_spec_set=LinkableSpecSet(), + ), + ), + ) diff --git a/metricflow/dataflow/builder/dataflow_plan_builder.py b/metricflow/dataflow/builder/dataflow_plan_builder.py index 40b938eb99..be52f45442 100644 --- a/metricflow/dataflow/builder/dataflow_plan_builder.py +++ b/metricflow/dataflow/builder/dataflow_plan_builder.py @@ -50,6 +50,7 @@ from metricflow_semantics.specs.spec_set import InstanceSpecSet, group_specs_by_type from metricflow_semantics.specs.time_dimension_spec import TimeDimensionSpec from metricflow_semantics.specs.where_filter.where_filter_spec import WhereFilterSpec +from metricflow_semantics.specs.where_filter.where_filter_spec_set import WhereFilterSpecSet from metricflow_semantics.specs.where_filter.where_filter_transform import WhereSpecFactory from metricflow_semantics.sql.sql_join_type import SqlJoinType from metricflow_semantics.sql.sql_table import SqlTable @@ -152,7 +153,7 @@ def _build_query_output_node( """Build SQL output node from query inputs. May be used to build query DFP or source node.""" for metric_spec in query_spec.metric_specs: if ( - len(metric_spec.filter_specs) > 0 + len(metric_spec.filter_spec_set.all_filter_specs) > 0 or metric_spec.offset_to_grain is not None or metric_spec.offset_window is not None or metric_spec.alias is not None @@ -185,7 +186,7 @@ def _build_query_output_node( metric_specs=tuple( MetricSpec( element_name=metric_spec.element_name, - filter_specs=query_level_filter_specs, + filter_spec_set=WhereFilterSpecSet(query_level_filter_specs=query_level_filter_specs), ) for metric_spec in query_spec.metric_specs ), @@ -259,7 +260,7 @@ def _build_aggregated_conversion_node( # Build measure recipes base_required_linkable_specs, _ = self.__get_required_and_extraneous_linkable_specs( queried_linkable_specs=queried_linkable_specs, - filter_specs=base_measure_spec.filter_specs, + filter_specs=base_measure_spec.filter_spec_set.all_filter_specs, ) base_measure_recipe = self._find_source_node_recipe( FindSourceNodeRecipeParameterSet( @@ -394,7 +395,7 @@ def _build_conversion_metric_output_node( metric_reference=metric_spec.reference, conversion_type_params=conversion_type_params, filter_spec_factory=filter_spec_factory, - descendent_filter_specs=metric_spec.filter_specs, + descendent_filter_spec_set=metric_spec.filter_spec_set, queried_linkable_specs=queried_linkable_specs, ) # TODO: [custom granularity] change this to an assertion once we're sure there aren't exceptions @@ -531,7 +532,7 @@ def _build_base_metric_output_node( if metric.type is MetricType.CUMULATIVE else None ), - descendent_filter_specs=metric_spec.filter_specs, + descendent_filter_spec_set=metric_spec.filter_spec_set, ) logger.debug( LazyFormat( @@ -575,7 +576,7 @@ def _build_derived_metric_output_node( ) required_linkable_specs, extraneous_linkable_specs = self.__get_required_and_extraneous_linkable_specs( - queried_linkable_specs=queried_linkable_specs, filter_specs=metric_spec.filter_specs + queried_linkable_specs=queried_linkable_specs, filter_specs=metric_spec.filter_spec_set.all_filter_specs ) parent_nodes: List[DataflowPlanNode] = [] @@ -587,10 +588,12 @@ def _build_derived_metric_output_node( ) for metric_input_spec in metric_input_specs: - filter_specs: List[WhereFilterSpec] = [] - filter_specs.extend(metric_definition_filter_specs) + where_filter_spec_set = WhereFilterSpecSet( + metric_level_filter_specs=tuple(metric_definition_filter_specs), + ) + # These are the filters that's defined as part of the input metric. - filter_specs.extend(metric_input_spec.filter_specs) + where_filter_spec_set = where_filter_spec_set.merge(metric_input_spec.filter_spec_set) # If metric is offset, we'll apply where constraint after offset to avoid removing values # unexpectedly. Time constraint will be applied by INNER JOINing to time spine. @@ -598,8 +601,7 @@ def _build_derived_metric_output_node( # is about post-join to pre-join for dimension access, and relies on the builder to collect # predicates from query and metric specs and make them available at measure level. if not metric_spec.has_time_offset: - filter_specs.extend(metric_spec.filter_specs) - + where_filter_spec_set = where_filter_spec_set.merge(metric_spec.filter_spec_set) metric_pushdown_state = ( predicate_pushdown_state if not metric_spec.has_time_offset @@ -611,7 +613,7 @@ def _build_derived_metric_output_node( BuildAnyMetricOutputNodeParameterSet( metric_spec=MetricSpec( element_name=metric_input_spec.element_name, - filter_specs=tuple(filter_specs), + filter_spec_set=where_filter_spec_set, alias=metric_input_spec.alias, offset_window=metric_input_spec.offset_window, offset_to_grain=metric_input_spec.offset_to_grain, @@ -656,8 +658,10 @@ def _build_derived_metric_output_node( join_type=SqlJoinType.INNER, ) - if len(metric_spec.filter_specs) > 0: - output_node = WhereConstraintNode.create(parent_node=output_node, where_specs=metric_spec.filter_specs) + if len(metric_spec.filter_spec_set.all_filter_specs) > 0: + output_node = WhereConstraintNode.create( + parent_node=output_node, where_specs=metric_spec.filter_spec_set.all_filter_specs + ) if not extraneous_linkable_specs.is_subset_of(queried_linkable_specs): output_node = FilterElementsNode.create( parent_node=output_node, @@ -1257,7 +1261,7 @@ def _build_input_measure_specs_for_conversion_metric( metric_reference: MetricReference, conversion_type_params: ConversionTypeParams, filter_spec_factory: WhereSpecFactory, - descendent_filter_specs: Sequence[WhereFilterSpec], + descendent_filter_spec_set: WhereFilterSpecSet, queried_linkable_specs: LinkableSpecSet, ) -> Tuple[MetricInputMeasureSpec, MetricInputMeasureSpec]: """Return [base_measure_input, conversion_measure_input] for computing a conversion metric.""" @@ -1271,7 +1275,7 @@ def _build_input_measure_specs_for_conversion_metric( metric=metric, input_measure=input_measure, queried_linkable_specs=queried_linkable_specs, - descendent_filter_specs=descendent_filter_specs, + descendent_filter_spec_set=descendent_filter_spec_set, include_filters=include_filters, ) # Filters should only be applied to base measures. @@ -1288,7 +1292,7 @@ def _build_input_measure_spec( filter_spec_factory: WhereSpecFactory, metric: Metric, input_measure: MetricInputMeasure, - descendent_filter_specs: Sequence[WhereFilterSpec], + descendent_filter_spec_set: WhereFilterSpecSet, queried_linkable_specs: LinkableSpecSet, include_filters: bool = True, child_metric_offset_window: Optional[MetricTimeWindow] = None, @@ -1301,13 +1305,13 @@ def _build_input_measure_spec( descendent_filter_specs includes all filter specs required to compute the metric in the query. This includes the filters in the query and any filter in the definition of metrics in between. """ - filter_specs: Tuple[WhereFilterSpec, ...] = () + filter_spec_set: WhereFilterSpecSet = WhereFilterSpecSet() if include_filters: - filter_specs = self._build_filter_specs_for_input_measure( + filter_spec_set = self._build_filter_specs_for_input_measure( filter_spec_factory=filter_spec_factory, metric=metric, input_measure=input_measure, - descendent_filter_specs=descendent_filter_specs, + descendent_filter_spec_set=descendent_filter_spec_set, ) measure_spec = MeasureSpec( @@ -1350,7 +1354,7 @@ def _build_input_measure_spec( offset_window=child_metric_offset_window, offset_to_grain=child_metric_offset_to_grain, cumulative_description=cumulative_description, - filter_specs=filter_specs, + filter_spec_set=filter_spec_set, alias=input_measure.alias, before_aggregation_time_spine_join_description=before_aggregation_time_spine_join_description, after_aggregation_time_spine_join_description=after_aggregation_time_spine_join_description, @@ -1361,19 +1365,24 @@ def _build_filter_specs_for_input_measure( filter_spec_factory: WhereSpecFactory, metric: Metric, input_measure: MetricInputMeasure, - descendent_filter_specs: Sequence[WhereFilterSpec], - ) -> Tuple[WhereFilterSpec, ...]: + descendent_filter_spec_set: WhereFilterSpecSet, + ) -> WhereFilterSpecSet: metric_reference = MetricReference(element_name=metric.name) - filter_specs: List[WhereFilterSpec] = [] filter_location = WhereFilterLocation.for_metric(metric_reference) - for filter_ in (input_measure.filter, metric.filter): - filter_specs.extend( + + filter_spec_set = WhereFilterSpecSet( + measure_level_filter_specs=tuple( filter_spec_factory.create_from_where_filter_intersection( - filter_location=filter_location, filter_intersection=filter_ + filter_location=filter_location, filter_intersection=input_measure.filter ) - ) - filter_specs.extend(descendent_filter_specs) - return tuple(filter_specs) + ), + metric_level_filter_specs=tuple( + filter_spec_factory.create_from_where_filter_intersection( + filter_location=filter_location, filter_intersection=metric.filter + ) + ), + ) + return filter_spec_set.merge(descendent_filter_spec_set) def _build_input_metric_specs_for_derived_metric( self, @@ -1385,14 +1394,20 @@ def _build_input_metric_specs_for_derived_metric( input_metric_specs: List[MetricSpec] = [] for input_metric in metric.input_metrics: - filter_specs = filter_spec_factory.create_from_where_filter_intersection( - filter_location=WhereFilterLocation.for_input_metric(input_metric_reference=input_metric.as_reference), - filter_intersection=input_metric.filter, + filter_spec_set = WhereFilterSpecSet( + metric_level_filter_specs=tuple( + filter_spec_factory.create_from_where_filter_intersection( + filter_location=WhereFilterLocation.for_input_metric( + input_metric_reference=input_metric.as_reference + ), + filter_intersection=input_metric.filter, + ) + ), ) spec = MetricSpec( element_name=input_metric.name, - filter_specs=tuple(filter_specs), + filter_spec_set=filter_spec_set, alias=input_metric.alias, offset_window=( PydanticMetricTimeWindow( @@ -1425,8 +1440,8 @@ def build_aggregated_measure( logger.debug( LazyFormat( lambda: f"Building aggregated measure: {measure_spec} with input measure filters:\n" - f"{mf_pformat(metric_input_measure_spec.filter_specs)}\n" - f"and filters:\n{mf_pformat(metric_input_measure_spec.filter_specs)}" + f"{mf_pformat(metric_input_measure_spec.filter_spec_set)}\n" + f"and filters:\n{mf_pformat(metric_input_measure_spec.filter_spec_set)}" ) ) @@ -1521,7 +1536,7 @@ def _build_aggregated_measure_from_measure_source_node( required_linkable_specs, extraneous_linkable_specs = self.__get_required_and_extraneous_linkable_specs( queried_linkable_specs=queried_linkable_specs, - filter_specs=metric_input_measure_spec.filter_specs, + filter_specs=metric_input_measure_spec.filter_spec_set.all_filter_specs, non_additive_dimension_spec=non_additive_dimension_spec, ) @@ -1668,11 +1683,11 @@ def _build_aggregated_measure_from_measure_source_node( ) pre_aggregate_node: DataflowPlanNode = cumulative_metric_constrained_node or unaggregated_measure_node - if len(metric_input_measure_spec.filter_specs) > 0: + if len(metric_input_measure_spec.filter_spec_set.all_filter_specs) > 0: # Apply where constraint on the node pre_aggregate_node = WhereConstraintNode.create( parent_node=pre_aggregate_node, - where_specs=metric_input_measure_spec.filter_specs, + where_specs=metric_input_measure_spec.filter_spec_set.all_filter_specs, ) if non_additive_dimension_spec is not None: @@ -1747,7 +1762,7 @@ def _build_aggregated_measure_from_measure_source_node( # time spine join. queried_filter_specs = [ filter_spec - for filter_spec in metric_input_measure_spec.filter_specs + for filter_spec in metric_input_measure_spec.filter_spec_set.after_measure_aggregation_filter_specs if set(filter_spec.linkable_specs).issubset(set(queried_linkable_specs.as_tuple)) ] if len(queried_filter_specs) > 0: diff --git a/tests_metricflow/integration/test_cases/itest_join_to_timespine.yaml b/tests_metricflow/integration/test_cases/itest_join_to_timespine.yaml new file mode 100644 index 0000000000..bbad3d3db0 --- /dev/null +++ b/tests_metricflow/integration/test_cases/itest_join_to_timespine.yaml @@ -0,0 +1,41 @@ +integration_test: + name: test_constraint_on_measure_selected_in_group_by + description: Tests that the filter on measure is not re-applied even if selected in group by + model: SIMPLE_MODEL + metrics: ["instant_bookings_with_measure_filter"] + group_bys: ["metric_time__day", "booking__is_instant"] + where_filter: | + {{ render_time_constraint(render_time_dimension_template('metric_time', 'day'), start_time="2020-01-01") }} + check_query: | + SELECT + metric_time__day + , booking__is_instant + , bookings AS instant_bookings_with_measure_filter + FROM ( + SELECT + t.ds AS metric_time__day + , b.booking__is_instant AS booking__is_instant + , b.bookings AS bookings + FROM {{ source_schema }}.mf_time_spine t + LEFT OUTER JOIN ( + SELECT + metric_time__day + , booking__is_instant + , SUM(bookings) AS bookings + FROM ( + SELECT + {{ render_date_trunc("ds", TimeGranularity.DAY) }} AS metric_time__day + , listing_id AS listing + , is_instant AS booking__is_instant + , 1 AS bookings + FROM {{ source_schema }}.fct_bookings b + ) d + WHERE booking__is_instant AND listing IS NOT NULL AND {{ render_time_constraint("metric_time__day", start_time="2020-01-01") }} + GROUP BY + metric_time__day + , booking__is_instant + ) b + ON + t.ds = b.metric_time__day + ) c + WHERE {{ render_time_constraint("metric_time__day", start_time="2020-01-01") }} diff --git a/tests_metricflow/query_rendering/test_time_spine_join_rendering.py b/tests_metricflow/query_rendering/test_time_spine_join_rendering.py index 261b644677..43e0438a01 100644 --- a/tests_metricflow/query_rendering/test_time_spine_join_rendering.py +++ b/tests_metricflow/query_rendering/test_time_spine_join_rendering.py @@ -152,3 +152,34 @@ def test_join_to_time_spine_with_queried_time_constraint( dataflow_plan_builder=dataflow_plan_builder, query_spec=query_spec, ) + + +@pytest.mark.sql_engine_snapshot +def test_join_to_time_spine_with_input_measure_constraint( + request: FixtureRequest, + mf_test_configuration: MetricFlowTestConfiguration, + dataflow_plan_builder: DataflowPlanBuilder, + dataflow_to_sql_converter: DataflowToSqlQueryPlanConverter, + sql_client: SqlClient, + query_parser: MetricFlowQueryParser, +) -> None: + """Check filter hierarchy. + + Ensure that the measure filter 'booking__is_instant' doesn't get applied again post-aggregation. + """ + query_spec = query_parser.parse_and_validate_query( + metric_names=("instant_bookings_with_measure_filter",), + group_by_names=("metric_time__day", "booking__is_instant"), + where_constraints=[ + PydanticWhereFilter(where_sql_template="{{ TimeDimension('metric_time', 'day') }} > '2020-01-01'") + ], + ).query_spec + + render_and_check( + request=request, + mf_test_configuration=mf_test_configuration, + dataflow_to_sql_converter=dataflow_to_sql_converter, + sql_client=sql_client, + dataflow_plan_builder=dataflow_plan_builder, + query_spec=query_spec, + ) diff --git a/tests_metricflow/snapshots/test_cyclic_join.py/DataflowPlan/test_cyclic_join__dfp_0.xml b/tests_metricflow/snapshots/test_cyclic_join.py/DataflowPlan/test_cyclic_join__dfp_0.xml index ae541e136e..2c9fa8f657 100644 --- a/tests_metricflow/snapshots/test_cyclic_join.py/DataflowPlan/test_cyclic_join__dfp_0.xml +++ b/tests_metricflow/snapshots/test_cyclic_join.py/DataflowPlan/test_cyclic_join__dfp_0.xml @@ -5,7 +5,7 @@ - + diff --git a/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_common_semantic_model__dfp_0.xml b/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_common_semantic_model__dfp_0.xml index a858d37305..35a23c550a 100644 --- a/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_common_semantic_model__dfp_0.xml +++ b/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_common_semantic_model__dfp_0.xml @@ -8,7 +8,7 @@ - + @@ -83,7 +83,7 @@ - + diff --git a/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_cumulative_metric_no_window_or_grain_with_metric_time__dfp_0.xml b/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_cumulative_metric_no_window_or_grain_with_metric_time__dfp_0.xml index 14b91fd6fb..e5e4dde501 100644 --- a/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_cumulative_metric_no_window_or_grain_with_metric_time__dfp_0.xml +++ b/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_cumulative_metric_no_window_or_grain_with_metric_time__dfp_0.xml @@ -5,7 +5,7 @@ - + diff --git a/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_cumulative_metric_no_window_or_grain_without_metric_time__dfp_0.xml b/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_cumulative_metric_no_window_or_grain_without_metric_time__dfp_0.xml index 1fae1308e4..ce7fc8b703 100644 --- a/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_cumulative_metric_no_window_or_grain_without_metric_time__dfp_0.xml +++ b/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_cumulative_metric_no_window_or_grain_without_metric_time__dfp_0.xml @@ -5,7 +5,7 @@ - + diff --git a/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_cumulative_metric_with_non_default_grain__dfp_0.xml b/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_cumulative_metric_with_non_default_grain__dfp_0.xml index d7a5165024..5db430b0e1 100644 --- a/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_cumulative_metric_with_non_default_grain__dfp_0.xml +++ b/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_cumulative_metric_with_non_default_grain__dfp_0.xml @@ -5,7 +5,8 @@ - + + @@ -21,7 +22,8 @@ - + + diff --git a/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_cumulative_metric_with_window__dfp_0.xml b/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_cumulative_metric_with_window__dfp_0.xml index 4f0bf5034f..3f1d60f4f5 100644 --- a/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_cumulative_metric_with_window__dfp_0.xml +++ b/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_cumulative_metric_with_window__dfp_0.xml @@ -5,7 +5,8 @@ - + + diff --git a/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_derived_cumulative_metric_with_non_default_grain__dfp_0.xml b/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_derived_cumulative_metric_with_non_default_grain__dfp_0.xml index b9bf963f55..2a04af7d16 100644 --- a/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_derived_cumulative_metric_with_non_default_grain__dfp_0.xml +++ b/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_derived_cumulative_metric_with_non_default_grain__dfp_0.xml @@ -5,11 +5,17 @@ - + + - + + + + + + @@ -25,7 +31,12 @@ - + + + + + + diff --git a/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_derived_metric_offset_to_grain__dfp_0.xml b/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_derived_metric_offset_to_grain__dfp_0.xml index 60b0f12c7a..03183025f2 100644 --- a/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_derived_metric_offset_to_grain__dfp_0.xml +++ b/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_derived_metric_offset_to_grain__dfp_0.xml @@ -5,14 +5,15 @@ - + + - + @@ -42,8 +43,13 @@ - - + + + + + + + diff --git a/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_derived_metric_offset_window__dfp_0.xml b/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_derived_metric_offset_window__dfp_0.xml index 7c268973d6..49f2bf9e41 100644 --- a/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_derived_metric_offset_window__dfp_0.xml +++ b/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_derived_metric_offset_window__dfp_0.xml @@ -5,13 +5,14 @@ - + + diff --git a/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_derived_metric_offset_with_granularity__dfp_0.xml b/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_derived_metric_offset_with_granularity__dfp_0.xml index 8b323050cd..26a46f4a75 100644 --- a/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_derived_metric_offset_with_granularity__dfp_0.xml +++ b/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_derived_metric_offset_with_granularity__dfp_0.xml @@ -5,13 +5,14 @@ - + + diff --git a/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_derived_offset_cumulative_metric__dfp_0.xml b/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_derived_offset_cumulative_metric__dfp_0.xml index ebbab1e3c5..3f60f53ed9 100644 --- a/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_derived_offset_cumulative_metric__dfp_0.xml +++ b/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_derived_offset_cumulative_metric__dfp_0.xml @@ -5,13 +5,15 @@ - + + + diff --git a/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_dont_join_to_time_spine_if_no_time_dimension_requested__dfp_0.xml b/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_dont_join_to_time_spine_if_no_time_dimension_requested__dfp_0.xml index ce964af845..237663c5e9 100644 --- a/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_dont_join_to_time_spine_if_no_time_dimension_requested__dfp_0.xml +++ b/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_dont_join_to_time_spine_if_no_time_dimension_requested__dfp_0.xml @@ -5,7 +5,8 @@ - + + diff --git a/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_join_to_time_spine_derived_metric__dfp_0.xml b/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_join_to_time_spine_derived_metric__dfp_0.xml index 17eeb4bf57..29c9395100 100644 --- a/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_join_to_time_spine_derived_metric__dfp_0.xml +++ b/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_join_to_time_spine_derived_metric__dfp_0.xml @@ -5,14 +5,19 @@ - + + + + + - + + @@ -61,6 +66,7 @@ + diff --git a/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_join_to_time_spine_with_filters__dfp_0.xml b/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_join_to_time_spine_with_filters__dfp_0.xml index 50316718a8..2b69965b1c 100644 --- a/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_join_to_time_spine_with_filters__dfp_0.xml +++ b/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_join_to_time_spine_with_filters__dfp_0.xml @@ -5,48 +5,52 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_join_to_time_spine_with_metric_time__dfp_0.xml b/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_join_to_time_spine_with_metric_time__dfp_0.xml index d0523cc91e..56b9d9eee4 100644 --- a/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_join_to_time_spine_with_metric_time__dfp_0.xml +++ b/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_join_to_time_spine_with_metric_time__dfp_0.xml @@ -5,7 +5,8 @@ - + + diff --git a/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_join_to_time_spine_with_non_metric_time__dfp_0.xml b/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_join_to_time_spine_with_non_metric_time__dfp_0.xml index 88a6c47515..99338874f6 100644 --- a/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_join_to_time_spine_with_non_metric_time__dfp_0.xml +++ b/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_join_to_time_spine_with_non_metric_time__dfp_0.xml @@ -5,7 +5,8 @@ - + + diff --git a/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_joined_plan__dfp_0.xml b/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_joined_plan__dfp_0.xml index 041f258d06..a5b1e264e2 100644 --- a/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_joined_plan__dfp_0.xml +++ b/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_joined_plan__dfp_0.xml @@ -5,7 +5,7 @@ - + diff --git a/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_limit_rows_plan__dfp_0.xml b/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_limit_rows_plan__dfp_0.xml index 6f085318f4..007af3ed97 100644 --- a/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_limit_rows_plan__dfp_0.xml +++ b/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_limit_rows_plan__dfp_0.xml @@ -9,7 +9,7 @@ - + diff --git a/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_measure_constraint_plan__dfp_0.xml b/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_measure_constraint_plan__dfp_0.xml index ef4a3fc46d..eb9df1f197 100644 --- a/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_measure_constraint_plan__dfp_0.xml +++ b/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_measure_constraint_plan__dfp_0.xml @@ -5,67 +5,72 @@ - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -212,60 +217,64 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -411,7 +420,7 @@ - + diff --git a/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_measure_constraint_with_reused_measure_plan__dfp_0.xml b/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_measure_constraint_with_reused_measure_plan__dfp_0.xml index fce10fcf79..1ee5a04112 100644 --- a/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_measure_constraint_with_reused_measure_plan__dfp_0.xml +++ b/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_measure_constraint_with_reused_measure_plan__dfp_0.xml @@ -5,58 +5,63 @@ - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -147,7 +152,7 @@ - + diff --git a/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_metric_in_metric_where_filter__dfp_0.xml b/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_metric_in_metric_where_filter__dfp_0.xml index 8586871725..af42c3338c 100644 --- a/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_metric_in_metric_where_filter__dfp_0.xml +++ b/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_metric_in_metric_where_filter__dfp_0.xml @@ -5,7 +5,7 @@ - + @@ -89,7 +89,8 @@ - + + diff --git a/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_metric_in_query_where_filter__dfp_0.xml b/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_metric_in_query_where_filter__dfp_0.xml index 2a6db6ce4a..226f6cda8c 100644 --- a/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_metric_in_query_where_filter__dfp_0.xml +++ b/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_metric_in_query_where_filter__dfp_0.xml @@ -5,33 +5,35 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -115,7 +117,8 @@ - + + diff --git a/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_multi_semantic_model_ratio_metrics_plan__dfp_0.xml b/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_multi_semantic_model_ratio_metrics_plan__dfp_0.xml index 7e620b5c4b..6137586bd3 100644 --- a/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_multi_semantic_model_ratio_metrics_plan__dfp_0.xml +++ b/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_multi_semantic_model_ratio_metrics_plan__dfp_0.xml @@ -5,14 +5,14 @@ - + - + @@ -87,7 +87,7 @@ - + diff --git a/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_multihop_join_plan__dfp_0.xml b/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_multihop_join_plan__dfp_0.xml index 9fe8220797..378d694411 100644 --- a/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_multihop_join_plan__dfp_0.xml +++ b/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_multihop_join_plan__dfp_0.xml @@ -5,7 +5,7 @@ - + diff --git a/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_multiple_metrics_plan__dfp_0.xml b/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_multiple_metrics_plan__dfp_0.xml index 68223678f4..a60caf65d2 100644 --- a/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_multiple_metrics_plan__dfp_0.xml +++ b/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_multiple_metrics_plan__dfp_0.xml @@ -8,7 +8,7 @@ - + @@ -43,7 +43,7 @@ - + diff --git a/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_nested_derived_metric_with_outer_offset__dfp_0.xml b/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_nested_derived_metric_with_outer_offset__dfp_0.xml index 338fa413db..2392d9cadb 100644 --- a/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_nested_derived_metric_with_outer_offset__dfp_0.xml +++ b/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_nested_derived_metric_with_outer_offset__dfp_0.xml @@ -5,7 +5,7 @@ - + @@ -27,6 +27,7 @@ + @@ -35,6 +36,7 @@ + diff --git a/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_offset_to_grain_metric_filter_and_query_have_different_granularities__dfp_0.xml b/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_offset_to_grain_metric_filter_and_query_have_different_granularities__dfp_0.xml index 95f2c0484c..084542cad3 100644 --- a/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_offset_to_grain_metric_filter_and_query_have_different_granularities__dfp_0.xml +++ b/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_offset_to_grain_metric_filter_and_query_have_different_granularities__dfp_0.xml @@ -5,95 +5,103 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_offset_window_metric_filter_and_query_have_different_granularities__dfp_0.xml b/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_offset_window_metric_filter_and_query_have_different_granularities__dfp_0.xml index 452e48a547..8e983aa0d1 100644 --- a/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_offset_window_metric_filter_and_query_have_different_granularities__dfp_0.xml +++ b/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_offset_window_metric_filter_and_query_have_different_granularities__dfp_0.xml @@ -5,97 +5,105 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -206,48 +214,52 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_order_by_plan__dfp_0.xml b/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_order_by_plan__dfp_0.xml index d0ec1221b3..13efa2eb88 100644 --- a/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_order_by_plan__dfp_0.xml +++ b/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_order_by_plan__dfp_0.xml @@ -13,12 +13,16 @@ - + + + + + - + diff --git a/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_primary_entity_dimension__dfp_0.xml b/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_primary_entity_dimension__dfp_0.xml index 7830d4624c..c346097a11 100644 --- a/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_primary_entity_dimension__dfp_0.xml +++ b/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_primary_entity_dimension__dfp_0.xml @@ -5,7 +5,7 @@ - + diff --git a/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_simple_plan__dfp_0.xml b/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_simple_plan__dfp_0.xml index 7830d4624c..c346097a11 100644 --- a/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_simple_plan__dfp_0.xml +++ b/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_simple_plan__dfp_0.xml @@ -5,7 +5,7 @@ - + diff --git a/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_single_semantic_model_ratio_metrics_plan__dfp_0.xml b/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_single_semantic_model_ratio_metrics_plan__dfp_0.xml index dab3c934ed..8f13a18d4b 100644 --- a/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_single_semantic_model_ratio_metrics_plan__dfp_0.xml +++ b/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_single_semantic_model_ratio_metrics_plan__dfp_0.xml @@ -5,14 +5,14 @@ - + - + @@ -87,7 +87,7 @@ - + diff --git a/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_where_constrained_plan__dfp_0.xml b/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_where_constrained_plan__dfp_0.xml index 84b8ef2d20..d08dbf4043 100644 --- a/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_where_constrained_plan__dfp_0.xml +++ b/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_where_constrained_plan__dfp_0.xml @@ -5,60 +5,64 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_where_constrained_plan_time_dimension__dfp_0.xml b/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_where_constrained_plan_time_dimension__dfp_0.xml index bea1ca13e9..a7a3bd3a5b 100644 --- a/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_where_constrained_plan_time_dimension__dfp_0.xml +++ b/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_where_constrained_plan_time_dimension__dfp_0.xml @@ -5,48 +5,52 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_where_constrained_with_common_linkable_plan__dfp_0.xml b/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_where_constrained_with_common_linkable_plan__dfp_0.xml index a38f86e1df..214d2abf08 100644 --- a/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_where_constrained_with_common_linkable_plan__dfp_0.xml +++ b/tests_metricflow/snapshots/test_dataflow_plan_builder.py/DataflowPlan/test_where_constrained_with_common_linkable_plan__dfp_0.xml @@ -5,60 +5,64 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests_metricflow/snapshots/test_dataflow_to_sql_plan.py/DataflowPlan/test_compute_metrics_node_simple_expr__plan0.xml b/tests_metricflow/snapshots/test_dataflow_to_sql_plan.py/DataflowPlan/test_compute_metrics_node_simple_expr__plan0.xml index aeae47c427..994c19943d 100644 --- a/tests_metricflow/snapshots/test_dataflow_to_sql_plan.py/DataflowPlan/test_compute_metrics_node_simple_expr__plan0.xml +++ b/tests_metricflow/snapshots/test_dataflow_to_sql_plan.py/DataflowPlan/test_compute_metrics_node_simple_expr__plan0.xml @@ -5,7 +5,7 @@ - + diff --git a/tests_metricflow/snapshots/test_dataflow_to_sql_plan.py/DataflowPlan/test_join_to_time_spine_node_with_offset_to_grain__plan0.xml b/tests_metricflow/snapshots/test_dataflow_to_sql_plan.py/DataflowPlan/test_join_to_time_spine_node_with_offset_to_grain__plan0.xml index ee960d5dfc..ebf38ffd4a 100644 --- a/tests_metricflow/snapshots/test_dataflow_to_sql_plan.py/DataflowPlan/test_join_to_time_spine_node_with_offset_to_grain__plan0.xml +++ b/tests_metricflow/snapshots/test_dataflow_to_sql_plan.py/DataflowPlan/test_join_to_time_spine_node_with_offset_to_grain__plan0.xml @@ -24,7 +24,7 @@ - + diff --git a/tests_metricflow/snapshots/test_dataflow_to_sql_plan.py/DataflowPlan/test_join_to_time_spine_node_with_offset_window__plan0.xml b/tests_metricflow/snapshots/test_dataflow_to_sql_plan.py/DataflowPlan/test_join_to_time_spine_node_with_offset_window__plan0.xml index bbc356942c..1dc7bd471c 100644 --- a/tests_metricflow/snapshots/test_dataflow_to_sql_plan.py/DataflowPlan/test_join_to_time_spine_node_with_offset_window__plan0.xml +++ b/tests_metricflow/snapshots/test_dataflow_to_sql_plan.py/DataflowPlan/test_join_to_time_spine_node_with_offset_window__plan0.xml @@ -24,7 +24,7 @@ - + diff --git a/tests_metricflow/snapshots/test_dataflow_to_sql_plan.py/DataflowPlan/test_join_to_time_spine_node_without_offset__plan0.xml b/tests_metricflow/snapshots/test_dataflow_to_sql_plan.py/DataflowPlan/test_join_to_time_spine_node_without_offset__plan0.xml index ff11742636..865319fe64 100644 --- a/tests_metricflow/snapshots/test_dataflow_to_sql_plan.py/DataflowPlan/test_join_to_time_spine_node_without_offset__plan0.xml +++ b/tests_metricflow/snapshots/test_dataflow_to_sql_plan.py/DataflowPlan/test_join_to_time_spine_node_without_offset__plan0.xml @@ -24,7 +24,7 @@ - + diff --git a/tests_metricflow/snapshots/test_predicate_pushdown_optimizer.py/DataflowPlan/test_conversion_metric_predicate_pushdown__dfp_0.xml b/tests_metricflow/snapshots/test_predicate_pushdown_optimizer.py/DataflowPlan/test_conversion_metric_predicate_pushdown__dfp_0.xml index 7ad32f714a..dd1ef50a0c 100644 --- a/tests_metricflow/snapshots/test_predicate_pushdown_optimizer.py/DataflowPlan/test_conversion_metric_predicate_pushdown__dfp_0.xml +++ b/tests_metricflow/snapshots/test_predicate_pushdown_optimizer.py/DataflowPlan/test_conversion_metric_predicate_pushdown__dfp_0.xml @@ -5,50 +5,54 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests_metricflow/snapshots/test_predicate_pushdown_optimizer.py/DataflowPlan/test_conversion_metric_predicate_pushdown__dfpo_0.xml b/tests_metricflow/snapshots/test_predicate_pushdown_optimizer.py/DataflowPlan/test_conversion_metric_predicate_pushdown__dfpo_0.xml index d35f059305..f7025ddb5e 100644 --- a/tests_metricflow/snapshots/test_predicate_pushdown_optimizer.py/DataflowPlan/test_conversion_metric_predicate_pushdown__dfpo_0.xml +++ b/tests_metricflow/snapshots/test_predicate_pushdown_optimizer.py/DataflowPlan/test_conversion_metric_predicate_pushdown__dfpo_0.xml @@ -5,50 +5,54 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests_metricflow/snapshots/test_predicate_pushdown_optimizer.py/DataflowPlan/test_cumulative_metric_predicate_pushdown__dfp_0.xml b/tests_metricflow/snapshots/test_predicate_pushdown_optimizer.py/DataflowPlan/test_cumulative_metric_predicate_pushdown__dfp_0.xml index c31c343de1..4185ec4345 100644 --- a/tests_metricflow/snapshots/test_predicate_pushdown_optimizer.py/DataflowPlan/test_cumulative_metric_predicate_pushdown__dfp_0.xml +++ b/tests_metricflow/snapshots/test_predicate_pushdown_optimizer.py/DataflowPlan/test_cumulative_metric_predicate_pushdown__dfp_0.xml @@ -5,50 +5,54 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests_metricflow/snapshots/test_predicate_pushdown_optimizer.py/DataflowPlan/test_cumulative_metric_predicate_pushdown__dfpo_0.xml b/tests_metricflow/snapshots/test_predicate_pushdown_optimizer.py/DataflowPlan/test_cumulative_metric_predicate_pushdown__dfpo_0.xml index 42a4942691..2c30b359e4 100644 --- a/tests_metricflow/snapshots/test_predicate_pushdown_optimizer.py/DataflowPlan/test_cumulative_metric_predicate_pushdown__dfpo_0.xml +++ b/tests_metricflow/snapshots/test_predicate_pushdown_optimizer.py/DataflowPlan/test_cumulative_metric_predicate_pushdown__dfpo_0.xml @@ -5,50 +5,54 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests_metricflow/snapshots/test_predicate_pushdown_optimizer.py/DataflowPlan/test_fill_nulls_time_spine_metric_predicate_pushdown__dfp_0.xml b/tests_metricflow/snapshots/test_predicate_pushdown_optimizer.py/DataflowPlan/test_fill_nulls_time_spine_metric_predicate_pushdown__dfp_0.xml index 6ddc35d3b2..29f3109850 100644 --- a/tests_metricflow/snapshots/test_predicate_pushdown_optimizer.py/DataflowPlan/test_fill_nulls_time_spine_metric_predicate_pushdown__dfp_0.xml +++ b/tests_metricflow/snapshots/test_predicate_pushdown_optimizer.py/DataflowPlan/test_fill_nulls_time_spine_metric_predicate_pushdown__dfp_0.xml @@ -5,100 +5,108 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -270,52 +278,56 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests_metricflow/snapshots/test_predicate_pushdown_optimizer.py/DataflowPlan/test_fill_nulls_time_spine_metric_predicate_pushdown__dfpo_0.xml b/tests_metricflow/snapshots/test_predicate_pushdown_optimizer.py/DataflowPlan/test_fill_nulls_time_spine_metric_predicate_pushdown__dfpo_0.xml index 29aa9318d9..6bf27175d8 100644 --- a/tests_metricflow/snapshots/test_predicate_pushdown_optimizer.py/DataflowPlan/test_fill_nulls_time_spine_metric_predicate_pushdown__dfpo_0.xml +++ b/tests_metricflow/snapshots/test_predicate_pushdown_optimizer.py/DataflowPlan/test_fill_nulls_time_spine_metric_predicate_pushdown__dfpo_0.xml @@ -5,100 +5,108 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -269,52 +277,56 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests_metricflow/snapshots/test_predicate_pushdown_optimizer.py/DataflowPlan/test_fill_nulls_time_spine_metric_with_post_agg_join_predicate_pushdown__dfp_0.xml b/tests_metricflow/snapshots/test_predicate_pushdown_optimizer.py/DataflowPlan/test_fill_nulls_time_spine_metric_with_post_agg_join_predicate_pushdown__dfp_0.xml index 3da28f6b88..a81250fadc 100644 --- a/tests_metricflow/snapshots/test_predicate_pushdown_optimizer.py/DataflowPlan/test_fill_nulls_time_spine_metric_with_post_agg_join_predicate_pushdown__dfp_0.xml +++ b/tests_metricflow/snapshots/test_predicate_pushdown_optimizer.py/DataflowPlan/test_fill_nulls_time_spine_metric_with_post_agg_join_predicate_pushdown__dfp_0.xml @@ -5,100 +5,108 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -297,52 +305,56 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests_metricflow/snapshots/test_predicate_pushdown_optimizer.py/DataflowPlan/test_fill_nulls_time_spine_metric_with_post_agg_join_predicate_pushdown__dfpo_0.xml b/tests_metricflow/snapshots/test_predicate_pushdown_optimizer.py/DataflowPlan/test_fill_nulls_time_spine_metric_with_post_agg_join_predicate_pushdown__dfpo_0.xml index 95f2d06915..3590143536 100644 --- a/tests_metricflow/snapshots/test_predicate_pushdown_optimizer.py/DataflowPlan/test_fill_nulls_time_spine_metric_with_post_agg_join_predicate_pushdown__dfpo_0.xml +++ b/tests_metricflow/snapshots/test_predicate_pushdown_optimizer.py/DataflowPlan/test_fill_nulls_time_spine_metric_with_post_agg_join_predicate_pushdown__dfpo_0.xml @@ -5,100 +5,108 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -296,52 +304,56 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests_metricflow/snapshots/test_predicate_pushdown_optimizer.py/DataflowPlan/test_offset_metric_predicate_pushdown__dfp_0.xml b/tests_metricflow/snapshots/test_predicate_pushdown_optimizer.py/DataflowPlan/test_offset_metric_predicate_pushdown__dfp_0.xml index c0e8831b43..c95f71a2fb 100644 --- a/tests_metricflow/snapshots/test_predicate_pushdown_optimizer.py/DataflowPlan/test_offset_metric_predicate_pushdown__dfp_0.xml +++ b/tests_metricflow/snapshots/test_predicate_pushdown_optimizer.py/DataflowPlan/test_offset_metric_predicate_pushdown__dfp_0.xml @@ -5,100 +5,108 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -251,52 +259,56 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests_metricflow/snapshots/test_predicate_pushdown_optimizer.py/DataflowPlan/test_offset_metric_predicate_pushdown__dfpo_0.xml b/tests_metricflow/snapshots/test_predicate_pushdown_optimizer.py/DataflowPlan/test_offset_metric_predicate_pushdown__dfpo_0.xml index 2fe9b2919b..9bac28617d 100644 --- a/tests_metricflow/snapshots/test_predicate_pushdown_optimizer.py/DataflowPlan/test_offset_metric_predicate_pushdown__dfpo_0.xml +++ b/tests_metricflow/snapshots/test_predicate_pushdown_optimizer.py/DataflowPlan/test_offset_metric_predicate_pushdown__dfpo_0.xml @@ -5,100 +5,108 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -250,52 +258,56 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests_metricflow/snapshots/test_predicate_pushdown_optimizer.py/DataflowPlan/test_simple_join_categorical_pushdown__dfp_0.xml b/tests_metricflow/snapshots/test_predicate_pushdown_optimizer.py/DataflowPlan/test_simple_join_categorical_pushdown__dfp_0.xml index 2070c49cf8..35911247bb 100644 --- a/tests_metricflow/snapshots/test_predicate_pushdown_optimizer.py/DataflowPlan/test_simple_join_categorical_pushdown__dfp_0.xml +++ b/tests_metricflow/snapshots/test_predicate_pushdown_optimizer.py/DataflowPlan/test_simple_join_categorical_pushdown__dfp_0.xml @@ -5,50 +5,54 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests_metricflow/snapshots/test_predicate_pushdown_optimizer.py/DataflowPlan/test_simple_join_categorical_pushdown__dfpo_0.xml b/tests_metricflow/snapshots/test_predicate_pushdown_optimizer.py/DataflowPlan/test_simple_join_categorical_pushdown__dfpo_0.xml index 33876637a4..f4ee63c16c 100644 --- a/tests_metricflow/snapshots/test_predicate_pushdown_optimizer.py/DataflowPlan/test_simple_join_categorical_pushdown__dfpo_0.xml +++ b/tests_metricflow/snapshots/test_predicate_pushdown_optimizer.py/DataflowPlan/test_simple_join_categorical_pushdown__dfpo_0.xml @@ -5,50 +5,54 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests_metricflow/snapshots/test_predicate_pushdown_optimizer.py/DataflowPlan/test_simple_join_metric_time_pushdown_with_two_targets__dfp_0.xml b/tests_metricflow/snapshots/test_predicate_pushdown_optimizer.py/DataflowPlan/test_simple_join_metric_time_pushdown_with_two_targets__dfp_0.xml index a96be3d209..89067544b1 100644 --- a/tests_metricflow/snapshots/test_predicate_pushdown_optimizer.py/DataflowPlan/test_simple_join_metric_time_pushdown_with_two_targets__dfp_0.xml +++ b/tests_metricflow/snapshots/test_predicate_pushdown_optimizer.py/DataflowPlan/test_simple_join_metric_time_pushdown_with_two_targets__dfp_0.xml @@ -5,48 +5,52 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests_metricflow/snapshots/test_predicate_pushdown_optimizer.py/DataflowPlan/test_simple_join_metric_time_pushdown_with_two_targets__dfpo_0.xml b/tests_metricflow/snapshots/test_predicate_pushdown_optimizer.py/DataflowPlan/test_simple_join_metric_time_pushdown_with_two_targets__dfpo_0.xml index e1a03ea3a2..d53580b70e 100644 --- a/tests_metricflow/snapshots/test_predicate_pushdown_optimizer.py/DataflowPlan/test_simple_join_metric_time_pushdown_with_two_targets__dfpo_0.xml +++ b/tests_metricflow/snapshots/test_predicate_pushdown_optimizer.py/DataflowPlan/test_simple_join_metric_time_pushdown_with_two_targets__dfpo_0.xml @@ -5,48 +5,52 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests_metricflow/snapshots/test_source_scan_optimizer.py/DataflowPlan/test_2_metrics_from_1_semantic_model__dfp_0.xml b/tests_metricflow/snapshots/test_source_scan_optimizer.py/DataflowPlan/test_2_metrics_from_1_semantic_model__dfp_0.xml index a858d37305..35a23c550a 100644 --- a/tests_metricflow/snapshots/test_source_scan_optimizer.py/DataflowPlan/test_2_metrics_from_1_semantic_model__dfp_0.xml +++ b/tests_metricflow/snapshots/test_source_scan_optimizer.py/DataflowPlan/test_2_metrics_from_1_semantic_model__dfp_0.xml @@ -8,7 +8,7 @@ - + @@ -83,7 +83,7 @@ - + diff --git a/tests_metricflow/snapshots/test_source_scan_optimizer.py/DataflowPlan/test_2_metrics_from_1_semantic_model__dfpo_0.xml b/tests_metricflow/snapshots/test_source_scan_optimizer.py/DataflowPlan/test_2_metrics_from_1_semantic_model__dfpo_0.xml index 8eb95c772c..3f01d31cea 100644 --- a/tests_metricflow/snapshots/test_source_scan_optimizer.py/DataflowPlan/test_2_metrics_from_1_semantic_model__dfpo_0.xml +++ b/tests_metricflow/snapshots/test_source_scan_optimizer.py/DataflowPlan/test_2_metrics_from_1_semantic_model__dfpo_0.xml @@ -5,8 +5,8 @@ - - + + diff --git a/tests_metricflow/snapshots/test_source_scan_optimizer.py/DataflowPlan/test_2_metrics_from_2_semantic_models__dfp_0.xml b/tests_metricflow/snapshots/test_source_scan_optimizer.py/DataflowPlan/test_2_metrics_from_2_semantic_models__dfp_0.xml index 08f4c08b7c..d4303fed87 100644 --- a/tests_metricflow/snapshots/test_source_scan_optimizer.py/DataflowPlan/test_2_metrics_from_2_semantic_models__dfp_0.xml +++ b/tests_metricflow/snapshots/test_source_scan_optimizer.py/DataflowPlan/test_2_metrics_from_2_semantic_models__dfp_0.xml @@ -8,7 +8,7 @@ - + @@ -38,7 +38,7 @@ - + diff --git a/tests_metricflow/snapshots/test_source_scan_optimizer.py/DataflowPlan/test_2_metrics_from_2_semantic_models__dfpo_0.xml b/tests_metricflow/snapshots/test_source_scan_optimizer.py/DataflowPlan/test_2_metrics_from_2_semantic_models__dfpo_0.xml index 3a71422521..edabef3987 100644 --- a/tests_metricflow/snapshots/test_source_scan_optimizer.py/DataflowPlan/test_2_metrics_from_2_semantic_models__dfpo_0.xml +++ b/tests_metricflow/snapshots/test_source_scan_optimizer.py/DataflowPlan/test_2_metrics_from_2_semantic_models__dfpo_0.xml @@ -8,7 +8,7 @@ - + @@ -38,7 +38,7 @@ - + diff --git a/tests_metricflow/snapshots/test_source_scan_optimizer.py/DataflowPlan/test_2_ratio_metrics_from_1_semantic_model__dfp_0.xml b/tests_metricflow/snapshots/test_source_scan_optimizer.py/DataflowPlan/test_2_ratio_metrics_from_1_semantic_model__dfp_0.xml index 250532a51b..dc62d027e6 100644 --- a/tests_metricflow/snapshots/test_source_scan_optimizer.py/DataflowPlan/test_2_ratio_metrics_from_1_semantic_model__dfp_0.xml +++ b/tests_metricflow/snapshots/test_source_scan_optimizer.py/DataflowPlan/test_2_ratio_metrics_from_1_semantic_model__dfp_0.xml @@ -8,14 +8,14 @@ - + - + @@ -45,7 +45,7 @@ - + @@ -77,14 +77,14 @@ - + - + @@ -114,7 +114,8 @@ - + + diff --git a/tests_metricflow/snapshots/test_source_scan_optimizer.py/DataflowPlan/test_2_ratio_metrics_from_1_semantic_model__dfpo_0.xml b/tests_metricflow/snapshots/test_source_scan_optimizer.py/DataflowPlan/test_2_ratio_metrics_from_1_semantic_model__dfpo_0.xml index e1d9cc33e6..013fd42bb7 100644 --- a/tests_metricflow/snapshots/test_source_scan_optimizer.py/DataflowPlan/test_2_ratio_metrics_from_1_semantic_model__dfpo_0.xml +++ b/tests_metricflow/snapshots/test_source_scan_optimizer.py/DataflowPlan/test_2_ratio_metrics_from_1_semantic_model__dfpo_0.xml @@ -5,14 +5,14 @@ - - + + - - - + + + diff --git a/tests_metricflow/snapshots/test_source_scan_optimizer.py/DataflowPlan/test_3_metrics_from_2_semantic_models__dfp_0.xml b/tests_metricflow/snapshots/test_source_scan_optimizer.py/DataflowPlan/test_3_metrics_from_2_semantic_models__dfp_0.xml index 361d5828ef..3b6cfa44be 100644 --- a/tests_metricflow/snapshots/test_source_scan_optimizer.py/DataflowPlan/test_3_metrics_from_2_semantic_models__dfp_0.xml +++ b/tests_metricflow/snapshots/test_source_scan_optimizer.py/DataflowPlan/test_3_metrics_from_2_semantic_models__dfp_0.xml @@ -8,7 +8,7 @@ - + @@ -38,7 +38,7 @@ - + @@ -68,7 +68,7 @@ - + diff --git a/tests_metricflow/snapshots/test_source_scan_optimizer.py/DataflowPlan/test_3_metrics_from_2_semantic_models__dfpo_0.xml b/tests_metricflow/snapshots/test_source_scan_optimizer.py/DataflowPlan/test_3_metrics_from_2_semantic_models__dfpo_0.xml index f1e91edd7e..1c1297dfff 100644 --- a/tests_metricflow/snapshots/test_source_scan_optimizer.py/DataflowPlan/test_3_metrics_from_2_semantic_models__dfpo_0.xml +++ b/tests_metricflow/snapshots/test_source_scan_optimizer.py/DataflowPlan/test_3_metrics_from_2_semantic_models__dfpo_0.xml @@ -8,8 +8,8 @@ - - + + @@ -40,7 +40,7 @@ - + diff --git a/tests_metricflow/snapshots/test_source_scan_optimizer.py/DataflowPlan/test_constrained_metric_not_combined__dfp_0.xml b/tests_metricflow/snapshots/test_source_scan_optimizer.py/DataflowPlan/test_constrained_metric_not_combined__dfp_0.xml index 23dcf84f95..44aaaa6fca 100644 --- a/tests_metricflow/snapshots/test_source_scan_optimizer.py/DataflowPlan/test_constrained_metric_not_combined__dfp_0.xml +++ b/tests_metricflow/snapshots/test_source_scan_optimizer.py/DataflowPlan/test_constrained_metric_not_combined__dfp_0.xml @@ -8,7 +8,7 @@ - + @@ -38,7 +38,8 @@ - + + diff --git a/tests_metricflow/snapshots/test_source_scan_optimizer.py/DataflowPlan/test_constrained_metric_not_combined__dfpo_0.xml b/tests_metricflow/snapshots/test_source_scan_optimizer.py/DataflowPlan/test_constrained_metric_not_combined__dfpo_0.xml index 950ea86ea8..8aa2d0415c 100644 --- a/tests_metricflow/snapshots/test_source_scan_optimizer.py/DataflowPlan/test_constrained_metric_not_combined__dfpo_0.xml +++ b/tests_metricflow/snapshots/test_source_scan_optimizer.py/DataflowPlan/test_constrained_metric_not_combined__dfpo_0.xml @@ -8,7 +8,7 @@ - + @@ -38,7 +38,8 @@ - + + diff --git a/tests_metricflow/snapshots/test_source_scan_optimizer.py/DataflowPlan/test_derived_metric__dfp_0.xml b/tests_metricflow/snapshots/test_source_scan_optimizer.py/DataflowPlan/test_derived_metric__dfp_0.xml index 072ac54f7f..f87c5f1f3e 100644 --- a/tests_metricflow/snapshots/test_source_scan_optimizer.py/DataflowPlan/test_derived_metric__dfp_0.xml +++ b/tests_metricflow/snapshots/test_source_scan_optimizer.py/DataflowPlan/test_derived_metric__dfp_0.xml @@ -5,14 +5,20 @@ - + + - + + + + + + @@ -42,7 +48,7 @@ - + diff --git a/tests_metricflow/snapshots/test_source_scan_optimizer.py/DataflowPlan/test_derived_metric__dfpo_0.xml b/tests_metricflow/snapshots/test_source_scan_optimizer.py/DataflowPlan/test_derived_metric__dfpo_0.xml index 7f26acf6e3..c473b8dc01 100644 --- a/tests_metricflow/snapshots/test_source_scan_optimizer.py/DataflowPlan/test_derived_metric__dfpo_0.xml +++ b/tests_metricflow/snapshots/test_source_scan_optimizer.py/DataflowPlan/test_derived_metric__dfpo_0.xml @@ -5,12 +5,18 @@ - + + - - + + + + + + + diff --git a/tests_metricflow/snapshots/test_source_scan_optimizer.py/DataflowPlan/test_derived_metric_with_non_derived_metric__dfp_0.xml b/tests_metricflow/snapshots/test_source_scan_optimizer.py/DataflowPlan/test_derived_metric_with_non_derived_metric__dfp_0.xml index 83aeaf2599..9cd778e018 100644 --- a/tests_metricflow/snapshots/test_source_scan_optimizer.py/DataflowPlan/test_derived_metric_with_non_derived_metric__dfp_0.xml +++ b/tests_metricflow/snapshots/test_source_scan_optimizer.py/DataflowPlan/test_derived_metric_with_non_derived_metric__dfp_0.xml @@ -8,7 +8,7 @@ - + @@ -38,14 +38,20 @@ - + + - + + + + + + @@ -75,7 +81,7 @@ - + diff --git a/tests_metricflow/snapshots/test_source_scan_optimizer.py/DataflowPlan/test_derived_metric_with_non_derived_metric__dfpo_0.xml b/tests_metricflow/snapshots/test_source_scan_optimizer.py/DataflowPlan/test_derived_metric_with_non_derived_metric__dfpo_0.xml index 50934e5b2c..b2957206d9 100644 --- a/tests_metricflow/snapshots/test_source_scan_optimizer.py/DataflowPlan/test_derived_metric_with_non_derived_metric__dfpo_0.xml +++ b/tests_metricflow/snapshots/test_source_scan_optimizer.py/DataflowPlan/test_derived_metric_with_non_derived_metric__dfpo_0.xml @@ -8,7 +8,7 @@ - + @@ -38,12 +38,18 @@ - + + - - + + + + + + + diff --git a/tests_metricflow/snapshots/test_source_scan_optimizer.py/DataflowPlan/test_duplicate_measures__dfp_0.xml b/tests_metricflow/snapshots/test_source_scan_optimizer.py/DataflowPlan/test_duplicate_measures__dfp_0.xml index 70206579ae..d6799bd36e 100644 --- a/tests_metricflow/snapshots/test_source_scan_optimizer.py/DataflowPlan/test_duplicate_measures__dfp_0.xml +++ b/tests_metricflow/snapshots/test_source_scan_optimizer.py/DataflowPlan/test_duplicate_measures__dfp_0.xml @@ -8,11 +8,11 @@ - + - + @@ -43,11 +43,11 @@ - + - + diff --git a/tests_metricflow/snapshots/test_source_scan_optimizer.py/DataflowPlan/test_duplicate_measures__dfpo_0.xml b/tests_metricflow/snapshots/test_source_scan_optimizer.py/DataflowPlan/test_duplicate_measures__dfpo_0.xml index ae4de4f369..87336d0655 100644 --- a/tests_metricflow/snapshots/test_source_scan_optimizer.py/DataflowPlan/test_duplicate_measures__dfpo_0.xml +++ b/tests_metricflow/snapshots/test_source_scan_optimizer.py/DataflowPlan/test_duplicate_measures__dfpo_0.xml @@ -5,12 +5,12 @@ - - + + - + diff --git a/tests_metricflow/snapshots/test_source_scan_optimizer.py/DataflowPlan/test_nested_derived_metric__dfp_0.xml b/tests_metricflow/snapshots/test_source_scan_optimizer.py/DataflowPlan/test_nested_derived_metric__dfp_0.xml index f3d7f7cb2b..dbb5e43e68 100644 --- a/tests_metricflow/snapshots/test_source_scan_optimizer.py/DataflowPlan/test_nested_derived_metric__dfp_0.xml +++ b/tests_metricflow/snapshots/test_source_scan_optimizer.py/DataflowPlan/test_nested_derived_metric__dfp_0.xml @@ -5,21 +5,32 @@ - + + - + + + + + + - + + + + + + @@ -49,7 +60,7 @@ - + @@ -81,7 +92,12 @@ - + + + + + + @@ -111,7 +127,7 @@ - + diff --git a/tests_metricflow/snapshots/test_source_scan_optimizer.py/DataflowPlan/test_nested_derived_metric__dfpo_0.xml b/tests_metricflow/snapshots/test_source_scan_optimizer.py/DataflowPlan/test_nested_derived_metric__dfpo_0.xml index cd517b382c..01876f368b 100644 --- a/tests_metricflow/snapshots/test_source_scan_optimizer.py/DataflowPlan/test_nested_derived_metric__dfpo_0.xml +++ b/tests_metricflow/snapshots/test_source_scan_optimizer.py/DataflowPlan/test_nested_derived_metric__dfpo_0.xml @@ -5,19 +5,30 @@ - + + - + + + + + + - - + + + + + + + @@ -50,8 +61,13 @@ - - + + + + + + + diff --git a/tests_metricflow/snapshots/test_time_spine_join_rendering.py/SqlQueryPlan/BigQuery/test_join_to_time_spine_with_input_measure_constraint__plan0.sql b/tests_metricflow/snapshots/test_time_spine_join_rendering.py/SqlQueryPlan/BigQuery/test_join_to_time_spine_with_input_measure_constraint__plan0.sql new file mode 100644 index 0000000000..2c3e9c9fbe --- /dev/null +++ b/tests_metricflow/snapshots/test_time_spine_join_rendering.py/SqlQueryPlan/BigQuery/test_join_to_time_spine_with_input_measure_constraint__plan0.sql @@ -0,0 +1,257 @@ +-- Compute Metrics via Expressions +SELECT + subq_9.metric_time__day + , subq_9.booking__is_instant + , subq_9.bookings AS instant_bookings_with_measure_filter +FROM ( + -- Constrain Output with WHERE + SELECT + subq_8.metric_time__day + , subq_8.booking__is_instant + , subq_8.bookings + FROM ( + -- Join to Time Spine Dataset + SELECT + subq_6.metric_time__day AS metric_time__day + , subq_5.booking__is_instant AS booking__is_instant + , subq_5.bookings AS bookings + FROM ( + -- Time Spine + SELECT + subq_7.ds AS metric_time__day + FROM ***************************.mf_time_spine subq_7 + ) subq_6 + LEFT OUTER JOIN ( + -- Aggregate Measures + SELECT + subq_4.metric_time__day + , subq_4.booking__is_instant + , SUM(subq_4.bookings) AS bookings + FROM ( + -- Pass Only Elements: ['bookings', 'booking__is_instant', 'metric_time__day'] + SELECT + subq_3.metric_time__day + , subq_3.booking__is_instant + , subq_3.bookings + FROM ( + -- Constrain Output with WHERE + SELECT + subq_2.metric_time__day + , subq_2.listing + , subq_2.booking__is_instant + , subq_2.bookings + FROM ( + -- Pass Only Elements: ['bookings', 'booking__is_instant', 'metric_time__day', 'listing'] + SELECT + subq_1.metric_time__day + , subq_1.listing + , subq_1.booking__is_instant + , subq_1.bookings + FROM ( + -- Metric Time Dimension 'ds' + SELECT + subq_0.ds__day + , subq_0.ds__week + , subq_0.ds__month + , subq_0.ds__quarter + , subq_0.ds__year + , subq_0.ds__extract_year + , subq_0.ds__extract_quarter + , subq_0.ds__extract_month + , subq_0.ds__extract_day + , subq_0.ds__extract_dow + , subq_0.ds__extract_doy + , subq_0.ds_partitioned__day + , subq_0.ds_partitioned__week + , subq_0.ds_partitioned__month + , subq_0.ds_partitioned__quarter + , subq_0.ds_partitioned__year + , subq_0.ds_partitioned__extract_year + , subq_0.ds_partitioned__extract_quarter + , subq_0.ds_partitioned__extract_month + , subq_0.ds_partitioned__extract_day + , subq_0.ds_partitioned__extract_dow + , subq_0.ds_partitioned__extract_doy + , subq_0.paid_at__day + , subq_0.paid_at__week + , subq_0.paid_at__month + , subq_0.paid_at__quarter + , subq_0.paid_at__year + , subq_0.paid_at__extract_year + , subq_0.paid_at__extract_quarter + , subq_0.paid_at__extract_month + , subq_0.paid_at__extract_day + , subq_0.paid_at__extract_dow + , subq_0.paid_at__extract_doy + , subq_0.booking__ds__day + , subq_0.booking__ds__week + , subq_0.booking__ds__month + , subq_0.booking__ds__quarter + , subq_0.booking__ds__year + , subq_0.booking__ds__extract_year + , subq_0.booking__ds__extract_quarter + , subq_0.booking__ds__extract_month + , subq_0.booking__ds__extract_day + , subq_0.booking__ds__extract_dow + , subq_0.booking__ds__extract_doy + , subq_0.booking__ds_partitioned__day + , subq_0.booking__ds_partitioned__week + , subq_0.booking__ds_partitioned__month + , subq_0.booking__ds_partitioned__quarter + , subq_0.booking__ds_partitioned__year + , subq_0.booking__ds_partitioned__extract_year + , subq_0.booking__ds_partitioned__extract_quarter + , subq_0.booking__ds_partitioned__extract_month + , subq_0.booking__ds_partitioned__extract_day + , subq_0.booking__ds_partitioned__extract_dow + , subq_0.booking__ds_partitioned__extract_doy + , subq_0.booking__paid_at__day + , subq_0.booking__paid_at__week + , subq_0.booking__paid_at__month + , subq_0.booking__paid_at__quarter + , subq_0.booking__paid_at__year + , subq_0.booking__paid_at__extract_year + , subq_0.booking__paid_at__extract_quarter + , subq_0.booking__paid_at__extract_month + , subq_0.booking__paid_at__extract_day + , subq_0.booking__paid_at__extract_dow + , subq_0.booking__paid_at__extract_doy + , subq_0.ds__day AS metric_time__day + , subq_0.ds__week AS metric_time__week + , subq_0.ds__month AS metric_time__month + , subq_0.ds__quarter AS metric_time__quarter + , subq_0.ds__year AS metric_time__year + , subq_0.ds__extract_year AS metric_time__extract_year + , subq_0.ds__extract_quarter AS metric_time__extract_quarter + , subq_0.ds__extract_month AS metric_time__extract_month + , subq_0.ds__extract_day AS metric_time__extract_day + , subq_0.ds__extract_dow AS metric_time__extract_dow + , subq_0.ds__extract_doy AS metric_time__extract_doy + , subq_0.listing + , subq_0.guest + , subq_0.host + , subq_0.booking__listing + , subq_0.booking__guest + , subq_0.booking__host + , subq_0.is_instant + , subq_0.booking__is_instant + , subq_0.bookings + , subq_0.instant_bookings + , subq_0.booking_value + , subq_0.max_booking_value + , subq_0.min_booking_value + , subq_0.bookers + , subq_0.average_booking_value + , subq_0.referred_bookings + , subq_0.median_booking_value + , subq_0.booking_value_p99 + , subq_0.discrete_booking_value_p99 + , subq_0.approximate_continuous_booking_value_p99 + , subq_0.approximate_discrete_booking_value_p99 + FROM ( + -- Read Elements From Semantic Model 'bookings_source' + SELECT + 1 AS bookings + , CASE WHEN is_instant THEN 1 ELSE 0 END AS instant_bookings + , bookings_source_src_28000.booking_value + , bookings_source_src_28000.booking_value AS max_booking_value + , bookings_source_src_28000.booking_value AS min_booking_value + , bookings_source_src_28000.guest_id AS bookers + , bookings_source_src_28000.booking_value AS average_booking_value + , bookings_source_src_28000.booking_value AS booking_payments + , CASE WHEN referrer_id IS NOT NULL THEN 1 ELSE 0 END AS referred_bookings + , bookings_source_src_28000.booking_value AS median_booking_value + , bookings_source_src_28000.booking_value AS booking_value_p99 + , bookings_source_src_28000.booking_value AS discrete_booking_value_p99 + , bookings_source_src_28000.booking_value AS approximate_continuous_booking_value_p99 + , bookings_source_src_28000.booking_value AS approximate_discrete_booking_value_p99 + , bookings_source_src_28000.is_instant + , DATETIME_TRUNC(bookings_source_src_28000.ds, day) AS ds__day + , DATETIME_TRUNC(bookings_source_src_28000.ds, isoweek) AS ds__week + , DATETIME_TRUNC(bookings_source_src_28000.ds, month) AS ds__month + , DATETIME_TRUNC(bookings_source_src_28000.ds, quarter) AS ds__quarter + , DATETIME_TRUNC(bookings_source_src_28000.ds, year) AS ds__year + , EXTRACT(year FROM bookings_source_src_28000.ds) AS ds__extract_year + , EXTRACT(quarter FROM bookings_source_src_28000.ds) AS ds__extract_quarter + , EXTRACT(month FROM bookings_source_src_28000.ds) AS ds__extract_month + , EXTRACT(day FROM bookings_source_src_28000.ds) AS ds__extract_day + , IF(EXTRACT(dayofweek FROM bookings_source_src_28000.ds) = 1, 7, EXTRACT(dayofweek FROM bookings_source_src_28000.ds) - 1) AS ds__extract_dow + , EXTRACT(dayofyear FROM bookings_source_src_28000.ds) AS ds__extract_doy + , DATETIME_TRUNC(bookings_source_src_28000.ds_partitioned, day) AS ds_partitioned__day + , DATETIME_TRUNC(bookings_source_src_28000.ds_partitioned, isoweek) AS ds_partitioned__week + , DATETIME_TRUNC(bookings_source_src_28000.ds_partitioned, month) AS ds_partitioned__month + , DATETIME_TRUNC(bookings_source_src_28000.ds_partitioned, quarter) AS ds_partitioned__quarter + , DATETIME_TRUNC(bookings_source_src_28000.ds_partitioned, year) AS ds_partitioned__year + , EXTRACT(year FROM bookings_source_src_28000.ds_partitioned) AS ds_partitioned__extract_year + , EXTRACT(quarter FROM bookings_source_src_28000.ds_partitioned) AS ds_partitioned__extract_quarter + , EXTRACT(month FROM bookings_source_src_28000.ds_partitioned) AS ds_partitioned__extract_month + , EXTRACT(day FROM bookings_source_src_28000.ds_partitioned) AS ds_partitioned__extract_day + , IF(EXTRACT(dayofweek FROM bookings_source_src_28000.ds_partitioned) = 1, 7, EXTRACT(dayofweek FROM bookings_source_src_28000.ds_partitioned) - 1) AS ds_partitioned__extract_dow + , EXTRACT(dayofyear FROM bookings_source_src_28000.ds_partitioned) AS ds_partitioned__extract_doy + , DATETIME_TRUNC(bookings_source_src_28000.paid_at, day) AS paid_at__day + , DATETIME_TRUNC(bookings_source_src_28000.paid_at, isoweek) AS paid_at__week + , DATETIME_TRUNC(bookings_source_src_28000.paid_at, month) AS paid_at__month + , DATETIME_TRUNC(bookings_source_src_28000.paid_at, quarter) AS paid_at__quarter + , DATETIME_TRUNC(bookings_source_src_28000.paid_at, year) AS paid_at__year + , EXTRACT(year FROM bookings_source_src_28000.paid_at) AS paid_at__extract_year + , EXTRACT(quarter FROM bookings_source_src_28000.paid_at) AS paid_at__extract_quarter + , EXTRACT(month FROM bookings_source_src_28000.paid_at) AS paid_at__extract_month + , EXTRACT(day FROM bookings_source_src_28000.paid_at) AS paid_at__extract_day + , IF(EXTRACT(dayofweek FROM bookings_source_src_28000.paid_at) = 1, 7, EXTRACT(dayofweek FROM bookings_source_src_28000.paid_at) - 1) AS paid_at__extract_dow + , EXTRACT(dayofyear FROM bookings_source_src_28000.paid_at) AS paid_at__extract_doy + , bookings_source_src_28000.is_instant AS booking__is_instant + , DATETIME_TRUNC(bookings_source_src_28000.ds, day) AS booking__ds__day + , DATETIME_TRUNC(bookings_source_src_28000.ds, isoweek) AS booking__ds__week + , DATETIME_TRUNC(bookings_source_src_28000.ds, month) AS booking__ds__month + , DATETIME_TRUNC(bookings_source_src_28000.ds, quarter) AS booking__ds__quarter + , DATETIME_TRUNC(bookings_source_src_28000.ds, year) AS booking__ds__year + , EXTRACT(year FROM bookings_source_src_28000.ds) AS booking__ds__extract_year + , EXTRACT(quarter FROM bookings_source_src_28000.ds) AS booking__ds__extract_quarter + , EXTRACT(month FROM bookings_source_src_28000.ds) AS booking__ds__extract_month + , EXTRACT(day FROM bookings_source_src_28000.ds) AS booking__ds__extract_day + , IF(EXTRACT(dayofweek FROM bookings_source_src_28000.ds) = 1, 7, EXTRACT(dayofweek FROM bookings_source_src_28000.ds) - 1) AS booking__ds__extract_dow + , EXTRACT(dayofyear FROM bookings_source_src_28000.ds) AS booking__ds__extract_doy + , DATETIME_TRUNC(bookings_source_src_28000.ds_partitioned, day) AS booking__ds_partitioned__day + , DATETIME_TRUNC(bookings_source_src_28000.ds_partitioned, isoweek) AS booking__ds_partitioned__week + , DATETIME_TRUNC(bookings_source_src_28000.ds_partitioned, month) AS booking__ds_partitioned__month + , DATETIME_TRUNC(bookings_source_src_28000.ds_partitioned, quarter) AS booking__ds_partitioned__quarter + , DATETIME_TRUNC(bookings_source_src_28000.ds_partitioned, year) AS booking__ds_partitioned__year + , EXTRACT(year FROM bookings_source_src_28000.ds_partitioned) AS booking__ds_partitioned__extract_year + , EXTRACT(quarter FROM bookings_source_src_28000.ds_partitioned) AS booking__ds_partitioned__extract_quarter + , EXTRACT(month FROM bookings_source_src_28000.ds_partitioned) AS booking__ds_partitioned__extract_month + , EXTRACT(day FROM bookings_source_src_28000.ds_partitioned) AS booking__ds_partitioned__extract_day + , IF(EXTRACT(dayofweek FROM bookings_source_src_28000.ds_partitioned) = 1, 7, EXTRACT(dayofweek FROM bookings_source_src_28000.ds_partitioned) - 1) AS booking__ds_partitioned__extract_dow + , EXTRACT(dayofyear FROM bookings_source_src_28000.ds_partitioned) AS booking__ds_partitioned__extract_doy + , DATETIME_TRUNC(bookings_source_src_28000.paid_at, day) AS booking__paid_at__day + , DATETIME_TRUNC(bookings_source_src_28000.paid_at, isoweek) AS booking__paid_at__week + , DATETIME_TRUNC(bookings_source_src_28000.paid_at, month) AS booking__paid_at__month + , DATETIME_TRUNC(bookings_source_src_28000.paid_at, quarter) AS booking__paid_at__quarter + , DATETIME_TRUNC(bookings_source_src_28000.paid_at, year) AS booking__paid_at__year + , EXTRACT(year FROM bookings_source_src_28000.paid_at) AS booking__paid_at__extract_year + , EXTRACT(quarter FROM bookings_source_src_28000.paid_at) AS booking__paid_at__extract_quarter + , EXTRACT(month FROM bookings_source_src_28000.paid_at) AS booking__paid_at__extract_month + , EXTRACT(day FROM bookings_source_src_28000.paid_at) AS booking__paid_at__extract_day + , IF(EXTRACT(dayofweek FROM bookings_source_src_28000.paid_at) = 1, 7, EXTRACT(dayofweek FROM bookings_source_src_28000.paid_at) - 1) AS booking__paid_at__extract_dow + , EXTRACT(dayofyear FROM bookings_source_src_28000.paid_at) AS booking__paid_at__extract_doy + , bookings_source_src_28000.listing_id AS listing + , bookings_source_src_28000.guest_id AS guest + , bookings_source_src_28000.host_id AS host + , bookings_source_src_28000.listing_id AS booking__listing + , bookings_source_src_28000.guest_id AS booking__guest + , bookings_source_src_28000.host_id AS booking__host + FROM ***************************.fct_bookings bookings_source_src_28000 + ) subq_0 + ) subq_1 + ) subq_2 + WHERE ((booking__is_instant) AND (listing IS NOT NULL)) AND (metric_time__day > '2020-01-01') + ) subq_3 + ) subq_4 + GROUP BY + metric_time__day + , booking__is_instant + ) subq_5 + ON + subq_6.metric_time__day = subq_5.metric_time__day + ) subq_8 + WHERE metric_time__day > '2020-01-01' +) subq_9 diff --git a/tests_metricflow/snapshots/test_time_spine_join_rendering.py/SqlQueryPlan/BigQuery/test_join_to_time_spine_with_input_measure_constraint__plan0_optimized.sql b/tests_metricflow/snapshots/test_time_spine_join_rendering.py/SqlQueryPlan/BigQuery/test_join_to_time_spine_with_input_measure_constraint__plan0_optimized.sql new file mode 100644 index 0000000000..206fbfae89 --- /dev/null +++ b/tests_metricflow/snapshots/test_time_spine_join_rendering.py/SqlQueryPlan/BigQuery/test_join_to_time_spine_with_input_measure_constraint__plan0_optimized.sql @@ -0,0 +1,41 @@ +-- Constrain Output with WHERE +-- Compute Metrics via Expressions +SELECT + metric_time__day + , booking__is_instant + , bookings AS instant_bookings_with_measure_filter +FROM ( + -- Join to Time Spine Dataset + SELECT + subq_17.ds AS metric_time__day + , subq_15.booking__is_instant AS booking__is_instant + , subq_15.bookings AS bookings + FROM ***************************.mf_time_spine subq_17 + LEFT OUTER JOIN ( + -- Constrain Output with WHERE + -- Pass Only Elements: ['bookings', 'booking__is_instant', 'metric_time__day'] + -- Aggregate Measures + SELECT + metric_time__day + , booking__is_instant + , SUM(bookings) AS bookings + FROM ( + -- Read Elements From Semantic Model 'bookings_source' + -- Metric Time Dimension 'ds' + -- Pass Only Elements: ['bookings', 'booking__is_instant', 'metric_time__day', 'listing'] + SELECT + DATETIME_TRUNC(ds, day) AS metric_time__day + , listing_id AS listing + , is_instant AS booking__is_instant + , 1 AS bookings + FROM ***************************.fct_bookings bookings_source_src_28000 + ) subq_12 + WHERE ((booking__is_instant) AND (listing IS NOT NULL)) AND (metric_time__day > '2020-01-01') + GROUP BY + metric_time__day + , booking__is_instant + ) subq_15 + ON + subq_17.ds = subq_15.metric_time__day +) subq_18 +WHERE metric_time__day > '2020-01-01' diff --git a/tests_metricflow/snapshots/test_time_spine_join_rendering.py/SqlQueryPlan/Databricks/test_join_to_time_spine_with_input_measure_constraint__plan0.sql b/tests_metricflow/snapshots/test_time_spine_join_rendering.py/SqlQueryPlan/Databricks/test_join_to_time_spine_with_input_measure_constraint__plan0.sql new file mode 100644 index 0000000000..9e4ebf2de9 --- /dev/null +++ b/tests_metricflow/snapshots/test_time_spine_join_rendering.py/SqlQueryPlan/Databricks/test_join_to_time_spine_with_input_measure_constraint__plan0.sql @@ -0,0 +1,257 @@ +-- Compute Metrics via Expressions +SELECT + subq_9.metric_time__day + , subq_9.booking__is_instant + , subq_9.bookings AS instant_bookings_with_measure_filter +FROM ( + -- Constrain Output with WHERE + SELECT + subq_8.metric_time__day + , subq_8.booking__is_instant + , subq_8.bookings + FROM ( + -- Join to Time Spine Dataset + SELECT + subq_6.metric_time__day AS metric_time__day + , subq_5.booking__is_instant AS booking__is_instant + , subq_5.bookings AS bookings + FROM ( + -- Time Spine + SELECT + subq_7.ds AS metric_time__day + FROM ***************************.mf_time_spine subq_7 + ) subq_6 + LEFT OUTER JOIN ( + -- Aggregate Measures + SELECT + subq_4.metric_time__day + , subq_4.booking__is_instant + , SUM(subq_4.bookings) AS bookings + FROM ( + -- Pass Only Elements: ['bookings', 'booking__is_instant', 'metric_time__day'] + SELECT + subq_3.metric_time__day + , subq_3.booking__is_instant + , subq_3.bookings + FROM ( + -- Constrain Output with WHERE + SELECT + subq_2.metric_time__day + , subq_2.listing + , subq_2.booking__is_instant + , subq_2.bookings + FROM ( + -- Pass Only Elements: ['bookings', 'booking__is_instant', 'metric_time__day', 'listing'] + SELECT + subq_1.metric_time__day + , subq_1.listing + , subq_1.booking__is_instant + , subq_1.bookings + FROM ( + -- Metric Time Dimension 'ds' + SELECT + subq_0.ds__day + , subq_0.ds__week + , subq_0.ds__month + , subq_0.ds__quarter + , subq_0.ds__year + , subq_0.ds__extract_year + , subq_0.ds__extract_quarter + , subq_0.ds__extract_month + , subq_0.ds__extract_day + , subq_0.ds__extract_dow + , subq_0.ds__extract_doy + , subq_0.ds_partitioned__day + , subq_0.ds_partitioned__week + , subq_0.ds_partitioned__month + , subq_0.ds_partitioned__quarter + , subq_0.ds_partitioned__year + , subq_0.ds_partitioned__extract_year + , subq_0.ds_partitioned__extract_quarter + , subq_0.ds_partitioned__extract_month + , subq_0.ds_partitioned__extract_day + , subq_0.ds_partitioned__extract_dow + , subq_0.ds_partitioned__extract_doy + , subq_0.paid_at__day + , subq_0.paid_at__week + , subq_0.paid_at__month + , subq_0.paid_at__quarter + , subq_0.paid_at__year + , subq_0.paid_at__extract_year + , subq_0.paid_at__extract_quarter + , subq_0.paid_at__extract_month + , subq_0.paid_at__extract_day + , subq_0.paid_at__extract_dow + , subq_0.paid_at__extract_doy + , subq_0.booking__ds__day + , subq_0.booking__ds__week + , subq_0.booking__ds__month + , subq_0.booking__ds__quarter + , subq_0.booking__ds__year + , subq_0.booking__ds__extract_year + , subq_0.booking__ds__extract_quarter + , subq_0.booking__ds__extract_month + , subq_0.booking__ds__extract_day + , subq_0.booking__ds__extract_dow + , subq_0.booking__ds__extract_doy + , subq_0.booking__ds_partitioned__day + , subq_0.booking__ds_partitioned__week + , subq_0.booking__ds_partitioned__month + , subq_0.booking__ds_partitioned__quarter + , subq_0.booking__ds_partitioned__year + , subq_0.booking__ds_partitioned__extract_year + , subq_0.booking__ds_partitioned__extract_quarter + , subq_0.booking__ds_partitioned__extract_month + , subq_0.booking__ds_partitioned__extract_day + , subq_0.booking__ds_partitioned__extract_dow + , subq_0.booking__ds_partitioned__extract_doy + , subq_0.booking__paid_at__day + , subq_0.booking__paid_at__week + , subq_0.booking__paid_at__month + , subq_0.booking__paid_at__quarter + , subq_0.booking__paid_at__year + , subq_0.booking__paid_at__extract_year + , subq_0.booking__paid_at__extract_quarter + , subq_0.booking__paid_at__extract_month + , subq_0.booking__paid_at__extract_day + , subq_0.booking__paid_at__extract_dow + , subq_0.booking__paid_at__extract_doy + , subq_0.ds__day AS metric_time__day + , subq_0.ds__week AS metric_time__week + , subq_0.ds__month AS metric_time__month + , subq_0.ds__quarter AS metric_time__quarter + , subq_0.ds__year AS metric_time__year + , subq_0.ds__extract_year AS metric_time__extract_year + , subq_0.ds__extract_quarter AS metric_time__extract_quarter + , subq_0.ds__extract_month AS metric_time__extract_month + , subq_0.ds__extract_day AS metric_time__extract_day + , subq_0.ds__extract_dow AS metric_time__extract_dow + , subq_0.ds__extract_doy AS metric_time__extract_doy + , subq_0.listing + , subq_0.guest + , subq_0.host + , subq_0.booking__listing + , subq_0.booking__guest + , subq_0.booking__host + , subq_0.is_instant + , subq_0.booking__is_instant + , subq_0.bookings + , subq_0.instant_bookings + , subq_0.booking_value + , subq_0.max_booking_value + , subq_0.min_booking_value + , subq_0.bookers + , subq_0.average_booking_value + , subq_0.referred_bookings + , subq_0.median_booking_value + , subq_0.booking_value_p99 + , subq_0.discrete_booking_value_p99 + , subq_0.approximate_continuous_booking_value_p99 + , subq_0.approximate_discrete_booking_value_p99 + FROM ( + -- Read Elements From Semantic Model 'bookings_source' + SELECT + 1 AS bookings + , CASE WHEN is_instant THEN 1 ELSE 0 END AS instant_bookings + , bookings_source_src_28000.booking_value + , bookings_source_src_28000.booking_value AS max_booking_value + , bookings_source_src_28000.booking_value AS min_booking_value + , bookings_source_src_28000.guest_id AS bookers + , bookings_source_src_28000.booking_value AS average_booking_value + , bookings_source_src_28000.booking_value AS booking_payments + , CASE WHEN referrer_id IS NOT NULL THEN 1 ELSE 0 END AS referred_bookings + , bookings_source_src_28000.booking_value AS median_booking_value + , bookings_source_src_28000.booking_value AS booking_value_p99 + , bookings_source_src_28000.booking_value AS discrete_booking_value_p99 + , bookings_source_src_28000.booking_value AS approximate_continuous_booking_value_p99 + , bookings_source_src_28000.booking_value AS approximate_discrete_booking_value_p99 + , bookings_source_src_28000.is_instant + , DATE_TRUNC('day', bookings_source_src_28000.ds) AS ds__day + , DATE_TRUNC('week', bookings_source_src_28000.ds) AS ds__week + , DATE_TRUNC('month', bookings_source_src_28000.ds) AS ds__month + , DATE_TRUNC('quarter', bookings_source_src_28000.ds) AS ds__quarter + , DATE_TRUNC('year', bookings_source_src_28000.ds) AS ds__year + , EXTRACT(year FROM bookings_source_src_28000.ds) AS ds__extract_year + , EXTRACT(quarter FROM bookings_source_src_28000.ds) AS ds__extract_quarter + , EXTRACT(month FROM bookings_source_src_28000.ds) AS ds__extract_month + , EXTRACT(day FROM bookings_source_src_28000.ds) AS ds__extract_day + , EXTRACT(DAYOFWEEK_ISO FROM bookings_source_src_28000.ds) AS ds__extract_dow + , EXTRACT(doy FROM bookings_source_src_28000.ds) AS ds__extract_doy + , DATE_TRUNC('day', bookings_source_src_28000.ds_partitioned) AS ds_partitioned__day + , DATE_TRUNC('week', bookings_source_src_28000.ds_partitioned) AS ds_partitioned__week + , DATE_TRUNC('month', bookings_source_src_28000.ds_partitioned) AS ds_partitioned__month + , DATE_TRUNC('quarter', bookings_source_src_28000.ds_partitioned) AS ds_partitioned__quarter + , DATE_TRUNC('year', bookings_source_src_28000.ds_partitioned) AS ds_partitioned__year + , EXTRACT(year FROM bookings_source_src_28000.ds_partitioned) AS ds_partitioned__extract_year + , EXTRACT(quarter FROM bookings_source_src_28000.ds_partitioned) AS ds_partitioned__extract_quarter + , EXTRACT(month FROM bookings_source_src_28000.ds_partitioned) AS ds_partitioned__extract_month + , EXTRACT(day FROM bookings_source_src_28000.ds_partitioned) AS ds_partitioned__extract_day + , EXTRACT(DAYOFWEEK_ISO FROM bookings_source_src_28000.ds_partitioned) AS ds_partitioned__extract_dow + , EXTRACT(doy FROM bookings_source_src_28000.ds_partitioned) AS ds_partitioned__extract_doy + , DATE_TRUNC('day', bookings_source_src_28000.paid_at) AS paid_at__day + , DATE_TRUNC('week', bookings_source_src_28000.paid_at) AS paid_at__week + , DATE_TRUNC('month', bookings_source_src_28000.paid_at) AS paid_at__month + , DATE_TRUNC('quarter', bookings_source_src_28000.paid_at) AS paid_at__quarter + , DATE_TRUNC('year', bookings_source_src_28000.paid_at) AS paid_at__year + , EXTRACT(year FROM bookings_source_src_28000.paid_at) AS paid_at__extract_year + , EXTRACT(quarter FROM bookings_source_src_28000.paid_at) AS paid_at__extract_quarter + , EXTRACT(month FROM bookings_source_src_28000.paid_at) AS paid_at__extract_month + , EXTRACT(day FROM bookings_source_src_28000.paid_at) AS paid_at__extract_day + , EXTRACT(DAYOFWEEK_ISO FROM bookings_source_src_28000.paid_at) AS paid_at__extract_dow + , EXTRACT(doy FROM bookings_source_src_28000.paid_at) AS paid_at__extract_doy + , bookings_source_src_28000.is_instant AS booking__is_instant + , DATE_TRUNC('day', bookings_source_src_28000.ds) AS booking__ds__day + , DATE_TRUNC('week', bookings_source_src_28000.ds) AS booking__ds__week + , DATE_TRUNC('month', bookings_source_src_28000.ds) AS booking__ds__month + , DATE_TRUNC('quarter', bookings_source_src_28000.ds) AS booking__ds__quarter + , DATE_TRUNC('year', bookings_source_src_28000.ds) AS booking__ds__year + , EXTRACT(year FROM bookings_source_src_28000.ds) AS booking__ds__extract_year + , EXTRACT(quarter FROM bookings_source_src_28000.ds) AS booking__ds__extract_quarter + , EXTRACT(month FROM bookings_source_src_28000.ds) AS booking__ds__extract_month + , EXTRACT(day FROM bookings_source_src_28000.ds) AS booking__ds__extract_day + , EXTRACT(DAYOFWEEK_ISO FROM bookings_source_src_28000.ds) AS booking__ds__extract_dow + , EXTRACT(doy FROM bookings_source_src_28000.ds) AS booking__ds__extract_doy + , DATE_TRUNC('day', bookings_source_src_28000.ds_partitioned) AS booking__ds_partitioned__day + , DATE_TRUNC('week', bookings_source_src_28000.ds_partitioned) AS booking__ds_partitioned__week + , DATE_TRUNC('month', bookings_source_src_28000.ds_partitioned) AS booking__ds_partitioned__month + , DATE_TRUNC('quarter', bookings_source_src_28000.ds_partitioned) AS booking__ds_partitioned__quarter + , DATE_TRUNC('year', bookings_source_src_28000.ds_partitioned) AS booking__ds_partitioned__year + , EXTRACT(year FROM bookings_source_src_28000.ds_partitioned) AS booking__ds_partitioned__extract_year + , EXTRACT(quarter FROM bookings_source_src_28000.ds_partitioned) AS booking__ds_partitioned__extract_quarter + , EXTRACT(month FROM bookings_source_src_28000.ds_partitioned) AS booking__ds_partitioned__extract_month + , EXTRACT(day FROM bookings_source_src_28000.ds_partitioned) AS booking__ds_partitioned__extract_day + , EXTRACT(DAYOFWEEK_ISO FROM bookings_source_src_28000.ds_partitioned) AS booking__ds_partitioned__extract_dow + , EXTRACT(doy FROM bookings_source_src_28000.ds_partitioned) AS booking__ds_partitioned__extract_doy + , DATE_TRUNC('day', bookings_source_src_28000.paid_at) AS booking__paid_at__day + , DATE_TRUNC('week', bookings_source_src_28000.paid_at) AS booking__paid_at__week + , DATE_TRUNC('month', bookings_source_src_28000.paid_at) AS booking__paid_at__month + , DATE_TRUNC('quarter', bookings_source_src_28000.paid_at) AS booking__paid_at__quarter + , DATE_TRUNC('year', bookings_source_src_28000.paid_at) AS booking__paid_at__year + , EXTRACT(year FROM bookings_source_src_28000.paid_at) AS booking__paid_at__extract_year + , EXTRACT(quarter FROM bookings_source_src_28000.paid_at) AS booking__paid_at__extract_quarter + , EXTRACT(month FROM bookings_source_src_28000.paid_at) AS booking__paid_at__extract_month + , EXTRACT(day FROM bookings_source_src_28000.paid_at) AS booking__paid_at__extract_day + , EXTRACT(DAYOFWEEK_ISO FROM bookings_source_src_28000.paid_at) AS booking__paid_at__extract_dow + , EXTRACT(doy FROM bookings_source_src_28000.paid_at) AS booking__paid_at__extract_doy + , bookings_source_src_28000.listing_id AS listing + , bookings_source_src_28000.guest_id AS guest + , bookings_source_src_28000.host_id AS host + , bookings_source_src_28000.listing_id AS booking__listing + , bookings_source_src_28000.guest_id AS booking__guest + , bookings_source_src_28000.host_id AS booking__host + FROM ***************************.fct_bookings bookings_source_src_28000 + ) subq_0 + ) subq_1 + ) subq_2 + WHERE ((booking__is_instant) AND (listing IS NOT NULL)) AND (metric_time__day > '2020-01-01') + ) subq_3 + ) subq_4 + GROUP BY + subq_4.metric_time__day + , subq_4.booking__is_instant + ) subq_5 + ON + subq_6.metric_time__day = subq_5.metric_time__day + ) subq_8 + WHERE metric_time__day > '2020-01-01' +) subq_9 diff --git a/tests_metricflow/snapshots/test_time_spine_join_rendering.py/SqlQueryPlan/Databricks/test_join_to_time_spine_with_input_measure_constraint__plan0_optimized.sql b/tests_metricflow/snapshots/test_time_spine_join_rendering.py/SqlQueryPlan/Databricks/test_join_to_time_spine_with_input_measure_constraint__plan0_optimized.sql new file mode 100644 index 0000000000..c3948c32d3 --- /dev/null +++ b/tests_metricflow/snapshots/test_time_spine_join_rendering.py/SqlQueryPlan/Databricks/test_join_to_time_spine_with_input_measure_constraint__plan0_optimized.sql @@ -0,0 +1,41 @@ +-- Constrain Output with WHERE +-- Compute Metrics via Expressions +SELECT + metric_time__day + , booking__is_instant + , bookings AS instant_bookings_with_measure_filter +FROM ( + -- Join to Time Spine Dataset + SELECT + subq_17.ds AS metric_time__day + , subq_15.booking__is_instant AS booking__is_instant + , subq_15.bookings AS bookings + FROM ***************************.mf_time_spine subq_17 + LEFT OUTER JOIN ( + -- Constrain Output with WHERE + -- Pass Only Elements: ['bookings', 'booking__is_instant', 'metric_time__day'] + -- Aggregate Measures + SELECT + metric_time__day + , booking__is_instant + , SUM(bookings) AS bookings + FROM ( + -- Read Elements From Semantic Model 'bookings_source' + -- Metric Time Dimension 'ds' + -- Pass Only Elements: ['bookings', 'booking__is_instant', 'metric_time__day', 'listing'] + SELECT + DATE_TRUNC('day', ds) AS metric_time__day + , listing_id AS listing + , is_instant AS booking__is_instant + , 1 AS bookings + FROM ***************************.fct_bookings bookings_source_src_28000 + ) subq_12 + WHERE ((booking__is_instant) AND (listing IS NOT NULL)) AND (metric_time__day > '2020-01-01') + GROUP BY + metric_time__day + , booking__is_instant + ) subq_15 + ON + subq_17.ds = subq_15.metric_time__day +) subq_18 +WHERE metric_time__day > '2020-01-01' diff --git a/tests_metricflow/snapshots/test_time_spine_join_rendering.py/SqlQueryPlan/DuckDB/test_join_to_time_spine_with_input_measure_constraint__plan0.sql b/tests_metricflow/snapshots/test_time_spine_join_rendering.py/SqlQueryPlan/DuckDB/test_join_to_time_spine_with_input_measure_constraint__plan0.sql new file mode 100644 index 0000000000..f41dbae562 --- /dev/null +++ b/tests_metricflow/snapshots/test_time_spine_join_rendering.py/SqlQueryPlan/DuckDB/test_join_to_time_spine_with_input_measure_constraint__plan0.sql @@ -0,0 +1,257 @@ +-- Compute Metrics via Expressions +SELECT + subq_9.metric_time__day + , subq_9.booking__is_instant + , subq_9.bookings AS instant_bookings_with_measure_filter +FROM ( + -- Constrain Output with WHERE + SELECT + subq_8.metric_time__day + , subq_8.booking__is_instant + , subq_8.bookings + FROM ( + -- Join to Time Spine Dataset + SELECT + subq_6.metric_time__day AS metric_time__day + , subq_5.booking__is_instant AS booking__is_instant + , subq_5.bookings AS bookings + FROM ( + -- Time Spine + SELECT + subq_7.ds AS metric_time__day + FROM ***************************.mf_time_spine subq_7 + ) subq_6 + LEFT OUTER JOIN ( + -- Aggregate Measures + SELECT + subq_4.metric_time__day + , subq_4.booking__is_instant + , SUM(subq_4.bookings) AS bookings + FROM ( + -- Pass Only Elements: ['bookings', 'booking__is_instant', 'metric_time__day'] + SELECT + subq_3.metric_time__day + , subq_3.booking__is_instant + , subq_3.bookings + FROM ( + -- Constrain Output with WHERE + SELECT + subq_2.metric_time__day + , subq_2.listing + , subq_2.booking__is_instant + , subq_2.bookings + FROM ( + -- Pass Only Elements: ['bookings', 'booking__is_instant', 'metric_time__day', 'listing'] + SELECT + subq_1.metric_time__day + , subq_1.listing + , subq_1.booking__is_instant + , subq_1.bookings + FROM ( + -- Metric Time Dimension 'ds' + SELECT + subq_0.ds__day + , subq_0.ds__week + , subq_0.ds__month + , subq_0.ds__quarter + , subq_0.ds__year + , subq_0.ds__extract_year + , subq_0.ds__extract_quarter + , subq_0.ds__extract_month + , subq_0.ds__extract_day + , subq_0.ds__extract_dow + , subq_0.ds__extract_doy + , subq_0.ds_partitioned__day + , subq_0.ds_partitioned__week + , subq_0.ds_partitioned__month + , subq_0.ds_partitioned__quarter + , subq_0.ds_partitioned__year + , subq_0.ds_partitioned__extract_year + , subq_0.ds_partitioned__extract_quarter + , subq_0.ds_partitioned__extract_month + , subq_0.ds_partitioned__extract_day + , subq_0.ds_partitioned__extract_dow + , subq_0.ds_partitioned__extract_doy + , subq_0.paid_at__day + , subq_0.paid_at__week + , subq_0.paid_at__month + , subq_0.paid_at__quarter + , subq_0.paid_at__year + , subq_0.paid_at__extract_year + , subq_0.paid_at__extract_quarter + , subq_0.paid_at__extract_month + , subq_0.paid_at__extract_day + , subq_0.paid_at__extract_dow + , subq_0.paid_at__extract_doy + , subq_0.booking__ds__day + , subq_0.booking__ds__week + , subq_0.booking__ds__month + , subq_0.booking__ds__quarter + , subq_0.booking__ds__year + , subq_0.booking__ds__extract_year + , subq_0.booking__ds__extract_quarter + , subq_0.booking__ds__extract_month + , subq_0.booking__ds__extract_day + , subq_0.booking__ds__extract_dow + , subq_0.booking__ds__extract_doy + , subq_0.booking__ds_partitioned__day + , subq_0.booking__ds_partitioned__week + , subq_0.booking__ds_partitioned__month + , subq_0.booking__ds_partitioned__quarter + , subq_0.booking__ds_partitioned__year + , subq_0.booking__ds_partitioned__extract_year + , subq_0.booking__ds_partitioned__extract_quarter + , subq_0.booking__ds_partitioned__extract_month + , subq_0.booking__ds_partitioned__extract_day + , subq_0.booking__ds_partitioned__extract_dow + , subq_0.booking__ds_partitioned__extract_doy + , subq_0.booking__paid_at__day + , subq_0.booking__paid_at__week + , subq_0.booking__paid_at__month + , subq_0.booking__paid_at__quarter + , subq_0.booking__paid_at__year + , subq_0.booking__paid_at__extract_year + , subq_0.booking__paid_at__extract_quarter + , subq_0.booking__paid_at__extract_month + , subq_0.booking__paid_at__extract_day + , subq_0.booking__paid_at__extract_dow + , subq_0.booking__paid_at__extract_doy + , subq_0.ds__day AS metric_time__day + , subq_0.ds__week AS metric_time__week + , subq_0.ds__month AS metric_time__month + , subq_0.ds__quarter AS metric_time__quarter + , subq_0.ds__year AS metric_time__year + , subq_0.ds__extract_year AS metric_time__extract_year + , subq_0.ds__extract_quarter AS metric_time__extract_quarter + , subq_0.ds__extract_month AS metric_time__extract_month + , subq_0.ds__extract_day AS metric_time__extract_day + , subq_0.ds__extract_dow AS metric_time__extract_dow + , subq_0.ds__extract_doy AS metric_time__extract_doy + , subq_0.listing + , subq_0.guest + , subq_0.host + , subq_0.booking__listing + , subq_0.booking__guest + , subq_0.booking__host + , subq_0.is_instant + , subq_0.booking__is_instant + , subq_0.bookings + , subq_0.instant_bookings + , subq_0.booking_value + , subq_0.max_booking_value + , subq_0.min_booking_value + , subq_0.bookers + , subq_0.average_booking_value + , subq_0.referred_bookings + , subq_0.median_booking_value + , subq_0.booking_value_p99 + , subq_0.discrete_booking_value_p99 + , subq_0.approximate_continuous_booking_value_p99 + , subq_0.approximate_discrete_booking_value_p99 + FROM ( + -- Read Elements From Semantic Model 'bookings_source' + SELECT + 1 AS bookings + , CASE WHEN is_instant THEN 1 ELSE 0 END AS instant_bookings + , bookings_source_src_28000.booking_value + , bookings_source_src_28000.booking_value AS max_booking_value + , bookings_source_src_28000.booking_value AS min_booking_value + , bookings_source_src_28000.guest_id AS bookers + , bookings_source_src_28000.booking_value AS average_booking_value + , bookings_source_src_28000.booking_value AS booking_payments + , CASE WHEN referrer_id IS NOT NULL THEN 1 ELSE 0 END AS referred_bookings + , bookings_source_src_28000.booking_value AS median_booking_value + , bookings_source_src_28000.booking_value AS booking_value_p99 + , bookings_source_src_28000.booking_value AS discrete_booking_value_p99 + , bookings_source_src_28000.booking_value AS approximate_continuous_booking_value_p99 + , bookings_source_src_28000.booking_value AS approximate_discrete_booking_value_p99 + , bookings_source_src_28000.is_instant + , DATE_TRUNC('day', bookings_source_src_28000.ds) AS ds__day + , DATE_TRUNC('week', bookings_source_src_28000.ds) AS ds__week + , DATE_TRUNC('month', bookings_source_src_28000.ds) AS ds__month + , DATE_TRUNC('quarter', bookings_source_src_28000.ds) AS ds__quarter + , DATE_TRUNC('year', bookings_source_src_28000.ds) AS ds__year + , EXTRACT(year FROM bookings_source_src_28000.ds) AS ds__extract_year + , EXTRACT(quarter FROM bookings_source_src_28000.ds) AS ds__extract_quarter + , EXTRACT(month FROM bookings_source_src_28000.ds) AS ds__extract_month + , EXTRACT(day FROM bookings_source_src_28000.ds) AS ds__extract_day + , EXTRACT(isodow FROM bookings_source_src_28000.ds) AS ds__extract_dow + , EXTRACT(doy FROM bookings_source_src_28000.ds) AS ds__extract_doy + , DATE_TRUNC('day', bookings_source_src_28000.ds_partitioned) AS ds_partitioned__day + , DATE_TRUNC('week', bookings_source_src_28000.ds_partitioned) AS ds_partitioned__week + , DATE_TRUNC('month', bookings_source_src_28000.ds_partitioned) AS ds_partitioned__month + , DATE_TRUNC('quarter', bookings_source_src_28000.ds_partitioned) AS ds_partitioned__quarter + , DATE_TRUNC('year', bookings_source_src_28000.ds_partitioned) AS ds_partitioned__year + , EXTRACT(year FROM bookings_source_src_28000.ds_partitioned) AS ds_partitioned__extract_year + , EXTRACT(quarter FROM bookings_source_src_28000.ds_partitioned) AS ds_partitioned__extract_quarter + , EXTRACT(month FROM bookings_source_src_28000.ds_partitioned) AS ds_partitioned__extract_month + , EXTRACT(day FROM bookings_source_src_28000.ds_partitioned) AS ds_partitioned__extract_day + , EXTRACT(isodow FROM bookings_source_src_28000.ds_partitioned) AS ds_partitioned__extract_dow + , EXTRACT(doy FROM bookings_source_src_28000.ds_partitioned) AS ds_partitioned__extract_doy + , DATE_TRUNC('day', bookings_source_src_28000.paid_at) AS paid_at__day + , DATE_TRUNC('week', bookings_source_src_28000.paid_at) AS paid_at__week + , DATE_TRUNC('month', bookings_source_src_28000.paid_at) AS paid_at__month + , DATE_TRUNC('quarter', bookings_source_src_28000.paid_at) AS paid_at__quarter + , DATE_TRUNC('year', bookings_source_src_28000.paid_at) AS paid_at__year + , EXTRACT(year FROM bookings_source_src_28000.paid_at) AS paid_at__extract_year + , EXTRACT(quarter FROM bookings_source_src_28000.paid_at) AS paid_at__extract_quarter + , EXTRACT(month FROM bookings_source_src_28000.paid_at) AS paid_at__extract_month + , EXTRACT(day FROM bookings_source_src_28000.paid_at) AS paid_at__extract_day + , EXTRACT(isodow FROM bookings_source_src_28000.paid_at) AS paid_at__extract_dow + , EXTRACT(doy FROM bookings_source_src_28000.paid_at) AS paid_at__extract_doy + , bookings_source_src_28000.is_instant AS booking__is_instant + , DATE_TRUNC('day', bookings_source_src_28000.ds) AS booking__ds__day + , DATE_TRUNC('week', bookings_source_src_28000.ds) AS booking__ds__week + , DATE_TRUNC('month', bookings_source_src_28000.ds) AS booking__ds__month + , DATE_TRUNC('quarter', bookings_source_src_28000.ds) AS booking__ds__quarter + , DATE_TRUNC('year', bookings_source_src_28000.ds) AS booking__ds__year + , EXTRACT(year FROM bookings_source_src_28000.ds) AS booking__ds__extract_year + , EXTRACT(quarter FROM bookings_source_src_28000.ds) AS booking__ds__extract_quarter + , EXTRACT(month FROM bookings_source_src_28000.ds) AS booking__ds__extract_month + , EXTRACT(day FROM bookings_source_src_28000.ds) AS booking__ds__extract_day + , EXTRACT(isodow FROM bookings_source_src_28000.ds) AS booking__ds__extract_dow + , EXTRACT(doy FROM bookings_source_src_28000.ds) AS booking__ds__extract_doy + , DATE_TRUNC('day', bookings_source_src_28000.ds_partitioned) AS booking__ds_partitioned__day + , DATE_TRUNC('week', bookings_source_src_28000.ds_partitioned) AS booking__ds_partitioned__week + , DATE_TRUNC('month', bookings_source_src_28000.ds_partitioned) AS booking__ds_partitioned__month + , DATE_TRUNC('quarter', bookings_source_src_28000.ds_partitioned) AS booking__ds_partitioned__quarter + , DATE_TRUNC('year', bookings_source_src_28000.ds_partitioned) AS booking__ds_partitioned__year + , EXTRACT(year FROM bookings_source_src_28000.ds_partitioned) AS booking__ds_partitioned__extract_year + , EXTRACT(quarter FROM bookings_source_src_28000.ds_partitioned) AS booking__ds_partitioned__extract_quarter + , EXTRACT(month FROM bookings_source_src_28000.ds_partitioned) AS booking__ds_partitioned__extract_month + , EXTRACT(day FROM bookings_source_src_28000.ds_partitioned) AS booking__ds_partitioned__extract_day + , EXTRACT(isodow FROM bookings_source_src_28000.ds_partitioned) AS booking__ds_partitioned__extract_dow + , EXTRACT(doy FROM bookings_source_src_28000.ds_partitioned) AS booking__ds_partitioned__extract_doy + , DATE_TRUNC('day', bookings_source_src_28000.paid_at) AS booking__paid_at__day + , DATE_TRUNC('week', bookings_source_src_28000.paid_at) AS booking__paid_at__week + , DATE_TRUNC('month', bookings_source_src_28000.paid_at) AS booking__paid_at__month + , DATE_TRUNC('quarter', bookings_source_src_28000.paid_at) AS booking__paid_at__quarter + , DATE_TRUNC('year', bookings_source_src_28000.paid_at) AS booking__paid_at__year + , EXTRACT(year FROM bookings_source_src_28000.paid_at) AS booking__paid_at__extract_year + , EXTRACT(quarter FROM bookings_source_src_28000.paid_at) AS booking__paid_at__extract_quarter + , EXTRACT(month FROM bookings_source_src_28000.paid_at) AS booking__paid_at__extract_month + , EXTRACT(day FROM bookings_source_src_28000.paid_at) AS booking__paid_at__extract_day + , EXTRACT(isodow FROM bookings_source_src_28000.paid_at) AS booking__paid_at__extract_dow + , EXTRACT(doy FROM bookings_source_src_28000.paid_at) AS booking__paid_at__extract_doy + , bookings_source_src_28000.listing_id AS listing + , bookings_source_src_28000.guest_id AS guest + , bookings_source_src_28000.host_id AS host + , bookings_source_src_28000.listing_id AS booking__listing + , bookings_source_src_28000.guest_id AS booking__guest + , bookings_source_src_28000.host_id AS booking__host + FROM ***************************.fct_bookings bookings_source_src_28000 + ) subq_0 + ) subq_1 + ) subq_2 + WHERE ((booking__is_instant) AND (listing IS NOT NULL)) AND (metric_time__day > '2020-01-01') + ) subq_3 + ) subq_4 + GROUP BY + subq_4.metric_time__day + , subq_4.booking__is_instant + ) subq_5 + ON + subq_6.metric_time__day = subq_5.metric_time__day + ) subq_8 + WHERE metric_time__day > '2020-01-01' +) subq_9 diff --git a/tests_metricflow/snapshots/test_time_spine_join_rendering.py/SqlQueryPlan/DuckDB/test_join_to_time_spine_with_input_measure_constraint__plan0_optimized.sql b/tests_metricflow/snapshots/test_time_spine_join_rendering.py/SqlQueryPlan/DuckDB/test_join_to_time_spine_with_input_measure_constraint__plan0_optimized.sql new file mode 100644 index 0000000000..c3948c32d3 --- /dev/null +++ b/tests_metricflow/snapshots/test_time_spine_join_rendering.py/SqlQueryPlan/DuckDB/test_join_to_time_spine_with_input_measure_constraint__plan0_optimized.sql @@ -0,0 +1,41 @@ +-- Constrain Output with WHERE +-- Compute Metrics via Expressions +SELECT + metric_time__day + , booking__is_instant + , bookings AS instant_bookings_with_measure_filter +FROM ( + -- Join to Time Spine Dataset + SELECT + subq_17.ds AS metric_time__day + , subq_15.booking__is_instant AS booking__is_instant + , subq_15.bookings AS bookings + FROM ***************************.mf_time_spine subq_17 + LEFT OUTER JOIN ( + -- Constrain Output with WHERE + -- Pass Only Elements: ['bookings', 'booking__is_instant', 'metric_time__day'] + -- Aggregate Measures + SELECT + metric_time__day + , booking__is_instant + , SUM(bookings) AS bookings + FROM ( + -- Read Elements From Semantic Model 'bookings_source' + -- Metric Time Dimension 'ds' + -- Pass Only Elements: ['bookings', 'booking__is_instant', 'metric_time__day', 'listing'] + SELECT + DATE_TRUNC('day', ds) AS metric_time__day + , listing_id AS listing + , is_instant AS booking__is_instant + , 1 AS bookings + FROM ***************************.fct_bookings bookings_source_src_28000 + ) subq_12 + WHERE ((booking__is_instant) AND (listing IS NOT NULL)) AND (metric_time__day > '2020-01-01') + GROUP BY + metric_time__day + , booking__is_instant + ) subq_15 + ON + subq_17.ds = subq_15.metric_time__day +) subq_18 +WHERE metric_time__day > '2020-01-01' diff --git a/tests_metricflow/snapshots/test_time_spine_join_rendering.py/SqlQueryPlan/Postgres/test_join_to_time_spine_with_input_measure_constraint__plan0.sql b/tests_metricflow/snapshots/test_time_spine_join_rendering.py/SqlQueryPlan/Postgres/test_join_to_time_spine_with_input_measure_constraint__plan0.sql new file mode 100644 index 0000000000..f41dbae562 --- /dev/null +++ b/tests_metricflow/snapshots/test_time_spine_join_rendering.py/SqlQueryPlan/Postgres/test_join_to_time_spine_with_input_measure_constraint__plan0.sql @@ -0,0 +1,257 @@ +-- Compute Metrics via Expressions +SELECT + subq_9.metric_time__day + , subq_9.booking__is_instant + , subq_9.bookings AS instant_bookings_with_measure_filter +FROM ( + -- Constrain Output with WHERE + SELECT + subq_8.metric_time__day + , subq_8.booking__is_instant + , subq_8.bookings + FROM ( + -- Join to Time Spine Dataset + SELECT + subq_6.metric_time__day AS metric_time__day + , subq_5.booking__is_instant AS booking__is_instant + , subq_5.bookings AS bookings + FROM ( + -- Time Spine + SELECT + subq_7.ds AS metric_time__day + FROM ***************************.mf_time_spine subq_7 + ) subq_6 + LEFT OUTER JOIN ( + -- Aggregate Measures + SELECT + subq_4.metric_time__day + , subq_4.booking__is_instant + , SUM(subq_4.bookings) AS bookings + FROM ( + -- Pass Only Elements: ['bookings', 'booking__is_instant', 'metric_time__day'] + SELECT + subq_3.metric_time__day + , subq_3.booking__is_instant + , subq_3.bookings + FROM ( + -- Constrain Output with WHERE + SELECT + subq_2.metric_time__day + , subq_2.listing + , subq_2.booking__is_instant + , subq_2.bookings + FROM ( + -- Pass Only Elements: ['bookings', 'booking__is_instant', 'metric_time__day', 'listing'] + SELECT + subq_1.metric_time__day + , subq_1.listing + , subq_1.booking__is_instant + , subq_1.bookings + FROM ( + -- Metric Time Dimension 'ds' + SELECT + subq_0.ds__day + , subq_0.ds__week + , subq_0.ds__month + , subq_0.ds__quarter + , subq_0.ds__year + , subq_0.ds__extract_year + , subq_0.ds__extract_quarter + , subq_0.ds__extract_month + , subq_0.ds__extract_day + , subq_0.ds__extract_dow + , subq_0.ds__extract_doy + , subq_0.ds_partitioned__day + , subq_0.ds_partitioned__week + , subq_0.ds_partitioned__month + , subq_0.ds_partitioned__quarter + , subq_0.ds_partitioned__year + , subq_0.ds_partitioned__extract_year + , subq_0.ds_partitioned__extract_quarter + , subq_0.ds_partitioned__extract_month + , subq_0.ds_partitioned__extract_day + , subq_0.ds_partitioned__extract_dow + , subq_0.ds_partitioned__extract_doy + , subq_0.paid_at__day + , subq_0.paid_at__week + , subq_0.paid_at__month + , subq_0.paid_at__quarter + , subq_0.paid_at__year + , subq_0.paid_at__extract_year + , subq_0.paid_at__extract_quarter + , subq_0.paid_at__extract_month + , subq_0.paid_at__extract_day + , subq_0.paid_at__extract_dow + , subq_0.paid_at__extract_doy + , subq_0.booking__ds__day + , subq_0.booking__ds__week + , subq_0.booking__ds__month + , subq_0.booking__ds__quarter + , subq_0.booking__ds__year + , subq_0.booking__ds__extract_year + , subq_0.booking__ds__extract_quarter + , subq_0.booking__ds__extract_month + , subq_0.booking__ds__extract_day + , subq_0.booking__ds__extract_dow + , subq_0.booking__ds__extract_doy + , subq_0.booking__ds_partitioned__day + , subq_0.booking__ds_partitioned__week + , subq_0.booking__ds_partitioned__month + , subq_0.booking__ds_partitioned__quarter + , subq_0.booking__ds_partitioned__year + , subq_0.booking__ds_partitioned__extract_year + , subq_0.booking__ds_partitioned__extract_quarter + , subq_0.booking__ds_partitioned__extract_month + , subq_0.booking__ds_partitioned__extract_day + , subq_0.booking__ds_partitioned__extract_dow + , subq_0.booking__ds_partitioned__extract_doy + , subq_0.booking__paid_at__day + , subq_0.booking__paid_at__week + , subq_0.booking__paid_at__month + , subq_0.booking__paid_at__quarter + , subq_0.booking__paid_at__year + , subq_0.booking__paid_at__extract_year + , subq_0.booking__paid_at__extract_quarter + , subq_0.booking__paid_at__extract_month + , subq_0.booking__paid_at__extract_day + , subq_0.booking__paid_at__extract_dow + , subq_0.booking__paid_at__extract_doy + , subq_0.ds__day AS metric_time__day + , subq_0.ds__week AS metric_time__week + , subq_0.ds__month AS metric_time__month + , subq_0.ds__quarter AS metric_time__quarter + , subq_0.ds__year AS metric_time__year + , subq_0.ds__extract_year AS metric_time__extract_year + , subq_0.ds__extract_quarter AS metric_time__extract_quarter + , subq_0.ds__extract_month AS metric_time__extract_month + , subq_0.ds__extract_day AS metric_time__extract_day + , subq_0.ds__extract_dow AS metric_time__extract_dow + , subq_0.ds__extract_doy AS metric_time__extract_doy + , subq_0.listing + , subq_0.guest + , subq_0.host + , subq_0.booking__listing + , subq_0.booking__guest + , subq_0.booking__host + , subq_0.is_instant + , subq_0.booking__is_instant + , subq_0.bookings + , subq_0.instant_bookings + , subq_0.booking_value + , subq_0.max_booking_value + , subq_0.min_booking_value + , subq_0.bookers + , subq_0.average_booking_value + , subq_0.referred_bookings + , subq_0.median_booking_value + , subq_0.booking_value_p99 + , subq_0.discrete_booking_value_p99 + , subq_0.approximate_continuous_booking_value_p99 + , subq_0.approximate_discrete_booking_value_p99 + FROM ( + -- Read Elements From Semantic Model 'bookings_source' + SELECT + 1 AS bookings + , CASE WHEN is_instant THEN 1 ELSE 0 END AS instant_bookings + , bookings_source_src_28000.booking_value + , bookings_source_src_28000.booking_value AS max_booking_value + , bookings_source_src_28000.booking_value AS min_booking_value + , bookings_source_src_28000.guest_id AS bookers + , bookings_source_src_28000.booking_value AS average_booking_value + , bookings_source_src_28000.booking_value AS booking_payments + , CASE WHEN referrer_id IS NOT NULL THEN 1 ELSE 0 END AS referred_bookings + , bookings_source_src_28000.booking_value AS median_booking_value + , bookings_source_src_28000.booking_value AS booking_value_p99 + , bookings_source_src_28000.booking_value AS discrete_booking_value_p99 + , bookings_source_src_28000.booking_value AS approximate_continuous_booking_value_p99 + , bookings_source_src_28000.booking_value AS approximate_discrete_booking_value_p99 + , bookings_source_src_28000.is_instant + , DATE_TRUNC('day', bookings_source_src_28000.ds) AS ds__day + , DATE_TRUNC('week', bookings_source_src_28000.ds) AS ds__week + , DATE_TRUNC('month', bookings_source_src_28000.ds) AS ds__month + , DATE_TRUNC('quarter', bookings_source_src_28000.ds) AS ds__quarter + , DATE_TRUNC('year', bookings_source_src_28000.ds) AS ds__year + , EXTRACT(year FROM bookings_source_src_28000.ds) AS ds__extract_year + , EXTRACT(quarter FROM bookings_source_src_28000.ds) AS ds__extract_quarter + , EXTRACT(month FROM bookings_source_src_28000.ds) AS ds__extract_month + , EXTRACT(day FROM bookings_source_src_28000.ds) AS ds__extract_day + , EXTRACT(isodow FROM bookings_source_src_28000.ds) AS ds__extract_dow + , EXTRACT(doy FROM bookings_source_src_28000.ds) AS ds__extract_doy + , DATE_TRUNC('day', bookings_source_src_28000.ds_partitioned) AS ds_partitioned__day + , DATE_TRUNC('week', bookings_source_src_28000.ds_partitioned) AS ds_partitioned__week + , DATE_TRUNC('month', bookings_source_src_28000.ds_partitioned) AS ds_partitioned__month + , DATE_TRUNC('quarter', bookings_source_src_28000.ds_partitioned) AS ds_partitioned__quarter + , DATE_TRUNC('year', bookings_source_src_28000.ds_partitioned) AS ds_partitioned__year + , EXTRACT(year FROM bookings_source_src_28000.ds_partitioned) AS ds_partitioned__extract_year + , EXTRACT(quarter FROM bookings_source_src_28000.ds_partitioned) AS ds_partitioned__extract_quarter + , EXTRACT(month FROM bookings_source_src_28000.ds_partitioned) AS ds_partitioned__extract_month + , EXTRACT(day FROM bookings_source_src_28000.ds_partitioned) AS ds_partitioned__extract_day + , EXTRACT(isodow FROM bookings_source_src_28000.ds_partitioned) AS ds_partitioned__extract_dow + , EXTRACT(doy FROM bookings_source_src_28000.ds_partitioned) AS ds_partitioned__extract_doy + , DATE_TRUNC('day', bookings_source_src_28000.paid_at) AS paid_at__day + , DATE_TRUNC('week', bookings_source_src_28000.paid_at) AS paid_at__week + , DATE_TRUNC('month', bookings_source_src_28000.paid_at) AS paid_at__month + , DATE_TRUNC('quarter', bookings_source_src_28000.paid_at) AS paid_at__quarter + , DATE_TRUNC('year', bookings_source_src_28000.paid_at) AS paid_at__year + , EXTRACT(year FROM bookings_source_src_28000.paid_at) AS paid_at__extract_year + , EXTRACT(quarter FROM bookings_source_src_28000.paid_at) AS paid_at__extract_quarter + , EXTRACT(month FROM bookings_source_src_28000.paid_at) AS paid_at__extract_month + , EXTRACT(day FROM bookings_source_src_28000.paid_at) AS paid_at__extract_day + , EXTRACT(isodow FROM bookings_source_src_28000.paid_at) AS paid_at__extract_dow + , EXTRACT(doy FROM bookings_source_src_28000.paid_at) AS paid_at__extract_doy + , bookings_source_src_28000.is_instant AS booking__is_instant + , DATE_TRUNC('day', bookings_source_src_28000.ds) AS booking__ds__day + , DATE_TRUNC('week', bookings_source_src_28000.ds) AS booking__ds__week + , DATE_TRUNC('month', bookings_source_src_28000.ds) AS booking__ds__month + , DATE_TRUNC('quarter', bookings_source_src_28000.ds) AS booking__ds__quarter + , DATE_TRUNC('year', bookings_source_src_28000.ds) AS booking__ds__year + , EXTRACT(year FROM bookings_source_src_28000.ds) AS booking__ds__extract_year + , EXTRACT(quarter FROM bookings_source_src_28000.ds) AS booking__ds__extract_quarter + , EXTRACT(month FROM bookings_source_src_28000.ds) AS booking__ds__extract_month + , EXTRACT(day FROM bookings_source_src_28000.ds) AS booking__ds__extract_day + , EXTRACT(isodow FROM bookings_source_src_28000.ds) AS booking__ds__extract_dow + , EXTRACT(doy FROM bookings_source_src_28000.ds) AS booking__ds__extract_doy + , DATE_TRUNC('day', bookings_source_src_28000.ds_partitioned) AS booking__ds_partitioned__day + , DATE_TRUNC('week', bookings_source_src_28000.ds_partitioned) AS booking__ds_partitioned__week + , DATE_TRUNC('month', bookings_source_src_28000.ds_partitioned) AS booking__ds_partitioned__month + , DATE_TRUNC('quarter', bookings_source_src_28000.ds_partitioned) AS booking__ds_partitioned__quarter + , DATE_TRUNC('year', bookings_source_src_28000.ds_partitioned) AS booking__ds_partitioned__year + , EXTRACT(year FROM bookings_source_src_28000.ds_partitioned) AS booking__ds_partitioned__extract_year + , EXTRACT(quarter FROM bookings_source_src_28000.ds_partitioned) AS booking__ds_partitioned__extract_quarter + , EXTRACT(month FROM bookings_source_src_28000.ds_partitioned) AS booking__ds_partitioned__extract_month + , EXTRACT(day FROM bookings_source_src_28000.ds_partitioned) AS booking__ds_partitioned__extract_day + , EXTRACT(isodow FROM bookings_source_src_28000.ds_partitioned) AS booking__ds_partitioned__extract_dow + , EXTRACT(doy FROM bookings_source_src_28000.ds_partitioned) AS booking__ds_partitioned__extract_doy + , DATE_TRUNC('day', bookings_source_src_28000.paid_at) AS booking__paid_at__day + , DATE_TRUNC('week', bookings_source_src_28000.paid_at) AS booking__paid_at__week + , DATE_TRUNC('month', bookings_source_src_28000.paid_at) AS booking__paid_at__month + , DATE_TRUNC('quarter', bookings_source_src_28000.paid_at) AS booking__paid_at__quarter + , DATE_TRUNC('year', bookings_source_src_28000.paid_at) AS booking__paid_at__year + , EXTRACT(year FROM bookings_source_src_28000.paid_at) AS booking__paid_at__extract_year + , EXTRACT(quarter FROM bookings_source_src_28000.paid_at) AS booking__paid_at__extract_quarter + , EXTRACT(month FROM bookings_source_src_28000.paid_at) AS booking__paid_at__extract_month + , EXTRACT(day FROM bookings_source_src_28000.paid_at) AS booking__paid_at__extract_day + , EXTRACT(isodow FROM bookings_source_src_28000.paid_at) AS booking__paid_at__extract_dow + , EXTRACT(doy FROM bookings_source_src_28000.paid_at) AS booking__paid_at__extract_doy + , bookings_source_src_28000.listing_id AS listing + , bookings_source_src_28000.guest_id AS guest + , bookings_source_src_28000.host_id AS host + , bookings_source_src_28000.listing_id AS booking__listing + , bookings_source_src_28000.guest_id AS booking__guest + , bookings_source_src_28000.host_id AS booking__host + FROM ***************************.fct_bookings bookings_source_src_28000 + ) subq_0 + ) subq_1 + ) subq_2 + WHERE ((booking__is_instant) AND (listing IS NOT NULL)) AND (metric_time__day > '2020-01-01') + ) subq_3 + ) subq_4 + GROUP BY + subq_4.metric_time__day + , subq_4.booking__is_instant + ) subq_5 + ON + subq_6.metric_time__day = subq_5.metric_time__day + ) subq_8 + WHERE metric_time__day > '2020-01-01' +) subq_9 diff --git a/tests_metricflow/snapshots/test_time_spine_join_rendering.py/SqlQueryPlan/Postgres/test_join_to_time_spine_with_input_measure_constraint__plan0_optimized.sql b/tests_metricflow/snapshots/test_time_spine_join_rendering.py/SqlQueryPlan/Postgres/test_join_to_time_spine_with_input_measure_constraint__plan0_optimized.sql new file mode 100644 index 0000000000..c3948c32d3 --- /dev/null +++ b/tests_metricflow/snapshots/test_time_spine_join_rendering.py/SqlQueryPlan/Postgres/test_join_to_time_spine_with_input_measure_constraint__plan0_optimized.sql @@ -0,0 +1,41 @@ +-- Constrain Output with WHERE +-- Compute Metrics via Expressions +SELECT + metric_time__day + , booking__is_instant + , bookings AS instant_bookings_with_measure_filter +FROM ( + -- Join to Time Spine Dataset + SELECT + subq_17.ds AS metric_time__day + , subq_15.booking__is_instant AS booking__is_instant + , subq_15.bookings AS bookings + FROM ***************************.mf_time_spine subq_17 + LEFT OUTER JOIN ( + -- Constrain Output with WHERE + -- Pass Only Elements: ['bookings', 'booking__is_instant', 'metric_time__day'] + -- Aggregate Measures + SELECT + metric_time__day + , booking__is_instant + , SUM(bookings) AS bookings + FROM ( + -- Read Elements From Semantic Model 'bookings_source' + -- Metric Time Dimension 'ds' + -- Pass Only Elements: ['bookings', 'booking__is_instant', 'metric_time__day', 'listing'] + SELECT + DATE_TRUNC('day', ds) AS metric_time__day + , listing_id AS listing + , is_instant AS booking__is_instant + , 1 AS bookings + FROM ***************************.fct_bookings bookings_source_src_28000 + ) subq_12 + WHERE ((booking__is_instant) AND (listing IS NOT NULL)) AND (metric_time__day > '2020-01-01') + GROUP BY + metric_time__day + , booking__is_instant + ) subq_15 + ON + subq_17.ds = subq_15.metric_time__day +) subq_18 +WHERE metric_time__day > '2020-01-01' diff --git a/tests_metricflow/snapshots/test_time_spine_join_rendering.py/SqlQueryPlan/Redshift/test_join_to_time_spine_with_input_measure_constraint__plan0.sql b/tests_metricflow/snapshots/test_time_spine_join_rendering.py/SqlQueryPlan/Redshift/test_join_to_time_spine_with_input_measure_constraint__plan0.sql new file mode 100644 index 0000000000..bbd8e67d1d --- /dev/null +++ b/tests_metricflow/snapshots/test_time_spine_join_rendering.py/SqlQueryPlan/Redshift/test_join_to_time_spine_with_input_measure_constraint__plan0.sql @@ -0,0 +1,257 @@ +-- Compute Metrics via Expressions +SELECT + subq_9.metric_time__day + , subq_9.booking__is_instant + , subq_9.bookings AS instant_bookings_with_measure_filter +FROM ( + -- Constrain Output with WHERE + SELECT + subq_8.metric_time__day + , subq_8.booking__is_instant + , subq_8.bookings + FROM ( + -- Join to Time Spine Dataset + SELECT + subq_6.metric_time__day AS metric_time__day + , subq_5.booking__is_instant AS booking__is_instant + , subq_5.bookings AS bookings + FROM ( + -- Time Spine + SELECT + subq_7.ds AS metric_time__day + FROM ***************************.mf_time_spine subq_7 + ) subq_6 + LEFT OUTER JOIN ( + -- Aggregate Measures + SELECT + subq_4.metric_time__day + , subq_4.booking__is_instant + , SUM(subq_4.bookings) AS bookings + FROM ( + -- Pass Only Elements: ['bookings', 'booking__is_instant', 'metric_time__day'] + SELECT + subq_3.metric_time__day + , subq_3.booking__is_instant + , subq_3.bookings + FROM ( + -- Constrain Output with WHERE + SELECT + subq_2.metric_time__day + , subq_2.listing + , subq_2.booking__is_instant + , subq_2.bookings + FROM ( + -- Pass Only Elements: ['bookings', 'booking__is_instant', 'metric_time__day', 'listing'] + SELECT + subq_1.metric_time__day + , subq_1.listing + , subq_1.booking__is_instant + , subq_1.bookings + FROM ( + -- Metric Time Dimension 'ds' + SELECT + subq_0.ds__day + , subq_0.ds__week + , subq_0.ds__month + , subq_0.ds__quarter + , subq_0.ds__year + , subq_0.ds__extract_year + , subq_0.ds__extract_quarter + , subq_0.ds__extract_month + , subq_0.ds__extract_day + , subq_0.ds__extract_dow + , subq_0.ds__extract_doy + , subq_0.ds_partitioned__day + , subq_0.ds_partitioned__week + , subq_0.ds_partitioned__month + , subq_0.ds_partitioned__quarter + , subq_0.ds_partitioned__year + , subq_0.ds_partitioned__extract_year + , subq_0.ds_partitioned__extract_quarter + , subq_0.ds_partitioned__extract_month + , subq_0.ds_partitioned__extract_day + , subq_0.ds_partitioned__extract_dow + , subq_0.ds_partitioned__extract_doy + , subq_0.paid_at__day + , subq_0.paid_at__week + , subq_0.paid_at__month + , subq_0.paid_at__quarter + , subq_0.paid_at__year + , subq_0.paid_at__extract_year + , subq_0.paid_at__extract_quarter + , subq_0.paid_at__extract_month + , subq_0.paid_at__extract_day + , subq_0.paid_at__extract_dow + , subq_0.paid_at__extract_doy + , subq_0.booking__ds__day + , subq_0.booking__ds__week + , subq_0.booking__ds__month + , subq_0.booking__ds__quarter + , subq_0.booking__ds__year + , subq_0.booking__ds__extract_year + , subq_0.booking__ds__extract_quarter + , subq_0.booking__ds__extract_month + , subq_0.booking__ds__extract_day + , subq_0.booking__ds__extract_dow + , subq_0.booking__ds__extract_doy + , subq_0.booking__ds_partitioned__day + , subq_0.booking__ds_partitioned__week + , subq_0.booking__ds_partitioned__month + , subq_0.booking__ds_partitioned__quarter + , subq_0.booking__ds_partitioned__year + , subq_0.booking__ds_partitioned__extract_year + , subq_0.booking__ds_partitioned__extract_quarter + , subq_0.booking__ds_partitioned__extract_month + , subq_0.booking__ds_partitioned__extract_day + , subq_0.booking__ds_partitioned__extract_dow + , subq_0.booking__ds_partitioned__extract_doy + , subq_0.booking__paid_at__day + , subq_0.booking__paid_at__week + , subq_0.booking__paid_at__month + , subq_0.booking__paid_at__quarter + , subq_0.booking__paid_at__year + , subq_0.booking__paid_at__extract_year + , subq_0.booking__paid_at__extract_quarter + , subq_0.booking__paid_at__extract_month + , subq_0.booking__paid_at__extract_day + , subq_0.booking__paid_at__extract_dow + , subq_0.booking__paid_at__extract_doy + , subq_0.ds__day AS metric_time__day + , subq_0.ds__week AS metric_time__week + , subq_0.ds__month AS metric_time__month + , subq_0.ds__quarter AS metric_time__quarter + , subq_0.ds__year AS metric_time__year + , subq_0.ds__extract_year AS metric_time__extract_year + , subq_0.ds__extract_quarter AS metric_time__extract_quarter + , subq_0.ds__extract_month AS metric_time__extract_month + , subq_0.ds__extract_day AS metric_time__extract_day + , subq_0.ds__extract_dow AS metric_time__extract_dow + , subq_0.ds__extract_doy AS metric_time__extract_doy + , subq_0.listing + , subq_0.guest + , subq_0.host + , subq_0.booking__listing + , subq_0.booking__guest + , subq_0.booking__host + , subq_0.is_instant + , subq_0.booking__is_instant + , subq_0.bookings + , subq_0.instant_bookings + , subq_0.booking_value + , subq_0.max_booking_value + , subq_0.min_booking_value + , subq_0.bookers + , subq_0.average_booking_value + , subq_0.referred_bookings + , subq_0.median_booking_value + , subq_0.booking_value_p99 + , subq_0.discrete_booking_value_p99 + , subq_0.approximate_continuous_booking_value_p99 + , subq_0.approximate_discrete_booking_value_p99 + FROM ( + -- Read Elements From Semantic Model 'bookings_source' + SELECT + 1 AS bookings + , CASE WHEN is_instant THEN 1 ELSE 0 END AS instant_bookings + , bookings_source_src_28000.booking_value + , bookings_source_src_28000.booking_value AS max_booking_value + , bookings_source_src_28000.booking_value AS min_booking_value + , bookings_source_src_28000.guest_id AS bookers + , bookings_source_src_28000.booking_value AS average_booking_value + , bookings_source_src_28000.booking_value AS booking_payments + , CASE WHEN referrer_id IS NOT NULL THEN 1 ELSE 0 END AS referred_bookings + , bookings_source_src_28000.booking_value AS median_booking_value + , bookings_source_src_28000.booking_value AS booking_value_p99 + , bookings_source_src_28000.booking_value AS discrete_booking_value_p99 + , bookings_source_src_28000.booking_value AS approximate_continuous_booking_value_p99 + , bookings_source_src_28000.booking_value AS approximate_discrete_booking_value_p99 + , bookings_source_src_28000.is_instant + , DATE_TRUNC('day', bookings_source_src_28000.ds) AS ds__day + , DATE_TRUNC('week', bookings_source_src_28000.ds) AS ds__week + , DATE_TRUNC('month', bookings_source_src_28000.ds) AS ds__month + , DATE_TRUNC('quarter', bookings_source_src_28000.ds) AS ds__quarter + , DATE_TRUNC('year', bookings_source_src_28000.ds) AS ds__year + , EXTRACT(year FROM bookings_source_src_28000.ds) AS ds__extract_year + , EXTRACT(quarter FROM bookings_source_src_28000.ds) AS ds__extract_quarter + , EXTRACT(month FROM bookings_source_src_28000.ds) AS ds__extract_month + , EXTRACT(day FROM bookings_source_src_28000.ds) AS ds__extract_day + , CASE WHEN EXTRACT(dow FROM bookings_source_src_28000.ds) = 0 THEN EXTRACT(dow FROM bookings_source_src_28000.ds) + 7 ELSE EXTRACT(dow FROM bookings_source_src_28000.ds) END AS ds__extract_dow + , EXTRACT(doy FROM bookings_source_src_28000.ds) AS ds__extract_doy + , DATE_TRUNC('day', bookings_source_src_28000.ds_partitioned) AS ds_partitioned__day + , DATE_TRUNC('week', bookings_source_src_28000.ds_partitioned) AS ds_partitioned__week + , DATE_TRUNC('month', bookings_source_src_28000.ds_partitioned) AS ds_partitioned__month + , DATE_TRUNC('quarter', bookings_source_src_28000.ds_partitioned) AS ds_partitioned__quarter + , DATE_TRUNC('year', bookings_source_src_28000.ds_partitioned) AS ds_partitioned__year + , EXTRACT(year FROM bookings_source_src_28000.ds_partitioned) AS ds_partitioned__extract_year + , EXTRACT(quarter FROM bookings_source_src_28000.ds_partitioned) AS ds_partitioned__extract_quarter + , EXTRACT(month FROM bookings_source_src_28000.ds_partitioned) AS ds_partitioned__extract_month + , EXTRACT(day FROM bookings_source_src_28000.ds_partitioned) AS ds_partitioned__extract_day + , CASE WHEN EXTRACT(dow FROM bookings_source_src_28000.ds_partitioned) = 0 THEN EXTRACT(dow FROM bookings_source_src_28000.ds_partitioned) + 7 ELSE EXTRACT(dow FROM bookings_source_src_28000.ds_partitioned) END AS ds_partitioned__extract_dow + , EXTRACT(doy FROM bookings_source_src_28000.ds_partitioned) AS ds_partitioned__extract_doy + , DATE_TRUNC('day', bookings_source_src_28000.paid_at) AS paid_at__day + , DATE_TRUNC('week', bookings_source_src_28000.paid_at) AS paid_at__week + , DATE_TRUNC('month', bookings_source_src_28000.paid_at) AS paid_at__month + , DATE_TRUNC('quarter', bookings_source_src_28000.paid_at) AS paid_at__quarter + , DATE_TRUNC('year', bookings_source_src_28000.paid_at) AS paid_at__year + , EXTRACT(year FROM bookings_source_src_28000.paid_at) AS paid_at__extract_year + , EXTRACT(quarter FROM bookings_source_src_28000.paid_at) AS paid_at__extract_quarter + , EXTRACT(month FROM bookings_source_src_28000.paid_at) AS paid_at__extract_month + , EXTRACT(day FROM bookings_source_src_28000.paid_at) AS paid_at__extract_day + , CASE WHEN EXTRACT(dow FROM bookings_source_src_28000.paid_at) = 0 THEN EXTRACT(dow FROM bookings_source_src_28000.paid_at) + 7 ELSE EXTRACT(dow FROM bookings_source_src_28000.paid_at) END AS paid_at__extract_dow + , EXTRACT(doy FROM bookings_source_src_28000.paid_at) AS paid_at__extract_doy + , bookings_source_src_28000.is_instant AS booking__is_instant + , DATE_TRUNC('day', bookings_source_src_28000.ds) AS booking__ds__day + , DATE_TRUNC('week', bookings_source_src_28000.ds) AS booking__ds__week + , DATE_TRUNC('month', bookings_source_src_28000.ds) AS booking__ds__month + , DATE_TRUNC('quarter', bookings_source_src_28000.ds) AS booking__ds__quarter + , DATE_TRUNC('year', bookings_source_src_28000.ds) AS booking__ds__year + , EXTRACT(year FROM bookings_source_src_28000.ds) AS booking__ds__extract_year + , EXTRACT(quarter FROM bookings_source_src_28000.ds) AS booking__ds__extract_quarter + , EXTRACT(month FROM bookings_source_src_28000.ds) AS booking__ds__extract_month + , EXTRACT(day FROM bookings_source_src_28000.ds) AS booking__ds__extract_day + , CASE WHEN EXTRACT(dow FROM bookings_source_src_28000.ds) = 0 THEN EXTRACT(dow FROM bookings_source_src_28000.ds) + 7 ELSE EXTRACT(dow FROM bookings_source_src_28000.ds) END AS booking__ds__extract_dow + , EXTRACT(doy FROM bookings_source_src_28000.ds) AS booking__ds__extract_doy + , DATE_TRUNC('day', bookings_source_src_28000.ds_partitioned) AS booking__ds_partitioned__day + , DATE_TRUNC('week', bookings_source_src_28000.ds_partitioned) AS booking__ds_partitioned__week + , DATE_TRUNC('month', bookings_source_src_28000.ds_partitioned) AS booking__ds_partitioned__month + , DATE_TRUNC('quarter', bookings_source_src_28000.ds_partitioned) AS booking__ds_partitioned__quarter + , DATE_TRUNC('year', bookings_source_src_28000.ds_partitioned) AS booking__ds_partitioned__year + , EXTRACT(year FROM bookings_source_src_28000.ds_partitioned) AS booking__ds_partitioned__extract_year + , EXTRACT(quarter FROM bookings_source_src_28000.ds_partitioned) AS booking__ds_partitioned__extract_quarter + , EXTRACT(month FROM bookings_source_src_28000.ds_partitioned) AS booking__ds_partitioned__extract_month + , EXTRACT(day FROM bookings_source_src_28000.ds_partitioned) AS booking__ds_partitioned__extract_day + , CASE WHEN EXTRACT(dow FROM bookings_source_src_28000.ds_partitioned) = 0 THEN EXTRACT(dow FROM bookings_source_src_28000.ds_partitioned) + 7 ELSE EXTRACT(dow FROM bookings_source_src_28000.ds_partitioned) END AS booking__ds_partitioned__extract_dow + , EXTRACT(doy FROM bookings_source_src_28000.ds_partitioned) AS booking__ds_partitioned__extract_doy + , DATE_TRUNC('day', bookings_source_src_28000.paid_at) AS booking__paid_at__day + , DATE_TRUNC('week', bookings_source_src_28000.paid_at) AS booking__paid_at__week + , DATE_TRUNC('month', bookings_source_src_28000.paid_at) AS booking__paid_at__month + , DATE_TRUNC('quarter', bookings_source_src_28000.paid_at) AS booking__paid_at__quarter + , DATE_TRUNC('year', bookings_source_src_28000.paid_at) AS booking__paid_at__year + , EXTRACT(year FROM bookings_source_src_28000.paid_at) AS booking__paid_at__extract_year + , EXTRACT(quarter FROM bookings_source_src_28000.paid_at) AS booking__paid_at__extract_quarter + , EXTRACT(month FROM bookings_source_src_28000.paid_at) AS booking__paid_at__extract_month + , EXTRACT(day FROM bookings_source_src_28000.paid_at) AS booking__paid_at__extract_day + , CASE WHEN EXTRACT(dow FROM bookings_source_src_28000.paid_at) = 0 THEN EXTRACT(dow FROM bookings_source_src_28000.paid_at) + 7 ELSE EXTRACT(dow FROM bookings_source_src_28000.paid_at) END AS booking__paid_at__extract_dow + , EXTRACT(doy FROM bookings_source_src_28000.paid_at) AS booking__paid_at__extract_doy + , bookings_source_src_28000.listing_id AS listing + , bookings_source_src_28000.guest_id AS guest + , bookings_source_src_28000.host_id AS host + , bookings_source_src_28000.listing_id AS booking__listing + , bookings_source_src_28000.guest_id AS booking__guest + , bookings_source_src_28000.host_id AS booking__host + FROM ***************************.fct_bookings bookings_source_src_28000 + ) subq_0 + ) subq_1 + ) subq_2 + WHERE ((booking__is_instant) AND (listing IS NOT NULL)) AND (metric_time__day > '2020-01-01') + ) subq_3 + ) subq_4 + GROUP BY + subq_4.metric_time__day + , subq_4.booking__is_instant + ) subq_5 + ON + subq_6.metric_time__day = subq_5.metric_time__day + ) subq_8 + WHERE metric_time__day > '2020-01-01' +) subq_9 diff --git a/tests_metricflow/snapshots/test_time_spine_join_rendering.py/SqlQueryPlan/Redshift/test_join_to_time_spine_with_input_measure_constraint__plan0_optimized.sql b/tests_metricflow/snapshots/test_time_spine_join_rendering.py/SqlQueryPlan/Redshift/test_join_to_time_spine_with_input_measure_constraint__plan0_optimized.sql new file mode 100644 index 0000000000..c3948c32d3 --- /dev/null +++ b/tests_metricflow/snapshots/test_time_spine_join_rendering.py/SqlQueryPlan/Redshift/test_join_to_time_spine_with_input_measure_constraint__plan0_optimized.sql @@ -0,0 +1,41 @@ +-- Constrain Output with WHERE +-- Compute Metrics via Expressions +SELECT + metric_time__day + , booking__is_instant + , bookings AS instant_bookings_with_measure_filter +FROM ( + -- Join to Time Spine Dataset + SELECT + subq_17.ds AS metric_time__day + , subq_15.booking__is_instant AS booking__is_instant + , subq_15.bookings AS bookings + FROM ***************************.mf_time_spine subq_17 + LEFT OUTER JOIN ( + -- Constrain Output with WHERE + -- Pass Only Elements: ['bookings', 'booking__is_instant', 'metric_time__day'] + -- Aggregate Measures + SELECT + metric_time__day + , booking__is_instant + , SUM(bookings) AS bookings + FROM ( + -- Read Elements From Semantic Model 'bookings_source' + -- Metric Time Dimension 'ds' + -- Pass Only Elements: ['bookings', 'booking__is_instant', 'metric_time__day', 'listing'] + SELECT + DATE_TRUNC('day', ds) AS metric_time__day + , listing_id AS listing + , is_instant AS booking__is_instant + , 1 AS bookings + FROM ***************************.fct_bookings bookings_source_src_28000 + ) subq_12 + WHERE ((booking__is_instant) AND (listing IS NOT NULL)) AND (metric_time__day > '2020-01-01') + GROUP BY + metric_time__day + , booking__is_instant + ) subq_15 + ON + subq_17.ds = subq_15.metric_time__day +) subq_18 +WHERE metric_time__day > '2020-01-01' diff --git a/tests_metricflow/snapshots/test_time_spine_join_rendering.py/SqlQueryPlan/Snowflake/test_join_to_time_spine_with_input_measure_constraint__plan0.sql b/tests_metricflow/snapshots/test_time_spine_join_rendering.py/SqlQueryPlan/Snowflake/test_join_to_time_spine_with_input_measure_constraint__plan0.sql new file mode 100644 index 0000000000..2083a56236 --- /dev/null +++ b/tests_metricflow/snapshots/test_time_spine_join_rendering.py/SqlQueryPlan/Snowflake/test_join_to_time_spine_with_input_measure_constraint__plan0.sql @@ -0,0 +1,257 @@ +-- Compute Metrics via Expressions +SELECT + subq_9.metric_time__day + , subq_9.booking__is_instant + , subq_9.bookings AS instant_bookings_with_measure_filter +FROM ( + -- Constrain Output with WHERE + SELECT + subq_8.metric_time__day + , subq_8.booking__is_instant + , subq_8.bookings + FROM ( + -- Join to Time Spine Dataset + SELECT + subq_6.metric_time__day AS metric_time__day + , subq_5.booking__is_instant AS booking__is_instant + , subq_5.bookings AS bookings + FROM ( + -- Time Spine + SELECT + subq_7.ds AS metric_time__day + FROM ***************************.mf_time_spine subq_7 + ) subq_6 + LEFT OUTER JOIN ( + -- Aggregate Measures + SELECT + subq_4.metric_time__day + , subq_4.booking__is_instant + , SUM(subq_4.bookings) AS bookings + FROM ( + -- Pass Only Elements: ['bookings', 'booking__is_instant', 'metric_time__day'] + SELECT + subq_3.metric_time__day + , subq_3.booking__is_instant + , subq_3.bookings + FROM ( + -- Constrain Output with WHERE + SELECT + subq_2.metric_time__day + , subq_2.listing + , subq_2.booking__is_instant + , subq_2.bookings + FROM ( + -- Pass Only Elements: ['bookings', 'booking__is_instant', 'metric_time__day', 'listing'] + SELECT + subq_1.metric_time__day + , subq_1.listing + , subq_1.booking__is_instant + , subq_1.bookings + FROM ( + -- Metric Time Dimension 'ds' + SELECT + subq_0.ds__day + , subq_0.ds__week + , subq_0.ds__month + , subq_0.ds__quarter + , subq_0.ds__year + , subq_0.ds__extract_year + , subq_0.ds__extract_quarter + , subq_0.ds__extract_month + , subq_0.ds__extract_day + , subq_0.ds__extract_dow + , subq_0.ds__extract_doy + , subq_0.ds_partitioned__day + , subq_0.ds_partitioned__week + , subq_0.ds_partitioned__month + , subq_0.ds_partitioned__quarter + , subq_0.ds_partitioned__year + , subq_0.ds_partitioned__extract_year + , subq_0.ds_partitioned__extract_quarter + , subq_0.ds_partitioned__extract_month + , subq_0.ds_partitioned__extract_day + , subq_0.ds_partitioned__extract_dow + , subq_0.ds_partitioned__extract_doy + , subq_0.paid_at__day + , subq_0.paid_at__week + , subq_0.paid_at__month + , subq_0.paid_at__quarter + , subq_0.paid_at__year + , subq_0.paid_at__extract_year + , subq_0.paid_at__extract_quarter + , subq_0.paid_at__extract_month + , subq_0.paid_at__extract_day + , subq_0.paid_at__extract_dow + , subq_0.paid_at__extract_doy + , subq_0.booking__ds__day + , subq_0.booking__ds__week + , subq_0.booking__ds__month + , subq_0.booking__ds__quarter + , subq_0.booking__ds__year + , subq_0.booking__ds__extract_year + , subq_0.booking__ds__extract_quarter + , subq_0.booking__ds__extract_month + , subq_0.booking__ds__extract_day + , subq_0.booking__ds__extract_dow + , subq_0.booking__ds__extract_doy + , subq_0.booking__ds_partitioned__day + , subq_0.booking__ds_partitioned__week + , subq_0.booking__ds_partitioned__month + , subq_0.booking__ds_partitioned__quarter + , subq_0.booking__ds_partitioned__year + , subq_0.booking__ds_partitioned__extract_year + , subq_0.booking__ds_partitioned__extract_quarter + , subq_0.booking__ds_partitioned__extract_month + , subq_0.booking__ds_partitioned__extract_day + , subq_0.booking__ds_partitioned__extract_dow + , subq_0.booking__ds_partitioned__extract_doy + , subq_0.booking__paid_at__day + , subq_0.booking__paid_at__week + , subq_0.booking__paid_at__month + , subq_0.booking__paid_at__quarter + , subq_0.booking__paid_at__year + , subq_0.booking__paid_at__extract_year + , subq_0.booking__paid_at__extract_quarter + , subq_0.booking__paid_at__extract_month + , subq_0.booking__paid_at__extract_day + , subq_0.booking__paid_at__extract_dow + , subq_0.booking__paid_at__extract_doy + , subq_0.ds__day AS metric_time__day + , subq_0.ds__week AS metric_time__week + , subq_0.ds__month AS metric_time__month + , subq_0.ds__quarter AS metric_time__quarter + , subq_0.ds__year AS metric_time__year + , subq_0.ds__extract_year AS metric_time__extract_year + , subq_0.ds__extract_quarter AS metric_time__extract_quarter + , subq_0.ds__extract_month AS metric_time__extract_month + , subq_0.ds__extract_day AS metric_time__extract_day + , subq_0.ds__extract_dow AS metric_time__extract_dow + , subq_0.ds__extract_doy AS metric_time__extract_doy + , subq_0.listing + , subq_0.guest + , subq_0.host + , subq_0.booking__listing + , subq_0.booking__guest + , subq_0.booking__host + , subq_0.is_instant + , subq_0.booking__is_instant + , subq_0.bookings + , subq_0.instant_bookings + , subq_0.booking_value + , subq_0.max_booking_value + , subq_0.min_booking_value + , subq_0.bookers + , subq_0.average_booking_value + , subq_0.referred_bookings + , subq_0.median_booking_value + , subq_0.booking_value_p99 + , subq_0.discrete_booking_value_p99 + , subq_0.approximate_continuous_booking_value_p99 + , subq_0.approximate_discrete_booking_value_p99 + FROM ( + -- Read Elements From Semantic Model 'bookings_source' + SELECT + 1 AS bookings + , CASE WHEN is_instant THEN 1 ELSE 0 END AS instant_bookings + , bookings_source_src_28000.booking_value + , bookings_source_src_28000.booking_value AS max_booking_value + , bookings_source_src_28000.booking_value AS min_booking_value + , bookings_source_src_28000.guest_id AS bookers + , bookings_source_src_28000.booking_value AS average_booking_value + , bookings_source_src_28000.booking_value AS booking_payments + , CASE WHEN referrer_id IS NOT NULL THEN 1 ELSE 0 END AS referred_bookings + , bookings_source_src_28000.booking_value AS median_booking_value + , bookings_source_src_28000.booking_value AS booking_value_p99 + , bookings_source_src_28000.booking_value AS discrete_booking_value_p99 + , bookings_source_src_28000.booking_value AS approximate_continuous_booking_value_p99 + , bookings_source_src_28000.booking_value AS approximate_discrete_booking_value_p99 + , bookings_source_src_28000.is_instant + , DATE_TRUNC('day', bookings_source_src_28000.ds) AS ds__day + , DATE_TRUNC('week', bookings_source_src_28000.ds) AS ds__week + , DATE_TRUNC('month', bookings_source_src_28000.ds) AS ds__month + , DATE_TRUNC('quarter', bookings_source_src_28000.ds) AS ds__quarter + , DATE_TRUNC('year', bookings_source_src_28000.ds) AS ds__year + , EXTRACT(year FROM bookings_source_src_28000.ds) AS ds__extract_year + , EXTRACT(quarter FROM bookings_source_src_28000.ds) AS ds__extract_quarter + , EXTRACT(month FROM bookings_source_src_28000.ds) AS ds__extract_month + , EXTRACT(day FROM bookings_source_src_28000.ds) AS ds__extract_day + , EXTRACT(dayofweekiso FROM bookings_source_src_28000.ds) AS ds__extract_dow + , EXTRACT(doy FROM bookings_source_src_28000.ds) AS ds__extract_doy + , DATE_TRUNC('day', bookings_source_src_28000.ds_partitioned) AS ds_partitioned__day + , DATE_TRUNC('week', bookings_source_src_28000.ds_partitioned) AS ds_partitioned__week + , DATE_TRUNC('month', bookings_source_src_28000.ds_partitioned) AS ds_partitioned__month + , DATE_TRUNC('quarter', bookings_source_src_28000.ds_partitioned) AS ds_partitioned__quarter + , DATE_TRUNC('year', bookings_source_src_28000.ds_partitioned) AS ds_partitioned__year + , EXTRACT(year FROM bookings_source_src_28000.ds_partitioned) AS ds_partitioned__extract_year + , EXTRACT(quarter FROM bookings_source_src_28000.ds_partitioned) AS ds_partitioned__extract_quarter + , EXTRACT(month FROM bookings_source_src_28000.ds_partitioned) AS ds_partitioned__extract_month + , EXTRACT(day FROM bookings_source_src_28000.ds_partitioned) AS ds_partitioned__extract_day + , EXTRACT(dayofweekiso FROM bookings_source_src_28000.ds_partitioned) AS ds_partitioned__extract_dow + , EXTRACT(doy FROM bookings_source_src_28000.ds_partitioned) AS ds_partitioned__extract_doy + , DATE_TRUNC('day', bookings_source_src_28000.paid_at) AS paid_at__day + , DATE_TRUNC('week', bookings_source_src_28000.paid_at) AS paid_at__week + , DATE_TRUNC('month', bookings_source_src_28000.paid_at) AS paid_at__month + , DATE_TRUNC('quarter', bookings_source_src_28000.paid_at) AS paid_at__quarter + , DATE_TRUNC('year', bookings_source_src_28000.paid_at) AS paid_at__year + , EXTRACT(year FROM bookings_source_src_28000.paid_at) AS paid_at__extract_year + , EXTRACT(quarter FROM bookings_source_src_28000.paid_at) AS paid_at__extract_quarter + , EXTRACT(month FROM bookings_source_src_28000.paid_at) AS paid_at__extract_month + , EXTRACT(day FROM bookings_source_src_28000.paid_at) AS paid_at__extract_day + , EXTRACT(dayofweekiso FROM bookings_source_src_28000.paid_at) AS paid_at__extract_dow + , EXTRACT(doy FROM bookings_source_src_28000.paid_at) AS paid_at__extract_doy + , bookings_source_src_28000.is_instant AS booking__is_instant + , DATE_TRUNC('day', bookings_source_src_28000.ds) AS booking__ds__day + , DATE_TRUNC('week', bookings_source_src_28000.ds) AS booking__ds__week + , DATE_TRUNC('month', bookings_source_src_28000.ds) AS booking__ds__month + , DATE_TRUNC('quarter', bookings_source_src_28000.ds) AS booking__ds__quarter + , DATE_TRUNC('year', bookings_source_src_28000.ds) AS booking__ds__year + , EXTRACT(year FROM bookings_source_src_28000.ds) AS booking__ds__extract_year + , EXTRACT(quarter FROM bookings_source_src_28000.ds) AS booking__ds__extract_quarter + , EXTRACT(month FROM bookings_source_src_28000.ds) AS booking__ds__extract_month + , EXTRACT(day FROM bookings_source_src_28000.ds) AS booking__ds__extract_day + , EXTRACT(dayofweekiso FROM bookings_source_src_28000.ds) AS booking__ds__extract_dow + , EXTRACT(doy FROM bookings_source_src_28000.ds) AS booking__ds__extract_doy + , DATE_TRUNC('day', bookings_source_src_28000.ds_partitioned) AS booking__ds_partitioned__day + , DATE_TRUNC('week', bookings_source_src_28000.ds_partitioned) AS booking__ds_partitioned__week + , DATE_TRUNC('month', bookings_source_src_28000.ds_partitioned) AS booking__ds_partitioned__month + , DATE_TRUNC('quarter', bookings_source_src_28000.ds_partitioned) AS booking__ds_partitioned__quarter + , DATE_TRUNC('year', bookings_source_src_28000.ds_partitioned) AS booking__ds_partitioned__year + , EXTRACT(year FROM bookings_source_src_28000.ds_partitioned) AS booking__ds_partitioned__extract_year + , EXTRACT(quarter FROM bookings_source_src_28000.ds_partitioned) AS booking__ds_partitioned__extract_quarter + , EXTRACT(month FROM bookings_source_src_28000.ds_partitioned) AS booking__ds_partitioned__extract_month + , EXTRACT(day FROM bookings_source_src_28000.ds_partitioned) AS booking__ds_partitioned__extract_day + , EXTRACT(dayofweekiso FROM bookings_source_src_28000.ds_partitioned) AS booking__ds_partitioned__extract_dow + , EXTRACT(doy FROM bookings_source_src_28000.ds_partitioned) AS booking__ds_partitioned__extract_doy + , DATE_TRUNC('day', bookings_source_src_28000.paid_at) AS booking__paid_at__day + , DATE_TRUNC('week', bookings_source_src_28000.paid_at) AS booking__paid_at__week + , DATE_TRUNC('month', bookings_source_src_28000.paid_at) AS booking__paid_at__month + , DATE_TRUNC('quarter', bookings_source_src_28000.paid_at) AS booking__paid_at__quarter + , DATE_TRUNC('year', bookings_source_src_28000.paid_at) AS booking__paid_at__year + , EXTRACT(year FROM bookings_source_src_28000.paid_at) AS booking__paid_at__extract_year + , EXTRACT(quarter FROM bookings_source_src_28000.paid_at) AS booking__paid_at__extract_quarter + , EXTRACT(month FROM bookings_source_src_28000.paid_at) AS booking__paid_at__extract_month + , EXTRACT(day FROM bookings_source_src_28000.paid_at) AS booking__paid_at__extract_day + , EXTRACT(dayofweekiso FROM bookings_source_src_28000.paid_at) AS booking__paid_at__extract_dow + , EXTRACT(doy FROM bookings_source_src_28000.paid_at) AS booking__paid_at__extract_doy + , bookings_source_src_28000.listing_id AS listing + , bookings_source_src_28000.guest_id AS guest + , bookings_source_src_28000.host_id AS host + , bookings_source_src_28000.listing_id AS booking__listing + , bookings_source_src_28000.guest_id AS booking__guest + , bookings_source_src_28000.host_id AS booking__host + FROM ***************************.fct_bookings bookings_source_src_28000 + ) subq_0 + ) subq_1 + ) subq_2 + WHERE ((booking__is_instant) AND (listing IS NOT NULL)) AND (metric_time__day > '2020-01-01') + ) subq_3 + ) subq_4 + GROUP BY + subq_4.metric_time__day + , subq_4.booking__is_instant + ) subq_5 + ON + subq_6.metric_time__day = subq_5.metric_time__day + ) subq_8 + WHERE metric_time__day > '2020-01-01' +) subq_9 diff --git a/tests_metricflow/snapshots/test_time_spine_join_rendering.py/SqlQueryPlan/Snowflake/test_join_to_time_spine_with_input_measure_constraint__plan0_optimized.sql b/tests_metricflow/snapshots/test_time_spine_join_rendering.py/SqlQueryPlan/Snowflake/test_join_to_time_spine_with_input_measure_constraint__plan0_optimized.sql new file mode 100644 index 0000000000..c3948c32d3 --- /dev/null +++ b/tests_metricflow/snapshots/test_time_spine_join_rendering.py/SqlQueryPlan/Snowflake/test_join_to_time_spine_with_input_measure_constraint__plan0_optimized.sql @@ -0,0 +1,41 @@ +-- Constrain Output with WHERE +-- Compute Metrics via Expressions +SELECT + metric_time__day + , booking__is_instant + , bookings AS instant_bookings_with_measure_filter +FROM ( + -- Join to Time Spine Dataset + SELECT + subq_17.ds AS metric_time__day + , subq_15.booking__is_instant AS booking__is_instant + , subq_15.bookings AS bookings + FROM ***************************.mf_time_spine subq_17 + LEFT OUTER JOIN ( + -- Constrain Output with WHERE + -- Pass Only Elements: ['bookings', 'booking__is_instant', 'metric_time__day'] + -- Aggregate Measures + SELECT + metric_time__day + , booking__is_instant + , SUM(bookings) AS bookings + FROM ( + -- Read Elements From Semantic Model 'bookings_source' + -- Metric Time Dimension 'ds' + -- Pass Only Elements: ['bookings', 'booking__is_instant', 'metric_time__day', 'listing'] + SELECT + DATE_TRUNC('day', ds) AS metric_time__day + , listing_id AS listing + , is_instant AS booking__is_instant + , 1 AS bookings + FROM ***************************.fct_bookings bookings_source_src_28000 + ) subq_12 + WHERE ((booking__is_instant) AND (listing IS NOT NULL)) AND (metric_time__day > '2020-01-01') + GROUP BY + metric_time__day + , booking__is_instant + ) subq_15 + ON + subq_17.ds = subq_15.metric_time__day +) subq_18 +WHERE metric_time__day > '2020-01-01' diff --git a/tests_metricflow/snapshots/test_time_spine_join_rendering.py/SqlQueryPlan/Trino/test_join_to_time_spine_with_input_measure_constraint__plan0.sql b/tests_metricflow/snapshots/test_time_spine_join_rendering.py/SqlQueryPlan/Trino/test_join_to_time_spine_with_input_measure_constraint__plan0.sql new file mode 100644 index 0000000000..da3c66f29f --- /dev/null +++ b/tests_metricflow/snapshots/test_time_spine_join_rendering.py/SqlQueryPlan/Trino/test_join_to_time_spine_with_input_measure_constraint__plan0.sql @@ -0,0 +1,257 @@ +-- Compute Metrics via Expressions +SELECT + subq_9.metric_time__day + , subq_9.booking__is_instant + , subq_9.bookings AS instant_bookings_with_measure_filter +FROM ( + -- Constrain Output with WHERE + SELECT + subq_8.metric_time__day + , subq_8.booking__is_instant + , subq_8.bookings + FROM ( + -- Join to Time Spine Dataset + SELECT + subq_6.metric_time__day AS metric_time__day + , subq_5.booking__is_instant AS booking__is_instant + , subq_5.bookings AS bookings + FROM ( + -- Time Spine + SELECT + subq_7.ds AS metric_time__day + FROM ***************************.mf_time_spine subq_7 + ) subq_6 + LEFT OUTER JOIN ( + -- Aggregate Measures + SELECT + subq_4.metric_time__day + , subq_4.booking__is_instant + , SUM(subq_4.bookings) AS bookings + FROM ( + -- Pass Only Elements: ['bookings', 'booking__is_instant', 'metric_time__day'] + SELECT + subq_3.metric_time__day + , subq_3.booking__is_instant + , subq_3.bookings + FROM ( + -- Constrain Output with WHERE + SELECT + subq_2.metric_time__day + , subq_2.listing + , subq_2.booking__is_instant + , subq_2.bookings + FROM ( + -- Pass Only Elements: ['bookings', 'booking__is_instant', 'metric_time__day', 'listing'] + SELECT + subq_1.metric_time__day + , subq_1.listing + , subq_1.booking__is_instant + , subq_1.bookings + FROM ( + -- Metric Time Dimension 'ds' + SELECT + subq_0.ds__day + , subq_0.ds__week + , subq_0.ds__month + , subq_0.ds__quarter + , subq_0.ds__year + , subq_0.ds__extract_year + , subq_0.ds__extract_quarter + , subq_0.ds__extract_month + , subq_0.ds__extract_day + , subq_0.ds__extract_dow + , subq_0.ds__extract_doy + , subq_0.ds_partitioned__day + , subq_0.ds_partitioned__week + , subq_0.ds_partitioned__month + , subq_0.ds_partitioned__quarter + , subq_0.ds_partitioned__year + , subq_0.ds_partitioned__extract_year + , subq_0.ds_partitioned__extract_quarter + , subq_0.ds_partitioned__extract_month + , subq_0.ds_partitioned__extract_day + , subq_0.ds_partitioned__extract_dow + , subq_0.ds_partitioned__extract_doy + , subq_0.paid_at__day + , subq_0.paid_at__week + , subq_0.paid_at__month + , subq_0.paid_at__quarter + , subq_0.paid_at__year + , subq_0.paid_at__extract_year + , subq_0.paid_at__extract_quarter + , subq_0.paid_at__extract_month + , subq_0.paid_at__extract_day + , subq_0.paid_at__extract_dow + , subq_0.paid_at__extract_doy + , subq_0.booking__ds__day + , subq_0.booking__ds__week + , subq_0.booking__ds__month + , subq_0.booking__ds__quarter + , subq_0.booking__ds__year + , subq_0.booking__ds__extract_year + , subq_0.booking__ds__extract_quarter + , subq_0.booking__ds__extract_month + , subq_0.booking__ds__extract_day + , subq_0.booking__ds__extract_dow + , subq_0.booking__ds__extract_doy + , subq_0.booking__ds_partitioned__day + , subq_0.booking__ds_partitioned__week + , subq_0.booking__ds_partitioned__month + , subq_0.booking__ds_partitioned__quarter + , subq_0.booking__ds_partitioned__year + , subq_0.booking__ds_partitioned__extract_year + , subq_0.booking__ds_partitioned__extract_quarter + , subq_0.booking__ds_partitioned__extract_month + , subq_0.booking__ds_partitioned__extract_day + , subq_0.booking__ds_partitioned__extract_dow + , subq_0.booking__ds_partitioned__extract_doy + , subq_0.booking__paid_at__day + , subq_0.booking__paid_at__week + , subq_0.booking__paid_at__month + , subq_0.booking__paid_at__quarter + , subq_0.booking__paid_at__year + , subq_0.booking__paid_at__extract_year + , subq_0.booking__paid_at__extract_quarter + , subq_0.booking__paid_at__extract_month + , subq_0.booking__paid_at__extract_day + , subq_0.booking__paid_at__extract_dow + , subq_0.booking__paid_at__extract_doy + , subq_0.ds__day AS metric_time__day + , subq_0.ds__week AS metric_time__week + , subq_0.ds__month AS metric_time__month + , subq_0.ds__quarter AS metric_time__quarter + , subq_0.ds__year AS metric_time__year + , subq_0.ds__extract_year AS metric_time__extract_year + , subq_0.ds__extract_quarter AS metric_time__extract_quarter + , subq_0.ds__extract_month AS metric_time__extract_month + , subq_0.ds__extract_day AS metric_time__extract_day + , subq_0.ds__extract_dow AS metric_time__extract_dow + , subq_0.ds__extract_doy AS metric_time__extract_doy + , subq_0.listing + , subq_0.guest + , subq_0.host + , subq_0.booking__listing + , subq_0.booking__guest + , subq_0.booking__host + , subq_0.is_instant + , subq_0.booking__is_instant + , subq_0.bookings + , subq_0.instant_bookings + , subq_0.booking_value + , subq_0.max_booking_value + , subq_0.min_booking_value + , subq_0.bookers + , subq_0.average_booking_value + , subq_0.referred_bookings + , subq_0.median_booking_value + , subq_0.booking_value_p99 + , subq_0.discrete_booking_value_p99 + , subq_0.approximate_continuous_booking_value_p99 + , subq_0.approximate_discrete_booking_value_p99 + FROM ( + -- Read Elements From Semantic Model 'bookings_source' + SELECT + 1 AS bookings + , CASE WHEN is_instant THEN 1 ELSE 0 END AS instant_bookings + , bookings_source_src_28000.booking_value + , bookings_source_src_28000.booking_value AS max_booking_value + , bookings_source_src_28000.booking_value AS min_booking_value + , bookings_source_src_28000.guest_id AS bookers + , bookings_source_src_28000.booking_value AS average_booking_value + , bookings_source_src_28000.booking_value AS booking_payments + , CASE WHEN referrer_id IS NOT NULL THEN 1 ELSE 0 END AS referred_bookings + , bookings_source_src_28000.booking_value AS median_booking_value + , bookings_source_src_28000.booking_value AS booking_value_p99 + , bookings_source_src_28000.booking_value AS discrete_booking_value_p99 + , bookings_source_src_28000.booking_value AS approximate_continuous_booking_value_p99 + , bookings_source_src_28000.booking_value AS approximate_discrete_booking_value_p99 + , bookings_source_src_28000.is_instant + , DATE_TRUNC('day', bookings_source_src_28000.ds) AS ds__day + , DATE_TRUNC('week', bookings_source_src_28000.ds) AS ds__week + , DATE_TRUNC('month', bookings_source_src_28000.ds) AS ds__month + , DATE_TRUNC('quarter', bookings_source_src_28000.ds) AS ds__quarter + , DATE_TRUNC('year', bookings_source_src_28000.ds) AS ds__year + , EXTRACT(year FROM bookings_source_src_28000.ds) AS ds__extract_year + , EXTRACT(quarter FROM bookings_source_src_28000.ds) AS ds__extract_quarter + , EXTRACT(month FROM bookings_source_src_28000.ds) AS ds__extract_month + , EXTRACT(day FROM bookings_source_src_28000.ds) AS ds__extract_day + , EXTRACT(DAY_OF_WEEK FROM bookings_source_src_28000.ds) AS ds__extract_dow + , EXTRACT(doy FROM bookings_source_src_28000.ds) AS ds__extract_doy + , DATE_TRUNC('day', bookings_source_src_28000.ds_partitioned) AS ds_partitioned__day + , DATE_TRUNC('week', bookings_source_src_28000.ds_partitioned) AS ds_partitioned__week + , DATE_TRUNC('month', bookings_source_src_28000.ds_partitioned) AS ds_partitioned__month + , DATE_TRUNC('quarter', bookings_source_src_28000.ds_partitioned) AS ds_partitioned__quarter + , DATE_TRUNC('year', bookings_source_src_28000.ds_partitioned) AS ds_partitioned__year + , EXTRACT(year FROM bookings_source_src_28000.ds_partitioned) AS ds_partitioned__extract_year + , EXTRACT(quarter FROM bookings_source_src_28000.ds_partitioned) AS ds_partitioned__extract_quarter + , EXTRACT(month FROM bookings_source_src_28000.ds_partitioned) AS ds_partitioned__extract_month + , EXTRACT(day FROM bookings_source_src_28000.ds_partitioned) AS ds_partitioned__extract_day + , EXTRACT(DAY_OF_WEEK FROM bookings_source_src_28000.ds_partitioned) AS ds_partitioned__extract_dow + , EXTRACT(doy FROM bookings_source_src_28000.ds_partitioned) AS ds_partitioned__extract_doy + , DATE_TRUNC('day', bookings_source_src_28000.paid_at) AS paid_at__day + , DATE_TRUNC('week', bookings_source_src_28000.paid_at) AS paid_at__week + , DATE_TRUNC('month', bookings_source_src_28000.paid_at) AS paid_at__month + , DATE_TRUNC('quarter', bookings_source_src_28000.paid_at) AS paid_at__quarter + , DATE_TRUNC('year', bookings_source_src_28000.paid_at) AS paid_at__year + , EXTRACT(year FROM bookings_source_src_28000.paid_at) AS paid_at__extract_year + , EXTRACT(quarter FROM bookings_source_src_28000.paid_at) AS paid_at__extract_quarter + , EXTRACT(month FROM bookings_source_src_28000.paid_at) AS paid_at__extract_month + , EXTRACT(day FROM bookings_source_src_28000.paid_at) AS paid_at__extract_day + , EXTRACT(DAY_OF_WEEK FROM bookings_source_src_28000.paid_at) AS paid_at__extract_dow + , EXTRACT(doy FROM bookings_source_src_28000.paid_at) AS paid_at__extract_doy + , bookings_source_src_28000.is_instant AS booking__is_instant + , DATE_TRUNC('day', bookings_source_src_28000.ds) AS booking__ds__day + , DATE_TRUNC('week', bookings_source_src_28000.ds) AS booking__ds__week + , DATE_TRUNC('month', bookings_source_src_28000.ds) AS booking__ds__month + , DATE_TRUNC('quarter', bookings_source_src_28000.ds) AS booking__ds__quarter + , DATE_TRUNC('year', bookings_source_src_28000.ds) AS booking__ds__year + , EXTRACT(year FROM bookings_source_src_28000.ds) AS booking__ds__extract_year + , EXTRACT(quarter FROM bookings_source_src_28000.ds) AS booking__ds__extract_quarter + , EXTRACT(month FROM bookings_source_src_28000.ds) AS booking__ds__extract_month + , EXTRACT(day FROM bookings_source_src_28000.ds) AS booking__ds__extract_day + , EXTRACT(DAY_OF_WEEK FROM bookings_source_src_28000.ds) AS booking__ds__extract_dow + , EXTRACT(doy FROM bookings_source_src_28000.ds) AS booking__ds__extract_doy + , DATE_TRUNC('day', bookings_source_src_28000.ds_partitioned) AS booking__ds_partitioned__day + , DATE_TRUNC('week', bookings_source_src_28000.ds_partitioned) AS booking__ds_partitioned__week + , DATE_TRUNC('month', bookings_source_src_28000.ds_partitioned) AS booking__ds_partitioned__month + , DATE_TRUNC('quarter', bookings_source_src_28000.ds_partitioned) AS booking__ds_partitioned__quarter + , DATE_TRUNC('year', bookings_source_src_28000.ds_partitioned) AS booking__ds_partitioned__year + , EXTRACT(year FROM bookings_source_src_28000.ds_partitioned) AS booking__ds_partitioned__extract_year + , EXTRACT(quarter FROM bookings_source_src_28000.ds_partitioned) AS booking__ds_partitioned__extract_quarter + , EXTRACT(month FROM bookings_source_src_28000.ds_partitioned) AS booking__ds_partitioned__extract_month + , EXTRACT(day FROM bookings_source_src_28000.ds_partitioned) AS booking__ds_partitioned__extract_day + , EXTRACT(DAY_OF_WEEK FROM bookings_source_src_28000.ds_partitioned) AS booking__ds_partitioned__extract_dow + , EXTRACT(doy FROM bookings_source_src_28000.ds_partitioned) AS booking__ds_partitioned__extract_doy + , DATE_TRUNC('day', bookings_source_src_28000.paid_at) AS booking__paid_at__day + , DATE_TRUNC('week', bookings_source_src_28000.paid_at) AS booking__paid_at__week + , DATE_TRUNC('month', bookings_source_src_28000.paid_at) AS booking__paid_at__month + , DATE_TRUNC('quarter', bookings_source_src_28000.paid_at) AS booking__paid_at__quarter + , DATE_TRUNC('year', bookings_source_src_28000.paid_at) AS booking__paid_at__year + , EXTRACT(year FROM bookings_source_src_28000.paid_at) AS booking__paid_at__extract_year + , EXTRACT(quarter FROM bookings_source_src_28000.paid_at) AS booking__paid_at__extract_quarter + , EXTRACT(month FROM bookings_source_src_28000.paid_at) AS booking__paid_at__extract_month + , EXTRACT(day FROM bookings_source_src_28000.paid_at) AS booking__paid_at__extract_day + , EXTRACT(DAY_OF_WEEK FROM bookings_source_src_28000.paid_at) AS booking__paid_at__extract_dow + , EXTRACT(doy FROM bookings_source_src_28000.paid_at) AS booking__paid_at__extract_doy + , bookings_source_src_28000.listing_id AS listing + , bookings_source_src_28000.guest_id AS guest + , bookings_source_src_28000.host_id AS host + , bookings_source_src_28000.listing_id AS booking__listing + , bookings_source_src_28000.guest_id AS booking__guest + , bookings_source_src_28000.host_id AS booking__host + FROM ***************************.fct_bookings bookings_source_src_28000 + ) subq_0 + ) subq_1 + ) subq_2 + WHERE ((booking__is_instant) AND (listing IS NOT NULL)) AND (metric_time__day > '2020-01-01') + ) subq_3 + ) subq_4 + GROUP BY + subq_4.metric_time__day + , subq_4.booking__is_instant + ) subq_5 + ON + subq_6.metric_time__day = subq_5.metric_time__day + ) subq_8 + WHERE metric_time__day > '2020-01-01' +) subq_9 diff --git a/tests_metricflow/snapshots/test_time_spine_join_rendering.py/SqlQueryPlan/Trino/test_join_to_time_spine_with_input_measure_constraint__plan0_optimized.sql b/tests_metricflow/snapshots/test_time_spine_join_rendering.py/SqlQueryPlan/Trino/test_join_to_time_spine_with_input_measure_constraint__plan0_optimized.sql new file mode 100644 index 0000000000..c3948c32d3 --- /dev/null +++ b/tests_metricflow/snapshots/test_time_spine_join_rendering.py/SqlQueryPlan/Trino/test_join_to_time_spine_with_input_measure_constraint__plan0_optimized.sql @@ -0,0 +1,41 @@ +-- Constrain Output with WHERE +-- Compute Metrics via Expressions +SELECT + metric_time__day + , booking__is_instant + , bookings AS instant_bookings_with_measure_filter +FROM ( + -- Join to Time Spine Dataset + SELECT + subq_17.ds AS metric_time__day + , subq_15.booking__is_instant AS booking__is_instant + , subq_15.bookings AS bookings + FROM ***************************.mf_time_spine subq_17 + LEFT OUTER JOIN ( + -- Constrain Output with WHERE + -- Pass Only Elements: ['bookings', 'booking__is_instant', 'metric_time__day'] + -- Aggregate Measures + SELECT + metric_time__day + , booking__is_instant + , SUM(bookings) AS bookings + FROM ( + -- Read Elements From Semantic Model 'bookings_source' + -- Metric Time Dimension 'ds' + -- Pass Only Elements: ['bookings', 'booking__is_instant', 'metric_time__day', 'listing'] + SELECT + DATE_TRUNC('day', ds) AS metric_time__day + , listing_id AS listing + , is_instant AS booking__is_instant + , 1 AS bookings + FROM ***************************.fct_bookings bookings_source_src_28000 + ) subq_12 + WHERE ((booking__is_instant) AND (listing IS NOT NULL)) AND (metric_time__day > '2020-01-01') + GROUP BY + metric_time__day + , booking__is_instant + ) subq_15 + ON + subq_17.ds = subq_15.metric_time__day +) subq_18 +WHERE metric_time__day > '2020-01-01'