from __future__ import annotations from typing import Optional from fastapi import APIRouter, Depends, HTTPException, Query from app.core.config import settings from app.db.store import Store from app.models.schemas.plant import PlantCreate, PlantOut, PlantUpdate router = APIRouter() def _get_store() -> Store: s = Store(settings.DB_PATH) try: yield s finally: s.close() @router.post("", response_model=PlantOut, status_code=201) async def create_plant(body: PlantCreate, store: Store = Depends(_get_store)): cur = store.conn.execute( """INSERT INTO plants (common_name, latin_binomial, variety, location_id, planting_date, rootstock, scion_source, graft_date, days_to_maturity, notes) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING *""", ( body.common_name, body.latin_binomial, body.variety, body.location_id, body.planting_date, body.rootstock, body.scion_source, body.graft_date, body.days_to_maturity, body.notes, ), ) row = store._row_to_dict(cur.fetchone()) store.conn.commit() return row @router.get("", response_model=list[PlantOut]) async def list_plants( location_id: Optional[int] = Query(None), store: Store = Depends(_get_store), ): if location_id is not None: rows = store.conn.execute( "SELECT * FROM plants WHERE location_id = ? ORDER BY common_name", (location_id,), ).fetchall() else: rows = store.conn.execute( "SELECT * FROM plants ORDER BY common_name" ).fetchall() return [store._row_to_dict(r) for r in rows] @router.get("/{plant_id}", response_model=PlantOut) async def get_plant(plant_id: int, store: Store = Depends(_get_store)): row = store.conn.execute( "SELECT * FROM plants WHERE id = ?", (plant_id,) ).fetchone() if not row: raise HTTPException(status_code=404, detail="Plant not found") return store._row_to_dict(row) @router.patch("/{plant_id}", response_model=PlantOut) async def update_plant( plant_id: int, body: PlantUpdate, store: Store = Depends(_get_store) ): updates = {k: v for k, v in body.model_dump().items() if v is not None} if not updates: row = store.conn.execute( "SELECT * FROM plants WHERE id = ?", (plant_id,) ).fetchone() if not row: raise HTTPException(status_code=404, detail="Plant not found") return store._row_to_dict(row) set_clause = ", ".join(f"{k} = ?" for k in updates) set_clause += ", updated_at = datetime('now')" values = list(updates.values()) + [plant_id] cur = store.conn.execute( f"UPDATE plants SET {set_clause} WHERE id = ? RETURNING *", values ) row = cur.fetchone() store.conn.commit() if not row: raise HTTPException(status_code=404, detail="Plant not found") return store._row_to_dict(row) @router.delete("/{plant_id}", status_code=204) async def delete_plant(plant_id: int, store: Store = Depends(_get_store)): store.conn.execute("DELETE FROM plants WHERE id = ?", (plant_id,)) store.conn.commit()