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.db.models.recipe.tool import Tool
from mealie.schema.cookbook.cookbook import ReadCookBook from mealie.schema.cookbook.cookbook import ReadCookBook
from mealie.schema.recipe import Recipe 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.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 from .repository_generic import RepositoryGeneric
@ -139,7 +145,7 @@ class RepositoryRecipes(RepositoryGeneric[Recipe, RecipeModel]):
categories: list[UUID4 | str] | None = None, categories: list[UUID4 | str] | None = None,
tags: list[UUID4 | str] | None = None, tags: list[UUID4 | str] | None = None,
tools: list[UUID4 | str] | None = None, tools: list[UUID4 | str] | None = None,
) -> RecipePagination: ) -> PaginationBase[RecipeSummary]:
q = self.session.query(self.model) q = self.session.query(self.model)
args = [ args = [
@ -150,6 +156,10 @@ class RepositoryRecipes(RepositoryGeneric[Recipe, RecipeModel]):
if load_food: if load_food:
args.append(joinedload(RecipeModel.recipe_ingredient).options(joinedload(RecipeIngredient.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) q = q.options(*args)
@ -201,12 +211,13 @@ class RepositoryRecipes(RepositoryGeneric[Recipe, RecipeModel]):
self.session.rollback() self.session.rollback()
raise e raise e
return RecipePagination( items = [item_class.from_orm(item) for item in data]
return PaginationBase(
page=pagination.page, page=pagination.page,
per_page=pagination.per_page, per_page=pagination.per_page,
total=count, total=count,
total_pages=total_pages, total_pages=total_pages,
items=data, items=items,
) )
def get_by_categories(self, categories: list[RecipeCategory]) -> list[RecipeSummary]: 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.routes._base.routers import MealieCrudRoute, UserAPIRouter
from mealie.schema.cookbook.cookbook import ReadCookBook from mealie.schema.cookbook.cookbook import ReadCookBook
from mealie.schema.recipe import Recipe, RecipeImageTypes, ScrapeRecipe 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_asset import RecipeAsset
from mealie.schema.recipe.recipe_ingredient import RecipeIngredient from mealie.schema.recipe.recipe_ingredient import RecipeIngredient
from mealie.schema.recipe.recipe_scraper import ScrapeRecipeTest from mealie.schema.recipe.recipe_scraper import ScrapeRecipeTest
from mealie.schema.recipe.recipe_settings import RecipeSettings from mealie.schema.recipe.recipe_settings import RecipeSettings
from mealie.schema.recipe.recipe_step import RecipeStep from mealie.schema.recipe.recipe_step import RecipeStep
from mealie.schema.recipe.request_helpers import RecipeDuplicate, RecipeZipTokenResponse, UpdateImageResponse 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.schema.response.responses import ErrorResponse
from mealie.services import urls from mealie.services import urls
from mealie.services.event_bus_service.event_types import ( from mealie.services.event_bus_service.event_types import (
@ -232,7 +240,7 @@ class RecipeController(BaseRecipeController):
# ================================================================================================================== # ==================================================================================================================
# CRUD Operations # CRUD Operations
@router.get("", response_model=RecipePagination) @router.get("", response_model=PaginationBase[RecipeSummary | RecipeSummaryWithIngredients])
def get_all( def get_all(
self, self,
request: Request, request: Request,

View File

@ -91,8 +91,6 @@ class RecipeSummary(MealieModel):
rating: int | None rating: int | None
org_url: str | None = Field(None, alias="orgURL") org_url: str | None = Field(None, alias="orgURL")
recipe_ingredient: list[RecipeIngredient] | None = []
date_added: datetime.date | None date_added: datetime.date | None
date_updated: datetime.datetime | None date_updated: datetime.datetime | None
@ -103,29 +101,9 @@ class RecipeSummary(MealieModel):
class Config: class Config:
orm_mode = True 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) class RecipeSummaryWithIngredients(RecipeSummary):
def validate_categories(cats: list[Any]): # type: ignore recipe_ingredient: list[RecipeIngredient] | None = []
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 RecipePaginationQuery(PaginationQuery): class RecipePaginationQuery(PaginationQuery):
@ -205,8 +183,33 @@ class Recipe(RecipeSummary):
return recipe_ingredient 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 from mealie.schema.recipe.recipe_ingredient import RecipeIngredient # noqa: E402
RecipeSummary.update_forward_refs() RecipeSummary.update_forward_refs()
RecipeSummaryWithIngredients.update_forward_refs()
Recipe.update_forward_refs() Recipe.update_forward_refs()