From ebab422869446b6a16eab3e2bd9158f95005af9e Mon Sep 17 00:00:00 2001 From: jableader Date: Sat, 13 Jan 2024 18:42:23 +1100 Subject: [PATCH] Meals --- main.py | 46 +++++++++++++++++++++++++++++++++++++++------- meals/__init__.py | 1 + meals/db.py | 45 +++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 83 insertions(+), 9 deletions(-) diff --git a/main.py b/main.py index 0664b41..1f75913 100644 --- a/main.py +++ b/main.py @@ -1,5 +1,6 @@ import sqlite3 -import product, recipe, db +import product, recipe, db, meals +import datetime from pydantic import BaseModel from typing import List, Annotated @@ -51,19 +52,26 @@ class ProductUrl(BaseModel): async def create_product(url: ProductUrl, conn: sqlite3.Connection = Depends(get_db)) -> product.Product: return await product.get_or_create(conn, url.url, url.tags) -@app.get("/recipes/{recipe_id}") -async def get_recipe(recipe_id: int, conn: sqlite3.Connection = Depends(get_db)) -> recipe.Recipe: - r = await recipe.find_recipe_by_id(conn, recipe_id) +async def load_full_recipe(conn: sqlite3.Connection, id: int) -> recipe.Recipe: + r = await recipe.find_recipe_by_id(conn, id) if not r: - return JSONResponse(status_code=404, content={'message': 'Recipe not found'}) + return None r.ingredients = [] - async for ingredient in recipe.find_ingredients_by_recipe_id(conn, recipe_id): + async for ingredient in recipe.find_ingredients_by_recipe_id(conn, id): ingredient.product = await product.find_product_by_id(conn, ingredient.product_id) r.ingredients.append(ingredient) return r +@app.get("/recipes/{recipe_id}") +async def get_recipe(recipe_id: int, conn: sqlite3.Connection = Depends(get_db)) -> recipe.Recipe: + r = await load_full_recipe(conn, recipe_id) + if not r: + return JSONResponse(status_code=404, content={'message': 'Recipe not found'}) + + return r + @app.post('/recipes/') async def create_recipe(item: recipe.Recipe, conn: sqlite3.Connection = Depends(get_db)) -> recipe.Recipe: if not item.ingredients: @@ -80,4 +88,28 @@ async def create_recipe(item: recipe.Recipe, conn: sqlite3.Connection = Depends( await recipe.insert_ingredient(conn, ingredient) await conn.commit() - return item \ No newline at end of file + return item + +@app.get("/meals/") +async def get_meals(start: datetime.datetime, end: datetime.datetime, conn: sqlite3.Connection = Depends(get_db)) -> List[meals.Meal]: + result = [] + async for meal in meals.find_meals_by_date_range(conn, start, end): + meal.recipe = await load_full_recipe(conn, meal.recipe_id) + result.append(meal) + + return result + +@app.post("/meals/") +async def create_meal(meal: meals.Meal, conn: sqlite3.Connection = Depends(get_db)) -> meals.Meal: + if not meal.chef: + return JSONResponse(status_code=400, content={'message': 'Meal must have at least one chef'}) + + if not meal.cleanup: + return JSONResponse(status_code=400, content={'message': 'Meal must have at least one cleanup person'}) + + if not meal.consumers: + return JSONResponse(status_code=400, content={'message': 'Meal must have at least one consumer'}) + + await meals.insert_meal(conn, meal) + await conn.commit() + return meal \ No newline at end of file diff --git a/meals/__init__.py b/meals/__init__.py index e69de29..0f72027 100644 --- a/meals/__init__.py +++ b/meals/__init__.py @@ -0,0 +1 @@ +from meals.db import * \ No newline at end of file diff --git a/meals/db.py b/meals/db.py index 9ba0754..522e44e 100644 --- a/meals/db.py +++ b/meals/db.py @@ -37,12 +37,27 @@ async def create(conn): FOREIGN KEY(recipe_id) REFERENCES Recipe(id) );''') +async def insert_meal_participant(conn, meal_id: int, person_id: int, role: str): + await conn.execute(''' + INSERT INTO MealParticipant (meal_id, person_id, role) + VALUES (?, ?, ?) + ''', (meal_id, person_id, role)) + async def insert_meal(conn, meal: Meal): async with conn.execute(''' INSERT INTO Meal (date) VALUES (?) ''', (meal.date,)) as cursor: - return cursor.lastrowid + meal.id = cursor.lastrowid + + for person in meal.chef: + await insert_meal_participant(conn, meal.id, person.id, 'chef') + + for person in meal.cleanup: + await insert_meal_participant(conn, meal.id, person.id, 'cleanup') + + for person in meal.consumers: + await insert_meal_participant(conn, meal.id, person.id, 'consumer') async def find_meal_by_id(conn, meal_id: int) -> Meal: async with conn.execute(f''' @@ -60,4 +75,30 @@ async def find_meal_by_date(conn, date: datetime) -> Meal: LIMIT 1 ''', (date,)) as cursor: async for row in cursor: - return Meal(**{k:v for k,v in zip(Meal.KEYS, row)}) \ No newline at end of file + return Meal(**{k:v for k,v in zip(Meal.KEYS, row)}) + +async def find_meals_by_date_range(conn, start: datetime, end: datetime) -> List[Meal]: + async with conn.execute(f''' + SELECT {','.join(Meal.KEYS)} FROM Meal + WHERE date >= ? AND date <= ? + ''', (start, end)) as cursor: + result = [] + async for row in cursor: + result.append(Meal(**{k:v for k,v in zip(Meal.KEYS, row)})) + return result + +async def load_participants(conn, meal: Meal) -> None: + async with conn.execute(f''' + SELECT person_id, role FROM MealParticipant + WHERE meal_id = ? + ''', (meal.id,)) as cursor: + async for row in cursor: + person = await Person.find_person_by_id(conn, row[0]) + if row[1] == 'chef': + meal.chef.append(person) + elif row[1] == 'cleanup': + meal.cleanup.append(person) + elif row[1] == 'consumer': + meal.consumers.append(person) + else: + raise Exception(f'Unknown role: {row[1]}') \ No newline at end of file