FastAPI backend for personal health and skincare data with MCP export. Includes SQLModel models for products, inventory, medications, lab results, routines, and skin condition snapshots. Pytest suite with 111 tests running on SQLite in-memory (no PostgreSQL required). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
113 lines
3.7 KiB
Python
113 lines
3.7 KiB
Python
from datetime import datetime
|
|
from typing import ClassVar
|
|
from uuid import UUID, uuid4
|
|
|
|
from sqlalchemy import Column, DateTime
|
|
from sqlmodel import Field, Relationship, SQLModel
|
|
|
|
from .base import utc_now
|
|
from .domain import Domain
|
|
from .enums import MedicationKind, ResultFlag
|
|
|
|
|
|
class MedicationEntry(SQLModel, table=True):
|
|
__tablename__ = "medication_entries"
|
|
__domains__: ClassVar[frozenset[Domain]] = frozenset({Domain.HEALTH})
|
|
|
|
record_id: UUID = Field(default_factory=uuid4, primary_key=True)
|
|
|
|
kind: MedicationKind = Field(index=True)
|
|
|
|
product_name: str = Field(index=True)
|
|
active_substance: str | None = Field(default=None, index=True)
|
|
formulation: str | None = Field(default=None)
|
|
route: str | None = Field(default=None)
|
|
source_file: str | None = Field(default=None)
|
|
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,
|
|
),
|
|
)
|
|
|
|
usage_history: list["MedicationUsage"] = Relationship(back_populates="medication")
|
|
|
|
|
|
class MedicationUsage(SQLModel, table=True):
|
|
__tablename__ = "medication_usages"
|
|
__domains__: ClassVar[frozenset[Domain]] = frozenset({Domain.HEALTH})
|
|
|
|
record_id: UUID = Field(default_factory=uuid4, primary_key=True)
|
|
medication_record_id: UUID = Field(
|
|
foreign_key="medication_entries.record_id", index=True
|
|
)
|
|
|
|
dose_value: float | None = Field(default=None, ge=0)
|
|
dose_unit: str | None = Field(default=None)
|
|
frequency: str | None = Field(default=None)
|
|
schedule_text: str | None = Field(default=None)
|
|
as_needed: bool = Field(default=False, index=True)
|
|
|
|
valid_from: datetime = Field(index=True)
|
|
valid_to: datetime | None = Field(default=None, index=True)
|
|
|
|
source_file: str | None = Field(default=None)
|
|
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,
|
|
),
|
|
)
|
|
|
|
medication: MedicationEntry = Relationship(back_populates="usage_history")
|
|
|
|
|
|
class LabResult(SQLModel, table=True):
|
|
__tablename__ = "lab_results"
|
|
__domains__: ClassVar[frozenset[Domain]] = frozenset({Domain.HEALTH})
|
|
|
|
record_id: UUID = Field(default_factory=uuid4, primary_key=True)
|
|
|
|
collected_at: datetime = Field(index=True)
|
|
test_code: str = Field(index=True, regex=r"^\d+-\d$")
|
|
test_name_original: str | None = Field(default=None)
|
|
test_name_loinc: str | None = Field(default=None)
|
|
|
|
value_num: float | None = Field(default=None)
|
|
value_text: str | None = Field(default=None)
|
|
value_bool: bool | None = Field(default=None)
|
|
|
|
unit_original: str | None = Field(default=None)
|
|
unit_ucum: str | None = Field(default=None)
|
|
|
|
ref_low: float | None = Field(default=None)
|
|
ref_high: float | None = Field(default=None)
|
|
ref_text: str | None = Field(default=None)
|
|
flag: ResultFlag | None = Field(default=None, index=True)
|
|
|
|
lab: str | None = Field(default=None, index=True)
|
|
source_file: str | None = Field(default=None)
|
|
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,
|
|
),
|
|
)
|