diff --git a/metricflow-semantics/metricflow_semantics/test_helpers/semantic_manifest_yamls/ambiguous_resolution_manifest/metrics.yaml b/metricflow-semantics/metricflow_semantics/test_helpers/semantic_manifest_yamls/ambiguous_resolution_manifest/metrics.yaml index 706d9558c9..9c3ebbc576 100644 --- a/metricflow-semantics/metricflow_semantics/test_helpers/semantic_manifest_yamls/ambiguous_resolution_manifest/metrics.yaml +++ b/metricflow-semantics/metricflow_semantics/test_helpers/semantic_manifest_yamls/ambiguous_resolution_manifest/metrics.yaml @@ -92,3 +92,31 @@ metric: metrics: - name: monthly_metric_0 filter: "{{ TimeDimension('metric_time') }} = '2020-01-01'" +--- +metric: + name: simple_metric_with_time_granularity + description: Simple metric with time granularity + type: simple + type_params: + measure: monthly_measure_1 + time_granularity: quarter +--- +metric: + name: derived_metric_with_time_granularity + description: Derived metric with time granularity + type: derived + time_granularity: year + type_params: + expr: simple_metric_with_time_granularity * 2 + metrics: + - name: simple_metric_with_time_granularity +--- +metric: + name: derived_metric_without_time_granularity + description: Derived metric without time granularity + type: derived + type_params: + expr: simple_metric_with_time_granularity * monthly_metric_0 + metrics: + - name: simple_metric_with_time_granularity + - name: monthly_metric_0 diff --git a/metricflow-semantics/tests_metricflow_semantics/query/test_metric_time_granularity.py b/metricflow-semantics/tests_metricflow_semantics/query/test_metric_time_granularity.py new file mode 100644 index 0000000000..b40773070b --- /dev/null +++ b/metricflow-semantics/tests_metricflow_semantics/query/test_metric_time_granularity.py @@ -0,0 +1,119 @@ +from __future__ import annotations + +import logging + +import pytest +from _pytest.fixtures import FixtureRequest +from metricflow_semantics.model.semantic_manifest_lookup import SemanticManifestLookup +from metricflow_semantics.query.query_exceptions import InvalidQueryException +from metricflow_semantics.query.query_parser import MetricFlowQueryParser +from metricflow_semantics.test_helpers.config_helpers import MetricFlowTestConfiguration +from metricflow_semantics.test_helpers.snapshot_helpers import assert_object_snapshot_equal, assert_str_snapshot_equal + + +@pytest.fixture +def query_parser( # noqa: D103 + simple_semantic_manifest_lookup: SemanticManifestLookup, +) -> MetricFlowQueryParser: + return MetricFlowQueryParser(semantic_manifest_lookup=simple_semantic_manifest_lookup) + + +@pytest.fixture +def ambiguous_resolution_query_parser( # noqa: D103 + ambiguous_resolution_manifest_lookup: SemanticManifestLookup, +) -> MetricFlowQueryParser: + return MetricFlowQueryParser(semantic_manifest_lookup=ambiguous_resolution_manifest_lookup) + + +def test_simple_metric_with_explicit_time_granularity( # noqa: D + request: FixtureRequest, + mf_test_configuration: MetricFlowTestConfiguration, + query_parser: MetricFlowQueryParser, +) -> None: + query_spec = query_parser.parse_and_validate_query( + metric_names=["largest_listing"], group_by_names=["metric_time"] + ).query_spec + + assert_object_snapshot_equal( + request=request, + mf_test_configuration=mf_test_configuration, + obj_id="result_0", + obj=query_spec, + ) + + +def test_simple_metric_without_explicit_time_granularity( + request: FixtureRequest, + mf_test_configuration: MetricFlowTestConfiguration, + ambiguous_resolution_query_parser: MetricFlowQueryParser, +) -> None: + """Tests that a metric without default granularity uses the min granualrity for its agg_time_dim.""" + query_spec = ambiguous_resolution_query_parser.parse_and_validate_query( + metric_names=["monthly_metric_0"], + group_by_names=["metric_time"], + ).query_spec + + assert_object_snapshot_equal( + request=request, + mf_test_configuration=mf_test_configuration, + obj_id="result_0", + obj=query_spec, + ) + + +def test_derived_metric_with_explicit_time_granularity( + request: FixtureRequest, + mf_test_configuration: MetricFlowTestConfiguration, + ambiguous_resolution_query_parser: MetricFlowQueryParser, +) -> None: + """Tests that a derived metric with default granularity ignores the default granularities set on its input metrics.""" + query_spec = ambiguous_resolution_query_parser.parse_and_validate_query( + metric_names=["derived_metric_with_time_granularity"], + group_by_names=["metric_time"], + ).query_spec + + assert_object_snapshot_equal( + request=request, + mf_test_configuration=mf_test_configuration, + obj_id="result_0", + obj=query_spec, + ) + + +def test_derived_metric_without_explicit_time_granularity( + request: FixtureRequest, + mf_test_configuration: MetricFlowTestConfiguration, + ambiguous_resolution_query_parser: MetricFlowQueryParser, +) -> None: + """Tests a derived metric without explicit default granularity. + + Should ignore the default granularities set on its input metrics. + """ + query_spec = ambiguous_resolution_query_parser.parse_and_validate_query( + metric_names=["derived_metric_without_time_granularity"], + group_by_names=["metric_time"], + ).query_spec + + assert_object_snapshot_equal( + request=request, + mf_test_configuration=mf_test_configuration, + obj_id="result_0", + obj=query_spec, + ) + + +def test_non_metric_time_ignores_default_granularity( # noqa: D + request: FixtureRequest, + mf_test_configuration: MetricFlowTestConfiguration, + query_parser: MetricFlowQueryParser, +) -> None: + query_spec = query_parser.parse_and_validate_query( + metric_names=["largest_listing"], group_by_names=["listing__ds"] + ).query_spec + + assert_object_snapshot_equal( + request=request, + mf_test_configuration=mf_test_configuration, + obj_id="result_0", + obj=query_spec, + ) diff --git a/metricflow-semantics/tests_metricflow_semantics/query/test_query_parser.py b/metricflow-semantics/tests_metricflow_semantics/query/test_query_parser.py index 4186116ccc..1bbd18fe0c 100644 --- a/metricflow-semantics/tests_metricflow_semantics/query/test_query_parser.py +++ b/metricflow-semantics/tests_metricflow_semantics/query/test_query_parser.py @@ -83,7 +83,6 @@ type_params: measure: bookings filter: "{{ Dimension('booking__is_instant') }}" - time_granularity: year --- metric: name: month_bookings @@ -659,34 +658,3 @@ def test_invalid_group_by_metric(bookings_query_parser: MetricFlowQueryParser) - bookings_query_parser.parse_and_validate_query( metric_names=("bookings",), where_constraint_str="{{ Metric('listings', ['garbage']) }} > 1" ) - - -def test_default_granularity(bookings_query_parser: MetricFlowQueryParser) -> None: - """Tests different scenarios using default granularity.""" - # Metric with default_granularity set - query_spec = bookings_query_parser.parse_and_validate_query( - metric_names=("instant_bookings",), group_by_names=("metric_time",) - ).query_spec - assert len(query_spec.time_dimension_specs) == 1 - assert query_spec.time_dimension_specs[0] == MTD_SPEC_YEAR - - # Metric without default_granularity set - query_spec = bookings_query_parser.parse_and_validate_query( - metric_names=("month_bookings",), group_by_names=("metric_time",) - ).query_spec - assert len(query_spec.time_dimension_specs) == 1 - assert query_spec.time_dimension_specs[0] == MTD_SPEC_MONTH - - # Derived metric with different agg_time_dimensions and no default granularity set - query_spec = bookings_query_parser.parse_and_validate_query( - metric_names=("instant_plus_months_bookings",), group_by_names=("metric_time",) - ).query_spec - assert len(query_spec.time_dimension_specs) == 1 - assert query_spec.time_dimension_specs[0] == MTD_SPEC_MONTH - - # Using non-metric_time - should ignore default granularity - query_spec = bookings_query_parser.parse_and_validate_query( - metric_names=("instant_bookings",), group_by_names=("booking__ds",) - ).query_spec - assert len(query_spec.time_dimension_specs) == 1 - assert query_spec.time_dimension_specs[0].time_granularity == TimeGranularity.DAY diff --git a/metricflow-semantics/tests_metricflow_semantics/snapshots/test_metric_time_granularity.py/MetricFlowQuerySpec/test_derived_metric_with_explicit_time_granularity__result_0.txt b/metricflow-semantics/tests_metricflow_semantics/snapshots/test_metric_time_granularity.py/MetricFlowQuerySpec/test_derived_metric_with_explicit_time_granularity__result_0.txt new file mode 100644 index 0000000000..1cbbd0e8be --- /dev/null +++ b/metricflow-semantics/tests_metricflow_semantics/snapshots/test_metric_time_granularity.py/MetricFlowQuerySpec/test_derived_metric_with_explicit_time_granularity__result_0.txt @@ -0,0 +1,7 @@ +MetricFlowQuerySpec( + metric_specs=(MetricSpec(element_name='derived_metric_with_time_granularity'),), + time_dimension_specs=(TimeDimensionSpec(element_name='metric_time', time_granularity=YEAR),), + filter_intersection=PydanticWhereFilterIntersection(), + filter_spec_resolution_lookup=FilterSpecResolutionLookUp(), + min_max_only=False, +) diff --git a/metricflow-semantics/tests_metricflow_semantics/snapshots/test_metric_time_granularity.py/MetricFlowQuerySpec/test_derived_metric_without_explicit_time_granularity__result_0.txt b/metricflow-semantics/tests_metricflow_semantics/snapshots/test_metric_time_granularity.py/MetricFlowQuerySpec/test_derived_metric_without_explicit_time_granularity__result_0.txt new file mode 100644 index 0000000000..e128590790 --- /dev/null +++ b/metricflow-semantics/tests_metricflow_semantics/snapshots/test_metric_time_granularity.py/MetricFlowQuerySpec/test_derived_metric_without_explicit_time_granularity__result_0.txt @@ -0,0 +1,7 @@ +MetricFlowQuerySpec( + metric_specs=(MetricSpec(element_name='derived_metric_without_time_granularity'),), + time_dimension_specs=(TimeDimensionSpec(element_name='metric_time', time_granularity=MONTH),), + filter_intersection=PydanticWhereFilterIntersection(), + filter_spec_resolution_lookup=FilterSpecResolutionLookUp(), + min_max_only=False, +) diff --git a/metricflow-semantics/tests_metricflow_semantics/snapshots/test_metric_time_granularity.py/MetricFlowQuerySpec/test_non_metric_time_ignores_default_granularity__result_0.txt b/metricflow-semantics/tests_metricflow_semantics/snapshots/test_metric_time_granularity.py/MetricFlowQuerySpec/test_non_metric_time_ignores_default_granularity__result_0.txt new file mode 100644 index 0000000000..a009b6c10d --- /dev/null +++ b/metricflow-semantics/tests_metricflow_semantics/snapshots/test_metric_time_granularity.py/MetricFlowQuerySpec/test_non_metric_time_ignores_default_granularity__result_0.txt @@ -0,0 +1,13 @@ +MetricFlowQuerySpec( + metric_specs=(MetricSpec(element_name='largest_listing'),), + time_dimension_specs=( + TimeDimensionSpec( + element_name='ds', + entity_links=(EntityReference(element_name='listing'),), + time_granularity=DAY, + ), + ), + filter_intersection=PydanticWhereFilterIntersection(), + filter_spec_resolution_lookup=FilterSpecResolutionLookUp(), + min_max_only=False, +) diff --git a/metricflow-semantics/tests_metricflow_semantics/snapshots/test_metric_time_granularity.py/MetricFlowQuerySpec/test_simple_metric_with_explicit_time_granularity__result_0.txt b/metricflow-semantics/tests_metricflow_semantics/snapshots/test_metric_time_granularity.py/MetricFlowQuerySpec/test_simple_metric_with_explicit_time_granularity__result_0.txt new file mode 100644 index 0000000000..56b55e7f8c --- /dev/null +++ b/metricflow-semantics/tests_metricflow_semantics/snapshots/test_metric_time_granularity.py/MetricFlowQuerySpec/test_simple_metric_with_explicit_time_granularity__result_0.txt @@ -0,0 +1,7 @@ +MetricFlowQuerySpec( + metric_specs=(MetricSpec(element_name='largest_listing'),), + time_dimension_specs=(TimeDimensionSpec(element_name='metric_time', time_granularity=MONTH),), + filter_intersection=PydanticWhereFilterIntersection(), + filter_spec_resolution_lookup=FilterSpecResolutionLookUp(), + min_max_only=False, +) diff --git a/metricflow-semantics/tests_metricflow_semantics/snapshots/test_metric_time_granularity.py/MetricFlowQuerySpec/test_simple_metric_without_explicit_time_granularity__result_0.txt b/metricflow-semantics/tests_metricflow_semantics/snapshots/test_metric_time_granularity.py/MetricFlowQuerySpec/test_simple_metric_without_explicit_time_granularity__result_0.txt new file mode 100644 index 0000000000..e4e886ec47 --- /dev/null +++ b/metricflow-semantics/tests_metricflow_semantics/snapshots/test_metric_time_granularity.py/MetricFlowQuerySpec/test_simple_metric_without_explicit_time_granularity__result_0.txt @@ -0,0 +1,7 @@ +MetricFlowQuerySpec( + metric_specs=(MetricSpec(element_name='monthly_metric_0'),), + time_dimension_specs=(TimeDimensionSpec(element_name='metric_time', time_granularity=MONTH),), + filter_intersection=PydanticWhereFilterIntersection(), + filter_spec_resolution_lookup=FilterSpecResolutionLookUp(), + min_max_only=False, +)