refactor/recipe-to-snake-case (#364)

* formatting

* snake case all recipes entries

* set foreign key to int

* run scheduler at startup and not import

* set SQLite file path before imports

Co-authored-by: hay-kot <hay-kot@pm.me>
This commit is contained in:
Hayden 2021-04-28 21:17:49 -08:00 committed by GitHub
parent ee445e7f54
commit 61e0a52100
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
19 changed files with 107 additions and 104 deletions

View file

@ -33,8 +33,7 @@
<v-col cols="12" sm="12" md="4" lg="4">
<Ingredients :value="ingredients" :edit="false" />
<div v-if="medium">
<v-card class="mt-2" v-if="categories.length > 0"
>
<v-card class="mt-2" v-if="categories.length > 0">
<v-card-title class="py-2">
{{ $t("recipe.categories") }}
</v-card-title>

View file

@ -2,13 +2,14 @@ import uvicorn
from fastapi import FastAPI
from mealie.core import root_logger
# import utils.startup as startup
from mealie.core.config import APP_VERSION, settings
from mealie.routes import backup_routes, debug_routes, migration_routes, theme_routes, utility_routes
from mealie.routes import (backup_routes, debug_routes, migration_routes,
theme_routes, utility_routes)
from mealie.routes.groups import groups
from mealie.routes.mealplans import mealplans
from mealie.routes.recipe import all_recipe_routes, category_routes, recipe_assets, recipe_crud_routes, tag_routes
from mealie.routes.recipe import (all_recipe_routes, category_routes,
recipe_assets, recipe_crud_routes,
tag_routes)
from mealie.routes.site_settings import all_settings
from mealie.routes.users import users
@ -51,11 +52,11 @@ def api_routers():
api_routers()
start_scheduler()
@app.on_event("startup")
def system_startup():
start_scheduler()
logger.info("-----SYSTEM STARTUP----- \n")
logger.info("------APP SETTINGS------")
logger.info(settings.json(indent=4, exclude={"SECRET", "DEFAULT_PASSWORD", "SFTP_PASSWORD", "SFTP_USERNAME"}))

View file

@ -9,7 +9,7 @@ from mealie.db.models.model_base import BaseMixins, SqlAlchemyBase
class Meal(SqlAlchemyBase):
__tablename__ = "meal"
id = sa.Column(sa.Integer, primary_key=True)
parent_id = sa.Column(sa.String, sa.ForeignKey("mealplan.uid"))
parent_id = sa.Column(sa.Integer, sa.ForeignKey("mealplan.uid"))
slug = sa.Column(sa.String)
name = sa.Column(sa.String)
date = sa.Column(sa.Date)

View file

@ -5,7 +5,7 @@ from mealie.db.models.model_base import SqlAlchemyBase
class ApiExtras(SqlAlchemyBase):
__tablename__ = "api_extras"
id = sa.Column(sa.Integer, primary_key=True)
parent_id = sa.Column(sa.String, sa.ForeignKey("recipes.id"))
parent_id = sa.Column(sa.Integer, sa.ForeignKey("recipes.id"))
key_name = sa.Column(sa.String, unique=True)
value = sa.Column(sa.String)

View file

@ -5,7 +5,7 @@ from mealie.db.models.model_base import SqlAlchemyBase
class RecipeAsset(SqlAlchemyBase):
__tablename__ = "recipe_assets"
id = sa.Column(sa.Integer, primary_key=True)
parent_id = sa.Column(sa.String, sa.ForeignKey("recipes.id"))
parent_id = sa.Column(sa.Integer, sa.ForeignKey("recipes.id"))
name = sa.Column(sa.String)
icon = sa.Column(sa.String)
file_name = sa.Column(sa.String)

View file

@ -41,7 +41,7 @@ class Category(SqlAlchemyBase):
id = sa.Column(sa.Integer, primary_key=True)
name = sa.Column(sa.String, index=True, nullable=False)
slug = sa.Column(sa.String, index=True, unique=True, nullable=False)
recipes = orm.relationship("RecipeModel", secondary=recipes2categories, back_populates="recipeCategory")
recipes = orm.relationship("RecipeModel", secondary=recipes2categories, back_populates="recipe_category")
@validates("name")
def validate_name(self, key, name):

View file

@ -6,7 +6,7 @@ class RecipeIngredient(SqlAlchemyBase):
__tablename__ = "recipes_ingredients"
id = sa.Column(sa.Integer, primary_key=True)
position = sa.Column(sa.Integer)
parent_id = sa.Column(sa.String, sa.ForeignKey("recipes.id"))
parent_id = sa.Column(sa.Integer, sa.ForeignKey("recipes.id"))
ingredient = sa.Column(sa.String)
def update(self, ingredient):

View file

@ -5,7 +5,7 @@ from mealie.db.models.model_base import SqlAlchemyBase
class RecipeInstruction(SqlAlchemyBase):
__tablename__ = "recipe_instructions"
id = sa.Column(sa.Integer, primary_key=True)
parent_id = sa.Column(sa.String, sa.ForeignKey("recipes.id"))
parent_id = sa.Column(sa.Integer, sa.ForeignKey("recipes.id"))
position = sa.Column(sa.Integer)
type = sa.Column(sa.String, default="")
text = sa.Column(sa.String)

View file

@ -5,7 +5,7 @@ from mealie.db.models.model_base import SqlAlchemyBase
class Note(SqlAlchemyBase):
__tablename__ = "notes"
id = sa.Column(sa.Integer, primary_key=True)
parent_id = sa.Column(sa.String, sa.ForeignKey("recipes.id"))
parent_id = sa.Column(sa.Integer, sa.ForeignKey("recipes.id"))
title = sa.Column(sa.String)
text = sa.Column(sa.String)

View file

@ -5,29 +5,29 @@ from mealie.db.models.model_base import SqlAlchemyBase
class Nutrition(SqlAlchemyBase):
__tablename__ = "recipe_nutrition"
id = sa.Column(sa.Integer, primary_key=True)
parent_id = sa.Column(sa.String, sa.ForeignKey("recipes.id"))
parent_id = sa.Column(sa.Integer, sa.ForeignKey("recipes.id"))
calories = sa.Column(sa.String)
fatContent = sa.Column(sa.String)
fiberContent = sa.Column(sa.String)
proteinContent = sa.Column(sa.String)
carbohydrateContent = sa.Column(sa.String)
sodiumContent = sa.Column(sa.String)
sugarContent = sa.Column(sa.String)
fat_content = sa.Column(sa.String)
fiber_content = sa.Column(sa.String)
protein_content = sa.Column(sa.String)
carbohydrate_content = sa.Column(sa.String)
sodium_content = sa.Column(sa.String)
sugar_content = sa.Column(sa.String)
def __init__(
self,
calories=None,
fatContent=None,
fiberContent=None,
proteinContent=None,
sodiumContent=None,
sugarContent=None,
carbohydrateContent=None,
fat_content=None,
fiber_content=None,
protein_content=None,
sodium_content=None,
sugar_content=None,
carbohydrate_content=None,
) -> None:
self.calories = calories
self.fatContent = fatContent
self.fiberContent = fiberContent
self.proteinContent = proteinContent
self.sodiumContent = sodiumContent
self.sugarContent = sugarContent
self.carbohydrateContent = carbohydrateContent
self.fat_content = fat_content
self.fiber_content = fiber_content
self.protein_content = protein_content
self.sodium_content = sodium_content
self.sugar_content = sugar_content
self.carbohydrate_content = carbohydrate_content

View file

@ -27,24 +27,24 @@ class RecipeModel(SqlAlchemyBase, BaseMixins):
name = sa.Column(sa.String, nullable=False)
description = sa.Column(sa.String)
image = sa.Column(sa.String)
totalTime = sa.Column(sa.String)
prepTime = sa.Column(sa.String)
performTime = sa.Column(sa.String)
total_time = sa.Column(sa.String)
prep_time = sa.Column(sa.String)
perform_time = sa.Column(sa.String)
cookTime = sa.Column(sa.String)
recipeYield = sa.Column(sa.String)
recipe_yield = sa.Column(sa.String)
recipeCuisine = sa.Column(sa.String)
tools: list[Tool] = orm.relationship("Tool", cascade="all, delete-orphan")
assets: list[RecipeAsset] = orm.relationship("RecipeAsset", cascade="all, delete-orphan")
nutrition: Nutrition = orm.relationship("Nutrition", uselist=False, cascade="all, delete-orphan")
recipeCategory: list = orm.relationship("Category", secondary=recipes2categories, back_populates="recipes")
recipe_category: list = orm.relationship("Category", secondary=recipes2categories, back_populates="recipes")
recipeIngredient: list[RecipeIngredient] = orm.relationship(
recipe_ingredient: list[RecipeIngredient] = orm.relationship(
"RecipeIngredient",
cascade="all, delete-orphan",
order_by="RecipeIngredient.position",
collection_class=ordering_list("position"),
)
recipeInstructions: list[RecipeInstruction] = orm.relationship(
recipe_instructions: list[RecipeInstruction] = orm.relationship(
"RecipeInstruction",
cascade="all, delete-orphan",
order_by="RecipeInstruction.position",
@ -55,10 +55,10 @@ class RecipeModel(SqlAlchemyBase, BaseMixins):
slug = sa.Column(sa.String, index=True, unique=True)
settings = orm.relationship("RecipeSettings", uselist=False, cascade="all, delete-orphan")
tags: list[Tag] = orm.relationship("Tag", secondary=recipes2tags, back_populates="recipes")
dateAdded = sa.Column(sa.Date, default=date.today)
date_added = sa.Column(sa.Date, default=date.today)
notes: list[Note] = orm.relationship("Note", cascade="all, delete-orphan")
rating = sa.Column(sa.Integer)
orgURL = sa.Column(sa.String)
org_url = sa.Column(sa.String)
extras: list[ApiExtras] = orm.relationship("ApiExtras", cascade="all, delete-orphan")
@validates("name")
@ -72,22 +72,22 @@ class RecipeModel(SqlAlchemyBase, BaseMixins):
name: str = None,
description: str = None,
image: str = None,
recipeYield: str = None,
recipeIngredient: list[str] = None,
recipeInstructions: list[dict] = None,
recipe_yield: str = None,
recipe_ingredient: list[str] = None,
recipe_instructions: list[dict] = None,
recipeCuisine: str = None,
totalTime: str = None,
prepTime: str = None,
total_time: str = None,
prep_time: str = None,
nutrition: dict = None,
tools: list[str] = None,
performTime: str = None,
perform_time: str = None,
slug: str = None,
recipeCategory: list[str] = None,
recipe_category: list[str] = None,
tags: list[str] = None,
dateAdded: datetime.date = None,
date_added: datetime.date = None,
notes: list[dict] = None,
rating: int = None,
orgURL: str = None,
org_url: str = None,
extras: dict = None,
assets: list = None,
settings: dict = None,
@ -103,28 +103,28 @@ class RecipeModel(SqlAlchemyBase, BaseMixins):
self.tools = [Tool(tool=x) for x in tools] if tools else []
self.recipeYield = recipeYield
self.recipeIngredient = [RecipeIngredient(ingredient=ingr) for ingr in recipeIngredient]
self.recipe_yield = recipe_yield
self.recipe_ingredient = [RecipeIngredient(ingredient=ingr) for ingr in recipe_ingredient]
self.assets = [RecipeAsset(**a) for a in assets]
self.recipeInstructions = [
self.recipe_instructions = [
RecipeInstruction(text=instruc.get("text"), title=instruc.get("title"), type=instruc.get("@type", None))
for instruc in recipeInstructions
for instruc in recipe_instructions
]
self.totalTime = totalTime
self.prepTime = prepTime
self.performTime = performTime
self.total_time = total_time
self.prep_time = prep_time
self.perform_time = perform_time
self.recipeCategory = [Category.create_if_not_exist(session=session, name=cat) for cat in recipeCategory]
self.recipe_category = [Category.create_if_not_exist(session=session, name=cat) for cat in recipe_category]
# Mealie Specific
self.settings = RecipeSettings(**settings) if settings else RecipeSettings()
print(self.settings)
self.tags = [Tag.create_if_not_exist(session=session, name=tag) for tag in tags]
self.slug = slug
self.dateAdded = dateAdded
self.date_added = date_added
self.notes = [Note(**note) for note in notes]
self.rating = rating
self.orgURL = orgURL
self.org_url = org_url
self.extras = [ApiExtras(key=key, value=value) for key, value in extras.items()]
def update(self, *args, **kwargs):

View file

@ -5,7 +5,7 @@ from mealie.db.models.model_base import SqlAlchemyBase
class Tool(SqlAlchemyBase):
__tablename__ = "tools"
id = sa.Column(sa.Integer, primary_key=True)
parent_id = sa.Column(sa.String, sa.ForeignKey("recipes.id"))
parent_id = sa.Column(sa.Integer, sa.ForeignKey("recipes.id"))
tool = sa.Column(sa.String)
def __init__(self, tool) -> None:

View file

@ -21,4 +21,4 @@ def get_shopping_list(
mealplan: MealPlanInDB
slugs = [x.slug for x in mealplan.meals]
recipes: list[Recipe] = [db.recipes.get(session, x) for x in slugs]
return [{"name": x.name, "recipeIngredient": x.recipeIngredient} for x in recipes if x]
return [{"name": x.name, "recipe_ingredient": x.recipe_ingredient} for x in recipes if x]

View file

@ -50,11 +50,11 @@ def get_all_recipes(
- description
- image
- recipeYield
- totalTime
- prepTime
- performTime
- total_time
- prep_time
- perform_time
- rating
- orgURL
- org_url
**Note:** You may experience problems with with query parameters. As an alternative
you may also use the post method and provide a body.
@ -78,11 +78,11 @@ def get_all_recipes_post(body: AllRecipeRequest, session: Session = Depends(gene
- description
- image
- recipeYield
- totalTime
- prepTime
- performTime
- total_time
- prep_time
- perform_time
- rating
- orgURL
- org_url
Refer to the body example for data formats.

View file

@ -43,27 +43,27 @@ class RecipeAsset(CamelModel):
orm_mode = True
class Nutrition(BaseModel):
class Nutrition(CamelModel):
calories: Optional[str]
fatContent: Optional[str]
proteinContent: Optional[str]
carbohydrateContent: Optional[str]
fiberContent: Optional[str]
sodiumContent: Optional[str]
sugarContent: Optional[str]
fat_content: Optional[str]
protein_content: Optional[str]
carbohydrate_content: Optional[str]
fiber_content: Optional[str]
sodium_content: Optional[str]
sugar_content: Optional[str]
class Config:
orm_mode = True
class RecipeSummary(BaseModel):
class RecipeSummary(CamelModel):
id: Optional[int]
name: str
slug: Optional[str] = ""
image: Optional[Any]
description: Optional[str]
recipeCategory: Optional[list[str]] = []
recipe_category: Optional[list[str]] = []
tags: Optional[list[str]] = []
rating: Optional[int]
@ -74,28 +74,28 @@ class RecipeSummary(BaseModel):
def getter_dict(_cls, name_orm: RecipeModel):
return {
**GetterDict(name_orm),
"recipeCategory": [x.name for x in name_orm.recipeCategory],
"recipe_category": [x.name for x in name_orm.recipe_category],
"tags": [x.name for x in name_orm.tags],
}
class Recipe(RecipeSummary):
recipeYield: Optional[str]
recipeIngredient: Optional[list[str]]
recipeInstructions: Optional[list[RecipeStep]]
recipe_yield: Optional[str]
recipe_ingredient: Optional[list[str]]
recipe_instructions: Optional[list[RecipeStep]]
nutrition: Optional[Nutrition]
tools: Optional[list[str]] = []
totalTime: Optional[str] = None
prepTime: Optional[str] = None
performTime: Optional[str] = None
total_time: Optional[str] = None
prep_time: Optional[str] = None
perform_time: Optional[str] = None
# Mealie Specific
settings: Optional[RecipeSettings]
assets: Optional[list[RecipeAsset]] = []
dateAdded: Optional[datetime.date]
date_added: Optional[datetime.date]
notes: Optional[list[RecipeNote]] = []
orgURL: Optional[str]
org_url: Optional[str] = Field(None, alias="orgURL")
extras: Optional[dict] = {}
class Config:
@ -105,8 +105,8 @@ class Recipe(RecipeSummary):
def getter_dict(_cls, name_orm: RecipeModel):
return {
**GetterDict(name_orm),
"recipeIngredient": [x.ingredient for x in name_orm.recipeIngredient],
"recipeCategory": [x.name for x in name_orm.recipeCategory],
"recipe_ingredient": [x.ingredient for x in name_orm.recipe_ingredient],
"recipe_category": [x.name for x in name_orm.recipe_category],
"tags": [x.name for x in name_orm.tags],
"tools": [x.tool for x in name_orm.tools],
"extras": {x.key_name: x.value for x in name_orm.extras},
@ -117,22 +117,22 @@ class Recipe(RecipeSummary):
"name": "Chicken and Rice With Leeks and Salsa Verde",
"description": "This one-skillet dinner gets deep oniony flavor from lots of leeks cooked down to jammy tenderness.",
"image": "chicken-and-rice-with-leeks-and-salsa-verde.jpg",
"recipeYield": "4 Servings",
"recipeIngredient": [
"recipe_yield": "4 Servings",
"recipe_ingredient": [
"1 1/2 lb. skinless, boneless chicken thighs (4-8 depending on size)",
"Kosher salt, freshly ground pepper",
"3 Tbsp. unsalted butter, divided",
],
"recipeInstructions": [
"recipe_instructions": [
{
"text": "Season chicken with salt and pepper.",
},
],
"slug": "chicken-and-rice-with-leeks-and-salsa-verde",
"tags": ["favorite", "yummy!"],
"recipeCategory": ["Dinner", "Pasta"],
"recipe_category": ["Dinner", "Pasta"],
"notes": [{"title": "Watch Out!", "text": "Prep the day before!"}],
"orgURL": "https://www.bonappetit.com/recipe/chicken-and-rice-with-leeks-and-salsa-verde",
"org_url": "https://www.bonappetit.com/recipe/chicken-and-rice-with-leeks-and-salsa-verde",
"rating": 3,
"extras": {"message": "Don't forget to defrost the chicken!"},
}

View file

@ -83,7 +83,7 @@ class ImportDatabase:
del recipe_dict["categories"]
try:
del recipe_dict["_id"]
del recipe_dict["dateAdded"]
del recipe_dict["date_added"]
except:
pass
# Migration from list to Object Type Data

View file

@ -144,7 +144,7 @@ class MigrationBase(BaseModel):
"""Calls the rewrite_alias function and the Cleaner.clean function on a
dictionary and returns the result unpacked into a Recipe object"""
recipe_dict = self.rewrite_alias(recipe_dict)
recipe_dict = Cleaner.clean(recipe_dict, url=recipe_dict.get("orgURL", None))
recipe_dict = Cleaner.clean(recipe_dict, url=recipe_dict.get("org_url", None))
return Recipe(**recipe_dict)

View file

@ -37,7 +37,7 @@ class NextcloudDir:
class NextcloudMigration(MigrationBase):
key_aliases: Optional[list[MigrationAlias]] = [
MigrationAlias(key="tags", alias="keywords", func=helpers.split_by_comma),
MigrationAlias(key="orgURL", alias="url", func=None),
MigrationAlias(key="org_url", alias="url", func=None),
]

View file

@ -1,9 +1,16 @@
from mealie.core.config import app_dirs, settings
#! I don't like it either!
SQLITE_FILE = app_dirs.SQLITE_DIR.joinpath("test.db")
SQLITE_FILE.unlink(missing_ok=True)
settings.SQLITE_FILE = SQLITE_FILE
import json
import requests
from fastapi.testclient import TestClient
from mealie.app import app
from mealie.core.config import app_dirs, settings
from mealie.db.db_setup import generate_session, sql_global_init
from mealie.db.init_db import init_db
from pytest import fixture
@ -12,10 +19,6 @@ from tests.app_routes import AppRoutes
from tests.test_config import TEST_DATA
from tests.utils.recipe_data import build_recipe_store, get_raw_no_image, get_raw_recipe
SQLITE_FILE = app_dirs.SQLITE_DIR.joinpath("test.db")
SQLITE_FILE.unlink(missing_ok=True)
TestSessionLocal = sql_global_init(SQLITE_FILE, check_thread=False)
init_db(TestSessionLocal())