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

@@ -1 +0,0 @@
from .access_model_factory import Database

View File

@@ -1,307 +0,0 @@
from __future__ import annotations
from typing import Any, Callable, Generic, TypeVar, Union
from uuid import UUID
from pydantic import UUID4
from sqlalchemy import func
from sqlalchemy.orm import load_only
from sqlalchemy.orm.session import Session
from mealie.core.root_logger import get_logger
logger = get_logger()
T = TypeVar("T")
D = TypeVar("D")
class AccessModel(Generic[T, D]):
"""A Generic BaseAccess Model method to perform common operations on the database
Args:
Generic ([T]): Represents the Pydantic Model
Generic ([D]): Represents the SqlAlchemyModel Model
"""
def __init__(self, session: Session, primary_key: Union[str, int], sql_model: D, schema: T) -> None:
self.session = session
self.primary_key = primary_key
self.sql_model = sql_model
self.schema = schema
self.observers: list = []
self.limit_by_group = False
self.user_id = None
self.limit_by_user = False
self.group_id = None
def subscribe(self, func: Callable) -> None:
self.observers.append(func)
def by_user(self, user_id: UUID4) -> AccessModel:
self.limit_by_user = True
self.user_id = user_id
return self
def by_group(self, group_id: UUID) -> AccessModel:
self.limit_by_group = True
self.group_id = group_id
return self
def _filter_builder(self, **kwargs) -> dict[str, Any]:
dct = {}
if self.limit_by_user:
dct["user_id"] = self.user_id
if self.limit_by_group:
dct["group_id"] = self.group_id
return {**dct, **kwargs}
# TODO: Run Observer in Async Background Task
def update_observers(self) -> None:
if self.observers:
for observer in self.observers:
observer()
def get_all(self, limit: int = None, order_by: str = None, start=0, override_schema=None) -> list[T]:
eff_schema = override_schema or self.schema
order_attr = None
if order_by:
order_attr = getattr(self.sql_model, str(order_by))
order_attr = order_attr.desc()
return [
eff_schema.from_orm(x)
for x in self.session.query(self.sql_model).order_by(order_attr).offset(start).limit(limit).all()
]
return [eff_schema.from_orm(x) for x in self.session.query(self.sql_model).offset(start).limit(limit).all()]
def multi_query(
self,
query_by: dict[str, str],
start=0,
limit: int = None,
override_schema=None,
order_by: str = None,
) -> list[T]:
eff_schema = override_schema or self.schema
order_attr = None
if order_by:
order_attr = getattr(self.sql_model, str(order_by))
order_attr = order_attr.desc()
return [
eff_schema.from_orm(x)
for x in self.session.query(self.sql_model)
.filter_by(**query_by)
.order_by(order_attr)
.offset(start)
.limit(limit)
.all()
]
def get_all_limit_columns(self, fields: list[str], limit: int = None) -> list[D]:
"""Queries the database for the selected model. Restricts return responses to the
keys specified under "fields"
Args:
session (Session): Database Session Object
fields (list[str]): list of column names to query
limit (int): A limit of values to return
Returns:
list[SqlAlchemyBase]: Returns a list of ORM objects
"""
return self.session.query(self.sql_model).options(load_only(*fields)).limit(limit).all()
def get_all_primary_keys(self) -> list[str]:
"""Queries the database of the selected model and returns a list
of all primary_key values
Args:
session (Session): Database Session object
Returns:
list[str]:
"""
results = self.session.query(self.sql_model).options(load_only(str(self.primary_key)))
results_as_dict = [x.dict() for x in results]
return [x.get(self.primary_key) for x in results_as_dict]
def _query_one(self, match_value: str, match_key: str = None) -> D:
"""
Query the sql database for one item an return the sql alchemy model
object. If no match key is provided the primary_key attribute will be used.
"""
if match_key is None:
match_key = self.primary_key
filter = self._filter_builder(**{match_key: match_value})
return self.session.query(self.sql_model).filter_by(**filter).one()
def get_one(self, value: str | int, key: str = None, any_case=False, override_schema=None) -> T:
key = key or self.primary_key
q = self.session.query(self.sql_model)
if any_case:
search_attr = getattr(self.sql_model, key)
q = q.filter(func.lower(search_attr) == key.lower()).filter_by(**self._filter_builder())
else:
q = self.session.query(self.sql_model).filter_by(**self._filter_builder(**{key: value}))
result = q.one_or_none()
if not result:
return
eff_schema = override_schema or self.schema
return eff_schema.from_orm(result)
def get(
self, match_value: str, match_key: str = None, limit=1, any_case=False, override_schema=None
) -> T | list[T]:
"""Retrieves an entry from the database by matching a key/value pair. If no
key is provided the class objects primary key will be used to match against.
Args:
match_value (str): A value used to match against the key/value in the database
match_key (str, optional): They key to match the value against. Defaults to None.
limit (int, optional): A limit to returned responses. Defaults to 1.
Returns:
dict or list[dict]:
"""
match_key = match_key or self.primary_key
if any_case:
search_attr = getattr(self.sql_model, match_key)
result = (
self.session.query(self.sql_model)
.filter(func.lower(search_attr) == match_value.lower())
.limit(limit)
.all()
)
else:
result = self.session.query(self.sql_model).filter_by(**{match_key: match_value}).limit(limit).all()
eff_schema = override_schema or self.schema
if limit == 1:
try:
return eff_schema.from_orm(result[0])
except IndexError:
return None
return [eff_schema.from_orm(x) for x in result]
def create(self, document: T) -> T:
"""Creates a new database entry for the given SQL Alchemy Model.
Args:
session (Session): A Database Session
document (dict): A python dictionary representing the data structure
Returns:
dict: A dictionary representation of the database entry
"""
document = document if isinstance(document, dict) else document.dict()
new_document = self.sql_model(session=self.session, **document)
self.session.add(new_document)
self.session.commit()
self.session.refresh(new_document)
if self.observers:
self.update_observers()
return self.schema.from_orm(new_document)
def update(self, match_value: str, new_data: dict) -> T:
"""Update a database entry.
Args:
session (Session): Database Session
match_value (str): Match "key"
new_data (str): Match "value"
Returns:
dict: Returns a dictionary representation of the database entry
"""
new_data = new_data if isinstance(new_data, dict) else new_data.dict()
entry = self._query_one(match_value=match_value)
entry.update(session=self.session, **new_data)
if self.observers:
self.update_observers()
self.session.commit()
return self.schema.from_orm(entry)
def patch(self, match_value: str, new_data: dict) -> T:
new_data = new_data if isinstance(new_data, dict) else new_data.dict()
entry = self._query_one(match_value=match_value)
if not entry:
return
entry_as_dict = self.schema.from_orm(entry).dict()
entry_as_dict.update(new_data)
return self.update(match_value, entry_as_dict)
def delete(self, primary_key_value) -> D:
result = self.session.query(self.sql_model).filter_by(**{self.primary_key: primary_key_value}).one()
results_as_model = self.schema.from_orm(result)
try:
self.session.delete(result)
self.session.commit()
except Exception as e:
self.session.rollback()
raise e
if self.observers:
self.update_observers()
return results_as_model
def delete_all(self) -> None:
self.session.query(self.sql_model).delete()
self.session.commit()
if self.observers:
self.update_observers()
def count_all(self, match_key=None, match_value=None) -> int:
if None in [match_key, match_value]:
return self.session.query(self.sql_model).count()
else:
return self.session.query(self.sql_model).filter_by(**{match_key: match_value}).count()
def _count_attribute(
self,
attribute_name: str,
attr_match: str = None,
count=True,
override_schema=None,
) -> Union[int, T]:
eff_schema = override_schema or self.schema
# attr_filter = getattr(self.sql_model, attribute_name)
if count:
return self.session.query(self.sql_model).filter(attribute_name == attr_match).count() # noqa: 711
else:
return [
eff_schema.from_orm(x)
for x in self.session.query(self.sql_model).filter(attribute_name == attr_match).all() # noqa: 711
]

