From 2caa9f91faaa9bf7826a5e5df6bc8e4cdac48d1b Mon Sep 17 00:00:00 2001 From: Nargis Sultani Date: Wed, 22 Nov 2023 02:22:26 -0500 Subject: [PATCH] Ticckt 45, running almebic on startup --- alembic.ini | 2 +- db_revisions/env.py | 102 ------------------ db_revisions/utils.py | 11 -- {db_revisions => src/db_revisions}/README | 0 src/db_revisions/__init__.py | 20 ++++ src/db_revisions/env.py | 49 +++++++++ .../db_revisions}/script.py.mako | 0 src/db_revisions/utils.py | 41 +++++++ ...9_create_financial_institution_domains_.py | 0 ...98b11074c54_create_denied_domains_table.py | 0 ...93f_create_financial_institutions_table.py | 0 src/main.py | 7 ++ 12 files changed, 118 insertions(+), 114 deletions(-) delete mode 100644 db_revisions/env.py delete mode 100644 db_revisions/utils.py rename {db_revisions => src/db_revisions}/README (100%) create mode 100644 src/db_revisions/__init__.py create mode 100644 src/db_revisions/env.py rename {db_revisions => src/db_revisions}/script.py.mako (100%) create mode 100644 src/db_revisions/utils.py rename {db_revisions => src/db_revisions}/versions/20e0d51d8be9_create_financial_institution_domains_.py (100%) rename {db_revisions => src/db_revisions}/versions/a98b11074c54_create_denied_domains_table.py (100%) rename {db_revisions => src/db_revisions}/versions/f76c5004993f_create_financial_institutions_table.py (100%) diff --git a/alembic.ini b/alembic.ini index d00656c..dc22590 100644 --- a/alembic.ini +++ b/alembic.ini @@ -2,7 +2,7 @@ [alembic] # path to migration scripts -script_location = ./db_revisions +script_location = ./src/db_revisions # template used to generate migration file names; The default value is %%(rev)s_%%(slug)s # Uncomment the line below if you want the files to be prepended with date and time diff --git a/db_revisions/env.py b/db_revisions/env.py deleted file mode 100644 index 1a14900..0000000 --- a/db_revisions/env.py +++ /dev/null @@ -1,102 +0,0 @@ -import os -from dotenv import load_dotenv -from logging.config import fileConfig -from sqlalchemy import engine_from_config, pool -from alembic import context -from entities.models import Base - -# this is the Alembic Config object, which provides -# access to the values within the .ini file in use. -config = context.config - -# Interpret the config file for Python logging. -# This line sets up loggers basically. -if config.config_file_name is not None: - fileConfig(config.config_file_name) - -# this specific to SBL configuration - -ENV = os.getenv("ENV", "LOCAL") - -if ENV == "LOCAL": - load_dotenv("src/.env.local") -else: - load_dotenv() - -INST_DB_USER = os.environ.get("INST_DB_USER") -INST_DB_PWD = os.environ.get("INST_DB_PWD") -INST_DB_HOST = os.environ.get("INST_DB_HOST") -INST_DB_NAME = os.environ.get("INST_DB_NAME") -INST_DB_SCHEMA = os.environ.get("INST_DB_SCHEMA") -INST_CONN = f"postgresql://{INST_DB_USER}:{INST_DB_PWD}@{INST_DB_HOST}/{INST_DB_NAME}" -config.set_main_option("sqlalchemy.url", INST_CONN) - -# end specific SBL configuration - -# add your model's MetaData object here -# for 'autogenerate' support -# from myapp import mymodel - -target_metadata = Base.metadata -target_metadata.schema = INST_DB_SCHEMA - -# 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. - - -def run_migrations_offline() -> None: - """Run migrations in 'offline' mode. This generates the SQL script without executing on the database. - - 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() -> None: - """Run migrations in 'online' mode. - - In this scenario we need to create an Engine - and associate a connection with the context. - - """ - - connectable = context.config.attributes.get("connection", None) - - if connectable is None: - connectable = engine_from_config( - context.config.get_section(context.config.config_ini_section), - prefix="sqlalchemy.", - poolclass=pool.NullPool, - ) - - with connectable.connect() as connection: - context.configure( - connection=connection, target_metadata=target_metadata, version_table_schema=target_metadata.schema - ) - - with context.begin_transaction(): - context.run_migrations() - - -if context.is_offline_mode(): - run_migrations_offline() -else: - run_migrations_online() diff --git a/db_revisions/utils.py b/db_revisions/utils.py deleted file mode 100644 index a8c9d57..0000000 --- a/db_revisions/utils.py +++ /dev/null @@ -1,11 +0,0 @@ -from alembic import op -from sqlalchemy import engine_from_config -from sqlalchemy.engine import reflection - - -def table_exists(table_name): - config = op.get_context().config - engine = engine_from_config(config.get_section(config.config_ini_section), prefix="sqlalchemy.") - inspector = reflection.Inspector.from_engine(engine) - tables = inspector.get_table_names() - return table_name in tables diff --git a/db_revisions/README b/src/db_revisions/README similarity index 100% rename from db_revisions/README rename to src/db_revisions/README diff --git a/src/db_revisions/__init__.py b/src/db_revisions/__init__.py new file mode 100644 index 0000000..86b4b91 --- /dev/null +++ b/src/db_revisions/__init__.py @@ -0,0 +1,20 @@ +import os +import logging +from alembic import command as alembic +from alembic.config import Config +from .utils import INST_DB_URL, basedir + +log = logging.getLogger() + + +def get_alembic_config(db_url: str = INST_DB_URL) -> Config: + alembic_dir = os.path.join(basedir, "db_revisions") + alembic_cfg = Config() + alembic_cfg.set_main_option("script_location", alembic_dir) + alembic_cfg.set_main_option("sqlalchemy.url", str(db_url)) + return alembic_cfg + + +def upgrade_database(revision: str = "head", db_url: str = INST_DB_URL) -> None: + alembic_cfg = get_alembic_config(db_url) + alembic.upgrade(alembic_cfg, revision) diff --git a/src/db_revisions/env.py b/src/db_revisions/env.py new file mode 100644 index 0000000..8add18b --- /dev/null +++ b/src/db_revisions/env.py @@ -0,0 +1,49 @@ +from sqlalchemy import engine_from_config, pool +from logging.config import fileConfig +from alembic import context +from entities.models import Base +from db_revisions.utils import INST_DB_URL, INST_DB_SCHEMA + +# this is the Alembic Config object, which provides +# access to the values within the .ini file in use. +config = context.config +config.set_main_option("sqlalchemy.url", INST_DB_URL) +# add your model's MetaData object here +# for 'autogenerate' support +target_metadata = Base.metadata +target_metadata.schema = INST_DB_SCHEMA + +# Interpret the config file for Python logging. +# This line sets up loggers basically. +if config.config_file_name is not None: + fileConfig(config.config_file_name) + + +def run_migrations_offline(): + 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(): + configuration = config.get_section(config.config_ini_section) + connectable = engine_from_config( + configuration, + prefix="sqlalchemy.", + poolclass=pool.NullPool, + ) + with connectable.connect() as connection: + context.configure( + connection=connection, target_metadata=target_metadata, version_table_schema=target_metadata.schema + ) + with context.begin_transaction(): + context.run_migrations() + + +if context.is_offline_mode(): + run_migrations_offline() +else: + run_migrations_online() diff --git a/db_revisions/script.py.mako b/src/db_revisions/script.py.mako similarity index 100% rename from db_revisions/script.py.mako rename to src/db_revisions/script.py.mako diff --git a/src/db_revisions/utils.py b/src/db_revisions/utils.py new file mode 100644 index 0000000..b1c9ee2 --- /dev/null +++ b/src/db_revisions/utils.py @@ -0,0 +1,41 @@ +import os +import sys +from dotenv import load_dotenv +from alembic import op +from sqlalchemy import engine_from_config +from sqlalchemy.engine import reflection + +if getattr(sys, "frozen", False): + # we are running in a bundle + basedir = sys._MEIPast +else: + # we are running in a normal Python environment + basedir = os.path.abspath(os.path.join(os.path.dirname(__file__), "..")) + sys.path.append(basedir) + +# this specific to SBL configuration +env_file = os.path.join(basedir, ".env.local") + +ENV = os.getenv("ENV", "LOCAL") + +if ENV == "LOCAL": + load_dotenv(env_file) +else: + load_dotenv() + +INST_DB_USER = os.environ.get("INST_DB_USER") +INST_DB_PWD = os.environ.get("INST_DB_PWD") +INST_DB_HOST = os.environ.get("INST_DB_HOST") +INST_DB_NAME = os.environ.get("INST_DB_NAME") +INST_DB_SCHEMA = os.environ.get("INST_DB_SCHEMA") +INST_DB_PATH = f"{INST_DB_USER}:{INST_DB_PWD}@{INST_DB_HOST}/{INST_DB_NAME}" +INST_DB_URL = f"postgresql://{INST_DB_USER}:{INST_DB_PWD}@{INST_DB_HOST}/{INST_DB_NAME}" +# end specific SBL configuration + + +def table_exists(table_name): + config = op.get_context().config + engine = engine_from_config(config.get_section(config.config_ini_section), prefix="sqlalchemy.") + inspector = reflection.Inspector.from_engine(engine) + tables = inspector.get_table_names() + return table_name in tables diff --git a/db_revisions/versions/20e0d51d8be9_create_financial_institution_domains_.py b/src/db_revisions/versions/20e0d51d8be9_create_financial_institution_domains_.py similarity index 100% rename from db_revisions/versions/20e0d51d8be9_create_financial_institution_domains_.py rename to src/db_revisions/versions/20e0d51d8be9_create_financial_institution_domains_.py diff --git a/db_revisions/versions/a98b11074c54_create_denied_domains_table.py b/src/db_revisions/versions/a98b11074c54_create_denied_domains_table.py similarity index 100% rename from db_revisions/versions/a98b11074c54_create_denied_domains_table.py rename to src/db_revisions/versions/a98b11074c54_create_denied_domains_table.py diff --git a/db_revisions/versions/f76c5004993f_create_financial_institutions_table.py b/src/db_revisions/versions/f76c5004993f_create_financial_institutions_table.py similarity index 100% rename from db_revisions/versions/f76c5004993f_create_financial_institutions_table.py rename to src/db_revisions/versions/f76c5004993f_create_financial_institutions_table.py diff --git a/src/main.py b/src/main.py index 7940eb8..daac3ba 100644 --- a/src/main.py +++ b/src/main.py @@ -12,11 +12,18 @@ from config import settings +from db_revisions import upgrade_database + log = logging.getLogger() app = FastAPI() +@app.on_event("startup") +async def startup() -> None: + upgrade_database() + + @app.exception_handler(HTTPException) async def http_exception_handler(request: Request, exception: HTTPException) -> JSONResponse: log.error(exception, exc_info=True, stack_info=True)