11# mock_selection_builder.py — Development-only testing harness for criteria logic
22import sys
33import os
4+ import re
45from typing import Optional
56
67sys .path .insert (0 , os .path .abspath (os .path .join (os .path .dirname (__file__ ), "../.." )))
@@ -14,23 +15,40 @@ def __init__(self, lynch_due_date_change_reason_id):
1415 self .lynch_due_date_change_reason_id = lynch_due_date_change_reason_id
1516
1617
17- class PrevalentIncidentStatusType :
18- """
19- Maps symbolic values for FOBT prevalent/incident episode classification.
20- """
18+ class NotifyEventStatus :
19+ _label_to_id = {
20+ "S1" : 9901 ,
21+ "S2" : 9902 ,
22+ "M1" : 9903 ,
23+ # Extend as needed
24+ }
2125
22- PREVALENT = "prevalent"
23- INCIDENT = "incident"
26+ @classmethod
27+ def get_id (cls , description : str ) -> int :
28+ key = description .strip ().upper ()
29+ if key not in cls ._label_to_id :
30+ raise ValueError (f"Unknown Notify event type: '{ description } '" )
31+ return cls ._label_to_id [key ]
2432
25- _valid_values = {PREVALENT , INCIDENT }
2633
27- @classmethod
28- def from_description (cls , description : str ) -> str :
29- key = description .strip ().lower ()
30- if key not in cls ._valid_values :
31- raise ValueError (f"Unknown FOBT episode status: '{ description } '" )
32- return key
34+ def parse_notify_criteria (criteria : str ) -> dict :
35+ """
36+ Parses criteria strings like 'S1 - new' or 'S1 (S1w) - sending' into parts.
37+ """
38+ criteria = criteria .strip ()
39+ if criteria .lower () == "none" :
40+ return {"status" : "none" }
41+
42+ pattern = r"^(?P<type>[^\s(]+)(?:\s+\((?P<code>[^)]+)\))?\s*-\s*(?P<status>\w+)$"
43+ match = re .match (pattern , criteria , re .IGNORECASE )
44+ if not match :
45+ raise ValueError (f"Invalid Notify criteria format: '{ criteria } '" )
3346
47+ return {
48+ "type" : match .group ("type" ),
49+ "code" : match .group ("code" ),
50+ "status" : match .group ("status" ).lower (),
51+ }
3452
3553class MockSelectionBuilder :
3654 """
@@ -98,22 +116,42 @@ def _dataset_source_for_criteria_key(self) -> dict:
98116 def _add_join_to_surveillance_review (self ):
99117 self .sql_from .append ("-- JOIN to surveillance review placeholder" )
100118
119+
101120 # === Example testable method below ===
102121 # Replace this with the one you want to test,
103122 # then use utils/oracle/test_subject_criteria_dev.py to run your scenarios
104123
105- def _add_criteria_fobt_prevalent_incident_status (self ) -> None :
124+ def _add_criteria_notify_queued_message_status (self ) -> None :
106125 """
107- Filters subjects by whether their FOBT episode is prevalent or incident .
126+ Filters subjects based on Notify queued message status, e.g. 'S1 (S1w) - new' .
108127 """
109128 try :
110- value = PrevalentIncidentStatusType .from_description (self .criteria_value )
111- column = "ss.fobt_incident_subject_epis_id"
129+ parts = parse_notify_criteria (self .criteria_value )
130+ status = parts ["status" ]
131+
132+ if status == "none" :
133+ clause = "NOT EXISTS"
134+ else :
135+ clause = "EXISTS"
136+
137+ self .sql_where .append (f"AND { clause } (" )
138+ self .sql_where .append (
139+ "SELECT 1 FROM notify_message_queue nmq "
140+ "INNER JOIN notify_message_definition nmd ON nmd.message_definition_id = nmq.message_definition_id "
141+ "WHERE nmq.nhs_number = c.nhs_number "
142+ )
143+
144+ # Simulate getNotifyMessageEventStatusIdFromCriteria()
145+ event_status_id = NotifyEventStatus .get_id (parts ["type" ])
146+ self .sql_where .append (f"AND nmd.event_status_id = { event_status_id } " )
147+
148+ if status != "none" :
149+ self .sql_where .append (f"AND nmq.message_status = '{ status } ' " )
150+
151+ if "code" in parts and parts ["code" ]:
152+ self .sql_where .append (f"AND nmd.message_code = '{ parts ['code' ]} ' " )
112153
113- if value == PrevalentIncidentStatusType .PREVALENT :
114- self .sql_where .append (f"AND { column } IS NULL" )
115- elif value == PrevalentIncidentStatusType .INCIDENT :
116- self .sql_where .append (f"AND { column } IS NOT NULL" )
154+ self .sql_where .append (")" )
117155
118156 except Exception :
119157 raise SelectionBuilderException (self .criteria_key_name , self .criteria_value )
0 commit comments