View File

@@ -1,178 +0,0 @@
from functools import cached_property
from sqlalchemy.orm import Session
from mealie.db.models.event import Event, EventNotification
from mealie.db.models.group import Group, GroupMealPlan, ReportEntryModel, ReportModel
from mealie.db.models.group.cookbook import CookBook
from mealie.db.models.group.exports import GroupDataExportsModel
from mealie.db.models.group.invite_tokens import GroupInviteToken
from mealie.db.models.group.preferences import GroupPreferencesModel
from mealie.db.models.group.webhooks import GroupWebhooksModel
from mealie.db.models.recipe.category import Category
from mealie.db.models.recipe.comment import RecipeComment
from mealie.db.models.recipe.ingredient import IngredientFoodModel, IngredientUnitModel
from mealie.db.models.recipe.recipe import RecipeModel
from mealie.db.models.recipe.shared import RecipeShareTokenModel
from mealie.db.models.recipe.tag import Tag
from mealie.db.models.recipe.tool import Tool
from mealie.db.models.server.task import ServerTaskModel
from mealie.db.models.sign_up import SignUp
from mealie.db.models.users import LongLiveToken, User
from mealie.db.models.users.password_reset import PasswordResetModel
from mealie.schema.cookbook.cookbook import ReadCookBook
from mealie.schema.events import Event as EventSchema
from mealie.schema.events import EventNotificationIn
from mealie.schema.group.group_exports import GroupDataExport
from mealie.schema.group.group_preferences import ReadGroupPreferences
from mealie.schema.group.invite_token import ReadInviteToken
from mealie.schema.group.webhook import ReadWebhook
from mealie.schema.meal_plan.new_meal import ReadPlanEntry
from mealie.schema.recipe import Recipe, RecipeCategoryResponse, RecipeCommentOut, RecipeTagResponse, RecipeTool
from mealie.schema.recipe.recipe_ingredient import IngredientFood, IngredientUnit
from mealie.schema.recipe.recipe_share_token import RecipeShareToken
from mealie.schema.reports.reports import ReportEntryOut, ReportOut
from mealie.schema.server import ServerTask
from mealie.schema.user import GroupInDB, LongLiveTokenInDB, PrivateUser, SignUpOut
from mealie.schema.user.user_passwords import PrivatePasswordResetToken
from ._access_model import AccessModel
from .group_access_model import GroupDataAccessModel
from .meal_access_model import MealDataAccessModel
from .recipe_access_model import RecipeDataAccessModel
from .user_access_model import UserDataAccessModel
pk_id = "id"
pk_slug = "slug"
pk_token = "token"
pk_group_id = "group_id"
class CategoryDataAccessModel(AccessModel):
def get_empty(self):
return self.session.query(Category).filter(~Category.recipes.any()).all()
class TagsDataAccessModel(AccessModel):
def get_empty(self):
return self.session.query(Tag).filter(~Tag.recipes.any()).all()
class Database:
def __init__(self, session: Session) -> None:
"""
`DatabaseAccessLayer` class is the data access layer for all database actions within
Mealie. Database uses composition from classes derived from AccessModel. These
can be substantiated from the AccessModel class or through inheritance when
additional methods are required.
"""
self.session = session
# ================================================================
# Recipe Items
@cached_property
def recipes(self) -> RecipeDataAccessModel:
return RecipeDataAccessModel(self.session, pk_slug, RecipeModel, Recipe)
@cached_property
def ingredient_foods(self) -> AccessModel[IngredientFood, IngredientFoodModel]:
return AccessModel(self.session, pk_id, IngredientFoodModel, IngredientFood)
@cached_property
def ingredient_units(self) -> AccessModel[IngredientUnit, IngredientUnitModel]:
return AccessModel(self.session, pk_id, IngredientUnitModel, IngredientUnit)
@cached_property
def tools(self) -> AccessModel[RecipeTool, Tool]:
return AccessModel(self.session, pk_id, Tool, RecipeTool)
@cached_property
def comments(self) -> AccessModel[RecipeCommentOut, RecipeComment]:
return AccessModel(self.session, pk_id, RecipeComment, RecipeCommentOut)
@cached_property
def categories(self) -> CategoryDataAccessModel:
return CategoryDataAccessModel(self.session, pk_slug, Category, RecipeCategoryResponse)
@cached_property
def tags(self) -> TagsDataAccessModel:
return TagsDataAccessModel(self.session, pk_slug, Tag, RecipeTagResponse)
@cached_property
def recipe_share_tokens(self) -> AccessModel[RecipeShareToken, RecipeShareTokenModel]:
return AccessModel(self.session, pk_id, RecipeShareTokenModel, RecipeShareToken)
# ================================================================
# Site Items
@cached_property
def sign_up(self) -> AccessModel[SignUpOut, SignUp]:
return AccessModel(self.session, pk_id, SignUp, SignUpOut)
@cached_property
def event_notifications(self) -> AccessModel[EventNotificationIn, EventNotification]:
return AccessModel(self.session, pk_id, EventNotification, EventNotificationIn)
@cached_property
def events(self) -> AccessModel[EventSchema, Event]:
return AccessModel(self.session, pk_id, Event, EventSchema)
# ================================================================
# User Items
@cached_property
def users(self) -> UserDataAccessModel:
return UserDataAccessModel(self.session, pk_id, User, PrivateUser)
@cached_property
def api_tokens(self) -> AccessModel[LongLiveTokenInDB, LongLiveToken]:
return AccessModel(self.session, pk_id, LongLiveToken, LongLiveTokenInDB)
@cached_property
def tokens_pw_reset(self) -> AccessModel[PrivatePasswordResetToken, PasswordResetModel]:
return AccessModel(self.session, pk_token, PasswordResetModel, PrivatePasswordResetToken)
# ================================================================
# Group Items
@cached_property
def server_tasks(self) -> AccessModel[ServerTask, ServerTaskModel]:
return AccessModel(self.session, pk_id, ServerTaskModel, ServerTask)
@cached_property
def groups(self) -> GroupDataAccessModel:
return GroupDataAccessModel(self.session, pk_id, Group, GroupInDB)
@cached_property
def group_invite_tokens(self) -> AccessModel[ReadInviteToken, GroupInviteToken]:
return AccessModel(self.session, pk_token, GroupInviteToken, ReadInviteToken)
@cached_property
def group_preferences(self) -> AccessModel[ReadGroupPreferences, GroupPreferencesModel]:
return AccessModel(self.session, pk_group_id, GroupPreferencesModel, ReadGroupPreferences)
@cached_property
def group_exports(self) -> AccessModel[GroupDataExport, GroupDataExportsModel]:
return AccessModel(self.session, pk_id, GroupDataExportsModel, GroupDataExport)
@cached_property
def meals(self) -> MealDataAccessModel:
return MealDataAccessModel(self.session, pk_id, GroupMealPlan, ReadPlanEntry)
@cached_property
def cookbooks(self) -> AccessModel[ReadCookBook, CookBook]:
return AccessModel(self.session, pk_id, CookBook, ReadCookBook)
@cached_property
def webhooks(self) -> AccessModel[ReadWebhook, GroupWebhooksModel]:
return AccessModel(self.session, pk_id, GroupWebhooksModel, ReadWebhook)
@cached_property
def group_reports(self) -> AccessModel[ReportOut, ReportModel]:
return AccessModel(self.session, pk_id, ReportModel, ReportOut)
@cached_property
def group_report_entries(self) -> AccessModel[ReportEntryOut, ReportEntryModel]:
return AccessModel(self.session, pk_id, ReportEntryModel, ReportEntryOut)

