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 15:32 +0000

1from collections.abc import Sequence 1a

2from functools import cached_property 1a

3 

4from pydantic import UUID4 1a

5from sqlalchemy import select 1a

6from sqlalchemy.orm import Session 1a

7 

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

72 

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

80 

81PK_ID = "id" 1a

82PK_SLUG = "slug" 1a

83PK_TOKEN = "token" 1a

84PK_GROUP_ID = "group_id" 1a

85PK_HOUSEHOLD_ID = "household_id" 1a

86 

87 

88class RepositoryCategories(GroupRepositoryGeneric[CategoryOut, Category]): 1a

89 def get_empty(self) -> Sequence[Category]: 1a

90 stmt = select(Category).filter(~Category.recipes.any()) 1c

91 

92 return self.session.execute(stmt).scalars().all() 1c

93 

94 

95class RepositoryTags(GroupRepositoryGeneric[TagOut, Tag]): 1a

96 def get_empty(self) -> Sequence[Tag]: 1a

97 stmt = select(Tag).filter(~Tag.recipes.any()) 1c

98 return self.session.execute(stmt).scalars().all() 1c

99 

100 

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 """ 

108 

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 1amcnefgdhijklb

117 self.group_id = group_id 1amcnefgdhijklb

118 self.household_id = household_id 1amcnefgdhijklb

119 

120 # ================================================================ 

121 # Recipe 

122 

123 @cached_property 1a

124 def recipes(self) -> RepositoryRecipes: 1a

125 return RepositoryRecipes( 1cefgdhijklb

126 self.session, PK_SLUG, RecipeModel, Recipe, group_id=self.group_id, household_id=self.household_id 

127 ) 

128 

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) 1cefgdhijklb

132 

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) 1efgdhijklb

136 

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) 1cefgdhijklb

140 

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) 1cefgdhijklb

146 

147 @cached_property 1a

148 def categories(self) -> RepositoryCategories: 1a

149 return RepositoryCategories(self.session, PK_ID, Category, CategoryOut, group_id=self.group_id) 1cb

150 

151 @cached_property 1a

152 def tags(self) -> RepositoryTags: 1a

153 return RepositoryTags(self.session, PK_ID, Tag, TagOut, group_id=self.group_id) 1cb

154 

155 @cached_property 1a

156 def recipe_share_tokens(self) -> GroupRepositoryGeneric[RecipeShareToken, RecipeShareTokenModel]: 1a

157 return GroupRepositoryGeneric( 

158 self.session, PK_ID, RecipeShareTokenModel, RecipeShareToken, group_id=self.group_id 

159 ) 

160 

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( 1efgdhijklb

166 self.session, PK_ID, RecipeTimelineEvent, RecipeTimelineEventOut, group_id=self.group_id 

167 ) 

168 

169 # ================================================================ 

170 # User 

171 

172 @cached_property 1a

173 def users(self) -> RepositoryUsers: 1a

174 return RepositoryUsers(self.session, PK_ID, User, PrivateUser, group_id=self.group_id) 1amcnefgdhijklb

175 

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) 

179 

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) 1efgdhijklb

183 

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 ) 

189 

190 # ================================================================ 

191 # Group 

192 

193 @cached_property 1a

194 def groups(self) -> RepositoryGroup: 1a

195 return RepositoryGroup(self.session, PK_ID, Group, GroupInDB) 1amcefgdhijklb

196 

197 @cached_property 1a

198 def group_preferences(self) -> GroupRepositoryGeneric[ReadGroupPreferences, GroupPreferencesModel]: 1a

199 return GroupRepositoryGeneric( 1amb

200 self.session, PK_GROUP_ID, GroupPreferencesModel, ReadGroupPreferences, group_id=self.group_id 

201 ) 

202 

203 @cached_property 1a

204 def group_exports(self) -> GroupRepositoryGeneric[GroupDataExport, GroupDataExportsModel]: 1a

205 return GroupRepositoryGeneric( 1cb

206 self.session, PK_ID, GroupDataExportsModel, GroupDataExport, group_id=self.group_id 

207 ) 

208 

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) 1cb

212 

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) 

216 

217 # ================================================================ 

218 # Household 

219 

220 @cached_property 1a

221 def households(self) -> RepositoryHousehold: 1a

222 return RepositoryHousehold(self.session, PK_ID, Household, HouseholdInDB, group_id=self.group_id) 1amcefgdhijklb

223 

224 @cached_property 1a

225 def household_preferences(self) -> HouseholdRepositoryGeneric[ReadHouseholdPreferences, HouseholdPreferencesModel]: 1a

226 return HouseholdRepositoryGeneric( 1amb

227 self.session, 

228 PK_HOUSEHOLD_ID, 

229 HouseholdPreferencesModel, 

230 ReadHouseholdPreferences, 

231 group_id=self.group_id, 

232 household_id=self.household_id, 

233 ) 

234 

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 ) 

245 

246 @cached_property 1a

247 def cookbooks(self) -> RepositoryCookbooks: 1a

248 return RepositoryCookbooks( 1cnefgdhijklb

249 self.session, PK_ID, CookBook, ReadCookBook, group_id=self.group_id, household_id=self.household_id 

250 ) 

251 

252 @cached_property 1a

253 def group_invite_tokens(self) -> HouseholdRepositoryGeneric[ReadInviteToken, GroupInviteToken]: 1a

254 return HouseholdRepositoryGeneric( 1cdb

255 self.session, 

256 PK_TOKEN, 

257 GroupInviteToken, 

258 ReadInviteToken, 

259 group_id=self.group_id, 

260 household_id=self.household_id, 

261 ) 

262 

263 @cached_property 1a

264 def group_recipe_actions(self) -> HouseholdRepositoryGeneric[GroupRecipeActionOut, GroupRecipeAction]: 1a

265 return HouseholdRepositoryGeneric( 1cefgdhijklb

266 self.session, 

267 PK_ID, 

268 GroupRecipeAction, 

269 GroupRecipeActionOut, 

270 group_id=self.group_id, 

271 household_id=self.household_id, 

272 ) 

273 

274 # ================================================================ 

275 # Meal Plan 

276 

277 @cached_property 1a

278 def meals(self) -> RepositoryMeals: 1a

279 return RepositoryMeals( 1cefgdhijklb

280 self.session, PK_ID, GroupMealPlan, ReadPlanEntry, group_id=self.group_id, household_id=self.household_id 

281 ) 

282 

283 @cached_property 1a

284 def group_meal_plan_rules(self) -> RepositoryMealPlanRules: 1a

285 return RepositoryMealPlanRules( 1cefgdhijklb

286 self.session, 

287 PK_ID, 

288 GroupMealPlanRules, 

289 PlanRulesOut, 

290 group_id=self.group_id, 

291 household_id=self.household_id, 

292 ) 

293 

294 # ================================================================ 

295 # Shopping List 

296 

297 @cached_property 1a

298 def group_shopping_lists(self) -> RepositoryShoppingList: 1a

299 return RepositoryShoppingList( 1cefgdhijklb

300 self.session, PK_ID, ShoppingList, ShoppingListOut, group_id=self.group_id, household_id=self.household_id 

301 ) 

302 

303 @cached_property 1a

304 def group_shopping_list_item(self) -> HouseholdRepositoryGeneric[ShoppingListItemOut, ShoppingListItem]: 1a

305 return HouseholdRepositoryGeneric( 1cefgdhijklb

306 self.session, 

307 PK_ID, 

308 ShoppingListItem, 

309 ShoppingListItemOut, 

310 group_id=self.group_id, 

311 household_id=self.household_id, 

312 ) 

313 

314 @cached_property 1a

315 def group_shopping_list_item_references( 1a

316 self, 

317 ) -> HouseholdRepositoryGeneric[ShoppingListItemRecipeRefOut, ShoppingListItemRecipeReference]: 

318 return HouseholdRepositoryGeneric( 1cefgdhijklb

319 self.session, 

320 PK_ID, 

321 ShoppingListItemRecipeReference, 

322 ShoppingListItemRecipeRefOut, 

323 group_id=self.group_id, 

324 household_id=self.household_id, 

325 ) 

326 

327 @cached_property 1a

328 def group_shopping_list_recipe_refs( 1a

329 self, 

330 ) -> HouseholdRepositoryGeneric[ShoppingListRecipeRefOut, ShoppingListRecipeReference]: 

331 return HouseholdRepositoryGeneric( 1cefgdhijklb

332 self.session, 

333 PK_ID, 

334 ShoppingListRecipeReference, 

335 ShoppingListRecipeRefOut, 

336 group_id=self.group_id, 

337 household_id=self.household_id, 

338 ) 

339 

340 @cached_property 1a

341 def shopping_list_multi_purpose_labels( 1a

342 self, 

343 ) -> HouseholdRepositoryGeneric[ShoppingListMultiPurposeLabelOut, ShoppingListMultiPurposeLabel]: 

344 return HouseholdRepositoryGeneric( 1efgdhijklb

345 self.session, 

346 PK_ID, 

347 ShoppingListMultiPurposeLabel, 

348 ShoppingListMultiPurposeLabelOut, 

349 group_id=self.group_id, 

350 household_id=self.household_id, 

351 ) 

352 

353 @cached_property 1a

354 def group_multi_purpose_labels(self) -> GroupRepositoryGeneric[MultiPurposeLabelOut, MultiPurposeLabel]: 1a

355 return GroupRepositoryGeneric( 1cefgdhijklb

356 self.session, PK_ID, MultiPurposeLabel, MultiPurposeLabelOut, group_id=self.group_id 

357 ) 

358 

359 # ================================================================ 

360 # Events 

361 

362 @cached_property 1a

363 def group_event_notifier(self) -> HouseholdRepositoryGeneric[GroupEventNotifierOut, GroupEventNotifierModel]: 1a

364 return HouseholdRepositoryGeneric( 1mcefgdhijklb

365 self.session, 

366 PK_ID, 

367 GroupEventNotifierModel, 

368 GroupEventNotifierOut, 

369 group_id=self.group_id, 

370 household_id=self.household_id, 

371 ) 

372 

373 @cached_property 1a

374 def webhooks(self) -> HouseholdRepositoryGeneric[ReadWebhook, GroupWebhooksModel]: 1a

375 return HouseholdRepositoryGeneric( 1cefgdhijklb

376 self.session, PK_ID, GroupWebhooksModel, ReadWebhook, group_id=self.group_id, household_id=self.household_id 

377 )