mirror of
https://github.com/mealie-recipes/mealie.git
synced 2025-12-28 13:05:26 -05:00
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:
@@ -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()
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user