View File

@@ -1,24 +0,0 @@
from sqlalchemy.orm.session import Session
from mealie.db.models.group import Group
from mealie.schema.meal_plan.meal import MealPlanOut
from mealie.schema.user.user import GroupInDB
from ._access_model import AccessModel
class GroupDataAccessModel(AccessModel[GroupInDB, Group]):
def get_meals(self, session: Session, match_value: str, match_key: str = "name") -> list[MealPlanOut]:
"""A Helper function to get the group from the database and return a sorted list of
Args:
session (Session): SqlAlchemy Session
match_value (str): Match Value
match_key (str, optional): Match Key. Defaults to "name".
Returns:
list[MealPlanOut]: [description]
"""
group: GroupInDB = session.query(self.sql_model).filter_by(**{match_key: match_value}).one_or_none()
return group.mealplans

View File

@@ -1,25 +0,0 @@
from datetime import date
from uuid import UUID
from mealie.db.models.group import GroupMealPlan
from mealie.schema.meal_plan.new_meal import ReadPlanEntry
from ._access_model import AccessModel
class MealDataAccessModel(AccessModel[ReadPlanEntry, GroupMealPlan]):
def get_slice(self, start: date, end: date, group_id: UUID) -> list[ReadPlanEntry]:
start = start.strftime("%Y-%m-%d")
end = end.strftime("%Y-%m-%d")
qry = self.session.query(GroupMealPlan).filter(
GroupMealPlan.date.between(start, end),
GroupMealPlan.group_id == group_id,
)
return [self.schema.from_orm(x) for x in qry.all()]
def get_today(self, group_id: UUID) -> list[ReadPlanEntry]:
today = date.today()
qry = self.session.query(GroupMealPlan).filter(GroupMealPlan.date == today, GroupMealPlan.group_id == group_id)
return [self.schema.from_orm(x) for x in qry.all()]

