from fastapi import APIRouter, Depends, HTTPException, Query from sqlalchemy import text from sqlalchemy.orm import Session from typing import Any from app.database import get_session from app.auth import get_current_user router = APIRouter() def _row(r) -> dict: return dict(r._mapping) @router.get("/summary") def harvest_summary( session: Session = Depends(get_session), _: str = Depends(get_current_user), ) -> list[dict]: rows = session.execute(text(""" SELECT EXTRACT(YEAR FROM date::date)::INTEGER AS year, type, SUM(weight_kg) AS total_kg, COUNT(*) AS n_harvests FROM honey_harvests GROUP BY year, type ORDER BY year DESC, total_kg DESC """)).fetchall() return [_row(r) for r in rows] @router.get("") def list_harvests( colony_id: int | None = Query(default=None), apiary_id: int | None = Query(default=None), session: Session = Depends(get_session), _: str = Depends(get_current_user), ) -> list[dict]: if colony_id is not None: rows = session.execute(text(""" SELECT h.*, c.name AS colony_name, a.name AS apiary_name FROM honey_harvests h LEFT JOIN colonies c ON c.id = h.colony_id LEFT JOIN apiaries a ON a.id = h.apiary_id WHERE h.colony_id = :colony_id ORDER BY h.date DESC """), {"colony_id": colony_id}).fetchall() elif apiary_id is not None: rows = session.execute(text(""" SELECT h.*, c.name AS colony_name, a.name AS apiary_name FROM honey_harvests h LEFT JOIN colonies c ON c.id = h.colony_id LEFT JOIN apiaries a ON a.id = h.apiary_id WHERE h.apiary_id = :apiary_id ORDER BY h.date DESC """), {"apiary_id": apiary_id}).fetchall() else: rows = session.execute(text(""" SELECT h.*, c.name AS colony_name, a.name AS apiary_name FROM honey_harvests h LEFT JOIN colonies c ON c.id = h.colony_id LEFT JOIN apiaries a ON a.id = h.apiary_id ORDER BY h.date DESC """)).fetchall() return [_row(r) for r in rows] @router.post("", status_code=201) def create_harvest( body: dict[str, Any], session: Session = Depends(get_session), _: str = Depends(get_current_user), ) -> dict: row = session.execute(text(""" INSERT INTO honey_harvests (date, weight_kg, colony_id, apiary_id, type, notes, time) VALUES (:date, :weight_kg, :colony_id, :apiary_id, :type, :notes, :time) RETURNING * """), { "date": body.get("date"), "weight_kg": body.get("weight_kg"), "colony_id": body.get("colony_id"), "apiary_id": body.get("apiary_id"), "type": body.get("type"), "notes": body.get("notes"), "time": body.get("time"), }).fetchone() session.commit() return _row(row) @router.get("/{id}") def get_harvest( id: int, session: Session = Depends(get_session), _: str = Depends(get_current_user), ) -> dict: row = session.execute( text("SELECT * FROM honey_harvests WHERE id = :id"), {"id": id} ).fetchone() if row is None: raise HTTPException(status_code=404, detail="Not found") return _row(row) @router.put("/{id}") def update_harvest( id: int, body: dict[str, Any], session: Session = Depends(get_session), _: str = Depends(get_current_user), ) -> dict: result = session.execute(text(""" UPDATE honey_harvests SET date = :date, weight_kg = :weight_kg, notes = :notes WHERE id = :id RETURNING * """), { "id": id, "date": body.get("date"), "weight_kg": body.get("weight_kg"), "notes": body.get("notes"), }).fetchone() session.commit() if result is None: raise HTTPException(status_code=404, detail="Not found") return _row(result) @router.delete("/{id}", status_code=204) def delete_harvest( id: int, session: Session = Depends(get_session), _: str = Depends(get_current_user), ): session.execute(text("DELETE FROM honey_harvests WHERE id = :id"), {"id": id}) session.commit()