diff --git a/main.py b/main.py index 1ad129d..2f31e7b 100644 --- a/main.py +++ b/main.py @@ -246,60 +246,49 @@ async def delete_meal(meal_id: int, conn: sqlite3.Connection = Depends(get_db)) await conn.commit() return meal +class CurrentShoppingList(BaseModel): + requests: List[shopping.ShoppingListRequest] + overlapping_previous_shops: List[shopping.ShoppingList] + +@app.get("/api/shopping/current") +async def get_current_shopping_list(conn: sqlite3.Connection = Depends(get_db)) -> CurrentShoppingList: + overlapping = [] + current_requests = [r async for r in shopping.get_current_requests(conn)] + + for request in current_requests: + if request.meal_id: + overlapping.extend([r async for r in shopping.get_shopping_list_with_meal(conn, request.meal_id)]) + + return CurrentShoppingList(requests=current_requests, overlapping_previous_shops=overlapping) + @app.get("/api/shopping/{list_id}") -async def get_shopping_list(list_id: Union[int, str], conn: sqlite3.Connection = Depends(get_db)) -> shopping.ShoppingList: - if list_id.lower() == 'current': - return await shopping.current_shopping_list(conn) - - try: - list_id = int(list_id) - except ValueError: - return JSONResponse(status_code=400, content={'message': 'Invalid shopping list ID'}) - +async def get_shopping_list(list_id: int, conn: sqlite3.Connection = Depends(get_db)) -> shopping.ShoppingList: return await shopping.load_shopping_list(conn, list_id) -@app.post("/api/shopping/current/purchased") -async def mark_purchased(conn: sqlite3.Connection = Depends(get_db), person: persons.Person = Depends(cookie_person)) -> shopping.ShoppingList: - response = await shopping.mark_purchased(conn) +class ShoppingListPurchase(shopping.ShoppingList): + completed_requests: List[shopping.ShoppingListRequest] = [] - # Its easier to make the next shopping list now, while we know calling it requires commit() - await shopping.current_shopping_list(conn) +@app.post("/api/shopping/") +async def purchase_ingredients(lst: ShoppingListPurchase, conn: sqlite3.Connection = Depends(get_db)) -> shopping.ShoppingList: + await shopping.insert_shopping_list(conn, lst) + for request in lst.completed_requests: + if request.meal_id: + meal = await meals.find_meal_by_id(conn, request.meal_id) + if meal: + await meals.mark_purchased(conn, meal) + + await shopping.remove_request(conn, request) + await conn.commit() - return response - -class FoundResult(BaseModel): - created: List[shopping.ShoppingListResult] = [] - removed: List[shopping.ShoppingListResult] = [] - -@app.post("/api/shopping/current/found") -async def mark_shopping_list(ingredients: List[ingredients.Ingredient], conn: sqlite3.Connection = Depends(get_db)) -> FoundResult: - now = datetime.datetime.now() - result = FoundResult() - for ingredient in ingredients: - existing, created = await shopping.mark_found(conn, ingredient, now) - result.created.append(created) - - if existing: - result.removed.append(existing) - - await conn.commit() - return result - -@app.delete("/api/shopping/current/found/{product_id}") -async def unmark_shopping_list(product_id: int, conn: sqlite3.Connection = Depends(get_db)) -> List[shopping.ShoppingListResult]: - response = await shopping.unmark_found(conn, product_id) - await conn.commit() - return response - + return lst + @app.get("/api/shopping/current/me/ingredients") async def get_my_shopping_list(conn: sqlite3.Connection = Depends(get_db), person: persons.Person = Depends(cookie_person)) -> List[shopping.ShoppingListRequest]: - current = await shopping.current_shopping_list(conn) - return [r async for r in shopping.get_persons_requests(conn, current, person) if r.ingredient] + return [r async for r in shopping.get_current_requests(conn) if r.ingredient and r.person_id == person.id] @app.post("/api/shopping/current/me/ingredients") async def sync_my_shopping_list(requests: List[ingredients.Ingredient], conn: sqlite3.Connection = Depends(get_db), person: persons.Person = Depends(cookie_person)) -> List[shopping.ShoppingListRequest]: - current = await shopping.current_shopping_list(conn) - result = [r async for r in shopping.sync_persons_requested_ingredients(conn, current, person, requests) if r.ingredient] + result = [r async for r in shopping.sync_persons_requested_ingredients(conn, person, requests) if r.ingredient] await conn.commit() return result @@ -308,23 +297,21 @@ class MealIdWrapper(BaseModel): @app.post("/api/shopping/current/meals/me") async def request_meal(r: MealIdWrapper, conn: sqlite3.Connection = Depends(get_db), person: persons.Person = Depends(cookie_person)) -> shopping.ShoppingListRequest: - current = await shopping.current_shopping_list(conn) meal = await meals.find_meal_by_id(conn, r.meal_id) if not meal: return JSONResponse(status_code=404, content={'message': 'Meal not found'}) - response = await shopping.request_meal(conn, current, person, meal) + response = await shopping.request_meal(conn, person, meal) await conn.commit() return response @app.delete("/api/shopping/current/meals/{meal_id}") async def unrequest_meal(meal_id: int, conn: sqlite3.Connection = Depends(get_db), person: persons.Person = Depends(cookie_person)) -> dict: - current = await shopping.current_shopping_list(conn) meal = await meals.find_meal_by_id(conn, meal_id) if not meal: return JSONResponse(status_code=404, content={'message': 'Meal not found'}) - await shopping.delete_requests(conn, current, meal) + await shopping.unrequest_meal(conn, meal) await conn.commit() return {} diff --git a/meals/db.py b/meals/db.py index 96143a9..e97251a 100644 --- a/meals/db.py +++ b/meals/db.py @@ -17,7 +17,7 @@ class MealRecipe(BaseModel): recipe: Optional[Recipe] = None class Meal(BaseModel): - KEYS: ClassVar[List[str]] = ['id', 'suggested_date', 'consumed_date'] + KEYS: ClassVar[List[str]] = ['id', 'suggested_date', 'consumed_date', 'purchase_date'] id: int = -1 suggested_date: datetime.datetime consumed_date: Optional[datetime.datetime] = None @@ -37,7 +37,8 @@ async def create(conn): id INTEGER PRIMARY KEY, suggested_date TEXT, consumed_date TEXT, - deleted_date TEXT DEFAULT NULL + deleted_date TEXT DEFAULT NULL, + purchase_date TEXT DEFAULT NULL );''') await conn.execute(''' @@ -113,7 +114,7 @@ async def find_meal_by_id(conn, meal_id: int) -> Meal: LIMIT 1 ''', (meal_id,)) as cursor: async for row in cursor: - meal = await with_purchase_date(conn, Meal(**{k:v for k,v in zip(Meal.KEYS, row)})) + meal = Meal(**{k:v for k,v in zip(Meal.KEYS, row)}) await load_participants(conn, meal) await load_recipes(conn, meal) @@ -126,7 +127,7 @@ async def find_upcoming_meals_by_date_range(conn, start: datetime, end: datetime WHERE suggested_date >= ? AND suggested_date <= ? AND consumed_date IS NULL AND deleted_date IS NULL ''', (start, end)) as cursor: async for row in cursor: - yield await with_purchase_date(conn, Meal(**{k:v for k,v in zip(Meal.KEYS, row)})) + yield Meal(**{k:v for k,v in zip(Meal.KEYS, row)}) async def load_participants(conn, meal: Meal) -> None: async with conn.execute(f''' @@ -213,16 +214,13 @@ async def mark_consumed(conn, meal: Meal, date: datetime.datetime = datetime.dat WHERE id = ? ''', (date, meal.id)) -async def with_purchase_date(conn, meal: Meal) -> Meal: - async with conn.execute(''' - SELECT purchased_date FROM ShoppingList - WHERE id = ( - SELECT list_id FROM ShoppingListRequest - WHERE meal_id = ? - LIMIT 1 - ) - ''', (meal.id,)) as cursor: - async for row in cursor: - meal.purchase_date = row[0] - - return meal +async def mark_purchased(conn, meal: Meal) -> Meal: + meal.purchase_date = datetime.datetime.now() + + await conn.execute(''' + UPDATE Meal + SET purchase_date = ? + WHERE id = ? + ''', (meal.purchase_date, meal.id)) + + return meal \ No newline at end of file diff --git a/shopping/__init__.py b/shopping/__init__.py index 1a56f55..e7e75b8 100644 --- a/shopping/__init__.py +++ b/shopping/__init__.py @@ -1,2 +1,2 @@ -from shopping.db import ShoppingList, ShoppingListRequest, ShoppingListResult, current_shopping_list, mark_found, unmark_found, sync_persons_requested_ingredients, load_shopping_list, get_persons_requests, request_meal, delete_requests, mark_purchased +from shopping.db import ShoppingList, ShoppingListRequest, ShoppingListResult, sync_persons_requested_ingredients, load_shopping_list, get_current_requests, request_meal, unrequest_meal, insert_shopping_list, get_shopping_list_with_meal, remove_request diff --git a/shopping/db.py b/shopping/db.py index 4fa62ca..2a3c1de 100644 --- a/shopping/db.py +++ b/shopping/db.py @@ -1,17 +1,17 @@ -from meals import Meal, find_upcoming_meals_by_date_range, find_meal_by_id +from meals import Meal, find_meal_by_id from ingredients import Ingredient, insert_ingredient from persons import Person from products import Product from pydantic import BaseModel -from typing import AsyncIterator, List, ClassVar, Optional, Tuple +from typing import AsyncIterator, List, ClassVar, Optional -from datetime import datetime, timedelta +from datetime import datetime class ShoppingListRequest(BaseModel): KEYS: ClassVar[List[str]] = ['id', 'ingredient_id', 'list_id', 'person_id', 'meal_id', 'created_date'] id: int = -1 - list_id: int + list_id: Optional[int] = None ingredient_id: Optional[int] = None ingredient: Optional[Ingredient] = None @@ -25,7 +25,7 @@ class ShoppingListRequest(BaseModel): created_date: datetime = datetime.now() class ShoppingListResult(BaseModel): - KEYS: ClassVar[List[str]] = ['id', 'product_id', 'list_id', 'quantity', 'unit', 'created_date', 'found_date'] + KEYS: ClassVar[List[str]] = ['id', 'product_id', 'list_id', 'quantity', 'unit' ] id: int = -1 list_id: int product_id: int @@ -34,14 +34,18 @@ class ShoppingListResult(BaseModel): quantity: float unit: str - created_date: datetime = datetime.now() - found_date: Optional[datetime] = None +from enum import Enum + +class StoreEnum(str, Enum): + woolworths = 'woolworths' + coles = 'coles' + home = '' class ShoppingList(BaseModel): - KEYS: ClassVar[List[str]] = ['id', 'created_date', 'purchased_date'] + KEYS: ClassVar[List[str]] = ['id', 'created_date', 'store_name'] id: int = -1 created_date: datetime = datetime.now() - purchased_date: Optional[datetime] = None + store_name: StoreEnum = '' requests: List[ShoppingListRequest] = [] results: List[ShoppingListResult] = [] @@ -51,7 +55,7 @@ async def create(conn): CREATE TABLE IF NOT EXISTS ShoppingList ( id INTEGER PRIMARY KEY, created_date TEXT, - purchased_date TEXT + store_name TEXT, );''') await conn.execute(''' @@ -75,8 +79,6 @@ async def create(conn): list_id INTEGER, quantity REAL, unit TEXT, - created_date TEXT DEFAULT CURRENT_TIMESTAMP, - found_date TEXT, FOREIGN KEY(product_id) REFERENCES Product(id), FOREIGN KEY(list_id) REFERENCES ShoppingList(id) );''') @@ -99,9 +101,9 @@ def validate_request(request: ShoppingListRequest) -> None: async def insert_shopping_list(conn, shopping_list: ShoppingList): async with conn.execute(''' - INSERT INTO ShoppingList (created_date, purchased_date) - VALUES (CURRENT_TIMESTAMP, NULL) - ''') as cursor: + INSERT INTO ShoppingList (created_date, store_name) + VALUES (CURRENT_TIMESTAMP, ?) + ''', (shopping_list.store_name,)) as cursor: shopping_list.id = cursor.lastrowid for request in shopping_list.requests: @@ -129,59 +131,53 @@ async def insert_shopping_list(conn, shopping_list: ShoppingList): item.list_id = shopping_list.id async with conn.execute(''' - INSERT INTO ShoppingListResult (product_id, list_id, quantity, unit, created_date, found_date) - VALUES (?, ?, ?, ?, ?, ?) - ''', (item.product_id, item.list_id, item.quantity, item.unit, item.created_date, item.found_date)) as cursor: + INSERT INTO ShoppingListResult (product_id, list_id, quantity, unit) + VALUES (?, ?, ?, ?) + ''', (item.product_id, item.list_id, item.quantity, item.unit)) as cursor: item.id = cursor.lastrowid -async def find_request(conn, id: int) -> Optional[ShoppingListRequest]: - # Join Ingredient and Product to also load ingredient and product - product_keys = [f'product.{key}' for key in Product.KEYS] - ingredient_keys = [f'ingredient.{key}' for key in Ingredient.KEYS] - person_keys = [f'person.{key}' for key in Person.KEYS] - request_keys = [f'shoppinglistrequest.{key}' for key in ShoppingListRequest.KEYS] +async def remove_request(conn, request: ShoppingListRequest) -> None: + if request.list_id != None: + raise ValueError('Request is already completed') + + if request.meal and not request.meal_id: + raise ValueError('Meal request must have a meal id') + + if request.meal_id != None: + await conn.execute(''' + DELETE FROM ShoppingListRequest + WHERE meal_id = ? AND list_id IS NULL + ''', (request.meal_id,)) - async with conn.execute(f''' - SELECT {','.join(product_keys + ingredient_keys + person_keys + request_keys)} - FROM ShoppingListRequest - LEFT JOIN Ingredient ON ShoppingListRequest.ingredient_id = Ingredient.id - LEFT JOIN Product ON Ingredient.product_id = Product.id - LEFT JOIN Person ON ShoppingListRequest.person_id = Person.id - WHERE ShoppingListRequest.id = ? - ''', (id,)) as cursor: - async for row in cursor: - product_keys = {k:v for k,v in zip(Product.KEYS, row[:len(Product.KEYS)])} - product = Product(**product_keys) if product_keys['id'] else None + elif request.person_id != None and request.ingredient_id != None: + await conn.execute(''' + DELETE FROM ShoppingListRequest + WHERE person_id = ? AND ingredient_id = ? AND list_id IS NULL + ''', (request.person_id, request.ingredient_id)) - ingredient_keys = {k:v for k,v in zip(Ingredient.KEYS, row[len(Product.KEYS):len(Product.KEYS) + len(Ingredient.KEYS)])} - ingredient = Ingredient(**ingredient_keys, product=product) if ingredient_keys['id'] else None + else: + raise ValueError('Request is invalid') - person_keys = {k:v for k,v in zip(Person.KEYS, row[-len(Person.KEYS):])} - person = Person(**person_keys) if person_keys['id'] else None - - request_keys = {k:v for k,v in zip(ShoppingListRequest.KEYS, row[len(Product.KEYS) + len(Ingredient.KEYS):-len(Person.KEYS)])} - request = ShoppingListRequest(**request_keys, ingredient=ingredient, person=person) - - if request.meal_id is not None: - request.meal = await find_meal_by_id(conn, request.meal_id) - - return request - -async def find_requests_by_list_id(conn, list_id: int) -> AsyncIterator[ShoppingListRequest]: +async def find_requests_by_list_id(conn, list_id: Optional[int]) -> AsyncIterator[ShoppingListRequest]: # Join Ingredient and Product to also load ingredient and product ingredient_keys = [f'ingredient.{key}' for key in Ingredient.KEYS] product_keys = [f'product.{key}' for key in Product.KEYS] request_keys = [f'shoppinglistrequest.{key}' for key in ShoppingListRequest.KEYS] person_keys = [f'person.{key}' for key in Person.KEYS] - cursor = await conn.execute(f''' + select = f''' SELECT {','.join(ingredient_keys + product_keys + request_keys + person_keys)} FROM ShoppingListRequest LEFT JOIN Ingredient ON ShoppingListRequest.ingredient_id = Ingredient.id LEFT JOIN Product ON Ingredient.product_id = Product.id LEFT JOIN Person ON ShoppingListRequest.person_id = Person.id - WHERE list_id = ? - ''', (list_id,)) + ''' + + where, params = ' WHERE list_id IS NULL', () + if list_id is not None: + where, params = ' WHERE list_id = ?', (list_id,) + + cursor = await conn.execute(select + where, params) async for row in cursor: product_keys = {k:v for k,v in zip(Product.KEYS, row[len(Ingredient.KEYS):len(Ingredient.KEYS) + len(Product.KEYS)])} @@ -201,7 +197,7 @@ async def find_requests_by_list_id(conn, list_id: int) -> AsyncIterator[Shopping yield request -async def find_items_by_list_id(conn, list_id: int) -> AsyncIterator[ShoppingListResult]: +async def find_results_by_list_id(conn, list_id: int) -> AsyncIterator[ShoppingListResult]: product_keys = [f'product.{key}' for key in Product.KEYS] result_keys = [f'shoppinglistresult.{key}' for key in ShoppingListResult.KEYS] @@ -223,9 +219,9 @@ async def fill_related(conn, shopping_list: ShoppingList) -> ShoppingList: async for request in find_requests_by_list_id(conn, shopping_list.id): shopping_list.requests.append(request) - async for item in find_items_by_list_id(conn, shopping_list.id): + async for item in find_results_by_list_id(conn, shopping_list.id): shopping_list.results.append(item) - + async def load_shopping_list(conn, id: int) -> ShoppingList: shopping_list = None async with conn.execute(f''' @@ -242,160 +238,57 @@ async def load_shopping_list(conn, id: int) -> ShoppingList: return shopping_list -async def _upcoming_meals(conn) -> AsyncIterator[Meal]: - start = datetime.now() - end = start + timedelta(days=7) - async for meal in find_upcoming_meals_by_date_range(conn, start, end): - if meal.purchase_date is None: - yield meal - -async def current_shopping_list(conn) -> ShoppingList: - shopping_list = None - async with conn.execute(f''' - SELECT {','.join(ShoppingList.KEYS)} FROM ShoppingList - WHERE purchased_date IS NULL - LIMIT 1 - ''') as cursor: - async for row in cursor: - shopping_list = ShoppingList(**{k:v for k,v in zip(ShoppingList.KEYS, row)}) - await fill_related(conn, shopping_list) - break - - if not shopping_list: - shopping_list = ShoppingList() - - async for meal in _upcoming_meals(conn): - shopping_list.requests.append(ShoppingListRequest(list_id=shopping_list.id, meal_id=meal.id, meal=meal, created_date=datetime.now(),)) - - await insert_shopping_list(conn, shopping_list) - - return shopping_list - -async def find_existing_result(conn, product: Product, shopping_list: ShoppingList) -> ShoppingListResult: - async with conn.execute(f''' - SELECT {','.join(ShoppingListResult.KEYS)} FROM ShoppingListResult - WHERE product_id = ? AND list_id = ? - LIMIT 1 - ''', (product.id, shopping_list.id)) as cursor: - async for row in cursor: - return ShoppingListResult(**{k:v for k,v in zip(ShoppingListResult.KEYS, row)}, product=product) - - return None - -async def get_persons_requests(conn, shopping_list: ShoppingList, person: Person) -> AsyncIterator[ShoppingListRequest]: - async for request in find_requests_by_list_id(conn, shopping_list.id): - if request.person_id == person.id: - yield request - -async def request_ingredient(conn, shopping_list: ShoppingList, person: Person, ingredient: Ingredient) -> ShoppingListRequest: - if ingredient.id: +async def request_ingredient(conn, person: Person, ingredient: Ingredient) -> ShoppingListRequest: + if ingredient.id >= 0: raise ValueError('How did you get an existing ingredient?') await insert_ingredient(conn, ingredient) - request = ShoppingListRequest(ingredient_id=ingredient.id, ingredient=ingredient, list_id=shopping_list.id, person_id=person.id, created_date=datetime.now()) + request = ShoppingListRequest(ingredient_id=ingredient.id, ingredient=ingredient, person_id=person.id, created_date=datetime.now()) async with conn.execute(''' - INSERT INTO ShoppingListRequest (ingredient_id, list_id, person_id, created_date) - VALUES (?, ?, ?, ?) - ''', (request.ingredient_id, request.list_id, request.person_id, request.created_date)) as cursor: + INSERT INTO ShoppingListRequest (ingredient_id, person_id, created_date) + VALUES (?, ?, ?) + ''', (request.ingredient_id, request.person_id, request.created_date)) as cursor: request.id = cursor.lastrowid - shopping_list.requests.append(request) return request -async def request_meal(conn, shopping_list: ShoppingList, person: Person, meal: Meal) -> ShoppingListRequest: - request = ShoppingListRequest(meal_id=meal.id, meal=meal, list_id=shopping_list.id, person_id=person.id, created_date=datetime.now()) +async def request_meal(conn, person: Person, meal: Meal) -> ShoppingListRequest: + request = ShoppingListRequest(meal_id=meal.id, meal=meal, person_id=person.id, created_date=datetime.now()) async with conn.execute(''' - INSERT INTO ShoppingListRequest (meal_id, list_id, person_id, created_date) - VALUES (?, ?, ?, ?) - ''', (request.meal_id, request.list_id, request.person_id, request.created_date)) as cursor: + INSERT INTO ShoppingListRequest (meal_id, person_id, created_date) + VALUES (?, ?, ?) + ''', (request.meal_id, request.person_id, request.created_date)) as cursor: request.id = cursor.lastrowid return request -async def delete_requests(conn, shopping_list: ShoppingList, meal: Meal) -> None: +async def unrequest_meal(conn, meal: Meal) -> None: await conn.execute(''' DELETE FROM ShoppingListRequest - WHERE list_id = ? AND meal_id = ? - ''', (shopping_list.id, meal.id)) + WHERE list_id IS NULL AND meal_id = ? + ''', (meal.id,)) -async def sync_persons_requested_ingredients(conn, shopping_list: ShoppingList, person: Person, requests: List[Ingredient]) -> AsyncIterator[ShoppingListRequest]: +def get_current_requests(conn) -> AsyncIterator[ShoppingListRequest]: + return find_requests_by_list_id(conn, None) + +async def sync_persons_requested_ingredients(conn, person: Person, requests: List[Ingredient]) -> AsyncIterator[ShoppingListRequest]: # Delete existing and insert all as new await conn.execute(''' DELETE FROM ShoppingListRequest - WHERE list_id = ? AND person_id = ? AND ingredient_id IS NOT NULL - ''', (shopping_list.id, person.id)) + WHERE list_id IS NULL AND person_id = ? AND ingredient_id IS NOT NULL + ''', (person.id,)) for ingredient in requests: - ingredient.id = 0 - yield await request_ingredient(conn, shopping_list, person, ingredient) - -async def find_existing_result(conn, shopping_list: ShoppingList, product: Product, unit: str) -> Optional[ShoppingListResult]: - product_keys = [f'product.{key}' for key in Product.KEYS] - result_keys = [f'shoppinglistresult.{key}' for key in ShoppingListResult.KEYS] - - async with conn.execute(f''' - SELECT {','.join(product_keys + result_keys)} - FROM ShoppingListResult - LEFT JOIN Product ON ShoppingListResult.product_id = Product.id - WHERE ShoppingListResult.list_id = ? AND ShoppingListResult.product_id = ? AND ShoppingListResult.unit = ? - LIMIT 1 - ''', (shopping_list.id, product.id, unit)) as cursor: - async for row in cursor: - product_keys = {k:v for k,v in zip(Product.KEYS, row[:len(Product.KEYS)])} - product = Product(**product_keys) if product_keys['id'] else None - - result_keys = {k:v for k,v in zip(ShoppingListResult.KEYS, row[len(Product.KEYS):])} - return ShoppingListResult(**result_keys, product=product) - - return None - -async def mark_found(conn, ingredient: Ingredient, date_found: datetime) -> Tuple[ShoppingListResult, ShoppingListResult]: - product, quantity, unit = ingredient.product, ingredient.quantity, ingredient.unit - shopping_list = await current_shopping_list(conn) - - created = ShoppingListResult(product=product, product_id=product.id, list_id=shopping_list.id, quantity=quantity, unit=unit, found_date=date_found) - removed = await find_existing_result(conn, shopping_list, product, unit) + ingredient.id = -1 + yield await request_ingredient(conn, person, ingredient) +async def get_shopping_list_with_meal(conn, meal_id: int) -> AsyncIterator[ShoppingList]: async with conn.execute(''' - INSERT INTO ShoppingListResult (product_id, list_id, quantity, unit, created_date, found_date) - VALUES (?, ?, ?, ?, ?, ?) - ''', (created.product_id, created.list_id, quantity, unit, created.created_date, created.found_date)) as cursor: - created.id = cursor.lastrowid - - if removed: - shopping_list.results = [r for r in shopping_list.results if r.id != removed.id] - await conn.execute(''' - DELETE FROM ShoppingListResult - WHERE id = ? - ''', (removed.id,)) - - return removed, created - -async def unmark_found(conn, product_id: int) -> List[ShoppingListRequest]: - shopping_list = await current_shopping_list(conn) - - requests = [] - async with conn.execute(''' - DELETE FROM ShoppingListResult - WHERE list_id = ? AND product_id = ? - ''', (shopping_list.id, product_id)) as cursor: + SELECT list_id FROM ShoppingListRequest + WHERE meal_id = ? AND list_id IS NOT NULL + ''', (meal_id,)) as cursor: async for row in cursor: - requests.append(row) - - deleted = [r for r in shopping_list.results if r.product_id == product_id] - shopping_list.results = [r for r in shopping_list.results if r.product_id != product_id] - return deleted - -async def mark_purchased(conn) -> ShoppingList: - shopping_list = await current_shopping_list(conn) - shopping_list.purchased_date = datetime.now() - - await conn.execute(''' - UPDATE ShoppingList - SET purchased_date = ? - WHERE id = ? - ''', (shopping_list.purchased_date, shopping_list.id)) - - return shopping_list \ No newline at end of file + list_id = row[0] + yield await load_shopping_list(conn, list_id) \ No newline at end of file diff --git a/transform.sql b/transform.sql new file mode 100644 index 0000000..cac9b69 --- /dev/null +++ b/transform.sql @@ -0,0 +1,11 @@ +alter table ShoppingList +add store_name text not null default ''; + +alter table ShoppingListResult +drop created_date; + +alter table ShoppingListResult +drop found_date; + +alter table Meal +add purchase_date TEXT DEFAULT NULL; \ No newline at end of file