View File

@@ -1,82 +0,0 @@
from random import randint
from typing import Any
from sqlalchemy.orm import joinedload
from mealie.db.models.recipe.ingredient import RecipeIngredient
from mealie.db.models.recipe.recipe import RecipeModel
from mealie.db.models.recipe.settings import RecipeSettings
from mealie.schema.recipe import Recipe
from ._access_model import AccessModel
class RecipeDataAccessModel(AccessModel[Recipe, RecipeModel]):
def get_all_public(self, limit: int = None, order_by: str = None, start=0, override_schema=None):
eff_schema = override_schema or self.schema
if order_by:
order_attr = getattr(self.sql_model, str(order_by))
return [
eff_schema.from_orm(x)
for x in self.session.query(self.sql_model)
.join(RecipeSettings)
.filter(RecipeSettings.public == True) # noqa: 711
.order_by(order_attr.desc())
.offset(start)
.limit(limit)
.all()
]
return [
eff_schema.from_orm(x)
for x in self.session.query(self.sql_model)
.join(RecipeSettings)
.filter(RecipeSettings.public == True) # noqa: 711
.offset(start)
.limit(limit)
.all()
]
def update_image(self, slug: str, _: str = None) -> str:
entry: RecipeModel = self._query_one(match_value=slug)
entry.image = randint(0, 255)
self.session.commit()
return entry.image
def count_uncategorized(self, count=True, override_schema=None) -> int:
return self._count_attribute(
attribute_name=RecipeModel.recipe_category,
attr_match=None,
count=count,
override_schema=override_schema,
)
def count_untagged(self, count=True, override_schema=None) -> int:
return self._count_attribute(
attribute_name=RecipeModel.tags,
attr_match=None,
count=count,
override_schema=override_schema,
)
def summary(self, group_id, start=0, limit=99999, load_foods=False) -> Any:
args = [
joinedload(RecipeModel.recipe_category),
joinedload(RecipeModel.tags),
joinedload(RecipeModel.tools),
]
if load_foods:
args.append(joinedload(RecipeModel.recipe_ingredient).options(joinedload(RecipeIngredient.food)))
return (
self.session.query(RecipeModel)
.options(*args)
.filter(RecipeModel.group_id == group_id)
.offset(start)
.limit(limit)
.all()
)

