feat: plural foods and units, and aliases (#2674)

* added plural names and alias tables to foods/units

* updated models to include plural names and aliases

* updated parser to include plural and aliases

* fixed migrations

* fixed recursive models

* added plural abbreviation to migration

* updated parser and display prop

* update displays to use plurals

* fix display edgecase and remove print

* added/updated display tests

* fixed model bug and added parser tests

* added tests for aliases

* added new plural options to data management page

* removed unique constraint

* made base dialog more customizable

* added alias management to food and unit data pages

* removed unused awaits

* 🧹
This commit is contained in:
Michael Genson
2023-11-14 09:39:07 -06:00
committed by GitHub
parent 4b55b838ed
commit d440d51ffe
17 changed files with 1181 additions and 104 deletions

View File

@@ -47,13 +47,17 @@ from .recipe_comments import (
from .recipe_image_types import RecipeImageTypes
from .recipe_ingredient import (
CreateIngredientFood,
CreateIngredientFoodAlias,
CreateIngredientUnit,
CreateIngredientUnitAlias,
IngredientConfidence,
IngredientFood,
IngredientFoodAlias,
IngredientFoodPagination,
IngredientRequest,
IngredientsRequest,
IngredientUnit,
IngredientUnitAlias,
IngredientUnitPagination,
MergeFood,
MergeUnit,
@@ -88,25 +92,6 @@ __all__ = [
"RecipeToolOut",
"RecipeToolResponse",
"RecipeToolSave",
"RecipeTimelineEventCreate",
"RecipeTimelineEventIn",
"RecipeTimelineEventOut",
"RecipeTimelineEventPagination",
"RecipeTimelineEventUpdate",
"TimelineEventImage",
"TimelineEventType",
"RecipeAsset",
"RecipeSettings",
"RecipeShareToken",
"RecipeShareTokenCreate",
"RecipeShareTokenSave",
"RecipeShareTokenSummary",
"RecipeDuplicate",
"RecipeSlug",
"RecipeZipTokenResponse",
"SlugResponse",
"UpdateImageResponse",
"RecipeNote",
"CategoryBase",
"CategoryIn",
"CategoryOut",
@@ -117,12 +102,6 @@ __all__ = [
"TagIn",
"TagOut",
"TagSave",
"RecipeCommentCreate",
"RecipeCommentOut",
"RecipeCommentPagination",
"RecipeCommentSave",
"RecipeCommentUpdate",
"UserBase",
"AssignCategories",
"AssignSettings",
"AssignTags",
@@ -130,28 +109,19 @@ __all__ = [
"ExportBase",
"ExportRecipes",
"ExportTypes",
"IngredientReferences",
"RecipeStep",
"RecipeShareToken",
"RecipeShareTokenCreate",
"RecipeShareTokenSave",
"RecipeShareTokenSummary",
"ScrapeRecipe",
"ScrapeRecipeTest",
"RecipeCommentCreate",
"RecipeCommentOut",
"RecipeCommentPagination",
"RecipeCommentSave",
"RecipeCommentUpdate",
"UserBase",
"RecipeImageTypes",
"Nutrition",
"CreateIngredientFood",
"CreateIngredientUnit",
"IngredientConfidence",
"IngredientFood",
"IngredientFoodPagination",
"IngredientRequest",
"IngredientUnit",
"IngredientUnitPagination",
"IngredientsRequest",
"MergeFood",
"MergeUnit",
"ParsedIngredient",
"RecipeIngredient",
"RecipeIngredientBase",
"RegisteredParser",
"SaveIngredientFood",
"SaveIngredientUnit",
"UnitFoodBase",
"CreateRecipe",
"CreateRecipeBulk",
"CreateRecipeByUrlBulk",
@@ -165,6 +135,44 @@ __all__ = [
"RecipeTagPagination",
"RecipeTool",
"RecipeToolPagination",
"ScrapeRecipe",
"ScrapeRecipeTest",
"IngredientReferences",
"RecipeStep",
"CreateIngredientFood",
"CreateIngredientFoodAlias",
"CreateIngredientUnit",
"CreateIngredientUnitAlias",
"IngredientConfidence",
"IngredientFood",
"IngredientFoodAlias",
"IngredientFoodPagination",
"IngredientRequest",
"IngredientUnit",
"IngredientUnitAlias",
"IngredientUnitPagination",
"IngredientsRequest",
"MergeFood",
"MergeUnit",
"ParsedIngredient",
"RecipeIngredient",
"RecipeIngredientBase",
"RegisteredParser",
"SaveIngredientFood",
"SaveIngredientUnit",
"UnitFoodBase",
"RecipeAsset",
"RecipeTimelineEventCreate",
"RecipeTimelineEventIn",
"RecipeTimelineEventOut",
"RecipeTimelineEventPagination",
"RecipeTimelineEventUpdate",
"TimelineEventImage",
"TimelineEventType",
"RecipeDuplicate",
"RecipeSlug",
"RecipeZipTokenResponse",
"SlugResponse",
"UpdateImageResponse",
"Nutrition",
"RecipeSettings",
"RecipeNote",
]

View File

@@ -33,12 +33,23 @@ def display_fraction(fraction: Fraction):
class UnitFoodBase(MealieModel):
name: str
plural_name: str | None = None
description: str = ""
extras: dict | None = {}
class CreateIngredientFoodAlias(MealieModel):
name: str
class IngredientFoodAlias(CreateIngredientFoodAlias):
class Config:
orm_mode = True
class CreateIngredientFood(UnitFoodBase):
label_id: UUID4 | None = None
aliases: list[CreateIngredientFoodAlias] = []
class SaveIngredientFood(CreateIngredientFood):
@@ -48,10 +59,12 @@ class SaveIngredientFood(CreateIngredientFood):
class IngredientFood(CreateIngredientFood):
id: UUID4
label: MultiPurposeLabelSummary | None = None
aliases: list[IngredientFoodAlias] = []
created_at: datetime.datetime | None
update_at: datetime.datetime | None
_searchable_properties: ClassVar[list[str]] = ["name_normalized"]
_searchable_properties: ClassVar[list[str]] = ["name_normalized", "plural_name_normalized"]
_normalize_search: ClassVar[bool] = True
class Config:
@@ -67,10 +80,21 @@ class IngredientFoodPagination(PaginationBase):
items: list[IngredientFood]
class CreateIngredientUnitAlias(MealieModel):
name: str
class IngredientUnitAlias(CreateIngredientUnitAlias):
class Config:
orm_mode = True
class CreateIngredientUnit(UnitFoodBase):
fraction: bool = True
abbreviation: str = ""
plural_abbreviation: str | None = ""
use_abbreviation: bool = False
aliases: list[CreateIngredientUnitAlias] = []
class SaveIngredientUnit(CreateIngredientUnit):
@@ -79,10 +103,17 @@ class SaveIngredientUnit(CreateIngredientUnit):
class IngredientUnit(CreateIngredientUnit):
id: UUID4
aliases: list[IngredientUnitAlias] = []
created_at: datetime.datetime | None
update_at: datetime.datetime | None
_searchable_properties: ClassVar[list[str]] = ["name_normalized", "abbreviation_normalized"]
_searchable_properties: ClassVar[list[str]] = [
"name_normalized",
"plural_name_normalized",
"abbreviation_normalized",
"plural_abbreviation_normalized",
]
_normalize_search: ClassVar[bool] = True
class Config:
@@ -165,6 +196,36 @@ class RecipeIngredientBase(MealieModel):
return f"{whole_number} {display_fraction(qty)}"
def _format_unit_for_display(self) -> str:
if not self.unit:
return ""
use_plural = self.quantity and self.quantity > 1
unit_val = ""
if self.unit.use_abbreviation:
if use_plural:
unit_val = self.unit.plural_abbreviation or self.unit.abbreviation
else:
unit_val = self.unit.abbreviation
if not unit_val:
if use_plural:
unit_val = self.unit.plural_name or self.unit.name
else:
unit_val = self.unit.name
return unit_val
def _format_food_for_display(self) -> str:
if not self.food:
return ""
use_plural = (not self.quantity) or self.quantity > 1
if use_plural:
return self.food.plural_name or self.food.name
else:
return self.food.name
def _format_display(self) -> str:
components = []
@@ -183,15 +244,15 @@ class RecipeIngredientBase(MealieModel):
components.append(self.note or "")
else:
if self.quantity and self.unit:
components.append(self.unit.abbreviation if self.unit.use_abbreviation else self.unit.name)
components.append(self._format_unit_for_display())
if self.food:
components.append(self.food.name)
components.append(self._format_food_for_display())
if self.note:
components.append(self.note)
return " ".join(components)
return " ".join(components).strip()
class IngredientUnitPagination(PaginationBase):