Refactor/define repository layer (#883)

* move data access layer

* rename dal -> repo
This commit is contained in:
Hayden
2021-12-18 20:52:36 -09:00
committed by GitHub
parent ea7c4771ee
commit 74e13682cb
68 changed files with 371 additions and 369 deletions

View File

@@ -7,9 +7,9 @@ from sqlalchemy.orm.session import Session
from mealie.core.config import get_app_dirs, get_app_settings
from mealie.core.root_logger import get_logger
from mealie.db.database import get_database
from mealie.db.db_setup import SessionLocal
from mealie.lang import get_locale_provider
from mealie.repos.all_repositories import get_repositories
from mealie.schema.user.user import PrivateUser
logger = get_logger()
@@ -62,7 +62,7 @@ class BaseHttpService(Generic[T, D], ABC):
self.background_tasks = background_tasks
# Static Globals Dependency Injection
self.db = get_database(session)
self.db = get_repositories(session)
self.app_dirs = get_app_dirs()
self.settings = get_app_settings()
self.t = get_locale_provider().t

View File

@@ -9,13 +9,13 @@ from sqlalchemy.exc import IntegrityError
from sqlalchemy.orm import Session
from mealie.core.root_logger import get_logger
from mealie.db.data_access_layer._access_model import AccessModel
from mealie.repos.repository_generic import RepositoryGeneric
from mealie.schema.response import ErrorResponse
C = TypeVar("C", bound=BaseModel)
R = TypeVar("R", bound=BaseModel)
U = TypeVar("U", bound=BaseModel)
DAL = TypeVar("DAL", bound=AccessModel)
DAL = TypeVar("DAL", bound=RepositoryGeneric)
logger = get_logger()
@@ -25,16 +25,16 @@ class CrudHttpMixins(Generic[C, R, U], ABC):
@property
@abstractmethod
def dal(self) -> DAL:
def repo(self) -> DAL:
...
def populate_item(self, id: int) -> R:
self.item = self.dal.get_one(id)
self.item = self.repo.get_one(id)
return self.item
def _create_one(self, data: C, default_msg="generic-create-error", exception_msgs: dict | None = None) -> R:
try:
self.item = self.dal.create(data)
self.item = self.repo.create(data)
except Exception as ex:
logger.exception(ex)
self.session.rollback()
@@ -58,13 +58,13 @@ class CrudHttpMixins(Generic[C, R, U], ABC):
return
target_id = item_id or self.item.id
self.item = self.dal.update(target_id, data)
self.item = self.repo.update(target_id, data)
return self.item
def _patch_one(self, data: U, item_id: int) -> None:
try:
self.item = self.dal.patch(item_id, data.dict(exclude_unset=True, exclude_defaults=True))
self.item = self.repo.patch(item_id, data.dict(exclude_unset=True, exclude_defaults=True))
except IntegrityError:
raise HTTPException(status.HTTP_400_BAD_REQUEST, detail={"message": "generic-patch-error"})
@@ -73,7 +73,7 @@ class CrudHttpMixins(Generic[C, R, U], ABC):
logger.info(f"Deleting item with id {target_id}")
try:
self.item = self.dal.delete(target_id)
self.item = self.repo.delete(target_id)
except Exception as ex:
logger.exception(ex)
raise HTTPException(

View File

@@ -23,15 +23,15 @@ class AdminGroupService(
_schema = GroupInDB
@cached_property
def dal(self):
def repo(self):
return self.db.groups
def populate_item(self, id: UUID4) -> GroupInDB:
self.item = self.dal.get_one(id)
self.item = self.repo.get_one(id)
return self.item
def get_all(self) -> list[GroupInDB]:
return self.dal.get_all()
return self.repo.get_all()
def create_one(self, data: GroupBase) -> GroupInDB:
return create_new_group(self.db, data)
@@ -46,7 +46,7 @@ class AdminGroupService(
if data.name not in ["", self.item.name]:
self.item.name = data.name
self.item = self.dal.update(target_id, self.item)
self.item = self.repo.update(target_id, self.item)
return self.item

View File

@@ -16,15 +16,15 @@ class AdminUserService(
_schema = UserOut
@cached_property
def dal(self):
def repo(self):
return self.db.users
def populate_item(self, id: int) -> UserOut:
self.item = self.dal.get_one(id)
self.item = self.repo.get_one(id)
return self.item
def get_all(self) -> list[UserOut]:
return self.dal.get_all()
return self.repo.get_all()
def create_one(self, data: UserIn) -> UserOut:
return self._create_one(data)

View File

@@ -12,7 +12,7 @@ from mealie.core import root_logger
from mealie.core.config import get_app_dirs
app_dirs = get_app_dirs()
from mealie.db.database import get_database
from mealie.repos.all_repositories import get_repositories
logger = root_logger.get_logger()
@@ -113,7 +113,7 @@ def backup_all(
):
db_export = ExportDatabase(tag=tag, templates=templates)
db = get_database(session)
db = get_repositories(session)
if export_users:
all_users = db.users.get_all()

View File

@@ -8,7 +8,7 @@ from pydantic.main import BaseModel
from sqlalchemy.orm.session import Session
from mealie.core.config import get_app_dirs
from mealie.db.database import get_database
from mealie.repos.all_repositories import get_repositories
from mealie.schema.admin import CommentImport, GroupImport, NotificationImport, RecipeImport, UserImport
from mealie.schema.events import EventNotificationIn
from mealie.schema.recipe import Recipe, RecipeCommentOut
@@ -38,7 +38,7 @@ class ImportDatabase:
"""
self.user = user
self.session = session
self.db = get_database(session)
self.db = get_repositories(session)
self.archive = app_dirs.BACKUP_DIR.joinpath(zip_archive)
self.force_imports = force_import

View File

@@ -1,8 +1,8 @@
import apprise
from sqlalchemy.orm.session import Session
from mealie.db.database import get_database
from mealie.db.db_setup import create_session
from mealie.repos.all_repositories import get_repositories
from mealie.schema.events import Event, EventCategory
@@ -37,7 +37,7 @@ def post_notifications(event: Event, notification_urls=list[str], hard_fail=Fals
def save_event(title, text, category, session: Session, attachment=None):
event = Event(title=title, text=text, category=category)
session = session or create_session()
db = get_database(session)
db = get_repositories(session)
db.events.create(event.dict())
notification_objects = db.event_notifications.get(match_value=True, match_key=category, limit=9999)

View File

@@ -8,7 +8,7 @@ from uuid import UUID
from pydantic import BaseModel
from mealie.core.root_logger import get_logger
from mealie.db.database import Database
from mealie.repos.all_repositories import AllRepositories
from mealie.schema.reports.reports import ReportEntryCreate
from .._base_service import BaseService
@@ -29,7 +29,7 @@ class ExportedItem:
class ABCExporter(BaseService):
write_dir_to_zip: Callable[[Path, str, Optional[list[str]]], None]
def __init__(self, db: Database, group_id: UUID) -> None:
def __init__(self, db: AllRepositories, group_id: UUID) -> None:
self.logger = get_logger()
self.db = db
self.group_id = group_id

View File

@@ -4,7 +4,7 @@ import zipfile
from pathlib import Path
from uuid import UUID, uuid4
from mealie.db.database import Database
from mealie.repos.all_repositories import AllRepositories
from mealie.schema.group.group_exports import GroupDataExport
from mealie.schema.user import GroupInDB
from mealie.utils.fs_stats import pretty_size
@@ -21,7 +21,7 @@ class Exporter(BaseService):
self.temp_path = temp_zip
self.exporters = exporters
def run(self, db: Database) -> GroupDataExport:
def run(self, db: AllRepositories) -> GroupDataExport:
# Create Zip File
self.temp_path.touch()

View File

@@ -1,14 +1,14 @@
from typing import Iterator
from uuid import UUID
from mealie.db.database import Database
from mealie.repos.all_repositories import AllRepositories
from mealie.schema.recipe import Recipe
from ._abc_exporter import ABCExporter, ExportedItem
class RecipeExporter(ABCExporter):
def __init__(self, db: Database, group_id: UUID, recipes: list[str]) -> None:
def __init__(self, db: AllRepositories, group_id: UUID, recipes: list[str]) -> None:
"""
RecipeExporter is used to export a list of recipes to a zip file. The zip
file is then saved to a temporary directory and then available for a one-time

View File

@@ -21,7 +21,7 @@ class CookbookService(
_schema = ReadCookBook
@cached_property
def dal(self):
def repo(self):
return self.db.cookbooks
def populate_item(self, item_id: int) -> RecipeCookBook:
@@ -31,13 +31,13 @@ class CookbookService(
pass
if isinstance(item_id, int):
self.item = self.dal.get_one(item_id, override_schema=RecipeCookBook)
self.item = self.repo.get_one(item_id, override_schema=RecipeCookBook)
else:
self.item = self.dal.get_one(item_id, key="slug", override_schema=RecipeCookBook)
self.item = self.repo.get_one(item_id, key="slug", override_schema=RecipeCookBook)
def get_all(self) -> list[ReadCookBook]:
items = self.dal.get(self.group_id, "group_id", limit=999)
items = self.repo.get(self.group_id, "group_id", limit=999)
items.sort(key=lambda x: x.position)
return items
@@ -52,7 +52,7 @@ class CookbookService(
updated = []
for cookbook in data:
cb = self.dal.update(cookbook.id, cookbook)
cb = self.repo.update(cookbook.id, cookbook)
updated.append(cb)
return updated

View File

@@ -1,11 +1,11 @@
from uuid import uuid4
from mealie.db.data_access_layer.access_model_factory import Database
from mealie.repos.repository_factory import AllRepositories
from mealie.schema.group.group_preferences import CreateGroupPreferences
from mealie.schema.user.user import GroupBase, GroupInDB
def create_new_group(db: Database, g_base: GroupBase, g_preferences: CreateGroupPreferences = None) -> GroupInDB:
def create_new_group(db: AllRepositories, g_base: GroupBase, g_preferences: CreateGroupPreferences = None) -> GroupInDB:
created_group = db.groups.create(g_base)
# Assign Temporary ID before group is created

View File

@@ -21,19 +21,19 @@ class MealService(CrudHttpMixins[CreatePlanEntry, ReadPlanEntry, UpdatePlanEntry
item: ReadPlanEntry
@cached_property
def dal(self):
def repo(self):
return self.db.meals
def populate_item(self, id: int) -> ReadPlanEntry:
self.item = self.dal.get_one(id)
self.item = self.repo.get_one(id)
return self.item
def get_slice(self, start: date = None, end: date = None) -> list[ReadPlanEntry]:
# 2 days ago
return self.dal.get_slice(start, end, group_id=self.group_id)
return self.repo.get_slice(start, end, group_id=self.group_id)
def get_today(self) -> list[ReadPlanEntry]:
return self.dal.get_today(group_id=self.group_id)
return self.repo.get_today(group_id=self.group_id)
def create_one(self, data: CreatePlanEntry) -> ReadPlanEntry:
data = self.cast(data, SavePlanEntry)

View File

@@ -23,7 +23,7 @@ class GroupMigrationService(UserHttpService[int, ReportOut]):
_schema = ReportOut
@cached_property
def dal(self):
def repo(self):
raise NotImplementedError
def populate_item(self, _: UUID4) -> ReportOut:

View File

@@ -17,15 +17,15 @@ class GroupReportService(CrudHttpMixins[ReportOut, ReportCreate, ReportCreate],
_schema = ReportOut
@cached_property
def dal(self):
def repo(self):
return self.db.group_reports
def populate_item(self, id: int) -> ReportOut:
self.item = self.dal.get_one(id)
self.item = self.repo.get_one(id)
return self.item
def _get_all(self, report_type: ReportCategory = None) -> list[ReportSummary]:
return self.dal.multi_query({"group_id": self.group_id, "category": report_type}, limit=9999)
return self.repo.multi_query({"group_id": self.group_id, "category": report_type}, limit=9999)
def delete_one(self, id: int = None) -> ReportOut:
return self._delete_one(id)

View File

@@ -18,15 +18,15 @@ class WebhookService(CrudHttpMixins[ReadWebhook, CreateWebhook, CreateWebhook],
_schema = ReadWebhook
@cached_property
def dal(self):
def repo(self):
return self.db.webhooks
def populate_item(self, id: int) -> ReadWebhook:
self.item = self.dal.get_one(id)
self.item = self.repo.get_one(id)
return self.item
def get_all(self) -> list[ReadWebhook]:
return self.dal.get(self.group_id, match_key="group_id", limit=9999)
return self.repo.get(self.group_id, match_key="group_id", limit=9999)
def create_one(self, data: CreateWebhook) -> ReadWebhook:
data = self.cast(data, SaveWebhook)

View File

@@ -5,7 +5,7 @@ from uuid import UUID
from pydantic import UUID4
from mealie.core import root_logger
from mealie.db.database import Database
from mealie.repos.all_repositories import AllRepositories
from mealie.schema.recipe import Recipe
from mealie.schema.reports.reports import (
ReportCategory,
@@ -29,7 +29,9 @@ class BaseMigrator(BaseService):
report_id: int
report: ReportOut
def __init__(self, archive: Path, db: Database, session, user_id: UUID4, group_id: UUID, add_migration_tag: bool):
def __init__(
self, archive: Path, db: AllRepositories, session, user_id: UUID4, group_id: UUID, add_migration_tag: bool
):
self.archive = archive
self.db = db
self.session = session

View File

@@ -4,8 +4,8 @@ from pydantic import UUID4, BaseModel
from slugify import slugify
from sqlalchemy.orm import Session
from mealie.db.data_access_layer.access_model_factory import AccessModel
from mealie.db.database import Database
from mealie.repos.all_repositories import AllRepositories
from mealie.repos.repository_factory import RepositoryGeneric
from mealie.schema.recipe import RecipeCategory
from mealie.schema.recipe.recipe import RecipeTag
@@ -13,13 +13,13 @@ T = TypeVar("T", bound=BaseModel)
class DatabaseMigrationHelpers:
def __init__(self, db: Database, session: Session, group_id: int, user_id: UUID4) -> None:
def __init__(self, db: AllRepositories, session: Session, group_id: int, user_id: UUID4) -> None:
self.group_id = group_id
self.user_id = user_id
self.session = session
self.db = db
def _get_or_set_generic(self, accessor: AccessModel, items: list[str], out_model: T) -> list[T]:
def _get_or_set_generic(self, accessor: RepositoryGeneric, items: list[str], out_model: T) -> list[T]:
"""
Utility model for getting or setting categories or tags. This will only work for those two cases.

View File

@@ -25,7 +25,7 @@ class RecipeCommentsService(
_schema = RecipeCommentOut
@cached_property
def dal(self):
def repo(self):
return self.db.comments
def _check_comment_belongs_to_user(self) -> None:
@@ -33,11 +33,11 @@ class RecipeCommentsService(
raise HTTPException(detail="Comment does not belong to user")
def populate_item(self, id: UUID) -> RecipeCommentOut:
self.item = self.dal.get_one(id)
self.item = self.repo.get_one(id)
return self.item
def get_all(self) -> list[RecipeCommentOut]:
return self.dal.get_all()
return self.repo.get_all()
def create_one(self, data: RecipeCommentCreate) -> RecipeCommentOut:
save_data = RecipeCommentSave(text=data.text, user_id=self.user.id, recipe_id=data.recipe_id)

View File

@@ -17,15 +17,15 @@ class RecipeFoodService(
_schema = IngredientFood
@cached_property
def dal(self):
def repo(self):
return self.db.ingredient_foods
def populate_item(self, id: int) -> IngredientFood:
self.item = self.dal.get_one(id)
self.item = self.repo.get_one(id)
return self.item
def get_all(self) -> list[IngredientFood]:
return self.dal.get_all()
return self.repo.get_all()
def create_one(self, data: CreateIngredientFood) -> IngredientFood:
return self._create_one(data)

View File

@@ -11,7 +11,7 @@ from sqlalchemy import exc
from mealie.core.dependencies.grouped import UserDeps
from mealie.core.root_logger import get_logger
from mealie.db.data_access_layer.recipe_access_model import RecipeDataAccessModel
from mealie.repos.repository_recipes import RepositoryRecipes
from mealie.schema.recipe.recipe import CreateRecipe, Recipe, RecipeSummary
from mealie.schema.recipe.recipe_settings import RecipeSettings
from mealie.services._base_http_service.crud_http_mixins import CrudHttpMixins
@@ -40,7 +40,7 @@ class RecipeService(CrudHttpMixins[CreateRecipe, Recipe, Recipe], UserHttpServic
return {exc.IntegrityError: self.t("recipe.unique-name-error")}
@cached_property
def dal(self) -> RecipeDataAccessModel:
def repo(self) -> RepositoryRecipes:
return self.db.recipes.by_group(self.group_id)
@classmethod

View File

@@ -17,15 +17,15 @@ class RecipeToolService(
_schema = RecipeTool
@cached_property
def dal(self):
def repo(self):
return self.db.tools
def populate_item(self, id: int) -> RecipeTool:
self.item = self.dal.get_one(id)
self.item = self.repo.get_one(id)
return self.item
def get_all(self) -> list[RecipeTool]:
return self.dal.get_all()
return self.repo.get_all()
def create_one(self, data: RecipeToolCreate) -> RecipeTool:
return self._create_one(data)

View File

@@ -17,15 +17,15 @@ class RecipeUnitService(
_schema = IngredientUnit
@cached_property
def dal(self):
def repo(self):
return self.db.ingredient_units
def populate_item(self, id: int) -> IngredientUnit:
self.item = self.dal.get_one(id)
self.item = self.repo.get_one(id)
return self.item
def get_all(self) -> list[IngredientUnit]:
return self.dal.get_all()
return self.repo.get_all()
def create_one(self, data: CreateIngredientUnit) -> IngredientUnit:
return self._create_one(data)

View File

@@ -4,8 +4,8 @@ import requests
from sqlalchemy.orm.session import Session
from mealie.core import root_logger
from mealie.db.database import get_database
from mealie.db.db_setup import create_session
from mealie.repos.all_repositories import get_repositories
from mealie.schema.group.webhook import ReadWebhook
from ..scheduled_func import Cron, ScheduledFunc
@@ -16,7 +16,7 @@ logger = root_logger.get_logger()
def post_webhooks(webhook_id: int, session: Session = None):
session = session or create_session()
db = get_database(session)
db = get_repositories(session)
webhook: ReadWebhook = db.webhooks.get_one(webhook_id)
if not webhook.enabled:
@@ -39,7 +39,7 @@ def post_webhooks(webhook_id: int, session: Session = None):
def update_group_webhooks():
session = create_session()
db = get_database(session)
db = get_repositories(session)
webhooks: list[ReadWebhook] = db.webhooks.get_all()

View File

@@ -4,7 +4,7 @@ from typing import Any, Callable
from sqlalchemy.orm import Session
from mealie.db.database import get_database
from mealie.repos.all_repositories import get_repositories
from mealie.schema.server.tasks import ServerTask, ServerTaskCreate, ServerTaskNames
from .._base_http_service.http_services import UserHttpService
@@ -32,7 +32,7 @@ class BackgroundExecutor(UserHttpService):
def test_executor_func(task_id: int, session: Session) -> None:
database = get_database(session)
database = get_repositories(session)
task = database.server_tasks.get_one(task_id)
task.append_log("test task has started")

View File

@@ -9,15 +9,15 @@ class ServerTasksHttpService(UserHttpService[int, ServerTask]):
_schema = ServerTask
@cached_property
def dal(self):
def repo(self):
return self.db.server_tasks
def populate_item(self, id: int) -> ServerTask:
self.item = self.dal.get_one(id)
self.item = self.repo.get_one(id)
return self.item
def get_all(self) -> list[ServerTask]:
return self.dal.multi_query(query_by={"group_id": self.group_id}, order_by="created_at")
return self.repo.multi_query(query_by={"group_id": self.group_id}, order_by="created_at")
class AdminServerTasks(AdminHttpService[int, ServerTask]):
@@ -25,12 +25,12 @@ class AdminServerTasks(AdminHttpService[int, ServerTask]):
_schema = ServerTask
@cached_property
def dal(self):
def repo(self):
return self.db.server_tasks
def populate_item(self, id: int) -> ServerTask:
self.item = self.dal.get_one(id)
self.item = self.repo.get_one(id)
return self.item
def get_all(self) -> list[ServerTask]:
return self.dal.get_all(order_by="created_at")
return self.repo.get_all(order_by="created_at")

View File

@@ -22,11 +22,11 @@ class SharedRecipeService(
_schema = RecipeShareToken
@cached_property
def dal(self):
def repo(self):
return self.db.recipe_share_tokens
def populate_item(self, id: UUID4) -> RecipeShareToken:
self.item = self.dal.get_one(id)
self.item = self.repo.get_one(id)
return self.item
def get_all(self, recipe_id=None) -> list[RecipeShareTokenSummary]:
@@ -48,4 +48,4 @@ class SharedRecipeService(
def delete_one(self, item_id: UUID4 = None) -> None:
item_id = item_id or self.item.id
return self.dal.delete(item_id)
return self.repo.delete(item_id)

View File

@@ -3,7 +3,7 @@ from sqlalchemy.orm.session import Session
from mealie.core.root_logger import get_logger
from mealie.core.security import hash_password, url_safe_token
from mealie.db.database import get_database
from mealie.repos.all_repositories import get_repositories
from mealie.schema.user.user_passwords import SavePasswordResetToken
from mealie.services._base_service import BaseService
from mealie.services.email import EmailService
@@ -13,7 +13,7 @@ logger = get_logger(__name__)
class PasswordResetService(BaseService):
def __init__(self, session: Session) -> None:
self.db = get_database(session)
self.db = get_repositories(session)
super().__init__()
def generate_reset_token(self, email: str) -> SavePasswordResetToken: