Skip to content

Commit 758c430

Browse files
committed
Added LatestEpisodeHasDataset mapping and builder logic for filtering dataset presence in latest episode
1 parent b669385 commit 758c430

File tree

4 files changed

+156
-56
lines changed

4 files changed

+156
-56
lines changed
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
class LatestEpisodeHasDataset:
2+
"""
3+
Interprets presence and completion status of datasets in the latest episode.
4+
"""
5+
6+
NO = "no"
7+
YES_INCOMPLETE = "yes_incomplete"
8+
YES_COMPLETE = "yes_complete"
9+
PAST = "past"
10+
11+
_valid_values = {NO, YES_INCOMPLETE, YES_COMPLETE, PAST}
12+
13+
@classmethod
14+
def from_description(cls, description: str) -> str:
15+
key = description.strip().lower()
16+
if key not in cls._valid_values:
17+
raise ValueError(f"Unknown dataset status: '{description}'")
18+
return key

utils/oracle/mock_selection_builder.py

Lines changed: 68 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -4,47 +4,34 @@
44

55
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "../..")))
66
from classes.selection_builder_exception import SelectionBuilderException
7+
from classes.subject_selection_criteria_key import SubjectSelectionCriteriaKey
78

89

910
# Add helper class stubs below
10-
class IntendedExtentType:
11+
class LatestEpisodeHasDataset:
1112
"""
12-
Resolves intended extent descriptions to valid value IDs or null-check constants.
13+
Maps dataset status descriptions to filter interpretations.
1314
"""
1415

15-
NULL = "null"
16-
NOT_NULL = "not null"
16+
NO = "no"
17+
YES_INCOMPLETE = "yes_incomplete"
18+
YES_COMPLETE = "yes_complete"
19+
PAST = "past"
1720

1821
_mapping = {
19-
"null": NULL,
20-
"not null": NOT_NULL,
21-
"full": 9201,
22-
"partial": 9202,
23-
"none": 9203,
22+
"no": NO,
23+
"yes_incomplete": YES_INCOMPLETE,
24+
"yes_complete": YES_COMPLETE,
25+
"past": PAST,
2426
}
2527

2628
@classmethod
27-
def from_description(cls, description: str):
29+
def from_description(cls, description: str) -> str:
2830
key = description.strip().lower()
2931
if key not in cls._mapping:
30-
raise ValueError(f"Unknown intended extent: '{description}'")
32+
raise ValueError(f"Unknown dataset filter type: '{description}'")
3133
return cls._mapping[key]
3234

33-
@classmethod
34-
def get_id(cls, description: str) -> int:
35-
val = cls.from_description(description)
36-
if isinstance(val, int):
37-
return val
38-
raise ValueError(f"No ID associated with extent: '{description}'")
39-
40-
@classmethod
41-
def get_description(cls, sentinel: str) -> str:
42-
if sentinel == cls.NULL:
43-
return "NULL"
44-
if sentinel == cls.NOT_NULL:
45-
return "NOT NULL"
46-
raise ValueError(f"Unknown null sentinel: {sentinel}")
47-
4835

4936
class MockSelectionBuilder:
5037
"""
@@ -89,26 +76,69 @@ def _add_join_to_latest_episode(self) -> None:
8976
"""
9077
self.sql_from.append("-- JOIN to latest episode placeholder")
9178

79+
def _dataset_source_for_criteria_key(self) -> dict:
80+
"""
81+
Maps criteria key to dataset table and alias.
82+
"""
83+
key = self.criteria_key
84+
if key == SubjectSelectionCriteriaKey.LATEST_EPISODE_HAS_CANCER_AUDIT_DATASET:
85+
return {"table": "ds_cancer_audit_t", "alias": "cads"}
86+
if (
87+
key
88+
== SubjectSelectionCriteriaKey.LATEST_EPISODE_HAS_COLONOSCOPY_ASSESSMENT_DATASET
89+
):
90+
return {"table": "ds_patient_assessment_t", "alias": "dspa"}
91+
if key == SubjectSelectionCriteriaKey.LATEST_EPISODE_HAS_MDT_DATASET:
92+
return {"table": "ds_mdt_t", "alias": "mdt"}
93+
raise SelectionBuilderException(self.criteria_key_name, self.criteria_value)
94+
9295
# === Example testable method below ===
9396
# Replace this with the one you want to test,
9497
# then use utils/oracle/test_subject_criteria_dev.py to run your scenarios
9598

