Refactor puck event handling and add tell filtering

Updated puck event queries to improve robustness and ensure distinct results. Introduced filtering by `tell` in specific API endpoints and added validation for `tell` values. Incremented project version to 0.1.0a21 to reflect API changes.
This commit is contained in:
GotthardG 2025-02-04 17:07:25 +01:00
parent 780ba1959f
commit 9e5ae2b43c
2 changed files with 46 additions and 30 deletions

View File

@ -145,6 +145,7 @@ def get_pucks_at_beamline(slot_id: int, db: Session) -> List[PuckWithTellPositio
PuckModel,
PuckEventModel.event_type,
PuckEventModel.tell_position,
PuckEventModel.timestamp, # Useful for debugging or edge cases
DewarModel,
)
.join(
@ -163,36 +164,41 @@ def get_pucks_at_beamline(slot_id: int, db: Session) -> List[PuckWithTellPositio
)
.join(DewarModel, PuckModel.dewar_id == DewarModel.id, isouter=True)
.filter(PuckModel.dewar_id.in_(dewar_ids))
.distinct() # Ensure no duplicates
.all()
)
# Prepare the results
results = []
for puck, event_type, tell_position, dewar in pucks_with_latest_events:
dewar_name = dewar_map.get(puck.dewar_id, "Unknown")
results = {}
for (
puck,
event_type,
tell_position,
event_timestamp,
dewar,
) in pucks_with_latest_events:
dewar_name = dewar_map.get(puck.dewar_id)
pgroup = dewar_pgroups.get(puck.dewar_id)
# For pucks with no events or whose latest event is "puck_removed", set
# tell_position to None
# If the event is None or explicitly a "puck_removed", set `tell_position=None`
if event_type is None or event_type == "puck_removed":
tell_position = None
results.append(
PuckWithTellPosition(
id=puck.id,
pgroup=pgroup,
puck_name=puck.puck_name,
puck_type=puck.puck_type,
puck_location_in_dewar=int(puck.puck_location_in_dewar)
if puck.puck_location_in_dewar
else None,
dewar_id=puck.dewar_id,
dewar_name=dewar_name,
tell_position=tell_position,
)
# Always replace results since we are processing the latest event
results[puck.id] = PuckWithTellPosition(
id=puck.id,
pgroup=pgroup,
puck_name=puck.puck_name,
puck_type=puck.puck_type,
puck_location_in_dewar=int(puck.puck_location_in_dewar)
if puck.puck_location_in_dewar
else None,
dewar_id=puck.dewar_id,
dewar_name=dewar_name,
tell_position=tell_position, # Respect if `None` is explicitly set
)
return results
return list(results.values())
@router.get("/", response_model=List[PuckSchema])
@ -269,7 +275,7 @@ async def set_tell_positions(
tell=None, # Nullify the `tell` for removal
tell_position=None,
event_type="puck_removed",
timestamp=datetime.utcnow(),
timestamp=datetime.now(),
)
db.add(remove_event)
@ -309,9 +315,8 @@ async def set_tell_positions(
puck.id: db.query(PuckEventModel)
.filter(
PuckEventModel.puck_id == puck.id,
PuckEventModel.event_type == "tell_position_set",
)
.order_by(PuckEventModel.timestamp.desc())
.order_by(PuckEventModel.id.desc())
.first()
for puck in pucks_at_beamline
}
@ -358,7 +363,7 @@ async def set_tell_positions(
tell=None,
tell_position=None,
event_type="puck_removed",
timestamp=datetime.utcnow(),
timestamp=datetime.now(),
)
db.add(remove_event)
@ -368,7 +373,7 @@ async def set_tell_positions(
tell=tell,
tell_position=new_position,
event_type="tell_position_set",
timestamp=datetime.utcnow(),
timestamp=datetime.now(),
)
db.add(new_event)
@ -409,7 +414,7 @@ async def set_tell_positions(
tell=None,
tell_position=None,
event_type="puck_removed",
timestamp=datetime.utcnow(),
timestamp=datetime.now(),
)
db.add(remove_event)
results.append(
@ -436,13 +441,23 @@ async def set_tell_positions(
@router.get("/with-tell-position", response_model=List[PuckWithTellPosition])
async def get_pucks_with_tell_position(db: Session = Depends(get_db)):
async def get_pucks_with_tell_position(
tell: str, # Specify tell as a query parameter
db: Session = Depends(get_db),
):
"""
Retrieve all pucks with a valid `tell_position` set (non-null),
their associated samples, and the latest `tell_position` value (if any).
Only include pucks when their latest event has a `tell_position`
set and an `event_type` matching "tell_position_set".
their associated samples, and the latest `tell_position` value (if any),
filtered by a specific `tell`.
"""
# Validate the incoming `tell` value
try:
validate_tell(tell) # Ensure `tell` is valid using predefined valid options
except ValueError as error:
raise HTTPException(
status_code=400, detail=str(error)
) # Raise error for invalid tells
# Step 1: Prepare a subquery to fetch the latest event timestamp for each puck.
latest_event_subquery = (
db.query(
@ -471,6 +486,7 @@ async def get_pucks_with_tell_position(db: Session = Depends(get_db)):
.filter(
PuckEventModel.event_type == "tell_position_set"
) # Only include relevant event types
.filter(PuckEventModel.tell == tell) # Filter by the specific `tell` variable
.all()
)

View File

@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project]
name = "aareDB"
version = "0.1.0a20"
version = "0.1.0a21"
description = "Backend for next gen sample management system"
authors = [{name = "Guillaume Gotthard", email = "guillaume.gotthard@psi.ch"}]
license = {text = "MIT"}