diff --git a/.changes/unreleased/Features-20231009-210737.yaml b/.changes/unreleased/Features-20231009-210737.yaml new file mode 100644 index 00000000..31b530db --- /dev/null +++ b/.changes/unreleased/Features-20231009-210737.yaml @@ -0,0 +1,7 @@ +kind: Features +body: Allow metric filters and saved query where properties to accept lists of filter + expressions +time: 2023-10-09T21:07:37.978465-07:00 +custom: + Author: tlento + Issue: "147" diff --git a/dbt_semantic_interfaces/parsing/generated_json_schemas/default_explicit_schema.json b/dbt_semantic_interfaces/parsing/generated_json_schemas/default_explicit_schema.json index 784ba5b0..7d0c3253 100644 --- a/dbt_semantic_interfaces/parsing/generated_json_schemas/default_explicit_schema.json +++ b/dbt_semantic_interfaces/parsing/generated_json_schemas/default_explicit_schema.json @@ -139,6 +139,20 @@ ], "type": "object" }, + "filter_schema": { + "$id": "filter_schema", + "oneOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ] + }, "is-time-dimension": { "properties": { "type": { @@ -234,7 +248,7 @@ "type": "integer" }, "filter": { - "type": "string" + "$ref": "#/definitions/filter_schema" }, "join_to_timespine": { "type": "boolean" @@ -255,7 +269,7 @@ "type": "string" }, "filter": { - "type": "string" + "$ref": "#/definitions/filter_schema" }, "name": { "type": "string" @@ -277,7 +291,7 @@ "type": "string" }, "filter": { - "type": "string" + "$ref": "#/definitions/filter_schema" }, "label": { "type": "string" @@ -435,10 +449,7 @@ "type": "string" }, "where": { - "items": { - "type": "string" - }, - "type": "array" + "$ref": "#/definitions/filter_schema" } }, "required": [ diff --git a/dbt_semantic_interfaces/parsing/schemas.py b/dbt_semantic_interfaces/parsing/schemas.py index a0256b07..5262b786 100644 --- a/dbt_semantic_interfaces/parsing/schemas.py +++ b/dbt_semantic_interfaces/parsing/schemas.py @@ -39,6 +39,17 @@ time_dimension_type_values = ["TIME", "time"] +filter_schema = { + "$id": "filter_schema", + "oneOf": [ + {"type": "string"}, + { + "type": "array", + "items": {"type": "string"}, + } + ] +} + metric_input_measure_schema = { "$id": "metric_input_measure_schema", "oneOf": [ @@ -47,7 +58,7 @@ "type": "object", "properties": { "name": {"type": "string"}, - "filter": {"type": "string"}, + "filter": {"$ref": "filter_schema"}, "alias": {"type": "string"}, "join_to_timespine": {"type": "boolean"}, "fill_nulls_with": {"type": "integer"}, @@ -62,7 +73,7 @@ "type": "object", "properties": { "name": {"type": "string"}, - "filter": {"type": "string"}, + "filter": {"$ref": "filter_schema"}, "alias": {"type": "string"}, "offset_window": {"type": "string"}, "offset_to_grain": {"type": "string"}, @@ -218,7 +229,7 @@ }, "type": {"enum": metric_types_enum_values}, "type_params": {"$ref": "metric_type_params"}, - "filter": {"type": "string"}, + "filter": {"$ref": "filter_schema"}, "description": {"type": "string"}, "label": {"type": "string"}, }, @@ -292,10 +303,7 @@ "type": "array", "items": {"type": "string"}, }, - "where": { - "type": "array", - "items": {"type": "string"}, - }, + "where": {"$ref": "filter_schema"}, "label": {"type": "string"}, }, "required": ["name", "metrics"], @@ -333,6 +341,7 @@ project_configuration_schema["$id"]: project_configuration_schema, saved_query_schema["$id"]: saved_query_schema, # Sub-object schemas + filter_schema["$id"]: filter_schema, metric_input_measure_schema["$id"]: metric_input_measure_schema, metric_type_params_schema["$id"]: metric_type_params_schema, entity_schema["$id"]: entity_schema, diff --git a/tests/parsing/test_metric_parsing.py b/tests/parsing/test_metric_parsing.py index b88b4814..dba46209 100644 --- a/tests/parsing/test_metric_parsing.py +++ b/tests/parsing/test_metric_parsing.py @@ -342,6 +342,37 @@ def test_constraint_metric_parsing() -> None: ) +def test_constraint_list_metric_parsing() -> None: + """Test for parsing a metric specification with a list of constraints included.""" + yaml_contents = textwrap.dedent( + """\ + metric: + name: constraint_test + type: simple + type_params: + measure: + name: input_measure + filter: + - "{{ dimension('some_dimension') }} IN ('value1', 'value2')" + - "1 > 0" + """ + ) + file = YamlConfigFile(filepath="inline_for_test", contents=yaml_contents) + + build_result = parse_yaml_files_to_semantic_manifest(files=[file, EXAMPLE_PROJECT_CONFIGURATION_YAML_CONFIG_FILE]) + + assert len(build_result.semantic_manifest.metrics) == 1 + metric = build_result.semantic_manifest.metrics[0] + assert metric.name == "constraint_test" + assert metric.type is MetricType.SIMPLE + assert metric.filter == PydanticWhereFilterIntersection( + where_filters=[ + PydanticWhereFilter(where_sql_template="{{ dimension('some_dimension') }} IN ('value1', 'value2')"), + PydanticWhereFilter(where_sql_template="1 > 0"), + ] + ) + + def test_derived_metric_input_parsing() -> None: """Test for parsing derived metrics with metric_input properties.""" yaml_contents = textwrap.dedent(