diff --git a/dataconnect/models.py b/dataconnect/models.py index af696a5..57f67b0 100644 --- a/dataconnect/models.py +++ b/dataconnect/models.py @@ -14,6 +14,7 @@ class StudyEnvironment: uuid: UUID name: str + oid: str | None = None @dataclass(frozen=True) diff --git a/dataconnect/service/mappers.py b/dataconnect/service/mappers.py index 66bae58..e1c705e 100644 --- a/dataconnect/service/mappers.py +++ b/dataconnect/service/mappers.py @@ -53,7 +53,10 @@ def resource_to_study(resource: ResourceInfo) -> Study: return Study( uuid=UUID(data["uuid"]), name=data["name"], - environments=[StudyEnvironment(uuid=UUID(e["uuid"]), name=e["name"]) for e in data.get("environments", [])], + environments=[ + StudyEnvironment(uuid=UUID(e["uuid"]), name=e["name"], oid=e.get("oid")) + for e in data.get("environments", []) + ], ) diff --git a/readme/README-v1.1.0.md b/readme/README-v1.1.0.md index 69c18d2..fd70545 100644 --- a/readme/README-v1.1.0.md +++ b/readme/README-v1.1.0.md @@ -127,7 +127,7 @@ Retrieves a list of studies where the user has permission to manage custom code | search_study_name | str or None | Optional. The approximate name of the study | #### Output -Returns a list containing `total_records` (total studies available) and a `studies` array. Each study includes `name`, `uuid`, and an environments array. Each environment includes `name` and `uuid`. +Returns a list containing `total_records` (total studies available) and a `studies` array. Each study includes `name`, `uuid`, and an environments array. Each environment includes `name`, `uuid`, and `oid` — the upstream study environment OID. --- diff --git a/tests/test_resource_to_study.py b/tests/test_resource_to_study.py new file mode 100644 index 0000000..9eead2a --- /dev/null +++ b/tests/test_resource_to_study.py @@ -0,0 +1,67 @@ +from __future__ import annotations + +import json +from uuid import UUID + +from dataconnect.service.mappers import resource_to_study +from dataconnect.transport.models import DataRef, ResourceInfo + + +def _resource(payload: dict) -> ResourceInfo: + return ResourceInfo( + descriptor=b"", + endpoints=[DataRef(ticket=json.dumps(payload).encode("utf-8"))], + total_records=1, + schema_bytes=b"", + ) + + +def test_resource_to_study_exposes_environment_oid() -> None: + resource = _resource( + { + "uuid": "12345678-1234-1234-1234-123456789abc", + "name": "Study A", + "environments": [{"uuid": "11111111-1111-1111-1111-111111111111", "name": "Production", "oid": "prod"}], + } + ) + + study = resource_to_study(resource) + + assert study.environments[0].oid == "prod" + assert study.environments[0].name == "Production" + assert study.environments[0].uuid == UUID("11111111-1111-1111-1111-111111111111") + + +def test_resource_to_study_oid_differs_from_name_multiple_environments() -> None: + resource = _resource( + { + "uuid": "12345678-1234-1234-1234-123456789abc", + "name": "Study A", + "environments": [ + {"uuid": "11111111-1111-1111-1111-111111111111", "name": "Production", "oid": "prod"}, + {"uuid": "22222222-2222-2222-2222-222222222222", "name": "Custom Env", "oid": "other"}, + ], + } + ) + + study = resource_to_study(resource) + + # OID must track its own environment, not be derived from name/uuid. + assert study.environments[0].oid == "prod" + assert study.environments[1].oid == "other" + assert study.environments[1].name == "Custom Env" + + +def test_resource_to_study_missing_oid_defaults_to_none() -> None: + """Older/partial server payloads without 'oid' must not break parsing.""" + resource = _resource( + { + "uuid": "12345678-1234-1234-1234-123456789abc", + "name": "Study A", + "environments": [{"uuid": "11111111-1111-1111-1111-111111111111", "name": "Production"}], + } + ) + + study = resource_to_study(resource) + + assert study.environments[0].oid is None