87 lines
2.6 KiB
Python
87 lines
2.6 KiB
Python
from datetime import datetime
|
|
|
|
from sqlalchemy import DateTime
|
|
from sqlalchemy.orm import DeclarativeBase, Mapped, declared_attr, mapped_column
|
|
|
|
from fooder.utils.datetime import utc_now
|
|
from fooder.utils.password_helper import password_helper
|
|
|
|
|
|
class Base(DeclarativeBase):
|
|
pass
|
|
|
|
|
|
class CommonMixin:
|
|
@declared_attr.directive
|
|
def __tablename__(cls) -> str:
|
|
return cls.__name__.lower() # type: ignore
|
|
|
|
id: Mapped[int] = mapped_column(primary_key=True)
|
|
created_at: Mapped[datetime] = mapped_column(DateTime, default=utc_now)
|
|
last_changed: Mapped[datetime] = mapped_column(DateTime, default=utc_now, onupdate=utc_now)
|
|
|
|
|
|
class SoftDeleteMixin:
|
|
deleted_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True, default=None)
|
|
|
|
|
|
class PasswordMixin:
|
|
hashed_password: Mapped[str]
|
|
|
|
def set_password(self, password: str) -> None:
|
|
self.hashed_password = password_helper.hash(password)
|
|
|
|
def verify_password(self, password: str) -> bool:
|
|
return password_helper.verify(password, self.hashed_password)
|
|
|
|
|
|
class EntryMacrosMixin:
|
|
"""Computed macros for entry-like models that scale product macros by grams."""
|
|
|
|
@property
|
|
def amount(self) -> float:
|
|
return self.grams / 100 # type: ignore[attr-defined]
|
|
|
|
@property
|
|
def calories(self) -> float:
|
|
return self.amount * self.product.calories # type: ignore[attr-defined]
|
|
|
|
@property
|
|
def protein(self) -> float:
|
|
return self.amount * self.product.protein # type: ignore[attr-defined]
|
|
|
|
@property
|
|
def carb(self) -> float:
|
|
return self.amount * self.product.carb # type: ignore[attr-defined]
|
|
|
|
@property
|
|
def fat(self) -> float:
|
|
return self.amount * self.product.fat # type: ignore[attr-defined]
|
|
|
|
@property
|
|
def fiber(self) -> float:
|
|
return self.amount * self.product.fiber # type: ignore[attr-defined]
|
|
|
|
|
|
class AggregateMacrosMixin:
|
|
"""Computed macros for models that sum macros across child entries."""
|
|
|
|
@property
|
|
def calories(self) -> float:
|
|
return sum(e.calories for e in self.entries) # type: ignore[attr-defined]
|
|
|
|
@property
|
|
def protein(self) -> float:
|
|
return sum(e.protein for e in self.entries) # type: ignore[attr-defined]
|
|
|
|
@property
|
|
def carb(self) -> float:
|
|
return sum(e.carb for e in self.entries) # type: ignore[attr-defined]
|
|
|
|
@property
|
|
def fat(self) -> float:
|
|
return sum(e.fat for e in self.entries) # type: ignore[attr-defined]
|
|
|
|
@property
|
|
def fiber(self) -> float:
|
|
return sum(e.fiber for e in self.entries) # type: ignore[attr-defined]
|