mirror of
				https://github.com/mealie-recipes/mealie.git
				synced 2025-10-31 10:13:32 -04:00 
			
		
		
		
	chore: Optimize Loads on Queries (#4220)
Co-authored-by: Hayden <64056131+hay-kot@users.noreply.github.com>
This commit is contained in:
		| @@ -7,7 +7,7 @@ import sqlalchemy as sa | |||||||
| from pydantic import UUID4 | from pydantic import UUID4 | ||||||
| from slugify import slugify | from slugify import slugify | ||||||
| from sqlalchemy.exc import IntegrityError | from sqlalchemy.exc import IntegrityError | ||||||
| from sqlalchemy.orm import InstrumentedAttribute, joinedload | from sqlalchemy.orm import InstrumentedAttribute | ||||||
| from typing_extensions import Self | from typing_extensions import Self | ||||||
|  |  | ||||||
| from mealie.db.models.recipe.category import Category | from mealie.db.models.recipe.category import Category | ||||||
| @@ -165,15 +165,6 @@ class RepositoryRecipes(HouseholdRepositoryGeneric[Recipe, RecipeModel]): | |||||||
|         pagination_result = pagination.model_copy() |         pagination_result = pagination.model_copy() | ||||||
|         q = sa.select(self.model) |         q = sa.select(self.model) | ||||||
|  |  | ||||||
|         args = [ |  | ||||||
|             joinedload(RecipeModel.recipe_category), |  | ||||||
|             joinedload(RecipeModel.tags), |  | ||||||
|             joinedload(RecipeModel.tools), |  | ||||||
|             joinedload(RecipeModel.user), |  | ||||||
|         ] |  | ||||||
|  |  | ||||||
|         q = q.options(*args) |  | ||||||
|  |  | ||||||
|         fltr = self._filter_builder() |         fltr = self._filter_builder() | ||||||
|         q = q.filter_by(**fltr) |         q = q.filter_by(**fltr) | ||||||
|  |  | ||||||
| @@ -212,6 +203,8 @@ class RepositoryRecipes(HouseholdRepositoryGeneric[Recipe, RecipeModel]): | |||||||
|  |  | ||||||
|         q, count, total_pages = self.add_pagination_to_query(q, pagination_result) |         q, count, total_pages = self.add_pagination_to_query(q, pagination_result) | ||||||
|  |  | ||||||
|  |         # Apply options late, so they do not get used for counting | ||||||
|  |         q = q.options(*RecipeSummary.loader_options()) | ||||||
|         try: |         try: | ||||||
|             data = self.session.execute(q).scalars().unique().all() |             data = self.session.execute(q).scalars().unique().all() | ||||||
|         except Exception as e: |         except Exception as e: | ||||||
|   | |||||||
| @@ -14,6 +14,7 @@ from mealie.db.models.household import ( | |||||||
|     ShoppingListRecipeReference, |     ShoppingListRecipeReference, | ||||||
| ) | ) | ||||||
| from mealie.db.models.recipe import IngredientFoodModel, RecipeModel | from mealie.db.models.recipe import IngredientFoodModel, RecipeModel | ||||||
|  | from mealie.db.models.users.users import User | ||||||
| from mealie.schema._mealie import MealieModel | from mealie.schema._mealie import MealieModel | ||||||
| from mealie.schema._mealie.mealie_model import UpdatedAtField | from mealie.schema._mealie.mealie_model import UpdatedAtField | ||||||
| from mealie.schema._mealie.types import NoneFloat | from mealie.schema._mealie.types import NoneFloat | ||||||
| @@ -137,7 +138,9 @@ class ShoppingListItemOut(ShoppingListItemBase): | |||||||
|             joinedload(ShoppingListItem.label), |             joinedload(ShoppingListItem.label), | ||||||
|             joinedload(ShoppingListItem.unit), |             joinedload(ShoppingListItem.unit), | ||||||
|             selectinload(ShoppingListItem.recipe_references), |             selectinload(ShoppingListItem.recipe_references), | ||||||
|             joinedload(ShoppingListItem.shopping_list).joinedload(ShoppingList.user), |             joinedload(ShoppingListItem.shopping_list) | ||||||
|  |             .joinedload(ShoppingList.user) | ||||||
|  |             .load_only(User.household_id, User.group_id), | ||||||
|         ] |         ] | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -232,7 +235,7 @@ class ShoppingListSummary(ShoppingListSave): | |||||||
|             .joinedload(ShoppingListRecipeReference.recipe) |             .joinedload(ShoppingListRecipeReference.recipe) | ||||||
|             .joinedload(RecipeModel.tools), |             .joinedload(RecipeModel.tools), | ||||||
|             selectinload(ShoppingList.label_settings).joinedload(ShoppingListMultiPurposeLabel.label), |             selectinload(ShoppingList.label_settings).joinedload(ShoppingListMultiPurposeLabel.label), | ||||||
|             joinedload(ShoppingList.user), |             joinedload(ShoppingList.user).load_only(User.household_id, User.group_id), | ||||||
|         ] |         ] | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -279,7 +282,7 @@ class ShoppingListOut(ShoppingListUpdate): | |||||||
|             .joinedload(ShoppingListRecipeReference.recipe) |             .joinedload(ShoppingListRecipeReference.recipe) | ||||||
|             .joinedload(RecipeModel.tools), |             .joinedload(RecipeModel.tools), | ||||||
|             selectinload(ShoppingList.label_settings).joinedload(ShoppingListMultiPurposeLabel.label), |             selectinload(ShoppingList.label_settings).joinedload(ShoppingListMultiPurposeLabel.label), | ||||||
|             joinedload(ShoppingList.user), |             joinedload(ShoppingList.user).load_only(User.household_id, User.group_id), | ||||||
|         ] |         ] | ||||||
|  |  | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,5 +1,9 @@ | |||||||
| from pydantic import UUID4, ConfigDict | from pydantic import UUID4, ConfigDict | ||||||
|  | from sqlalchemy.orm import joinedload | ||||||
|  | from sqlalchemy.orm.interfaces import LoaderOption | ||||||
|  |  | ||||||
|  | from mealie.db.models.household.household import Household | ||||||
|  | from mealie.db.models.household.preferences import HouseholdPreferencesModel | ||||||
| from mealie.schema._mealie import MealieModel | from mealie.schema._mealie import MealieModel | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -27,3 +31,9 @@ class SaveHouseholdPreferences(UpdateHouseholdPreferences): | |||||||
| class ReadHouseholdPreferences(CreateHouseholdPreferences): | class ReadHouseholdPreferences(CreateHouseholdPreferences): | ||||||
|     id: UUID4 |     id: UUID4 | ||||||
|     model_config = ConfigDict(from_attributes=True) |     model_config = ConfigDict(from_attributes=True) | ||||||
|  |  | ||||||
|  |     @classmethod | ||||||
|  |     def loader_options(cls) -> list[LoaderOption]: | ||||||
|  |         return [ | ||||||
|  |             joinedload(HouseholdPreferencesModel.household).load_only(Household.group_id), | ||||||
|  |         ] | ||||||
|   | |||||||
| @@ -10,6 +10,7 @@ from sqlalchemy.orm.interfaces import LoaderOption | |||||||
|  |  | ||||||
| from mealie.db.models.household import GroupMealPlan | from mealie.db.models.household import GroupMealPlan | ||||||
| from mealie.db.models.recipe import RecipeModel | from mealie.db.models.recipe import RecipeModel | ||||||
|  | from mealie.db.models.users.users import User | ||||||
| from mealie.schema._mealie import MealieModel | from mealie.schema._mealie import MealieModel | ||||||
| from mealie.schema.recipe.recipe import RecipeSummary | from mealie.schema.recipe.recipe import RecipeSummary | ||||||
| from mealie.schema.response.pagination import PaginationBase | from mealie.schema.response.pagination import PaginationBase | ||||||
| @@ -66,7 +67,7 @@ class ReadPlanEntry(UpdatePlanEntry): | |||||||
|             selectinload(GroupMealPlan.recipe).joinedload(RecipeModel.recipe_category), |             selectinload(GroupMealPlan.recipe).joinedload(RecipeModel.recipe_category), | ||||||
|             selectinload(GroupMealPlan.recipe).joinedload(RecipeModel.tags), |             selectinload(GroupMealPlan.recipe).joinedload(RecipeModel.tags), | ||||||
|             selectinload(GroupMealPlan.recipe).joinedload(RecipeModel.tools), |             selectinload(GroupMealPlan.recipe).joinedload(RecipeModel.tools), | ||||||
|             selectinload(GroupMealPlan.user), |             selectinload(GroupMealPlan.user).load_only(User.household_id), | ||||||
|         ] |         ] | ||||||
|  |  | ||||||
|  |  | ||||||
|   | |||||||
| @@ -14,6 +14,7 @@ from sqlalchemy.orm import Session, joinedload, selectinload | |||||||
| from sqlalchemy.orm.interfaces import LoaderOption | from sqlalchemy.orm.interfaces import LoaderOption | ||||||
|  |  | ||||||
| from mealie.core.config import get_app_dirs | from mealie.core.config import get_app_dirs | ||||||
|  | from mealie.db.models.users.users import User | ||||||
| from mealie.schema._mealie import MealieModel, SearchType | from mealie.schema._mealie import MealieModel, SearchType | ||||||
| from mealie.schema._mealie.mealie_model import UpdatedAtField | from mealie.schema._mealie.mealie_model import UpdatedAtField | ||||||
| from mealie.schema.response.pagination import PaginationBase | from mealie.schema.response.pagination import PaginationBase | ||||||
| @@ -121,6 +122,15 @@ class RecipeSummary(MealieModel): | |||||||
|  |  | ||||||
|         return val |         return val | ||||||
|  |  | ||||||
|  |     @classmethod | ||||||
|  |     def loader_options(cls) -> list[LoaderOption]: | ||||||
|  |         return [ | ||||||
|  |             joinedload(RecipeModel.recipe_category), | ||||||
|  |             joinedload(RecipeModel.tags), | ||||||
|  |             joinedload(RecipeModel.tools), | ||||||
|  |             joinedload(RecipeModel.user).load_only(User.household_id), | ||||||
|  |         ] | ||||||
|  |  | ||||||
|  |  | ||||||
| class RecipePagination(PaginationBase): | class RecipePagination(PaginationBase): | ||||||
|     items: list[RecipeSummary] |     items: list[RecipeSummary] | ||||||
|   | |||||||
| @@ -9,6 +9,7 @@ from sqlalchemy.orm.interfaces import LoaderOption | |||||||
|  |  | ||||||
| from mealie.core.config import get_app_dirs | from mealie.core.config import get_app_dirs | ||||||
| from mealie.db.models.recipe.recipe_timeline import RecipeTimelineEvent | from mealie.db.models.recipe.recipe_timeline import RecipeTimelineEvent | ||||||
|  | from mealie.db.models.users.users import User | ||||||
| from mealie.schema._mealie import MealieModel | from mealie.schema._mealie import MealieModel | ||||||
| from mealie.schema._mealie.mealie_model import UpdatedAtField | from mealie.schema._mealie.mealie_model import UpdatedAtField | ||||||
| from mealie.schema.recipe.recipe import Recipe | from mealie.schema.recipe.recipe import Recipe | ||||||
| @@ -67,7 +68,7 @@ class RecipeTimelineEventOut(RecipeTimelineEventCreate): | |||||||
|     def loader_options(cls) -> list[LoaderOption]: |     def loader_options(cls) -> list[LoaderOption]: | ||||||
|         return [ |         return [ | ||||||
|             joinedload(RecipeTimelineEvent.recipe), |             joinedload(RecipeTimelineEvent.recipe), | ||||||
|             joinedload(RecipeTimelineEvent.user), |             joinedload(RecipeTimelineEvent.user).load_only(User.household_id, User.group_id), | ||||||
|         ] |         ] | ||||||
|  |  | ||||||
|     @classmethod |     @classmethod | ||||||
|   | |||||||
| @@ -8,7 +8,9 @@ from sqlalchemy.orm import joinedload, selectinload | |||||||
| from sqlalchemy.orm.interfaces import LoaderOption | from sqlalchemy.orm.interfaces import LoaderOption | ||||||
|  |  | ||||||
| from mealie.core.config import get_app_dirs, get_app_settings | from mealie.core.config import get_app_dirs, get_app_settings | ||||||
|  | from mealie.db.models.recipe.recipe import RecipeModel | ||||||
| from mealie.db.models.users import User | from mealie.db.models.users import User | ||||||
|  | from mealie.db.models.users.user_to_recipe import UserToRecipe | ||||||
| from mealie.db.models.users.users import AuthMethod, LongLiveToken | from mealie.db.models.users.users import AuthMethod, LongLiveToken | ||||||
| from mealie.schema._mealie import MealieModel | from mealie.schema._mealie import MealieModel | ||||||
| from mealie.schema.group.group_preferences import ReadGroupPreferences | from mealie.schema.group.group_preferences import ReadGroupPreferences | ||||||
| @@ -88,6 +90,12 @@ class UserRatingUpdate(MealieModel): | |||||||
| class UserRatingOut(UserRatingCreate): | class UserRatingOut(UserRatingCreate): | ||||||
|     id: UUID4 |     id: UUID4 | ||||||
|  |  | ||||||
|  |     @classmethod | ||||||
|  |     def loader_options(cls) -> list[LoaderOption]: | ||||||
|  |         return [ | ||||||
|  |             joinedload(UserToRecipe.recipe).joinedload(RecipeModel.user).load_only(User.household_id, User.group_id) | ||||||
|  |         ] | ||||||
|  |  | ||||||
|  |  | ||||||
| class UserRatings(BaseModel, Generic[DataT]): | class UserRatings(BaseModel, Generic[DataT]): | ||||||
|     ratings: list[DataT] |     ratings: list[DataT] | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user