Skip to content

Commit 320d4b0

Browse files
Merge pull request #29 from RudolfCardinal/improve_alembic_db_url_handling
Improve alembic db url handling + improve merge_db etc.
2 parents 2b5e1f2 + a2f6546 commit 320d4b0

File tree

6 files changed

+461
-163
lines changed

6 files changed

+461
-163
lines changed

cardinal_pythonlib/sqlalchemy/alembic_func.py

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -76,13 +76,15 @@ def get_head_revision_from_alembic(
7676
) -> str:
7777
"""
7878
Ask Alembic what its head revision is (i.e. where the Python code would
79-
like the database to be at).
79+
like the database to be at). This does not read the database.
8080
8181
Arguments:
82-
alembic_config_filename: config filename
83-
alembic_base_dir: directory to start in, so relative paths in the
84-
config file work.
85-
version_table: table name for Alembic versions
82+
alembic_config_filename:
83+
config filename
84+
alembic_base_dir:
85+
directory to start in, so relative paths in the config file work.
86+
version_table:
87+
table name for Alembic versions
8688
"""
8789
if alembic_base_dir is None:
8890
alembic_base_dir = os.path.dirname(alembic_config_filename)
@@ -148,6 +150,7 @@ def get_current_and_head_revision(
148150
@preserve_cwd
149151
def upgrade_database(
150152
alembic_config_filename: str,
153+
db_url: str = None,
151154
alembic_base_dir: str = None,
152155
starting_revision: str = None,
153156
destination_revision: str = "head",
@@ -164,6 +167,9 @@ def upgrade_database(
164167
alembic_config_filename:
165168
config filename
166169
170+
db_url:
171+
Optional database URL to use, by way of override.
172+
167173
alembic_base_dir:
168174
directory to start in, so relative paths in the config file work
169175
@@ -187,6 +193,8 @@ def upgrade_database(
187193
alembic_base_dir = os.path.dirname(alembic_config_filename)
188194
os.chdir(alembic_base_dir) # so the directory in the config file works
189195
config = Config(alembic_config_filename)
196+
if db_url:
197+
config.set_main_option("sqlalchemy.url", db_url)
190198
script = ScriptDirectory.from_config(config)
191199

192200
# noinspection PyUnusedLocal,PyProtectedMember
@@ -217,6 +225,7 @@ def upgrade(rev, context):
217225
def downgrade_database(
218226
alembic_config_filename: str,
219227
destination_revision: str,
228+
db_url: str = None,
220229
alembic_base_dir: str = None,
221230
starting_revision: str = None,
222231
version_table: str = DEFAULT_ALEMBIC_VERSION_TABLE,
@@ -233,6 +242,9 @@ def downgrade_database(
233242
alembic_config_filename:
234243
config filename
235244
245+
db_url:
246+
Optional database URL to use, by way of override.
247+
236248
alembic_base_dir:
237249
directory to start in, so relative paths in the config file work
238250
@@ -255,6 +267,8 @@ def downgrade_database(
255267
alembic_base_dir = os.path.dirname(alembic_config_filename)
256268
os.chdir(alembic_base_dir) # so the directory in the config file works
257269
config = Config(alembic_config_filename)
270+
if db_url:
271+
config.set_main_option("sqlalchemy.url", db_url)
258272
script = ScriptDirectory.from_config(config)
259273

260274
# noinspection PyUnusedLocal,PyProtectedMember
@@ -403,6 +417,9 @@ def stamp_allowing_unusual_version_table(
403417
This function is a clone of ``alembic.command.stamp()``, but allowing
404418
``version_table`` to change. See
405419
https://alembic.zzzcomputing.com/en/latest/api/commands.html#alembic.command.stamp
420+
421+
Note that the Config object can include the database URL; use
422+
``config.set_main_option("sqlalchemy.url", db_url)``.
406423
"""
407424

408425
script = ScriptDirectory.from_config(config)

cardinal_pythonlib/sqlalchemy/core_query.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,31 @@
2424
2525
**Query helper functions using the SQLAlchemy Core.**
2626
27+
Example of result types in SQLAlchemy 1.4+ and higher:
28+
29+
.. code-block:: python
30+
31+
from typing import List
32+
from sqlalchemy.engine.cursor import CursorResult
33+
from sqlalchemy.engine.result import MappingResult, Result
34+
from sqlalchemy.engine.row import Row, RowMapping
35+
36+
query = (
37+
select(text("*"))
38+
.select_from(table(some_tablename))
39+
)
40+
41+
# As tuples:
42+
result_1: CursorResult = session.execute(query)
43+
# ... or, more generically, of type Result
44+
like_unnamed_tuples: List[Row] = result_1.fetchall()
45+
46+
# Or:
47+
result_2: Result = session.execute(query)
48+
mapping_result: Mapping_Result = result_2.mappings()
49+
like_dicts: List[RowMapping] = list(mapping_result) # implicit fetchall()
50+
# ... or could have done: like_dicts = result_2.mappings().fetchall()
51+
2752
"""
2853

2954
from typing import Any, List, Optional, Tuple, Union

0 commit comments

Comments
 (0)