View File

@@ -1,36 +0,0 @@
import random
import shutil
from mealie.assets import users as users_assets
from mealie.schema.user.user import PrivateUser, User
from ._access_model import AccessModel
class UserDataAccessModel(AccessModel[PrivateUser, User]):
def update_password(self, id, password: str):
entry = self._query_one(match_value=id)
entry.update_password(password)
self.session.commit()
return self.schema.from_orm(entry)
def create(self, user: PrivateUser):
new_user = super().create(user)
# Select Random Image
all_images = [
users_assets.img_random_1,
users_assets.img_random_2,
users_assets.img_random_3,
]
random_image = random.choice(all_images)
shutil.copy(random_image, new_user.directory() / "profile.webp")
return new_user
def delete(self, id: str) -> User:
entry = super().delete(id)
# Delete the user's directory
shutil.rmtree(PrivateUser.get_directory(id))
return entry

View File

@@ -1,40 +0,0 @@
import json
from pathlib import Path
from mealie.core.root_logger import get_logger
from mealie.db.data_access_layer.access_model_factory import Database
from mealie.schema.recipe import CreateIngredientFood, CreateIngredientUnit
CWD = Path(__file__).parent
logger = get_logger(__name__)
def get_default_foods():
with open(CWD.joinpath("resources", "foods", "en-us.json"), "r") as f:
foods = json.loads(f.read())
return foods
def get_default_units() -> dict[str, str]:
with open(CWD.joinpath("resources", "units", "en-us.json"), "r") as f:
units = json.loads(f.read())
return units
def default_recipe_unit_init(db: Database) -> None:
for unit in get_default_units().values():
try:
db.ingredient_units.create(
CreateIngredientUnit(
name=unit["name"], description=unit["description"], abbreviation=unit["abbreviation"]
)
)
except Exception as e:
logger.error(e)
for food in get_default_foods():
try:
db.ingredient_foods.create(CreateIngredientFood(name=food, description=""))
except Exception as e:
logger.error(e)

