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 fastapi.responses import HTMLResponse
|
||||||
from html import escape as _html_escape
|
from html import escape as _html_escape
|
||||||
from pydantic import BaseModel, Field
|
from pydantic import BaseModel, Field
|
||||||
|
from sqlalchemy import text
|
||||||
from sqlalchemy.orm import Session, joinedload
|
from sqlalchemy.orm import Session, joinedload
|
||||||
from app.database import get_db
|
from app.database import get_db
|
||||||
from app.models import (
|
from app.models import (
|
||||||
@@ -351,9 +352,35 @@ def move_meal_item(
|
|||||||
)
|
)
|
||||||
|
|
||||||
if conflict:
|
if conflict:
|
||||||
# swap day/type
|
# Atomic swap via single SQL CASE statement — no intermediate
|
||||||
conflict.day_of_week = item.day_of_week
|
# unique-constraint violations.
|
||||||
conflict.meal_type = item.meal_type
|
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.day_of_week = new_day_of_week
|
||||||
item.meal_type = new_meal_type
|
item.meal_type = new_meal_type
|
||||||
|
|||||||
Reference in New Issue
Block a user