diff --git a/CHANGELOG.md b/CHANGELOG.md index e0012197..da3b225b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,10 +10,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - add `extracted_or_rule_labels` to query builder globals +- add two matched organizations to the test dummy data ### Changes - rename short and obscure cypher query variables to more expressive and verbose ones +- rename `stable_target_id` to more appropriate `identifier` argument for merged queries ### Deprecated diff --git a/mex/backend/graph/connector.py b/mex/backend/graph/connector.py index 283446f2..06d65ef1 100644 --- a/mex/backend/graph/connector.py +++ b/mex/backend/graph/connector.py @@ -289,7 +289,7 @@ def fetch_rule_items( def fetch_merged_items( self, query_string: str | None, - stable_target_id: str | None, + identifier: str | None, entity_type: Sequence[str] | None, skip: int, limit: int, @@ -298,7 +298,7 @@ def fetch_merged_items( Args: query_string: Optional full text search query term - stable_target_id: Optional stable target ID filter + identifier: Optional merged item identifier filter entity_type: Optional merged entity type filter skip: How many items to skip for pagination limit: How many items to return at most @@ -309,12 +309,12 @@ def fetch_merged_items( query_builder = QueryBuilder.get() query = query_builder.fetch_merged_items( filter_by_query_string=bool(query_string), - filter_by_stable_target_id=bool(stable_target_id), + filter_by_identifier=bool(identifier), ) result = self.commit( query, query_string=query_string, - stable_target_id=stable_target_id, + identifier=identifier, labels=entity_type or list(MERGED_MODEL_CLASSES_BY_NAME), skip=skip, limit=limit, diff --git a/mex/backend/graph/cypher/fetch_merged_items.cql b/mex/backend/graph/cypher/fetch_merged_items.cql index e45f344a..72dabe11 100644 --- a/mex/backend/graph/cypher/fetch_merged_items.cql +++ b/mex/backend/graph/cypher/fetch_merged_items.cql @@ -8,7 +8,7 @@ Globals: Args: filter_by_query_string: Whether the final query should accept a full text query string - filter_by_stable_target_id: Whether the final query should filter by stableTargetId + filter_by_identifier: Whether the final query should filter by the merged identifier Returns: total: Count of all items found by this query @@ -31,8 +31,8 @@ CALL () { <%- if filter_by_query_string %> <>elementId(hit) = elementId(extracted_or_rule_node) <%- endif %> - <%- if filter_by_stable_target_id %> - <>merged_node.identifier = $stable_target_id + <%- if filter_by_identifier %> + <>merged_node.identifier = $identifier <%- endif %> <>ANY(label IN labels(merged_node) WHERE label IN $labels) WITH DISTINCT merged_node AS merged_node diff --git a/mex/backend/merged/helpers.py b/mex/backend/merged/helpers.py index 8e2659d0..3aae619f 100644 --- a/mex/backend/merged/helpers.py +++ b/mex/backend/merged/helpers.py @@ -224,7 +224,7 @@ def merge_search_result_item( @overload def search_merged_items_in_graph( query_string: str | None = None, - stable_target_id: str | None = None, + identifier: str | None = None, entity_type: list[str] | None = None, skip: int = 0, limit: int = 100, @@ -235,7 +235,7 @@ def search_merged_items_in_graph( @overload def search_merged_items_in_graph( query_string: str | None = None, - stable_target_id: str | None = None, + identifier: str | None = None, entity_type: list[str] | None = None, skip: int = 0, limit: int = 100, @@ -245,7 +245,7 @@ def search_merged_items_in_graph( def search_merged_items_in_graph( # noqa: PLR0913 query_string: str | None = None, - stable_target_id: str | None = None, + identifier: str | None = None, entity_type: list[str] | None = None, skip: int = 0, limit: int = 100, @@ -255,7 +255,7 @@ def search_merged_items_in_graph( # noqa: PLR0913 Args: query_string: Full text search query term - stable_target_id: Optional stable target ID filter + identifier: Optional merged item identifier filter entity_type: Optional entity type filter skip: How many items to skip for pagination limit: How many items to return at most @@ -272,7 +272,7 @@ def search_merged_items_in_graph( # noqa: PLR0913 graph = GraphConnector.get() result = graph.fetch_merged_items( query_string=query_string, - stable_target_id=stable_target_id, + identifier=identifier, entity_type=entity_type, skip=skip, limit=limit, diff --git a/pdm.lock b/pdm.lock index abd11b20..c576bae6 100644 --- a/pdm.lock +++ b/pdm.lock @@ -5,7 +5,7 @@ groups = ["default", "dev"] strategy = ["inherit_metadata"] lock_version = "4.5.0" -content_hash = "sha256:a720fdf342f3f470525fe51769327141a59df5c4132ab63386805f2f210de85f" +content_hash = "sha256:f2007b6143bd40d05b587b3044b6e9b5a270a55917021d33411460221c9a85ec" [[metadata.targets]] requires_python = "==3.11.*" @@ -539,11 +539,11 @@ files = [ [[package]] name = "mex-common" -version = "0.45.0" +version = "0.46.0" requires_python = ">=3.11,<3.13" git = "https://github.com/robert-koch-institut/mex-common.git" -ref = "0.45.0" -revision = "f5ff330763011e1380d1321bf20bd7b346e1b484" +ref = "0.46.0" +revision = "ca1f62afdf09587d68fbb86c89bdbb2a1176377c" summary = "Common library for MEx python projects." groups = ["default"] marker = "python_version == \"3.11\"" @@ -873,14 +873,14 @@ files = [ [[package]] name = "pygments" -version = "2.19.0" +version = "2.19.1" requires_python = ">=3.8" summary = "Pygments is a syntax highlighting package written in Python." groups = ["dev"] marker = "python_version == \"3.11\"" files = [ - {file = "pygments-2.19.0-py3-none-any.whl", hash = "sha256:4755e6e64d22161d5b61432c0600c923c5927214e7c956e31c23923c89251a9b"}, - {file = "pygments-2.19.0.tar.gz", hash = "sha256:afc4146269910d4bdfabcd27c24923137a74d562a23a320a41a55ad303e19783"}, + {file = "pygments-2.19.1-py3-none-any.whl", hash = "sha256:9ea1544ad55cecf4b8242fab6dd35a93bbce657034b0611ee383099054ab6d8c"}, + {file = "pygments-2.19.1.tar.gz", hash = "sha256:61c16d2a8576dc0649d9f39e089b5f02bcd27fba10d8fb4dcc28173f7a45151f"}, ] [[package]] diff --git a/pyproject.toml b/pyproject.toml index b81ed019..f451cff0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -13,7 +13,7 @@ dependencies = [ "fastapi>=0.115,<1", "httpx>=0.27,<1", "jinja2>=3,<4", - "mex-common @ git+https://github.com/robert-koch-institut/mex-common.git@0.45.0", + "mex-common @ git+https://github.com/robert-koch-institut/mex-common.git@0.46.0", "neo4j>=5,<6", "pydantic>=2,<3", "starlette>=0.41,<1", diff --git a/tests/conftest.py b/tests/conftest.py index a8e6cad3..5a463047 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -11,6 +11,7 @@ from pytest import MonkeyPatch from mex.backend.graph.connector import GraphConnector +from mex.backend.identity.provider import GraphIdentityProvider from mex.backend.main import app from mex.backend.rules.helpers import create_and_get_rule_set from mex.backend.settings import BackendSettings @@ -22,6 +23,7 @@ AnyExtractedModel, ExtractedActivity, ExtractedContactPoint, + ExtractedOrganization, ExtractedOrganizationalUnit, ExtractedPrimarySource, OrganizationalUnitRuleSetRequest, @@ -182,7 +184,7 @@ def generate(cls: type[Identifier], seed: int | None = None) -> Identifier: @pytest.fixture(autouse=True) def set_identity_provider(is_integration_test: bool, monkeypatch: MonkeyPatch) -> None: """Ensure the identifier provider is set correctly for unit and int tests.""" - # yuck, all this needs cleaning up after MX-1596 + # TODO(ND): yuck, all this needs cleaning up after MX-1596 for settings in (BaseSettings.get(), BackendSettings.get()): if is_integration_test: monkeypatch.setitem(settings.model_config, "validate_assignment", False) @@ -234,7 +236,9 @@ def get_graph() -> list[dict[str, Any]]: @pytest.fixture -def dummy_data() -> dict[str, AnyExtractedModel]: +def dummy_data( + set_identity_provider: None, # noqa: ARG001 +) -> dict[str, AnyExtractedModel]: """Create a set of interlinked dummy data.""" primary_source_1 = ExtractedPrimarySource( hadPrimarySource=MEX_PRIMARY_SOURCE_STABLE_TARGET_ID, @@ -255,16 +259,34 @@ def dummy_data() -> dict[str, AnyExtractedModel]: hadPrimarySource=primary_source_1.stableTargetId, identifierInPrimarySource="cp-2", ) + organization_1 = ExtractedOrganization( + hadPrimarySource=primary_source_1.stableTargetId, + identifierInPrimarySource="rki", + officialName=[ + Text(value="RKI", language=TextLanguage.DE), + Text(value="Robert Koch Institut ist the best", language=TextLanguage.DE), + ], + ) + organization_2 = ExtractedOrganization( + hadPrimarySource=primary_source_2.stableTargetId, + identifierInPrimarySource="robert-koch-institute", + officialName=[ + Text(value="RKI", language=TextLanguage.DE), + Text(value="Robert Koch Institute", language=TextLanguage.EN), + ], + ) organizational_unit_1 = ExtractedOrganizationalUnit( hadPrimarySource=primary_source_2.stableTargetId, identifierInPrimarySource="ou-1", name=[Text(value="Unit 1", language=TextLanguage.EN)], + unitOf=[organization_1.stableTargetId], ) organizational_unit_2 = ExtractedOrganizationalUnit( hadPrimarySource=primary_source_2.stableTargetId, identifierInPrimarySource="ou-1.6", name=[Text(value="Unit 1.6", language=TextLanguage.EN)], parentUnit=organizational_unit_1.stableTargetId, + unitOf=[organization_1.stableTargetId], ) activity_1 = ExtractedActivity( abstract=[ @@ -289,18 +311,42 @@ def dummy_data() -> dict[str, AnyExtractedModel]: "primary_source_2": primary_source_2, "contact_point_1": contact_point_1, "contact_point_2": contact_point_2, + "organization_1": organization_1, + "organization_2": organization_2, "organizational_unit_1": organizational_unit_1, "organizational_unit_2": organizational_unit_2, "activity_1": activity_1, } +def _match_organization_items(dummy_data: dict[str, AnyExtractedModel]) -> None: + # TODO(ND): replace this crude item matching implementation (stopgap MX-1530) + connector = GraphConnector.get() + # remove the merged item for org2 + connector.commit( + f"""\ +MATCH(n) WHERE n.identifier='{dummy_data['organization_2'].stableTargetId}' +DETACH DELETE n;""" + ) + # connect the extracted item for org2 with the merged item for org1 + connector.commit( + f"""\ +MATCH(n :ExtractedOrganization) WHERE n.identifier = '{dummy_data['organization_2'].identifier}' +MATCH(m :MergedOrganization) WHERE m.identifier = '{dummy_data['organization_1'].stableTargetId}' +MERGE (n)-[:stableTargetId {{position:0}}]->(m);""" + ) + # clear the identity provider cache to refresh the `stableTargetId` property on org2 + provider = GraphIdentityProvider.get() + provider._cached_assign.cache_clear() + + @pytest.fixture def load_dummy_data( dummy_data: dict[str, AnyExtractedModel], ) -> dict[str, AnyExtractedModel]: """Ingest dummy data into the graph.""" GraphConnector.get().ingest(list(dummy_data.values())) + _match_organization_items(dummy_data) return dummy_data @@ -329,19 +375,19 @@ def organizational_unit_rule_set_request( @pytest.fixture def load_dummy_rule_set( organizational_unit_rule_set_request: OrganizationalUnitRuleSetRequest, - dummy_data: dict[str, AnyExtractedModel], + load_dummy_data: dict[str, AnyExtractedModel], ) -> OrganizationalUnitRuleSetResponse: GraphConnector.get().ingest( [ - dummy_data["primary_source_2"], - dummy_data["organizational_unit_1"], - dummy_data["organizational_unit_2"], + load_dummy_data["primary_source_2"], + load_dummy_data["organizational_unit_1"], + load_dummy_data["organizational_unit_2"], ] ) return cast( OrganizationalUnitRuleSetResponse, create_and_get_rule_set( organizational_unit_rule_set_request, - stable_target_id=dummy_data["organizational_unit_2"].stableTargetId, + stable_target_id=load_dummy_data["organizational_unit_2"].stableTargetId, ), ) diff --git a/tests/extracted/test_main.py b/tests/extracted/test_main.py index 656242c2..07a28084 100644 --- a/tests/extracted/test_main.py +++ b/tests/extracted/test_main.py @@ -86,23 +86,23 @@ def test_search_extracted_items_mocked( "version": None, } ], - "total": 8, + "total": 10, }, ), ( - "?limit=1&skip=6", + "?limit=1&skip=9", { "items": [ { "$type": "ExtractedContactPoint", "email": ["info@contact-point.one"], "hadPrimarySource": "bFQoRhcVH5DHUr", - "identifier": "bFQoRhcVH5DHUw", + "identifier": "bFQoRhcVH5DHUy", "identifierInPrimarySource": "cp-1", - "stableTargetId": "bFQoRhcVH5DHUx", + "stableTargetId": "bFQoRhcVH5DHUz", } ], - "total": 8, + "total": 10, }, ), ( @@ -111,18 +111,18 @@ def test_search_extracted_items_mocked( "items": [ { "$type": "ExtractedContactPoint", - "email": ["info@contact-point.one"], + "email": ["help@contact-point.two"], "hadPrimarySource": "bFQoRhcVH5DHUr", - "identifier": "bFQoRhcVH5DHUw", - "identifierInPrimarySource": "cp-1", - "stableTargetId": "bFQoRhcVH5DHUx", + "identifier": "bFQoRhcVH5DHUA", + "identifierInPrimarySource": "cp-2", + "stableTargetId": "bFQoRhcVH5DHUB", }, { "$type": "ExtractedContactPoint", - "email": ["help@contact-point.two"], + "email": ["info@contact-point.one"], "hadPrimarySource": "bFQoRhcVH5DHUr", "identifier": "bFQoRhcVH5DHUy", - "identifierInPrimarySource": "cp-2", + "identifierInPrimarySource": "cp-1", "stableTargetId": "bFQoRhcVH5DHUz", }, ], @@ -153,7 +153,7 @@ def test_search_extracted_items_mocked( }, ), ( - "?stableTargetId=bFQoRhcVH5DHUv", + "?stableTargetId=bFQoRhcVH5DHUx", { "items": [ { @@ -161,13 +161,13 @@ def test_search_extracted_items_mocked( "alternativeName": [], "email": [], "hadPrimarySource": "bFQoRhcVH5DHUt", - "identifier": "bFQoRhcVH5DHUu", + "identifier": "bFQoRhcVH5DHUw", "identifierInPrimarySource": "ou-1", "name": [{"language": "en", "value": "Unit 1"}], "parentUnit": None, "shortName": [], - "stableTargetId": "bFQoRhcVH5DHUv", - "unitOf": [], + "stableTargetId": "bFQoRhcVH5DHUx", + "unitOf": ["bFQoRhcVH5DHUv"], "website": [], } ], diff --git a/tests/graph/test_connector.py b/tests/graph/test_connector.py index f2c6bacc..354a40f9 100644 --- a/tests/graph/test_connector.py +++ b/tests/graph/test_connector.py @@ -1,3 +1,4 @@ +from typing import cast from unittest.mock import MagicMock, Mock, call import pytest @@ -18,6 +19,7 @@ MEX_PRIMARY_SOURCE_IDENTIFIER_IN_PRIMARY_SOURCE, MEX_PRIMARY_SOURCE_STABLE_TARGET_ID, AnyExtractedModel, + ExtractedOrganizationalUnit, OrganizationalUnitRuleSetRequest, OrganizationalUnitRuleSetResponse, ) @@ -299,7 +301,7 @@ def test_fetch_extracted_items() -> None: "stableTargetId": [MEX_EXTRACTED_PRIMARY_SOURCE.stableTargetId], } ], - "total": 8, + "total": 10, } @@ -384,7 +386,7 @@ def test_fetch_rule_items( "name": [{"value": "Unit 1.7", "language": "en"}], "website": [{"title": "Unit Homepage", "url": "https://unit-1-7"}], "parentUnit": [load_dummy_rule_set.additive.parentUnit], - "stableTargetId": ["bFQoRhcVH5DHUB"], + "stableTargetId": [load_dummy_rule_set.stableTargetId], } ], "total": 3, @@ -444,7 +446,7 @@ def test_mocked_graph_fetch_merged_items(mocked_graph: MockedGraph) -> None: graph = GraphConnector.get() result = graph.fetch_merged_items( query_string="my-query", - stable_target_id=Identifier.generate(99), + identifier=Identifier.generate(99), entity_type=["MergedFoo", "MergedBar", "MergedBatz"], skip=10, limit=100, @@ -452,7 +454,7 @@ def test_mocked_graph_fetch_merged_items(mocked_graph: MockedGraph) -> None: assert mocked_graph.call_args_list[-1].args == ( """\ -fetch_merged_items(filter_by_query_string=True, filter_by_stable_target_id=True)""", +fetch_merged_items(filter_by_query_string=True, filter_by_identifier=True)""", { "labels": [ "MergedFoo", @@ -462,7 +464,7 @@ def test_mocked_graph_fetch_merged_items(mocked_graph: MockedGraph) -> None: "limit": 100, "query_string": "my-query", "skip": 10, - "stable_target_id": "bFQoRhcVH5DHV1", + "identifier": "bFQoRhcVH5DHV1", }, ) @@ -493,47 +495,34 @@ def test_mocked_graph_fetch_merged_items(mocked_graph: MockedGraph) -> None: def test_fetch_merged_items() -> None: connector = GraphConnector.get() - result = connector.fetch_merged_items(None, None, None, 1, 1) + result = connector.fetch_merged_items( + query_string=None, + identifier=None, + entity_type=["MergedOrganizationalUnit"], + skip=1, + limit=1, + ) assert result.one() == { "items": [ { "components": [ { + "identifierInPrimarySource": "ou-1", "email": [], "entityType": "ExtractedOrganizationalUnit", + "identifier": "bFQoRhcVH5DHUw", + "stableTargetId": ["bFQoRhcVH5DHUx"], "hadPrimarySource": ["bFQoRhcVH5DHUt"], - "identifier": "bFQoRhcVH5DHUA", - "identifierInPrimarySource": "ou-1.6", - "name": [{"language": "en", "value": "Unit 1.6"}], - "parentUnit": ["bFQoRhcVH5DHUv"], - "stableTargetId": ["bFQoRhcVH5DHUB"], - }, - { - "email": [], - "entityType": "AdditiveOrganizationalUnit", - "name": [{"language": "en", "value": "Unit 1.7"}], - "parentUnit": ["bFQoRhcVH5DHUv"], - "stableTargetId": ["bFQoRhcVH5DHUB"], - "website": [ - {"title": "Unit Homepage", "url": "https://unit-1-7"} - ], - }, - { - "entityType": "PreventiveOrganizationalUnit", - "stableTargetId": ["bFQoRhcVH5DHUB"], - }, - { - "email": [], - "entityType": "SubtractiveOrganizationalUnit", - "stableTargetId": ["bFQoRhcVH5DHUB"], - }, + "unitOf": ["bFQoRhcVH5DHUv"], + "name": [{"value": "Unit 1", "language": "en"}], + } ], "entityType": "MergedOrganizationalUnit", - "identifier": "bFQoRhcVH5DHUB", + "identifier": "bFQoRhcVH5DHUx", } ], - "total": 8, + "total": 2, } @@ -541,7 +530,13 @@ def test_fetch_merged_items() -> None: def test_fetch_merged_items_empty() -> None: connector = GraphConnector.get() - result = connector.fetch_merged_items(None, "thisIdDoesNotExist", None, 0, 1) + result = connector.fetch_merged_items( + query_string=None, + identifier="thisIdDoesNotExist", + entity_type=None, + skip=0, + limit=1, + ) assert result.one() == {"items": [], "total": 0} @@ -641,14 +636,16 @@ def test_mocked_graph_exists_merged_item( @pytest.mark.parametrize( ("stable_target_id", "stem_types", "exists"), [ - ("bFQoRhcVH5DHUv", None, True), - ("bFQoRhcVH5DHUv", ["Person", "ContactPoint", "OrganizationalUnit"], True), - ("bFQoRhcVH5DHUv", ["Activity"], False), + ("bFQoRhcVH5DHUB", None, True), + ("bFQoRhcVH5DHUB", ["ContactPoint"], True), + ("bFQoRhcVH5DHUB", ["Person", "ContactPoint", "OrganizationalUnit"], True), + ("bFQoRhcVH5DHUB", ["Activity"], False), ("thisIdDoesNotExist", ["Activity"], False), ], ids=[ "found without type filter", "found with type filter", + "found with multi-type filter", "missed due to filter", "missed due to identifier", ], @@ -704,11 +701,13 @@ def test_mocked_graph_merge_edges( mocked_graph: MockedGraph, dummy_data: dict[str, AnyExtractedModel] ) -> None: mocked_graph.return_value = [ - {"edges": ["hadPrimarySource", "stableTargetId"]}, + {"edges": ["hadPrimarySource", "unitOf", "stableTargetId"]}, ] graph = GraphConnector.get() - extracted_organizational_unit = dummy_data["organizational_unit_1"] + extracted_organizational_unit = cast( + ExtractedOrganizationalUnit, dummy_data["organizational_unit_1"] + ) graph._merge_edges( extracted_organizational_unit, extracted_organizational_unit.stableTargetId, @@ -721,16 +720,17 @@ def test_mocked_graph_merge_edges( current_label="ExtractedOrganizationalUnit", current_constraints=["identifier"], merged_label="MergedOrganizationalUnit", - ref_labels=["hadPrimarySource", "stableTargetId"], + ref_labels=["hadPrimarySource", "unitOf", "stableTargetId"], )""", { "identifier": extracted_organizational_unit.identifier, "ref_identifiers": [ extracted_organizational_unit.hadPrimarySource, + extracted_organizational_unit.unitOf[0], extracted_organizational_unit.stableTargetId, ], - "ref_positions": [0, 0], - "stable_target_id": "cWWm02l1c6cucKjIhkFqY4", + "ref_positions": [0, 0, 0], + "stable_target_id": extracted_organizational_unit.stableTargetId, }, ) @@ -805,42 +805,79 @@ def test_mocked_graph_creates_rule_set( def test_mocked_graph_ingests_models( - mocked_graph: MockedGraph, dummy_data: dict[str, AnyExtractedModel] + mocked_graph: MockedGraph, + dummy_data: dict[str, AnyExtractedModel], ) -> None: + # the `$comment` keys are just for easier debugging mocked_graph.side_effect = [ - [{"current": {}}], # PrimarySource ps-1 item - [{"current": {}}], # PrimarySource ps-2 item - [{"current": {}}], # ContactPoint cp-1 item - [{"current": {}}], # ContactPoint cp-2 item - [{"current": {}}], # OrganizationalUnit ou-1 item - [{"current": {}}], # OrganizationalUnit ou-1.6 item - [{"current": {}}], # Activity a-1 item + [{"current": {}, "$comment": "mock response for PrimarySource ps-1 item"}], + [{"current": {}, "$comment": "mock response for PrimarySource ps-2 item"}], + [{"current": {}, "$comment": "mock response for ContactPoint cp-1 item"}], + [{"current": {}, "$comment": "mock response for ContactPoint cp-2 item"}], + [{"current": {}, "$comment": "mock response for Organization rki item"}], + [ + { + "current": {}, + "$comment": "mock response for Organization robert-koch-institute item", + } + ], + [{"current": {}, "$comment": "mock response for OrganizationalUnit ou-1 item"}], [ - # PrimarySource ps-1 edges - {"edges": ["hadPrimarySource", "stableTargetId"]}, + { + "current": {}, + "$comment": "mock response for OrganizationalUnit ou-1.6 item", + } ], + [{"current": {}, "$comment": "mock response for Activity a-1 item"}], [ - # PrimarySource ps-2 edges - {"edges": ["hadPrimarySource", "stableTargetId"]}, + { + "edges": ["hadPrimarySource", "stableTargetId"], + "$comment": "mock response for PrimarySource ps-1 edges", + }, ], [ - # ContactPoint cp-1 edges - {"edges": ["hadPrimarySource", "stableTargetId"]}, + { + "edges": ["hadPrimarySource", "stableTargetId"], + "$comment": "mock response for PrimarySource ps-2 edges", + }, ], [ - # ContactPoint cp-2 edges - {"edges": ["hadPrimarySource", "stableTargetId"]}, + { + "edges": ["hadPrimarySource", "stableTargetId"], + "$comment": "mock response for ContactPoint cp-1 edges", + }, ], [ - # OrganizationalUnit ou-1 edges - {"edges": ["hadPrimarySource", "stableTargetId"]} + { + "edges": ["hadPrimarySource", "stableTargetId"], + "$comment": "mock response for ContactPoint cp-2 edges", + }, ], [ - # OrganizationalUnit ou-1.6 edges - {"edges": ["hadPrimarySource", "parentUnit", "stableTargetId"]} + { + "edges": ["hadPrimarySource", "stableTargetId"], + "$comment": "mock response for Organization rki edges", + } + ], + [ + { + "edges": ["hadPrimarySource", "stableTargetId"], + "$comment": "mock response for Organization robert-koch-institute edges", + } + ], + [ + { + "edges": ["hadPrimarySource", "unitOf", "stableTargetId"], + "$comment": "mock response for OrganizationalUnit ou-1 edges", + } + ], + [ + { + "edges": ["hadPrimarySource", "parentUnit", "unitOf", "stableTargetId"], + "$comment": "mock response for OrganizationalUnit ou-1.6 edges", + } ], [ - # Activity a-1 edges { "edges": [ "hadPrimarySource", @@ -849,10 +886,12 @@ def test_mocked_graph_ingests_models( "contact", "responsibleUnit", "stableTargetId", - ] + ], + "$comment": "mock response for Activity a-1 edges", }, ], ] + graph = GraphConnector.get() identifiers = graph.ingest(list(dummy_data.values())) diff --git a/tests/graph/test_query.py b/tests/graph/test_query.py index 1dfa16d1..82098427 100644 --- a/tests/graph/test_query.py +++ b/tests/graph/test_query.py @@ -165,7 +165,7 @@ def test_fetch_database_status(query_builder: QueryBuilder) -> None: ], ids=["all-filters", "no-filters"], ) -def test_fetch_extracted_items( +def test_fetch_extracted_or_rule_items( query_builder: QueryBuilder, filter_by_query_string: bool, filter_by_stable_target_id: bool, @@ -181,7 +181,7 @@ def test_fetch_extracted_items( @pytest.mark.parametrize( ( "filter_by_query_string", - "filter_by_stable_target_id", + "filter_by_identifier", "expected", ), [ @@ -195,7 +195,7 @@ def test_fetch_extracted_items( OPTIONAL MATCH (extracted_or_rule_node:ExtractedThis|ExtractedThat|ExtractedOther|AdditiveThis|AdditiveThat|AdditiveOther)-[:stableTargetId]->(merged_node:MergedThis|MergedThat|MergedOther) WHERE elementId(hit) = elementId(extracted_or_rule_node) - AND merged_node.identifier = $stable_target_id + AND merged_node.identifier = $identifier AND ANY(label IN labels(merged_node) WHERE label IN $labels) WITH DISTINCT merged_node AS merged_node RETURN COUNT(merged_node) AS total @@ -206,7 +206,7 @@ def test_fetch_extracted_items( OPTIONAL MATCH (extracted_or_rule_node:ExtractedThis|ExtractedThat|ExtractedOther|AdditiveThis|AdditiveThat|AdditiveOther)-[:stableTargetId]->(merged_node:MergedThis|MergedThat|MergedOther) WHERE elementId(hit) = elementId(extracted_or_rule_node) - AND merged_node.identifier = $stable_target_id + AND merged_node.identifier = $identifier AND ANY(label IN labels(merged_node) WHERE label IN $labels) WITH DISTINCT merged_node AS merged_node OPTIONAL MATCH (extracted_or_rule_node)-[:stableTargetId]->(merged_node) @@ -283,12 +283,12 @@ def test_fetch_extracted_items( def test_fetch_merged_items( query_builder: QueryBuilder, filter_by_query_string: bool, - filter_by_stable_target_id: bool, + filter_by_identifier: bool, expected: str, ) -> None: query = query_builder.fetch_merged_items( filter_by_query_string=filter_by_query_string, - filter_by_stable_target_id=filter_by_stable_target_id, + filter_by_identifier=filter_by_identifier, ) assert str(query) == expected diff --git a/tests/identity/test_main.py b/tests/identity/test_main.py index 3dd393ab..74af36bc 100644 --- a/tests/identity/test_main.py +++ b/tests/identity/test_main.py @@ -103,9 +103,9 @@ def test_assign_identity_inconsistency_mocked( }, { "hadPrimarySource": "bFQoRhcVH5DHUr", - "identifier": "bFQoRhcVH5DHUE", + "identifier": "bFQoRhcVH5DHUI", "identifierInPrimarySource": "new-item", - "stableTargetId": "bFQoRhcVH5DHUF", + "stableTargetId": "bFQoRhcVH5DHUJ", }, ), ( @@ -115,9 +115,9 @@ def test_assign_identity_inconsistency_mocked( }, { "hadPrimarySource": "bFQoRhcVH5DHUr", - "identifier": "bFQoRhcVH5DHUy", + "identifier": "bFQoRhcVH5DHUA", "identifierInPrimarySource": "cp-2", - "stableTargetId": "bFQoRhcVH5DHUz", + "stableTargetId": "bFQoRhcVH5DHUB", }, ), ( @@ -242,24 +242,45 @@ def test_fetch_identities_mocked( }, ), ( - "?stableTargetId=bFQoRhcVH5DHUv", + "?stableTargetId=bFQoRhcVH5DHUx", { "items": [ { - "identifier": "bFQoRhcVH5DHUu", + "identifier": "bFQoRhcVH5DHUw", "hadPrimarySource": "bFQoRhcVH5DHUt", "identifierInPrimarySource": "ou-1", - "stableTargetId": "bFQoRhcVH5DHUv", + "stableTargetId": "bFQoRhcVH5DHUx", } ], "total": 1, }, ), + ( + "?stableTargetId=bFQoRhcVH5DHUv", + { + "items": [ + { + "identifier": "bFQoRhcVH5DHUC", + "hadPrimarySource": "bFQoRhcVH5DHUt", + "identifierInPrimarySource": "robert-koch-institute", + "stableTargetId": "bFQoRhcVH5DHUv", + }, + { + "identifier": "bFQoRhcVH5DHUu", + "hadPrimarySource": "bFQoRhcVH5DHUr", + "identifierInPrimarySource": "rki", + "stableTargetId": "bFQoRhcVH5DHUv", + }, + ], + "total": 2, + }, + ), ], ids=[ "nothing found", "by hadPrimarySource and identifierInPrimarySource", - "by stableTargetId", + "by stableTargetId find single unit", + "by stableTargetId find matched orgs", ], ) @pytest.mark.usefixtures("load_dummy_data") diff --git a/tests/identity/test_provider.py b/tests/identity/test_provider.py index b173d9b2..3cce8ab7 100644 --- a/tests/identity/test_provider.py +++ b/tests/identity/test_provider.py @@ -101,19 +101,19 @@ def test_assign_identity_inconsistency_mocked( "new-item", { "hadPrimarySource": "bFQoRhcVH5DHUr", - "identifier": "bFQoRhcVH5DHUE", + "identifier": "bFQoRhcVH5DHUI", "identifierInPrimarySource": "new-item", - "stableTargetId": "bFQoRhcVH5DHUF", + "stableTargetId": "bFQoRhcVH5DHUJ", }, ), ( "bFQoRhcVH5DHUr", "cp-2", { - "identifier": "bFQoRhcVH5DHUy", + "identifier": "bFQoRhcVH5DHUA", "hadPrimarySource": "bFQoRhcVH5DHUr", "identifierInPrimarySource": "cp-2", - "stableTargetId": "bFQoRhcVH5DHUz", + "stableTargetId": "bFQoRhcVH5DHUB", }, ), ( @@ -254,13 +254,13 @@ def test_fetch_identities_mocked( # noqa: PLR0913 ( None, None, - MergedOrganizationalUnitIdentifier("bFQoRhcVH5DHUv"), + MergedOrganizationalUnitIdentifier("bFQoRhcVH5DHUx"), [ { - "identifier": "bFQoRhcVH5DHUu", + "identifier": "bFQoRhcVH5DHUw", "hadPrimarySource": "bFQoRhcVH5DHUt", "identifierInPrimarySource": "ou-1", - "stableTargetId": "bFQoRhcVH5DHUv", + "stableTargetId": "bFQoRhcVH5DHUx", } ], ), diff --git a/tests/merged/test_helpers.py b/tests/merged/test_helpers.py index 5e29249b..743a3246 100644 --- a/tests/merged/test_helpers.py +++ b/tests/merged/test_helpers.py @@ -329,16 +329,19 @@ def test_create_merged_item( @pytest.mark.usefixtures("load_dummy_data", "load_dummy_rule_set") @pytest.mark.integration def test_search_merged_items_in_graph() -> None: - merged_result = search_merged_items_in_graph(stable_target_id="bFQoRhcVH5DHUB") + merged_result = search_merged_items_in_graph( + identifier="bFQoRhcVH5DHUF", + ) assert merged_result.model_dump(exclude_defaults=True) == { "items": [ { - "identifier": "bFQoRhcVH5DHUB", + "identifier": "bFQoRhcVH5DHUF", "name": [ {"language": "en", "value": "Unit 1.6"}, {"language": "en", "value": "Unit 1.7"}, ], - "parentUnit": "bFQoRhcVH5DHUv", + "parentUnit": "bFQoRhcVH5DHUx", + "unitOf": ["bFQoRhcVH5DHUv"], "website": [{"title": "Unit Homepage", "url": "https://unit-1-7"}], }, ], @@ -536,7 +539,7 @@ def test_search_merged_items_in_graph_mocked( mocked_graph.return_value = mocked_graph_result try: - merged_result = search_merged_items_in_graph(stable_target_id="bFQoRhcVH5DHUB") + merged_result = search_merged_items_in_graph(identifier="bFQoRhcVH5DHUB") except Exception as error: if str(expected) not in str(error): raise AssertionError(expected) from error diff --git a/tests/merged/test_main.py b/tests/merged/test_main.py index 3342dc9c..b00c0841 100644 --- a/tests/merged/test_main.py +++ b/tests/merged/test_main.py @@ -109,20 +109,20 @@ def test_search_merged_items_mocked( "version": None, } ], - "total": 8, + "total": 9, }, ), ( - "?limit=1&skip=6", + "?limit=1&skip=8", { "items": [ { - "$type": "MergedContactPoint", "email": ["info@contact-point.one"], - "identifier": "bFQoRhcVH5DHUx", + "$type": "MergedContactPoint", + "identifier": "bFQoRhcVH5DHUz", } ], - "total": 8, + "total": 9, }, ), ( @@ -131,12 +131,12 @@ def test_search_merged_items_mocked( "items": [ { "$type": "MergedContactPoint", - "email": ["info@contact-point.one"], - "identifier": "bFQoRhcVH5DHUx", + "email": ["help@contact-point.two"], + "identifier": "bFQoRhcVH5DHUB", }, { "$type": "MergedContactPoint", - "email": ["help@contact-point.two"], + "email": ["info@contact-point.one"], "identifier": "bFQoRhcVH5DHUz", }, ], @@ -164,40 +164,40 @@ def test_search_merged_items_mocked( }, ), ( - "?identifier=bFQoRhcVH5DHUv", + "?identifier=bFQoRhcVH5DHUx", { "items": [ { "$type": "MergedOrganizationalUnit", "alternativeName": [], "email": [], - "identifier": "bFQoRhcVH5DHUv", + "identifier": "bFQoRhcVH5DHUx", "name": [{"language": "en", "value": "Unit 1"}], "parentUnit": None, "shortName": [], - "unitOf": [], + "unitOf": ["bFQoRhcVH5DHUv"], "website": [], - } + }, ], "total": 1, }, ), ( - "?identifier=bFQoRhcVH5DHUB", + "?identifier=bFQoRhcVH5DHUF", { "items": [ { "$type": "MergedOrganizationalUnit", "alternativeName": [], "email": [], - "identifier": "bFQoRhcVH5DHUB", + "identifier": "bFQoRhcVH5DHUF", "name": [ {"language": "en", "value": "Unit 1.6"}, {"language": "en", "value": "Unit 1.7"}, ], - "parentUnit": "bFQoRhcVH5DHUv", + "parentUnit": "bFQoRhcVH5DHUx", "shortName": [], - "unitOf": [], + "unitOf": ["bFQoRhcVH5DHUv"], "website": [ { "language": None, diff --git a/tests/preview/test_main.py b/tests/preview/test_main.py index 81d19b72..b336d417 100644 --- a/tests/preview/test_main.py +++ b/tests/preview/test_main.py @@ -9,20 +9,18 @@ ("stable_target_id", "json_body", "expected"), [ ( - "bFQoRhcVH5DHUD", + "bFQoRhcVH5DHUH", { "additive": { "$type": "AdditiveActivity", "end": ["2025"], "title": [{"value": "A new beginning", "language": "en"}], }, - "preventive": {"$type": "PreventiveActivity"}, - "subtractive": {"$type": "SubtractiveActivity"}, }, { "$type": "MergedActivity", - "contact": ["bFQoRhcVH5DHUx", "bFQoRhcVH5DHUz", "bFQoRhcVH5DHUv"], - "responsibleUnit": ["bFQoRhcVH5DHUv"], + "contact": ["bFQoRhcVH5DHUz", "bFQoRhcVH5DHUB", "bFQoRhcVH5DHUx"], + "responsibleUnit": ["bFQoRhcVH5DHUx"], "title": [ {"value": "Aktivität 1", "language": "de"}, {"value": "A new beginning", "language": "en"}, @@ -41,34 +39,27 @@ "url": "https://activity-1", } ], - "identifier": "bFQoRhcVH5DHUD", + "identifier": "bFQoRhcVH5DHUH", }, ), ( - "bFQoRhcVH5DHUD", + "bFQoRhcVH5DHUH", { - "additive": {"$type": "AdditiveActivity"}, - "preventive": {"$type": "PreventiveActivity"}, "subtractive": { "$type": "SubtractiveActivity", "start": ["2014"], - "contact": ["bFQoRhcVH5DHUv"], + "contact": ["bFQoRhcVH5DHUx"], "abstract": [ {"value": "Une activité active.", "language": None}, ], }, }, { - "$type": "MergedActivity", - "contact": ["bFQoRhcVH5DHUx", "bFQoRhcVH5DHUz"], - "responsibleUnit": ["bFQoRhcVH5DHUv"], + "contact": ["bFQoRhcVH5DHUz", "bFQoRhcVH5DHUB"], + "responsibleUnit": ["bFQoRhcVH5DHUx"], + "title": [{"value": "Aktivität 1", "language": "de"}], + "abstract": [{"value": "An active activity.", "language": "en"}], "start": ["2014-08-24"], - "title": [ - {"value": "Aktivität 1", "language": "de"}, - ], - "abstract": [ - {"value": "An active activity.", "language": "en"}, - ], "theme": ["https://mex.rki.de/item/theme-11"], "website": [ { @@ -77,36 +68,28 @@ "url": "https://activity-1", } ], - "identifier": "bFQoRhcVH5DHUD", + "$type": "MergedActivity", + "identifier": "bFQoRhcVH5DHUH", }, ), ( - "bFQoRhcVH5DHUD", + "bFQoRhcVH5DHUH", { - "additive": { - "$type": "AdditiveActivity", - }, "preventive": { "$type": "PreventiveActivity", "theme": ["bFQoRhcVH5DHUr"], "title": ["bFQoRhcVH5DHUt"], }, - "subtractive": { - "$type": "SubtractiveActivity", - }, }, { - "$type": "MergedActivity", - "contact": ["bFQoRhcVH5DHUx", "bFQoRhcVH5DHUz", "bFQoRhcVH5DHUv"], - "responsibleUnit": ["bFQoRhcVH5DHUv"], - "start": ["2014-08-24"], - "title": [ - {"value": "Aktivität 1", "language": "de"}, - ], + "contact": ["bFQoRhcVH5DHUz", "bFQoRhcVH5DHUB", "bFQoRhcVH5DHUx"], + "responsibleUnit": ["bFQoRhcVH5DHUx"], + "title": [{"value": "Aktivität 1", "language": "de"}], "abstract": [ {"value": "An active activity.", "language": "en"}, {"value": "Une activité active.", "language": None}, ], + "start": ["2014-08-24"], "website": [ { "language": None, @@ -114,7 +97,8 @@ "url": "https://activity-1", } ], - "identifier": "bFQoRhcVH5DHUD", + "$type": "MergedActivity", + "identifier": "bFQoRhcVH5DHUH", }, ), ( diff --git a/tests/rules/test_main.py b/tests/rules/test_main.py index 6ab6b1f0..e8119abc 100644 --- a/tests/rules/test_main.py +++ b/tests/rules/test_main.py @@ -198,7 +198,7 @@ def test_get_rule_set( assert response.status_code == status.HTTP_200_OK, response.text assert response.json() == { "additive": { - "parentUnit": "bFQoRhcVH5DHUv", + "parentUnit": "bFQoRhcVH5DHUx", "name": [{"value": "Unit 1.7", "language": "en"}], "alternativeName": [], "email": [], @@ -230,7 +230,7 @@ def test_get_rule_set( "website": [], }, "$type": "OrganizationalUnitRuleSetResponse", - "stableTargetId": "bFQoRhcVH5DHUB", + "stableTargetId": load_dummy_rule_set.stableTargetId, } @@ -303,20 +303,42 @@ def test_update_rule_set( "website": [], }, "$type": "OrganizationalUnitRuleSetResponse", - "stableTargetId": "bFQoRhcVH5DHUB", + "stableTargetId": load_dummy_rule_set.stableTargetId, } assert get_graph() == [ + { + "fundingProgram": [], + "identifierInPrimarySource": "a-1", + "start": ["2014-08-24"], + "theme": ["https://mex.rki.de/item/theme-11"], + "label": "ExtractedActivity", + "activityType": [], + "identifier": "bFQoRhcVH5DHUG", + "end": [], + }, + { + "identifierInPrimarySource": "cp-2", + "email": ["help@contact-point.two"], + "label": "ExtractedContactPoint", + "identifier": "bFQoRhcVH5DHUA", + }, + { + "identifierInPrimarySource": "cp-1", + "email": ["info@contact-point.one"], + "label": "ExtractedContactPoint", + "identifier": "bFQoRhcVH5DHUy", + }, { "identifierInPrimarySource": "ou-1.6", "email": [], "label": "ExtractedOrganizationalUnit", - "identifier": "bFQoRhcVH5DHUA", + "identifier": "bFQoRhcVH5DHUE", }, { "identifierInPrimarySource": "ou-1", "email": [], "label": "ExtractedOrganizationalUnit", - "identifier": "bFQoRhcVH5DHUu", + "identifier": "bFQoRhcVH5DHUw", }, {"email": [], "label": "AdditiveOrganizationalUnit"}, {"email": [], "label": "SubtractiveOrganizationalUnit"}, @@ -326,6 +348,12 @@ def test_update_rule_set( "label": "hadPrimarySource", "end": "00000000000000", }, + { + "position": 0, + "start": "bFQoRhcVH5DHUq", + "label": "hadPrimarySource", + "end": "00000000000000", + }, { "position": 0, "start": "bFQoRhcVH5DHUs", @@ -338,48 +366,130 @@ def test_update_rule_set( "label": "stableTargetId", "end": "00000000000000", }, + {"position": 0, "start": "bFQoRhcVH5DHUG", "label": "website", "end": "Link"}, + {"position": 0, "start": "bFQoRhcVH5DHUG", "label": "abstract", "end": "Text"}, + {"position": 1, "start": "bFQoRhcVH5DHUG", "label": "abstract", "end": "Text"}, { "position": 0, "start": "AdditiveOrganizationalUnit", "label": "name", "end": "Text", }, - {"position": 0, "start": "bFQoRhcVH5DHUA", "label": "name", "end": "Text"}, - {"position": 0, "start": "bFQoRhcVH5DHUu", "label": "name", "end": "Text"}, + {"position": 0, "start": "bFQoRhcVH5DHUE", "label": "name", "end": "Text"}, + {"position": 0, "start": "bFQoRhcVH5DHUw", "label": "name", "end": "Text"}, { "position": 0, - "start": "AdditiveOrganizationalUnit", + "start": "bFQoRhcVH5DHUC", + "label": "officialName", + "end": "Text", + }, + { + "position": 0, + "start": "bFQoRhcVH5DHUu", + "label": "officialName", + "end": "Text", + }, + { + "position": 1, + "start": "bFQoRhcVH5DHUC", + "label": "officialName", + "end": "Text", + }, + { + "position": 1, + "start": "bFQoRhcVH5DHUu", + "label": "officialName", + "end": "Text", + }, + {"position": 0, "start": "bFQoRhcVH5DHUG", "label": "title", "end": "Text"}, + { + "position": 1, + "start": "bFQoRhcVH5DHUG", + "label": "contact", + "end": "bFQoRhcVH5DHUB", + }, + { + "position": 0, + "start": "bFQoRhcVH5DHUA", "label": "stableTargetId", "end": "bFQoRhcVH5DHUB", }, + { + "position": 0, + "start": "AdditiveOrganizationalUnit", + "label": "stableTargetId", + "end": "bFQoRhcVH5DHUF", + }, { "position": 0, "start": "PreventiveOrganizationalUnit", "label": "stableTargetId", - "end": "bFQoRhcVH5DHUB", + "end": "bFQoRhcVH5DHUF", }, { "position": 0, "start": "SubtractiveOrganizationalUnit", "label": "stableTargetId", - "end": "bFQoRhcVH5DHUB", + "end": "bFQoRhcVH5DHUF", }, { "position": 0, - "start": "bFQoRhcVH5DHUA", + "start": "bFQoRhcVH5DHUE", "label": "stableTargetId", - "end": "bFQoRhcVH5DHUB", + "end": "bFQoRhcVH5DHUF", + }, + { + "position": 0, + "start": "bFQoRhcVH5DHUG", + "label": "stableTargetId", + "end": "bFQoRhcVH5DHUH", }, { "position": 0, "start": "bFQoRhcVH5DHUA", "label": "hadPrimarySource", - "end": "bFQoRhcVH5DHUt", + "end": "bFQoRhcVH5DHUr", + }, + { + "position": 0, + "start": "bFQoRhcVH5DHUG", + "label": "hadPrimarySource", + "end": "bFQoRhcVH5DHUr", }, { "position": 0, "start": "bFQoRhcVH5DHUu", "label": "hadPrimarySource", + "end": "bFQoRhcVH5DHUr", + }, + { + "position": 0, + "start": "bFQoRhcVH5DHUy", + "label": "hadPrimarySource", + "end": "bFQoRhcVH5DHUr", + }, + { + "position": 0, + "start": "bFQoRhcVH5DHUq", + "label": "stableTargetId", + "end": "bFQoRhcVH5DHUr", + }, + { + "position": 0, + "start": "bFQoRhcVH5DHUC", + "label": "hadPrimarySource", + "end": "bFQoRhcVH5DHUt", + }, + { + "position": 0, + "start": "bFQoRhcVH5DHUE", + "label": "hadPrimarySource", + "end": "bFQoRhcVH5DHUt", + }, + { + "position": 0, + "start": "bFQoRhcVH5DHUw", + "label": "hadPrimarySource", "end": "bFQoRhcVH5DHUt", }, { @@ -390,8 +500,8 @@ def test_update_rule_set( }, { "position": 0, - "start": "bFQoRhcVH5DHUA", - "label": "parentUnit", + "start": "bFQoRhcVH5DHUC", + "label": "stableTargetId", "end": "bFQoRhcVH5DHUv", }, { @@ -400,13 +510,91 @@ def test_update_rule_set( "label": "stableTargetId", "end": "bFQoRhcVH5DHUv", }, + { + "position": 0, + "start": "bFQoRhcVH5DHUE", + "label": "unitOf", + "end": "bFQoRhcVH5DHUv", + }, + { + "position": 0, + "start": "bFQoRhcVH5DHUw", + "label": "unitOf", + "end": "bFQoRhcVH5DHUv", + }, + { + "position": 2, + "start": "bFQoRhcVH5DHUG", + "label": "contact", + "end": "bFQoRhcVH5DHUx", + }, + { + "position": 0, + "start": "bFQoRhcVH5DHUE", + "label": "parentUnit", + "end": "bFQoRhcVH5DHUx", + }, + { + "position": 0, + "start": "bFQoRhcVH5DHUG", + "label": "responsibleUnit", + "end": "bFQoRhcVH5DHUx", + }, + { + "position": 0, + "start": "bFQoRhcVH5DHUw", + "label": "stableTargetId", + "end": "bFQoRhcVH5DHUx", + }, + { + "position": 0, + "start": "bFQoRhcVH5DHUG", + "label": "contact", + "end": "bFQoRhcVH5DHUz", + }, + { + "position": 0, + "start": "bFQoRhcVH5DHUy", + "label": "stableTargetId", + "end": "bFQoRhcVH5DHUz", + }, + { + "rorId": [], + "identifierInPrimarySource": "robert-koch-institute", + "gndId": [], + "wikidataId": [], + "geprisId": [], + "viafId": [], + "isniId": [], + "label": "ExtractedOrganization", + "identifier": "bFQoRhcVH5DHUC", + }, + { + "rorId": [], + "identifierInPrimarySource": "rki", + "gndId": [], + "wikidataId": [], + "geprisId": [], + "viafId": [], + "isniId": [], + "label": "ExtractedOrganization", + "identifier": "bFQoRhcVH5DHUu", + }, {"label": "MergedPrimarySource", "identifier": "00000000000000"}, { "identifierInPrimarySource": "mex", "label": "ExtractedPrimarySource", "identifier": "00000000000001", }, - {"label": "MergedOrganizationalUnit", "identifier": "bFQoRhcVH5DHUB"}, + {"label": "MergedContactPoint", "identifier": "bFQoRhcVH5DHUB"}, + {"label": "MergedOrganizationalUnit", "identifier": "bFQoRhcVH5DHUF"}, + {"label": "MergedActivity", "identifier": "bFQoRhcVH5DHUH"}, + { + "identifierInPrimarySource": "ps-1", + "label": "ExtractedPrimarySource", + "identifier": "bFQoRhcVH5DHUq", + }, + {"label": "MergedPrimarySource", "identifier": "bFQoRhcVH5DHUr"}, { "identifierInPrimarySource": "ps-2", "label": "ExtractedPrimarySource", @@ -414,9 +602,23 @@ def test_update_rule_set( "version": "Cool Version v2.13", }, {"label": "MergedPrimarySource", "identifier": "bFQoRhcVH5DHUt"}, - {"label": "MergedOrganizationalUnit", "identifier": "bFQoRhcVH5DHUv"}, + {"label": "MergedOrganization", "identifier": "bFQoRhcVH5DHUv"}, + {"label": "MergedOrganizationalUnit", "identifier": "bFQoRhcVH5DHUx"}, + {"label": "MergedContactPoint", "identifier": "bFQoRhcVH5DHUz"}, + {"title": "Activity Homepage", "label": "Link", "url": "https://activity-1"}, {"label": "PreventiveOrganizationalUnit"}, + {"value": "Aktivität 1", "label": "Text", "language": "de"}, + {"value": "RKI", "label": "Text", "language": "de"}, + {"value": "RKI", "label": "Text", "language": "de"}, + { + "value": "Robert Koch Institut ist the best", + "label": "Text", + "language": "de", + }, {"value": "A new unit name", "label": "Text", "language": "en"}, + {"value": "An active activity.", "label": "Text", "language": "en"}, + {"value": "Robert Koch Institute", "label": "Text", "language": "en"}, {"value": "Unit 1", "label": "Text", "language": "en"}, {"value": "Unit 1.6", "label": "Text", "language": "en"}, + {"value": "Une activité active.", "label": "Text"}, ] diff --git a/tests/test_roundtrip.py b/tests/test_roundtrip.py index b9941ab0..34af4eb1 100644 --- a/tests/test_roundtrip.py +++ b/tests/test_roundtrip.py @@ -1,8 +1,6 @@ -from typing import Annotated - import pytest -from pydantic import Field, TypeAdapter +from mex.backend.extracted.models import ExtractedItemSearch from mex.backend.graph.connector import MEX_EXTRACTED_PRIMARY_SOURCE, GraphConnector from mex.common.models import AnyExtractedModel @@ -19,13 +17,9 @@ def test_graph_ingest_and_query_roundtrip( connector = GraphConnector.get() result = connector.fetch_extracted_items(None, None, None, 0, len(seeded_models)) - extracted_model_adapter = TypeAdapter( - list[Annotated[AnyExtractedModel, Field(discriminator="entityType")]] - ) - - expected = extracted_model_adapter.validate_python( - [e.model_dump() for e in seeded_models] + expected = ExtractedItemSearch( + items=[e.model_dump() for e in seeded_models], total=len(seeded_models) ) - fetched = extracted_model_adapter.validate_python(result["items"]) + fetched = ExtractedItemSearch(items=result["items"], total=result["total"]) assert fetched == expected