TICKET-007 (backend): meals — from-log, unpack, components, recursive nutrition, cycle detection
This commit is contained in:
@@ -2,6 +2,9 @@
|
||||
|
||||
ORM objects never leave this module; functions return Pydantic schemas.
|
||||
Handlers stay thin (~15 lines) by calling into these functions.
|
||||
|
||||
Meal foods are returned as MealRead (with components + computed nutrition)
|
||||
via get_meal(). get_food() returns the appropriate type based on is_meal.
|
||||
"""
|
||||
|
||||
from datetime import datetime, timezone
|
||||
@@ -10,7 +13,8 @@ from sqlalchemy import desc, func, select
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from models import DailyLogEntry, Food
|
||||
from schemas import FoodCreate, FoodRead, FoodUpdate
|
||||
from schemas import FoodCreate, FoodRead, FoodUpdate, MealRead
|
||||
from services.meals import _build_meal_read, load_meal_with_components
|
||||
|
||||
|
||||
# ── Shared query helpers (§8.1 rule 7) ───────────────────────────────────────
|
||||
@@ -56,13 +60,32 @@ def list_foods(
|
||||
return [FoodRead.model_validate(f) for f in foods]
|
||||
|
||||
|
||||
def get_food(db: Session, food_id: int) -> FoodRead | None:
|
||||
def get_food(db: Session, food_id: int) -> FoodRead | MealRead | None:
|
||||
"""Get a single food by id. INCLUDES soft-deleted foods (historical log
|
||||
rendering depends on this — spec §2.1). Returns None for unknown id."""
|
||||
food = db.get(Food, food_id)
|
||||
rendering depends on this — spec §2.1).
|
||||
|
||||
Returns MealRead (with components + computed nutrition) for meal foods,
|
||||
plain FoodRead for non-meals. Returns None for unknown id.
|
||||
"""
|
||||
food = load_meal_with_components(db, food_id)
|
||||
if food is None:
|
||||
# Not a meal — try as a plain food
|
||||
food = db.get(Food, food_id)
|
||||
if food is None:
|
||||
return None
|
||||
return FoodRead.model_validate(food)
|
||||
# Meal food: return MealRead with components
|
||||
return _build_meal_read(food)
|
||||
|
||||
|
||||
def get_meal(db: Session, meal_id: int) -> MealRead | None:
|
||||
"""Get a meal food with components and computed nutrition.
|
||||
|
||||
Returns None if the food doesn't exist or is not a meal."""
|
||||
meal = load_meal_with_components(db, meal_id)
|
||||
if meal is None:
|
||||
return None
|
||||
return FoodRead.model_validate(food)
|
||||
return _build_meal_read(meal)
|
||||
|
||||
|
||||
def create_food(db: Session, data: FoodCreate) -> FoodRead:
|
||||
|
||||
Reference in New Issue
Block a user