Feature/automated meal planner (#939)

* cleanup oversized buttons

* add get all by category function to reciep repos

* fix shopping-list can_merge logic

* use randomized data for testing

* add random getter to repository for meal-planner

* add stub route for random meals

* cleanup global namespace

* add rules database type

* fix type

* add plan rules schema

* test plan rules methods

* add mealplan rules controller

* add new repository

* update frontend types

* formatting

* fix regression

* update autogenerated types

* add api class for mealplan rules

* add tests and fix bugs

* fix data returns

* proof of concept rules editor

* add tag support

* remove old group categories

* add tag support

* implement random by rules api

* change snack to sides

* remove incorrect typing

* split repo for custom methods

* fix query and use and_ clause

* use repo function

* remove old test

* update changelog
This commit is contained in:
Hayden
2022-02-07 19:03:11 -09:00
committed by GitHub
parent 40d1f586cd
commit d1024e272d
43 changed files with 1153 additions and 175 deletions

View File

@@ -15,8 +15,6 @@ from .cookbook import CookBook
from .mealplan import GroupMealPlan
from .preferences import GroupPreferencesModel
settings = get_app_settings()
class Group(SqlAlchemyBase, BaseMixins):
__tablename__ = "groups"
@@ -75,6 +73,8 @@ class Group(SqlAlchemyBase, BaseMixins):
@staticmethod
def get_ref(session: Session, name: str):
settings = get_app_settings()
item = session.query(Group).filter(Group.name == name).one_or_none()
if item is None:
item = session.query(Group).filter(Group.name == settings.DEFAULT_GROUP).one()

View File

@@ -1,8 +1,28 @@
from sqlalchemy import Column, Date, ForeignKey, String, orm
from sqlalchemy.sql.sqltypes import Integer
from mealie.db.models.recipe.tag import Tag, plan_rules_to_tags
from .._model_base import BaseMixins, SqlAlchemyBase
from .._model_utils import GUID, auto_init
from ..recipe.category import Category, plan_rules_to_categories
class GroupMealPlanRules(BaseMixins, SqlAlchemyBase):
__tablename__ = "group_meal_plan_rules"
id = Column(GUID, primary_key=True, default=GUID.generate)
group_id = Column(GUID, ForeignKey("groups.id"), nullable=False)
day = Column(String, nullable=False, default="unset") # "MONDAY", "TUESDAY", "WEDNESDAY", etc...
entry_type = Column(String, nullable=False, default="") # "breakfast", "lunch", "dinner", "side"
categories = orm.relationship(Category, secondary=plan_rules_to_categories, uselist=True)
tags = orm.relationship(Tag, secondary=plan_rules_to_tags, uselist=True)
@auto_init()
def __init__(self, **_) -> None:
pass
class GroupMealPlan(SqlAlchemyBase, BaseMixins):

View File

@@ -18,6 +18,13 @@ group2categories = sa.Table(
sa.Column("category_id", sa.Integer, sa.ForeignKey("categories.id")),
)
plan_rules_to_categories = sa.Table(
"plan_rules_to_categories",
SqlAlchemyBase.metadata,
sa.Column("group_plan_rule_id", GUID, sa.ForeignKey("group_meal_plan_rules.id")),
sa.Column("category_id", sa.Integer, sa.ForeignKey("categories.id")),
)
recipes2categories = sa.Table(
"recipes2categories",
SqlAlchemyBase.metadata,

View File

@@ -72,7 +72,7 @@ class RecipeModel(SqlAlchemyBase, BaseMixins):
assets = orm.relationship("RecipeAsset", cascade="all, delete-orphan")
nutrition: Nutrition = orm.relationship("Nutrition", uselist=False, cascade="all, delete-orphan")
recipe_category: list = orm.relationship("Category", secondary=recipes2categories, back_populates="recipes")
recipe_category = orm.relationship("Category", secondary=recipes2categories, back_populates="recipes")
tools = orm.relationship("Tool", secondary=recipes_to_tools, back_populates="recipes")
recipe_ingredient: list[RecipeIngredient] = orm.relationship(

View File

@@ -5,6 +5,7 @@ from sqlalchemy.orm import validates
from mealie.core import root_logger
from mealie.db.models._model_base import BaseMixins, SqlAlchemyBase
from mealie.db.models._model_utils import guid
logger = root_logger.get_logger()
@@ -15,6 +16,13 @@ recipes2tags = sa.Table(
sa.Column("tag_id", sa.Integer, sa.ForeignKey("tags.id")),
)
plan_rules_to_tags = sa.Table(
"plan_rules_to_tags",
SqlAlchemyBase.metadata,
sa.Column("plan_rule_id", guid.GUID, sa.ForeignKey("group_meal_plan_rules.id")),
sa.Column("tag_id", sa.Integer, sa.ForeignKey("tags.id")),
)
class Tag(SqlAlchemyBase, BaseMixins):
__tablename__ = "tags"
@@ -42,8 +50,7 @@ class Tag(SqlAlchemyBase, BaseMixins):
slug = slugify(match_value)
result = session.query(Tag).filter(Tag.slug == slug).one_or_none()
if result:
if result := session.query(Tag).filter(Tag.slug == slug).one_or_none():
logger.debug("Category exists, associating recipe")
return result
else: