2024-04-25 02:03:30 +00:00
|
|
|
import json, datetime
|
2024-01-13 03:21:38 +00:00
|
|
|
|
2024-04-25 02:03:30 +00:00
|
|
|
from persons import Person
|
2024-01-17 12:51:07 +00:00
|
|
|
from ingredients import Ingredient, find_ingredients_by_recipe_id
|
2024-01-13 03:21:38 +00:00
|
|
|
|
2024-04-25 02:03:30 +00:00
|
|
|
from pydantic import BaseModel
|
2024-05-13 03:59:46 +00:00
|
|
|
from typing import AsyncIterator, List, ClassVar, Tuple, Optional
|
2024-01-13 03:21:38 +00:00
|
|
|
|
|
|
|
|
class Recipe(BaseModel):
|
2024-05-19 11:22:30 +00:00
|
|
|
KEYS: ClassVar[List[str]] = ['id', 'name', 'link', 'serves', 'image_urls', 'based_on_recipe', 'created_by_id', 'date_created', 'hidden_by_id', 'date_hidden']
|
|
|
|
|
NON_INSERT_KEYS: ClassVar[List[str]] = ['id', 'created_date', 'hidden_by_id', 'date_hidden']
|
|
|
|
|
|
2024-05-20 10:09:57 +00:00
|
|
|
id: int = -1
|
2024-01-13 03:21:38 +00:00
|
|
|
name: str
|
|
|
|
|
link: str
|
2024-05-19 11:22:30 +00:00
|
|
|
serves: int
|
2024-01-13 08:44:07 +00:00
|
|
|
image_urls: List[str] = []
|
2024-01-13 03:21:38 +00:00
|
|
|
ingredients: List[Ingredient] = []
|
2024-04-25 02:03:30 +00:00
|
|
|
based_on_recipe: Optional[int] = None
|
|
|
|
|
|
2024-05-19 11:22:30 +00:00
|
|
|
date_created: datetime.datetime = datetime.datetime.now()
|
2024-05-20 11:50:04 +00:00
|
|
|
created_by_id: Optional[int]
|
2024-04-25 02:03:30 +00:00
|
|
|
created_by: Optional[Person] = None
|
|
|
|
|
|
|
|
|
|
date_hidden: Optional[datetime.datetime] = None
|
|
|
|
|
hidden_by_id: Optional[int] = None
|
|
|
|
|
hidden_by: Optional[Person] = None
|
2024-01-13 03:21:38 +00:00
|
|
|
|
|
|
|
|
async def create(conn):
|
|
|
|
|
await conn.execute('''
|
|
|
|
|
CREATE TABLE IF NOT EXISTS Recipe (
|
|
|
|
|
id INTEGER PRIMARY KEY,
|
2024-04-25 02:03:30 +00:00
|
|
|
name TEXT NOT NULL,
|
|
|
|
|
link TEXT NOT NULL,
|
2024-05-19 11:22:30 +00:00
|
|
|
serves INTEGER NOT NULL,
|
2024-04-25 02:03:30 +00:00
|
|
|
image_urls TEXT NOT NULL,
|
|
|
|
|
based_on_recipe INTEGER NULL,
|
|
|
|
|
|
|
|
|
|
date_created DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
|
|
|
created_by_id INTEGER NOT NULL,
|
|
|
|
|
|
|
|
|
|
date_hidden DATETIME DEFAULT NULL,
|
|
|
|
|
hidden_by_id INTEGER DEFAULT NULL,
|
|
|
|
|
|
|
|
|
|
FOREIGN KEY (based_on_recipe) REFERENCES Recipe(id)
|
|
|
|
|
FOREIGN KEY (created_by_id) REFERENCES Person(id)
|
|
|
|
|
FOREIGN KEY (hidden_by_id) REFERENCES Person(id)
|
2024-01-13 03:21:38 +00:00
|
|
|
);''')
|
|
|
|
|
|
2024-05-19 11:22:30 +00:00
|
|
|
def _as_insert_field(recipe: Recipe, name: str):
|
|
|
|
|
value = getattr(recipe, name)
|
|
|
|
|
if name == 'image_urls':
|
|
|
|
|
return json.dumps(value)
|
|
|
|
|
return value
|
|
|
|
|
|
2024-01-13 03:21:38 +00:00
|
|
|
async def insert_recipe(conn, recipe: Recipe):
|
2024-05-19 11:22:30 +00:00
|
|
|
fields_to_insert = [k for k in Recipe.KEYS if k not in Recipe.NON_INSERT_KEYS]
|
|
|
|
|
actual_values = [_as_insert_field(recipe, k) for k in fields_to_insert]
|
|
|
|
|
|
|
|
|
|
insert_stmt = f'''
|
|
|
|
|
INSERT INTO Recipe ({','.join(fields_to_insert)})
|
|
|
|
|
VALUES ({','.join(['?'] * len(fields_to_insert))})
|
|
|
|
|
'''
|
|
|
|
|
|
|
|
|
|
async with conn.execute(insert_stmt, actual_values) as cursor:
|
2024-01-13 03:21:38 +00:00
|
|
|
recipe.id = cursor.lastrowid
|
|
|
|
|
|
2024-04-28 03:57:02 +00:00
|
|
|
async def hide_recipe(conn, recipe_id: int, person: Person):
|
|
|
|
|
await conn.execute('''
|
|
|
|
|
UPDATE Recipe
|
|
|
|
|
SET date_hidden = CURRENT_TIMESTAMP, hidden_by_id = ?
|
|
|
|
|
WHERE id = ?
|
|
|
|
|
''', (person.id, recipe_id))
|
|
|
|
|
|
2024-01-17 10:39:48 +00:00
|
|
|
def row_to_recipe(col_tuples: List[Tuple[str, ...]]) -> Recipe:
|
|
|
|
|
d = {k:v for k,v in col_tuples}
|
2024-01-13 11:37:39 +00:00
|
|
|
d['image_urls'] = json.loads(d['image_urls'])
|
2024-01-13 08:44:07 +00:00
|
|
|
return Recipe(**d)
|
|
|
|
|
|
2024-01-13 03:21:38 +00:00
|
|
|
async def find_recipe_by_id(conn, recipe_id: int) -> Recipe:
|
|
|
|
|
async with conn.execute(f'''
|
|
|
|
|
SELECT {','.join(Recipe.KEYS)} FROM Recipe
|
|
|
|
|
WHERE id = ?
|
|
|
|
|
LIMIT 1
|
|
|
|
|
''', (recipe_id,)) as cursor:
|
|
|
|
|
async for row in cursor:
|
2024-01-17 10:39:48 +00:00
|
|
|
return row_to_recipe(zip(Recipe.KEYS, row))
|
2024-01-13 08:44:07 +00:00
|
|
|
|
2024-05-13 03:59:46 +00:00
|
|
|
async def find_recipes_by_name(conn, name: str) -> AsyncIterator[Recipe]:
|
2024-01-13 11:37:39 +00:00
|
|
|
async with conn.execute(f'''
|
|
|
|
|
SELECT {','.join(Recipe.KEYS)} FROM Recipe
|
2024-04-28 03:57:02 +00:00
|
|
|
WHERE name LIKE ? AND date_hidden IS NULL
|
2024-01-13 11:37:39 +00:00
|
|
|
''', (f'%{name}%',)) as cursor:
|
|
|
|
|
async for row in cursor:
|
2024-01-17 10:39:48 +00:00
|
|
|
yield row_to_recipe(zip(Recipe.KEYS, row))
|
2024-01-13 11:37:39 +00:00
|
|
|
|
2024-05-13 03:59:46 +00:00
|
|
|
async def get_all(conn) -> AsyncIterator[Recipe]:
|
2024-01-13 08:44:07 +00:00
|
|
|
async with conn.execute(f'''
|
2024-04-28 03:57:02 +00:00
|
|
|
SELECT {','.join(Recipe.KEYS)} FROM Recipe WHERE date_hidden IS NULL
|
2024-01-13 08:44:07 +00:00
|
|
|
''') as cursor:
|
|
|
|
|
async for row in cursor:
|
2024-01-17 10:39:48 +00:00
|
|
|
yield row_to_recipe(zip(Recipe.KEYS, row))
|
|
|
|
|
|
2024-04-25 04:57:39 +00:00
|
|
|
async def load_recipe_ingredients(conn, recipe: Recipe) -> None:
|
2024-01-17 12:51:07 +00:00
|
|
|
async for ingredient in find_ingredients_by_recipe_id(conn, recipe.id):
|
|
|
|
|
recipe.ingredients.append(ingredient)
|