Skip to content

Commit

Permalink
fix: all recipes performance regressions (#2062)
Browse files Browse the repository at this point in the history
* Move recipe validations from RecipeSummary to Recipe

* fix RepositoryRecipes loading recipes with ingredients even when load_food is False

* Add eager loading of ingredient units

* fix trying to instantiate PaginationBase with concrete type not being valid for mypy

* fix linting issue
  • Loading branch information
fleshgolem authored Jan 29, 2023
1 parent 2340ee5 commit 49bd420
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 31 deletions.
21 changes: 16 additions & 5 deletions mealie/repos/repository_recipes.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,15 @@
from mealie.db.models.recipe.tool import Tool
from mealie.schema.cookbook.cookbook import ReadCookBook
from mealie.schema.recipe import Recipe
from mealie.schema.recipe.recipe import RecipeCategory, RecipePagination, RecipeSummary, RecipeTag, RecipeTool
from mealie.schema.recipe.recipe import (
RecipeCategory,
RecipeSummary,
RecipeSummaryWithIngredients,
RecipeTag,
RecipeTool,
)
from mealie.schema.recipe.recipe_category import CategoryBase, TagBase
from mealie.schema.response.pagination import PaginationQuery
from mealie.schema.response.pagination import PaginationBase, PaginationQuery

from .repository_generic import RepositoryGeneric

Expand Down Expand Up @@ -139,7 +145,7 @@ def page_all(
categories: list[UUID4 | str] | None = None,
tags: list[UUID4 | str] | None = None,
tools: list[UUID4 | str] | None = None,
) -> RecipePagination:
) -> PaginationBase[RecipeSummary]:
q = self.session.query(self.model)

args = [
Expand All @@ -150,6 +156,10 @@ def page_all(

if load_food:
args.append(joinedload(RecipeModel.recipe_ingredient).options(joinedload(RecipeIngredient.food)))
args.append(joinedload(RecipeModel.recipe_ingredient).options(joinedload(RecipeIngredient.unit)))
item_class = RecipeSummaryWithIngredients
else:
item_class = RecipeSummary

q = q.options(*args)

Expand Down Expand Up @@ -201,12 +211,13 @@ def page_all(
self.session.rollback()
raise e

return RecipePagination(
items = [item_class.from_orm(item) for item in data]
return PaginationBase(
page=pagination.page,
per_page=pagination.per_page,
total=count,
total_pages=total_pages,
items=data,
items=items,
)

def get_by_categories(self, categories: list[RecipeCategory]) -> list[RecipeSummary]:
Expand Down
12 changes: 10 additions & 2 deletions mealie/routes/recipe/recipe_crud_routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,21 @@
from mealie.routes._base.routers import MealieCrudRoute, UserAPIRouter
from mealie.schema.cookbook.cookbook import ReadCookBook
from mealie.schema.recipe import Recipe, RecipeImageTypes, ScrapeRecipe
from mealie.schema.recipe.recipe import CreateRecipe, CreateRecipeByUrlBulk, RecipePagination, RecipePaginationQuery
from mealie.schema.recipe.recipe import (
CreateRecipe,
CreateRecipeByUrlBulk,
RecipePagination,
RecipePaginationQuery,
RecipeSummary,
RecipeSummaryWithIngredients,
)
from mealie.schema.recipe.recipe_asset import RecipeAsset
from mealie.schema.recipe.recipe_ingredient import RecipeIngredient
from mealie.schema.recipe.recipe_scraper import ScrapeRecipeTest
from mealie.schema.recipe.recipe_settings import RecipeSettings
from mealie.schema.recipe.recipe_step import RecipeStep
from mealie.schema.recipe.request_helpers import RecipeDuplicate, RecipeZipTokenResponse, UpdateImageResponse
from mealie.schema.response import PaginationBase
from mealie.schema.response.responses import ErrorResponse
from mealie.services import urls
from mealie.services.event_bus_service.event_types import (
Expand Down Expand Up @@ -232,7 +240,7 @@ def create_recipe_from_zip(self, temp_path=Depends(temporary_zip_path), archive:
# ==================================================================================================================
# CRUD Operations

@router.get("", response_model=RecipePagination)
@router.get("", response_model=PaginationBase[RecipeSummary | RecipeSummaryWithIngredients])
def get_all(
self,
request: Request,
Expand Down
51 changes: 27 additions & 24 deletions mealie/schema/recipe/recipe.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,6 @@ class RecipeSummary(MealieModel):
rating: int | None
org_url: str | None = Field(None, alias="orgURL")

recipe_ingredient: list[RecipeIngredient] | None = []

date_added: datetime.date | None
date_updated: datetime.datetime | None

Expand All @@ -103,29 +101,9 @@ class RecipeSummary(MealieModel):
class Config:
orm_mode = True

@validator("tags", always=True, pre=True, allow_reuse=True)
def validate_tags(cats: list[Any]): # type: ignore
if isinstance(cats, list) and cats and isinstance(cats[0], str):
return [RecipeTag(id=uuid4(), name=c, slug=slugify(c)) for c in cats]
return cats

@validator("recipe_category", always=True, pre=True, allow_reuse=True)
def validate_categories(cats: list[Any]): # type: ignore
if isinstance(cats, list) and cats and isinstance(cats[0], str):
return [RecipeCategory(id=uuid4(), name=c, slug=slugify(c)) for c in cats]
return cats

@validator("group_id", always=True, pre=True, allow_reuse=True)
def validate_group_id(group_id: Any):
if isinstance(group_id, int):
return uuid4()
return group_id

@validator("user_id", always=True, pre=True, allow_reuse=True)
def validate_user_id(user_id: Any):
if isinstance(user_id, int):
return uuid4()
return user_id
class RecipeSummaryWithIngredients(RecipeSummary):
recipe_ingredient: list[RecipeIngredient] | None = []


class RecipePaginationQuery(PaginationQuery):
Expand Down Expand Up @@ -205,8 +183,33 @@ def validate_ingredients(recipe_ingredient, values):

return recipe_ingredient

@validator("tags", always=True, pre=True, allow_reuse=True)
def validate_tags(cats: list[Any]): # type: ignore
if isinstance(cats, list) and cats and isinstance(cats[0], str):
return [RecipeTag(id=uuid4(), name=c, slug=slugify(c)) for c in cats]
return cats

@validator("recipe_category", always=True, pre=True, allow_reuse=True)
def validate_categories(cats: list[Any]): # type: ignore
if isinstance(cats, list) and cats and isinstance(cats[0], str):
return [RecipeCategory(id=uuid4(), name=c, slug=slugify(c)) for c in cats]
return cats

@validator("group_id", always=True, pre=True, allow_reuse=True)
def validate_group_id(group_id: Any):
if isinstance(group_id, int):
return uuid4()
return group_id

@validator("user_id", always=True, pre=True, allow_reuse=True)
def validate_user_id(user_id: Any):
if isinstance(user_id, int):
return uuid4()
return user_id


from mealie.schema.recipe.recipe_ingredient import RecipeIngredient # noqa: E402

RecipeSummary.update_forward_refs()
RecipeSummaryWithIngredients.update_forward_refs()
Recipe.update_forward_refs()

0 comments on commit 49bd420

Please sign in to comment.