View File

@@ -1,62 +0,0 @@
from mealie.core import root_logger
from mealie.core.config import get_app_settings
from mealie.core.security import hash_password
from mealie.db.data_access_layer.access_model_factory import Database
logger = root_logger.get_logger("init_users")
settings = get_app_settings()
def dev_users() -> list[dict]:
return [
{
"full_name": "Jason",
"username": "jason",
"email": "jason@email.com",
"password": hash_password(settings.DEFAULT_PASSWORD),
"group": settings.DEFAULT_GROUP,
"admin": False,
},
{
"full_name": "Bob",
"username": "bob",
"email": "bob@email.com",
"password": hash_password(settings.DEFAULT_PASSWORD),
"group": settings.DEFAULT_GROUP,
"admin": False,
},
{
"full_name": "Sarah",
"username": "sarah",
"email": "sarah@email.com",
"password": hash_password(settings.DEFAULT_PASSWORD),
"group": settings.DEFAULT_GROUP,
"admin": False,
},
{
"full_name": "Sammy",
"username": "sammy",
"email": "sammy@email.com",
"password": hash_password(settings.DEFAULT_PASSWORD),
"group": settings.DEFAULT_GROUP,
"admin": False,
},
]
def default_user_init(db: Database):
default_user = {
"full_name": "Change Me",
"username": "admin",
"email": settings.DEFAULT_EMAIL,
"password": hash_password(settings.DEFAULT_PASSWORD),
"group": settings.DEFAULT_GROUP,
"admin": True,
}
logger.info("Generating Default User")
db.users.create(default_user)
if not settings.PRODUCTION:
for user in dev_users():
db.users.create(user)

View File