96-
def _add_criteria_diagnostic_test_intended_extent(self) -> None:
99+
def _add_criteria_latest_episode_has_dataset(self) -> None:
97100
"""
98-
Adds WHERE clause filtering diagnostic tests by intended_extent_id.
99-
Supports null checks and value comparisons.
101+
Filters based on presence or completion status of a dataset in the latest episode.
100102
"""
101103
try:
102-
idx = getattr(self, "criteria_index", 0)
103-
xt = f"xt{idx}"
104-
extent = IntendedExtentType.from_description(self.criteria_value)
105-
106-
self.sql_where.append(f"AND {xt}.intended_extent_id ")
107-
108-
if extent in (IntendedExtentType.NULL, IntendedExtentType.NOT_NULL):
109-
self.sql_where.append(f"IS {IntendedExtentType.get_description(extent)}")
104+
self._add_join_to_latest_episode()
105+
106+
dataset_info = self._dataset_source_for_criteria_key()
107+
dataset_table = dataset_info["table"]
108+
alias = dataset_info["alias"]
109+
110+
clause = "AND EXISTS ( "
111+
value = self.criteria_value.strip().lower()
112+
status = LatestEpisodeHasDataset.from_description(value)
113+
filter_clause = ""
114+
115+
if status == LatestEpisodeHasDataset.NO:
116+
clause = "AND NOT EXISTS ( "
117+
elif status == LatestEpisodeHasDataset.YES_INCOMPLETE:
118+
filter_clause = f"AND {alias}.dataset_completed_date IS NULL"
119+
elif status == LatestEpisodeHasDataset.YES_COMPLETE:
120+
filter_clause = f"AND {alias}.dataset_completed_date IS NOT NULL"
121+
elif status == LatestEpisodeHasDataset.PAST:
122+
filter_clause = (
123+
f"AND TRUNC({alias}.dataset_completed_date) < TRUNC(SYSDATE)"
124+
)
110125
else:
111-
self.sql_where.append(f"{self.criteria_comparator} {IntendedExtentType.get_id(self.criteria_value)}")
126+
raise SelectionBuilderException(
127+
self.criteria_key_name, self.criteria_value
128+
)
129+
130+
self.sql_where.append(
131+
"".join(
132+
[
133+
clause,
134+
f"SELECT 1 FROM {dataset_table} {alias} ",
135+
f"WHERE {alias}.episode_id = ep.subject_epis_id ",
136+
f"AND {alias}.deleted_flag = 'N' ",
137+
filter_clause,
138+
")",
139+
]
140+
)
141+
)
112142

113143
except Exception:
114144
raise SelectionBuilderException(self.criteria_key_name, self.criteria_value)

utils/oracle/subject_selection_query_builder.py

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
DiagnosticTestHasOutcomeOfResult,
3636
)
3737
from classes.intended_extent_type import IntendedExtentType
38+
from classes.latest_episode_has_dataset import LatestEpisodeHasDataset
3839

3940

4041
class SubjectSelectionQueryBuilder:
@@ -1822,6 +1823,71 @@ def _add_criteria_diagnostic_test_intended_extent(self) -> None:
18221823
except Exception:
18231824
raise SelectionBuilderException(self.criteria_key_name, self.criteria_value)
18241825

