Skip to content

Commit

Permalink
rewrite all db models to sqla 2.0 mapping api
Browse files Browse the repository at this point in the history
  • Loading branch information
fleshgolem committed Jan 27, 2023
1 parent ac86f16 commit 07e14b2
Show file tree
Hide file tree
Showing 31 changed files with 594 additions and 397 deletions.
11 changes: 3 additions & 8 deletions mealie/db/db_setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,9 @@ def sql_global_init(db_url: str):
if "sqlite" in db_url:
connect_args["check_same_thread"] = False

engine = sa.create_engine(
db_url,
echo=False,
connect_args=connect_args,
pool_pre_ping=True,
)

SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
engine = sa.create_engine(db_url, echo=False, connect_args=connect_args, pool_pre_ping=True, future=True)

SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine, future=True)

return SessionLocal, engine

Expand Down
10 changes: 3 additions & 7 deletions mealie/db/models/_model_base.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
from datetime import datetime

from sqlalchemy import Column, DateTime, Integer
from sqlalchemy.ext.declarative import as_declarative
from sqlalchemy.orm import declarative_base
from sqlalchemy.orm import DeclarativeBase
from sqlalchemy.orm.session import Session


@as_declarative()
class Base:
class SqlAlchemyBase(DeclarativeBase):
__allow_unmapped__ = True
id = Column(Integer, primary_key=True)
created_at = Column(DateTime, default=datetime.now)
update_at = Column(DateTime, default=datetime.now, onupdate=datetime.now)
Expand All @@ -32,6 +31,3 @@ def get_ref(cls, match_value: str, match_attr: str | None = None, session: Sessi
eff_ref = getattr(cls, match_attr)

return session.query(cls).filter(eff_ref == match_value).one_or_none()


SqlAlchemyBase = declarative_base(cls=Base, constructor=None)
3 changes: 1 addition & 2 deletions mealie/db/models/_model_utils/auto_init.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
from sqlalchemy.orm.mapper import Mapper
from sqlalchemy.orm.relationships import RelationshipProperty
from sqlalchemy.sql.base import ColumnCollection
from sqlalchemy.util._collections import ImmutableProperties

from .helpers import safe_call

Expand Down Expand Up @@ -125,7 +124,7 @@ def wrapper(self: DeclarativeMeta, *args, **kwargs): # sourcery no-metrics

alchemy_mapper: Mapper = self.__mapper__
model_columns: ColumnCollection = alchemy_mapper.columns
relationships: ImmutableProperties = alchemy_mapper.relationships
relationships = alchemy_mapper.relationships

session = kwargs.get("session", None)

Expand Down
38 changes: 23 additions & 15 deletions mealie/db/models/group/cookbook.py
Original file line number Diff line number Diff line change
@@ -1,33 +1,41 @@
from sqlalchemy import Boolean, Column, ForeignKey, Integer, String, orm
from typing import TYPE_CHECKING

from sqlalchemy import Boolean, ForeignKey, Integer, String, orm
from sqlalchemy.orm import Mapped, mapped_column

from .._model_base import BaseMixins, SqlAlchemyBase
from .._model_utils import auto_init, guid
from ..recipe.category import Category, cookbooks_to_categories
from ..recipe.tag import Tag, cookbooks_to_tags
from ..recipe.tool import Tool, cookbooks_to_tools

if TYPE_CHECKING:
from group import Group


class CookBook(SqlAlchemyBase, BaseMixins):
__tablename__ = "cookbooks"
id = Column(guid.GUID, primary_key=True, default=guid.GUID.generate)
position = Column(Integer, nullable=False, default=1)
id: Mapped[guid.GUID] = mapped_column(guid.GUID, primary_key=True, default=guid.GUID.generate)
position: Mapped[int] = mapped_column(Integer, nullable=False, default=1)

group_id = Column(guid.GUID, ForeignKey("groups.id"))
group = orm.relationship("Group", back_populates="cookbooks")
group_id: Mapped[guid.GUID] = mapped_column(guid.GUID, ForeignKey("groups.id"))
group: Mapped["Group"] = orm.relationship("Group", back_populates="cookbooks")

name = Column(String, nullable=False)
slug = Column(String, nullable=False)
description = Column(String, default="")
public = Column(Boolean, default=False)
name: Mapped[str] = mapped_column(String, nullable=False)
slug: Mapped[str] = mapped_column(String, nullable=False)
description: Mapped[str] = mapped_column(String, default="")
public: Mapped[str] = mapped_column(Boolean, default=False)

categories = orm.relationship(Category, secondary=cookbooks_to_categories, single_parent=True)
require_all_categories = Column(Boolean, default=True)
categories: Mapped[list[Category]] = orm.relationship(
Category, secondary=cookbooks_to_categories, single_parent=True
)
require_all_categories: Mapped[bool] = mapped_column(Boolean, default=True)

tags = orm.relationship(Tag, secondary=cookbooks_to_tags, single_parent=True)
require_all_tags = Column(Boolean, default=True)
tags: Mapped[list[Tag]] = orm.relationship(Tag, secondary=cookbooks_to_tags, single_parent=True)
require_all_tags: Mapped[bool] = mapped_column(Boolean, default=True)

tools = orm.relationship(Tool, secondary=cookbooks_to_tools, single_parent=True)
require_all_tools = Column(Boolean, default=True)
tools: Mapped[list[Tool]] = orm.relationship(Tool, secondary=cookbooks_to_tools, single_parent=True)
require_all_tools: Mapped[bool] = mapped_column(Boolean, default=True)

@auto_init()
def __init__(self, **_) -> None:
Expand Down
68 changes: 38 additions & 30 deletions mealie/db/models/group/events.py
Original file line number Diff line number Diff line change
@@ -1,42 +1,48 @@
from sqlalchemy import Boolean, Column, ForeignKey, String, orm
from typing import TYPE_CHECKING

from sqlalchemy import Boolean, ForeignKey, String, orm
from sqlalchemy.orm import Mapped, mapped_column

from .._model_base import BaseMixins, SqlAlchemyBase
from .._model_utils import GUID, auto_init

if TYPE_CHECKING:
from group import Group


class GroupEventNotifierOptionsModel(SqlAlchemyBase, BaseMixins):
__tablename__ = "group_events_notifier_options"

id = Column(GUID, primary_key=True, default=GUID.generate)
event_notifier_id = Column(GUID, ForeignKey("group_events_notifiers.id"), nullable=False)
id: Mapped[GUID] = mapped_column(GUID, primary_key=True, default=GUID.generate)
event_notifier_id: Mapped[GUID] = mapped_column(GUID, ForeignKey("group_events_notifiers.id"), nullable=False)

recipe_created = Column(Boolean, default=False, nullable=False)
recipe_updated = Column(Boolean, default=False, nullable=False)
recipe_deleted = Column(Boolean, default=False, nullable=False)
recipe_created: Mapped[bool] = mapped_column(Boolean, default=False, nullable=False)
recipe_updated: Mapped[bool] = mapped_column(Boolean, default=False, nullable=False)
recipe_deleted: Mapped[bool] = mapped_column(Boolean, default=False, nullable=False)

user_signup = Column(Boolean, default=False, nullable=False)
user_signup: Mapped[bool] = mapped_column(Boolean, default=False, nullable=False)

data_migrations = Column(Boolean, default=False, nullable=False)
data_export = Column(Boolean, default=False, nullable=False)
data_import = Column(Boolean, default=False, nullable=False)
data_migrations: Mapped[bool] = mapped_column(Boolean, default=False, nullable=False)
data_export: Mapped[bool] = mapped_column(Boolean, default=False, nullable=False)
data_import: Mapped[bool] = mapped_column(Boolean, default=False, nullable=False)

mealplan_entry_created = Column(Boolean, default=False, nullable=False)
mealplan_entry_created: Mapped[bool] = mapped_column(Boolean, default=False, nullable=False)

shopping_list_created = Column(Boolean, default=False, nullable=False)
shopping_list_updated = Column(Boolean, default=False, nullable=False)
shopping_list_deleted = Column(Boolean, default=False, nullable=False)
shopping_list_created: Mapped[bool] = mapped_column(Boolean, default=False, nullable=False)
shopping_list_updated: Mapped[bool] = mapped_column(Boolean, default=False, nullable=False)
shopping_list_deleted: Mapped[bool] = mapped_column(Boolean, default=False, nullable=False)

cookbook_created = Column(Boolean, default=False, nullable=False)
cookbook_updated = Column(Boolean, default=False, nullable=False)
cookbook_deleted = Column(Boolean, default=False, nullable=False)
cookbook_created: Mapped[bool] = mapped_column(Boolean, default=False, nullable=False)
cookbook_updated: Mapped[bool] = mapped_column(Boolean, default=False, nullable=False)
cookbook_deleted: Mapped[bool] = mapped_column(Boolean, default=False, nullable=False)

tag_created = Column(Boolean, default=False, nullable=False)
tag_updated = Column(Boolean, default=False, nullable=False)
tag_deleted = Column(Boolean, default=False, nullable=False)
tag_created: Mapped[bool] = mapped_column(Boolean, default=False, nullable=False)
tag_updated: Mapped[bool] = mapped_column(Boolean, default=False, nullable=False)
tag_deleted: Mapped[bool] = mapped_column(Boolean, default=False, nullable=False)

category_created = Column(Boolean, default=False, nullable=False)
category_updated = Column(Boolean, default=False, nullable=False)
category_deleted = Column(Boolean, default=False, nullable=False)
category_created: Mapped[bool] = mapped_column(Boolean, default=False, nullable=False)
category_updated: Mapped[bool] = mapped_column(Boolean, default=False, nullable=False)
category_deleted: Mapped[bool] = mapped_column(Boolean, default=False, nullable=False)

@auto_init()
def __init__(self, **_) -> None:
Expand All @@ -46,15 +52,17 @@ def __init__(self, **_) -> None:
class GroupEventNotifierModel(SqlAlchemyBase, BaseMixins):
__tablename__ = "group_events_notifiers"

id = Column(GUID, primary_key=True, default=GUID.generate)
name = Column(String, nullable=False)
enabled = Column(Boolean, default=True, nullable=False)
apprise_url = Column(String, nullable=False)
id: Mapped[GUID] = mapped_column(GUID, primary_key=True, default=GUID.generate)
name: Mapped[str] = mapped_column(String, nullable=False)
enabled: Mapped[bool] = mapped_column(Boolean, default=True, nullable=False)
apprise_url: Mapped[str] = mapped_column(String, nullable=False)

group = orm.relationship("Group", back_populates="group_event_notifiers", single_parent=True)
group_id = Column(GUID, ForeignKey("groups.id"), index=True)
group: Mapped["Group"] = orm.relationship("Group", back_populates="group_event_notifiers", single_parent=True)
group_id: Mapped[GUID] = mapped_column(GUID, ForeignKey("groups.id"), index=True)

options = orm.relationship(GroupEventNotifierOptionsModel, uselist=False, cascade="all, delete-orphan")
options: Mapped[GroupEventNotifierOptionsModel] = orm.relationship(
GroupEventNotifierOptionsModel, uselist=False, cascade="all, delete-orphan"
)

@auto_init()
def __init__(self, **_) -> None:
Expand Down
24 changes: 15 additions & 9 deletions mealie/db/models/group/exports.py
Original file line number Diff line number Diff line change
@@ -1,21 +1,27 @@
from sqlalchemy import Column, ForeignKey, String, orm
from typing import TYPE_CHECKING

from sqlalchemy import ForeignKey, String, orm
from sqlalchemy.orm import Mapped, mapped_column

from .._model_base import BaseMixins, SqlAlchemyBase
from .._model_utils import GUID, auto_init

if TYPE_CHECKING:
from group import Group


class GroupDataExportsModel(SqlAlchemyBase, BaseMixins):
__tablename__ = "group_data_exports"
id = Column(GUID, primary_key=True, default=GUID.generate)
id: Mapped[GUID] = mapped_column(GUID, primary_key=True, default=GUID.generate)

group = orm.relationship("Group", back_populates="data_exports", single_parent=True)
group_id = Column(GUID, ForeignKey("groups.id"), index=True)
group: Mapped["Group"] = orm.relationship("Group", back_populates="data_exports", single_parent=True)
group_id: Mapped[GUID] = mapped_column(GUID, ForeignKey("groups.id"), index=True)

name = Column(String, nullable=False)
filename = Column(String, nullable=False)
path = Column(String, nullable=False)
size = Column(String, nullable=False)
expires = Column(String, nullable=False)
name: Mapped[str] = mapped_column(String, nullable=False)
filename: Mapped[str] = mapped_column(String, nullable=False)
path: Mapped[str] = mapped_column(String, nullable=False)
size: Mapped[str] = mapped_column(String, nullable=False)
expires: Mapped[str] = mapped_column(String, nullable=False)

@auto_init()
def __init__(self, **_) -> None:
Expand Down
64 changes: 43 additions & 21 deletions mealie/db/models/group/group.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
from typing import TYPE_CHECKING

import sqlalchemy as sa
import sqlalchemy.orm as orm
from sqlalchemy.orm import Mapped, mapped_column
from sqlalchemy.orm.session import Session

from mealie.core.config import get_app_settings
Expand All @@ -15,18 +18,31 @@
from .mealplan import GroupMealPlan
from .preferences import GroupPreferencesModel

if TYPE_CHECKING:
from ..recipe.ingredient import IngredientFoodModel, IngredientUnitModel
from ..recipe.recipe import RecipeModel
from ..recipe.tag import Tag
from ..recipe.tool import Tool
from ..users import User
from .events import GroupEventNotifierModel
from .exports import GroupDataExportsModel
from .report import ReportModel
from .shopping_list import ShoppingList


class Group(SqlAlchemyBase, BaseMixins):
__tablename__ = "groups"
id = sa.Column(GUID, primary_key=True, default=GUID.generate)
name = sa.Column(sa.String, index=True, nullable=False, unique=True)
users = orm.relationship("User", back_populates="group")
categories = orm.relationship(Category, secondary=group_to_categories, single_parent=True, uselist=True)
id: Mapped[GUID] = mapped_column(GUID, primary_key=True, default=GUID.generate)
name: Mapped[str] = mapped_column(sa.String, index=True, nullable=False, unique=True)
users: Mapped[list["User"]] = orm.relationship("User", back_populates="group")
categories: Mapped[Category] = orm.relationship(
Category, secondary=group_to_categories, single_parent=True, uselist=True
)

invite_tokens = orm.relationship(
invite_tokens: Mapped[list[GroupInviteToken]] = orm.relationship(
GroupInviteToken, back_populates="group", cascade="all, delete-orphan", uselist=True
)
preferences = orm.relationship(
preferences: Mapped[GroupPreferencesModel] = orm.relationship(
GroupPreferencesModel,
back_populates="group",
uselist=False,
Expand All @@ -35,7 +51,7 @@ class Group(SqlAlchemyBase, BaseMixins):
)

# Recipes
recipes = orm.relationship("RecipeModel", back_populates="group", uselist=True)
recipes: Mapped[list["RecipeModel"]] = orm.relationship("RecipeModel", back_populates="group", uselist=True)

# CRUD From Others
common_args = {
Expand All @@ -44,23 +60,29 @@ class Group(SqlAlchemyBase, BaseMixins):
"single_parent": True,
}

labels = orm.relationship(MultiPurposeLabel, **common_args)
labels: Mapped[list[MultiPurposeLabel]] = orm.relationship(MultiPurposeLabel, **common_args)

mealplans = orm.relationship(GroupMealPlan, order_by="GroupMealPlan.date", **common_args)
webhooks = orm.relationship(GroupWebhooksModel, **common_args)
cookbooks = orm.relationship(CookBook, **common_args)
server_tasks = orm.relationship(ServerTaskModel, **common_args)
data_exports = orm.relationship("GroupDataExportsModel", **common_args)
shopping_lists = orm.relationship("ShoppingList", **common_args)
group_reports = orm.relationship("ReportModel", **common_args)
group_event_notifiers = orm.relationship("GroupEventNotifierModel", **common_args)
mealplans: Mapped[list[GroupMealPlan]] = orm.relationship(
GroupMealPlan, order_by="GroupMealPlan.date", **common_args
)
webhooks: Mapped[list[GroupWebhooksModel]] = orm.relationship(GroupWebhooksModel, **common_args)
cookbooks: Mapped[list[CookBook]] = orm.relationship(CookBook, **common_args)
server_tasks: Mapped[list[ServerTaskModel]] = orm.relationship(ServerTaskModel, **common_args)
data_exports: Mapped[list["GroupDataExportsModel"]] = orm.relationship("GroupDataExportsModel", **common_args)
shopping_lists: Mapped[list["ShoppingList"]] = orm.relationship("ShoppingList", **common_args)
group_reports: Mapped[list["ReportModel"]] = orm.relationship("ReportModel", **common_args)
group_event_notifiers: Mapped[list["GroupEventNotifierModel"]] = orm.relationship(
"GroupEventNotifierModel", **common_args
)

# Owned Models
ingredient_units = orm.relationship("IngredientUnitModel", **common_args)
ingredient_foods = orm.relationship("IngredientFoodModel", **common_args)
tools = orm.relationship("Tool", **common_args)
tags = orm.relationship("Tag", **common_args)
categories = orm.relationship("Category", **common_args)
ingredient_units: Mapped[list["IngredientUnitModel"]] = orm.relationship("IngredientUnitModel", **common_args)
ingredient_foods: Mapped[list["IngredientFoodModel"]] = orm.relationship("IngredientFoodModel", **common_args)
tools: Mapped[list["Tool"]] = orm.relationship("Tool", **common_args)
tags: Mapped[list["Tag"]] = orm.relationship("Tag", **common_args)

# TODO: Why does this exist twice?
categories: Mapped[list["Category"]] = orm.relationship("Category", **common_args)

class Config:
exclude = {
Expand Down
16 changes: 11 additions & 5 deletions mealie/db/models/group/invite_tokens.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,22 @@
from sqlalchemy import Column, ForeignKey, Integer, String, orm
from typing import TYPE_CHECKING

from sqlalchemy import ForeignKey, Integer, String, orm
from sqlalchemy.orm import Mapped, mapped_column

from .._model_base import BaseMixins, SqlAlchemyBase
from .._model_utils import auto_init, guid

if TYPE_CHECKING:
from group import Group


class GroupInviteToken(SqlAlchemyBase, BaseMixins):
__tablename__ = "invite_tokens"
token = Column(String, index=True, nullable=False, unique=True)
uses_left = Column(Integer, nullable=False, default=1)
token: Mapped[str] = mapped_column(String, index=True, nullable=False, unique=True)
uses_left: Mapped[int] = mapped_column(Integer, nullable=False, default=1)

group_id = Column(guid.GUID, ForeignKey("groups.id"))
group = orm.relationship("Group", back_populates="invite_tokens")
group_id: Mapped[guid.GUID] = mapped_column(guid.GUID, ForeignKey("groups.id"))
group: Mapped["Group"] = orm.relationship("Group", back_populates="invite_tokens")

@auto_init()
def __init__(self, **_):
Expand Down
Loading

0 comments on commit 07e14b2

Please sign in to comment.