mirror of
https://github.com/mealie-recipes/mealie.git
synced 2025-05-24 01:12:54 -04:00
278 lines
12 KiB
Python
278 lines
12 KiB
Python
from functools import cached_property
|
|
|
|
from sqlalchemy import func
|
|
from sqlalchemy.orm import Session
|
|
|
|
from mealie.db.models.group import Group, GroupMealPlan, ReportEntryModel, ReportModel
|
|
from mealie.db.models.group.cookbook import CookBook
|
|
from mealie.db.models.group.events import GroupEventNotifierModel
|
|
from mealie.db.models.group.exports import GroupDataExportsModel
|
|
from mealie.db.models.group.invite_tokens import GroupInviteToken
|
|
from mealie.db.models.group.mealplan import GroupMealPlanRules
|
|
from mealie.db.models.group.preferences import GroupPreferencesModel
|
|
from mealie.db.models.group.shopping_list import (
|
|
ShoppingList,
|
|
ShoppingListItem,
|
|
ShoppingListItemRecipeReference,
|
|
ShoppingListRecipeReference,
|
|
)
|
|
from mealie.db.models.group.webhooks import GroupWebhooksModel
|
|
from mealie.db.models.labels import MultiPurposeLabel
|
|
from mealie.db.models.recipe.category import Category
|
|
from mealie.db.models.recipe.comment import RecipeComment
|
|
from mealie.db.models.recipe.ingredient import IngredientFoodModel, IngredientUnitModel
|
|
from mealie.db.models.recipe.recipe import RecipeModel
|
|
from mealie.db.models.recipe.recipe_timeline import RecipeTimelineEvent
|
|
from mealie.db.models.recipe.shared import RecipeShareTokenModel
|
|
from mealie.db.models.recipe.tag import Tag
|
|
from mealie.db.models.recipe.tool import Tool
|
|
from mealie.db.models.server.task import ServerTaskModel
|
|
from mealie.db.models.users import LongLiveToken, User
|
|
from mealie.db.models.users.password_reset import PasswordResetModel
|
|
from mealie.repos.repository_foods import RepositoryFood
|
|
from mealie.repos.repository_meal_plan_rules import RepositoryMealPlanRules
|
|
from mealie.repos.repository_units import RepositoryUnit
|
|
from mealie.schema.cookbook.cookbook import ReadCookBook
|
|
from mealie.schema.group.group_events import GroupEventNotifierOut
|
|
from mealie.schema.group.group_exports import GroupDataExport
|
|
from mealie.schema.group.group_preferences import ReadGroupPreferences
|
|
from mealie.schema.group.group_shopping_list import (
|
|
ShoppingListItemOut,
|
|
ShoppingListItemRecipeRefOut,
|
|
ShoppingListOut,
|
|
ShoppingListRecipeRefOut,
|
|
)
|
|
from mealie.schema.group.invite_token import ReadInviteToken
|
|
from mealie.schema.group.webhook import ReadWebhook
|
|
from mealie.schema.labels import MultiPurposeLabelOut
|
|
from mealie.schema.meal_plan.new_meal import ReadPlanEntry
|
|
from mealie.schema.meal_plan.plan_rules import PlanRulesOut
|
|
from mealie.schema.recipe import Recipe, RecipeCommentOut, RecipeToolOut
|
|
from mealie.schema.recipe.recipe_category import CategoryCount, CategoryOut, TagCount, TagOut
|
|
from mealie.schema.recipe.recipe_ingredient import IngredientFood, IngredientUnit
|
|
from mealie.schema.recipe.recipe_share_token import RecipeShareToken
|
|
from mealie.schema.recipe.recipe_timeline_events import RecipeTimelineEventOut
|
|
from mealie.schema.reports.reports import ReportEntryOut, ReportOut
|
|
from mealie.schema.response.pagination import PaginationBase, PaginationQuery
|
|
from mealie.schema.server import ServerTask
|
|
from mealie.schema.user import GroupInDB, LongLiveTokenInDB, PrivateUser
|
|
from mealie.schema.user.user_passwords import PrivatePasswordResetToken
|
|
|
|
from .repository_generic import RepositoryGeneric
|
|
from .repository_group import RepositoryGroup
|
|
from .repository_meals import RepositoryMeals
|
|
from .repository_recipes import RepositoryRecipes
|
|
from .repository_shopping_list import RepositoryShoppingList
|
|
from .repository_users import RepositoryUsers
|
|
|
|
PK_ID = "id"
|
|
PK_SLUG = "slug"
|
|
PK_TOKEN = "token"
|
|
PK_GROUP_ID = "group_id"
|
|
|
|
|
|
class RepositoryCategories(RepositoryGeneric[CategoryOut, Category]):
|
|
def get_empty(self):
|
|
return self.session.query(Category).filter(~Category.recipes.any()).all()
|
|
|
|
def get_all_count_recipes(self, pagination: PaginationQuery) -> PaginationBase[TagCount]:
|
|
q = self.session.query(Category, func.count(RecipeModel.id).filter(RecipeModel.recipe_category)).group_by(
|
|
Category.id
|
|
)
|
|
|
|
fltr = self._filter_builder()
|
|
q = q.filter_by(**fltr)
|
|
q, count, total_pages = self.add_pagination_to_query(q, pagination)
|
|
|
|
try:
|
|
data: list[tuple[Category, int]] = q.all()
|
|
except Exception as e:
|
|
self._log_exception(e)
|
|
self.session.rollback()
|
|
raise e
|
|
|
|
return PaginationBase(
|
|
page=pagination.page,
|
|
per_page=pagination.per_page,
|
|
total=count,
|
|
total_pages=total_pages,
|
|
items=[CategoryCount(**s[0].__dict__, count=s[1]) for s in data],
|
|
)
|
|
|
|
|
|
class RepositoryTags(RepositoryGeneric[TagOut, Tag]):
|
|
def get_empty(self):
|
|
return self.session.query(Tag).filter(~Tag.recipes.any()).all()
|
|
|
|
def get_all_count_recipes(self, pagination: PaginationQuery) -> PaginationBase[TagCount]:
|
|
q = self.session.query(self.model, func.count(RecipeModel.id)).join(RecipeModel.tags).group_by(self.model)
|
|
|
|
fltr = self._filter_builder()
|
|
q = q.filter_by(**fltr)
|
|
q, count, total_pages = self.add_pagination_to_query(q, pagination)
|
|
|
|
try:
|
|
data: list[tuple[Tag, int]] = q.all()
|
|
except Exception as e:
|
|
self._log_exception(e)
|
|
self.session.rollback()
|
|
raise e
|
|
|
|
return PaginationBase(
|
|
page=pagination.page,
|
|
per_page=pagination.per_page,
|
|
total=count,
|
|
total_pages=total_pages,
|
|
items=[TagCount(**s[0].__dict__, count=s[1]) for s in data],
|
|
)
|
|
|
|
|
|
class AllRepositories:
|
|
def __init__(self, session: Session) -> None:
|
|
"""
|
|
`AllRepositories` class is the data access layer for all database actions within
|
|
Mealie. Database uses composition from classes derived from AccessModel. These
|
|
can be substantiated from the AccessModel class or through inheritance when
|
|
additional methods are required.
|
|
"""
|
|
|
|
self.session = session
|
|
|
|
# ================================================================
|
|
# Recipe
|
|
|
|
@cached_property
|
|
def recipes(self) -> RepositoryRecipes:
|
|
return RepositoryRecipes(self.session, PK_SLUG, RecipeModel, Recipe)
|
|
|
|
@cached_property
|
|
def ingredient_foods(self) -> RepositoryFood:
|
|
return RepositoryFood(self.session, PK_ID, IngredientFoodModel, IngredientFood)
|
|
|
|
@cached_property
|
|
def ingredient_units(self) -> RepositoryUnit:
|
|
return RepositoryUnit(self.session, PK_ID, IngredientUnitModel, IngredientUnit)
|
|
|
|
@cached_property
|
|
def tools(self) -> RepositoryGeneric[RecipeToolOut, Tool]:
|
|
return RepositoryGeneric(self.session, PK_ID, Tool, RecipeToolOut)
|
|
|
|
@cached_property
|
|
def comments(self) -> RepositoryGeneric[RecipeCommentOut, RecipeComment]:
|
|
return RepositoryGeneric(self.session, PK_ID, RecipeComment, RecipeCommentOut)
|
|
|
|
@cached_property
|
|
def categories(self) -> RepositoryCategories:
|
|
return RepositoryCategories(self.session, PK_ID, Category, CategoryOut)
|
|
|
|
@cached_property
|
|
def tags(self) -> RepositoryTags:
|
|
return RepositoryTags(self.session, PK_ID, Tag, TagOut)
|
|
|
|
@cached_property
|
|
def recipe_share_tokens(self) -> RepositoryGeneric[RecipeShareToken, RecipeShareTokenModel]:
|
|
return RepositoryGeneric(self.session, PK_ID, RecipeShareTokenModel, RecipeShareToken)
|
|
|
|
@cached_property
|
|
def recipe_timeline_events(self) -> RepositoryGeneric[RecipeTimelineEventOut, RecipeTimelineEvent]:
|
|
return RepositoryGeneric(self.session, PK_ID, RecipeTimelineEvent, RecipeTimelineEventOut)
|
|
|
|
# ================================================================
|
|
# User
|
|
|
|
@cached_property
|
|
def users(self) -> RepositoryUsers:
|
|
return RepositoryUsers(self.session, PK_ID, User, PrivateUser)
|
|
|
|
@cached_property
|
|
def api_tokens(self) -> RepositoryGeneric[LongLiveTokenInDB, LongLiveToken]:
|
|
return RepositoryGeneric(self.session, PK_ID, LongLiveToken, LongLiveTokenInDB)
|
|
|
|
@cached_property
|
|
def tokens_pw_reset(self) -> RepositoryGeneric[PrivatePasswordResetToken, PasswordResetModel]:
|
|
return RepositoryGeneric(self.session, PK_TOKEN, PasswordResetModel, PrivatePasswordResetToken)
|
|
|
|
# ================================================================
|
|
# Group
|
|
|
|
@cached_property
|
|
def server_tasks(self) -> RepositoryGeneric[ServerTask, ServerTaskModel]:
|
|
return RepositoryGeneric(self.session, PK_ID, ServerTaskModel, ServerTask)
|
|
|
|
@cached_property
|
|
def groups(self) -> RepositoryGroup:
|
|
return RepositoryGroup(self.session, PK_ID, Group, GroupInDB)
|
|
|
|
@cached_property
|
|
def group_invite_tokens(self) -> RepositoryGeneric[ReadInviteToken, GroupInviteToken]:
|
|
return RepositoryGeneric(self.session, PK_TOKEN, GroupInviteToken, ReadInviteToken)
|
|
|
|
@cached_property
|
|
def group_preferences(self) -> RepositoryGeneric[ReadGroupPreferences, GroupPreferencesModel]:
|
|
return RepositoryGeneric(self.session, PK_GROUP_ID, GroupPreferencesModel, ReadGroupPreferences)
|
|
|
|
@cached_property
|
|
def group_exports(self) -> RepositoryGeneric[GroupDataExport, GroupDataExportsModel]:
|
|
return RepositoryGeneric(self.session, PK_ID, GroupDataExportsModel, GroupDataExport)
|
|
|
|
@cached_property
|
|
def group_reports(self) -> RepositoryGeneric[ReportOut, ReportModel]:
|
|
return RepositoryGeneric(self.session, PK_ID, ReportModel, ReportOut)
|
|
|
|
@cached_property
|
|
def group_report_entries(self) -> RepositoryGeneric[ReportEntryOut, ReportEntryModel]:
|
|
return RepositoryGeneric(self.session, PK_ID, ReportEntryModel, ReportEntryOut)
|
|
|
|
@cached_property
|
|
def cookbooks(self) -> RepositoryGeneric[ReadCookBook, CookBook]:
|
|
return RepositoryGeneric(self.session, PK_ID, CookBook, ReadCookBook)
|
|
|
|
# ================================================================
|
|
# Meal Plan
|
|
|
|
@cached_property
|
|
def meals(self) -> RepositoryMeals:
|
|
return RepositoryMeals(self.session, PK_ID, GroupMealPlan, ReadPlanEntry)
|
|
|
|
@cached_property
|
|
def group_meal_plan_rules(self) -> RepositoryMealPlanRules:
|
|
return RepositoryMealPlanRules(self.session, PK_ID, GroupMealPlanRules, PlanRulesOut)
|
|
|
|
@cached_property
|
|
def webhooks(self) -> RepositoryGeneric[ReadWebhook, GroupWebhooksModel]:
|
|
return RepositoryGeneric(self.session, PK_ID, GroupWebhooksModel, ReadWebhook)
|
|
|
|
# ================================================================
|
|
# Shopping List
|
|
|
|
@cached_property
|
|
def group_shopping_lists(self) -> RepositoryShoppingList:
|
|
return RepositoryShoppingList(self.session, PK_ID, ShoppingList, ShoppingListOut)
|
|
|
|
@cached_property
|
|
def group_shopping_list_item(self) -> RepositoryGeneric[ShoppingListItemOut, ShoppingListItem]:
|
|
return RepositoryGeneric(self.session, PK_ID, ShoppingListItem, ShoppingListItemOut)
|
|
|
|
@cached_property
|
|
def group_shopping_list_item_references(
|
|
self,
|
|
) -> RepositoryGeneric[ShoppingListItemRecipeRefOut, ShoppingListItemRecipeReference]:
|
|
return RepositoryGeneric(self.session, PK_ID, ShoppingListItemRecipeReference, ShoppingListItemRecipeRefOut)
|
|
|
|
@cached_property
|
|
def group_shopping_list_recipe_refs(
|
|
self,
|
|
) -> RepositoryGeneric[ShoppingListRecipeRefOut, ShoppingListRecipeReference]:
|
|
return RepositoryGeneric(self.session, PK_ID, ShoppingListRecipeReference, ShoppingListRecipeRefOut)
|
|
|
|
@cached_property
|
|
def group_multi_purpose_labels(self) -> RepositoryGeneric[MultiPurposeLabelOut, MultiPurposeLabel]:
|
|
return RepositoryGeneric(self.session, PK_ID, MultiPurposeLabel, MultiPurposeLabelOut)
|
|
|
|
# ================================================================
|
|
# Group Events
|
|
|
|
@cached_property
|
|
def group_event_notifier(self) -> RepositoryGeneric[GroupEventNotifierOut, GroupEventNotifierModel]:
|
|
return RepositoryGeneric(self.session, PK_ID, GroupEventNotifierModel, GroupEventNotifierOut)
|