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.10.6, created at 2025-11-25 17:29 +0000

1import datetime 1a

2from enum import Enum 1a

3from typing import Annotated 1a

4 

5import sqlalchemy as sa 1a

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

7 

8from mealie.core.root_logger import get_logger 1a

9from mealie.db.models.recipe import RecipeModel 1a

10from mealie.schema._mealie import MealieModel 1a

11from mealie.schema.response.pagination import PaginationBase 1a

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

13 

14logger = get_logger() 1a

15 

16 

17class PlanRulesDay(str, Enum): 1a

18 monday = "monday" 1a

19 tuesday = "tuesday" 1a

20 wednesday = "wednesday" 1a

21 thursday = "thursday" 1a

22 friday = "friday" 1a

23 saturday = "saturday" 1a

24 sunday = "sunday" 1a

25 unset = "unset" 1a

26 

27 @staticmethod 1a

28 def from_date(date: datetime.date): 1a

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

30 try: 1IdCefghijklmnopbqrstuvwDEc

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

32 except KeyError: 

33 return PlanRulesDay.unset 

34 

35 

36class PlanRulesType(str, Enum): 1a

37 breakfast = "breakfast" 1a

38 lunch = "lunch" 1a

39 dinner = "dinner" 1a

40 side = "side" 1a

41 unset = "unset" 1a

42 

43 

44class PlanRulesCreate(MealieModel): 1a

45 day: PlanRulesDay = PlanRulesDay.unset 1a

46 entry_type: PlanRulesType = PlanRulesType.unset 1a

47 query_filter_string: str = "" 1a

48 

49 @field_validator("query_filter_string") 1a

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

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) 1HdefghijklmnoypbqrsztuvwxABc

54 

55 try: 1HdefghijklmnoypbqrsztuvwxABc

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

57 except Exception as e: 1bxc

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

59 

60 return value 1HdefghijklmnoypbqrsztuvwxABc

61 

62 

63class PlanRulesSave(PlanRulesCreate): 1a

64 group_id: UUID4 1a

65 household_id: UUID4 1a

66 

67 

68class PlanRulesOut(PlanRulesSave): 1a

69 id: UUID4 1a

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

71 

72 model_config = ConfigDict(from_attributes=True) 1a

73 

74 @field_validator("query_filter_string") 1a

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

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

77 return value 1dCefghijklmnoypbFqrsztuvGwDxABEc

78 

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

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

81 try: 1dCefghijklmnoypbFqrsztuvGwDxABEc

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

83 builder = QueryFilterBuilder(query_filter_string) 1dCefghijklmnoypbFqrsztuvGwDxABEc

84 return builder.as_json_model() 1dCefghijklmnoypbFqrsztuvGwDxABEc

85 except Exception: 

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

87 return QueryFilterJSON() 

88 

89 

90class PlanRulesPagination(PaginationBase): 1a

91 items: list[PlanRulesOut] 1a