2023-10-27 15:12:48 +02:00
|
|
|
from sqlalchemy.orm import relationship, Mapped, mapped_column, joinedload
|
|
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
|
|
from sqlalchemy import ForeignKey, Integer, select
|
|
|
|
|
|
|
|
from .base import Base, CommonMixin
|
|
|
|
from .preset_entry import PresetEntry
|
|
|
|
from typing import AsyncIterator, Optional, TYPE_CHECKING
|
|
|
|
|
|
|
|
|
|
|
|
if TYPE_CHECKING:
|
|
|
|
from .meal import Meal
|
|
|
|
|
|
|
|
|
|
|
|
class Preset(Base, CommonMixin):
|
|
|
|
"""Preset."""
|
|
|
|
|
|
|
|
name: Mapped[str]
|
|
|
|
user_id: Mapped[int] = mapped_column(Integer, ForeignKey("user.id"))
|
|
|
|
entries: Mapped[list[PresetEntry]] = relationship(
|
|
|
|
lazy="selectin", order_by=PresetEntry.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)
|
|
|
|
|
|
|
|
@property
|
|
|
|
def fiber(self) -> float:
|
|
|
|
"""fiber.
|
|
|
|
|
|
|
|
:rtype: float
|
|
|
|
"""
|
|
|
|
return sum(entry.fiber for entry in self.entries)
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
async def create(
|
|
|
|
cls, session: AsyncSession, user_id: int, name: str, meal: "Meal"
|
2024-05-20 13:45:21 +02:00
|
|
|
) -> "Preset":
|
2023-10-27 15:12:48 +02:00
|
|
|
preset = Preset(user_id=user_id, name=name)
|
|
|
|
|
|
|
|
session.add(preset)
|
|
|
|
|
|
|
|
try:
|
|
|
|
await session.flush()
|
|
|
|
except Exception:
|
|
|
|
raise RuntimeError()
|
|
|
|
|
|
|
|
for entry in meal.entries:
|
2023-10-27 16:17:10 +02:00
|
|
|
await PresetEntry.create(session, preset.id, entry)
|
|
|
|
|
2024-05-20 13:45:21 +02:00
|
|
|
db_preset = await cls.get(session, user_id, preset.id)
|
|
|
|
|
|
|
|
if not db_preset:
|
|
|
|
raise RuntimeError()
|
|
|
|
|
|
|
|
return db_preset
|
2023-10-27 15:12:48 +02:00
|
|
|
|
|
|
|
@classmethod
|
|
|
|
async def list_all(
|
2023-10-27 17:19:20 +02:00
|
|
|
cls,
|
|
|
|
session: AsyncSession,
|
|
|
|
user_id: int,
|
|
|
|
offset: int,
|
|
|
|
limit: int,
|
|
|
|
q: Optional[str] = None,
|
2023-10-27 15:12:48 +02:00
|
|
|
) -> AsyncIterator["Preset"]:
|
2023-10-27 17:23:21 +02:00
|
|
|
query = select(cls).filter(cls.user_id == user_id)
|
2023-10-27 15:12:48 +02:00
|
|
|
|
|
|
|
if q:
|
2023-10-27 17:23:21 +02:00
|
|
|
query = query.filter(cls.name.ilike(f"%{q.lower()}%"))
|
2023-10-27 15:12:48 +02:00
|
|
|
|
|
|
|
query = query.offset(offset).limit(limit)
|
|
|
|
stream = await session.stream_scalars(query.order_by(cls.id))
|
|
|
|
async for row in stream:
|
|
|
|
yield row
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
async def get(
|
|
|
|
cls, session: AsyncSession, user_id: int, preset_id: int
|
|
|
|
) -> "Optional[Preset]":
|
|
|
|
"""get."""
|
|
|
|
query = (
|
|
|
|
select(cls)
|
|
|
|
.where(cls.id == preset_id)
|
|
|
|
.where(cls.user_id == user_id)
|
|
|
|
.options(joinedload(cls.entries).joinedload(PresetEntry.product))
|
|
|
|
)
|
|
|
|
return await session.scalar(query)
|
2023-10-27 16:49:19 +02:00
|
|
|
|
|
|
|
async def delete(self, session: AsyncSession) -> None:
|
|
|
|
for entry in self.entries:
|
|
|
|
await session.delete(entry)
|
|
|
|
await session.delete(self)
|
|
|
|
await session.flush()
|