2025-05-30 20:35:55 +00:00

210 lines
5.8 KiB
Python

"""
CalorieEntry service for managing calorie tracking operations
"""
from datetime import datetime, date, timedelta
from typing import Optional, List, Dict, Any, Union
from sqlalchemy import func
from sqlalchemy.orm import Session, joinedload
from app import models, schemas
def get(db: Session, entry_id: int) -> Optional[models.CalorieEntry]:
"""
Get a calorie entry by ID
"""
return (
db.query(models.CalorieEntry)
.filter(models.CalorieEntry.id == entry_id)
.options(joinedload(models.CalorieEntry.food))
.first()
)
def get_multi_by_user(
db: Session,
*,
user_id: int,
skip: int = 0,
limit: int = 100,
start_date: Optional[date] = None,
end_date: Optional[date] = None,
meal_type: Optional[str] = None,
) -> List[models.CalorieEntry]:
"""
Get multiple calorie entries for a specific user with optional filters
"""
query = (
db.query(models.CalorieEntry)
.filter(models.CalorieEntry.user_id == user_id)
.options(joinedload(models.CalorieEntry.food))
)
if start_date:
query = query.filter(
func.date(models.CalorieEntry.consumed_at) >= start_date
)
if end_date:
query = query.filter(
func.date(models.CalorieEntry.consumed_at) <= end_date
)
if meal_type:
query = query.filter(models.CalorieEntry.meal_type == meal_type)
return (
query.order_by(models.CalorieEntry.consumed_at.desc())
.offset(skip)
.limit(limit)
.all()
)
def get_daily_summary(
db: Session,
*,
user_id: int,
date_: date
) -> Dict[str, Any]:
"""
Get a summary of calories for a specific date
"""
start_datetime = datetime.combine(date_, datetime.min.time())
end_datetime = datetime.combine(date_, datetime.max.time())
entries = (
db.query(models.CalorieEntry)
.join(models.Food, models.CalorieEntry.food_id == models.Food.id)
.filter(models.CalorieEntry.user_id == user_id)
.filter(models.CalorieEntry.consumed_at >= start_datetime)
.filter(models.CalorieEntry.consumed_at <= end_datetime)
.options(joinedload(models.CalorieEntry.food))
.all()
)
# Calculate total calories and nutrients
total_calories = 0.0
total_protein = 0.0
total_carbs = 0.0
total_fat = 0.0
total_fiber = 0.0
meal_summary = {}
for entry in entries:
# Calculate calories for this entry
calories = entry.quantity_g / 100 * entry.food.calories_per_100g
total_calories += calories
# Calculate nutrients if available
if entry.food.protein_g:
total_protein += entry.quantity_g / 100 * entry.food.protein_g
if entry.food.carbs_g:
total_carbs += entry.quantity_g / 100 * entry.food.carbs_g
if entry.food.fat_g:
total_fat += entry.quantity_g / 100 * entry.food.fat_g
if entry.food.fiber_g:
total_fiber += entry.quantity_g / 100 * entry.food.fiber_g
# Add to meal summary
meal_type = entry.meal_type or "Other"
if meal_type not in meal_summary:
meal_summary[meal_type] = 0.0
meal_summary[meal_type] += calories
# Get user's target calories
user = db.query(models.User).filter(models.User.id == user_id).first()
target_calories = user.target_calories if user else 2000.0
return {
"date": date_,
"total_calories": round(total_calories, 1),
"target_calories": target_calories,
"remaining_calories": round(target_calories - total_calories, 1),
"total_protein_g": round(total_protein, 1),
"total_carbs_g": round(total_carbs, 1),
"total_fat_g": round(total_fat, 1),
"total_fiber_g": round(total_fiber, 1),
"meal_summary": {k: round(v, 1) for k, v in meal_summary.items()},
"entry_count": len(entries),
}
def create(
db: Session, *, obj_in: schemas.CalorieEntryCreate, user_id: int
) -> models.CalorieEntry:
"""
Create a new calorie entry
"""
db_obj = models.CalorieEntry(
user_id=user_id,
food_id=obj_in.food_id,
quantity_g=obj_in.quantity_g,
meal_type=obj_in.meal_type,
notes=obj_in.notes,
consumed_at=obj_in.consumed_at or datetime.utcnow(),
)
db.add(db_obj)
db.commit()
db.refresh(db_obj)
return db_obj
def update(
db: Session,
*,
db_obj: models.CalorieEntry,
obj_in: Union[schemas.CalorieEntryUpdate, Dict[str, Any]]
) -> models.CalorieEntry:
"""
Update a calorie entry
"""
if isinstance(obj_in, dict):
update_data = obj_in
else:
update_data = obj_in.model_dump(exclude_unset=True)
for field in update_data:
if hasattr(db_obj, field):
setattr(db_obj, field, update_data[field])
db.add(db_obj)
db.commit()
db.refresh(db_obj)
return db_obj
def delete(db: Session, *, entry_id: int) -> models.CalorieEntry:
"""
Delete a calorie entry
"""
entry = db.query(models.CalorieEntry).filter(models.CalorieEntry.id == entry_id).first()
db.delete(entry)
db.commit()
return entry
def get_weekly_summary(
db: Session,
*,
user_id: int,
end_date: date = None
) -> List[Dict[str, Any]]:
"""
Get a weekly summary of calories
"""
if end_date is None:
end_date = date.today()
start_date = end_date - timedelta(days=6) # Last 7 days
summaries = []
current_date = start_date
while current_date <= end_date:
daily_summary = get_daily_summary(db, user_id=user_id, date_=current_date)
summaries.append(daily_summary)
current_date += timedelta(days=1)
return summaries