Skip to content

Commit 6b959ee

Browse files
committed
Added surveillance review status filter with dataset join helper
1 parent 4e6031f commit 6b959ee

File tree

4 files changed

+95
-121
lines changed

4 files changed

+95
-121
lines changed
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
class SurveillanceReviewStatusType:
2+
"""
3+
Maps review status labels to valid value IDs used in surveillance review filtering.
4+
"""
5+
6+
_label_to_id = {
7+
"awaiting review": 9301,
8+
"in progress": 9302,
9+
"completed": 9303,
10+
# Extend if needed
11+
}
12+
13+
@classmethod
14+
def get_id(cls, description: str) -> int:
15+
key = description.strip().lower()
16+
if key not in cls._label_to_id:
17+
raise ValueError(f"Unknown surveillance review status: '{description}'")
18+
return cls._label_to_id[key]

utils/oracle/mock_selection_builder.py

Lines changed: 26 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -5,34 +5,28 @@
55
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "../..")))
66
from classes.selection_builder_exception import SelectionBuilderException
77
from classes.subject_selection_criteria_key import SubjectSelectionCriteriaKey
8+
from classes.intended_extent_type import IntendedExtentType
89

910

1011
# Add helper class stubs below
11-
class LatestEpisodeLatestInvestigationDataset:
12-
NONE = "none"
13-
COLONOSCOPY_NEW = "colonoscopy_new"
14-
LIMITED_COLONOSCOPY_NEW = "limited_colonoscopy_new"
15-
FLEXIBLE_SIGMOIDOSCOPY_NEW = "flexible_sigmoidoscopy_new"
16-
CT_COLONOGRAPHY_NEW = "ct_colonography_new"
17-
ENDOSCOPY_INCOMPLETE = "endoscopy_incomplete"
18-
RADIOLOGY_INCOMPLETE = "radiology_incomplete"
19-
20-
_mapping = {
21-
"none": NONE,
22-
"colonoscopy_new": COLONOSCOPY_NEW,
23-
"limited_colonoscopy_new": LIMITED_COLONOSCOPY_NEW,
24-
"flexible_sigmoidoscopy_new": FLEXIBLE_SIGMOIDOSCOPY_NEW,
25-
"ct_colonography_new": CT_COLONOGRAPHY_NEW,
26-
"endoscopy_incomplete": ENDOSCOPY_INCOMPLETE,
27-
"radiology_incomplete": RADIOLOGY_INCOMPLETE,
12+
class SurveillanceReviewStatusType:
13+
"""
14+
Maps descriptive surveillance review statuses to valid value IDs.
15+
"""
16+
17+
_label_to_id = {
18+
"awaiting review": 9301,
19+
"in progress": 9302,
20+
"completed": 9303,
21+
# Extend as needed
2822
}
2923

3024
@classmethod
31-
def from_description(cls, description: str) -> str:
25+
def get_id(cls, description: str) -> int:
3226
key = description.strip().lower()
33-
if key not in cls._mapping:
34-
raise ValueError(f"Unknown investigation dataset filter: '{description}'")
35-
return cls._mapping[key]
27+
if key not in cls._label_to_id:
28+
raise ValueError(f"Unknown review status: '{description}'")
29+
return cls._label_to_id[key]
3630

3731

3832
class MockSelectionBuilder:
@@ -94,77 +88,24 @@ def _dataset_source_for_criteria_key(self) -> dict:
9488
return {"table": "ds_mdt_t", "alias": "mdt"}
9589
raise SelectionBuilderException(self.criteria_key_name, self.criteria_value)
9690

91+
def _add_join_to_surveillance_review(self):
92+
self.sql_from.append("-- JOIN to surveillance review placeholder")
93+
9794
# === Example testable method below ===
9895
# Replace this with the one you want to test,
9996
# then use utils/oracle/test_subject_criteria_dev.py to run your scenarios
10097

101-
def _add_criteria_latest_episode_latest_investigation_dataset(self) -> None:
98+
def _add_criteria_surveillance_review_status(self) -> None:
10299
"""
103-
Filters subjects based on their latest investigation dataset in their latest episode.
104-
Supports colonoscopy and radiology variations.
100+
Filters subjects based on the review_status_id in their surveillance review dataset.
105101
"""
106102
try:
107-
self._add_join_to_latest_episode()
108-
value = LatestEpisodeLatestInvestigationDataset.from_description(self.criteria_value)
109-
110-
if value == "none":
111-
self.sql_where.append(
112-
"AND NOT EXISTS (SELECT 'dsc1' FROM v_ds_colonoscopy dsc1 "
113-
"WHERE dsc1.episode_id = ep.subject_epis_id "
114-
"AND dsc1.confirmed_type_id = 16002)"
115-
)
116-
elif value == "colonoscopy_new":
117-
self.sql_where.append(
118-
"AND EXISTS (SELECT 'dsc2' FROM v_ds_colonoscopy dsc2 "
119-
"WHERE dsc2.episode_id = ep.subject_epis_id "
120-
"AND dsc2.confirmed_type_id = 16002 "
121-
"AND dsc2.deleted_flag = 'N' "
122-
"AND dsc2.dataset_new_flag = 'Y')"
123-
)
124-
elif value == "limited_colonoscopy_new":
125-
self.sql_where.append(
126-
"AND EXISTS (SELECT 'dsc3' FROM v_ds_colonoscopy dsc3 "
127-
"WHERE dsc3.episode_id = ep.subject_epis_id "
128-
"AND dsc3.confirmed_type_id = 17996 "
129-
"AND dsc3.deleted_flag = 'N' "
130-
"AND dsc3.dataset_new_flag = 'Y')"
131-
)
132-
elif value == "flexible_sigmoidoscopy_new":
133-
self.sql_where.append(
134-
"AND EXISTS (SELECT 'dsc4' FROM v_ds_colonoscopy dsc4 "
135-
"WHERE dsc4.episode_id = ep.subject_epis_id "
136-
"AND dsc4.confirmed_type_id = 16004 "
137-
"AND dsc4.deleted_flag = 'N' "
138-
"AND dsc4.dataset_new_flag = 'Y')"
139-
)
140-
elif value == "ct_colonography_new":
141-
self.sql_where.append(
142-
"AND EXISTS (SELECT 'dsr1' FROM v_ds_radiology dsr1 "
143-
"WHERE dsr1.episode_id = ep.subject_epis_id "
144-
"AND dsr1.confirmed_type_id = 16087 "
145-
"AND dsr1.deleted_flag = 'N' "
146-
"AND dsr1.dataset_new_flag = 'Y')"
147-
)
148-
elif value == "endoscopy_incomplete":
149-
self.sql_where.append(
150-
"AND EXISTS (SELECT 'dsei' FROM v_ds_colonoscopy dsei "
151-
"WHERE dsei.episode_id = ep.subject_epis_id "
152-
"AND dsei.deleted_flag = 'N' "
153-
"AND dsei.dataset_completed_flag = 'N' "
154-
"AND dsei.dataset_new_flag = 'N' "
155-
"AND dsei.confirmed_test_date >= TO_DATE('01/01/2020','dd/mm/yyyy'))"
156-
)
157-
elif value == "radiology_incomplete":
158-
self.sql_where.append(
159-
"AND EXISTS (SELECT 'dsri' FROM v_ds_radiology dsri "
160-
"WHERE dsri.episode_id = ep.subject_epis_id "
161-
"AND dsri.deleted_flag = 'N' "
162-
"AND dsri.dataset_completed_flag = 'N' "
163-
"AND dsri.dataset_new_flag = 'N' "
164-
"AND dsri.confirmed_test_date >= TO_DATE('01/01/2020','dd/mm/yyyy'))"
165-
)
166-
else:
167-
raise SelectionBuilderException(self.criteria_key_name, self.criteria_value)
103+
self._add_join_to_surveillance_review()
104+
status_id = SurveillanceReviewStatusType.get_id(self.criteria_value)
105+
106+
self.sql_where.append(
107+
f"AND sr.review_status_id {self.criteria_comparator} {status_id}"
108+
)
168109

169110
except Exception:
170111
raise SelectionBuilderException(self.criteria_key_name, self.criteria_value)

utils/oracle/subject_selection_query_builder.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
from classes.latest_episode_latest_investigation_dataset import (
4040
LatestEpisodeLatestInvestigationDataset,
4141
)
42+
from classes.surveillance_review_status_type import SurveillanceReviewStatusType
4243

4344

4445
class SubjectSelectionQueryBuilder:
@@ -1966,6 +1967,46 @@ def _add_criteria_latest_episode_latest_investigation_dataset(self) -> None:
19661967
except Exception:
19671968
raise SelectionBuilderException(self.criteria_key_name, self.criteria_value)
19681969

1970+
def _add_criteria_latest_episode_intended_extent(self) -> None:
1971+
"""
1972+
Filters subjects based on presence of a colonoscopy dataset with a specific intended_extent_id
1973+
in their latest episode.
1974+
"""
1975+
try:
1976+
self._add_join_to_latest_episode()
1977+
extent_id = IntendedExtentType.get_id(self.criteria_value)
1978+
1979+
self.sql_where.append(
1980+
"AND EXISTS (SELECT 'dsc' FROM v_ds_colonoscopy dsc "
1981+
"WHERE dsc.episode_id = ep.subject_epis_id "
1982+
f"AND dsc.intended_extent_id = {extent_id})"
1983+
)
1984+
1985+
except Exception:
1986+
raise SelectionBuilderException(self.criteria_key_name, self.criteria_value)
1987+
1988+
def _add_criteria_surveillance_review_status(self) -> None:
1989+
"""
1990+
Filters subjects based on the review_status_id in their surveillance review dataset.
1991+
"""
1992+
try:
1993+
self._add_join_to_surveillance_review()
1994+
status_id = SurveillanceReviewStatusType.get_id(self.criteria_value)
1995+
1996+
self.sql_where.append(
1997+
f"AND sr.review_status_id {self.criteria_comparator} {status_id}"
1998+
)
1999+
2000+
except Exception:
2001+
raise SelectionBuilderException(self.criteria_key_name, self.criteria_value)
2002+
2003+
def _add_join_to_surveillance_review(self) -> None:
2004+
"""
2005+
Internal helper. Adds the necessary join to the surveillance review dataset for filtering.
2006+
"""
2007+
self.sql_from.append("-- JOIN to surveillance review placeholder")
2008+
2009+
19692010
# ------------------------------------------------------------------------
19702011
# 🧬 CADS Clinical Dataset Filters
19712012
# ------------------------------------------------------------------------

utils/oracle/test_subject_criteria_dev.py

Lines changed: 10 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -31,46 +31,20 @@
3131

3232

3333
# Helper for mock sequencing
34-
def make_builder(key, value, index=0):
35-
b = MockSelectionBuilder(key, value)
34+
def make_builder(key, value, index=0, comparator="="):
35+
b = MockSelectionBuilder(key, value, comparator)
36+
b.criteria_key = key
37+
b.criteria_key_name = key.name
38+
b.criteria_value = value
3639
b.criteria_index = index
40+
b.criteria_comparator = comparator
3741
return b
3842

3943

40-
# === Test: LATEST_EPISODE_LATEST_INVESTIGATION_DATASET (none) ===
44+
# === Test: SURVEILLANCE_REVIEW_STATUS (completed) ===
4145
b = make_builder(
42-
SubjectSelectionCriteriaKey.LATEST_EPISODE_LATEST_INVESTIGATION_DATASET, "none"
46+
SubjectSelectionCriteriaKey.SURVEILLANCE_REVIEW_STATUS, "completed", comparator=">="
4347
)
44-
b._add_criteria_latest_episode_latest_investigation_dataset()
45-
print("=== LATEST_EPISODE_LATEST_INVESTIGATION_DATASET (none) ===")
46-
print(b.dump_sql(), end="\n\n")
47-
48-
# === Test: LATEST_EPISODE_LATEST_INVESTIGATION_DATASET (colonoscopy_new) ===
49-
b = make_builder(
50-
SubjectSelectionCriteriaKey.LATEST_EPISODE_LATEST_INVESTIGATION_DATASET,
51-
"colonoscopy_new",
52-
index=1,
53-
)
54-
b._add_criteria_latest_episode_latest_investigation_dataset()
55-
print("=== LATEST_EPISODE_LATEST_INVESTIGATION_DATASET (colonoscopy_new) ===")
56-
print(b.dump_sql(), end="\n\n")
57-
58-
# === Test: LATEST_EPISODE_LATEST_INVESTIGATION_DATASET (ct_colonography_new) ===
59-
b = make_builder(
60-
SubjectSelectionCriteriaKey.LATEST_EPISODE_LATEST_INVESTIGATION_DATASET,
61-
"ct_colonography_new",
62-
index=2,
63-
)
64-
b._add_criteria_latest_episode_latest_investigation_dataset()
65-
print("=== LATEST_EPISODE_LATEST_INVESTIGATION_DATASET (ct_colonography_new) ===")
66-
print(b.dump_sql(), end="\n\n")
67-
68-
# === Test: LATEST_EPISODE_LATEST_INVESTIGATION_DATASET (endoscopy_incomplete) ===
69-
b = make_builder(
70-
SubjectSelectionCriteriaKey.LATEST_EPISODE_LATEST_INVESTIGATION_DATASET,
71-
"endoscopy_incomplete",
72-
index=3,
73-
)
74-
b._add_criteria_latest_episode_latest_investigation_dataset()
75-
print("=== LATEST_EPISODE_LATEST_INVESTIGATION_DATASET (endoscopy_incomplete) ===")
48+
b._add_criteria_surveillance_review_status()
49+
print("=== SURVEILLANCE_REVIEW_STATUS (completed) ===")
7650
print(b.dump_sql(), end="\n\n")

0 commit comments

Comments
 (0)