Coverage for opt/mealie/lib/python3.12/site-packages/mealie/db/models/recipe/tool.py: 89%

34 statements  

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

1from typing import TYPE_CHECKING 

2 

3from pydantic import ConfigDict 

4from slugify import slugify 

5from sqlalchemy import Boolean, Column, ForeignKey, String, Table, UniqueConstraint, orm 

6from sqlalchemy.orm import Mapped, mapped_column 

7 

8from mealie.db.models._model_base import BaseMixins, SqlAlchemyBase 

9from mealie.db.models._model_utils.auto_init import auto_init 

10from mealie.db.models._model_utils.guid import GUID 

11 

12if TYPE_CHECKING: 12 ↛ 13line 12 didn't jump to line 13 because the condition on line 12 was never true

13 from ..group import Group 

14 from ..household import Household 

15 from . import RecipeModel 

16 

17households_to_tools = Table( 

18 "households_to_tools", 

19 SqlAlchemyBase.metadata, 

20 Column("household_id", GUID, ForeignKey("households.id"), index=True), 

21 Column("tool_id", GUID, ForeignKey("tools.id"), index=True), 

22 UniqueConstraint("household_id", "tool_id", name="household_id_tool_id_key"), 

23) 

24 

25recipes_to_tools = Table( 

26 "recipes_to_tools", 

27 SqlAlchemyBase.metadata, 

28 Column("recipe_id", GUID, ForeignKey("recipes.id"), index=True), 

29 Column("tool_id", GUID, ForeignKey("tools.id"), index=True), 

30 UniqueConstraint("recipe_id", "tool_id", name="recipe_id_tool_id_key"), 

31) 

32 

33cookbooks_to_tools = Table( 

34 "cookbooks_to_tools", 

35 SqlAlchemyBase.metadata, 

36 Column("cookbook_id", GUID, ForeignKey("cookbooks.id"), index=True), 

37 Column("tool_id", GUID, ForeignKey("tools.id"), index=True), 

38 UniqueConstraint("cookbook_id", "tool_id", name="cookbook_id_tool_id_key"), 

39) 

40 

41 

42class Tool(SqlAlchemyBase, BaseMixins): 

43 __tablename__ = "tools" 

44 __table_args__ = (UniqueConstraint("slug", "group_id", name="tools_slug_group_id_key"),) 

45 id: Mapped[GUID] = mapped_column(GUID, primary_key=True, default=GUID.generate) 

46 

47 # ID Relationships 

48 group_id: Mapped[GUID] = mapped_column(GUID, ForeignKey("groups.id"), nullable=False, index=True) 

49 group: Mapped["Group"] = orm.relationship("Group", back_populates="tools", foreign_keys=[group_id]) 

50 

51 name: Mapped[str] = mapped_column(String, index=True, nullable=False) 

52 slug: Mapped[str] = mapped_column(String, index=True, nullable=False) 

53 

54 households_with_tool: Mapped[list["Household"]] = orm.relationship( 

55 "Household", secondary=households_to_tools, back_populates="tools_on_hand" 

56 ) 

57 recipes: Mapped[list["RecipeModel"]] = orm.relationship( 

58 "RecipeModel", secondary=recipes_to_tools, back_populates="tools" 

59 ) 

60 

61 model_config = ConfigDict( 

62 exclude={ 

63 "households_with_tool", 

64 } 

65 ) 

66 

67 # Deprecated 

68 on_hand: Mapped[bool | None] = mapped_column(Boolean, default=False) 

69 

70 @auto_init() 

71 def __init__( 

72 self, session: orm.Session, group_id: GUID, name: str, households_with_tool: list[str] | None = None, **_ 

73 ) -> None: 

74 from ..household import Household 

75 

76 self.slug = slugify(name) 

77 

78 if not households_with_tool: 

79 self.households_with_tool = [] 

80 else: 

81 self.households_with_tool = ( 

82 session.query(Household) 

83 .filter(Household.group_id == group_id, Household.slug.in_(households_with_tool)) 

84 .all() 

85 )