Add Database Layer for Recipe Scaling (#506)

* move badge

* fix add individual ingredient

* fix redirect issue

Co-authored-by: hay-kot <hay-kot@pm.me>
This commit is contained in:
Hayden
2021-06-12 22:23:23 -08:00
committed by GitHub
parent 0a927afaa0
commit e95ca870b1
18 changed files with 298 additions and 62 deletions

View File

@@ -6,6 +6,7 @@ from mealie.db.models.event import Event, EventNotification
from mealie.db.models.group import Group
from mealie.db.models.mealplan import MealPlan
from mealie.db.models.recipe.comment import RecipeComment
from mealie.db.models.recipe.ingredient import IngredientFood, IngredientUnit
from mealie.db.models.recipe.recipe import Category, RecipeModel, Tag
from mealie.db.models.recipe.settings import RecipeSettings
from mealie.db.models.settings import CustomPage, SiteSettings
@@ -18,7 +19,8 @@ from mealie.schema.comments import CommentOut
from mealie.schema.event_notifications import EventNotificationIn
from mealie.schema.events import Event as EventSchema
from mealie.schema.meal import MealPlanOut
from mealie.schema.recipe import Recipe
from mealie.schema.recipe import (Recipe, RecipeIngredientFood,
RecipeIngredientUnit)
from mealie.schema.settings import CustomPageOut
from mealie.schema.settings import SiteSettings as SiteSettingsSchema
from mealie.schema.shopping_list import ShoppingListOut
@@ -87,6 +89,20 @@ class _Recipes(BaseDocument):
)
class _IngredientFoods(BaseDocument):
def __init__(self) -> None:
self.primary_key = "id"
self.sql_model = IngredientFood
self.schema = RecipeIngredientFood
class _IngredientUnits(BaseDocument):
def __init__(self) -> None:
self.primary_key = "id"
self.sql_model = IngredientUnit
self.schema = RecipeIngredientUnit
class _Categories(BaseDocument):
def __init__(self) -> None:
self.primary_key = "slug"
@@ -215,21 +231,28 @@ class _EventNotification(BaseDocument):
class Database:
def __init__(self) -> None:
# Recipes
self.recipes = _Recipes()
self.meals = _Meals()
self.settings = _Settings()
self.themes = _Themes()
self.ingredient_foods = _IngredientUnits()
self.ingredient_units = _IngredientFoods()
self.categories = _Categories()
self.tags = _Tags()
self.comments = _Comments()
# Site
self.settings = _Settings()
self.themes = _Themes()
self.sign_ups = _SignUps()
self.custom_pages = _CustomPages()
self.event_notifications = _EventNotification()
self.events = _Events()
# Users / Groups
self.users = _Users()
self.api_tokens = _LongLiveToken()
self.sign_ups = _SignUps()
self.groups = _Groups()
self.custom_pages = _CustomPages()
self.events = _Events()
self.event_notifications = _EventNotification()
self.meals = _Meals()
self.shopping_lists = _ShoppingList()
self.comments = _Comments()
db = Database()

View File

@@ -1,5 +1,70 @@
from mealie.db.models.model_base import SqlAlchemyBase
from sqlalchemy import Column, ForeignKey, Integer, String
from mealie.db.models.model_base import BaseMixins, SqlAlchemyBase
from requests import Session
from sqlalchemy import Boolean, Column, ForeignKey, Integer, String, Table, orm
ingredients_to_units = Table(
"ingredients_to_units",
SqlAlchemyBase.metadata,
Column("ingredient_units.id", Integer, ForeignKey("ingredient_units.id")),
Column("recipes_ingredients_id", Integer, ForeignKey("recipes_ingredients.id")),
)
ingredients_to_foods = Table(
"ingredients_to_foods",
SqlAlchemyBase.metadata,
Column("ingredient_foods.id", Integer, ForeignKey("ingredient_foods.id")),
Column("recipes_ingredients_id", Integer, ForeignKey("recipes_ingredients.id")),
)
class IngredientUnit(SqlAlchemyBase, BaseMixins):
__tablename__ = "ingredient_units"
id = Column(Integer, primary_key=True)
name = Column(String)
description = Column(String)
ingredients = orm.relationship("RecipeIngredient", secondary=ingredients_to_units, back_populates="unit")
def __init__(self, name: str, description: str = None) -> None:
self.name = name
self.description = description
@classmethod
def get_ref_or_create(cls, session: Session, obj: dict):
# sourcery skip: flip-comparison
if obj is None:
return None
name = obj.get("name")
unit = session.query(cls).filter("name" == name).one_or_none()
if not unit:
return cls(**obj)
class IngredientFood(SqlAlchemyBase, BaseMixins):
__tablename__ = "ingredient_foods"
id = Column(Integer, primary_key=True)
name = Column(String)
description = Column(String)
ingredients = orm.relationship("RecipeIngredient", secondary=ingredients_to_foods, back_populates="food")
def __init__(self, name: str, description: str = None) -> None:
self.name = name
self.description = description
@classmethod
def get_ref_or_create(cls, session: Session, obj: dict):
# sourcery skip: flip-comparison
if obj is None:
return None
name = obj.get("name")
unit = session.query(cls).filter("name" == name).one_or_none()
if not unit:
return cls(**obj)
class RecipeIngredient(SqlAlchemyBase):
@@ -7,8 +72,24 @@ class RecipeIngredient(SqlAlchemyBase):
id = Column(Integer, primary_key=True)
position = Column(Integer)
parent_id = Column(Integer, ForeignKey("recipes.id"))
# title = Column(String)
ingredient = Column(String)
def update(self, ingredient):
self.ingredient = ingredient
title = Column(String) # Section Header - Shows if Present
note = Column(String) # Force Show Text - Overrides Concat
# Scaling Items
unit = orm.relationship(IngredientUnit, secondary=ingredients_to_units, uselist=False)
food = orm.relationship(IngredientFood, secondary=ingredients_to_foods, uselist=False)
quantity = Column(Integer)
# Extras
disable_amount = Column(Boolean, default=False)
def __init__(
self, title: str, note: str, unit: dict, food: dict, quantity: int, disable_amount: bool, session: Session, **_
) -> None:
self.title = title
self.note = note
self.unit = IngredientUnit.get_ref_or_create(session, unit)
self.food = IngredientFood.get_ref_or_create(session, food)
self.quantity = quantity
self.disable_amount = disable_amount

View File

@@ -117,7 +117,7 @@ class RecipeModel(SqlAlchemyBase, BaseMixins):
self.tools = [Tool(tool=x) for x in tools] if tools else []
self.recipe_yield = recipe_yield
self.recipe_ingredient = [RecipeIngredient(ingredient=ingr) for ingr in recipe_ingredient]
self.recipe_ingredient = [RecipeIngredient(**ingr, session=session) for ingr in recipe_ingredient]
self.assets = [RecipeAsset(**a) for a in assets]
self.recipe_instructions = [
RecipeInstruction(text=instruc.get("text"), title=instruc.get("title"), type=instruc.get("@type", None))