@@ -1,224 +0,0 @@
{
"acorn-squash": "acorn squash",
"alfalfa-sprouts": "alfalfa sprouts",
"anchovies": "anchovies",
"apples": "apples",
"artichoke": "artichoke",
"arugula": "arugula",
"asparagus": "asparagus",
"aubergine": "aubergine",
"avocado": "avocado",
"bacon": "bacon",
"baking-powder": "baking powder",
"baking-soda": "baking soda",
"baking-sugar": "baking sugar",
"bar-sugar": "bar sugar",
"basil": "basil",
"bell-peppers": "bell peppers",
"blackberries": "blackberries",
"brassicas": "brassicas",
"bok-choy": "bok choy",
"broccoflower": "broccoflower",
"broccoli": "broccoli",
"broccolini": "broccolini",
"broccoli-rabe": "broccoli rabe",
"brussels-sprouts": "brussels sprouts",
"cabbage": "cabbage",
"cauliflower": "cauliflower",
"chinese-leaves": "chinese leaves",
"collard-greens": "collard greens",
"kohlrabi": "kohlrabi",
"bread": "bread",
"breadfruit": "breadfruit",
"broad-beans": "broad beans",
"brown-sugar": "brown sugar",
"butter": "butter",
"butternut-pumpkin": "butternut pumpkin",
"butternut-squash": "butternut squash",
"cactus-edible": "cactus, edible",
"calabrese": "calabrese",
"cannabis": "cannabis",
"capsicum": "capsicum",
"caraway": "caraway",
"carrot": "carrot",
"castor-sugar": "castor sugar",
"cayenne-pepper": "cayenne pepper",
"celeriac": "celeriac",
"celery": "celery",
"cereal-grains": "cereal grains",
"rice": "rice",
"chard": "chard",
"cheese": "cheese",
"chicory": "chicory",
"chilli-peppers": "chilli peppers",
"chives": "chives",
"chocolate": "chocolate",
"cilantro": "cilantro",
"cinnamon": "cinnamon",
"clarified-butter": "clarified butter",
"coconut": "coconut",
"coconut-milk": "coconut milk",
"coffee": "coffee",
"confectioners-sugar": "confectioners' sugar",
"coriander": "coriander",
"corn": "corn",
"corn-syrup": "corn syrup",
"cottonseed-oil": "cottonseed oil",
"courgette": "courgette",
"cream-of-tartar": "cream of tartar",
"cucumber": "cucumber",
"cumin": "cumin",
"daikon": "daikon",
"dairy-products-and-dairy-substitutes": "dairy products and dairy substitutes",
"eggs": "eggs",
"ghee": "ghee",
"milk": "milk",
"dandelion": "dandelion",
"demerara-sugar": "demerara sugar",
"dough": "dough",
"edible-cactus": "edible cactus",
"eggplant": "eggplant",
"endive": "endive",
"fats": "fats",
"spek": "spek",
"fava-beans": "fava beans",
"fiddlehead": "fiddlehead",
"fish": "fish",
"catfish": "catfish ",
"cod": "cod",
"salt-cod": "salt cod",
"salmon": "salmon",
"skate": "skate",
"stockfish": "stockfish",
"trout": "trout",
"tuna": "tuna",
"five-spice-powder": "five spice powder",
"flour": "flour",
"frisee": "frisee",
"fructose": "fructose",
"fruit": "fruit",
"apple": "apple",
"oranges": "oranges",
"pear": "pear",
"tomato": "tomato ",
"fruit-sugar": "fruit sugar",
"garam-masala": "garam masala",
"garlic": "garlic",
"gem-squash": "gem squash",
"ginger": "ginger",
"giblets": "giblets",
"grains": "grains",
"maize": "maize",
"sweetcorn": "sweetcorn",
"teff": "teff",
"grape-seed-oil": "grape seed oil",
"green-onion": "green onion",
"heart-of-palm": "heart of palm",
"hemp": "hemp",
"herbs": "herbs",
"oregano": "oregano",
"parsley": "parsley",
"honey": "honey",
"horse": "horse",
"icing-sugar": "icing sugar",
"isomalt": "isomalt",
"jackfruit": "jackfruit",
"jaggery": "jaggery",
"jams": "jams",
"jellies": "jellies",
"jerusalem-artichoke": "jerusalem artichoke",
"jicama": "jicama",
"kale": "kale",
"kumara": "kumara",
"leavening-agents": "leavening agents",
"leek": "leek",
"legumes": "legumes ",
"peas": "peas",
"beans": "beans",
"lentils": "lentils",
"lemongrass": "lemongrass",
"lettuce": "lettuce",
"liver": "liver",
"maple-syrup": "maple syrup",
"meat": "meat",
"mortadella": "mortadella",
"mushroom": "mushroom",
"white-mushroom": "white mushroom",
"mussels": "mussels",
"nori": "nori",
"nutmeg": "nutmeg",
"nutritional-yeast-flakes": "nutritional yeast flakes",
"nuts": "nuts",
"nanaimo-bar-mix": "nanaimo bar mix",
"octopuses": "octopuses",
"oils": "oils",
"olive-oil": "olive oil",
"okra": "okra",
"olive": "olive",
"onion-family": "onion family",
"onion": "onion",
"scallion": "scallion",
"shallot": "shallot",
"spring-onion": "spring onion",
"orange-blossom-water": "orange blossom water",
"oysters": "oysters",
"panch-puran": "panch puran",
"paprika": "paprika",
"parsnip": "parsnip",
"pepper": "pepper",
"peppers": "peppers",
"plantain": "plantain",
"pineapple": "pineapple",
"poppy-seeds": "poppy seeds",
"potatoes": "potatoes",
"poultry": "poultry",
"powdered-sugar": "powdered sugar",
"pumpkin": "pumpkin",
"pumpkin-seeds": "pumpkin seeds",
"radish": "radish",
"rape": "rape",
"raw-sugar": "raw sugar",
"refined-sugar": "refined sugar",
"rice-flour": "rice flour",
"rock-sugar": "rock sugar",
"rum": "rum",
"salt": "salt",
"seafood": "seafood",
"seeds": "seeds",
"sesame-seeds": "sesame seeds",
"sunflower-seeds": "sunflower seeds",
"soda": "soda",
"soda-baking": "soda, baking",
"soybean": "soybean",
"spaghetti-squash": "spaghetti squash",
"spices": "spices",
"spinach": "spinach",
"squash-family": "squash family",
"squash": "squash",
"zucchini": "zucchini",
"sugar": "sugar",
"caster-sugar": "caster sugar",
"granulated-sugar": "granulated sugar",
"superfine-sugar": "superfine sugar",
"turbanado-sugar": "turbanado sugar",
"unrefined-sugar": "unrefined sugar",
"white-sugar": "white sugar",
"sweet-potato": "sweet potato",
"sweeteners": "sweeteners",
"cane-sugar": "cane sugar",
"tahini": "tahini",
"tubers": "tubers",
"potato": "potato",
"sunchoke": "sunchoke",
"taro": "taro",
"yam": "yam",
"turnip": "turnip",
"vanilla": "vanilla",
"vegetables": "vegetables",
"fiddlehead-fern": "fiddlehead fern",
"ful": "ful",
"watercress": "watercress",
"watermelon": "watermelon",
"xanthan-gum": "xanthan gum",
"yeast": "yeast"
}

