From 17fcee0f2526134ae716febb2ec9f736fe27fe32 Mon Sep 17 00:00:00 2001 From: Paul Yang Date: Tue, 8 Aug 2023 15:56:21 -0700 Subject: [PATCH] Re-add validation to the manifests used for testing and fix raised issues. --- metricflow/test/fixtures/model_fixtures.py | 73 +++++++------------ .../bookings_from_sql_query_source.yaml | 29 -------- .../bookings_monthly_source.yaml | 14 ++-- .../extended_bookings_source.yaml | 8 +- .../listings_extended_source.yaml | 6 +- .../bridge_table.yaml | 4 +- .../scd_manifest/scd_accounts.yaml | 2 + .../semantic_models/users_latest.yaml | 3 +- .../dim_listings_extended.yaml | 2 +- .../fct_bookings_extended.yaml | 2 +- .../fct_bookings_extended_monthly.yaml | 50 +++++++------ .../test_cases/itest_granularity.yaml | 57 ++++++--------- .../test_semantic_model_join_evaluator.py | 8 +- 13 files changed, 106 insertions(+), 152 deletions(-) delete mode 100644 metricflow/test/fixtures/semantic_manifest_yamls/extended_date_manifest/semantic_models/bookings_from_sql_query_source.yaml diff --git a/metricflow/test/fixtures/model_fixtures.py b/metricflow/test/fixtures/model_fixtures.py index 6d7fcea2ce..c863a1eb00 100644 --- a/metricflow/test/fixtures/model_fixtures.py +++ b/metricflow/test/fixtures/model_fixtures.py @@ -4,10 +4,12 @@ import os from collections import OrderedDict from dataclasses import dataclass -from typing import Dict, List, Sequence +from typing import Dict, List, Optional, Sequence import pytest +from dbt_semantic_interfaces.implementations.semantic_manifest import PydanticSemanticManifest from dbt_semantic_interfaces.parsing.dir_to_model import ( + SemanticManifestBuildResult, parse_directory_of_yaml_files_to_semantic_manifest, parse_yaml_files_to_validation_ready_semantic_manifest, ) @@ -148,6 +150,20 @@ def create_data_sets( return data_sets +def load_semantic_manifest( + relative_manifest_path: str, + template_mapping: Optional[Dict[str, str]] = None, +) -> SemanticManifestBuildResult: + """Reads the manifest YAMLs from the standard location, applies transformations, runs validations.""" + yaml_file_directory = os.path.join(os.path.dirname(__file__), f"semantic_manifest_yamls/{relative_manifest_path}") + build_result = parse_directory_of_yaml_files_to_semantic_manifest( + yaml_file_directory, template_mapping=template_mapping + ) + validator = SemanticManifestValidator[PydanticSemanticManifest]() + validator.checked_validations(build_result.semantic_manifest) + return build_result + + @pytest.fixture(scope="session") def template_mapping(mf_test_session_state: MetricFlowTestSessionState) -> Dict[str, str]: """Mapping for template variables in the model YAML files.""" @@ -156,30 +172,19 @@ def template_mapping(mf_test_session_state: MetricFlowTestSessionState) -> Dict[ @pytest.fixture(scope="session") def simple_semantic_manifest_lookup_non_ds(template_mapping: Dict[str, str]) -> SemanticManifestLookup: # noqa: D - build_result = parse_directory_of_yaml_files_to_semantic_manifest( - os.path.join(os.path.dirname(__file__), "semantic_manifest_yamls/non_sm_manifest"), - template_mapping=template_mapping, - ) + build_result = load_semantic_manifest("non_sm_manifest", template_mapping) return SemanticManifestLookup(build_result.semantic_manifest) @pytest.fixture(scope="session") def simple_semantic_manifest_lookup(template_mapping: Dict[str, str]) -> SemanticManifestLookup: # noqa: D - build_result = parse_directory_of_yaml_files_to_semantic_manifest( - os.path.join(os.path.dirname(__file__), "semantic_manifest_yamls/simple_manifest"), - template_mapping=template_mapping, - ) + build_result = load_semantic_manifest("simple_manifest", template_mapping) return SemanticManifestLookup(build_result.semantic_manifest) @pytest.fixture(scope="session") def multi_hop_join_semantic_manifest_lookup(template_mapping: Dict[str, str]) -> SemanticManifestLookup: # noqa: D - build_result = parse_directory_of_yaml_files_to_semantic_manifest( - os.path.join( - os.path.dirname(__file__), "semantic_manifest_yamls/multi_hop_join_manifest/partitioned_semantic_models" - ), - template_mapping=template_mapping, - ) + build_result = load_semantic_manifest("multi_hop_join_manifest/partitioned_semantic_models", template_mapping) return SemanticManifestLookup(build_result.semantic_manifest) @@ -187,33 +192,21 @@ def multi_hop_join_semantic_manifest_lookup(template_mapping: Dict[str, str]) -> def unpartitioned_multi_hop_join_semantic_manifest_lookup( # noqa: D template_mapping: Dict[str, str] ) -> SemanticManifestLookup: - build_result = parse_directory_of_yaml_files_to_semantic_manifest( - os.path.join( - os.path.dirname(__file__), "semantic_manifest_yamls/multi_hop_join_manifest/unpartitioned_semantic_models" - ), - template_mapping=template_mapping, - ) + build_result = load_semantic_manifest("multi_hop_join_manifest/unpartitioned_semantic_models", template_mapping) return SemanticManifestLookup(build_result.semantic_manifest) @pytest.fixture(scope="session") def simple_semantic_manifest(template_mapping: Dict[str, str]) -> SemanticManifest: """Model used for many tests.""" - build_result = parse_directory_of_yaml_files_to_semantic_manifest( - os.path.join(os.path.dirname(__file__), "semantic_manifest_yamls/simple_manifest"), - template_mapping=template_mapping, - ) + build_result = load_semantic_manifest("simple_manifest", template_mapping) return build_result.semantic_manifest @pytest.fixture(scope="session") def simple_model__with_primary_transforms(template_mapping: Dict[str, str]) -> SemanticManifest: """Model used for tests pre-transformations.""" - build_result = parse_directory_of_yaml_files_to_semantic_manifest( - os.path.join(os.path.dirname(__file__), "semantic_manifest_yamls/simple_manifest"), - template_mapping=template_mapping, - apply_transformations=False, - ) + build_result = load_semantic_manifest("simple_manifest", template_mapping) transformed_model = PydanticSemanticManifestTransformer().transform( model=build_result.semantic_manifest, ordered_rule_sequences=(PydanticSemanticManifestTransformRuleSet().primary_rules,), @@ -223,38 +216,26 @@ def simple_model__with_primary_transforms(template_mapping: Dict[str, str]) -> S @pytest.fixture(scope="session") def extended_date_semantic_manifest_lookup(template_mapping: Dict[str, str]) -> SemanticManifestLookup: # noqa: D - build_result = parse_directory_of_yaml_files_to_semantic_manifest( - os.path.join(os.path.dirname(__file__), "semantic_manifest_yamls/extended_date_manifest"), - template_mapping=template_mapping, - ) + build_result = load_semantic_manifest("extended_date_manifest", template_mapping) return SemanticManifestLookup(build_result.semantic_manifest) @pytest.fixture(scope="session") def scd_semantic_manifest_lookup(template_mapping: Dict[str, str]) -> SemanticManifestLookup: """Initialize semantic model for SCD tests.""" - build_result = parse_directory_of_yaml_files_to_semantic_manifest( - os.path.join(os.path.dirname(__file__), "semantic_manifest_yamls/scd_manifest"), - template_mapping=template_mapping, - ) + build_result = load_semantic_manifest("scd_manifest", template_mapping) return SemanticManifestLookup(build_result.semantic_manifest) @pytest.fixture(scope="session") def data_warehouse_validation_model(template_mapping: Dict[str, str]) -> SemanticManifest: """Model used for data warehouse validation tests.""" - build_result = parse_directory_of_yaml_files_to_semantic_manifest( - os.path.join(os.path.dirname(__file__), "semantic_manifest_yamls/data_warehouse_validation_manifest"), - template_mapping=template_mapping, - ) + build_result = load_semantic_manifest("data_warehouse_validation_manifest", template_mapping) return build_result.semantic_manifest @pytest.fixture(scope="session") def cyclic_join_semantic_manifest_lookup(template_mapping: Dict[str, str]) -> SemanticManifestLookup: """Manifest that contains a potential cycle in the join graph (if not handled properly).""" - build_result = parse_directory_of_yaml_files_to_semantic_manifest( - os.path.join(os.path.dirname(__file__), "semantic_manifest_yamls/cyclic_join_manifest"), - template_mapping=template_mapping, - ) + build_result = load_semantic_manifest("cyclic_join_manifest", template_mapping) return SemanticManifestLookup(build_result.semantic_manifest) diff --git a/metricflow/test/fixtures/semantic_manifest_yamls/extended_date_manifest/semantic_models/bookings_from_sql_query_source.yaml b/metricflow/test/fixtures/semantic_manifest_yamls/extended_date_manifest/semantic_models/bookings_from_sql_query_source.yaml deleted file mode 100644 index bff5acd3ab..0000000000 --- a/metricflow/test/fixtures/semantic_manifest_yamls/extended_date_manifest/semantic_models/bookings_from_sql_query_source.yaml +++ /dev/null @@ -1,29 +0,0 @@ ---- -semantic_model: - name: bookings_from_sql_query_source - description: bookings_from_sql_query_source - - node_relation: - schema_name: $source_schema - alias: fct_bookings_extended - - defaults: - agg_time_dimension: ds - - measures: - - name: bookings_from_sql_query - expr: booking - agg: sum - create_metric: true - - dimensions: - - name: ds - type: time - type_params: - time_granularity: day - - entities: - - name: booking_id - type: primary - - name: listing_id - type: foreign diff --git a/metricflow/test/fixtures/semantic_manifest_yamls/extended_date_manifest/semantic_models/bookings_monthly_source.yaml b/metricflow/test/fixtures/semantic_manifest_yamls/extended_date_manifest/semantic_models/bookings_monthly_source.yaml index 7809a53d22..f98fd08d08 100644 --- a/metricflow/test/fixtures/semantic_manifest_yamls/extended_date_manifest/semantic_models/bookings_monthly_source.yaml +++ b/metricflow/test/fixtures/semantic_manifest_yamls/extended_date_manifest/semantic_models/bookings_monthly_source.yaml @@ -8,19 +8,23 @@ semantic_model: alias: fct_bookings_extended_monthly defaults: - agg_time_dimension: ds + agg_time_dimension: monthly_ds measures: - name: bookings_monthly agg: sum create_metric: true - primary_entity: booking_id + primary_entity: booking dimensions: - - name: ds + - name: monthly_ds + expr: ds type: time type_params: time_granularity: month - - name: is_instant - type: categorical + + entities: + - name: listing + expr: listing_id + type: foreign diff --git a/metricflow/test/fixtures/semantic_manifest_yamls/extended_date_manifest/semantic_models/extended_bookings_source.yaml b/metricflow/test/fixtures/semantic_manifest_yamls/extended_date_manifest/semantic_models/extended_bookings_source.yaml index 72bb210587..1158cf5ad5 100644 --- a/metricflow/test/fixtures/semantic_manifest_yamls/extended_date_manifest/semantic_models/extended_bookings_source.yaml +++ b/metricflow/test/fixtures/semantic_manifest_yamls/extended_date_manifest/semantic_models/extended_bookings_source.yaml @@ -25,11 +25,11 @@ semantic_model: type: time type_params: time_granularity: day - - name: is_instant - type: categorical entities: - - name: booking_id + - name: booking + expr: booking_id type: primary - - name: listing_id + - name: listing + expr: listing_id type: foreign diff --git a/metricflow/test/fixtures/semantic_manifest_yamls/extended_date_manifest/semantic_models/listings_extended_source.yaml b/metricflow/test/fixtures/semantic_manifest_yamls/extended_date_manifest/semantic_models/listings_extended_source.yaml index 6baf1a14c6..6b18edb526 100644 --- a/metricflow/test/fixtures/semantic_manifest_yamls/extended_date_manifest/semantic_models/listings_extended_source.yaml +++ b/metricflow/test/fixtures/semantic_manifest_yamls/extended_date_manifest/semantic_models/listings_extended_source.yaml @@ -8,11 +8,13 @@ semantic_model: alias: dim_listings_extended dimensions: - - name: listing_creation_ds + - name: ds + expr: listing_creation_ds type: time type_params: time_granularity: day entities: - - name: listing_id + - name: listing + expr: listing_id type: primary diff --git a/metricflow/test/fixtures/semantic_manifest_yamls/multi_hop_join_manifest/partitioned_semantic_models/bridge_table.yaml b/metricflow/test/fixtures/semantic_manifest_yamls/multi_hop_join_manifest/partitioned_semantic_models/bridge_table.yaml index 7dc099c9c7..3f804148fb 100644 --- a/metricflow/test/fixtures/semantic_manifest_yamls/multi_hop_join_manifest/partitioned_semantic_models/bridge_table.yaml +++ b/metricflow/test/fixtures/semantic_manifest_yamls/multi_hop_join_manifest/partitioned_semantic_models/bridge_table.yaml @@ -16,8 +16,10 @@ semantic_model: time_granularity: day is_partition: true + primary_entity: bridge_account + entities: - name: account_id - type: primary + type: unique - name: customer_id type: foreign diff --git a/metricflow/test/fixtures/semantic_manifest_yamls/scd_manifest/scd_accounts.yaml b/metricflow/test/fixtures/semantic_manifest_yamls/scd_manifest/scd_accounts.yaml index 1387a557d0..6753051366 100644 --- a/metricflow/test/fixtures/semantic_manifest_yamls/scd_manifest/scd_accounts.yaml +++ b/metricflow/test/fixtures/semantic_manifest_yamls/scd_manifest/scd_accounts.yaml @@ -25,6 +25,8 @@ semantic_model: - name: account_type type: categorical + primary_entity: scd_user + entities: - name: user type: natural diff --git a/metricflow/test/fixtures/semantic_manifest_yamls/simple_manifest/semantic_models/users_latest.yaml b/metricflow/test/fixtures/semantic_manifest_yamls/simple_manifest/semantic_models/users_latest.yaml index d85c37b44b..44134d966b 100644 --- a/metricflow/test/fixtures/semantic_manifest_yamls/simple_manifest/semantic_models/users_latest.yaml +++ b/metricflow/test/fixtures/semantic_manifest_yamls/simple_manifest/semantic_models/users_latest.yaml @@ -8,8 +8,9 @@ semantic_model: alias: dim_users_latest dimensions: - - name: ds + - name: ds_latest type: time + expr: ds type_params: time_granularity: day - name: home_state_latest diff --git a/metricflow/test/fixtures/source_table_snapshots/extended_date_model/dim_listings_extended.yaml b/metricflow/test/fixtures/source_table_snapshots/extended_date_model/dim_listings_extended.yaml index 05b68cb033..3f5f45351f 100644 --- a/metricflow/test/fixtures/source_table_snapshots/extended_date_model/dim_listings_extended.yaml +++ b/metricflow/test/fixtures/source_table_snapshots/extended_date_model/dim_listings_extended.yaml @@ -4,7 +4,7 @@ table_snapshot: - name: listing_creation_ds type: TIME - name: listing_id - type: INT + type: STRING rows: - ["2020-01-01", "0"] - ["2020-01-02", "1"] diff --git a/metricflow/test/fixtures/source_table_snapshots/extended_date_model/fct_bookings_extended.yaml b/metricflow/test/fixtures/source_table_snapshots/extended_date_model/fct_bookings_extended.yaml index d30fd0533d..69520f4157 100644 --- a/metricflow/test/fixtures/source_table_snapshots/extended_date_model/fct_bookings_extended.yaml +++ b/metricflow/test/fixtures/source_table_snapshots/extended_date_model/fct_bookings_extended.yaml @@ -8,7 +8,7 @@ table_snapshot: - name: booking type: INT - name: listing_id - type: INT + type: STRING - name: is_instant type: BOOLEAN rows: diff --git a/metricflow/test/fixtures/source_table_snapshots/extended_date_model/fct_bookings_extended_monthly.yaml b/metricflow/test/fixtures/source_table_snapshots/extended_date_model/fct_bookings_extended_monthly.yaml index 3b470773d9..29a4ac5bca 100644 --- a/metricflow/test/fixtures/source_table_snapshots/extended_date_model/fct_bookings_extended_monthly.yaml +++ b/metricflow/test/fixtures/source_table_snapshots/extended_date_model/fct_bookings_extended_monthly.yaml @@ -7,28 +7,30 @@ table_snapshot: type: INT - name: is_instant type: BOOLEAN + - name: listing_id + type: STRING rows: - - ["2020-01-01", "10", "True"] - - ["2020-01-01", "5", "False"] - - ["2020-02-01", "10", "True"] - - ["2020-02-01", "5", "False"] - - ["2020-03-01", "10", "True"] - - ["2020-03-01", "5", "False"] - - ["2020-04-01", "10", "True"] - - ["2020-04-01", "5", "False"] - - ["2020-05-01", "10", "True"] - - ["2020-05-01", "5", "False"] - - ["2020-06-01", "10", "True"] - - ["2020-06-01", "5", "False"] - - ["2020-07-01", "10", "True"] - - ["2020-07-01", "5", "False"] - - ["2020-08-01", "10", "True"] - - ["2020-08-01", "5", "False"] - - ["2020-09-01", "10", "True"] - - ["2020-09-01", "5", "False"] - - ["2020-10-01", "10", "True"] - - ["2020-10-01", "5", "False"] - - ["2020-11-01", "10", "True"] - - ["2020-11-01", "5", "False"] - - ["2020-12-01", "10", "True"] - - ["2020-12-01", "5", "False"] + - ["2020-01-01", "10", "True", "0"] + - ["2020-01-01", "5", "False", "1"] + - ["2020-02-01", "10", "True", "2"] + - ["2020-02-01", "5", "False", "3"] + - ["2020-03-01", "10", "True", "4"] + - ["2020-03-01", "5", "False", "5"] + - ["2020-04-01", "10", "True", "6"] + - ["2020-04-01", "5", "False", "7"] + - ["2020-05-01", "10", "True", "8"] + - ["2020-05-01", "5", "False", "9"] + - ["2020-06-01", "10", "True", "0"] + - ["2020-06-01", "5", "False", "0"] + - ["2020-07-01", "10", "True", "1"] + - ["2020-07-01", "5", "False", "2"] + - ["2020-08-01", "10", "True", "3"] + - ["2020-08-01", "5", "False", "4"] + - ["2020-09-01", "10", "True", "5"] + - ["2020-09-01", "5", "False", "6"] + - ["2020-10-01", "10", "True", "7"] + - ["2020-10-01", "5", "False", "8"] + - ["2020-11-01", "10", "True", "9"] + - ["2020-11-01", "5", "False", "0"] + - ["2020-12-01", "10", "True", "0"] + - ["2020-12-01", "5", "False", "1"] diff --git a/metricflow/test/integration/test_cases/itest_granularity.yaml b/metricflow/test/integration/test_cases/itest_granularity.yaml index 3c7da50078..7aee578af1 100644 --- a/metricflow/test/integration/test_cases/itest_granularity.yaml +++ b/metricflow/test/integration/test_cases/itest_granularity.yaml @@ -144,46 +144,32 @@ integration_test: description: Query a count distinct metric by time granularities. model: EXTENDED_DATE_MODEL metrics: ["bookings"] - group_bys: ["listing_id__listing_creation_ds__day"] + group_bys: ["listing__ds__day"] check_query: | SELECT SUM(booking) AS bookings - , {{ render_date_trunc("ds", TimeGranularity.DAY) }} AS listing_id__listing_creation_ds__day + , {{ render_date_trunc("ds", TimeGranularity.DAY) }} AS listing__ds__day FROM {{ source_schema }}.fct_bookings_extended b LEFT OUTER JOIN {{ source_schema }}.dim_listings_extended l ON b.listing_id = l.listing_id GROUP BY - listing_id__listing_creation_ds__day + 2 --- integration_test: name: query_granularity_for_joined_dundered_dimension_month description: Query a count distinct metric by time granularities. model: EXTENDED_DATE_MODEL metrics: ["bookings"] - group_bys: ["listing_id__listing_creation_ds__month"] + group_bys: ["listing__ds__month"] check_query: | SELECT SUM(booking) AS bookings - , {{ render_date_trunc("l.listing_creation_ds", TimeGranularity.MONTH) }} AS listing_id__listing_creation_ds__month + , {{ render_date_trunc("l.listing_creation_ds", TimeGranularity.MONTH) }} AS listing__ds__month FROM {{ source_schema }}.fct_bookings_extended b LEFT OUTER JOIN {{ source_schema }}.dim_listings_extended l ON b.listing_id = l.listing_id GROUP BY - listing_id__listing_creation_ds__month ---- -integration_test: - name: query_granularity_from_sql_query - description: Query a metric from a sql query by time granularities. - model: EXTENDED_DATE_MODEL - metrics: ["bookings_from_sql_query"] - group_bys: ["metric_time__week"] - check_query: | - SELECT - SUM(booking) AS bookings_from_sql_query - , {{ render_date_trunc("ds", TimeGranularity.WEEK) }} AS metric_time__week - FROM {{ source_schema }}.fct_bookings_extended - GROUP BY - metric_time__week + 2 --- integration_test: name: metric_with_non_day_granularity_expected_boundary @@ -290,34 +276,37 @@ integration_test: metric_time__month --- integration_test: - name: metrics_with_different_time_granularities_and_no_time_dim - description: Query two metrics with different time granularities, but without a time dimension. + name: metrics_with_different_time_granularities_and_no_metric_time + description: Query two metrics with different time granularities with a common dimension, but no metric time. model: EXTENDED_DATE_MODEL metrics: ["bookings_monthly", "bookings"] - group_bys: ["booking_id__is_instant"] + group_bys: ["listing__ds"] time_constraint: ["2020-01-15", "2020-02-15"] check_query: | SELECT - SUM(bookings_monthly) AS bookings_monthly - , SUM(bookings) AS bookings - , a.is_instant AS booking_id__is_instant + a.bookings_monthly AS bookings_monthly + , b.bookings AS bookings + , COALESCE(a.listing__ds__day, b.listing__ds__day) AS listing__ds__day FROM ( SELECT SUM(bookings_monthly) AS bookings_monthly - , is_instant - FROM {{ source_schema }}.fct_bookings_extended_monthly + , l.listing_creation_ds AS listing__ds__day + FROM {{ source_schema }}.fct_bookings_extended_monthly b + LEFT OUTER JOIN {{ source_schema }}.dim_listings_extended l + ON b.listing_id = l.listing_id WHERE {{ render_time_constraint("ds", "2020-01-01", "2020-02-29") }} - GROUP BY is_instant + GROUP BY 2 ) a FULL OUTER JOIN ( SELECT SUM(booking) AS bookings - , is_instant - FROM {{ source_schema }}.fct_bookings_extended + , l.listing_creation_ds AS listing__ds__day + FROM {{ source_schema }}.fct_bookings_extended b + LEFT OUTER JOIN {{ source_schema }}.dim_listings_extended l + ON b.listing_id = l.listing_id WHERE {{ render_time_constraint("ds", "2020-01-01", "2020-02-29") }} - GROUP BY is_instant + GROUP BY 2 ) b - ON a.is_instant = b.is_instant - GROUP BY a.is_instant + ON a.listing__ds__day = b.listing__ds__day diff --git a/metricflow/test/model/semantics/test_semantic_model_join_evaluator.py b/metricflow/test/model/semantics/test_semantic_model_join_evaluator.py index b888ce8293..e483facc58 100644 --- a/metricflow/test/model/semantics/test_semantic_model_join_evaluator.py +++ b/metricflow/test/model/semantics/test_semantic_model_join_evaluator.py @@ -325,7 +325,7 @@ def test_get_joinable_semantic_models_single_hop( # noqa: D right_semantic_model_reference=SemanticModelReference(semantic_model_name="bridge_table"), entity_reference=EntityReference(element_name="account_id"), join_type=SemanticModelEntityJoinType( - left_entity_type=EntityType.PRIMARY, right_entity_type=EntityType.PRIMARY + left_entity_type=EntityType.PRIMARY, right_entity_type=EntityType.UNIQUE ), ) ], @@ -352,7 +352,7 @@ def test_get_joinable_semantic_models_multi_hop( # noqa: D right_semantic_model_reference=SemanticModelReference(semantic_model_name="bridge_table"), entity_reference=EntityReference(element_name="account_id"), join_type=SemanticModelEntityJoinType( - left_entity_type=EntityType.PRIMARY, right_entity_type=EntityType.PRIMARY + left_entity_type=EntityType.PRIMARY, right_entity_type=EntityType.UNIQUE ), ) ], @@ -364,7 +364,7 @@ def test_get_joinable_semantic_models_multi_hop( # noqa: D right_semantic_model_reference=SemanticModelReference(semantic_model_name="bridge_table"), entity_reference=EntityReference(element_name="account_id"), join_type=SemanticModelEntityJoinType( - left_entity_type=EntityType.PRIMARY, right_entity_type=EntityType.PRIMARY + left_entity_type=EntityType.PRIMARY, right_entity_type=EntityType.UNIQUE ), ), SemanticModelEntityJoin( @@ -383,7 +383,7 @@ def test_get_joinable_semantic_models_multi_hop( # noqa: D right_semantic_model_reference=SemanticModelReference(semantic_model_name="bridge_table"), entity_reference=EntityReference(element_name="account_id"), join_type=SemanticModelEntityJoinType( - left_entity_type=EntityType.PRIMARY, right_entity_type=EntityType.PRIMARY + left_entity_type=EntityType.PRIMARY, right_entity_type=EntityType.UNIQUE ), ), SemanticModelEntityJoin(