summaryrefslogtreecommitdiff
path: root/alembic/op.py
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2011-11-15 13:07:40 -0500
committerMike Bayer <mike_mp@zzzcomputing.com>2011-11-15 13:07:40 -0500
commit2c05c7e0de90eaea23cd7e34b4405c2915a25171 (patch)
tree04a90fc89bca75c05a3035916051da8e37bcc455 /alembic/op.py
parentb5facd3a575afd1c2f99c8efcf888a077804c300 (diff)
downloadalembic-2c05c7e0de90eaea23cd7e34b4405c2915a25171.tar.gz
- remove add_constraint, this is not the current philosophy of the op package
- document most op methods - add support for create_index, drop_index - remove needless arguments from drop_table - propagate arguemnts to UniqueConstraint
Diffstat (limited to 'alembic/op.py')
-rw-r--r--alembic/op.py188
1 files changed, 158 insertions, 30 deletions
diff --git a/alembic/op.py b/alembic/op.py
index 4963122..cb016e8 100644
--- a/alembic/op.py
+++ b/alembic/op.py
@@ -5,19 +5,20 @@ from sqlalchemy import schema, sql
util.importlater.resolve_all()
-__all__ = [
+__all__ = sorted([
'alter_column',
'add_column',
'drop_column',
- 'add_constraint',
'create_foreign_key',
'create_table',
'drop_table',
+ 'drop_index',
+ 'create_index',
'bulk_insert',
'create_unique_constraint',
'get_context',
'get_bind',
- 'execute']
+ 'execute'])
def _foreign_key_constraint(name, source, referent, local_cols, remote_cols):
m = schema.MetaData()
@@ -35,21 +36,10 @@ def _foreign_key_constraint(name, source, referent, local_cols, remote_cols):
return f
-def _ensure_table_for_constraint(name, constraint):
- if getattr(constraint, 'parent', None) is not None:
- return
- if isinstance(constraint, schema.UniqueConstraint):
- # TODO: what if constraint has Column objects already
- columns = [schema.Column(n, NULLTYPE) for n in
- constraint._pending_colargs]
- else:
- columns = []
- return schema.Table(name, schema.MetaData(), *(columns + [constraint]) )
-
-def _unique_constraint(name, source, local_cols):
+def _unique_constraint(name, source, local_cols, **kw):
t = schema.Table(source, schema.MetaData(),
*[schema.Column(n, NULLTYPE) for n in local_cols])
- return schema.UniqueConstraint(*t.c, name=name)
+ return schema.UniqueConstraint(*t.c, name=name, **kw)
def _table(name, *columns, **kw):
m = schema.MetaData()
@@ -61,6 +51,12 @@ def _table(name, *columns, **kw):
def _column(name, type_, **kw):
return schema.Column(name, type_, **kw)
+def _index(name, tablename, columns, **kw):
+ t = schema.Table(tablename, schema.MetaData(),
+ *[schema.Column(n, NULLTYPE) for n in columns]
+ )
+ return schema.Index(name, *list(t.c), **kw)
+
def _ensure_table_for_fk(metadata, fk):
"""create a placeholder Table object for the referent of a
ForeignKey.
@@ -102,11 +98,31 @@ def add_column(table_name, column):
"""Issue an "add column" instruction using the current change context.
e.g.::
+
+ from alembic.op import add_column
+ from sqlalchemy import Column, String
+
+ add_column('organization',
+ Column('name', String())
+ )
+
+ The provided :class:`~sqlalchemy.schema.Column` object can also
+ specify a :class:`~sqlalchemy.schema.ForeignKey`, referencing
+ a remote table name. Alembic will automatically generate a stub
+ "referenced" table and emit a second ALTER statement in order
+ to add the constraint separately::
+ from alembic.op import add_column
+ from sqlalchemy import Column, INTEGER, ForeignKey
+
add_column('organization',
Column('account_id', INTEGER, ForeignKey('accounts.id'))
)
+ :param table_name: String name of the parent table.
+ :param column: a :class:`sqlalchemy.schema.Column` object
+ representing the new column.
+
"""
t = _table(table_name, column)
@@ -131,27 +147,84 @@ def drop_column(table_name, column_name):
_column(column_name, NULLTYPE)
)
-def add_constraint(table_name, constraint):
- """Issue an "add constraint" instruction using the current change context."""
-
- _ensure_table_for_constraint(table_name, constraint)
- get_impl().add_constraint(
- constraint
- )
def create_foreign_key(name, source, referent, local_cols, remote_cols):
- """Issue a "create foreign key" instruction using the current change context."""
+ """Issue a "create foreign key" instruction using the
+ current change context.
+
+ e.g.::
+
+ from alembic.op import create_foreign_key
+ create_foreign_key("fk_user_address", "address", "user", ["user_id"], ["id"])
+
+ This internally generates a :class:`~sqlalchemy.schema.Table` object
+ containing the necessary columns, then generates a new
+ :class:`~sqlalchemy.schema.ForeignKeyConstraint`
+ object which it then associates with the :class:`~sqlalchemy.schema.Table`.
+ Any event listeners associated with this action will be fired
+ off normally. The :class:`~sqlalchemy.schema.AddConstraint`
+ construct is ultimately used to generate the ALTER statement.
+
+ :param name: Name of the foreign key constraint. The name is necessary
+ so that an ALTER statement can be emitted. For setups that
+ use an automated naming scheme such as that described at
+ `NamingConventions <http://www.sqlalchemy.org/trac/wiki/UsageRecipes/NamingConventions>`_,
+ ``name`` here can be ``None``, as the event listener will
+ apply the name to the constraint object when it is associated
+ with the table.
+ :param source: String name of the source table. Currently
+ there is no support for dotted schema names.
+ :param referent: String name of the destination table. Currently
+ there is no support for dotted schema names.
+ :param local_cols: a list of string column names in the
+ source table.
+ :param remote_cols: a list of string column names in the
+ remote table.
+
+ """
get_impl().add_constraint(
_foreign_key_constraint(name, source, referent,
local_cols, remote_cols)
)
-def create_unique_constraint(name, source, local_cols):
- """Issue a "create unique constraint" instruction using the current change context."""
+def create_unique_constraint(name, source, local_cols, **kw):
+ """Issue a "create unique constraint" instruction using the current change context.
+
+ e.g.::
+
+ from alembic.op import create_unique_constraint
+ create_unique_constraint("uq_user_name", "user", ["name"])
+
+ This internally generates a :class:`~sqlalchemy.schema.Table` object
+ containing the necessary columns, then generates a new
+ :class:`~sqlalchemy.schema.UniqueConstraint`
+ object which it then associates with the :class:`~sqlalchemy.schema.Table`.
+ Any event listeners associated with this action will be fired
+ off normally. The :class:`~sqlalchemy.schema.AddConstraint`
+ construct is ultimately used to generate the ALTER statement.
+
+ :param name: Name of the unique constraint. The name is necessary
+ so that an ALTER statement can be emitted. For setups that
+ use an automated naming scheme such as that described at
+ `NamingConventions <http://www.sqlalchemy.org/trac/wiki/UsageRecipes/NamingConventions>`_,
+ ``name`` here can be ``None``, as the event listener will
+ apply the name to the constraint object when it is associated
+ with the table.
+ :param source: String name of the source table. Currently
+ there is no support for dotted schema names.
+ :param local_cols: a list of string column names in the
+ source table.
+ :param deferrable: optional bool. If set, emit DEFERRABLE or NOT DEFERRABLE when
+ issuing DDL for this constraint.
+ :param initially: optional string. If set, emit INITIALLY <value> when issuing DDL
+ for this constraint.
+
+ """
get_impl().add_constraint(
- _unique_constraint(name, source, local_cols)
+ _unique_constraint(name, source, local_cols,
+ **kw)
)
def create_table(name, *columns, **kw):
@@ -177,7 +250,7 @@ def create_table(name, *columns, **kw):
_table(name, *columns, **kw)
)
-def drop_table(name, *columns, **kw):
+def drop_table(name):
"""Issue a "drop table" instruction using the current change context.
@@ -187,9 +260,34 @@ def drop_table(name, *columns, **kw):
"""
get_impl().drop_table(
- _table(name, *columns, **kw)
+ _table(name)
)
+def create_index(name, tablename, *columns, **kw):
+ """Issue a "create index" instruction using the current change context.
+
+ e.g.::
+
+ from alembic.op import create_index
+ create_index('ik_test', 't1', ['foo', 'bar'])
+
+ """
+
+ get_impl().create_index(
+ _index(name, tablename, *columns, **kw)
+ )
+
+def drop_index(name):
+ """Issue a "drop index" instruction using the current change context.
+
+
+ e.g.::
+
+ drop_index("accounts")
+
+ """
+ get_impl().drop_index(_index(name, 'foo', []))
+
def bulk_insert(table, rows):
"""Issue a "bulk insert" operation using the current change context.
@@ -218,7 +316,37 @@ def execute(sql):
"""Execute the given SQL using the current change context.
In a SQL script context, the statement is emitted directly to the
- output stream.
+ output stream. There is *no* return result, however, as this
+ function is oriented towards generating a change script
+ that can run in "offline" mode. For full interaction
+ with a connected database, use the "bind" available
+ from the context::
+
+ from alembic.op import get_bind
+ connection = get_bind()
+
+ Also note that any parameterized statement here *will not work*
+ in offline mode - any kind of UPDATE or DELETE needs to render
+ inline expressions. Due to these limitations,
+ :func:`.execute` is overall not spectacularly useful for migration
+ scripts that wish to run in offline mode. Consider using the Alembic
+ directives, or if the environment is only meant to run in
+ "online" mode, use the ``get_context().bind``.
+
+ :param sql: Any legal SQLAlchemy expression, including:
+
+ * a string
+ * a :func:`sqlalchemy.sql.expression.text` construct, with the caveat that
+ bound parameters won't work correctly in offline mode.
+ * a :func:`sqlalchemy.sql.expression.insert` construct. If working
+ in offline mode, consider using :func:`alembic.op.bulk_insert`
+ instead to support parameterization.
+ * a :func:`sqlalchemy.sql.expression.update`, :func:`sqlalchemy.sql.expression.insert`,
+ or :func:`sqlalchemy.sql.expression.delete` construct, with the caveat
+ that bound parameters won't work correctly in offline mode.
+ * Pretty much anything that's "executable" as described
+ in :ref:`sqlexpression_toplevel`.
+
"""
get_impl().execute(sql)