Set up alembic migration usage (#954)
* Set up alembic migration usage * Fix import order, add isort as alembic hook * Only run migrations if needed * Include date as part of migration file name for better sorting * Skip initial migrations if tables already exist This eases the transition from a pre-alembic state * Fix deprecation warning in alembic revision * Add alembic test stubs
This commit is contained in:
parent
a897e180ed
commit
fdfb5b1a5e
14 changed files with 1197 additions and 25 deletions
72
alembic.ini
Normal file
72
alembic.ini
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
# A generic, single database configuration.
|
||||||
|
|
||||||
|
[alembic]
|
||||||
|
# path to migration scripts
|
||||||
|
script_location = alembic
|
||||||
|
|
||||||
|
# template used to generate migration files
|
||||||
|
file_template = %%(year)d-%%(month).2d-%%(day).2d-%%(hour).2d:%%(minute).2d:%%(second).2d_%%(rev)s_%%(slug)s
|
||||||
|
|
||||||
|
# sys.path path, will be prepended to sys.path if present.
|
||||||
|
# defaults to the current working directory.
|
||||||
|
prepend_sys_path = .
|
||||||
|
|
||||||
|
# timezone to use when rendering the date within the migration file
|
||||||
|
# as well as the filename.
|
||||||
|
# If specified, requires the python-dateutil library that can be
|
||||||
|
# installed by adding `alembic[tz]` to the pip requirements
|
||||||
|
# string value is passed to dateutil.tz.gettz()
|
||||||
|
# leave blank for localtime
|
||||||
|
# timezone =
|
||||||
|
|
||||||
|
# max length of characters to apply to the
|
||||||
|
# "slug" field
|
||||||
|
# truncate_slug_length = 40
|
||||||
|
|
||||||
|
# set to 'true' to run the environment during
|
||||||
|
# the 'revision' command, regardless of autogenerate
|
||||||
|
# revision_environment = false
|
||||||
|
|
||||||
|
# set to 'true' to allow .pyc and .pyo files without
|
||||||
|
# a source .py file to be detected as revisions in the
|
||||||
|
# versions/ directory
|
||||||
|
# sourceless = false
|
||||||
|
|
||||||
|
# version location specification; This defaults
|
||||||
|
# to alembic/versions. When using multiple version
|
||||||
|
# directories, initial revisions must be specified with --version-path.
|
||||||
|
# The path separator used here should be the separator specified by "version_path_separator"
|
||||||
|
# version_locations = %(here)s/bar:%(here)s/bat:alembic/versions
|
||||||
|
|
||||||
|
# version path separator; As mentioned above, this is the character used to split
|
||||||
|
# version_locations. Valid values are:
|
||||||
|
#
|
||||||
|
# version_path_separator = :
|
||||||
|
# version_path_separator = ;
|
||||||
|
# version_path_separator = space
|
||||||
|
version_path_separator = os # default: use os.pathsep
|
||||||
|
|
||||||
|
# the output encoding used when revision files
|
||||||
|
# are written from script.py.mako
|
||||||
|
# output_encoding = utf-8
|
||||||
|
|
||||||
|
# Will be replaced in alembic/env.py with the actual url
|
||||||
|
sqlalchemy.url =
|
||||||
|
|
||||||
|
|
||||||
|
[post_write_hooks]
|
||||||
|
# post_write_hooks defines scripts or Python functions that are run
|
||||||
|
# on newly generated revision scripts. See the documentation for further
|
||||||
|
# detail and examples
|
||||||
|
|
||||||
|
hooks = isort, black
|
||||||
|
|
||||||
|
# format using "isort" - use the console_scripts runner, against the "isort" entrypoint
|
||||||
|
isort.type = console_scripts
|
||||||
|
isort.entrypoint = isort
|
||||||
|
isort.options = REVISION_SCRIPT_FILENAME
|
||||||
|
|
||||||
|
# format using "black" - use the console_scripts runner, against the "black" entrypoint
|
||||||
|
black.type = console_scripts
|
||||||
|
black.entrypoint = black
|
||||||
|
black.options = REVISION_SCRIPT_FILENAME
|
1
alembic/README
Normal file
1
alembic/README
Normal file
|
@ -0,0 +1 @@
|
||||||
|
Generic single-database configuration.
|
77
alembic/env.py
Normal file
77
alembic/env.py
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
from sqlalchemy import engine_from_config, pool
|
||||||
|
|
||||||
|
import mealie.db.models._all_models # noqa: F401
|
||||||
|
from alembic import context
|
||||||
|
from mealie.core.config import get_app_settings
|
||||||
|
from mealie.db.models._model_base import SqlAlchemyBase
|
||||||
|
|
||||||
|
# this is the Alembic Config object, which provides
|
||||||
|
# access to the values within the .ini file in use.
|
||||||
|
config = context.config
|
||||||
|
|
||||||
|
# add your model's MetaData object here
|
||||||
|
# for 'autogenerate' support
|
||||||
|
# from myapp import mymodel
|
||||||
|
# target_metadata = mymodel.Base.metadata
|
||||||
|
target_metadata = SqlAlchemyBase.metadata
|
||||||
|
|
||||||
|
# other values from the config, defined by the needs of env.py,
|
||||||
|
# can be acquired:
|
||||||
|
# my_important_option = config.get_main_option("my_important_option")
|
||||||
|
# ... etc.
|
||||||
|
|
||||||
|
# Set DB url from config
|
||||||
|
settings = get_app_settings()
|
||||||
|
config.set_main_option("sqlalchemy.url", settings.DB_URL)
|
||||||
|
|
||||||
|
|
||||||
|
def run_migrations_offline():
|
||||||
|
"""Run migrations in 'offline' mode.
|
||||||
|
|
||||||
|
This configures the context with just a URL
|
||||||
|
and not an Engine, though an Engine is acceptable
|
||||||
|
here as well. By skipping the Engine creation
|
||||||
|
we don't even need a DBAPI to be available.
|
||||||
|
|
||||||
|
Calls to context.execute() here emit the given string to the
|
||||||
|
script output.
|
||||||
|
|
||||||
|
"""
|
||||||
|
url = config.get_main_option("sqlalchemy.url")
|
||||||
|
context.configure(
|
||||||
|
url=url,
|
||||||
|
target_metadata=target_metadata,
|
||||||
|
literal_binds=True,
|
||||||
|
dialect_opts={"paramstyle": "named"},
|
||||||
|
)
|
||||||
|
|
||||||
|
with context.begin_transaction():
|
||||||
|
context.run_migrations()
|
||||||
|
|
||||||
|
|
||||||
|
def run_migrations_online():
|
||||||
|
"""Run migrations in 'online' mode.
|
||||||
|
|
||||||
|
In this scenario we need to create an Engine
|
||||||
|
and associate a connection with the context.
|
||||||
|
|
||||||
|
"""
|
||||||
|
connectable = engine_from_config(
|
||||||
|
config.get_section(config.config_ini_section),
|
||||||
|
prefix="sqlalchemy.",
|
||||||
|
poolclass=pool.NullPool,
|
||||||
|
)
|
||||||
|
|
||||||
|
with connectable.connect() as connection:
|
||||||
|
context.configure(
|
||||||
|
connection=connection, target_metadata=target_metadata, user_module_prefix="mealie.db.migration_types."
|
||||||
|
)
|
||||||
|
|
||||||
|
with context.begin_transaction():
|
||||||
|
context.run_migrations()
|
||||||
|
|
||||||
|
|
||||||
|
if context.is_offline_mode():
|
||||||
|
run_migrations_offline()
|
||||||
|
else:
|
||||||
|
run_migrations_online()
|
26
alembic/script.py.mako
Normal file
26
alembic/script.py.mako
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
"""${message}
|
||||||
|
|
||||||
|
Revision ID: ${up_revision}
|
||||||
|
Revises: ${down_revision | comma,n}
|
||||||
|
Create Date: ${create_date}
|
||||||
|
|
||||||
|
"""
|
||||||
|
import sqlalchemy as sa
|
||||||
|
|
||||||
|
import mealie.db.migration_types
|
||||||
|
from alembic import op
|
||||||
|
${imports if imports else ""}
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = ${repr(up_revision)}
|
||||||
|
down_revision = ${repr(down_revision)}
|
||||||
|
branch_labels = ${repr(branch_labels)}
|
||||||
|
depends_on = ${repr(depends_on)}
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade():
|
||||||
|
${upgrades if upgrades else "pass"}
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade():
|
||||||
|
${downgrades if downgrades else "pass"}
|
|
@ -0,0 +1,920 @@
|
||||||
|
"""Initial tables
|
||||||
|
|
||||||
|
Revision ID: 6b0f5f32d602
|
||||||
|
Revises:
|
||||||
|
Create Date: 2022-02-21 19:56:24.351115
|
||||||
|
|
||||||
|
"""
|
||||||
|
import sqlalchemy as sa
|
||||||
|
from sqlalchemy import engine_from_config
|
||||||
|
|
||||||
|
import mealie.db.migration_types
|
||||||
|
from alembic import op
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = "6b0f5f32d602"
|
||||||
|
down_revision = None
|
||||||
|
branch_labels = None
|
||||||
|
depends_on = None
|
||||||
|
|
||||||
|
|
||||||
|
# Adapted from https://improveandrepeat.com/2021/09/python-friday-87-handling-pre-existing-tables-with-alembic-and-sqlalchemy/
|
||||||
|
def table_exists(table, schema=None):
|
||||||
|
config = op.get_context().config
|
||||||
|
engine = engine_from_config(config.get_section(config.config_ini_section), prefix="sqlalchemy.")
|
||||||
|
insp = sa.inspect(engine)
|
||||||
|
return insp.has_table(table, schema)
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade():
|
||||||
|
# Only create initial tables if they don't exist yet, to ease transition from pre-alembic state
|
||||||
|
if table_exists("users"):
|
||||||
|
return
|
||||||
|
|
||||||
|
op.create_table(
|
||||||
|
"groups",
|
||||||
|
sa.Column("created_at", sa.DateTime(), nullable=True),
|
||||||
|
sa.Column("update_at", sa.DateTime(), nullable=True),
|
||||||
|
sa.Column("id", mealie.db.migration_types.GUID(), nullable=False),
|
||||||
|
sa.Column("name", sa.String(), nullable=False),
|
||||||
|
sa.PrimaryKeyConstraint("id"),
|
||||||
|
)
|
||||||
|
op.create_index(op.f("ix_groups_name"), "groups", ["name"], unique=True)
|
||||||
|
op.create_table(
|
||||||
|
"categories",
|
||||||
|
sa.Column("created_at", sa.DateTime(), nullable=True),
|
||||||
|
sa.Column("update_at", sa.DateTime(), nullable=True),
|
||||||
|
sa.Column("group_id", mealie.db.migration_types.GUID(), nullable=False),
|
||||||
|
sa.Column("id", mealie.db.migration_types.GUID(), nullable=False),
|
||||||
|
sa.Column("name", sa.String(), nullable=False),
|
||||||
|
sa.Column("slug", sa.String(), nullable=False),
|
||||||
|
sa.ForeignKeyConstraint(
|
||||||
|
["group_id"],
|
||||||
|
["groups.id"],
|
||||||
|
),
|
||||||
|
sa.PrimaryKeyConstraint("id"),
|
||||||
|
sa.UniqueConstraint("slug", "group_id", name="category_slug_group_id_key"),
|
||||||
|
)
|
||||||
|
op.create_index(op.f("ix_categories_group_id"), "categories", ["group_id"], unique=False)
|
||||||
|
op.create_index(op.f("ix_categories_name"), "categories", ["name"], unique=False)
|
||||||
|
op.create_index(op.f("ix_categories_slug"), "categories", ["slug"], unique=False)
|
||||||
|
op.create_table(
|
||||||
|
"cookbooks",
|
||||||
|
sa.Column("created_at", sa.DateTime(), nullable=True),
|
||||||
|
sa.Column("update_at", sa.DateTime(), nullable=True),
|
||||||
|
sa.Column("id", mealie.db.migration_types.GUID(), nullable=False),
|
||||||
|
sa.Column("position", sa.Integer(), nullable=False),
|
||||||
|
sa.Column("name", sa.String(), nullable=False),
|
||||||
|
sa.Column("slug", sa.String(), nullable=False),
|
||||||
|
sa.Column("description", sa.String(), nullable=True),
|
||||||
|
sa.Column("group_id", mealie.db.migration_types.GUID(), nullable=True),
|
||||||
|
sa.ForeignKeyConstraint(
|
||||||
|
["group_id"],
|
||||||
|
["groups.id"],
|
||||||
|
),
|
||||||
|
sa.PrimaryKeyConstraint("id"),
|
||||||
|
)
|
||||||
|
op.create_table(
|
||||||
|
"group_data_exports",
|
||||||
|
sa.Column("created_at", sa.DateTime(), nullable=True),
|
||||||
|
sa.Column("update_at", sa.DateTime(), nullable=True),
|
||||||
|
sa.Column("id", mealie.db.migration_types.GUID(), nullable=False),
|
||||||
|
sa.Column("group_id", mealie.db.migration_types.GUID(), nullable=True),
|
||||||
|
sa.Column("name", sa.String(), nullable=False),
|
||||||
|
sa.Column("filename", sa.String(), nullable=False),
|
||||||
|
sa.Column("path", sa.String(), nullable=False),
|
||||||
|
sa.Column("size", sa.String(), nullable=False),
|
||||||
|
sa.Column("expires", sa.String(), nullable=False),
|
||||||
|
sa.ForeignKeyConstraint(
|
||||||
|
["group_id"],
|
||||||
|
["groups.id"],
|
||||||
|
),
|
||||||
|
sa.PrimaryKeyConstraint("id"),
|
||||||
|
)
|
||||||
|
op.create_index(op.f("ix_group_data_exports_group_id"), "group_data_exports", ["group_id"], unique=False)
|
||||||
|
op.create_table(
|
||||||
|
"group_events_notifiers",
|
||||||
|
sa.Column("created_at", sa.DateTime(), nullable=True),
|
||||||
|
sa.Column("update_at", sa.DateTime(), nullable=True),
|
||||||
|
sa.Column("id", mealie.db.migration_types.GUID(), nullable=False),
|
||||||
|
sa.Column("name", sa.String(), nullable=False),
|
||||||
|
sa.Column("enabled", sa.Boolean(), nullable=False),
|
||||||
|
sa.Column("apprise_url", sa.String(), nullable=False),
|
||||||
|
sa.Column("group_id", mealie.db.migration_types.GUID(), nullable=True),
|
||||||
|
sa.ForeignKeyConstraint(
|
||||||
|
["group_id"],
|
||||||
|
["groups.id"],
|
||||||
|
),
|
||||||
|
sa.PrimaryKeyConstraint("id"),
|
||||||
|
)
|
||||||
|
op.create_index(op.f("ix_group_events_notifiers_group_id"), "group_events_notifiers", ["group_id"], unique=False)
|
||||||
|
op.create_table(
|
||||||
|
"group_meal_plan_rules",
|
||||||
|
sa.Column("created_at", sa.DateTime(), nullable=True),
|
||||||
|
sa.Column("update_at", sa.DateTime(), nullable=True),
|
||||||
|
sa.Column("id", mealie.db.migration_types.GUID(), nullable=False),
|
||||||
|
sa.Column("group_id", mealie.db.migration_types.GUID(), nullable=False),
|
||||||
|
sa.Column("day", sa.String(), nullable=False),
|
||||||
|
sa.Column("entry_type", sa.String(), nullable=False),
|
||||||
|
sa.ForeignKeyConstraint(
|
||||||
|
["group_id"],
|
||||||
|
["groups.id"],
|
||||||
|
),
|
||||||
|
sa.PrimaryKeyConstraint("id"),
|
||||||
|
)
|
||||||
|
op.create_table(
|
||||||
|
"group_preferences",
|
||||||
|
sa.Column("created_at", sa.DateTime(), nullable=True),
|
||||||
|
sa.Column("update_at", sa.DateTime(), nullable=True),
|
||||||
|
sa.Column("id", mealie.db.migration_types.GUID(), nullable=False),
|
||||||
|
sa.Column("group_id", mealie.db.migration_types.GUID(), nullable=False),
|
||||||
|
sa.Column("private_group", sa.Boolean(), nullable=True),
|
||||||
|
sa.Column("first_day_of_week", sa.Integer(), nullable=True),
|
||||||
|
sa.Column("recipe_public", sa.Boolean(), nullable=True),
|
||||||
|
sa.Column("recipe_show_nutrition", sa.Boolean(), nullable=True),
|
||||||
|
sa.Column("recipe_show_assets", sa.Boolean(), nullable=True),
|
||||||
|
sa.Column("recipe_landscape_view", sa.Boolean(), nullable=True),
|
||||||
|
sa.Column("recipe_disable_comments", sa.Boolean(), nullable=True),
|
||||||
|
sa.Column("recipe_disable_amount", sa.Boolean(), nullable=True),
|
||||||
|
sa.ForeignKeyConstraint(
|
||||||
|
["group_id"],
|
||||||
|
["groups.id"],
|
||||||
|
),
|
||||||
|
sa.PrimaryKeyConstraint("id"),
|
||||||
|
)
|
||||||
|
op.create_index(op.f("ix_group_preferences_group_id"), "group_preferences", ["group_id"], unique=False)
|
||||||
|
op.create_table(
|
||||||
|
"group_reports",
|
||||||
|
sa.Column("created_at", sa.DateTime(), nullable=True),
|
||||||
|
sa.Column("update_at", sa.DateTime(), nullable=True),
|
||||||
|
sa.Column("id", mealie.db.migration_types.GUID(), nullable=False),
|
||||||
|
sa.Column("name", sa.String(), nullable=False),
|
||||||
|
sa.Column("status", sa.String(), nullable=False),
|
||||||
|
sa.Column("category", sa.String(), nullable=False),
|
||||||
|
sa.Column("timestamp", sa.DateTime(), nullable=False),
|
||||||
|
sa.Column("group_id", mealie.db.migration_types.GUID(), nullable=False),
|
||||||
|
sa.ForeignKeyConstraint(
|
||||||
|
["group_id"],
|
||||||
|
["groups.id"],
|
||||||
|
),
|
||||||
|
sa.PrimaryKeyConstraint("id"),
|
||||||
|
)
|
||||||
|
op.create_index(op.f("ix_group_reports_category"), "group_reports", ["category"], unique=False)
|
||||||
|
op.create_index(op.f("ix_group_reports_group_id"), "group_reports", ["group_id"], unique=False)
|
||||||
|
op.create_table(
|
||||||
|
"ingredient_units",
|
||||||
|
sa.Column("created_at", sa.DateTime(), nullable=True),
|
||||||
|
sa.Column("update_at", sa.DateTime(), nullable=True),
|
||||||
|
sa.Column("id", mealie.db.migration_types.GUID(), nullable=False),
|
||||||
|
sa.Column("group_id", mealie.db.migration_types.GUID(), nullable=False),
|
||||||
|
sa.Column("name", sa.String(), nullable=True),
|
||||||
|
sa.Column("description", sa.String(), nullable=True),
|
||||||
|
sa.Column("abbreviation", sa.String(), nullable=True),
|
||||||
|
sa.Column("fraction", sa.Boolean(), nullable=True),
|
||||||
|
sa.ForeignKeyConstraint(
|
||||||
|
["group_id"],
|
||||||
|
["groups.id"],
|
||||||
|
),
|
||||||
|
sa.PrimaryKeyConstraint("id"),
|
||||||
|
)
|
||||||
|
op.create_table(
|
||||||
|
"invite_tokens",
|
||||||
|
sa.Column("id", sa.Integer(), nullable=False),
|
||||||
|
sa.Column("created_at", sa.DateTime(), nullable=True),
|
||||||
|
sa.Column("update_at", sa.DateTime(), nullable=True),
|
||||||
|
sa.Column("token", sa.String(), nullable=False),
|
||||||
|
sa.Column("uses_left", sa.Integer(), nullable=False),
|
||||||
|
sa.Column("group_id", mealie.db.migration_types.GUID(), nullable=True),
|
||||||
|
sa.ForeignKeyConstraint(
|
||||||
|
["group_id"],
|
||||||
|
["groups.id"],
|
||||||
|
),
|
||||||
|
sa.PrimaryKeyConstraint("id"),
|
||||||
|
)
|
||||||
|
op.create_index(op.f("ix_invite_tokens_token"), "invite_tokens", ["token"], unique=True)
|
||||||
|
op.create_table(
|
||||||
|
"multi_purpose_labels",
|
||||||
|
sa.Column("created_at", sa.DateTime(), nullable=True),
|
||||||
|
sa.Column("update_at", sa.DateTime(), nullable=True),
|
||||||
|
sa.Column("id", mealie.db.migration_types.GUID(), nullable=False),
|
||||||
|
sa.Column("name", sa.String(length=255), nullable=False),
|
||||||
|
sa.Column("color", sa.String(length=10), nullable=False),
|
||||||
|
sa.Column("group_id", mealie.db.migration_types.GUID(), nullable=False),
|
||||||
|
sa.ForeignKeyConstraint(
|
||||||
|
["group_id"],
|
||||||
|
["groups.id"],
|
||||||
|
),
|
||||||
|
sa.PrimaryKeyConstraint("id"),
|
||||||
|
)
|
||||||
|
op.create_index(op.f("ix_multi_purpose_labels_group_id"), "multi_purpose_labels", ["group_id"], unique=False)
|
||||||
|
op.create_table(
|
||||||
|
"recipes",
|
||||||
|
sa.Column("created_at", sa.DateTime(), nullable=True),
|
||||||
|
sa.Column("update_at", sa.DateTime(), nullable=True),
|
||||||
|
sa.Column("id", mealie.db.migration_types.GUID(), nullable=False),
|
||||||
|
sa.Column("slug", sa.String(), nullable=True),
|
||||||
|
sa.Column("group_id", mealie.db.migration_types.GUID(), nullable=False),
|
||||||
|
sa.Column("user_id", mealie.db.migration_types.GUID(), nullable=True),
|
||||||
|
sa.Column("name", sa.String(), nullable=False),
|
||||||
|
sa.Column("description", sa.String(), nullable=True),
|
||||||
|
sa.Column("image", sa.String(), nullable=True),
|
||||||
|
sa.Column("total_time", sa.String(), nullable=True),
|
||||||
|
sa.Column("prep_time", sa.String(), nullable=True),
|
||||||
|
sa.Column("perform_time", sa.String(), nullable=True),
|
||||||
|
sa.Column("cook_time", sa.String(), nullable=True),
|
||||||
|
sa.Column("recipe_yield", sa.String(), nullable=True),
|
||||||
|
sa.Column("recipeCuisine", sa.String(), nullable=True),
|
||||||
|
sa.Column("rating", sa.Integer(), nullable=True),
|
||||||
|
sa.Column("org_url", sa.String(), nullable=True),
|
||||||
|
sa.Column("date_added", sa.Date(), nullable=True),
|
||||||
|
sa.Column("date_updated", sa.DateTime(), nullable=True),
|
||||||
|
sa.ForeignKeyConstraint(
|
||||||
|
["group_id"],
|
||||||
|
["groups.id"],
|
||||||
|
),
|
||||||
|
sa.ForeignKeyConstraint(["user_id"], ["users.id"], use_alter=True),
|
||||||
|
sa.PrimaryKeyConstraint("id"),
|
||||||
|
sa.UniqueConstraint("slug", "group_id", name="recipe_slug_group_id_key"),
|
||||||
|
)
|
||||||
|
op.create_index(op.f("ix_recipes_group_id"), "recipes", ["group_id"], unique=False)
|
||||||
|
op.create_index(op.f("ix_recipes_slug"), "recipes", ["slug"], unique=False)
|
||||||
|
op.create_index(op.f("ix_recipes_user_id"), "recipes", ["user_id"], unique=False)
|
||||||
|
op.create_table(
|
||||||
|
"server_tasks",
|
||||||
|
sa.Column("id", sa.Integer(), nullable=False),
|
||||||
|
sa.Column("created_at", sa.DateTime(), nullable=True),
|
||||||
|
sa.Column("update_at", sa.DateTime(), nullable=True),
|
||||||
|
sa.Column("name", sa.String(), nullable=False),
|
||||||
|
sa.Column("completed_date", sa.DateTime(), nullable=True),
|
||||||
|
sa.Column("status", sa.String(), nullable=False),
|
||||||
|
sa.Column("log", sa.String(), nullable=True),
|
||||||
|
sa.Column("group_id", mealie.db.migration_types.GUID(), nullable=False),
|
||||||
|
sa.ForeignKeyConstraint(
|
||||||
|
["group_id"],
|
||||||
|
["groups.id"],
|
||||||
|
),
|
||||||
|
sa.PrimaryKeyConstraint("id"),
|
||||||
|
)
|
||||||
|
op.create_index(op.f("ix_server_tasks_group_id"), "server_tasks", ["group_id"], unique=False)
|
||||||
|
op.create_table(
|
||||||
|
"shopping_lists",
|
||||||
|
sa.Column("created_at", sa.DateTime(), nullable=True),
|
||||||
|
sa.Column("update_at", sa.DateTime(), nullable=True),
|
||||||
|
sa.Column("id", mealie.db.migration_types.GUID(), nullable=False),
|
||||||
|
sa.Column("group_id", mealie.db.migration_types.GUID(), nullable=False),
|
||||||
|
sa.Column("name", sa.String(), nullable=True),
|
||||||
|
sa.ForeignKeyConstraint(
|
||||||
|
["group_id"],
|
||||||
|
["groups.id"],
|
||||||
|
),
|
||||||
|
sa.PrimaryKeyConstraint("id"),
|
||||||
|
)
|
||||||
|
op.create_index(op.f("ix_shopping_lists_group_id"), "shopping_lists", ["group_id"], unique=False)
|
||||||
|
op.create_table(
|
||||||
|
"tags",
|
||||||
|
sa.Column("created_at", sa.DateTime(), nullable=True),
|
||||||
|
sa.Column("update_at", sa.DateTime(), nullable=True),
|
||||||
|
sa.Column("id", mealie.db.migration_types.GUID(), nullable=False),
|
||||||
|
sa.Column("group_id", mealie.db.migration_types.GUID(), nullable=False),
|
||||||
|
sa.Column("name", sa.String(), nullable=False),
|
||||||
|
sa.Column("slug", sa.String(), nullable=False),
|
||||||
|
sa.ForeignKeyConstraint(
|
||||||
|
["group_id"],
|
||||||
|
["groups.id"],
|
||||||
|
),
|
||||||
|
sa.PrimaryKeyConstraint("id"),
|
||||||
|
sa.UniqueConstraint("slug", "group_id", name="tags_slug_group_id_key"),
|
||||||
|
)
|
||||||
|
op.create_index(op.f("ix_tags_group_id"), "tags", ["group_id"], unique=False)
|
||||||
|
op.create_index(op.f("ix_tags_name"), "tags", ["name"], unique=False)
|
||||||
|
op.create_index(op.f("ix_tags_slug"), "tags", ["slug"], unique=False)
|
||||||
|
op.create_table(
|
||||||
|
"tools",
|
||||||
|
sa.Column("created_at", sa.DateTime(), nullable=True),
|
||||||
|
sa.Column("update_at", sa.DateTime(), nullable=True),
|
||||||
|
sa.Column("id", mealie.db.migration_types.GUID(), nullable=False),
|
||||||
|
sa.Column("group_id", mealie.db.migration_types.GUID(), nullable=False),
|
||||||
|
sa.Column("name", sa.String(), nullable=False),
|
||||||
|
sa.Column("slug", sa.String(), nullable=False),
|
||||||
|
sa.Column("on_hand", sa.Boolean(), nullable=True),
|
||||||
|
sa.ForeignKeyConstraint(
|
||||||
|
["group_id"],
|
||||||
|
["groups.id"],
|
||||||
|
),
|
||||||
|
sa.PrimaryKeyConstraint("id"),
|
||||||
|
sa.UniqueConstraint("slug", "group_id", name="tools_slug_group_id_key"),
|
||||||
|
)
|
||||||
|
op.create_index(op.f("ix_tools_name"), "tools", ["name"], unique=True)
|
||||||
|
op.create_index(op.f("ix_tools_slug"), "tools", ["slug"], unique=True)
|
||||||
|
op.create_table(
|
||||||
|
"webhook_urls",
|
||||||
|
sa.Column("created_at", sa.DateTime(), nullable=True),
|
||||||
|
sa.Column("update_at", sa.DateTime(), nullable=True),
|
||||||
|
sa.Column("id", mealie.db.migration_types.GUID(), nullable=False),
|
||||||
|
sa.Column("group_id", mealie.db.migration_types.GUID(), nullable=True),
|
||||||
|
sa.Column("enabled", sa.Boolean(), nullable=True),
|
||||||
|
sa.Column("name", sa.String(), nullable=True),
|
||||||
|
sa.Column("url", sa.String(), nullable=True),
|
||||||
|
sa.Column("time", sa.String(), nullable=True),
|
||||||
|
sa.ForeignKeyConstraint(
|
||||||
|
["group_id"],
|
||||||
|
["groups.id"],
|
||||||
|
),
|
||||||
|
sa.PrimaryKeyConstraint("id"),
|
||||||
|
)
|
||||||
|
op.create_index(op.f("ix_webhook_urls_group_id"), "webhook_urls", ["group_id"], unique=False)
|
||||||
|
op.create_table(
|
||||||
|
"api_extras",
|
||||||
|
sa.Column("created_at", sa.DateTime(), nullable=True),
|
||||||
|
sa.Column("update_at", sa.DateTime(), nullable=True),
|
||||||
|
sa.Column("id", sa.Integer(), nullable=False),
|
||||||
|
sa.Column("recipee_id", mealie.db.migration_types.GUID(), nullable=True),
|
||||||
|
sa.Column("key_name", sa.String(), nullable=True),
|
||||||
|
sa.Column("value", sa.String(), nullable=True),
|
||||||
|
sa.ForeignKeyConstraint(
|
||||||
|
["recipee_id"],
|
||||||
|
["recipes.id"],
|
||||||
|
),
|
||||||
|
sa.PrimaryKeyConstraint("id"),
|
||||||
|
)
|
||||||
|
op.create_table(
|
||||||
|
"cookbooks_to_categories",
|
||||||
|
sa.Column("cookbook_id", mealie.db.migration_types.GUID(), nullable=True),
|
||||||
|
sa.Column("category_id", mealie.db.migration_types.GUID(), nullable=True),
|
||||||
|
sa.ForeignKeyConstraint(
|
||||||
|
["category_id"],
|
||||||
|
["categories.id"],
|
||||||
|
),
|
||||||
|
sa.ForeignKeyConstraint(
|
||||||
|
["cookbook_id"],
|
||||||
|
["cookbooks.id"],
|
||||||
|
),
|
||||||
|
)
|
||||||
|
op.create_table(
|
||||||
|
"group_events_notifier_options",
|
||||||
|
sa.Column("created_at", sa.DateTime(), nullable=True),
|
||||||
|
sa.Column("update_at", sa.DateTime(), nullable=True),
|
||||||
|
sa.Column("id", mealie.db.migration_types.GUID(), nullable=False),
|
||||||
|
sa.Column("event_notifier_id", mealie.db.migration_types.GUID(), nullable=False),
|
||||||
|
sa.Column("recipe_created", sa.Boolean(), nullable=False),
|
||||||
|
sa.Column("recipe_updated", sa.Boolean(), nullable=False),
|
||||||
|
sa.Column("recipe_deleted", sa.Boolean(), nullable=False),
|
||||||
|
sa.Column("user_signup", sa.Boolean(), nullable=False),
|
||||||
|
sa.Column("data_migrations", sa.Boolean(), nullable=False),
|
||||||
|
sa.Column("data_export", sa.Boolean(), nullable=False),
|
||||||
|
sa.Column("data_import", sa.Boolean(), nullable=False),
|
||||||
|
sa.Column("mealplan_entry_created", sa.Boolean(), nullable=False),
|
||||||
|
sa.Column("shopping_list_created", sa.Boolean(), nullable=False),
|
||||||
|
sa.Column("shopping_list_updated", sa.Boolean(), nullable=False),
|
||||||
|
sa.Column("shopping_list_deleted", sa.Boolean(), nullable=False),
|
||||||
|
sa.Column("cookbook_created", sa.Boolean(), nullable=False),
|
||||||
|
sa.Column("cookbook_updated", sa.Boolean(), nullable=False),
|
||||||
|
sa.Column("cookbook_deleted", sa.Boolean(), nullable=False),
|
||||||
|
sa.Column("tag_created", sa.Boolean(), nullable=False),
|
||||||
|
sa.Column("tag_updated", sa.Boolean(), nullable=False),
|
||||||
|
sa.Column("tag_deleted", sa.Boolean(), nullable=False),
|
||||||
|
sa.Column("category_created", sa.Boolean(), nullable=False),
|
||||||
|
sa.Column("category_updated", sa.Boolean(), nullable=False),
|
||||||
|
sa.Column("category_deleted", sa.Boolean(), nullable=False),
|
||||||
|
sa.ForeignKeyConstraint(
|
||||||
|
["event_notifier_id"],
|
||||||
|
["group_events_notifiers.id"],
|
||||||
|
),
|
||||||
|
sa.PrimaryKeyConstraint("id"),
|
||||||
|
)
|
||||||
|
op.create_table(
|
||||||
|
"group_meal_plans",
|
||||||
|
sa.Column("id", sa.Integer(), nullable=False),
|
||||||
|
sa.Column("created_at", sa.DateTime(), nullable=True),
|
||||||
|
sa.Column("update_at", sa.DateTime(), nullable=True),
|
||||||
|
sa.Column("date", sa.Date(), nullable=False),
|
||||||
|
sa.Column("entry_type", sa.String(), nullable=False),
|
||||||
|
sa.Column("title", sa.String(), nullable=False),
|
||||||
|
sa.Column("text", sa.String(), nullable=False),
|
||||||
|
sa.Column("group_id", mealie.db.migration_types.GUID(), nullable=True),
|
||||||
|
sa.Column("recipe_id", mealie.db.migration_types.GUID(), nullable=True),
|
||||||
|
sa.ForeignKeyConstraint(
|
||||||
|
["group_id"],
|
||||||
|
["groups.id"],
|
||||||
|
),
|
||||||
|
sa.ForeignKeyConstraint(
|
||||||
|
["recipe_id"],
|
||||||
|
["recipes.id"],
|
||||||
|
),
|
||||||
|
sa.PrimaryKeyConstraint("id"),
|
||||||
|
)
|
||||||
|
op.create_index(op.f("ix_group_meal_plans_date"), "group_meal_plans", ["date"], unique=False)
|
||||||
|
op.create_index(op.f("ix_group_meal_plans_entry_type"), "group_meal_plans", ["entry_type"], unique=False)
|
||||||
|
op.create_index(op.f("ix_group_meal_plans_group_id"), "group_meal_plans", ["group_id"], unique=False)
|
||||||
|
op.create_index(op.f("ix_group_meal_plans_recipe_id"), "group_meal_plans", ["recipe_id"], unique=False)
|
||||||
|
op.create_index(op.f("ix_group_meal_plans_title"), "group_meal_plans", ["title"], unique=False)
|
||||||
|
op.create_table(
|
||||||
|
"group_to_categories",
|
||||||
|
sa.Column("group_id", mealie.db.migration_types.GUID(), nullable=True),
|
||||||
|
sa.Column("category_id", mealie.db.migration_types.GUID(), nullable=True),
|
||||||
|
sa.ForeignKeyConstraint(
|
||||||
|
["category_id"],
|
||||||
|
["categories.id"],
|
||||||
|
),
|
||||||
|
sa.ForeignKeyConstraint(
|
||||||
|
["group_id"],
|
||||||
|
["groups.id"],
|
||||||
|
),
|
||||||
|
)
|
||||||
|
op.create_table(
|
||||||
|
"ingredient_foods",
|
||||||
|
sa.Column("created_at", sa.DateTime(), nullable=True),
|
||||||
|
sa.Column("update_at", sa.DateTime(), nullable=True),
|
||||||
|
sa.Column("id", mealie.db.migration_types.GUID(), nullable=False),
|
||||||
|
sa.Column("group_id", mealie.db.migration_types.GUID(), nullable=False),
|
||||||
|
sa.Column("name", sa.String(), nullable=True),
|
||||||
|
sa.Column("description", sa.String(), nullable=True),
|
||||||
|
sa.Column("label_id", mealie.db.migration_types.GUID(), nullable=True),
|
||||||
|
sa.ForeignKeyConstraint(
|
||||||
|
["group_id"],
|
||||||
|
["groups.id"],
|
||||||
|
),
|
||||||
|
sa.ForeignKeyConstraint(
|
||||||
|
["label_id"],
|
||||||
|
["multi_purpose_labels.id"],
|
||||||
|
),
|
||||||
|
sa.PrimaryKeyConstraint("id"),
|
||||||
|
)
|
||||||
|
op.create_table(
|
||||||
|
"notes",
|
||||||
|
sa.Column("created_at", sa.DateTime(), nullable=True),
|
||||||
|
sa.Column("update_at", sa.DateTime(), nullable=True),
|
||||||
|
sa.Column("id", sa.Integer(), nullable=False),
|
||||||
|
sa.Column("recipe_id", mealie.db.migration_types.GUID(), nullable=True),
|
||||||
|
sa.Column("title", sa.String(), nullable=True),
|
||||||
|
sa.Column("text", sa.String(), nullable=True),
|
||||||
|
sa.ForeignKeyConstraint(
|
||||||
|
["recipe_id"],
|
||||||
|
["recipes.id"],
|
||||||
|
),
|
||||||
|
sa.PrimaryKeyConstraint("id"),
|
||||||
|
)
|
||||||
|
op.create_table(
|
||||||
|
"plan_rules_to_categories",
|
||||||
|
sa.Column("group_plan_rule_id", mealie.db.migration_types.GUID(), nullable=True),
|
||||||
|
sa.Column("category_id", mealie.db.migration_types.GUID(), nullable=True),
|
||||||
|
sa.ForeignKeyConstraint(
|
||||||
|
["category_id"],
|
||||||
|
["categories.id"],
|
||||||
|
),
|
||||||
|
sa.ForeignKeyConstraint(
|
||||||
|
["group_plan_rule_id"],
|
||||||
|
["group_meal_plan_rules.id"],
|
||||||
|
),
|
||||||
|
)
|
||||||
|
op.create_table(
|
||||||
|
"plan_rules_to_tags",
|
||||||
|
sa.Column("plan_rule_id", mealie.db.migration_types.GUID(), nullable=True),
|
||||||
|
sa.Column("tag_id", mealie.db.migration_types.GUID(), nullable=True),
|
||||||
|
sa.ForeignKeyConstraint(
|
||||||
|
["plan_rule_id"],
|
||||||
|
["group_meal_plan_rules.id"],
|
||||||
|
),
|
||||||
|
sa.ForeignKeyConstraint(
|
||||||
|
["tag_id"],
|
||||||
|
["tags.id"],
|
||||||
|
),
|
||||||
|
)
|
||||||
|
op.create_table(
|
||||||
|
"recipe_assets",
|
||||||
|
sa.Column("created_at", sa.DateTime(), nullable=True),
|
||||||
|
sa.Column("update_at", sa.DateTime(), nullable=True),
|
||||||
|
sa.Column("id", sa.Integer(), nullable=False),
|
||||||
|
sa.Column("recipe_id", mealie.db.migration_types.GUID(), nullable=True),
|
||||||
|
sa.Column("name", sa.String(), nullable=True),
|
||||||
|
sa.Column("icon", sa.String(), nullable=True),
|
||||||
|
sa.Column("file_name", sa.String(), nullable=True),
|
||||||
|
sa.ForeignKeyConstraint(
|
||||||
|
["recipe_id"],
|
||||||
|
["recipes.id"],
|
||||||
|
),
|
||||||
|
sa.PrimaryKeyConstraint("id"),
|
||||||
|
)
|
||||||
|
op.create_table(
|
||||||
|
"recipe_instructions",
|
||||||
|
sa.Column("created_at", sa.DateTime(), nullable=True),
|
||||||
|
sa.Column("update_at", sa.DateTime(), nullable=True),
|
||||||
|
sa.Column("id", mealie.db.migration_types.GUID(), nullable=False),
|
||||||
|
sa.Column("recipe_id", mealie.db.migration_types.GUID(), nullable=True),
|
||||||
|
sa.Column("position", sa.Integer(), nullable=True),
|
||||||
|
sa.Column("type", sa.String(), nullable=True),
|
||||||
|
sa.Column("title", sa.String(), nullable=True),
|
||||||
|
sa.Column("text", sa.String(), nullable=True),
|
||||||
|
sa.ForeignKeyConstraint(
|
||||||
|
["recipe_id"],
|
||||||
|
["recipes.id"],
|
||||||
|
),
|
||||||
|
sa.PrimaryKeyConstraint("id"),
|
||||||
|
)
|
||||||
|
op.create_table(
|
||||||
|
"recipe_nutrition",
|
||||||
|
sa.Column("created_at", sa.DateTime(), nullable=True),
|
||||||
|
sa.Column("update_at", sa.DateTime(), nullable=True),
|
||||||
|
sa.Column("id", sa.Integer(), nullable=False),
|
||||||
|
sa.Column("recipe_id", mealie.db.migration_types.GUID(), nullable=True),
|
||||||
|
sa.Column("calories", sa.String(), nullable=True),
|
||||||
|
sa.Column("fat_content", sa.String(), nullable=True),
|
||||||
|
sa.Column("fiber_content", sa.String(), nullable=True),
|
||||||
|
sa.Column("protein_content", sa.String(), nullable=True),
|
||||||
|
sa.Column("carbohydrate_content", sa.String(), nullable=True),
|
||||||
|
sa.Column("sodium_content", sa.String(), nullable=True),
|
||||||
|
sa.Column("sugar_content", sa.String(), nullable=True),
|
||||||
|
sa.ForeignKeyConstraint(
|
||||||
|
["recipe_id"],
|
||||||
|
["recipes.id"],
|
||||||
|
),
|
||||||
|
sa.PrimaryKeyConstraint("id"),
|
||||||
|
)
|
||||||
|
op.create_table(
|
||||||
|
"recipe_settings",
|
||||||
|
sa.Column("created_at", sa.DateTime(), nullable=True),
|
||||||
|
sa.Column("update_at", sa.DateTime(), nullable=True),
|
||||||
|
sa.Column("id", sa.Integer(), nullable=False),
|
||||||
|
sa.Column("recipe_id", mealie.db.migration_types.GUID(), nullable=True),
|
||||||
|
sa.Column("public", sa.Boolean(), nullable=True),
|
||||||
|
sa.Column("show_nutrition", sa.Boolean(), nullable=True),
|
||||||
|
sa.Column("show_assets", sa.Boolean(), nullable=True),
|
||||||
|
sa.Column("landscape_view", sa.Boolean(), nullable=True),
|
||||||
|
sa.Column("disable_amount", sa.Boolean(), nullable=True),
|
||||||
|
sa.Column("disable_comments", sa.Boolean(), nullable=True),
|
||||||
|
sa.Column("locked", sa.Boolean(), nullable=True),
|
||||||
|
sa.ForeignKeyConstraint(
|
||||||
|
["recipe_id"],
|
||||||
|
["recipes.id"],
|
||||||
|
),
|
||||||
|
sa.PrimaryKeyConstraint("id"),
|
||||||
|
)
|
||||||
|
op.create_table(
|
||||||
|
"recipe_share_tokens",
|
||||||
|
sa.Column("created_at", sa.DateTime(), nullable=True),
|
||||||
|
sa.Column("update_at", sa.DateTime(), nullable=True),
|
||||||
|
sa.Column("id", mealie.db.migration_types.GUID(), nullable=False),
|
||||||
|
sa.Column("group_id", mealie.db.migration_types.GUID(), nullable=False),
|
||||||
|
sa.Column("recipe_id", mealie.db.migration_types.GUID(), nullable=False),
|
||||||
|
sa.Column("expires_at", sa.DateTime(), nullable=False),
|
||||||
|
sa.ForeignKeyConstraint(
|
||||||
|
["group_id"],
|
||||||
|
["groups.id"],
|
||||||
|
),
|
||||||
|
sa.ForeignKeyConstraint(
|
||||||
|
["recipe_id"],
|
||||||
|
["recipes.id"],
|
||||||
|
),
|
||||||
|
sa.PrimaryKeyConstraint("id"),
|
||||||
|
)
|
||||||
|
op.create_index(op.f("ix_recipe_share_tokens_group_id"), "recipe_share_tokens", ["group_id"], unique=False)
|
||||||
|
op.create_table(
|
||||||
|
"recipes_to_categories",
|
||||||
|
sa.Column("recipe_id", mealie.db.migration_types.GUID(), nullable=True),
|
||||||
|
sa.Column("category_id", mealie.db.migration_types.GUID(), nullable=True),
|
||||||
|
sa.ForeignKeyConstraint(
|
||||||
|
["category_id"],
|
||||||
|
["categories.id"],
|
||||||
|
),
|
||||||
|
sa.ForeignKeyConstraint(
|
||||||
|
["recipe_id"],
|
||||||
|
["recipes.id"],
|
||||||
|
),
|
||||||
|
)
|
||||||
|
op.create_table(
|
||||||
|
"recipes_to_tags",
|
||||||
|
sa.Column("recipe_id", mealie.db.migration_types.GUID(), nullable=True),
|
||||||
|
sa.Column("tag_id", mealie.db.migration_types.GUID(), nullable=True),
|
||||||
|
sa.ForeignKeyConstraint(
|
||||||
|
["recipe_id"],
|
||||||
|
["recipes.id"],
|
||||||
|
),
|
||||||
|
sa.ForeignKeyConstraint(
|
||||||
|
["tag_id"],
|
||||||
|
["tags.id"],
|
||||||
|
),
|
||||||
|
)
|
||||||
|
op.create_table(
|
||||||
|
"recipes_to_tools",
|
||||||
|
sa.Column("recipe_id", mealie.db.migration_types.GUID(), nullable=True),
|
||||||
|
sa.Column("tool_id", mealie.db.migration_types.GUID(), nullable=True),
|
||||||
|
sa.ForeignKeyConstraint(
|
||||||
|
["recipe_id"],
|
||||||
|
["recipes.id"],
|
||||||
|
),
|
||||||
|
sa.ForeignKeyConstraint(
|
||||||
|
["tool_id"],
|
||||||
|
["tools.id"],
|
||||||
|
),
|
||||||
|
)
|
||||||
|
op.create_table(
|
||||||
|
"report_entries",
|
||||||
|
sa.Column("created_at", sa.DateTime(), nullable=True),
|
||||||
|
sa.Column("update_at", sa.DateTime(), nullable=True),
|
||||||
|
sa.Column("id", mealie.db.migration_types.GUID(), nullable=False),
|
||||||
|
sa.Column("success", sa.Boolean(), nullable=True),
|
||||||
|
sa.Column("message", sa.String(), nullable=True),
|
||||||
|
sa.Column("exception", sa.String(), nullable=True),
|
||||||
|
sa.Column("timestamp", sa.DateTime(), nullable=False),
|
||||||
|
sa.Column("report_id", mealie.db.migration_types.GUID(), nullable=False),
|
||||||
|
sa.ForeignKeyConstraint(
|
||||||
|
["report_id"],
|
||||||
|
["group_reports.id"],
|
||||||
|
),
|
||||||
|
sa.PrimaryKeyConstraint("id"),
|
||||||
|
)
|
||||||
|
op.create_table(
|
||||||
|
"shopping_list_recipe_reference",
|
||||||
|
sa.Column("created_at", sa.DateTime(), nullable=True),
|
||||||
|
sa.Column("update_at", sa.DateTime(), nullable=True),
|
||||||
|
sa.Column("id", mealie.db.migration_types.GUID(), nullable=False),
|
||||||
|
sa.Column("shopping_list_id", mealie.db.migration_types.GUID(), nullable=False),
|
||||||
|
sa.Column("recipe_id", mealie.db.migration_types.GUID(), nullable=True),
|
||||||
|
sa.Column("recipe_quantity", sa.Float(), nullable=False),
|
||||||
|
sa.ForeignKeyConstraint(
|
||||||
|
["recipe_id"],
|
||||||
|
["recipes.id"],
|
||||||
|
),
|
||||||
|
sa.ForeignKeyConstraint(
|
||||||
|
["shopping_list_id"],
|
||||||
|
["shopping_lists.id"],
|
||||||
|
),
|
||||||
|
sa.PrimaryKeyConstraint("id", "shopping_list_id"),
|
||||||
|
)
|
||||||
|
op.create_index(
|
||||||
|
op.f("ix_shopping_list_recipe_reference_recipe_id"),
|
||||||
|
"shopping_list_recipe_reference",
|
||||||
|
["recipe_id"],
|
||||||
|
unique=False,
|
||||||
|
)
|
||||||
|
op.create_table(
|
||||||
|
"users",
|
||||||
|
sa.Column("created_at", sa.DateTime(), nullable=True),
|
||||||
|
sa.Column("update_at", sa.DateTime(), nullable=True),
|
||||||
|
sa.Column("id", mealie.db.migration_types.GUID(), nullable=False),
|
||||||
|
sa.Column("full_name", sa.String(), nullable=True),
|
||||||
|
sa.Column("username", sa.String(), nullable=True),
|
||||||
|
sa.Column("email", sa.String(), nullable=True),
|
||||||
|
sa.Column("password", sa.String(), nullable=True),
|
||||||
|
sa.Column("admin", sa.Boolean(), nullable=True),
|
||||||
|
sa.Column("advanced", sa.Boolean(), nullable=True),
|
||||||
|
sa.Column("group_id", mealie.db.migration_types.GUID(), nullable=False),
|
||||||
|
sa.Column("cache_key", sa.String(), nullable=True),
|
||||||
|
sa.Column("can_manage", sa.Boolean(), nullable=True),
|
||||||
|
sa.Column("can_invite", sa.Boolean(), nullable=True),
|
||||||
|
sa.Column("can_organize", sa.Boolean(), nullable=True),
|
||||||
|
sa.Column("owned_recipes_id", mealie.db.migration_types.GUID(), nullable=True),
|
||||||
|
sa.ForeignKeyConstraint(
|
||||||
|
["group_id"],
|
||||||
|
["groups.id"],
|
||||||
|
),
|
||||||
|
sa.ForeignKeyConstraint(
|
||||||
|
["owned_recipes_id"],
|
||||||
|
["recipes.id"],
|
||||||
|
),
|
||||||
|
sa.PrimaryKeyConstraint("id"),
|
||||||
|
)
|
||||||
|
op.create_index(op.f("ix_users_email"), "users", ["email"], unique=True)
|
||||||
|
op.create_index(op.f("ix_users_full_name"), "users", ["full_name"], unique=False)
|
||||||
|
op.create_index(op.f("ix_users_group_id"), "users", ["group_id"], unique=False)
|
||||||
|
op.create_index(op.f("ix_users_username"), "users", ["username"], unique=True)
|
||||||
|
op.create_table(
|
||||||
|
"long_live_tokens",
|
||||||
|
sa.Column("id", sa.Integer(), nullable=False),
|
||||||
|
sa.Column("created_at", sa.DateTime(), nullable=True),
|
||||||
|
sa.Column("update_at", sa.DateTime(), nullable=True),
|
||||||
|
sa.Column("name", sa.String(), nullable=False),
|
||||||
|
sa.Column("token", sa.String(), nullable=False),
|
||||||
|
sa.Column("user_id", mealie.db.migration_types.GUID(), nullable=True),
|
||||||
|
sa.ForeignKeyConstraint(
|
||||||
|
["user_id"],
|
||||||
|
["users.id"],
|
||||||
|
),
|
||||||
|
sa.PrimaryKeyConstraint("id"),
|
||||||
|
)
|
||||||
|
op.create_table(
|
||||||
|
"password_reset_tokens",
|
||||||
|
sa.Column("id", sa.Integer(), nullable=False),
|
||||||
|
sa.Column("created_at", sa.DateTime(), nullable=True),
|
||||||
|
sa.Column("update_at", sa.DateTime(), nullable=True),
|
||||||
|
sa.Column("user_id", mealie.db.migration_types.GUID(), nullable=False),
|
||||||
|
sa.Column("token", sa.String(length=64), nullable=False),
|
||||||
|
sa.ForeignKeyConstraint(
|
||||||
|
["user_id"],
|
||||||
|
["users.id"],
|
||||||
|
),
|
||||||
|
sa.PrimaryKeyConstraint("id"),
|
||||||
|
sa.UniqueConstraint("token"),
|
||||||
|
)
|
||||||
|
op.create_table(
|
||||||
|
"recipe_comments",
|
||||||
|
sa.Column("created_at", sa.DateTime(), nullable=True),
|
||||||
|
sa.Column("update_at", sa.DateTime(), nullable=True),
|
||||||
|
sa.Column("id", mealie.db.migration_types.GUID(), nullable=False),
|
||||||
|
sa.Column("text", sa.String(), nullable=True),
|
||||||
|
sa.Column("recipe_id", mealie.db.migration_types.GUID(), nullable=False),
|
||||||
|
sa.Column("user_id", mealie.db.migration_types.GUID(), nullable=False),
|
||||||
|
sa.ForeignKeyConstraint(
|
||||||
|
["recipe_id"],
|
||||||
|
["recipes.id"],
|
||||||
|
),
|
||||||
|
sa.ForeignKeyConstraint(
|
||||||
|
["user_id"],
|
||||||
|
["users.id"],
|
||||||
|
),
|
||||||
|
sa.PrimaryKeyConstraint("id"),
|
||||||
|
)
|
||||||
|
op.create_table(
|
||||||
|
"recipe_ingredient_ref_link",
|
||||||
|
sa.Column("id", sa.Integer(), nullable=False),
|
||||||
|
sa.Column("created_at", sa.DateTime(), nullable=True),
|
||||||
|
sa.Column("update_at", sa.DateTime(), nullable=True),
|
||||||
|
sa.Column("instruction_id", mealie.db.migration_types.GUID(), nullable=True),
|
||||||
|
sa.Column("reference_id", mealie.db.migration_types.GUID(), nullable=True),
|
||||||
|
sa.ForeignKeyConstraint(
|
||||||
|
["instruction_id"],
|
||||||
|
["recipe_instructions.id"],
|
||||||
|
),
|
||||||
|
sa.PrimaryKeyConstraint("id"),
|
||||||
|
)
|
||||||
|
op.create_table(
|
||||||
|
"recipes_ingredients",
|
||||||
|
sa.Column("created_at", sa.DateTime(), nullable=True),
|
||||||
|
sa.Column("update_at", sa.DateTime(), nullable=True),
|
||||||
|
sa.Column("id", sa.Integer(), nullable=False),
|
||||||
|
sa.Column("position", sa.Integer(), nullable=True),
|
||||||
|
sa.Column("recipe_id", mealie.db.migration_types.GUID(), nullable=True),
|
||||||
|
sa.Column("title", sa.String(), nullable=True),
|
||||||
|
sa.Column("note", sa.String(), nullable=True),
|
||||||
|
sa.Column("unit_id", mealie.db.migration_types.GUID(), nullable=True),
|
||||||
|
sa.Column("food_id", mealie.db.migration_types.GUID(), nullable=True),
|
||||||
|
sa.Column("quantity", sa.Integer(), nullable=True),
|
||||||
|
sa.Column("reference_id", mealie.db.migration_types.GUID(), nullable=True),
|
||||||
|
sa.ForeignKeyConstraint(
|
||||||
|
["food_id"],
|
||||||
|
["ingredient_foods.id"],
|
||||||
|
),
|
||||||
|
sa.ForeignKeyConstraint(
|
||||||
|
["recipe_id"],
|
||||||
|
["recipes.id"],
|
||||||
|
),
|
||||||
|
sa.ForeignKeyConstraint(
|
||||||
|
["unit_id"],
|
||||||
|
["ingredient_units.id"],
|
||||||
|
),
|
||||||
|
sa.PrimaryKeyConstraint("id"),
|
||||||
|
)
|
||||||
|
op.create_table(
|
||||||
|
"shopping_list_items",
|
||||||
|
sa.Column("created_at", sa.DateTime(), nullable=True),
|
||||||
|
sa.Column("update_at", sa.DateTime(), nullable=True),
|
||||||
|
sa.Column("id", mealie.db.migration_types.GUID(), nullable=False),
|
||||||
|
sa.Column("shopping_list_id", mealie.db.migration_types.GUID(), nullable=True),
|
||||||
|
sa.Column("is_ingredient", sa.Boolean(), nullable=True),
|
||||||
|
sa.Column("position", sa.Integer(), nullable=False),
|
||||||
|
sa.Column("checked", sa.Boolean(), nullable=True),
|
||||||
|
sa.Column("quantity", sa.Float(), nullable=True),
|
||||||
|
sa.Column("note", sa.String(), nullable=True),
|
||||||
|
sa.Column("is_food", sa.Boolean(), nullable=True),
|
||||||
|
sa.Column("unit_id", mealie.db.migration_types.GUID(), nullable=True),
|
||||||
|
sa.Column("food_id", mealie.db.migration_types.GUID(), nullable=True),
|
||||||
|
sa.Column("label_id", mealie.db.migration_types.GUID(), nullable=True),
|
||||||
|
sa.ForeignKeyConstraint(
|
||||||
|
["food_id"],
|
||||||
|
["ingredient_foods.id"],
|
||||||
|
),
|
||||||
|
sa.ForeignKeyConstraint(
|
||||||
|
["label_id"],
|
||||||
|
["multi_purpose_labels.id"],
|
||||||
|
),
|
||||||
|
sa.ForeignKeyConstraint(
|
||||||
|
["shopping_list_id"],
|
||||||
|
["shopping_lists.id"],
|
||||||
|
),
|
||||||
|
sa.ForeignKeyConstraint(
|
||||||
|
["unit_id"],
|
||||||
|
["ingredient_units.id"],
|
||||||
|
),
|
||||||
|
sa.PrimaryKeyConstraint("id"),
|
||||||
|
)
|
||||||
|
op.create_table(
|
||||||
|
"users_to_favorites",
|
||||||
|
sa.Column("user_id", mealie.db.migration_types.GUID(), nullable=True),
|
||||||
|
sa.Column("recipe_id", mealie.db.migration_types.GUID(), nullable=True),
|
||||||
|
sa.ForeignKeyConstraint(
|
||||||
|
["recipe_id"],
|
||||||
|
["recipes.id"],
|
||||||
|
),
|
||||||
|
sa.ForeignKeyConstraint(
|
||||||
|
["user_id"],
|
||||||
|
["users.id"],
|
||||||
|
),
|
||||||
|
)
|
||||||
|
op.create_table(
|
||||||
|
"shopping_list_item_recipe_reference",
|
||||||
|
sa.Column("created_at", sa.DateTime(), nullable=True),
|
||||||
|
sa.Column("update_at", sa.DateTime(), nullable=True),
|
||||||
|
sa.Column("id", mealie.db.migration_types.GUID(), nullable=False),
|
||||||
|
sa.Column("shopping_list_item_id", mealie.db.migration_types.GUID(), nullable=False),
|
||||||
|
sa.Column("recipe_id", mealie.db.migration_types.GUID(), nullable=True),
|
||||||
|
sa.Column("recipe_quantity", sa.Float(), nullable=False),
|
||||||
|
sa.ForeignKeyConstraint(
|
||||||
|
["recipe_id"],
|
||||||
|
["recipes.id"],
|
||||||
|
),
|
||||||
|
sa.ForeignKeyConstraint(
|
||||||
|
["shopping_list_item_id"],
|
||||||
|
["shopping_list_items.id"],
|
||||||
|
),
|
||||||
|
sa.PrimaryKeyConstraint("id", "shopping_list_item_id"),
|
||||||
|
)
|
||||||
|
op.create_index(
|
||||||
|
op.f("ix_shopping_list_item_recipe_reference_recipe_id"),
|
||||||
|
"shopping_list_item_recipe_reference",
|
||||||
|
["recipe_id"],
|
||||||
|
unique=False,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade():
|
||||||
|
op.drop_index(
|
||||||
|
op.f("ix_shopping_list_item_recipe_reference_recipe_id"), table_name="shopping_list_item_recipe_reference"
|
||||||
|
)
|
||||||
|
op.drop_table("shopping_list_item_recipe_reference")
|
||||||
|
op.drop_table("users_to_favorites")
|
||||||
|
op.drop_table("shopping_list_items")
|
||||||
|
op.drop_table("recipes_ingredients")
|
||||||
|
op.drop_table("recipe_ingredient_ref_link")
|
||||||
|
op.drop_table("recipe_comments")
|
||||||
|
op.drop_table("password_reset_tokens")
|
||||||
|
op.drop_table("long_live_tokens")
|
||||||
|
op.drop_index(op.f("ix_users_username"), table_name="users")
|
||||||
|
op.drop_index(op.f("ix_users_group_id"), table_name="users")
|
||||||
|
op.drop_index(op.f("ix_users_full_name"), table_name="users")
|
||||||
|
op.drop_index(op.f("ix_users_email"), table_name="users")
|
||||||
|
op.drop_table("users")
|
||||||
|
op.drop_index(op.f("ix_shopping_list_recipe_reference_recipe_id"), table_name="shopping_list_recipe_reference")
|
||||||
|
op.drop_table("shopping_list_recipe_reference")
|
||||||
|
op.drop_table("report_entries")
|
||||||
|
op.drop_table("recipes_to_tools")
|
||||||
|
op.drop_table("recipes_to_tags")
|
||||||
|
op.drop_table("recipes_to_categories")
|
||||||
|
op.drop_index(op.f("ix_recipe_share_tokens_group_id"), table_name="recipe_share_tokens")
|
||||||
|
op.drop_table("recipe_share_tokens")
|
||||||
|
op.drop_table("recipe_settings")
|
||||||
|
op.drop_table("recipe_nutrition")
|
||||||
|
op.drop_table("recipe_instructions")
|
||||||
|
op.drop_table("recipe_assets")
|
||||||
|
op.drop_table("plan_rules_to_tags")
|
||||||
|
op.drop_table("plan_rules_to_categories")
|
||||||
|
op.drop_table("notes")
|
||||||
|
op.drop_table("ingredient_foods")
|
||||||
|
op.drop_table("group_to_categories")
|
||||||
|
op.drop_index(op.f("ix_group_meal_plans_title"), table_name="group_meal_plans")
|
||||||
|
op.drop_index(op.f("ix_group_meal_plans_recipe_id"), table_name="group_meal_plans")
|
||||||
|
op.drop_index(op.f("ix_group_meal_plans_group_id"), table_name="group_meal_plans")
|
||||||
|
op.drop_index(op.f("ix_group_meal_plans_entry_type"), table_name="group_meal_plans")
|
||||||
|
op.drop_index(op.f("ix_group_meal_plans_date"), table_name="group_meal_plans")
|
||||||
|
op.drop_table("group_meal_plans")
|
||||||
|
op.drop_table("group_events_notifier_options")
|
||||||
|
op.drop_table("cookbooks_to_categories")
|
||||||
|
op.drop_table("api_extras")
|
||||||
|
op.drop_index(op.f("ix_webhook_urls_group_id"), table_name="webhook_urls")
|
||||||
|
op.drop_table("webhook_urls")
|
||||||
|
op.drop_index(op.f("ix_tools_slug"), table_name="tools")
|
||||||
|
op.drop_index(op.f("ix_tools_name"), table_name="tools")
|
||||||
|
op.drop_table("tools")
|
||||||
|
op.drop_index(op.f("ix_tags_slug"), table_name="tags")
|
||||||
|
op.drop_index(op.f("ix_tags_name"), table_name="tags")
|
||||||
|
op.drop_index(op.f("ix_tags_group_id"), table_name="tags")
|
||||||
|
op.drop_table("tags")
|
||||||
|
op.drop_index(op.f("ix_shopping_lists_group_id"), table_name="shopping_lists")
|
||||||
|
op.drop_table("shopping_lists")
|
||||||
|
op.drop_index(op.f("ix_server_tasks_group_id"), table_name="server_tasks")
|
||||||
|
op.drop_table("server_tasks")
|
||||||
|
op.drop_index(op.f("ix_recipes_user_id"), table_name="recipes")
|
||||||
|
op.drop_index(op.f("ix_recipes_slug"), table_name="recipes")
|
||||||
|
op.drop_index(op.f("ix_recipes_group_id"), table_name="recipes")
|
||||||
|
op.drop_table("recipes")
|
||||||
|
op.drop_index(op.f("ix_multi_purpose_labels_group_id"), table_name="multi_purpose_labels")
|
||||||
|
op.drop_table("multi_purpose_labels")
|
||||||
|
op.drop_index(op.f("ix_invite_tokens_token"), table_name="invite_tokens")
|
||||||
|
op.drop_table("invite_tokens")
|
||||||
|
op.drop_table("ingredient_units")
|
||||||
|
op.drop_index(op.f("ix_group_reports_group_id"), table_name="group_reports")
|
||||||
|
op.drop_index(op.f("ix_group_reports_category"), table_name="group_reports")
|
||||||
|
op.drop_table("group_reports")
|
||||||
|
op.drop_index(op.f("ix_group_preferences_group_id"), table_name="group_preferences")
|
||||||
|
op.drop_table("group_preferences")
|
||||||
|
op.drop_table("group_meal_plan_rules")
|
||||||
|
op.drop_index(op.f("ix_group_events_notifiers_group_id"), table_name="group_events_notifiers")
|
||||||
|
op.drop_table("group_events_notifiers")
|
||||||
|
op.drop_index(op.f("ix_group_data_exports_group_id"), table_name="group_data_exports")
|
||||||
|
op.drop_table("group_data_exports")
|
||||||
|
op.drop_table("cookbooks")
|
||||||
|
op.drop_index(op.f("ix_categories_slug"), table_name="categories")
|
||||||
|
op.drop_index(op.f("ix_categories_name"), table_name="categories")
|
||||||
|
op.drop_index(op.f("ix_categories_group_id"), table_name="categories")
|
||||||
|
op.drop_table("categories")
|
||||||
|
op.drop_index(op.f("ix_groups_name"), table_name="groups")
|
||||||
|
op.drop_table("groups")
|
|
@ -18,7 +18,7 @@ ENV = BASE_DIR.joinpath(".env")
|
||||||
|
|
||||||
dotenv.load_dotenv(ENV)
|
dotenv.load_dotenv(ENV)
|
||||||
PRODUCTION = os.getenv("PRODUCTION", "True").lower() in ["true", "1"]
|
PRODUCTION = os.getenv("PRODUCTION", "True").lower() in ["true", "1"]
|
||||||
TESTING = os.getenv("TESTING", "True").lower() in ["true", "1"]
|
TESTING = os.getenv("TESTING", "False").lower() in ["true", "1"]
|
||||||
|
|
||||||
|
|
||||||
def determine_data_dir() -> Path:
|
def determine_data_dir() -> Path:
|
||||||
|
|
|
@ -1,7 +1,13 @@
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
from sqlalchemy import engine
|
||||||
|
|
||||||
|
from alembic import command, config, script
|
||||||
|
from alembic.config import Config
|
||||||
|
from alembic.runtime import migration
|
||||||
from mealie.core import root_logger
|
from mealie.core import root_logger
|
||||||
from mealie.core.config import get_app_settings
|
from mealie.core.config import get_app_settings
|
||||||
from mealie.db.db_setup import create_session, engine
|
from mealie.db.db_setup import create_session
|
||||||
from mealie.db.models._model_base import SqlAlchemyBase
|
|
||||||
from mealie.repos.all_repositories import get_repositories
|
from mealie.repos.all_repositories import get_repositories
|
||||||
from mealie.repos.repository_factory import AllRepositories
|
from mealie.repos.repository_factory import AllRepositories
|
||||||
from mealie.repos.seed.init_users import default_user_init
|
from mealie.repos.seed.init_users import default_user_init
|
||||||
|
@ -9,15 +15,11 @@ from mealie.repos.seed.seeders import IngredientFoodsSeeder, IngredientUnitsSeed
|
||||||
from mealie.schema.user.user import GroupBase
|
from mealie.schema.user.user import GroupBase
|
||||||
from mealie.services.group_services.group_utils import create_new_group
|
from mealie.services.group_services.group_utils import create_new_group
|
||||||
|
|
||||||
|
PROJECT_DIR = Path(__file__).parent.parent.parent
|
||||||
|
|
||||||
logger = root_logger.get_logger("init_db")
|
logger = root_logger.get_logger("init_db")
|
||||||
|
|
||||||
|
|
||||||
def create_all_models():
|
|
||||||
import mealie.db.models._all_models # noqa: F401
|
|
||||||
|
|
||||||
SqlAlchemyBase.metadata.create_all(engine)
|
|
||||||
|
|
||||||
|
|
||||||
def init_db(db: AllRepositories) -> None:
|
def init_db(db: AllRepositories) -> None:
|
||||||
# TODO: Port other seed data to use abstract seeder class
|
# TODO: Port other seed data to use abstract seeder class
|
||||||
default_group_init(db)
|
default_group_init(db)
|
||||||
|
@ -42,24 +44,33 @@ def default_group_init(db: AllRepositories):
|
||||||
create_new_group(db, GroupBase(name=settings.DEFAULT_GROUP))
|
create_new_group(db, GroupBase(name=settings.DEFAULT_GROUP))
|
||||||
|
|
||||||
|
|
||||||
|
# Adapted from https://alembic.sqlalchemy.org/en/latest/cookbook.html#test-current-database-revision-is-at-head-s
|
||||||
|
def db_is_at_head(alembic_cfg: config.Config) -> bool:
|
||||||
|
settings = get_app_settings()
|
||||||
|
url = settings.DB_URL
|
||||||
|
connectable = engine.create_engine(url)
|
||||||
|
directory = script.ScriptDirectory.from_config(alembic_cfg)
|
||||||
|
with connectable.begin() as connection:
|
||||||
|
context = migration.MigrationContext.configure(connection)
|
||||||
|
return set(context.get_current_heads()) == set(directory.get_heads())
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
create_all_models()
|
alembic_cfg = Config(str(PROJECT_DIR / "alembic.ini"))
|
||||||
|
if db_is_at_head(alembic_cfg):
|
||||||
|
logger.info("Migration not needed.")
|
||||||
|
else:
|
||||||
|
logger.info("Migration needed. Performing migration...")
|
||||||
|
command.upgrade(alembic_cfg, "head")
|
||||||
|
|
||||||
session = create_session()
|
session = create_session()
|
||||||
db = get_repositories(session)
|
db = get_repositories(session)
|
||||||
|
|
||||||
try:
|
init_user = db.users.get_all()
|
||||||
init_user = db.users.get_all()
|
|
||||||
if not init_user:
|
|
||||||
raise Exception("No users found in database")
|
|
||||||
except Exception:
|
|
||||||
init_db(db)
|
|
||||||
return
|
|
||||||
|
|
||||||
if init_user:
|
if init_user:
|
||||||
logger.info("Database Exists")
|
logger.info("Database exists")
|
||||||
else:
|
else:
|
||||||
logger.info("Database Doesn't Exists, Initializing...")
|
logger.info("Database contains no users, initializing...")
|
||||||
init_db(db)
|
init_db(db)
|
||||||
|
|
||||||
|
|
||||||
|
|
1
mealie/db/migration_types.py
Normal file
1
mealie/db/migration_types.py
Normal file
|
@ -0,0 +1 @@
|
||||||
|
from mealie.db.models._model_utils.guid import GUID # noqa: F401
|
|
@ -10,10 +10,11 @@ from mealie.db.models._model_utils.guid import GUID
|
||||||
|
|
||||||
from .._model_base import BaseMixins, SqlAlchemyBase
|
from .._model_base import BaseMixins, SqlAlchemyBase
|
||||||
from .._model_utils import auto_init
|
from .._model_utils import auto_init
|
||||||
from ..users import users_to_favorites
|
from ..users.user_to_favorite import users_to_favorites
|
||||||
from .api_extras import ApiExtras
|
from .api_extras import ApiExtras
|
||||||
from .assets import RecipeAsset
|
from .assets import RecipeAsset
|
||||||
from .category import recipes_to_categories
|
from .category import recipes_to_categories
|
||||||
|
from .comment import RecipeComment
|
||||||
from .ingredient import RecipeIngredient
|
from .ingredient import RecipeIngredient
|
||||||
from .instruction import RecipeInstruction
|
from .instruction import RecipeInstruction
|
||||||
from .note import Note
|
from .note import Note
|
||||||
|
@ -50,7 +51,7 @@ class RecipeModel(SqlAlchemyBase, BaseMixins):
|
||||||
group_id = sa.Column(GUID, sa.ForeignKey("groups.id"), nullable=False, index=True)
|
group_id = sa.Column(GUID, sa.ForeignKey("groups.id"), nullable=False, index=True)
|
||||||
group = orm.relationship("Group", back_populates="recipes", foreign_keys=[group_id])
|
group = orm.relationship("Group", back_populates="recipes", foreign_keys=[group_id])
|
||||||
|
|
||||||
user_id = sa.Column(GUID, sa.ForeignKey("users.id"), index=True)
|
user_id = sa.Column(GUID, sa.ForeignKey("users.id", use_alter=True), index=True)
|
||||||
user = orm.relationship("User", uselist=False, foreign_keys=[user_id])
|
user = orm.relationship("User", uselist=False, foreign_keys=[user_id])
|
||||||
|
|
||||||
meal_entries = orm.relationship("GroupMealPlan", back_populates="recipe", cascade="all, delete-orphan")
|
meal_entries = orm.relationship("GroupMealPlan", back_populates="recipe", cascade="all, delete-orphan")
|
||||||
|
@ -93,7 +94,9 @@ class RecipeModel(SqlAlchemyBase, BaseMixins):
|
||||||
RecipeShareTokenModel, back_populates="recipe", cascade="all, delete, delete-orphan"
|
RecipeShareTokenModel, back_populates="recipe", cascade="all, delete, delete-orphan"
|
||||||
)
|
)
|
||||||
|
|
||||||
comments: list = orm.relationship("RecipeComment", back_populates="recipe", cascade="all, delete, delete-orphan")
|
comments: list[RecipeComment] = orm.relationship(
|
||||||
|
"RecipeComment", back_populates="recipe", cascade="all, delete, delete-orphan"
|
||||||
|
)
|
||||||
|
|
||||||
# Mealie Specific
|
# Mealie Specific
|
||||||
settings = orm.relationship("RecipeSettings", uselist=False, cascade="all, delete-orphan")
|
settings = orm.relationship("RecipeSettings", uselist=False, cascade="all, delete-orphan")
|
||||||
|
|
|
@ -5,7 +5,6 @@ from mealie.db.models._model_utils.guid import GUID
|
||||||
|
|
||||||
from .._model_base import BaseMixins, SqlAlchemyBase
|
from .._model_base import BaseMixins, SqlAlchemyBase
|
||||||
from .._model_utils import auto_init
|
from .._model_utils import auto_init
|
||||||
from ..group import Group
|
|
||||||
from .user_to_favorite import users_to_favorites
|
from .user_to_favorite import users_to_favorites
|
||||||
|
|
||||||
|
|
||||||
|
@ -74,6 +73,8 @@ class User(SqlAlchemyBase, BaseMixins):
|
||||||
settings = get_app_settings()
|
settings = get_app_settings()
|
||||||
group = settings.DEFAULT_GROUP
|
group = settings.DEFAULT_GROUP
|
||||||
|
|
||||||
|
from mealie.db.models.group import Group
|
||||||
|
|
||||||
self.group = Group.get_ref(session, group)
|
self.group = Group.get_ref(session, group)
|
||||||
|
|
||||||
self.favorite_recipes = []
|
self.favorite_recipes = []
|
||||||
|
@ -91,6 +92,8 @@ class User(SqlAlchemyBase, BaseMixins):
|
||||||
self.full_name = full_name
|
self.full_name = full_name
|
||||||
self.email = email
|
self.email = email
|
||||||
|
|
||||||
|
from mealie.db.models.group import Group
|
||||||
|
|
||||||
self.group = Group.get_ref(session, group)
|
self.group = Group.get_ref(session, group)
|
||||||
|
|
||||||
if self.username is None:
|
if self.username is None:
|
||||||
|
|
45
poetry.lock
generated
45
poetry.lock
generated
|
@ -6,6 +6,21 @@ category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = "*"
|
python-versions = "*"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "alembic"
|
||||||
|
version = "1.7.5"
|
||||||
|
description = "A database migration tool for SQLAlchemy."
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.6"
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
Mako = "*"
|
||||||
|
SQLAlchemy = ">=1.3.0"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
tz = ["python-dateutil"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "aniso8601"
|
name = "aniso8601"
|
||||||
version = "7.0.0"
|
version = "7.0.0"
|
||||||
|
@ -585,6 +600,21 @@ html5 = ["html5lib"]
|
||||||
htmlsoup = ["beautifulsoup4"]
|
htmlsoup = ["beautifulsoup4"]
|
||||||
source = ["Cython (>=0.29.7)"]
|
source = ["Cython (>=0.29.7)"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "mako"
|
||||||
|
version = "1.1.6"
|
||||||
|
description = "A super-fast templating language that borrows the best ideas from the existing templating languages."
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
MarkupSafe = ">=0.9.2"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
babel = ["babel"]
|
||||||
|
lingua = ["lingua"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "markdown"
|
name = "markdown"
|
||||||
version = "3.3.6"
|
version = "3.3.6"
|
||||||
|
@ -1458,13 +1488,17 @@ pgsql = ["psycopg2-binary"]
|
||||||
[metadata]
|
[metadata]
|
||||||
lock-version = "1.1"
|
lock-version = "1.1"
|
||||||
python-versions = "^3.10"
|
python-versions = "^3.10"
|
||||||
content-hash = "869d87ae4fb7dff15f0b53dddde737ce8a6c2b13217d6690f4e2b90d3198a18c"
|
content-hash = "94bda5d85d0fd3f5fb0c3ce59ff7cf515eaa3210c4533862e1c8bd22eecec8dd"
|
||||||
|
|
||||||
[metadata.files]
|
[metadata.files]
|
||||||
aiofiles = [
|
aiofiles = [
|
||||||
{file = "aiofiles-0.5.0-py3-none-any.whl", hash = "sha256:377fdf7815cc611870c59cbd07b68b180841d2a2b79812d8c218be02448c2acb"},
|
{file = "aiofiles-0.5.0-py3-none-any.whl", hash = "sha256:377fdf7815cc611870c59cbd07b68b180841d2a2b79812d8c218be02448c2acb"},
|
||||||
{file = "aiofiles-0.5.0.tar.gz", hash = "sha256:98e6bcfd1b50f97db4980e182ddd509b7cc35909e903a8fe50d8849e02d815af"},
|
{file = "aiofiles-0.5.0.tar.gz", hash = "sha256:98e6bcfd1b50f97db4980e182ddd509b7cc35909e903a8fe50d8849e02d815af"},
|
||||||
]
|
]
|
||||||
|
alembic = [
|
||||||
|
{file = "alembic-1.7.5-py3-none-any.whl", hash = "sha256:a9dde941534e3d7573d9644e8ea62a2953541e27bc1793e166f60b777ae098b4"},
|
||||||
|
{file = "alembic-1.7.5.tar.gz", hash = "sha256:7c328694a2e68f03ee971e63c3bd885846470373a5b532cf2c9f1601c413b153"},
|
||||||
|
]
|
||||||
aniso8601 = [
|
aniso8601 = [
|
||||||
{file = "aniso8601-7.0.0-py2.py3-none-any.whl", hash = "sha256:d10a4bf949f619f719b227ef5386e31f49a2b6d453004b21f02661ccc8670c7b"},
|
{file = "aniso8601-7.0.0-py2.py3-none-any.whl", hash = "sha256:d10a4bf949f619f719b227ef5386e31f49a2b6d453004b21f02661ccc8670c7b"},
|
||||||
{file = "aniso8601-7.0.0.tar.gz", hash = "sha256:513d2b6637b7853806ae79ffaca6f3e8754bdd547048f5ccc1420aec4b714f1e"},
|
{file = "aniso8601-7.0.0.tar.gz", hash = "sha256:513d2b6637b7853806ae79ffaca6f3e8754bdd547048f5ccc1420aec4b714f1e"},
|
||||||
|
@ -1703,6 +1737,7 @@ greenlet = [
|
||||||
{file = "greenlet-1.1.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:97e5306482182170ade15c4b0d8386ded995a07d7cc2ca8f27958d34d6736497"},
|
{file = "greenlet-1.1.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:97e5306482182170ade15c4b0d8386ded995a07d7cc2ca8f27958d34d6736497"},
|
||||||
{file = "greenlet-1.1.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e6a36bb9474218c7a5b27ae476035497a6990e21d04c279884eb10d9b290f1b1"},
|
{file = "greenlet-1.1.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e6a36bb9474218c7a5b27ae476035497a6990e21d04c279884eb10d9b290f1b1"},
|
||||||
{file = "greenlet-1.1.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:abb7a75ed8b968f3061327c433a0fbd17b729947b400747c334a9c29a9af6c58"},
|
{file = "greenlet-1.1.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:abb7a75ed8b968f3061327c433a0fbd17b729947b400747c334a9c29a9af6c58"},
|
||||||
|
{file = "greenlet-1.1.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b336501a05e13b616ef81ce329c0e09ac5ed8c732d9ba7e3e983fcc1a9e86965"},
|
||||||
{file = "greenlet-1.1.2-cp310-cp310-win_amd64.whl", hash = "sha256:14d4f3cd4e8b524ae9b8aa567858beed70c392fdec26dbdb0a8a418392e71708"},
|
{file = "greenlet-1.1.2-cp310-cp310-win_amd64.whl", hash = "sha256:14d4f3cd4e8b524ae9b8aa567858beed70c392fdec26dbdb0a8a418392e71708"},
|
||||||
{file = "greenlet-1.1.2-cp35-cp35m-macosx_10_14_x86_64.whl", hash = "sha256:17ff94e7a83aa8671a25bf5b59326ec26da379ace2ebc4411d690d80a7fbcf23"},
|
{file = "greenlet-1.1.2-cp35-cp35m-macosx_10_14_x86_64.whl", hash = "sha256:17ff94e7a83aa8671a25bf5b59326ec26da379ace2ebc4411d690d80a7fbcf23"},
|
||||||
{file = "greenlet-1.1.2-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:9f3cba480d3deb69f6ee2c1825060177a22c7826431458c697df88e6aeb3caee"},
|
{file = "greenlet-1.1.2-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:9f3cba480d3deb69f6ee2c1825060177a22c7826431458c697df88e6aeb3caee"},
|
||||||
|
@ -1715,6 +1750,7 @@ greenlet = [
|
||||||
{file = "greenlet-1.1.2-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f9d29ca8a77117315101425ec7ec2a47a22ccf59f5593378fc4077ac5b754fce"},
|
{file = "greenlet-1.1.2-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f9d29ca8a77117315101425ec7ec2a47a22ccf59f5593378fc4077ac5b754fce"},
|
||||||
{file = "greenlet-1.1.2-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:21915eb821a6b3d9d8eefdaf57d6c345b970ad722f856cd71739493ce003ad08"},
|
{file = "greenlet-1.1.2-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:21915eb821a6b3d9d8eefdaf57d6c345b970ad722f856cd71739493ce003ad08"},
|
||||||
{file = "greenlet-1.1.2-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eff9d20417ff9dcb0d25e2defc2574d10b491bf2e693b4e491914738b7908168"},
|
{file = "greenlet-1.1.2-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eff9d20417ff9dcb0d25e2defc2574d10b491bf2e693b4e491914738b7908168"},
|
||||||
|
{file = "greenlet-1.1.2-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:b8c008de9d0daba7b6666aa5bbfdc23dcd78cafc33997c9b7741ff6353bafb7f"},
|
||||||
{file = "greenlet-1.1.2-cp36-cp36m-win32.whl", hash = "sha256:32ca72bbc673adbcfecb935bb3fb1b74e663d10a4b241aaa2f5a75fe1d1f90aa"},
|
{file = "greenlet-1.1.2-cp36-cp36m-win32.whl", hash = "sha256:32ca72bbc673adbcfecb935bb3fb1b74e663d10a4b241aaa2f5a75fe1d1f90aa"},
|
||||||
{file = "greenlet-1.1.2-cp36-cp36m-win_amd64.whl", hash = "sha256:f0214eb2a23b85528310dad848ad2ac58e735612929c8072f6093f3585fd342d"},
|
{file = "greenlet-1.1.2-cp36-cp36m-win_amd64.whl", hash = "sha256:f0214eb2a23b85528310dad848ad2ac58e735612929c8072f6093f3585fd342d"},
|
||||||
{file = "greenlet-1.1.2-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:b92e29e58bef6d9cfd340c72b04d74c4b4e9f70c9fa7c78b674d1fec18896dc4"},
|
{file = "greenlet-1.1.2-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:b92e29e58bef6d9cfd340c72b04d74c4b4e9f70c9fa7c78b674d1fec18896dc4"},
|
||||||
|
@ -1723,6 +1759,7 @@ greenlet = [
|
||||||
{file = "greenlet-1.1.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1e12bdc622676ce47ae9abbf455c189e442afdde8818d9da983085df6312e7a1"},
|
{file = "greenlet-1.1.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1e12bdc622676ce47ae9abbf455c189e442afdde8818d9da983085df6312e7a1"},
|
||||||
{file = "greenlet-1.1.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8c790abda465726cfb8bb08bd4ca9a5d0a7bd77c7ac1ca1b839ad823b948ea28"},
|
{file = "greenlet-1.1.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8c790abda465726cfb8bb08bd4ca9a5d0a7bd77c7ac1ca1b839ad823b948ea28"},
|
||||||
{file = "greenlet-1.1.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f276df9830dba7a333544bd41070e8175762a7ac20350786b322b714b0e654f5"},
|
{file = "greenlet-1.1.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f276df9830dba7a333544bd41070e8175762a7ac20350786b322b714b0e654f5"},
|
||||||
|
{file = "greenlet-1.1.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:8c5d5b35f789a030ebb95bff352f1d27a93d81069f2adb3182d99882e095cefe"},
|
||||||
{file = "greenlet-1.1.2-cp37-cp37m-win32.whl", hash = "sha256:64e6175c2e53195278d7388c454e0b30997573f3f4bd63697f88d855f7a6a1fc"},
|
{file = "greenlet-1.1.2-cp37-cp37m-win32.whl", hash = "sha256:64e6175c2e53195278d7388c454e0b30997573f3f4bd63697f88d855f7a6a1fc"},
|
||||||
{file = "greenlet-1.1.2-cp37-cp37m-win_amd64.whl", hash = "sha256:b11548073a2213d950c3f671aa88e6f83cda6e2fb97a8b6317b1b5b33d850e06"},
|
{file = "greenlet-1.1.2-cp37-cp37m-win_amd64.whl", hash = "sha256:b11548073a2213d950c3f671aa88e6f83cda6e2fb97a8b6317b1b5b33d850e06"},
|
||||||
{file = "greenlet-1.1.2-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:9633b3034d3d901f0a46b7939f8c4d64427dfba6bbc5a36b1a67364cf148a1b0"},
|
{file = "greenlet-1.1.2-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:9633b3034d3d901f0a46b7939f8c4d64427dfba6bbc5a36b1a67364cf148a1b0"},
|
||||||
|
@ -1731,6 +1768,7 @@ greenlet = [
|
||||||
{file = "greenlet-1.1.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e859fcb4cbe93504ea18008d1df98dee4f7766db66c435e4882ab35cf70cac43"},
|
{file = "greenlet-1.1.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e859fcb4cbe93504ea18008d1df98dee4f7766db66c435e4882ab35cf70cac43"},
|
||||||
{file = "greenlet-1.1.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:00e44c8afdbe5467e4f7b5851be223be68adb4272f44696ee71fe46b7036a711"},
|
{file = "greenlet-1.1.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:00e44c8afdbe5467e4f7b5851be223be68adb4272f44696ee71fe46b7036a711"},
|
||||||
{file = "greenlet-1.1.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec8c433b3ab0419100bd45b47c9c8551248a5aee30ca5e9d399a0b57ac04651b"},
|
{file = "greenlet-1.1.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec8c433b3ab0419100bd45b47c9c8551248a5aee30ca5e9d399a0b57ac04651b"},
|
||||||
|
{file = "greenlet-1.1.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:2bde6792f313f4e918caabc46532aa64aa27a0db05d75b20edfc5c6f46479de2"},
|
||||||
{file = "greenlet-1.1.2-cp38-cp38-win32.whl", hash = "sha256:288c6a76705dc54fba69fbcb59904ae4ad768b4c768839b8ca5fdadec6dd8cfd"},
|
{file = "greenlet-1.1.2-cp38-cp38-win32.whl", hash = "sha256:288c6a76705dc54fba69fbcb59904ae4ad768b4c768839b8ca5fdadec6dd8cfd"},
|
||||||
{file = "greenlet-1.1.2-cp38-cp38-win_amd64.whl", hash = "sha256:8d2f1fb53a421b410751887eb4ff21386d119ef9cde3797bf5e7ed49fb51a3b3"},
|
{file = "greenlet-1.1.2-cp38-cp38-win_amd64.whl", hash = "sha256:8d2f1fb53a421b410751887eb4ff21386d119ef9cde3797bf5e7ed49fb51a3b3"},
|
||||||
{file = "greenlet-1.1.2-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:166eac03e48784a6a6e0e5f041cfebb1ab400b394db188c48b3a84737f505b67"},
|
{file = "greenlet-1.1.2-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:166eac03e48784a6a6e0e5f041cfebb1ab400b394db188c48b3a84737f505b67"},
|
||||||
|
@ -1739,6 +1777,7 @@ greenlet = [
|
||||||
{file = "greenlet-1.1.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b1692f7d6bc45e3200844be0dba153612103db241691088626a33ff1f24a0d88"},
|
{file = "greenlet-1.1.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b1692f7d6bc45e3200844be0dba153612103db241691088626a33ff1f24a0d88"},
|
||||||
{file = "greenlet-1.1.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7227b47e73dedaa513cdebb98469705ef0d66eb5a1250144468e9c3097d6b59b"},
|
{file = "greenlet-1.1.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7227b47e73dedaa513cdebb98469705ef0d66eb5a1250144468e9c3097d6b59b"},
|
||||||
{file = "greenlet-1.1.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7ff61ff178250f9bb3cd89752df0f1dd0e27316a8bd1465351652b1b4a4cdfd3"},
|
{file = "greenlet-1.1.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7ff61ff178250f9bb3cd89752df0f1dd0e27316a8bd1465351652b1b4a4cdfd3"},
|
||||||
|
{file = "greenlet-1.1.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:0051c6f1f27cb756ffc0ffbac7d2cd48cb0362ac1736871399a739b2885134d3"},
|
||||||
{file = "greenlet-1.1.2-cp39-cp39-win32.whl", hash = "sha256:f70a9e237bb792c7cc7e44c531fd48f5897961701cdaa06cf22fc14965c496cf"},
|
{file = "greenlet-1.1.2-cp39-cp39-win32.whl", hash = "sha256:f70a9e237bb792c7cc7e44c531fd48f5897961701cdaa06cf22fc14965c496cf"},
|
||||||
{file = "greenlet-1.1.2-cp39-cp39-win_amd64.whl", hash = "sha256:013d61294b6cd8fe3242932c1c5e36e5d1db2c8afb58606c5a67efce62c1f5fd"},
|
{file = "greenlet-1.1.2-cp39-cp39-win_amd64.whl", hash = "sha256:013d61294b6cd8fe3242932c1c5e36e5d1db2c8afb58606c5a67efce62c1f5fd"},
|
||||||
{file = "greenlet-1.1.2.tar.gz", hash = "sha256:e30f5ea4ae2346e62cedde8794a56858a67b878dd79f7df76a0767e356b1744a"},
|
{file = "greenlet-1.1.2.tar.gz", hash = "sha256:e30f5ea4ae2346e62cedde8794a56858a67b878dd79f7df76a0767e356b1744a"},
|
||||||
|
@ -1904,6 +1943,10 @@ lxml = [
|
||||||
{file = "lxml-4.7.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:447d5009d6b5447b2f237395d0018901dcc673f7d9f82ba26c1b9f9c3b444b60"},
|
{file = "lxml-4.7.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:447d5009d6b5447b2f237395d0018901dcc673f7d9f82ba26c1b9f9c3b444b60"},
|
||||||
{file = "lxml-4.7.1.tar.gz", hash = "sha256:a1613838aa6b89af4ba10a0f3a972836128801ed008078f8c1244e65958f1b24"},
|
{file = "lxml-4.7.1.tar.gz", hash = "sha256:a1613838aa6b89af4ba10a0f3a972836128801ed008078f8c1244e65958f1b24"},
|
||||||
]
|
]
|
||||||
|
mako = [
|
||||||
|
{file = "Mako-1.1.6-py2.py3-none-any.whl", hash = "sha256:afaf8e515d075b22fad7d7b8b30e4a1c90624ff2f3733a06ec125f5a5f043a57"},
|
||||||
|
{file = "Mako-1.1.6.tar.gz", hash = "sha256:4e9e345a41924a954251b95b4b28e14a301145b544901332e658907a7464b6b2"},
|
||||||
|
]
|
||||||
markdown = [
|
markdown = [
|
||||||
{file = "Markdown-3.3.6-py3-none-any.whl", hash = "sha256:9923332318f843411e9932237530df53162e29dc7a4e2b91e35764583c46c9a3"},
|
{file = "Markdown-3.3.6-py3-none-any.whl", hash = "sha256:9923332318f843411e9932237530df53162e29dc7a4e2b91e35764583c46c9a3"},
|
||||||
{file = "Markdown-3.3.6.tar.gz", hash = "sha256:76df8ae32294ec39dcf89340382882dfa12975f87f45c3ed1ecdb1e8cefc7006"},
|
{file = "Markdown-3.3.6.tar.gz", hash = "sha256:76df8ae32294ec39dcf89340382882dfa12975f87f45c3ed1ecdb1e8cefc7006"},
|
||||||
|
|
|
@ -17,6 +17,7 @@ fastapi = "^0.71.0"
|
||||||
uvicorn = {extras = ["standard"], version = "^0.13.0"}
|
uvicorn = {extras = ["standard"], version = "^0.13.0"}
|
||||||
APScheduler = "^3.8.1"
|
APScheduler = "^3.8.1"
|
||||||
SQLAlchemy = "^1.4.29"
|
SQLAlchemy = "^1.4.29"
|
||||||
|
alembic = "^1.7.5"
|
||||||
Jinja2 = "^2.11.2"
|
Jinja2 = "^2.11.2"
|
||||||
python-dotenv = "^0.15.0"
|
python-dotenv = "^0.15.0"
|
||||||
python-slugify = "^4.0.1"
|
python-slugify = "^4.0.1"
|
||||||
|
|
14
tests/unit_tests/test_alembic.py
Normal file
14
tests/unit_tests/test_alembic.py
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
# Test that alembic revisions are applicable and result in the current database
|
||||||
|
# See https://github.com/sqlalchemy/alembic/issues/724 for inspiration
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.skip("TODO: Implement")
|
||||||
|
def test_alembic_revisions_are_applicable():
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.skip("TODO: Implement")
|
||||||
|
def test_alembic_revisions_are_up_to_date():
|
||||||
|
pass
|
Loading…
Reference in a new issue