Source code for camcops_server.cc_modules.cc_alembic

#!/usr/bin/env python
# camcops_server/cc_modules/cc_alembic.py

"""
===============================================================================

    Copyright (C) 2012-2018 Rudolf Cardinal (rudolf@pobox.com).

    This file is part of CamCOPS.

    CamCOPS is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    CamCOPS is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with CamCOPS. If not, see <http://www.gnu.org/licenses/>.

===============================================================================

Functions to talk to Alembic; specifically, those functions that may be used
by users/administrators, such as to upgrade a database.

If you're a developer and want to create a new database migration, see instead

    tools/create_database_migration.py

"""

import logging
from typing import TYPE_CHECKING
import os

# from alembic import command
from alembic.config import Config
from cardinal_pythonlib.fileops import preserve_cwd
from cardinal_pythonlib.logs import BraceStyleAdapter
from cardinal_pythonlib.sqlalchemy.alembic_func import (
    # get_current_and_head_revision,
    upgrade_database,
    stamp_allowing_unusual_version_table,
)

from .cc_baseconstants import (
    ALEMBIC_BASE_DIR,
    ALEMBIC_CONFIG_FILENAME,
    ALEMBIC_VERSION_TABLE,
)
from .cc_sqlalchemy import Base

if TYPE_CHECKING:
    from sqlalchemy.sql.schema import MetaData
    from .cc_config import CamcopsConfig

log = BraceStyleAdapter(logging.getLogger(__name__))


def import_all_models():
    # noinspection PyUnresolvedReferences
    import camcops_server.cc_modules.cc_all_models  # delayed import  # import side effects (ensure all models registered)  # noqa


[docs]def upgrade_database_to_head(show_sql_only: bool = False) -> None: """ The primary upgrade method. """ import_all_models() # delayed, for command-line interfaces upgrade_database(alembic_base_dir=ALEMBIC_BASE_DIR, alembic_config_filename=ALEMBIC_CONFIG_FILENAME, version_table=ALEMBIC_VERSION_TABLE, as_sql=show_sql_only)
# ... will get its config information from the OS environment; see # run_alembic() in alembic/env.py @preserve_cwd def create_database_from_scratch(cfg: "CamcopsConfig") -> None: """ Takes the database from nothing to the "head" revision in one step, by bypassing Alembic's revisions and taking the state directly from the SQLAlchemy ORM metadata. See http://alembic.zzzcomputing.com/en/latest/cookbook.html#building-an-up-to-date-database-from-scratch # noqa This ASSUMES that the head revision "frozen" into the latest alembic/version/XXX.py file MATCHES THE STATE OF THE SQLALCHEMY ORM METADATA as judged by Base.metadata. If that's not the case, things will go awry later! (Alembic will think the database is at the state of its "head" revision, but it won't be.) It also ASSUMES (as many things do) that importing .cc_all_models imports all the models (or Base.metadata will be incomplete). """ import_all_models() # delayed, for command-line interfaces log.warning("Performing one-step database creation.") metadata = Base.metadata # type: MetaData engine = cfg.get_sqla_engine() metadata.create_all(engine) alembic_cfg = Config(ALEMBIC_CONFIG_FILENAME) os.chdir(ALEMBIC_BASE_DIR) # command.stamp(alembic_cfg, "head") stamp_allowing_unusual_version_table(alembic_cfg, "head", version_table=ALEMBIC_VERSION_TABLE) log.info("One-step database creation complete.")