fix: all recipes performance regressions (#2062)

* 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
This commit is contained in:
Sören 2023-01-29 01:50:26 +01:00 committed by GitHub
parent 2340ee5bfb
commit 49bd420c10
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 53 additions and 31 deletions

View File

@ -16,9 +16,15 @@ from mealie.db.models.recipe.tag import Tag
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
@ -139,7 +145,7 @@ class RepositoryRecipes(RepositoryGeneric[Recipe, RecipeModel]):
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 = [
@ -150,6 +156,10 @@ class RepositoryRecipes(RepositoryGeneric[Recipe, RecipeModel]):
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)
@ -201,12 +211,13 @@ class RepositoryRecipes(RepositoryGeneric[Recipe, RecipeModel]):
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]:

View File

@ -25,13 +25,21 @@ from mealie.routes._base.mixins import HttpRepo
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 (
@ -232,7 +240,7 @@ class RecipeController(BaseRecipeController):
# ==================================================================================================================
# CRUD Operations
@router.get("", response_model=RecipePagination)
@router.get("", response_model=PaginationBase[RecipeSummary | RecipeSummaryWithIngredients])
def get_all(
self,
request: Request,

View File

@ -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
@ -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):
@ -205,8 +183,33 @@ class Recipe(RecipeSummary):
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()