1826+
def _add_criteria_latest_episode_has_dataset(self) -> None:
1827+
"""
1828+
Filters based on presence or completion status of a dataset in the latest episode.
1829+
"""
1830+
try:
1831+
self._add_join_to_latest_episode()
1832+
1833+
dataset_info = self._dataset_source_for_criteria_key()
1834+
dataset_table = dataset_info["table"]
1835+
alias = dataset_info["alias"]
1836+
1837+
clause = "AND EXISTS ( "
1838+
value = self.criteria_value.strip().lower()
1839+
status = LatestEpisodeHasDataset.from_description(value)
1840+
filter_clause = ""
1841+
1842+
if status == LatestEpisodeHasDataset.NO:
1843+
clause = "AND NOT EXISTS ( "
1844+
elif status == LatestEpisodeHasDataset.YES_INCOMPLETE:
1845+
filter_clause = f"AND {alias}.dataset_completed_date IS NULL"
1846+
elif status == LatestEpisodeHasDataset.YES_COMPLETE:
1847+
filter_clause = f"AND {alias}.dataset_completed_date IS NOT NULL"
1848+
elif status == LatestEpisodeHasDataset.PAST:
1849+
filter_clause = (
1850+
f"AND TRUNC({alias}.dataset_completed_date) < TRUNC(SYSDATE)"
1851+
)
1852+
else:
1853+
raise SelectionBuilderException(
1854+
self.criteria_key_name, self.criteria_value
1855+
)
1856+
1857+
self.sql_where.append(
1858+
"".join(
1859+
[
1860+
clause,
1861+
f"SELECT 1 FROM {dataset_table} {alias} ",
1862+
f"WHERE {alias}.episode_id = ep.subject_epis_id ",
1863+
f"AND {alias}.deleted_flag = 'N' ",
1864+
filter_clause,
1865+
")",
1866+
]
1867+
)
1868+
)
1869+
1870+
except Exception:
1871+
raise SelectionBuilderException(self.criteria_key_name, self.criteria_value)
1872+
1873+
def _dataset_source_for_criteria_key(self) -> dict:
1874+
"""
1875+
Internal helper method.
1876+
Maps LATEST_EPISODE_HAS_* criteria keys to their corresponding dataset tables and aliases.
1877+
Used by _add_criteria_latest_episode_has_dataset().
1878+
"""
1879+
key = self.criteria_key
1880+
if key == SubjectSelectionCriteriaKey.LATEST_EPISODE_HAS_CANCER_AUDIT_DATASET:
1881+
return {"table": "ds_cancer_audit_t", "alias": "cads"}
1882+
if (
1883+
key
1884+
== SubjectSelectionCriteriaKey.LATEST_EPISODE_HAS_COLONOSCOPY_ASSESSMENT_DATASET
1885+
):
1886+
return {"table": "ds_patient_assessment_t", "alias": "dspa"}
1887+
if key == SubjectSelectionCriteriaKey.LATEST_EPISODE_HAS_MDT_DATASET:
1888+
return {"table": "ds_mdt_t", "alias": "mdt"}
1889+
raise SelectionBuilderException(self.criteria_key_name, self.criteria_value)
1890+
18251891
# ------------------------------------------------------------------------
18261892
# 🧬 CADS Clinical Dataset Filters
18271893
# ------------------------------------------------------------------------

utils/oracle/test_subject_criteria_dev.py

Lines changed: 4 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -37,24 +37,10 @@ def make_builder(key, value, index=0):
3737
return b
3838

3939

40-
# === Test: DIAGNOSTIC_TEST_INTENDED_EXTENT (null) ===
41-
b = make_builder(SubjectSelectionCriteriaKey.DIAGNOSTIC_TEST_INTENDED_EXTENT, "null")
42-
b._add_criteria_diagnostic_test_intended_extent()
43-
print("=== DIAGNOSTIC_TEST_INTENDED_EXTENT (null) ===")
44-
print(b.dump_sql(), end="\n\n")
45-
46-
# === Test: DIAGNOSTIC_TEST_INTENDED_EXTENT (not null) ===
47-
b = make_builder(
48-
SubjectSelectionCriteriaKey.DIAGNOSTIC_TEST_INTENDED_EXTENT, "not null", index=1
49-
)
50-
b._add_criteria_diagnostic_test_intended_extent()
51-
print("=== DIAGNOSTIC_TEST_INTENDED_EXTENT (not null) ===")
52-
print(b.dump_sql(), end="\n\n")
53-
54-
# === Test: DIAGNOSTIC_TEST_INTENDED_EXTENT (partial) ===
40+
# === Test: LATEST_EPISODE_HAS_CANCER_AUDIT_DATASET (yes_complete) ===
5541
b = make_builder(
56-
SubjectSelectionCriteriaKey.DIAGNOSTIC_TEST_INTENDED_EXTENT, "partial", index=2
42+
SubjectSelectionCriteriaKey.LATEST_EPISODE_HAS_CANCER_AUDIT_DATASET, "yes_complete"
5743
)
58-
b._add_criteria_diagnostic_test_intended_extent()
59-
print("=== DIAGNOSTIC_TEST_INTENDED_EXTENT (partial) ===")
44+
b._add_criteria_latest_episode_has_dataset()
45+
print("=== LATEST_EPISODE_HAS_CANCER_AUDIT_DATASET (yes_complete) ===")
6046
print(b.dump_sql(), end="\n\n")

0 commit comments

Comments
 (0)