View File

@@ -1,102 +0,0 @@
{
"teaspoon": {
"name": "teaspoon",
"description": "",
"abbreviation": "tsp"
},
"tablespoon": {
"name": "tablespoon",
"description": "",
"abbreviation": "tbsp"
},
"cup": {
"name": "cup",
"description": "",
"abbreviation": "cup"
},
"fluid-ounce": {
"name": "fluid ounce",
"description": "",
"abbreviation": "fl oz"
},
"pint": {
"name": "pint",
"description": "",
"abbreviation": "pt"
},
"quart": {
"name": "quart",
"description": "",
"abbreviation": "qt"
},
"gallon": {
"name": "gallon",
"description": "",
"abbreviation": "gal"
},
"milliliter": {
"name": "milliliter",
"description": "",
"abbreviation": "ml"
},
"liter": {
"name": "liter",
"description": "",
"abbreviation": "l"
},
"pound": {
"name": "pound",
"description": "",
"abbreviation": "lb"
},
"ounce": {
"name": "ounce",
"description": "",
"abbreviation": "oz"
},
"gram": {
"name": "gram",
"description": "",
"abbreviation": "g"
},
"kilogram": {
"name": "kilogram",
"description": "",
"abbreviation": "kg"
},
"milligram": {
"name": "milligram",
"description": "",
"abbreviation": "mg"
},
"splash": {
"name": "splash",
"description": "",
"abbreviation": ""
},
"dash": {
"name": "dash",
"description": "",
"abbreviation": ""
},
"serving": {
"name": "serving",
"description": "",
"abbreviation": ""
},
"head": {
"name": "head",
"description": "",
"abbreviation": ""
},
"clove": {
"name": "clove",
"description": "",
"abbreviation": ""
},
"can": {
"name": "can",
"description": "",
"abbreviation": ""
}
}

View File

@@ -1,7 +0,0 @@
from sqlalchemy.orm import Session
from .data_access_layer.access_model_factory import Database
def get_database(session: Session):
return Database(session)

View File

@@ -1,11 +1,11 @@
from mealie.core import root_logger
from mealie.core.config import get_app_settings
from mealie.db.data_access_layer.access_model_factory import Database
from mealie.db.data_initialization.init_units_foods import default_recipe_unit_init
from mealie.db.data_initialization.init_users import default_user_init
from mealie.db.database import get_database
from mealie.db.db_setup import create_session, engine
from mealie.db.models._model_base import SqlAlchemyBase
from mealie.repos.all_repositories import get_repositories
from mealie.repos.repository_factory import AllRepositories
from mealie.repos.seed.init_units_foods import default_recipe_unit_init
from mealie.repos.seed.init_users import default_user_init
from mealie.schema.user.user import GroupBase
from mealie.services.events import create_general_event
from mealie.services.group_services.group_utils import create_new_group
@@ -21,13 +21,13 @@ def create_all_models():
SqlAlchemyBase.metadata.create_all(engine)
def init_db(db: Database) -> None:
def init_db(db: AllRepositories) -> None:
default_group_init(db)
default_user_init(db)
default_recipe_unit_init(db)
def default_group_init(db: Database):
def default_group_init(db: AllRepositories):
logger.info("Generating Default Group")
create_new_group(db, GroupBase(name=settings.DEFAULT_GROUP))
@@ -36,7 +36,7 @@ def main():
create_all_models()
session = create_session()
db = get_database(session)
db = get_repositories(session)
try:
init_user = db.users.get_all()