summaryrefslogtreecommitdiff
path: root/docs/build/cookbook.rst
diff options
context:
space:
mode:
Diffstat (limited to 'docs/build/cookbook.rst')
-rw-r--r--docs/build/cookbook.rst74
1 files changed, 74 insertions, 0 deletions
diff --git a/docs/build/cookbook.rst b/docs/build/cookbook.rst
index d24aab9..8c1e0d7 100644
--- a/docs/build/cookbook.rst
+++ b/docs/build/cookbook.rst
@@ -187,3 +187,77 @@ To invoke our migrations with data included, we use the ``-x`` flag::
The :meth:`.EnvironmentContext.get_x_argument` is an easy way to support
new commandline options within environment and migration scripts.
+.. _connection_sharing:
+
+Sharing a Connection with a Series of Migration Commands and Environments
+=========================================================================
+
+It is often the case that an application will need to call upon a series
+of commands within :mod:`alembic.command`, where it would be advantageous
+for all operations to proceed along a single transaction. The connectivity
+for a migration is typically solely determined within the ``env.py`` script
+of a migration environment, which is called within the scope of a command.
+
+The steps to take here are:
+
+1. Produce the :class:`~sqlalchemy.engine.Connection` object to use.
+
+2. Place it somewhere that ``env.py`` will be able to access it. This
+ can be either a. a module-level global somewhere, or b.
+ an attribute which we place into the :attr:`.Config.attributes`
+ dictionary (if we are on an older Alembic version, we may also attach
+ an attribute directly to the :class:`.Config` object).
+
+3. The ``env.py`` script is modified such that it looks for this
+ :class:`~sqlalchemy.engine.Connection` and makes use of it, in lieu
+ of building up its own :class:`~sqlalchemy.engine.Engine` instance.
+
+We illustrate using :attr:`.Config.attributes`::
+
+ from alembic import command, config
+
+ cfg = config.Config("/path/to/yourapp/alembic.ini")
+ with engine.begin() as connection:
+ cfg.attributes['connection'] = connection
+ command.upgrade(cfg, "head")
+
+Then in ``env.py``::
+
+ def run_migrations_online():
+ connectable = config.attributes.get('connection', None)
+
+ if connectable is None:
+ # only create Engine if we don't have a Connection
+ # from the outside
+ connectable = engine_from_config(
+ config.get_section(config.config_ini_section),
+ prefix='sqlalchemy.',
+ poolclass=pool.NullPool)
+
+ # when connectable is already a Connection object, calling
+ # connect() gives us a *branched connection*.
+
+ with connectable.connect() as connection:
+ context.configure(
+ connection=connection,
+ target_metadata=target_metadata
+ )
+
+ with context.begin_transaction():
+ context.run_migrations()
+
+.. topic:: Branched Connections
+
+ Note that we are calling the ``connect()`` method, **even if we are
+ using a** :class:`~sqlalchemy.engine.Connection` **object to start with**.
+ The effect this has when calling :meth:`~sqlalchemy.engine.Connection.connect`
+ is that SQLAlchemy passes us a **branch** of the original connection; it
+ is in every way the same as the :class:`~sqlalchemy.engine.Connection`
+ we started with, except it provides **nested scope**; the
+ context we have here as well as the
+ :meth:`~sqlalchemy.engine.Connection.close` method of this branched
+ connection doesn't actually close the outer connection, which stays
+ active for continued use.
+
+.. versionadded:: 0.7.5 Added :attr:`.Config.attributes`.
+