Public Access
fix: atomic SQL swap for meal move endpoint
Replace two-step ORM update with single UPDATE ... CASE statement. Eliminates IntegrityError from SQLAlchemy flush order violating the unique constraint (meal_plan_id, day_of_week, meal_type).
This commit is contained in:
@@ -2,6 +2,7 @@ from fastapi import APIRouter, Depends, HTTPException, Query
|
||||
from fastapi.responses import HTMLResponse
|
||||
from html import escape as _html_escape
|
||||
from pydantic import BaseModel, Field
|
||||
from sqlalchemy import text
|
||||
from sqlalchemy.orm import Session, joinedload
|
||||
from app.database import get_db
|
||||
from app.models import (
|
||||
@@ -351,9 +352,35 @@ def move_meal_item(
|
||||
)
|
||||
|
||||
if conflict:
|
||||
# swap day/type
|
||||
conflict.day_of_week = item.day_of_week
|
||||
conflict.meal_type = item.meal_type
|
||||
# Atomic swap via single SQL CASE statement — no intermediate
|
||||
# unique-constraint violations.
|
||||
db.execute(
|
||||
text(
|
||||
"""
|
||||
UPDATE meal_plan_item
|
||||
SET day_of_week = CASE
|
||||
WHEN id = :item_id THEN :new_day
|
||||
WHEN id = :conflict_id THEN :old_day
|
||||
END,
|
||||
meal_type = CASE
|
||||
WHEN id = :item_id THEN :new_type
|
||||
WHEN id = :conflict_id THEN :old_type
|
||||
END
|
||||
WHERE id IN (:item_id, :conflict_id)
|
||||
"""
|
||||
),
|
||||
{
|
||||
"item_id": str(item_id),
|
||||
"conflict_id": str(conflict.id),
|
||||
"new_day": new_day_of_week,
|
||||
"new_type": new_meal_type,
|
||||
"old_day": item.day_of_week,
|
||||
"old_type": item.meal_type,
|
||||
},
|
||||
)
|
||||
db.commit()
|
||||
db.refresh(item)
|
||||
return {"message": "Meal swapped", "item": item}
|
||||
|
||||
item.day_of_week = new_day_of_week
|
||||
item.meal_type = new_meal_type
|
||||
|
||||
Reference in New Issue
Block a user