Add example scripts and enhance puck event queries

Introduced a new Jupyter Notebook with API usage examples for managing pucks and samples. Refactored puck retrieval logic to include the latest event type and `tell_position`, improving data accuracy. Updated backend version to 0.1.0a16 accordingly.
This commit is contained in:
GotthardG
2025-01-09 16:56:38 +01:00
parent 9bfcc30981
commit c45a46b07b
3 changed files with 276 additions and 29 deletions

View File

@ -271,7 +271,8 @@ async def get_last_tell_position(puck_id: str, db: Session = Depends(get_db)):
@router.get("/slot/{slot_identifier}", response_model=List[PuckWithTellPosition])
async def get_pucks_by_slot(slot_identifier: str, db: Session = Depends(get_db)):
"""
Retrieve all pucks in a slot with their latest `tell_position`.
Retrieve all pucks in a slot, reporting their latest event and
`tell_position` value.
"""
# Map keywords to slot IDs
slot_aliases = {
@ -328,50 +329,64 @@ async def get_pucks_by_slot(slot_identifier: str, db: Session = Depends(get_db))
dewar_ids = [dewar.id for dewar in dewars]
dewar_map = {dewar.id: dewar.dewar_name for dewar in dewars}
# Subquery to fetch the latest tell_position for each puck
subquery = (
# Subquery to fetch the latest event for each puck (any type of event)
latest_event_subquery = (
db.query(
PuckEventModel.puck_id,
PuckEventModel.puck_id.label("puck_id"),
func.max(PuckEventModel.timestamp).label("latest_event_time"),
)
.filter(PuckEventModel.event_type == "tell_position_set")
.group_by(PuckEventModel.puck_id)
.subquery()
.subquery(name="latest_event_subquery") # Explicitly name the subquery
)
# Fetch pucks with their latest tell_position
pucks_with_positions = (
db.query(PuckModel, PuckEventModel.tell_position)
.outerjoin(subquery, subquery.c.puck_id == PuckModel.id)
.outerjoin(
PuckEventModel,
(PuckEventModel.puck_id == PuckModel.id)
& (PuckEventModel.timestamp == subquery.c.latest_event_time),
# Main query to fetch pucks and their latest events
pucks_with_latest_events = (
db.query(
PuckModel,
PuckEventModel.event_type,
PuckEventModel.tell_position,
)
.filter(PuckModel.dewar_id.in_(dewar_ids))
.join( # Join pucks with the latest event
# (outer join to include pucks without events)
latest_event_subquery,
PuckModel.id == latest_event_subquery.c.puck_id,
isouter=True,
)
.join( # Fetch event details from the latest event timestamp
PuckEventModel,
(PuckEventModel.puck_id == latest_event_subquery.c.puck_id)
& (PuckEventModel.timestamp == latest_event_subquery.c.latest_event_time),
isouter=True,
)
.filter(PuckModel.dewar_id.in_(dewar_ids)) # Restrict pucks to relevant dewars
.all()
)
# Log the results of the subquery and pucks fetched:
logger.debug(f"Results from subquery (tell_position): {pucks_with_positions}")
# Log the results of the query
logger.debug(f"Results from query (latest events): {pucks_with_latest_events}")
if not pucks_with_positions:
if not pucks_with_latest_events:
logger.warning(f"No pucks found for slot: {slot_identifier}")
raise HTTPException(
status_code=404, detail=f"No pucks found for slot '{slot_identifier}'"
status_code=404, detail=f"No pucks found for slot {slot_identifier}"
)
# Prepare results:
# Prepare the final response
results = []
for puck, tell_position in pucks_with_positions:
for puck, event_type, tell_position in pucks_with_latest_events:
logger.debug(
f"Puck ID: {puck.id}, Name: {puck.puck_name},"
f" Tell Position: {tell_position}"
f"Puck ID: {puck.id}, Name: {puck.puck_name}, Event Type: {event_type}, "
f"Tell Position: {tell_position}"
)
dewar_name = dewar_map.get(puck.dewar_id, "Unknown")
# Prepare the PuckWithTellPosition instance
# For pucks with no events or whose latest event is `puck_removed`, set
# `tell_position` to None
if event_type is None or event_type == "puck_removed":
tell_position = None
# Construct the response model
results.append(
PuckWithTellPosition(
id=puck.id,
@ -382,11 +397,11 @@ async def get_pucks_by_slot(slot_identifier: str, db: Session = Depends(get_db))
else None,
dewar_id=puck.dewar_id,
dewar_name=dewar_name,
tell_position=tell_position, # Latest tell_position from subquery
tell_position=tell_position,
)
)
logger.info(f"Final response prepared for slot {slot_identifier}: {results}")
logger.info(f"Final response for slot {slot_identifier}: {results}")
return results
@ -396,8 +411,7 @@ async def get_pucks_with_tell_position(db: Session = Depends(get_db)):
Retrieve all pucks with a `tell_position` set (not null),
their associated samples, and the latest `tell_position` value (if any).
"""
# Query pucks with their latest `tell_position_set` event where
# `tell_position` is not null
pucks_with_events = (
db.query(PuckModel, PuckEventModel)
.join(PuckEventModel, PuckModel.id == PuckEventModel.puck_id)