Coverage for cc_modules/cc_alembic.py: 45%
40 statements
« prev ^ index » next coverage.py v6.5.0, created at 2022-11-08 23:14 +0000
« prev ^ index » next coverage.py v6.5.0, created at 2022-11-08 23:14 +0000
1#!/usr/bin/env python
3"""
4camcops_server/cc_modules/cc_alembic.py
6===============================================================================
8 Copyright (C) 2012, University of Cambridge, Department of Psychiatry.
9 Created by Rudolf Cardinal (rnc1001@cam.ac.uk).
11 This file is part of CamCOPS.
13 CamCOPS is free software: you can redistribute it and/or modify
14 it under the terms of the GNU General Public License as published by
15 the Free Software Foundation, either version 3 of the License, or
16 (at your option) any later version.
18 CamCOPS is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 GNU General Public License for more details.
23 You should have received a copy of the GNU General Public License
24 along with CamCOPS. If not, see <https://www.gnu.org/licenses/>.
26===============================================================================
28**Functions to talk to Alembic; specifically, those functions that may be used
29by users/administrators, such as to upgrade a database.**
31If you're a developer and want to create a new database migration, see
32``tools/create_database_migration.py`` instead.
34"""
36import logging
37from typing import TYPE_CHECKING
38import os
40from alembic.config import Config
41from cardinal_pythonlib.fileops import preserve_cwd
42from cardinal_pythonlib.logs import BraceStyleAdapter
43from cardinal_pythonlib.sqlalchemy.alembic_func import (
44 downgrade_database,
45 upgrade_database,
46 stamp_allowing_unusual_version_table,
47)
49from camcops_server.cc_modules.cc_baseconstants import (
50 ALEMBIC_BASE_DIR,
51 ALEMBIC_CONFIG_FILENAME,
52 ALEMBIC_VERSION_TABLE,
53)
54from camcops_server.cc_modules.cc_sqlalchemy import Base
56if TYPE_CHECKING:
57 from sqlalchemy.sql.schema import MetaData
58 from camcops_server.cc_modules.cc_config import CamcopsConfig
60log = BraceStyleAdapter(logging.getLogger(__name__))
63def import_all_models():
64 """
65 Imports all SQLAlchemy models. (This has side effects including setting up
66 the SQLAlchemy metadata properly.)
67 """
68 # noinspection PyUnresolvedReferences
69 import camcops_server.cc_modules.cc_all_models # delayed import # import side effects (ensure all models registered) # noqa
72def upgrade_database_to_head(show_sql_only: bool = False) -> None:
73 """
74 The primary upgrade method. Modifies the database structure from where it
75 is, stepwise through revisions, to the head revision.
77 Args:
78 show_sql_only: just show the SQL; don't execute it
79 """
80 upgrade_database_to_revision(revision="head", show_sql_only=show_sql_only)
83def upgrade_database_to_revision(
84 revision: str, show_sql_only: bool = False
85) -> None:
86 """
87 Upgrades the database to a specific revision. Modifies the database
88 structure from where it is, stepwise through revisions, to the specified
89 revision.
91 Args:
92 revision: destination revision
93 show_sql_only: just show the SQL; don't execute it
94 """
95 import_all_models() # delayed, for command-line interfaces
96 upgrade_database(
97 alembic_base_dir=ALEMBIC_BASE_DIR,
98 alembic_config_filename=ALEMBIC_CONFIG_FILENAME,
99 destination_revision=revision,
100 version_table=ALEMBIC_VERSION_TABLE,
101 as_sql=show_sql_only,
102 )
103 # ... will get its config information from the OS environment; see
104 # run_alembic() in alembic/env.py
107def downgrade_database_to_revision(
108 revision: str,
109 show_sql_only: bool = False,
110 confirm_downgrade_db: bool = False,
111) -> None:
112 """
113 Developer option. Takes the database to a specific revision.
115 Args:
116 revision: destination revision
117 show_sql_only: just show the SQL; don't execute it
118 confirm_downgrade_db: has the user confirmed? Necessary for the
119 (destructive) database operation.
120 """
121 if not show_sql_only and not confirm_downgrade_db:
122 log.critical("Destructive action not confirmed! Refusing.")
123 return
124 if show_sql_only:
125 log.warning(
126 "Current Alembic v1.0.0 bug in downgrading with "
127 "as_sql=True; may fail"
128 )
129 import_all_models() # delayed, for command-line interfaces
130 downgrade_database(
131 alembic_base_dir=ALEMBIC_BASE_DIR,
132 alembic_config_filename=ALEMBIC_CONFIG_FILENAME,
133 destination_revision=revision,
134 version_table=ALEMBIC_VERSION_TABLE,
135 as_sql=show_sql_only,
136 )
137 # ... will get its config information from the OS environment; see
138 # run_alembic() in alembic/env.py
141@preserve_cwd
142def create_database_from_scratch(cfg: "CamcopsConfig") -> None:
143 """
144 Takes the database from nothing to the "head" revision in one step, by
145 bypassing Alembic's revisions and taking the state directly from the
146 SQLAlchemy ORM metadata.
148 See
149 https://alembic.zzzcomputing.com/en/latest/cookbook.html#building-an-up-to-date-database-from-scratch
151 This function ASSUMES that the head revision "frozen" into the latest
152 ``alembic/version/XXX.py`` file MATCHES THE STATE OF THE SQLALCHEMY ORM
153 METADATA as judged by ``Base.metadata``. If that's not the case, things
154 will go awry later! (Alembic will think the database is at the state of its
155 "head" revision, but it won't be.)
157 It also ASSUMES (as many things do) that importing ``.cc_all_models``
158 imports all the models (or ``Base.metadata`` will be incomplete).
159 """ # noqa
160 import_all_models() # delayed, for command-line interfaces
162 log.warning("Performing one-step database creation.")
163 metadata = Base.metadata # type: MetaData
164 engine = cfg.get_sqla_engine()
165 metadata.create_all(engine)
167 alembic_cfg = Config(ALEMBIC_CONFIG_FILENAME)
168 os.chdir(ALEMBIC_BASE_DIR)
169 # command.stamp(alembic_cfg, "head")
170 stamp_allowing_unusual_version_table(
171 alembic_cfg, "head", version_table=ALEMBIC_VERSION_TABLE
172 )
173 log.info("One-step database creation complete.")