From 6844ebd3339e36f5d56d3174c6e8b3e3154f0da4 Mon Sep 17 00:00:00 2001 From: Thothore Date: Fri, 14 Aug 2026 15:57:52 +0200 Subject: [PATCH] add instance, series and study to patients --- orthanc/python/orthanc_graphql.py | 112 +++++++++++++++++++++++++++++- 1 file changed, 110 insertions(+), 2 deletions(-) diff --git a/orthanc/python/orthanc_graphql.py b/orthanc/python/orthanc_graphql.py index 019e815..cd6a7bf 100644 --- a/orthanc/python/orthanc_graphql.py +++ b/orthanc/python/orthanc_graphql.py @@ -4,18 +4,46 @@ """ import json -from ariadne import QueryType, graphql_sync, make_executable_schema +from ariadne import ObjectType, QueryType, graphql_sync, make_executable_schema import orthanc # 1. Define a GraphQL schema mirroring DICOM tags TYPE_DEFS = """ + type Instance { + id: ID! + sopInstanceUID: String! + instanceNumber: String + } + + type Series { + id: ID! + seriesInstanceUID: String! + modality: String! + seriesDescription: String + seriesNumber: String + manufacturer: String + instances(limit: Int = 100): [Instance!]! + } + + type Study { + id: ID! + studyInstanceUID: String! + studyDate: String + studyTime: String + accessionNumber: String + referringPhysicianName: String + studyDescription: String + series(limit: Int = 100): [Series!]! + } + type Patient { id: ID! patientId: String! patientName: String! patientBirthDate: String patientSex: String + studies(limit: Int = 100): [Study!]! } type Query { @@ -24,6 +52,9 @@ """ query = QueryType() +patient_type = ObjectType("Patient") +study_type = ObjectType("Study") +series_type = ObjectType("Series") @query.field("patients") @@ -50,7 +81,84 @@ def resolve_patients(_, _info, limit=100, since=0): return results -schema = make_executable_schema(TYPE_DEFS, query) +@patient_type.field("studies") +def resolve_patient_studies(patient_obj, _info, limit=100): + """Resolver bringing nested Studies for a given Patient.""" + # We must fetch the given patient ID's studies + patient_id = patient_obj['id'] + # If the user queries > 100 limit, make sure to respect it, but limit is standard at 100 + response = orthanc.RestApiGet(f'/patients/{patient_id}') + patient_details = json.loads(response) + + study_ids = patient_details.get("Studies", [])[:limit] + + results = [] + for study_id in study_ids: + # expand the study details using RestApiGet + s_resp = orthanc.RestApiGet(f'/studies/{study_id}') + s = json.loads(s_resp) + tags = s.get('MainDicomTags', {}) + results.append({ + 'id': s.get('ID', ''), + 'studyInstanceUID': tags.get('StudyInstanceUID', ''), + 'studyDate': tags.get('StudyDate'), + 'studyTime': tags.get('StudyTime'), + 'accessionNumber': tags.get('AccessionNumber'), + 'referringPhysicianName': tags.get('ReferringPhysicianName'), + 'studyDescription': tags.get('StudyDescription') + }) + return results + + +@study_type.field("series") +def resolve_study_series(study_obj, _info, limit=100): + """Resolver bringing nested Series for a given Study.""" + study_id = study_obj['id'] + response = orthanc.RestApiGet(f'/studies/{study_id}') + study_details = json.loads(response) + + series_ids = study_details.get("Series", [])[:limit] + + results = [] + for series_id in series_ids: + s_resp = orthanc.RestApiGet(f'/series/{series_id}') + s = json.loads(s_resp) + tags = s.get('MainDicomTags', {}) + results.append({ + 'id': s.get('ID', ''), + 'seriesInstanceUID': tags.get('SeriesInstanceUID', ''), + 'modality': tags.get('Modality', ''), + 'seriesDescription': tags.get('SeriesDescription'), + 'seriesNumber': tags.get('SeriesNumber'), + 'manufacturer': tags.get('Manufacturer') + }) + return results + + +@series_type.field("instances") +def resolve_series_instances(series_obj, _info, limit=100): + """Resolver bringing nested Instances for a given Series.""" + series_id = series_obj['id'] + response = orthanc.RestApiGet(f'/series/{series_id}') + series_details = json.loads(response) + + instance_ids = series_details.get("Instances", [])[:limit] + + results = [] + for instance_id in instance_ids: + i_resp = orthanc.RestApiGet(f'/instances/{instance_id}') + i = json.loads(i_resp) + tags = i.get('MainDicomTags', {}) + results.append({ + 'id': i.get('ID', ''), + 'sopInstanceUID': tags.get('SOPInstanceUID', ''), + 'instanceNumber': tags.get('InstanceNumber') + }) + return results + + +schema = make_executable_schema(TYPE_DEFS, query, patient_type, study_type, + series_type) def graphql_endpoint(output, _url, **request):