Coverage for opt/mealie/lib/python3.12/site-packages/mealie/schema/meal_plan/plan_rules.py: 92%

65 statements  

« prev     ^ index     » next       coverage.py v7.15.2, created at 2026-10-07 03:04 +0000

1import datetime 

2from enum import Enum 

3from typing import Annotated 

4 

5import sqlalchemy as sa 

6from pydantic import UUID4, ConfigDict, Field, ValidationInfo, field_validator 

7 

8from mealie.core.root_logger import get_logger 

9from mealie.db.models.recipe import RecipeModel 

10from mealie.schema._mealie import MealieModel 

11from mealie.schema.response.pagination import PaginationBase 

12from mealie.schema.response.query_filter import QueryFilterBuilder, QueryFilterJSON 

13 

14logger = get_logger() 

15 

16 

17class PlanRulesDay(str, Enum): 

18 monday = "monday" 

19 tuesday = "tuesday" 

20 wednesday = "wednesday" 

21 thursday = "thursday" 

22 friday = "friday" 

23 saturday = "saturday" 

24 sunday = "sunday" 

25 unset = "unset" 

26 

27 @staticmethod 

28 def from_date(date: datetime.date): 

29 """Returns the enum value for the date passed in""" 

30 try: 

31 return PlanRulesDay[(date.strftime("%A").lower())] 

32 except KeyError: 

33 return PlanRulesDay.unset 

34 

35 

36class PlanRulesType(str, Enum): 

37 breakfast = "breakfast" 

38 lunch = "lunch" 

39 dinner = "dinner" 

40 side = "side" 

41 unset = "unset" 

42 

43 

44class PlanRulesCreate(MealieModel): 

45 day: PlanRulesDay = PlanRulesDay.unset 

46 entry_type: PlanRulesType = PlanRulesType.unset 

47 query_filter_string: str = "" 

48 

49 @field_validator("query_filter_string") 

50 def validate_query_filter_string(cls, value: str) -> str: 

51 # The query filter builder does additional validations while building the 

52 # database query, so we make sure constructing the query is successful 

53 builder = QueryFilterBuilder(value) 

54 

55 try: 

56 builder.filter_query(sa.select(RecipeModel), RecipeModel) 

57 except Exception as e: 

58 raise ValueError("Invalid query filter string") from e 

59 

60 return value 

61 

62 

63class PlanRulesSave(PlanRulesCreate): 

64 group_id: UUID4 

65 household_id: UUID4 

66 

67 

68class PlanRulesOut(PlanRulesSave): 

69 id: UUID4 

70 query_filter: Annotated[QueryFilterJSON, Field(validate_default=True)] = None # type: ignore 

71 

72 model_config = ConfigDict(from_attributes=True) 

73 

74 @field_validator("query_filter_string") 

75 def validate_query_filter_string(value: str) -> str: 

76 # Skip validation since we are not updating the query filter string 

77 return value 

78 

79 @field_validator("query_filter", mode="before") 

80 def validate_query_filter(cls, _, info: ValidationInfo) -> QueryFilterJSON: 

81 try: 

82 query_filter_string: str = info.data.get("query_filter_string") or "" 

83 builder = QueryFilterBuilder(query_filter_string) 

84 return builder.as_json_model() 

85 except Exception: 

86 logger.exception(f"Invalid query filter string: {query_filter_string}") 

87 return QueryFilterJSON() 

88 

89 

90class PlanRulesPagination(PaginationBase): 

91 items: list[PlanRulesOut]