fooder-api/fooder/domain/meal.py

84 lines
2.3 KiB
Python

from sqlalchemy.orm import relationship, Mapped, mapped_column, joinedload
from sqlalchemy import ForeignKey, Integer
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.exc import IntegrityError
from typing import Optional
from .base import Base, CommonMixin
from .entry import Entry
class Meal(Base, CommonMixin):
"""Meal."""
name: Mapped[str]
order: Mapped[int]
diary_id: Mapped[int] = mapped_column(Integer, ForeignKey("diary.id"))
entries: Mapped[list[Entry]] = relationship(lazy="selectin", order_by=Entry.last_changed)
@property
def calories(self) -> float:
"""calories.
:rtype: float
"""
return sum(entry.calories for entry in self.entries)
@property
def protein(self) -> float:
"""protein.
:rtype: float
"""
return sum(entry.protein for entry in self.entries)
@property
def carb(self) -> float:
"""carb.
:rtype: float
"""
return sum(entry.carb for entry in self.entries)
@property
def fat(self) -> float:
"""fat.
:rtype: float
"""
return sum(entry.fat for entry in self.entries)
@classmethod
async def create(
cls,
session: AsyncSession,
diary_id: int,
order: int = 0,
name: Optional[str] = None,
) -> "Meal":
# check if order already exists in diary
query = select(cls).where(cls.diary_id == diary_id).where(cls.order == order)
existing_meal = await session.scalar(query)
assert existing_meal is None, "order already exists in diary"
if name is None:
name = f"Meal {order}"
meal = Meal(diary_id=diary_id, name=name, order=order)
session.add(meal)
try:
await session.flush()
except IntegrityError:
raise AssertionError("diary does not exist")
meal = await cls.get_by_id(session, meal.id)
if not meal:
raise RuntimeError()
return meal
@classmethod
async def get_by_id(cls, session: AsyncSession, id: int) -> "Optional[Meal]":
"""get_by_id."""
query = select(cls).where(cls.id == id).options(joinedload(cls.entries))
return await session.scalar(query.order_by(cls.id))