diff --git a/mealie/data/db/mealie.sqlite b/mealie/data/db/mealie.sqlite index 5a358d2ab..6a5535535 100644 Binary files a/mealie/data/db/mealie.sqlite and b/mealie/data/db/mealie.sqlite differ diff --git a/mealie/db/db_base.py b/mealie/db/db_base.py index c5a584377..d673fce7d 100644 --- a/mealie/db/db_base.py +++ b/mealie/db/db_base.py @@ -146,6 +146,7 @@ class BaseDocument: return BaseDocument._unpack_mongo(new_document) elif USE_SQL: session = self.create_session() + print(document) new_document = self.sql_model(**document) session.add(new_document) return_data = new_document.dict() @@ -153,6 +154,22 @@ class BaseDocument: return return_data + def update(self, match_value, new_data) -> dict: + if USE_MONGO: + return_data = self.update_mongo(match_value, new_data) + elif USE_SQL: + session, entry = self._query_one(match_value=match_value) + entry.update(session=session, **new_data) + return_data = entry.dict() + print(entry) + session.commit() + + session.close() + else: + raise Exception("No Database Configured") + + return return_data + def delete(self, primary_key_value) -> dict: if USE_MONGO: document = self.document.objects.get( diff --git a/mealie/db/db_mealplan.py b/mealie/db/db_mealplan.py index 70769a414..00ed5e3cf 100644 --- a/mealie/db/db_mealplan.py +++ b/mealie/db/db_mealplan.py @@ -1,11 +1,12 @@ from typing import List -from db.sql.meal_models import MealPlanModel from settings import USE_MONGO, USE_SQL from db.db_base import BaseDocument from db.db_setup import USE_MONGO, USE_SQL from db.mongo.meal_models import MealDocument, MealPlanDocument +from db.sql.db_session import create_session +from db.sql.meal_models import MealPlanModel class _Meals(BaseDocument): @@ -13,6 +14,8 @@ class _Meals(BaseDocument): self.primary_key = "uid" if USE_SQL: self.sql_model = MealPlanModel + self.create_session = create_session + self.document = MealPlanDocument @staticmethod @@ -34,7 +37,7 @@ class _Meals(BaseDocument): return meal_docs - def save_new(self, plan_data: dict) -> None: + def save_new_mongo(self, plan_data: dict) -> None: """Saves a new meal plan into the database Args: \n @@ -49,7 +52,7 @@ class _Meals(BaseDocument): elif USE_SQL: pass - def update(self, uid: str, plan_data: dict) -> dict: + def update_mongo(self, uid: str, plan_data: dict) -> dict: if USE_MONGO: document = self.document.objects.get(uid=uid) if document: diff --git a/mealie/db/db_recipes.py b/mealie/db/db_recipes.py index 9fcf50de8..271b8893a 100644 --- a/mealie/db/db_recipes.py +++ b/mealie/db/db_recipes.py @@ -3,7 +3,7 @@ from settings import USE_MONGO, USE_SQL from db.db_base import BaseDocument from db.mongo.recipe_models import RecipeDocument from db.sql.db_session import create_session -from db.sql.recipe_models import RecipeIngredient, RecipeModel +from db.sql.recipe_models import RecipeModel class _Recipes(BaseDocument): @@ -23,7 +23,7 @@ class _Recipes(BaseDocument): return recipe_data - def update(self, slug: str, new_data: dict) -> None: + def update_mongo(self, slug: str, new_data: dict) -> None: if USE_MONGO: document = self.document.objects.get(slug=slug) @@ -47,16 +47,16 @@ class _Recipes(BaseDocument): document.update(set__extras=new_data.get("extras")) document.save() - return new_data.get("slug") - elif USE_SQL: - session, recipe = self._query_one(match_value=slug) - recipe.update(session=session, **new_data) - recipe_dict = recipe.dict() - session.commit() + return new_data + # elif USE_SQL: + # session, recipe = self._query_one(match_value=slug) + # recipe.update(session=session, **new_data) + # recipe_dict = recipe.dict() + # session.commit() - session.close() + # session.close() - return recipe_dict + # return recipe_dict def update_image(self, slug: str, extension: str) -> None: if USE_MONGO: diff --git a/mealie/db/db_settings.py b/mealie/db/db_settings.py index d2a340742..997ec595f 100644 --- a/mealie/db/db_settings.py +++ b/mealie/db/db_settings.py @@ -14,6 +14,7 @@ class _Settings(BaseDocument): if USE_SQL: self.sql_model = SiteSettingsModel + self.create_session = create_session self.document = SiteSettingsDocument @@ -33,20 +34,11 @@ class _Settings(BaseDocument): return new_settings.dict() - def update(self, name: str, new_data: dict) -> dict: + def update_mongo(self, name: str, new_data: dict) -> dict: if USE_MONGO: document = self.document.objects.get(name=name) if document: document.update(set__webhooks=WebhooksDocument(**new_data["webhooks"])) document.save() elif USE_SQL: - session = create_session() - updated_settings = ( - session.query(self.sql_model) - .filter_by(**{self.primary_key: name}) - .one() - ) - updated_settings.update(**new_data) - - session.commit() return diff --git a/mealie/db/sql/meal_models.py b/mealie/db/sql/meal_models.py index e08bc57c0..ad880267c 100644 --- a/mealie/db/sql/meal_models.py +++ b/mealie/db/sql/meal_models.py @@ -3,7 +3,7 @@ from typing import List import sqlalchemy as sa import sqlalchemy.orm as orm -from db.sql.model_base import SqlAlchemyBase +from db.sql.model_base import BaseMixins, SqlAlchemyBase class Meal(SqlAlchemyBase): @@ -17,6 +17,14 @@ class Meal(SqlAlchemyBase): image = sa.Column(sa.String) description = sa.Column(sa.String) + def __init__(self, slug, name, date, dateText, image, description) -> None: + self.slug = slug + self.name = name + self.date = date + self.dateText = dateText + self.image = image + self.description = description + def dict(self) -> dict: data = { "slug": self.slug, @@ -30,21 +38,21 @@ class Meal(SqlAlchemyBase): return data -class MealPlanModel(SqlAlchemyBase): +class MealPlanModel(SqlAlchemyBase, BaseMixins): __tablename__ = "mealplan" - uid = sa.Column( - sa.String, default=uuid.uuid1, primary_key=True, unique=True - ) #! Probably Bad? + uid = sa.Column(sa.Integer, primary_key=True, unique=True) #! Probably Bad? startDate = sa.Column(sa.Date) endDate = sa.Column(sa.Date) meals: List[Meal] = orm.relation(Meal) - def __init__(self, startDate, endDate, meals) -> None: + def __init__(self, startDate, endDate, meals, uid=None) -> None: self.startDate = startDate self.endDate = endDate - self.meals = [Meal(meal) for meal in meals] + self.meals = [Meal(**meal) for meal in meals] + + def update(self, session, startDate, endDate, meals, uid) -> None: + MealPlanModel._sql_remove_list(session, [Meal], uid) - def update(self, startDate, endDate, meals) -> None: self.__init__(startDate, endDate, meals) def dict(self) -> dict: diff --git a/mealie/db/sql/model_base.py b/mealie/db/sql/model_base.py index 94d0abcff..96dc8b16c 100644 --- a/mealie/db/sql/model_base.py +++ b/mealie/db/sql/model_base.py @@ -1,3 +1,22 @@ import sqlalchemy.ext.declarative as dec -SqlAlchemyBase = dec.declarative_base() \ No newline at end of file +SqlAlchemyBase = dec.declarative_base() + + +class BaseMixins: + @staticmethod + def _sql_remove_list(session, list_of_tables: list, parent_id): + """ + docstring + """ + for table in list_of_tables: + session.query(table).filter_by(parent_id=parent_id).delete() + + @staticmethod + def _flatten_dict(list_of_dict: list[dict]): + finalMap = {} + for d in list_of_dict: + + finalMap.update(d.dict()) + + return finalMap diff --git a/mealie/db/sql/recipe_models.py b/mealie/db/sql/recipe_models.py index c46c5b4d4..58b926ccd 100644 --- a/mealie/db/sql/recipe_models.py +++ b/mealie/db/sql/recipe_models.py @@ -4,7 +4,7 @@ from typing import List import sqlalchemy as sa import sqlalchemy.orm as orm -from db.sql.model_base import SqlAlchemyBase +from db.sql.model_base import BaseMixins, SqlAlchemyBase class ApiExtras(SqlAlchemyBase): @@ -79,7 +79,7 @@ class RecipeInstruction(SqlAlchemyBase): return data -class RecipeModel(SqlAlchemyBase): +class RecipeModel(SqlAlchemyBase, BaseMixins): __tablename__ = "recipes" id = sa.Column(sa.Integer, primary_key=True) name = sa.Column(sa.String) @@ -155,21 +155,6 @@ class RecipeModel(SqlAlchemyBase): self.orgURL = orgURL self.extras = [ApiExtras(key=key, value=value) for key, value in extras.items()] - @staticmethod - def _update_list_str(new_list, existing, cls_model): - current_index = 0 - - new_list = [] - for item in new_list: - try: - existing.update(new_list[current_index]) - current_index += 1 - except: - existing.append(cls_model(item)) - - for item in new_list[current_index:]: - existing.append(cls_model(item)) - def update( self, session, @@ -189,20 +174,14 @@ class RecipeModel(SqlAlchemyBase): orgURL: str = None, extras: dict = None, ): + """Updated a database entry by removing nested rows and rebuilds the row through the __init__ functions""" self.name = name self.description = description self.image = image self.recipeYield = recipeYield - # Deleted Recipe Ingredeints - self.recipeIngredient = [ - RecipeIngredient(ingredient=ingr) for ingr in recipeIngredient - ] - list_of_tables = [RecipeIngredient, RecipeInstruction, Category, Tag, ApiExtras] - - for table in list_of_tables: - session.query(table).filter_by(parent_id=self.id).delete() + RecipeModel._sql_remove_list(session, list_of_tables, self.id) self.__init__( name=name, @@ -222,16 +201,6 @@ class RecipeModel(SqlAlchemyBase): extras=extras, ) - - @staticmethod - def _flatten_dict(list_of_dict: List[dict]): - finalMap = {} - for d in list_of_dict: - - finalMap.update(d.dict()) - - return finalMap - def dict(self): data = { "name": self.name, diff --git a/mealie/db/sql/settings_models.py b/mealie/db/sql/settings_models.py index e33b838ad..c710b9241 100644 --- a/mealie/db/sql/settings_models.py +++ b/mealie/db/sql/settings_models.py @@ -1,22 +1,28 @@ import sqlalchemy as sa import sqlalchemy.orm as orm -from db.sql.model_base import SqlAlchemyBase +from db.sql.model_base import BaseMixins, SqlAlchemyBase -class WebhookURLModel(SqlAlchemyBase): - __tablename__ = "webhook_urls" - id = sa.Column(sa.Integer, primary_key=True) - url = sa.Column(sa.String) - parent_id = sa.Column(sa.Integer, sa.ForeignKey("webhook_settings.id")) +class SiteSettingsModel(SqlAlchemyBase): + __tablename__ = "site_settings" + name = sa.Column(sa.String, primary_key=True) + webhooks = orm.relationship("WebHookModel", uselist=False, cascade="all, delete") - def update(self, url) -> str: - self.url = url + def __init__(self, name: str = None, webhooks: dict = None) -> None: + self.name = name + self.webhooks = WebHookModel(**webhooks) - def to_str(self): - return self.url + def update(self, session, name, webhooks: dict) -> dict: + self.name = name + self.webhooks.update(session=session, **webhooks) + return + + def dict(self): + data = {"name": self.name, "webhooks": self.webhooks.dict()} + return data -class WebHookModel(SqlAlchemyBase): +class WebHookModel(SqlAlchemyBase, BaseMixins): __tablename__ = "webhook_settings" id = sa.Column(sa.Integer, primary_key=True) parent_id = sa.Column(sa.String, sa.ForeignKey("site_settings.name")) @@ -29,25 +35,16 @@ class WebHookModel(SqlAlchemyBase): def __init__( self, webhookURLs: list, webhookTime: str, enabled: bool = False ) -> None: - self.webhookURLs = [WebhookURLModel(x) for x in webhookURLs] + self.webhookURLs = [WebhookURLModel(url=x) for x in webhookURLs] self.webhookTime = webhookTime self.enabled = enabled - def update(self, webhookURLs: list, webhookTime: str, enabled: bool) -> None: - current_webhooks = 0 + def update( + self, session, webhookURLs: list, webhookTime: str, enabled: bool + ) -> None: + self._sql_remove_list(session, [WebhookURLModel], self.id) - for webhook_url in self.webhookURLs: - try: - webhook_url.update(webhookURLs[current_webhooks]) - current_webhooks += 1 - except: - self.webhookURLs.remove(webhook_url) - - for webhook_url in webhookURLs[current_webhooks:]: - self.webhookURLs.append(WebhookURLModel(webhook_url)) - - self.webhookTime = webhookTime - self.enabled = enabled + self.__init__(webhookURLs, webhookTime, enabled) def dict(self): data = { @@ -58,22 +55,31 @@ class WebHookModel(SqlAlchemyBase): return data -class SiteSettingsModel(SqlAlchemyBase): - __tablename__ = "site_settings" +class WebhookURLModel(SqlAlchemyBase): + __tablename__ = "webhook_urls" + id = sa.Column(sa.Integer, primary_key=True) + url = sa.Column(sa.String) + parent_id = sa.Column(sa.Integer, sa.ForeignKey("webhook_settings.id")) + + def to_str(self): + return self.url + + +class SiteThemeModel(SqlAlchemyBase): + __tablename__ = "site_theme" name = sa.Column(sa.String, primary_key=True) - webhooks = orm.relationship("WebHookModel", uselist=False, cascade="all, delete") + colors = orm.relationship("ThemeColorsModel", uselist=False, cascade="all, delete") - def __init__(self, name: str = None, webhooks: dict = None) -> None: + def __init__(self, name: str, colors: dict) -> None: self.name = name - self.webhooks = WebHookModel(**webhooks) + self.colors = ThemeColorsModel(**colors) - def update(self, name, webhooks: dict) -> dict: - self.name = name - self.webhooks.update(**webhooks) - return + def update(self, name, colors: dict) -> dict: + self.colors.update(**colors) + return self.dict() def dict(self): - data = {"name": self.name, "webhooks": self.webhooks.dict()} + data = {"name": self.name, "colors": self.colors.dict()} return data @@ -118,21 +124,3 @@ class ThemeColorsModel(SqlAlchemyBase): "error": self.error, } return data - - -class SiteThemeModel(SqlAlchemyBase): - __tablename__ = "site_theme" - name = sa.Column(sa.String, primary_key=True) - colors = orm.relationship("ThemeColorsModel", uselist=False, cascade="all, delete") - - def __init__(self, name: str, colors: dict) -> None: - self.name = name - self.colors = ThemeColorsModel(**colors) - - def update(self, name, colors: dict) -> dict: - self.colors.update(**colors) - return self.dict() - - def dict(self): - data = {"name": self.name, "colors": self.colors.dict()} - return data diff --git a/mealie/routes/meal_routes.py b/mealie/routes/meal_routes.py index 66b2632f1..efd4ebe82 100644 --- a/mealie/routes/meal_routes.py +++ b/mealie/routes/meal_routes.py @@ -32,15 +32,16 @@ def set_meal_plan(data: MealPlan): @router.post("/api/meal-plan/{plan_id}/update/", tags=["Meal Plan"]) def update_meal_plan(plan_id: str, meal_plan: MealPlan): """ Updates a meal plan based off ID """ - - try: - meal_plan.process_meals() - meal_plan.update(plan_id) - except: - raise HTTPException( - status_code=404, - detail=SnackResponse.error("Unable to Update Mealplan"), - ) + meal_plan.process_meals() + meal_plan.update(plan_id) + # try: + # meal_plan.process_meals() + # meal_plan.update(plan_id) + # except: + # raise HTTPException( + # status_code=404, + # detail=SnackResponse.error("Unable to Update Mealplan"), + # ) return SnackResponse.success("Mealplan Updated") diff --git a/mealie/services/backups/exports.py b/mealie/services/backups/exports.py index 81d02e2bc..8784cb983 100644 --- a/mealie/services/backups/exports.py +++ b/mealie/services/backups/exports.py @@ -7,6 +7,7 @@ from jinja2 import Template from services.recipe_services import Recipe from services.settings_services import SiteSettings, SiteTheme from settings import BACKUP_DIR, IMG_DIR, TEMP_DIR, TEMPLATE_DIR +from sqlalchemy.sql.sqltypes import String from utils.logger import logger @@ -108,7 +109,7 @@ class ExportDatabase: @staticmethod def _write_json_file(data, out_file: Path): - json_data = json.dumps(data, indent=4) + json_data = json.dumps(data, indent=4, default=str) with open(out_file, "w") as f: f.write(json_data) diff --git a/mealie/services/settings_services.py b/mealie/services/settings_services.py index 792b8c3f3..fc239b621 100644 --- a/mealie/services/settings_services.py +++ b/mealie/services/settings_services.py @@ -43,7 +43,7 @@ class SiteSettings(BaseModel): return cls(**document) def update(self): - db.settings.update(name="main", new_data=self.dict()) + db.settings.update("main", new_data=self.dict()) class Colors(BaseModel):