Without cascade, SQLAlchemy tried to NULL-out foreign keys on child rows before deleting the parent, hitting NOT NULL constraints in PostgreSQL. - Routine.steps: cascade="all, delete-orphan" (routine_steps.routine_id) - MedicationEntry.usage_history: cascade="all, delete-orphan" (medication_usages.medication_record_id) Product.inventory already had cascade set correctly. No DB migration needed — ORM-level only. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
73 lines
2.4 KiB
Python
73 lines
2.4 KiB
Python
from datetime import date, datetime
|
|
from typing import TYPE_CHECKING, ClassVar, List, Optional
|
|
from uuid import UUID, uuid4
|
|
|
|
from sqlalchemy import Column, DateTime, UniqueConstraint
|
|
from sqlmodel import Field, Relationship, SQLModel
|
|
|
|
from .base import utc_now
|
|
from .domain import Domain
|
|
from .enums import GroomingAction, PartOfDay
|
|
|
|
if TYPE_CHECKING:
|
|
from .product import Product
|
|
|
|
|
|
class Routine(SQLModel, table=True):
|
|
__tablename__ = "routines"
|
|
__domains__: ClassVar[frozenset[Domain]] = frozenset({Domain.SKINCARE})
|
|
__table_args__ = (
|
|
UniqueConstraint(
|
|
"routine_date", "part_of_day", name="uq_routine_date_part_of_day"
|
|
),
|
|
)
|
|
|
|
id: UUID = Field(default_factory=uuid4, primary_key=True)
|
|
routine_date: date = Field(index=True)
|
|
part_of_day: PartOfDay = Field(index=True)
|
|
notes: str | None = Field(default=None)
|
|
|
|
created_at: datetime = Field(default_factory=utc_now, nullable=False)
|
|
updated_at: datetime = Field(
|
|
default_factory=utc_now,
|
|
sa_column=Column(
|
|
DateTime(timezone=True),
|
|
default=utc_now,
|
|
onupdate=utc_now,
|
|
nullable=False,
|
|
),
|
|
)
|
|
|
|
steps: List["RoutineStep"] = Relationship(
|
|
back_populates="routine",
|
|
sa_relationship_kwargs={"cascade": "all, delete-orphan"},
|
|
)
|
|
|
|
|
|
class GroomingSchedule(SQLModel, table=True):
|
|
__tablename__ = "grooming_schedule"
|
|
__domains__: ClassVar[frozenset[Domain]] = frozenset({Domain.SKINCARE})
|
|
|
|
id: UUID = Field(default_factory=uuid4, primary_key=True)
|
|
day_of_week: int = Field(ge=0, le=6, index=True) # 0 = poniedziałek, 6 = niedziela
|
|
action: GroomingAction
|
|
notes: str | None = Field(default=None)
|
|
|
|
|
|
class RoutineStep(SQLModel, table=True):
|
|
__tablename__ = "routine_steps"
|
|
__domains__: ClassVar[frozenset[Domain]] = frozenset({Domain.SKINCARE})
|
|
|
|
id: UUID = Field(default_factory=uuid4, primary_key=True)
|
|
routine_id: UUID = Field(foreign_key="routines.id", index=True)
|
|
product_id: UUID | None = Field(default=None, foreign_key="products.id", index=True)
|
|
order_index: int = Field(ge=0)
|
|
|
|
action_type: GroomingAction | None = Field(default=None)
|
|
action_notes: str | None = Field(default=None)
|
|
|
|
dose: str | None = Field(default=None)
|
|
region: str | None = Field(default=None)
|
|
|
|
routine: Routine = Relationship(back_populates="steps")
|
|
product: Optional["Product"] = Relationship()
|