77
88
99# Add helper class stubs below
10- class AppointmentStatusType :
10+ class WhichDiagnosticTest :
1111 """
12- Mocked appointment status mapping for test purposes .
13- Replace IDs with real values from production if needed .
12+ Test stub that maps criteria values to normalized diagnostic test selection keys .
13+ Used by _add_join_to_diagnostic_tests for test harness evaluation .
1414 """
1515
16+ ANY_TEST_IN_ANY_EPISODE = "any_test_in_any_episode"
17+ ANY_TEST_IN_LATEST_EPISODE = "any_test_in_latest_episode"
18+ ONLY_TEST_IN_LATEST_EPISODE = "only_test_in_latest_episode"
19+ ONLY_NOT_VOID_TEST_IN_LATEST_EPISODE = "only_not_void_test_in_latest_episode"
20+ LATEST_TEST_IN_LATEST_EPISODE = "latest_test_in_latest_episode"
21+ LATEST_NOT_VOID_TEST_IN_LATEST_EPISODE = "latest_not_void_test_in_latest_episode"
22+ EARLIEST_NOT_VOID_TEST_IN_LATEST_EPISODE = (
23+ "earliest_not_void_test_in_latest_episode"
24+ )
25+ EARLIER_TEST_IN_LATEST_EPISODE = "earlier_test_in_latest_episode"
26+ LATER_TEST_IN_LATEST_EPISODE = "later_test_in_latest_episode"
27+
1628 _mapping = {
17- "booked" : 2001 ,
18- "attended" : 2002 ,
19- "cancelled" : 2003 ,
20- "dna" : 2004 , # Did Not Attend
29+ "any_test_in_any_episode" : ANY_TEST_IN_ANY_EPISODE ,
30+ "any_test_in_latest_episode" : ANY_TEST_IN_LATEST_EPISODE ,
31+ "only_test_in_latest_episode" : ONLY_TEST_IN_LATEST_EPISODE ,
32+ "only_not_void_test_in_latest_episode" : ONLY_NOT_VOID_TEST_IN_LATEST_EPISODE ,
33+ "latest_test_in_latest_episode" : LATEST_TEST_IN_LATEST_EPISODE ,
34+ "latest_not_void_test_in_latest_episode" : LATEST_NOT_VOID_TEST_IN_LATEST_EPISODE ,
35+ "earliest_not_void_test_in_latest_episode" : EARLIEST_NOT_VOID_TEST_IN_LATEST_EPISODE ,
36+ "earlier_test_in_latest_episode" : EARLIER_TEST_IN_LATEST_EPISODE ,
37+ "later_test_in_latest_episode" : LATER_TEST_IN_LATEST_EPISODE ,
2138 }
2239
2340 @classmethod
24- def get_id (cls , description : str ) -> int :
41+ def from_description (cls , description : str ) -> str :
2542 key = description .strip ().lower ()
2643 if key not in cls ._mapping :
27- raise ValueError (f"Unknown appointment status : { description } " )
44+ raise ValueError (f"Unknown diagnostic test type : { description } " )
2845 return cls ._mapping [key ]
2946
3047
@@ -47,6 +64,7 @@ def __init__(self, criteria_key, criteria_value, criteria_comparator=">="):
4764 self .criteria_key_name = criteria_key .description
4865 self .criteria_value = criteria_value
4966 self .criteria_comparator = criteria_comparator
67+ self .criteria_index : int = 0
5068 self .sql_where = []
5169 self .sql_from = []
5270
@@ -74,21 +92,79 @@ def _add_join_to_latest_episode(self) -> None:
7492 # Replace this with the one you want to test,
7593 # then use utils/oracle/test_subject_criteria_dev.py to run your scenarios
7694
77- def _add_criteria_appointment_status (self ) -> None :
78- """
79- Filters appointments by status (e.g. booked, attended).
80- Requires prior join to appointment_t as alias 'ap'.
81-
82- Uses comparator and resolves status label to ID via AppointmentStatusType.
83- """
95+ def _add_join_to_diagnostic_tests (self ) -> None :
8496 try :
85- comparator = self .criteria_comparator
86- value = self .criteria_value .strip ()
87- status_id = AppointmentStatusType .get_id (value )
97+ which = WhichDiagnosticTest .from_description (self .criteria_value )
98+ idx = getattr (self , "criteria_index" , 0 )
99+ xt = f"xt{ idx } "
100+ xtp = f"xt{ idx - 1 } "
88101
89- self .sql_where .append (
90- f"AND ap.appointment_status_id { comparator } { status_id } "
102+ self .sql_from .append (
103+ f"INNER JOIN external_tests_t { xt } ON { xt } .screening_subject_id = ss.screening_subject_id "
91104 )
92105
106+ if which == WhichDiagnosticTest .ANY_TEST_IN_ANY_EPISODE :
107+ return
108+
109+ self ._add_join_to_latest_episode ()
110+
111+ handlers = {
112+ WhichDiagnosticTest .ANY_TEST_IN_LATEST_EPISODE : self ._handle_any_test_in_latest_episode ,
113+ WhichDiagnosticTest .ONLY_TEST_IN_LATEST_EPISODE : self ._handle_only_test_in_latest_episode ,
114+ WhichDiagnosticTest .ONLY_NOT_VOID_TEST_IN_LATEST_EPISODE : self ._handle_only_test_in_latest_episode ,
115+ WhichDiagnosticTest .LATEST_TEST_IN_LATEST_EPISODE : self ._handle_latest_test_in_latest_episode ,
116+ WhichDiagnosticTest .LATEST_NOT_VOID_TEST_IN_LATEST_EPISODE : self ._handle_latest_test_in_latest_episode ,
117+ WhichDiagnosticTest .EARLIEST_NOT_VOID_TEST_IN_LATEST_EPISODE : self ._handle_earliest_test_in_latest_episode ,
118+ WhichDiagnosticTest .EARLIER_TEST_IN_LATEST_EPISODE : self ._handle_earlier_or_later_test ,
119+ WhichDiagnosticTest .LATER_TEST_IN_LATEST_EPISODE : self ._handle_earlier_or_later_test ,
120+ }
121+
122+ if which in handlers :
123+ handlers [which ](which , xt , xtp )
124+ else :
125+ raise ValueError (f"Unsupported diagnostic test type: { which } " )
126+
93127 except Exception :
94128 raise SelectionBuilderException (self .criteria_key_name , self .criteria_value )
129+
130+ def _handle_any_test_in_latest_episode (self , which , xt , _ ):
131+ self .sql_from .append (f"AND { xt } .subject_epis_id = ep.subject_epis_id" )
132+
133+ def _handle_only_test_in_latest_episode (self , which , xt , _ ):
134+ self .sql_from .append (f"AND { xt } .subject_epis_id = ep.subject_epis_id" )
135+ if which == WhichDiagnosticTest .ONLY_NOT_VOID_TEST_IN_LATEST_EPISODE :
136+ self .sql_from .append (f"AND { xt } .void = 'N'" )
137+ self .sql_from .append (
138+ f"""AND NOT EXISTS (
139+ SELECT 'xto' FROM external_tests_t xto
140+ WHERE xto.screening_subject_id = ss.screening_subject_id
141+ { 'AND xto.void = \' N\' ' if which == WhichDiagnosticTest .ONLY_NOT_VOID_TEST_IN_LATEST_EPISODE else '' }
142+ AND xto.subject_epis_id = ep.subject_epis_id
143+ AND xto.ext_test_id != { xt } .ext_test_id )"""
144+ )
145+
146+ def _handle_latest_test_in_latest_episode (self , which , xt , _ ):
147+ self .sql_from .append (
148+ f"""AND { xt } .ext_test_id = (
149+ SELECT MAX(xtx.ext_test_id) FROM external_tests_t xtx
150+ WHERE xtx.screening_subject_id = ss.screening_subject_id
151+ { 'AND xtx.void = \' N\' ' if which == WhichDiagnosticTest .LATEST_NOT_VOID_TEST_IN_LATEST_EPISODE else '' }
152+ AND xtx.subject_epis_id = ep.subject_epis_id )"""
153+ )
154+
155+ def _handle_earliest_test_in_latest_episode (self , which , xt , _ ):
156+ self .sql_from .append (
157+ f"""AND { xt } .ext_test_id = (
158+ SELECT MIN(xtn.ext_test_id) FROM external_tests_t xtn
159+ WHERE xtn.screening_subject_id = ss.screening_subject_id
160+ AND xtn.void = 'N'
161+ AND xtn.subject_epis_id = ep.subject_epis_id )"""
162+ )
163+
164+ def _handle_earlier_or_later_test (self , which , xt , xtp ):
165+ if getattr (self , "criteria_index" , 0 ) == 0 :
166+ raise SelectionBuilderException (self .criteria_key_name , self .criteria_value )
167+ comparator = (
168+ "<" if which == WhichDiagnosticTest .EARLIER_TEST_IN_LATEST_EPISODE else ">"
169+ )
170+ self .sql_from .append (f"AND { xt } .ext_test_id { comparator } { xtp } .ext_test_id" )
0 commit comments