from typing import List, ClassVar from pydantic import BaseModel from persons import Person import datetime class Meal(BaseModel): KEYS: ClassVar[List[str]] = ['id', 'date'] id: int date: datetime.datetime chef: List[Person] = [] cleanup: List[Person] = [] consumers: List[Person] = [] recipes: List[Person] = [] async def create(conn): await conn.execute(''' CREATE TABLE IF NOT EXISTS Meal ( id INTEGER PRIMARY KEY, date TEXT UNIQUE );''') await conn.execute(''' CREATE TABLE IF NOT EXISTS MealParticipant ( meal_id INTEGER, person_id INTEGER, role TEXT, FOREIGN KEY(meal_id) REFERENCES Meal(id), FOREIGN KEY(person_id) REFERENCES Person(id) );''') await conn.execute(''' CREATE TABLE IF NOT EXISTS MealRecipe ( meal_id INTEGER, recipe_id INTEGER, FOREIGN KEY(meal_id) REFERENCES Meal(id), 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: 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''' SELECT {','.join(Meal.KEYS)} FROM Meal WHERE id = ? LIMIT 1 ''', (meal_id,)) as cursor: async for row in cursor: return Meal(**{k:v for k,v in zip(Meal.KEYS, row)}) async def find_meal_by_date(conn, date: datetime) -> Meal: async with conn.execute(f''' SELECT {','.join(Meal.KEYS)} FROM Meal WHERE date = ? LIMIT 1 ''', (date,)) as cursor: async for row in cursor: 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]}')