1212from .utils import process_properties
1313
1414
15+ def validate_location_kind (location : models .LocationNode , expected_kind : str , field_name : str ) -> None :
16+ """Validate that a location has the expected kind."""
17+ if location .kind .upper () != expected_kind .upper ():
18+ raise Exception (
19+ f"{ field_name } must be a location of kind { expected_kind } , "
20+ f"but got { location .kind } "
21+ )
22+
23+
24+ def validate_position_kind (location : models .LocationNode , field_name : str ) -> None :
25+ """Validate that a location is a valid position type."""
26+ allowed_kinds = {"HOSPITAL" , "PRACTICE" , "CLINIC" , "WARD" , "BED" , "ROOM" }
27+ if location .kind .upper () not in allowed_kinds :
28+ raise Exception (
29+ f"{ field_name } must be a location of kind HOSPITAL, PRACTICE, CLINIC, "
30+ f"WARD, BED, or ROOM, but got { location .kind } "
31+ )
32+
33+
34+ def validate_team_kind (location : models .LocationNode , field_name : str ) -> None :
35+ """Validate that a location is a valid team type."""
36+ allowed_kinds = {"CLINIC" , "TEAM" , "PRACTICE" , "HOSPITAL" }
37+ if location .kind .upper () not in allowed_kinds :
38+ raise Exception (
39+ f"{ field_name } must be a location of kind CLINIC, TEAM, PRACTICE, "
40+ f"or HOSPITAL, but got { location .kind } "
41+ )
42+
43+
1544@strawberry .type
1645class PatientQuery :
1746 @strawberry .field
@@ -26,6 +55,7 @@ async def patient(
2655 .options (
2756 selectinload (models .Patient .assigned_locations ),
2857 selectinload (models .Patient .tasks ),
58+ selectinload (models .Patient .teams ),
2959 ),
3060 )
3161 return result .scalars ().first ()
@@ -40,6 +70,7 @@ async def patients(
4070 query = select (models .Patient ).options (
4171 selectinload (models .Patient .assigned_locations ),
4272 selectinload (models .Patient .tasks ),
73+ selectinload (models .Patient .teams ),
4374 )
4475
4576 if states :
@@ -88,6 +119,7 @@ async def recent_patients(
88119 .options (
89120 selectinload (models .Patient .assigned_locations ),
90121 selectinload (models .Patient .tasks ),
122+ selectinload (models .Patient .teams ),
91123 )
92124 .limit (limit )
93125 )
@@ -103,26 +135,70 @@ async def create_patient(
103135 info : Info ,
104136 data : CreatePatientInput ,
105137 ) -> PatientType :
138+ db = info .context .db
106139 initial_state = data .state .value if data .state else PatientState .WAIT .value
140+
141+ clinic_result = await db .execute (
142+ select (models .LocationNode ).where (
143+ models .LocationNode .id == data .clinic_id ,
144+ ),
145+ )
146+ clinic = clinic_result .scalars ().first ()
147+ if not clinic :
148+ raise Exception (f"Clinic location with id { data .clinic_id } not found" )
149+ validate_location_kind (clinic , "CLINIC" , "clinic_id" )
150+
151+ position = None
152+ if data .position_id :
153+ position_result = await db .execute (
154+ select (models .LocationNode ).where (
155+ models .LocationNode .id == data .position_id ,
156+ ),
157+ )
158+ position = position_result .scalars ().first ()
159+ if not position :
160+ raise Exception (f"Position location with id { data .position_id } not found" )
161+ validate_position_kind (position , "position_id" )
162+
163+ teams = []
164+ if data .team_ids :
165+ teams_result = await db .execute (
166+ select (models .LocationNode ).where (
167+ models .LocationNode .id .in_ (data .team_ids ),
168+ ),
169+ )
170+ teams = list (teams_result .scalars ().all ())
171+ if len (teams ) != len (data .team_ids ):
172+ found_ids = {t .id for t in teams }
173+ missing_ids = set (data .team_ids ) - found_ids
174+ raise Exception (f"Team locations with ids { missing_ids } not found" )
175+ for team in teams :
176+ validate_team_kind (team , "team_ids" )
177+
107178 new_patient = models .Patient (
108179 firstname = data .firstname ,
109180 lastname = data .lastname ,
110181 birthdate = data .birthdate ,
111182 sex = data .sex .value ,
112183 state = initial_state ,
113184 assigned_location_id = data .assigned_location_id ,
185+ clinic_id = data .clinic_id ,
186+ position_id = data .position_id ,
114187 )
115188
189+ if teams :
190+ new_patient .teams = teams
191+
116192 if data .assigned_location_ids :
117- result = await info . context . db .execute (
193+ result = await db .execute (
118194 select (models .LocationNode ).where (
119195 models .LocationNode .id .in_ (data .assigned_location_ids ),
120196 ),
121197 )
122198 locations = result .scalars ().all ()
123199 new_patient .assigned_locations = list (locations )
124200 elif data .assigned_location_id :
125- result = await info . context . db .execute (
201+ result = await db .execute (
126202 select (models .LocationNode ).where (
127203 models .LocationNode .id == data .assigned_location_id ,
128204 ),
@@ -133,16 +209,16 @@ async def create_patient(
133209
134210 if data .properties :
135211 await process_properties (
136- info . context . db ,
212+ db ,
137213 new_patient ,
138214 data .properties ,
139215 "patient" ,
140216 )
141217
142- info . context . db .add (new_patient )
143- await info . context . db .commit ()
218+ db .add (new_patient )
219+ await db .commit ()
144220
145- await info . context . db .refresh (new_patient , ["assigned_locations" ])
221+ await db .refresh (new_patient , ["assigned_locations" , "teams " ])
146222 await redis_client .publish ("patient_created" , new_patient .id )
147223 return new_patient
148224
@@ -157,7 +233,10 @@ async def update_patient(
157233 result = await db .execute (
158234 select (models .Patient )
159235 .where (models .Patient .id == id )
160- .options (selectinload (models .Patient .assigned_locations )),
236+ .options (
237+ selectinload (models .Patient .assigned_locations ),
238+ selectinload (models .Patient .teams ),
239+ ),
161240 )
162241 patient = result .scalars ().first ()
163242 if not patient :
@@ -172,6 +251,49 @@ async def update_patient(
172251 if data .sex is not None :
173252 patient .sex = data .sex .value
174253
254+ # Update clinic (if provided)
255+ if data .clinic_id is not None :
256+ clinic_result = await db .execute (
257+ select (models .LocationNode ).where (
258+ models .LocationNode .id == data .clinic_id ,
259+ ),
260+ )
261+ clinic = clinic_result .scalars ().first ()
262+ if not clinic :
263+ raise Exception (f"Clinic location with id { data .clinic_id } not found" )
264+ validate_location_kind (clinic , "CLINIC" , "clinic_id" )
265+ patient .clinic_id = data .clinic_id
266+
267+ if data .position_id is not None :
268+ position_result = await db .execute (
269+ select (models .LocationNode ).where (
270+ models .LocationNode .id == data .position_id ,
271+ ),
272+ )
273+ position = position_result .scalars ().first ()
274+ if not position :
275+ raise Exception (f"Position location with id { data .position_id } not found" )
276+ validate_position_kind (position , "position_id" )
277+ patient .position_id = data .position_id
278+
279+ if data .team_ids is not None :
280+ if len (data .team_ids ) == 0 :
281+ patient .teams = []
282+ else :
283+ teams_result = await db .execute (
284+ select (models .LocationNode ).where (
285+ models .LocationNode .id .in_ (data .team_ids ),
286+ ),
287+ )
288+ teams = list (teams_result .scalars ().all ())
289+ if len (teams ) != len (data .team_ids ):
290+ found_ids = {t .id for t in teams }
291+ missing_ids = set (data .team_ids ) - found_ids
292+ raise Exception (f"Team locations with ids { missing_ids } not found" )
293+ for team in teams :
294+ validate_team_kind (team , "team_ids" )
295+ patient .teams = teams
296+
175297 if data .assigned_location_ids is not None :
176298 result = await db .execute (
177299 select (models .LocationNode ).where (
@@ -196,7 +318,7 @@ async def update_patient(
196318 await process_properties (db , patient , data .properties , "patient" )
197319
198320 await db .commit ()
199- await db .refresh (patient , ["assigned_locations" ])
321+ await db .refresh (patient , ["assigned_locations" , "teams" ])
200322 return patient
201323
202324 @strawberry .mutation
@@ -218,7 +340,10 @@ async def admit_patient(self, info: Info, id: strawberry.ID) -> PatientType:
218340 result = await db .execute (
219341 select (models .Patient )
220342 .where (models .Patient .id == id )
221- .options (selectinload (models .Patient .assigned_locations )),
343+ .options (
344+ selectinload (models .Patient .assigned_locations ),
345+ selectinload (models .Patient .teams ),
346+ ),
222347 )
223348 patient = result .scalars ().first ()
224349 if not patient :
@@ -234,7 +359,10 @@ async def discharge_patient(self, info: Info, id: strawberry.ID) -> PatientType:
234359 result = await db .execute (
235360 select (models .Patient )
236361 .where (models .Patient .id == id )
237- .options (selectinload (models .Patient .assigned_locations )),
362+ .options (
363+ selectinload (models .Patient .assigned_locations ),
364+ selectinload (models .Patient .teams ),
365+ ),
238366 )
239367 patient = result .scalars ().first ()
240368 if not patient :
@@ -250,7 +378,10 @@ async def mark_patient_dead(self, info: Info, id: strawberry.ID) -> PatientType:
250378 result = await db .execute (
251379 select (models .Patient )
252380 .where (models .Patient .id == id )
253- .options (selectinload (models .Patient .assigned_locations )),
381+ .options (
382+ selectinload (models .Patient .assigned_locations ),
383+ selectinload (models .Patient .teams ),
384+ ),
254385 )
255386 patient = result .scalars ().first ()
256387 if not patient :
@@ -266,7 +397,10 @@ async def wait_patient(self, info: Info, id: strawberry.ID) -> PatientType:
266397 result = await db .execute (
267398 select (models .Patient )
268399 .where (models .Patient .id == id )
269- .options (selectinload (models .Patient .assigned_locations )),
400+ .options (
401+ selectinload (models .Patient .assigned_locations ),
402+ selectinload (models .Patient .teams ),
403+ ),
270404 )
271405 patient = result .scalars ().first ()
272406 if not patient :
0 commit comments