Skip to content

Commit 3c34d31

Browse files
fix: PostgreSQL compatibility in jobs.py
- Use adapter.interval_expr() for INTERVAL expressions - Use single quotes for string literals in WHERE clauses (PostgreSQL interprets double quotes as column identifiers) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 97db517 commit 3c34d31

File tree

1 file changed

+12
-9
lines changed

1 file changed

+12
-9
lines changed

src/datajoint/jobs.py

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -249,7 +249,7 @@ def pending(self) -> "Job":
249249
Job
250250
Restricted query with ``status='pending'``.
251251
"""
252-
return self & 'status="pending"'
252+
return self & "status='pending'"
253253

254254
@property
255255
def reserved(self) -> "Job":
@@ -261,7 +261,7 @@ def reserved(self) -> "Job":
261261
Job
262262
Restricted query with ``status='reserved'``.
263263
"""
264-
return self & 'status="reserved"'
264+
return self & "status='reserved'"
265265

266266
@property
267267
def errors(self) -> "Job":
@@ -273,7 +273,7 @@ def errors(self) -> "Job":
273273
Job
274274
Restricted query with ``status='error'``.
275275
"""
276-
return self & 'status="error"'
276+
return self & "status='error'"
277277

278278
@property
279279
def ignored(self) -> "Job":
@@ -285,7 +285,7 @@ def ignored(self) -> "Job":
285285
Job
286286
Restricted query with ``status='ignore'``.
287287
"""
288-
return self & 'status="ignore"'
288+
return self & "status='ignore'"
289289

290290
@property
291291
def completed(self) -> "Job":
@@ -297,7 +297,7 @@ def completed(self) -> "Job":
297297
Job
298298
Restricted query with ``status='success'``.
299299
"""
300-
return self & 'status="success"'
300+
return self & "status='success'"
301301

302302
# -------------------------------------------------------------------------
303303
# Core job management methods
@@ -376,7 +376,8 @@ def refresh(
376376

377377
if new_key_list:
378378
# Use server time for scheduling (CURRENT_TIMESTAMP(3) matches datetime(3) precision)
379-
scheduled_time = self.connection.query(f"SELECT CURRENT_TIMESTAMP(3) + INTERVAL {delay} SECOND").fetchone()[0]
379+
interval_expr = self.adapter.interval_expr(delay, "second")
380+
scheduled_time = self.connection.query(f"SELECT CURRENT_TIMESTAMP(3) + {interval_expr}").fetchone()[0]
380381

381382
for key in new_key_list:
382383
job_entry = {
@@ -404,7 +405,8 @@ def refresh(
404405

405406
# 3. Remove stale jobs (not ignore status) - use server CURRENT_TIMESTAMP for consistent timing
406407
if stale_timeout > 0:
407-
old_jobs = self & f"created_time < CURRENT_TIMESTAMP - INTERVAL {stale_timeout} SECOND" & 'status != "ignore"'
408+
stale_interval = self.adapter.interval_expr(stale_timeout, "second")
409+
old_jobs = self & f"created_time < CURRENT_TIMESTAMP - {stale_interval}" & "status != 'ignore'"
408410

409411
for key in old_jobs.keys():
410412
# Check if key still in key_source
@@ -414,7 +416,8 @@ def refresh(
414416

415417
# 4. Handle orphaned reserved jobs - use server CURRENT_TIMESTAMP for consistent timing
416418
if orphan_timeout is not None and orphan_timeout > 0:
417-
orphaned_jobs = self.reserved & f"reserved_time < CURRENT_TIMESTAMP - INTERVAL {orphan_timeout} SECOND"
419+
orphan_interval = self.adapter.interval_expr(orphan_timeout, "second")
420+
orphaned_jobs = self.reserved & f"reserved_time < CURRENT_TIMESTAMP - {orphan_interval}"
418421

419422
for key in orphaned_jobs.keys():
420423
(self & key).delete_quick()
@@ -441,7 +444,7 @@ def reserve(self, key: dict) -> bool:
441444
True if reservation successful, False if job not available.
442445
"""
443446
# Check if job is pending and scheduled (use CURRENT_TIMESTAMP(3) for datetime(3) precision)
444-
job = (self & key & 'status="pending"' & "scheduled_time <= CURRENT_TIMESTAMP(3)").to_dicts()
447+
job = (self & key & "status='pending'" & "scheduled_time <= CURRENT_TIMESTAMP(3)").to_dicts()
445448

446449
if not job:
447450
return False

0 commit comments

Comments
 (0)