|
@@ -0,0 +1,161 @@
|
|
|
+import os
|
|
|
+from sys import stdin, stdout, argv
|
|
|
+from uuid import uuid4
|
|
|
+from json import dumps, load
|
|
|
+
|
|
|
+import psycopg
|
|
|
+from psycopg import Cursor
|
|
|
+import pandas as pd
|
|
|
+
|
|
|
+from app.data.QueryManager import QueryManager, display_mapper
|
|
|
+from app.parse_recipe import parse_recipe
|
|
|
+
|
|
|
+try:
|
|
|
+ from db_credentials import HOST, PASSWORD
|
|
|
+ host = f'host={HOST}'
|
|
|
+ password = f'password={PASSWORD}'
|
|
|
+except:
|
|
|
+ host = ''
|
|
|
+ password = ''
|
|
|
+
|
|
|
+user = os.getenv('USER')
|
|
|
+conn = psycopg.connect(f"{host} dbname=grocery user={user} {password}")
|
|
|
+cur: Cursor = conn.cursor()
|
|
|
+query_manager = QueryManager(cur, display_mapper)
|
|
|
+with open(argv[1], 'rb') as f:
|
|
|
+ units = { x['name']: x for x in load(f) }
|
|
|
+
|
|
|
+# {
|
|
|
+# "id": "7cb5a83d-268a-4898-b24e-08b4753039a5",
|
|
|
+# "userId": "d0f22cce-fa1c-420e-98ae-d85831c725b1",
|
|
|
+# "groupId": "c6229a83-ce82-4be1-9683-ff14f83025c9",
|
|
|
+# "name": "Another",
|
|
|
+# "slug": "another",
|
|
|
+# "image": null,
|
|
|
+# "recipeYield": null,
|
|
|
+# "totalTime": null,
|
|
|
+# "prepTime": null,
|
|
|
+# "cookTime": null,
|
|
|
+# "performTime": null,
|
|
|
+# "description": "",
|
|
|
+# "recipeCategory": [],
|
|
|
+# "tags": [],
|
|
|
+# "tools": [],
|
|
|
+# "rating": null,
|
|
|
+# "orgURL": null,
|
|
|
+# "dateAdded": "2024-04-14",
|
|
|
+# "dateUpdated": "2024-04-14T18:49:34.284815",
|
|
|
+# "createdAt": "2024-04-14T18:49:34.293412",
|
|
|
+# "updateAt": "2024-04-14T18:49:34.293418",
|
|
|
+# "lastMade": null,
|
|
|
+# "recipeIngredient": [
|
|
|
+# {
|
|
|
+# "quantity": 1.0,
|
|
|
+# "unit": null,
|
|
|
+# "food": null,
|
|
|
+# "note": "1 Cup Flour",
|
|
|
+# "isFood": false,
|
|
|
+# "disableAmount": true,
|
|
|
+# "display": "1 Cup Flour",
|
|
|
+# "title": null,
|
|
|
+# "originalText": null,
|
|
|
+# "referenceId": "2e4403e7-fbfb-42b6-b38b-adf38f09bf78"
|
|
|
+# }
|
|
|
+# ],
|
|
|
+# "recipeInstructions": [
|
|
|
+# {
|
|
|
+# "id": "f8c85a36-1044-45e7-b22b-e37764d892a9",
|
|
|
+# "title": "",
|
|
|
+# "text": "Recipe steps as well as other fields in the recipe page support markdown syntax.\n\n**Add a link**\n\n[My Link](https://demo.mealie.io)\n\n",
|
|
|
+# "ingredientReferences": []
|
|
|
+# }
|
|
|
+# ],
|
|
|
+# "nutrition": {
|
|
|
+# "calories": null,
|
|
|
+# "fatContent": null,
|
|
|
+# "proteinContent": null,
|
|
|
+# "carbohydrateContent": null,
|
|
|
+# "fiberContent": null,
|
|
|
+# "sodiumContent": null,
|
|
|
+# "sugarContent": null
|
|
|
+# },
|
|
|
+# "settings": {
|
|
|
+# "public": true,
|
|
|
+# "showNutrition": true,
|
|
|
+# "showAssets": true,
|
|
|
+# "landscapeView": false,
|
|
|
+# "disableComments": true,
|
|
|
+# "disableAmount": true,
|
|
|
+# "locked": false
|
|
|
+# },
|
|
|
+# "assets": [],
|
|
|
+# "notes": [],
|
|
|
+# "extras": {},
|
|
|
+# "comments": []
|
|
|
+# }
|
|
|
+
|
|
|
+cur.execute("BEGIN;")
|
|
|
+with open('units.sql') as f:
|
|
|
+ to_exec = ''
|
|
|
+ quote = False
|
|
|
+ conn.add_notice_handler(lambda x: print(f"[{x.severity}] {x.message_primary}"))
|
|
|
+ for line in filter(lambda x: x.strip() not in ('BEGIN;','ROLLBACK;'), f):
|
|
|
+ if line.startswith("""$$"""):
|
|
|
+ quote = True if not quote else False
|
|
|
+ to_exec += line
|
|
|
+ if not line.strip().endswith(';'):
|
|
|
+ continue
|
|
|
+ if quote:
|
|
|
+ continue
|
|
|
+ cur.execute(to_exec)
|
|
|
+ try:
|
|
|
+ data = pd.DataFrame(cur.fetchall(), columns=[
|
|
|
+ x.name for x in cur.description
|
|
|
+ ])
|
|
|
+ if not data.empty:
|
|
|
+ print()
|
|
|
+ print(cur._last_query)
|
|
|
+ print(data.to_string(index=False))
|
|
|
+
|
|
|
+ except psycopg.ProgrammingError:
|
|
|
+ pass
|
|
|
+ to_exec = ''
|
|
|
+
|
|
|
+parsed = parse_recipe(stdin, query_manager)
|
|
|
+cur.execute('ROLLBACK')
|
|
|
+def unit_mapper(unit):
|
|
|
+ if 'Cup' in unit:
|
|
|
+ return 'cup'
|
|
|
+
|
|
|
+ return unit.replace(' (metric)', '').replace(' (US)', '')
|
|
|
+
|
|
|
+
|
|
|
+mealie = {
|
|
|
+ 'recipeYield': parsed['feeds'],
|
|
|
+ 'recipeInstructions': [{
|
|
|
+ "id": str(uuid4()),
|
|
|
+ "title": "",
|
|
|
+ "text": line,
|
|
|
+ "ingredientReferences": [],
|
|
|
+ } for line in parsed['instructions'].splitlines()],
|
|
|
+ 'recipeIngredient': [{
|
|
|
+ "quantity": quantity,
|
|
|
+ "unit": units[unit_mapper(unit)],
|
|
|
+ "food": None,
|
|
|
+ "note": product,
|
|
|
+ "isFood": False,
|
|
|
+ "disableAmount": False,
|
|
|
+ "display": product,
|
|
|
+ "title": None,
|
|
|
+ "originalText": o,
|
|
|
+ "referenceId": str(uuid4())
|
|
|
+ } for product, quantity, unit, o in map(
|
|
|
+ lambda x: (*x, ' '.join([*x[1:], x[0]])),
|
|
|
+ parsed['ingredients']
|
|
|
+ )]
|
|
|
+}
|
|
|
+stdout.write(dumps(mealie))
|
|
|
+
|
|
|
+cur.close()
|
|
|
+conn.close()
|
|
|
+
|