Load meal by ID

This commit is contained in:
jableader 2024-01-17 21:39:48 +11:00
parent 33169c69ef
commit a137199400
4 changed files with 71 additions and 10 deletions

15
main.py
View file

@ -117,8 +117,21 @@ async def get_meals(start: datetime.datetime, end: datetime.datetime, conn: sqli
return result
@app.get("/meals/{meal_id}")
async def get_meal(meal_id: int, request: Request, conn: sqlite3.Connection = Depends(get_db)) -> meals.Meal:
meal = await meals.find_meal_by_id(conn, meal_id)
if not meal:
return JSONResponse(status_code=404, content={'message': 'Meal not found'})
await meals.load_participants(conn, meal)
await meals.load_recipes(conn, meal)
await meals.load_extra_ingredients(conn, meal)
return meal
@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'})
@ -127,6 +140,7 @@ async def create_meal(meal: meals.Meal, conn: sqlite3.Connection = Depends(get_d
if not meal.consumers:
return JSONResponse(status_code=400, content={'message': 'Meal must have at least one consumer'})
"""
if len(meal.recipes) == 0 and len(meal.extra_ingredients) == 0:
return JSONResponse(status_code=400, content={'message': 'Meal must have at least one recipe or ingredient'})
@ -135,6 +149,7 @@ async def create_meal(meal: meals.Meal, conn: sqlite3.Connection = Depends(get_d
await conn.commit()
return meal
@app.get("/persons/")
async def get_persons(conn: sqlite3.Connection = Depends(get_db)) -> List[meals.Person]:
result = []

View file

@ -1,7 +1,9 @@
from typing import List, ClassVar
from pydantic import BaseModel
from persons import Person
from ingredients import Ingredient
from ingredients import Ingredient, insert_ingredient
from products import Product
from recipes import Recipe, row_to_recipe
import datetime
@ -45,6 +47,12 @@ async def insert_meal_participant(conn, meal_id: int, person_id: int, role: str)
VALUES (?, ?, ?)
''', (meal_id, person_id, role))
async def insert_meal_recipe(conn, meal_id: int, recipe_id: int):
await conn.execute('''
INSERT INTO MealRecipe (meal_id, recipe_id)
VALUES (?, ?)
''', (meal_id, recipe_id))
async def insert_meal(conn, meal: Meal):
async with conn.execute('''
INSERT INTO Meal (date)
@ -61,6 +69,13 @@ async def insert_meal(conn, meal: Meal):
for person in meal.consumers:
await insert_meal_participant(conn, meal.id, person.id, 'consumer')
for recipe in meal.recipes:
await insert_meal_recipe(conn, meal.id, recipe.id)
for ingredient in meal.extra_ingredients:
ingredient.meal_id = meal.id
await insert_ingredient(conn, ingredient)
async def find_meal_by_id(conn, meal_id: int) -> Meal:
async with conn.execute(f'''
SELECT {','.join(Meal.KEYS)} FROM Meal
@ -103,4 +118,27 @@ async def load_participants(conn, meal: Meal) -> None:
elif row[1] == 'consumer':
meal.consumers.append(person)
else:
raise Exception(f'Unknown role: {row[1]}')
raise Exception(f'Unknown role: {row[1]}')
async def load_recipes(conn, meal: Meal) -> None:
async with conn.execute(f'''
SELECT {','.join(Recipe.KEYS)} FROM Recipe
JOIN MealRecipe ON MealRecipe.recipe_id = Recipe.id
WHERE MealRecipe.meal_id = ?
''', (meal.id,)) as cursor:
async for row in cursor:
meal.recipes.append(row_to_recipe(zip(Recipe.KEYS, row)))
async def load_extra_ingredients(conn, meal: Meal) -> None:
ingredient_cols = [f'Ingredient.{k}' for k in Ingredient.KEYS]
product_cols = [f'Product.{k}' for k in Product.KEYS]
async with conn.execute(f'''
SELECT {','.join(ingredient_cols + product_cols)} FROM Ingredient
JOIN Product ON Ingredient.product_id = Product.id
WHERE meal_id = ?
''', (meal.id,)) as cursor:
async for row in cursor:
ingredient = Ingredient(**{k:v for k,v in zip(Ingredient.KEYS, row[:len(Ingredient.KEYS)])})
ingredient.product = Product(**{k:v for k,v in zip(Product.KEYS, row[len(Ingredient.KEYS):])})
meal.extra_ingredients.append(ingredient)

View file

@ -1,4 +1,4 @@
from recipes.db import Recipe, insert_recipe, find_recipe_by_id, get_all, find_recipes_by_name
from recipes.db import Recipe, insert_recipe, find_recipe_by_id, get_all, find_recipes_by_name, row_to_recipe
from recipes.scraping import scrape_recipe_ldata as _scrape_recipe_ldata
from ingredients import parse_ingredient_from_nlp as _parse_ingredient_from_nlp, match_existing_products as _match_existing_products

View file

@ -2,8 +2,8 @@ import json
from ingredients import Ingredient
from pydantic import BaseModel
from typing import List, ClassVar
from pydantic import BaseModel, Field
from typing import List, ClassVar, Tuple
class Recipe(BaseModel):
KEYS: ClassVar[List[str]] = ['id', 'name', 'link', 'image_urls', 'raw_data']
@ -31,8 +31,8 @@ async def insert_recipe(conn, recipe: Recipe):
''', (recipe.name, recipe.link, recipe.raw_data, json.dumps(recipe.image_urls))) as cursor:
recipe.id = cursor.lastrowid
def row_to_recipe(row) -> Recipe:
d = {k:v for k,v in zip(Recipe.KEYS, row)}
def row_to_recipe(col_tuples: List[Tuple[str, ...]]) -> Recipe:
d = {k:v for k,v in col_tuples}
d['image_urls'] = json.loads(d['image_urls'])
return Recipe(**d)
@ -43,7 +43,7 @@ async def find_recipe_by_id(conn, recipe_id: int) -> Recipe:
LIMIT 1
''', (recipe_id,)) as cursor:
async for row in cursor:
return row_to_recipe(row)
return row_to_recipe(zip(Recipe.KEYS, row))
async def find_recipes_by_name(conn, name: str) -> List[Recipe]:
async with conn.execute(f'''
@ -51,11 +51,19 @@ async def find_recipes_by_name(conn, name: str) -> List[Recipe]:
WHERE name LIKE ?
''', (f'%{name}%',)) as cursor:
async for row in cursor:
yield row_to_recipe(row)
yield row_to_recipe(zip(Recipe.KEYS, row))
async def get_all(conn) -> List[Recipe]:
async with conn.execute(f'''
SELECT {','.join(Recipe.KEYS)} FROM Recipe
''') as cursor:
async for row in cursor:
yield row_to_recipe(row)
yield row_to_recipe(zip(Recipe.KEYS, row))
async def load_ingredients(conn, recipe: Recipe):
async with conn.execute(f'''
SELECT {','.join(Ingredient.KEYS)} FROM Ingredient
WHERE recipe_id = ?
''', (recipe.id,)) as cursor:
async for row in cursor:
recipe.ingredients.append(Ingredient(**{k:v for k,v in zip(Ingredient.KEYS, row)}))