Coverage for opt/mealie/lib/python3.12/site-packages/mealie/repos/repository_factory.py: 99%
184 statements
« prev ^ index » next coverage.py v7.10.6, created at 2025-11-25 17:29 +0000
« prev ^ index » next coverage.py v7.10.6, created at 2025-11-25 17:29 +0000
1from collections.abc import Sequence 1a
2from functools import cached_property 1a
4from pydantic import UUID4 1a
5from sqlalchemy import select 1a
6from sqlalchemy.orm import Session 1a
8from mealie.db.models.group import Group, ReportEntryModel, ReportModel 1a
9from mealie.db.models.group.exports import GroupDataExportsModel 1a
10from mealie.db.models.group.preferences import GroupPreferencesModel 1a
11from mealie.db.models.household.cookbook import CookBook 1a
12from mealie.db.models.household.events import GroupEventNotifierModel 1a
13from mealie.db.models.household.household import Household 1a
14from mealie.db.models.household.household_to_recipe import HouseholdToRecipe 1a
15from mealie.db.models.household.invite_tokens import GroupInviteToken 1a
16from mealie.db.models.household.mealplan import GroupMealPlan, GroupMealPlanRules 1a
17from mealie.db.models.household.preferences import HouseholdPreferencesModel 1a
18from mealie.db.models.household.recipe_action import GroupRecipeAction 1a
19from mealie.db.models.household.shopping_list import ( 1a
20 ShoppingList,
21 ShoppingListItem,
22 ShoppingListItemRecipeReference,
23 ShoppingListMultiPurposeLabel,
24 ShoppingListRecipeReference,
25)
26from mealie.db.models.household.webhooks import GroupWebhooksModel 1a
27from mealie.db.models.labels import MultiPurposeLabel 1a
28from mealie.db.models.recipe.category import Category 1a
29from mealie.db.models.recipe.comment import RecipeComment 1a
30from mealie.db.models.recipe.ingredient import IngredientFoodModel, IngredientUnitModel 1a
31from mealie.db.models.recipe.recipe import RecipeModel 1a
32from mealie.db.models.recipe.recipe_timeline import RecipeTimelineEvent 1a
33from mealie.db.models.recipe.shared import RecipeShareTokenModel 1a
34from mealie.db.models.recipe.tag import Tag 1a
35from mealie.db.models.recipe.tool import Tool 1a
36from mealie.db.models.users import LongLiveToken, User 1a
37from mealie.db.models.users.password_reset import PasswordResetModel 1a
38from mealie.db.models.users.user_to_recipe import UserToRecipe 1a
39from mealie.repos.repository_cookbooks import RepositoryCookbooks 1a
40from mealie.repos.repository_foods import RepositoryFood 1a
41from mealie.repos.repository_household import RepositoryHousehold, RepositoryHouseholdRecipes 1a
42from mealie.repos.repository_meal_plan_rules import RepositoryMealPlanRules 1a
43from mealie.repos.repository_units import RepositoryUnit 1a
44from mealie.schema.cookbook.cookbook import ReadCookBook 1a
45from mealie.schema.group.group_exports import GroupDataExport 1a
46from mealie.schema.group.group_preferences import ReadGroupPreferences 1a
47from mealie.schema.household.group_events import GroupEventNotifierOut 1a
48from mealie.schema.household.group_recipe_action import GroupRecipeActionOut 1a
49from mealie.schema.household.group_shopping_list import ( 1a
50 ShoppingListItemOut,
51 ShoppingListItemRecipeRefOut,
52 ShoppingListMultiPurposeLabelOut,
53 ShoppingListOut,
54 ShoppingListRecipeRefOut,
55)
56from mealie.schema.household.household import HouseholdInDB, HouseholdRecipeOut 1a
57from mealie.schema.household.household_preferences import ReadHouseholdPreferences 1a
58from mealie.schema.household.invite_token import ReadInviteToken 1a
59from mealie.schema.household.webhook import ReadWebhook 1a
60from mealie.schema.labels import MultiPurposeLabelOut 1a
61from mealie.schema.meal_plan.new_meal import ReadPlanEntry 1a
62from mealie.schema.meal_plan.plan_rules import PlanRulesOut 1a
63from mealie.schema.recipe import Recipe, RecipeCommentOut, RecipeToolOut 1a
64from mealie.schema.recipe.recipe_category import CategoryOut, TagOut 1a
65from mealie.schema.recipe.recipe_ingredient import IngredientFood, IngredientUnit 1a
66from mealie.schema.recipe.recipe_share_token import RecipeShareToken 1a
67from mealie.schema.recipe.recipe_timeline_events import RecipeTimelineEventOut 1a
68from mealie.schema.reports.reports import ReportEntryOut, ReportOut 1a
69from mealie.schema.user import GroupInDB, LongLiveTokenInDB, PrivateUser 1a
70from mealie.schema.user.user import UserRatingOut 1a
71from mealie.schema.user.user_passwords import PrivatePasswordResetToken 1a
73from ._utils import NOT_SET, NotSet 1a
74from .repository_generic import GroupRepositoryGeneric, HouseholdRepositoryGeneric 1a
75from .repository_group import RepositoryGroup 1a
76from .repository_meals import RepositoryMeals 1a
77from .repository_recipes import RepositoryRecipes 1a
78from .repository_shopping_list import RepositoryShoppingList 1a
79from .repository_users import RepositoryUserRatings, RepositoryUsers 1a
81PK_ID = "id" 1a
82PK_SLUG = "slug" 1a
83PK_TOKEN = "token" 1a
84PK_GROUP_ID = "group_id" 1a
85PK_HOUSEHOLD_ID = "household_id" 1a
88class RepositoryCategories(GroupRepositoryGeneric[CategoryOut, Category]): 1a
89 def get_empty(self) -> Sequence[Category]: 1a
90 stmt = select(Category).filter(~Category.recipes.any())
92 return self.session.execute(stmt).scalars().all()
95class RepositoryTags(GroupRepositoryGeneric[TagOut, Tag]): 1a
96 def get_empty(self) -> Sequence[Tag]: 1a
97 stmt = select(Tag).filter(~Tag.recipes.any()) 1U
98 return self.session.execute(stmt).scalars().all() 1U
101class AllRepositories: 1a
102 """
103 `AllRepositories` class is the data access layer for all database actions within
104 Mealie. Database uses composition from classes derived from AccessModel. These
105 can be substantiated from the AccessModel class or through inheritance when
106 additional methods are required.
107 """
109 def __init__( 1a
110 self,
111 session: Session,
112 *,
113 group_id: UUID4 | None | NotSet = NOT_SET,
114 household_id: UUID4 | None | NotSet = NOT_SET,
115 ) -> None:
116 self.session = session 2a S xbybzb) * V P U 1 2 ` { | Q W I K L } O 3 4 T + , ~ R 5 - ab. / bbX 6 7 8 9 cbdbebAbfbgbY hbBbib: jb; kbZ lbmbCbDbnb= ? ob@ ! Eb[ pb# $ % 0 qbFbrbsb] tb^ ' ubvb_ c o z p d e f q g h G i j r k s D v l w A B t m J M F H n x y C N E u wb( b
117 self.group_id = group_id 2a S xbybzb) * V P U 1 2 ` { | Q W I K L } O 3 4 T + , ~ R 5 - ab. / bbX 6 7 8 9 cbdbebAbfbgbY hbBbib: jb; kbZ lbmbCbDbnb= ? ob@ ! Eb[ pb# $ % 0 qbFbrbsb] tb^ ' ubvb_ c o z p d e f q g h G i j r k s D v l w A B t m J M F H n x y C N E u wb( b
118 self.household_id = household_id 2a S xbybzb) * V P U 1 2 ` { | Q W I K L } O 3 4 T + , ~ R 5 - ab. / bbX 6 7 8 9 cbdbebAbfbgbY hbBbib: jb; kbZ lbmbCbDbnb= ? ob@ ! Eb[ pb# $ % 0 qbFbrbsb] tb^ ' ubvb_ c o z p d e f q g h G i j r k s D v l w A B t m J M F H n x y C N E u wb( b
120 # ================================================================
121 # Recipe
123 @cached_property 1a
124 def recipes(self) -> RepositoryRecipes: 1a
125 return RepositoryRecipes( 11WT+,R5X6789#$%_cozpdefqghGijrksvlwABtmnxCub
126 self.session, PK_SLUG, RecipeModel, Recipe, group_id=self.group_id, household_id=self.household_id
127 )
129 @cached_property 1a
130 def ingredient_foods(self) -> RepositoryFood: 1a
131 return RepositoryFood(self.session, PK_ID, IngredientFoodModel, IngredientFood, group_id=self.group_id) 1QO34cozpdefqghGijrksDvlwABtmMFnxyCEub
133 @cached_property 1a
134 def ingredient_units(self) -> RepositoryUnit: 1a
135 return RepositoryUnit(self.session, PK_ID, IngredientUnitModel, IngredientUnit, group_id=self.group_id) 134cozpdefqghGijrksDvlwABtmJFnxyCEub
137 @cached_property 1a
138 def tools(self) -> GroupRepositoryGeneric[RecipeToolOut, Tool]: 1a
139 return GroupRepositoryGeneric(self.session, PK_ID, Tool, RecipeToolOut, group_id=self.group_id) 1OcopdefqghijrksDvlwABtmnxyCub
141 @cached_property 1a
142 def comments(self) -> GroupRepositoryGeneric[RecipeCommentOut, RecipeComment]: 1a
143 # Since users can comment on recipes that belong to other households,
144 # this is a group repository, rather than a household repository.
145 return GroupRepositoryGeneric(self.session, PK_ID, RecipeComment, RecipeCommentOut, group_id=self.group_id) 1cozpdefqghGijrksDlwABtmnxyNub
147 @cached_property 1a
148 def categories(self) -> RepositoryCategories: 1a
149 return RepositoryCategories(self.session, PK_ID, Category, CategoryOut, group_id=self.group_id) 1POb
151 @cached_property 1a
152 def tags(self) -> RepositoryTags: 1a
153 return RepositoryTags(self.session, PK_ID, Tag, TagOut, group_id=self.group_id) 1UOb
155 @cached_property 1a
156 def recipe_share_tokens(self) -> GroupRepositoryGeneric[RecipeShareToken, RecipeShareTokenModel]: 1a
157 return GroupRepositoryGeneric( 1[b
158 self.session, PK_ID, RecipeShareTokenModel, RecipeShareToken, group_id=self.group_id
159 )
161 @cached_property 1a
162 def recipe_timeline_events(self) -> GroupRepositoryGeneric[RecipeTimelineEventOut, RecipeTimelineEvent]: 1a
163 # Since users can post events on recipes that belong to other households,
164 # this is a group repository, rather than a household repository.
165 return GroupRepositoryGeneric( 11TcdefqghijrksvlAtmnEub
166 self.session, PK_ID, RecipeTimelineEvent, RecipeTimelineEventOut, group_id=self.group_id
167 )
169 # ================================================================
170 # User
172 @cached_property 1a
173 def users(self) -> RepositoryUsers: 1a
174 return RepositoryUsers(self.session, PK_ID, User, PrivateUser, group_id=self.group_id) 2a S xb) * V P U 1 2 ` { | Q W I K L } O 3 4 T + , ~ R 5 - ab. / bbX 6 7 8 9 cbdbebAbfbgbY hbBbib: jb; kbZ lbmbCbDbnb= ? ob@ ! Eb[ pb# $ % 0 qbFbrbsb] tb^ ' ubvb_ c o z p d e f q g h G i j r k s D v l w A B t m J M F H n x y C N E u wbb
176 @cached_property 1a
177 def user_ratings(self) -> RepositoryUserRatings: 1a
178 return RepositoryUserRatings(self.session, PK_ID, UserToRecipe, UserRatingOut, group_id=self.group_id)
180 @cached_property 1a
181 def api_tokens(self) -> GroupRepositoryGeneric[LongLiveTokenInDB, LongLiveToken]: 1a
182 return GroupRepositoryGeneric(self.session, PK_ID, LongLiveToken, LongLiveTokenInDB, group_id=self.group_id) 2- ebc o p d e f g h i j r k l A B m F H n x y E b
184 @cached_property 1a
185 def tokens_pw_reset(self) -> GroupRepositoryGeneric[PrivatePasswordResetToken, PasswordResetModel]: 1a
186 return GroupRepositoryGeneric(
187 self.session, PK_TOKEN, PasswordResetModel, PrivatePasswordResetToken, group_id=self.group_id
188 )
190 # ================================================================
191 # Group
193 @cached_property 1a
194 def groups(self) -> RepositoryGroup: 1a
195 return RepositoryGroup(self.session, PK_ID, Group, GroupInDB) 2a S ybzb* V P U 2 ` { | I K L O 3 4 T + , ~ R 5 - ab. / bbX 6 7 8 9 cbdbfbgbY hbib: jb; kbZ lbmbnb= ? ob@ ! [ pb# $ % 0 qbrbsb] tb^ ' ubvbc o z p d e f q g h G i j r k s D v l w A B t m J M F H n x y C N E u ( b
197 @cached_property 1a
198 def group_preferences(self) -> GroupRepositoryGeneric[ReadGroupPreferences, GroupPreferencesModel]: 1a
199 return GroupRepositoryGeneric( 1aS.b
200 self.session, PK_GROUP_ID, GroupPreferencesModel, ReadGroupPreferences, group_id=self.group_id
201 )
203 @cached_property 1a
204 def group_exports(self) -> GroupRepositoryGeneric[GroupDataExport, GroupDataExportsModel]: 1a
205 return GroupRepositoryGeneric(
206 self.session, PK_ID, GroupDataExportsModel, GroupDataExport, group_id=self.group_id
207 )
209 @cached_property 1a
210 def group_reports(self) -> GroupRepositoryGeneric[ReportOut, ReportModel]: 1a
211 return GroupRepositoryGeneric(self.session, PK_ID, ReportModel, ReportOut, group_id=self.group_id) 1*Rb
213 @cached_property 1a
214 def group_report_entries(self) -> GroupRepositoryGeneric[ReportEntryOut, ReportEntryModel]: 1a
215 return GroupRepositoryGeneric(self.session, PK_ID, ReportEntryModel, ReportEntryOut, group_id=self.group_id) 1Rb
217 # ================================================================
218 # Household
220 @cached_property 1a
221 def households(self) -> RepositoryHousehold: 1a
222 return RepositoryHousehold(self.session, PK_ID, Household, HouseholdInDB, group_id=self.group_id) 1aS)P12QIOTR5X6789YZ!#$%0'_cozpdefqghGijrksvlwABtmJMFHnyCNEu(b
224 @cached_property 1a
225 def household_preferences(self) -> HouseholdRepositoryGeneric[ReadHouseholdPreferences, HouseholdPreferencesModel]: 1a
226 return HouseholdRepositoryGeneric( 1aS/b
227 self.session,
228 PK_HOUSEHOLD_ID,
229 HouseholdPreferencesModel,
230 ReadHouseholdPreferences,
231 group_id=self.group_id,
232 household_id=self.household_id,
233 )
235 @cached_property 1a
236 def household_recipes(self) -> RepositoryHouseholdRecipes: 1a
237 return RepositoryHouseholdRecipes(
238 self.session,
239 PK_ID,
240 HouseholdToRecipe,
241 HouseholdRecipeOut,
242 group_id=self.group_id,
243 household_id=self.household_id,
244 )
246 @cached_property 1a
247 def cookbooks(self) -> RepositoryCookbooks: 1a
248 return RepositoryCookbooks( 1:=?]cozpdefqghijrksDvlwABtmJFHnxyCub
249 self.session, PK_ID, CookBook, ReadCookBook, group_id=self.group_id, household_id=self.household_id
250 )
252 @cached_property 1a
253 def group_invite_tokens(self) -> HouseholdRepositoryGeneric[ReadInviteToken, GroupInviteToken]: 1a
254 return HouseholdRepositoryGeneric( 1VWb
255 self.session,
256 PK_TOKEN,
257 GroupInviteToken,
258 ReadInviteToken,
259 group_id=self.group_id,
260 household_id=self.household_id,
261 )
263 @cached_property 1a
264 def group_recipe_actions(self) -> HouseholdRepositoryGeneric[GroupRecipeActionOut, GroupRecipeAction]: 1a
265 return HouseholdRepositoryGeneric( 1cozpdefqghGijrksDvlwAtmMFHnxyCEub
266 self.session,
267 PK_ID,
268 GroupRecipeAction,
269 GroupRecipeActionOut,
270 group_id=self.group_id,
271 household_id=self.household_id,
272 )
274 # ================================================================
275 # Meal Plan
277 @cached_property 1a
278 def meals(self) -> RepositoryMeals: 1a
279 return RepositoryMeals( 1VWY;Z@0^cozpdefqghGijksvlwBtmnxyCNub
280 self.session, PK_ID, GroupMealPlan, ReadPlanEntry, group_id=self.group_id, household_id=self.household_id
281 )
283 @cached_property 1a
284 def group_meal_plan_rules(self) -> RepositoryMealPlanRules: 1a
285 return RepositoryMealPlanRules( 1WcozpdefqghGijrksDvlwABtmHnxyCNEub
286 self.session,
287 PK_ID,
288 GroupMealPlanRules,
289 PlanRulesOut,
290 group_id=self.group_id,
291 household_id=self.household_id,
292 )
294 # ================================================================
295 # Shopping List
297 @cached_property 1a
298 def group_shopping_lists(self) -> RepositoryShoppingList: 1a
299 return RepositoryShoppingList( 1PQIKLcozpdefqghijrksDvlwtmJMFHnxyCEub
300 self.session, PK_ID, ShoppingList, ShoppingListOut, group_id=self.group_id, household_id=self.household_id
301 )
303 @cached_property 1a
304 def group_shopping_list_item(self) -> HouseholdRepositoryGeneric[ShoppingListItemOut, ShoppingListItem]: 1a
305 return HouseholdRepositoryGeneric( 1IKLcozpdefqghijrksvlwtmnxyub
306 self.session,
307 PK_ID,
308 ShoppingListItem,
309 ShoppingListItemOut,
310 group_id=self.group_id,
311 household_id=self.household_id,
312 )
314 @cached_property 1a
315 def group_shopping_list_item_references( 1a
316 self,
317 ) -> HouseholdRepositoryGeneric[ShoppingListItemRecipeRefOut, ShoppingListItemRecipeReference]:
318 return HouseholdRepositoryGeneric( 1IKLcozpdefqghijrksvlwtmnxyub
319 self.session,
320 PK_ID,
321 ShoppingListItemRecipeReference,
322 ShoppingListItemRecipeRefOut,
323 group_id=self.group_id,
324 household_id=self.household_id,
325 )
327 @cached_property 1a
328 def group_shopping_list_recipe_refs( 1a
329 self,
330 ) -> HouseholdRepositoryGeneric[ShoppingListRecipeRefOut, ShoppingListRecipeReference]:
331 return HouseholdRepositoryGeneric( 1IKLcozpdefqghijrksvlwtmnxyub
332 self.session,
333 PK_ID,
334 ShoppingListRecipeReference,
335 ShoppingListRecipeRefOut,
336 group_id=self.group_id,
337 household_id=self.household_id,
338 )
340 @cached_property 1a
341 def shopping_list_multi_purpose_labels( 1a
342 self,
343 ) -> HouseholdRepositoryGeneric[ShoppingListMultiPurposeLabelOut, ShoppingListMultiPurposeLabel]:
344 return HouseholdRepositoryGeneric( 1QIKLcozpdefqghijrksDvlwtmJMFHnxyCEub
345 self.session,
346 PK_ID,
347 ShoppingListMultiPurposeLabel,
348 ShoppingListMultiPurposeLabelOut,
349 group_id=self.group_id,
350 household_id=self.household_id,
351 )
353 @cached_property 1a
354 def group_multi_purpose_labels(self) -> GroupRepositoryGeneric[MultiPurposeLabelOut, MultiPurposeLabel]: 1a
355 return GroupRepositoryGeneric( 2) Q I K L c o z p d e f q g h i j r k s D v l w A B t m J M F H n x y C N E u wb( b
356 self.session, PK_ID, MultiPurposeLabel, MultiPurposeLabelOut, group_id=self.group_id
357 )
359 # ================================================================
360 # Events
362 @cached_property 1a
363 def group_event_notifier(self) -> HouseholdRepositoryGeneric[GroupEventNotifierOut, GroupEventNotifierModel]: 1a
364 return HouseholdRepositoryGeneric( 1SVP2QIKLOTRXYZ!0'cozpdefqghGijrksDvlwABtmJMFHnxyCNEu(b
365 self.session,
366 PK_ID,
367 GroupEventNotifierModel,
368 GroupEventNotifierOut,
369 group_id=self.group_id,
370 household_id=self.household_id,
371 )
373 @cached_property 1a
374 def webhooks(self) -> HouseholdRepositoryGeneric[ReadWebhook, GroupWebhooksModel]: 1a
375 return HouseholdRepositoryGeneric( 1P}cozpdefqghGijrksDvlwABtmJFHnxyNEub
376 self.session, PK_ID, GroupWebhooksModel, ReadWebhook, group_id=self.group_id, household_id=self.household_id
377 )