fix: Organizer Models Not Lazy Loaded When Migrating (#2760)

* lazy load attrs when running unique constraint fix

* speeling

---------

Co-authored-by: boc-the-git <3479092+boc-the-git@users.noreply.github.com>
This commit is contained in:
Michael Genson 2023-11-27 10:48:51 -06:00 committed by GitHub
parent 340841b37a
commit 714fb6a723
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -10,6 +10,7 @@ from dataclasses import dataclass
from typing import Any from typing import Any
import sqlalchemy as sa import sqlalchemy as sa
from pydantic import UUID4
from sqlalchemy.orm import Session, load_only from sqlalchemy.orm import Session, load_only
import mealie.db.migration_types import mealie.db.migration_types
@ -51,58 +52,78 @@ def _get_duplicates(session: Session, model: SqlAlchemyBase) -> defaultdict[str,
return duplicate_map return duplicate_map
def _resolve_duplicate_food(session: Session, keep_food: IngredientFoodModel, dupe_food: IngredientFoodModel): def _resolve_duplicate_food(
for shopping_list_item in session.query(ShoppingListItem).filter_by(food_id=dupe_food.id).all(): session: Session,
shopping_list_item.food_id = keep_food.id keep_food: IngredientFoodModel,
keep_food_id: UUID4,
dupe_food_id: UUID4,
):
for shopping_list_item in session.query(ShoppingListItem).filter_by(food_id=dupe_food_id).all():
shopping_list_item.food_id = keep_food_id
shopping_list_item.food = keep_food shopping_list_item.food = keep_food
session.commit() session.commit()
for recipe_ingredient in session.query(RecipeIngredientModel).filter_by(food_id=dupe_food.id).all(): for recipe_ingredient in (
recipe_ingredient.food_id = keep_food.id session.query(RecipeIngredientModel)
.options(load_only(RecipeIngredientModel.id, RecipeIngredientModel.food_id))
.filter_by(food_id=dupe_food_id)
.all()
):
recipe_ingredient.food_id = keep_food_id
recipe_ingredient.food = keep_food recipe_ingredient.food = keep_food
session.commit() session.commit()
session.delete(dupe_food) session.query(IngredientFoodModel).options(load_only(IngredientFoodModel.id)).filter_by(id=dupe_food_id).delete()
session.commit() session.commit()
def _resolve_duplicate_unit(session: Session, keep_unit: IngredientUnitModel, dupe_unit: IngredientUnitModel): def _resolve_duplicate_unit(
for shopping_list_item in session.query(ShoppingListItem).filter_by(unit_id=dupe_unit.id).all(): session: Session,
shopping_list_item.unit_id = keep_unit.id keep_unit: IngredientUnitModel,
keep_unit_id: UUID4,
dupe_unit_id: UUID4,
):
for shopping_list_item in session.query(ShoppingListItem).filter_by(unit_id=dupe_unit_id).all():
shopping_list_item.unit_id = keep_unit_id
shopping_list_item.unit = keep_unit shopping_list_item.unit = keep_unit
session.commit() session.commit()
for recipe_ingredient in session.query(RecipeIngredientModel).filter_by(unit_id=dupe_unit.id).all(): for recipe_ingredient in session.query(RecipeIngredientModel).filter_by(unit_id=dupe_unit_id).all():
recipe_ingredient.unit_id = keep_unit.id recipe_ingredient.unit_id = keep_unit_id
recipe_ingredient.unit = keep_unit recipe_ingredient.unit = keep_unit
session.commit() session.commit()
session.delete(dupe_unit) session.query(IngredientUnitModel).options(load_only(IngredientUnitModel.id)).filter_by(id=dupe_unit_id).delete()
session.commit() session.commit()
def _resolve_duplicate_label(session: Session, keep_label: MultiPurposeLabel, dupe_label: MultiPurposeLabel): def _resolve_duplicate_label(
for shopping_list_item in session.query(ShoppingListItem).filter_by(label_id=dupe_label.id).all(): session: Session,
shopping_list_item.label_id = keep_label.id keep_label: MultiPurposeLabel,
keep_label_id: UUID4,
dupe_label_id: UUID4,
):
for shopping_list_item in session.query(ShoppingListItem).filter_by(label_id=dupe_label_id).all():
shopping_list_item.label_id = keep_label_id
shopping_list_item.label = keep_label shopping_list_item.label = keep_label
session.commit() session.commit()
for ingredient_food in session.query(IngredientFoodModel).filter_by(label_id=dupe_label.id).all(): for ingredient_food in session.query(IngredientFoodModel).filter_by(label_id=dupe_label_id).all():
ingredient_food.label_id = keep_label.id ingredient_food.label_id = keep_label_id
ingredient_food.label = keep_label ingredient_food.label = keep_label
session.commit() session.commit()
session.delete(dupe_label) session.query(MultiPurposeLabel).options(load_only(MultiPurposeLabel.id)).filter_by(id=dupe_label_id).delete()
session.commit() session.commit()
def _resolve_duplivate_foods_units_labels(): def _resolve_duplicate_foods_units_labels():
bind = op.get_bind() bind = op.get_bind()
session = Session(bind=bind) session = Session(bind=bind)
@ -119,8 +140,7 @@ def _resolve_duplivate_foods_units_labels():
keep_id = ids[0] keep_id = ids[0]
keep_obj = session.query(model).options(load_only(model.id)).filter_by(id=keep_id).first() keep_obj = session.query(model).options(load_only(model.id)).filter_by(id=keep_id).first()
for dupe_id in ids[1:]: for dupe_id in ids[1:]:
dupe_obj = session.query(model).options(load_only(model.id)).filter_by(id=dupe_id).first() resolve_func(session, keep_obj, keep_id, dupe_id)
resolve_func(session, keep_obj, dupe_obj)
def _remove_duplicates_from_m2m_table(session: Session, table_meta: TableMeta): def _remove_duplicates_from_m2m_table(session: Session, table_meta: TableMeta):
@ -155,7 +175,7 @@ def _remove_duplicates_from_m2m_tables(table_metas: list[TableMeta]):
def upgrade(): def upgrade():
_resolve_duplivate_foods_units_labels() _resolve_duplicate_foods_units_labels()
_remove_duplicates_from_m2m_tables( _remove_duplicates_from_m2m_tables(
[ [
TableMeta("cookbooks_to_categories", "cookbook_id", "category_id"), TableMeta("cookbooks_to_categories", "cookbook_id", "category_id"),