Skip to content

Commit 5ab54f4

Browse files
committed
Support date ranges in C-FIND query identifier
Conformance to DICOM Scheduled Procedure Step Start Date means support for date ranges. If the query param is '*' matches on any date will be returned. If the query param starts with '-' matches on records until the date param will be returned. If the query param ends with '-' matches on records on and after the date param will be returned. If the query param contains '-' between two date params, records between and including the two dates will be returned.
1 parent 42e712e commit 5ab54f4

3 files changed

Lines changed: 119 additions & 7 deletions

File tree

src/services/storage.py

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -373,7 +373,7 @@ def find_worklist_items(
373373
374374
Args:
375375
modality: Filter by modality (e.g., "MG")
376-
scheduled_date: Filter by scheduled date (YYYYMMDD)
376+
scheduled_date: Filter by scheduled date (YYYYMMDD, or range like "20240101-20240131")
377377
patient_id: Filter by patient ID
378378
379379
Returns:
@@ -393,8 +393,19 @@ def find_worklist_items(
393393
params.append(modality)
394394

395395
if scheduled_date:
396-
where_clauses.append("scheduled_date = ?")
397-
params.append(scheduled_date)
396+
if scheduled_date.endswith("-"):
397+
where_clauses.append("scheduled_date >= ?")
398+
params.append(scheduled_date[:-1].strip())
399+
elif scheduled_date.startswith("-"):
400+
where_clauses.append("scheduled_date <= ?")
401+
params.append(scheduled_date[1:].strip())
402+
elif "-" in scheduled_date:
403+
start_date, end_date = [s.strip() for s in scheduled_date.split("-", 1)]
404+
where_clauses.append("scheduled_date >= ? AND scheduled_date <= ?")
405+
params.extend([start_date, end_date])
406+
else:
407+
where_clauses.append("scheduled_date = ?")
408+
params.append(scheduled_date.strip())
398409

399410
if patient_id:
400411
where_clauses.append("patient_id = ?")

tests/integration/test_c_find_returns_worklist_items.py

Lines changed: 44 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ def with_worklist_items(self, storage):
4040
patient_name="JONES^MARY",
4141
patient_birth_date="19900202",
4242
patient_sex="F",
43-
scheduled_date="20240102",
43+
scheduled_date="20240302",
4444
scheduled_time="094500",
4545
modality="MG",
4646
procedure_code="12345-6",
@@ -89,15 +89,15 @@ def test_cfind_returns_scheduled_items(self, event, storage):
8989
assert ds.StudyDescription == "MAMMOGRAPHY"
9090
assert ds.ScheduledProcedureStepSequence[0].Modality == "MG"
9191
assert ds.ScheduledProcedureStepSequence[0].ScheduledProcedureStepDescription == "MAMMOGRAPHY"
92-
assert ds.ScheduledProcedureStepSequence[0].ScheduledProcedureStepStartDate == "20240102"
92+
assert ds.ScheduledProcedureStepSequence[0].ScheduledProcedureStepStartDate == "20240302"
9393
assert ds.ScheduledProcedureStepSequence[0].ScheduledProcedureStepStartTime == "094500"
9494

9595
status, ds = results[2]
9696
assert status == SUCCESS
9797
assert ds is None
9898

99-
def test_cfind_filters_by_scheduled_date(self, event, storage):
100-
event.identifier.ScheduledProcedureStepSequence[0].ScheduledProcedureStepStartDate = "20240101"
99+
def test_cfind_filters_by_scheduled_date_range(self, event, storage):
100+
event.identifier.ScheduledProcedureStepSequence[0].ScheduledProcedureStepStartDate = "20240101-20240201"
101101

102102
results = list(CFind(storage).call(event))
103103

@@ -116,6 +116,46 @@ def test_cfind_filters_by_scheduled_date(self, event, storage):
116116
assert status == SUCCESS
117117
assert ds is None
118118

119+
def test_cfind_filters_by_before_scheduled_date(self, event, storage):
120+
event.identifier.ScheduledProcedureStepSequence[0].ScheduledProcedureStepStartDate = "-20240101"
121+
122+
results = list(CFind(storage).call(event))
123+
124+
assert len(results) == 2
125+
126+
status, ds = results[0]
127+
assert status == PENDING
128+
assert ds.PatientID == "999123456"
129+
assert ds.PatientName == "SMITH^JANE"
130+
assert ds.PatientBirthDate == "19800101"
131+
assert ds.AccessionNumber == "ACC123456"
132+
assert ds.ScheduledProcedureStepSequence[0].Modality == "MG"
133+
assert ds.ScheduledProcedureStepSequence[0].ScheduledProcedureStepStartDate == "20240101"
134+
135+
status, ds = results[1]
136+
assert status == SUCCESS
137+
assert ds is None
138+
139+
def test_cfind_filters_by_after_scheduled_date(self, event, storage):
140+
event.identifier.ScheduledProcedureStepSequence[0].ScheduledProcedureStepStartDate = "20240201-"
141+
142+
results = list(CFind(storage).call(event))
143+
144+
assert len(results) == 2
145+
146+
status, ds = results[0]
147+
assert status == PENDING
148+
assert ds.PatientID == "999234567"
149+
assert ds.PatientName == "JONES^MARY"
150+
assert ds.PatientBirthDate == "19900202"
151+
assert ds.AccessionNumber == "ACC234567"
152+
assert ds.ScheduledProcedureStepSequence[0].Modality == "MG"
153+
assert ds.ScheduledProcedureStepSequence[0].ScheduledProcedureStepStartDate == "20240302"
154+
155+
status, ds = results[1]
156+
assert status == SUCCESS
157+
assert ds is None
158+
119159
def test_cfind_filters_by_modality(self, event, storage):
120160
storage.store_worklist_item(
121161
WorklistItem(

tests/services/test_storage.py

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,67 @@ def test_find_worklist_items_with_filters(self, mock_db, tmp_dir):
283283
["MG", "20240101", "999123456"],
284284
)
285285

286+
def test_find_worklist_items_with_date_range(self, mock_db, tmp_dir):
287+
mock_cursor = MagicMock()
288+
mock_cursor.fetchall.return_value = []
289+
mock_connection = MagicMock()
290+
mock_connection.execute.return_value = mock_cursor
291+
mock_db.connect.return_value = mock_connection
292+
293+
subject = MWLStorage(tmp_dir)
294+
mock_connection.reset_mock()
295+
296+
subject.find_worklist_items(scheduled_date="20240101 - 20240131")
297+
298+
mock_connection.execute.assert_called_once_with(
299+
(
300+
"SELECT accession_number, modality, patient_birth_date, patient_id, "
301+
"patient_name, patient_sex, procedure_code, scheduled_date, scheduled_time, "
302+
"source_message_id, study_description, study_instance_uid, status, mpps_instance_uid "
303+
"FROM worklist_items WHERE scheduled_date BETWEEN ? AND ? "
304+
"ORDER BY scheduled_date, scheduled_time"
305+
),
306+
["20240101", "20240131"],
307+
)
308+
309+
def test_find_worklist_items_with_open_ended_date_range(self, mock_db, tmp_dir):
310+
mock_cursor = MagicMock()
311+
mock_cursor.fetchall.return_value = []
312+
mock_connection = MagicMock()
313+
mock_connection.execute.return_value = mock_cursor
314+
mock_db.connect.return_value = mock_connection
315+
316+
subject = MWLStorage(tmp_dir)
317+
mock_connection.reset_mock()
318+
319+
subject.find_worklist_items(scheduled_date="20240101 -")
320+
321+
mock_connection.execute.assert_called_once_with(
322+
(
323+
"SELECT accession_number, modality, patient_birth_date, patient_id, "
324+
"patient_name, patient_sex, procedure_code, scheduled_date, scheduled_time, "
325+
"source_message_id, study_description, study_instance_uid, status, mpps_instance_uid "
326+
"FROM worklist_items WHERE scheduled_date >= ? "
327+
"ORDER BY scheduled_date, scheduled_time"
328+
),
329+
["20240101"],
330+
)
331+
332+
mock_connection.reset_mock()
333+
334+
subject.find_worklist_items(scheduled_date="-20240101")
335+
336+
mock_connection.execute.assert_called_once_with(
337+
(
338+
"SELECT accession_number, modality, patient_birth_date, patient_id, "
339+
"patient_name, patient_sex, procedure_code, scheduled_date, scheduled_time, "
340+
"source_message_id, study_description, study_instance_uid, status, mpps_instance_uid "
341+
"FROM worklist_items WHERE scheduled_date <= ? "
342+
"ORDER BY scheduled_date, scheduled_time"
343+
),
344+
["20240101"],
345+
)
346+
286347
def test_get_worklist_item(self, mock_db, tmp_dir, result):
287348
mock_cursor = MagicMock()
288349
mock_cursor.fetchone.return_value = result

0 commit comments

Comments
 (0)