refactor: split table models into Base/Table/Public for proper FastAPI serialization
Add ProductBase, ProductPublic, ProductWithInventory and SkinConditionSnapshotBase, SkinConditionSnapshotPublic. Table models now inherit from their Base counterpart and override JSON fields with sa_column. All field_serializer hacks removed; FastAPI response models use the non-table Public classes so Pydantic coerces raw DB dicts → typed models cleanly. ProductCreate and SnapshotCreate now simply inherit their respective Base classes. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
479be25112
commit
c09acc7c81
15 changed files with 225 additions and 198 deletions
|
|
@ -1,6 +1,5 @@
|
|||
import uuid
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Medications
|
||||
# ---------------------------------------------------------------------------
|
||||
|
|
@ -32,9 +31,7 @@ def test_list_filter_kind(client):
|
|||
client.post(
|
||||
"/health/medications", json={"kind": "prescription", "product_name": "A"}
|
||||
)
|
||||
client.post(
|
||||
"/health/medications", json={"kind": "supplement", "product_name": "B"}
|
||||
)
|
||||
client.post("/health/medications", json={"kind": "supplement", "product_name": "B"})
|
||||
r = client.get("/health/medications?kind=supplement")
|
||||
assert r.status_code == 200
|
||||
data = r.json()
|
||||
|
|
@ -46,9 +43,7 @@ def test_list_filter_product_name(client):
|
|||
client.post(
|
||||
"/health/medications", json={"kind": "otc", "product_name": "Epiduo Forte"}
|
||||
)
|
||||
client.post(
|
||||
"/health/medications", json={"kind": "otc", "product_name": "Panoxyl"}
|
||||
)
|
||||
client.post("/health/medications", json={"kind": "otc", "product_name": "Panoxyl"})
|
||||
r = client.get("/health/medications?product_name=epid")
|
||||
assert r.status_code == 200
|
||||
data = r.json()
|
||||
|
|
@ -113,7 +108,11 @@ def test_create_usage(client, created_medication):
|
|||
mid = created_medication["record_id"]
|
||||
r = client.post(
|
||||
f"/health/medications/{mid}/usages",
|
||||
json={"valid_from": "2026-01-01T08:00:00", "dose_value": 1.0, "dose_unit": "pea"},
|
||||
json={
|
||||
"valid_from": "2026-01-01T08:00:00",
|
||||
"dose_value": 1.0,
|
||||
"dose_unit": "pea",
|
||||
},
|
||||
)
|
||||
assert r.status_code == 201
|
||||
data = r.json()
|
||||
|
|
@ -156,7 +155,9 @@ def test_update_usage(client, created_medication):
|
|||
)
|
||||
uid = r.json()["record_id"]
|
||||
|
||||
r2 = client.patch(f"/health/usages/{uid}", json={"dose_value": 2.5, "dose_unit": "mg"})
|
||||
r2 = client.patch(
|
||||
f"/health/usages/{uid}", json={"dose_value": 2.5, "dose_unit": "mg"}
|
||||
)
|
||||
assert r2.status_code == 200
|
||||
assert r2.json()["dose_value"] == 2.5
|
||||
assert r2.json()["dose_unit"] == "mg"
|
||||
|
|
@ -247,8 +248,14 @@ def test_list_filter_flag(client):
|
|||
|
||||
|
||||
def test_list_filter_date_range(client):
|
||||
client.post("/health/lab-results", json={**LAB_RESULT_DATA, "collected_at": "2026-01-01T00:00:00"})
|
||||
client.post("/health/lab-results", json={**LAB_RESULT_DATA, "collected_at": "2026-06-01T00:00:00"})
|
||||
client.post(
|
||||
"/health/lab-results",
|
||||
json={**LAB_RESULT_DATA, "collected_at": "2026-01-01T00:00:00"},
|
||||
)
|
||||
client.post(
|
||||
"/health/lab-results",
|
||||
json={**LAB_RESULT_DATA, "collected_at": "2026-06-01T00:00:00"},
|
||||
)
|
||||
r = client.get("/health/lab-results?from_date=2026-05-01T00:00:00")
|
||||
assert r.status_code == 200
|
||||
data = r.json()
|
||||
|
|
@ -271,7 +278,9 @@ def test_get_lab_result_not_found(client):
|
|||
def test_update_lab_result(client):
|
||||
r = client.post("/health/lab-results", json=LAB_RESULT_DATA)
|
||||
rid = r.json()["record_id"]
|
||||
r2 = client.patch(f"/health/lab-results/{rid}", json={"notes": "Recheck in 3 months"})
|
||||
r2 = client.patch(
|
||||
f"/health/lab-results/{rid}", json={"notes": "Recheck in 3 months"}
|
||||
)
|
||||
assert r2.status_code == 200
|
||||
assert r2.json()["notes"] == "Recheck in 3 months"
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,7 @@
|
|||
"""Unit tests for Product.to_llm_context() — no database required."""
|
||||
from uuid import uuid4
|
||||
|
||||
from typing import Any
|
||||
|
||||
import pytest
|
||||
from uuid import uuid4
|
||||
|
||||
from innercontext.models import Product
|
||||
from innercontext.models.enums import (
|
||||
|
|
|
|||
|
|
@ -55,7 +55,9 @@ def test_list_filter_category(client, client_and_data=None):
|
|||
"recommended_time": "both",
|
||||
"leave_on": True,
|
||||
}
|
||||
r1 = client.post("/products", json={**base, "name": "Moist", "category": "moisturizer"})
|
||||
r1 = client.post(
|
||||
"/products", json={**base, "name": "Moist", "category": "moisturizer"}
|
||||
)
|
||||
r2 = client.post("/products", json={**base, "name": "Ser", "category": "serum"})
|
||||
assert r1.status_code == 201
|
||||
assert r2.status_code == 201
|
||||
|
|
@ -96,7 +98,12 @@ def test_list_filter_is_medication(client):
|
|||
# is_medication=True requires usage_notes (model validator)
|
||||
client.post(
|
||||
"/products",
|
||||
json={**base, "name": "Med", "is_medication": True, "usage_notes": "Apply pea-sized amount"},
|
||||
json={
|
||||
**base,
|
||||
"name": "Med",
|
||||
"is_medication": True,
|
||||
"usage_notes": "Apply pea-sized amount",
|
||||
},
|
||||
)
|
||||
|
||||
r = client.get("/products?is_medication=true")
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
import uuid
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Routines
|
||||
# ---------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -112,9 +112,7 @@ def test_update_snapshot_concerns(client):
|
|||
|
||||
|
||||
def test_update_snapshot_not_found(client):
|
||||
r = client.patch(
|
||||
f"/skincare/{uuid.uuid4()}", json={"overall_state": "good"}
|
||||
)
|
||||
r = client.patch(f"/skincare/{uuid.uuid4()}", json={"overall_state": "good"})
|
||||
assert r.status_code == 404
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue