summaryrefslogtreecommitdiff
path: root/alembic
diff options
context:
space:
mode:
Diffstat (limited to 'alembic')
-rw-r--r--alembic/ddl/postgresql.py51
-rw-r--r--alembic/op.pyi49
-rw-r--r--alembic/operations/ops.py49
3 files changed, 100 insertions, 49 deletions
diff --git a/alembic/ddl/postgresql.py b/alembic/ddl/postgresql.py
index 5fb981d..cc0488b 100644
--- a/alembic/ddl/postgresql.py
+++ b/alembic/ddl/postgresql.py
@@ -25,6 +25,7 @@ from sqlalchemy.sql import operators
from sqlalchemy.sql.elements import ColumnClause
from sqlalchemy.sql.elements import TextClause
from sqlalchemy.sql.elements import UnaryExpression
+from sqlalchemy.sql.functions import FunctionElement
from sqlalchemy.types import NULLTYPE
from .base import alter_column
@@ -662,22 +663,15 @@ def _exclude_constraint(
("name", render._render_gen_name(autogen_context, constraint.name))
)
- if alter:
+ def do_expr_where_opts():
args = [
- repr(render._render_gen_name(autogen_context, constraint.name))
+ "(%s, %r)"
+ % (
+ _render_potential_column(sqltext, autogen_context),
+ opstring,
+ )
+ for sqltext, name, opstring in constraint._render_exprs # type:ignore[attr-defined] # noqa
]
- if not has_batch:
- args += [repr(render._ident(constraint.table.name))]
- args.extend(
- [
- "(%s, %r)"
- % (
- _render_potential_column(sqltext, autogen_context),
- opstring,
- )
- for sqltext, name, opstring in constraint._render_exprs # type:ignore[attr-defined] # noqa
- ]
- )
if constraint.where is not None:
args.append(
"where=%s"
@@ -686,24 +680,21 @@ def _exclude_constraint(
)
)
args.extend(["%s=%r" % (k, v) for k, v in opts])
+ return args
+
+ if alter:
+ args = [
+ repr(render._render_gen_name(autogen_context, constraint.name))
+ ]
+ if not has_batch:
+ args += [repr(render._ident(constraint.table.name))]
+ args.extend(do_expr_where_opts())
return "%(prefix)screate_exclude_constraint(%(args)s)" % {
"prefix": render._alembic_autogenerate_prefix(autogen_context),
"args": ", ".join(args),
}
else:
- args = [
- "(%s, %r)"
- % (_render_potential_column(sqltext, autogen_context), opstring)
- for sqltext, name, opstring in constraint._render_exprs
- ]
- if constraint.where is not None:
- args.append(
- "where=%s"
- % render._render_potential_expr(
- constraint.where, autogen_context
- )
- )
- args.extend(["%s=%r" % (k, v) for k, v in opts])
+ args = do_expr_where_opts()
return "%(prefix)sExcludeConstraint(%(args)s)" % {
"prefix": _postgresql_autogenerate_prefix(autogen_context),
"args": ", ".join(args),
@@ -711,7 +702,7 @@ def _exclude_constraint(
def _render_potential_column(
- value: Union[ColumnClause, Column, TextClause],
+ value: Union[ColumnClause, Column, TextClause, FunctionElement],
autogen_context: AutogenContext,
) -> str:
if isinstance(value, ColumnClause):
@@ -727,5 +718,7 @@ def _render_potential_column(
}
else:
return render._render_potential_expr(
- value, autogen_context, wrap_in_text=isinstance(value, TextClause)
+ value,
+ autogen_context,
+ wrap_in_text=isinstance(value, (TextClause, FunctionElement)),
)
diff --git a/alembic/op.pyi b/alembic/op.pyi
index 01edb61..535b2d5 100644
--- a/alembic/op.pyi
+++ b/alembic/op.pyi
@@ -53,11 +53,39 @@ def add_column(
op.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::
+ The :meth:`.Operations.add_column` method typically corresponds
+ to the SQL command "ALTER TABLE... ADD COLUMN". Within the scope
+ of this command, the column's name, datatype, nullability,
+ and optional server-generated defaults may be indicated.
+
+ .. note::
+
+ With the exception of NOT NULL constraints or single-column FOREIGN KEY
+ constraints, other kinds of constraints such as PRIMARY KEY, UNIQUE or
+ CHECK constraints **cannot** be generated using this method; for these
+ constraints, refer to operations such as
+ :meth:`.Operations.create_primary_key` and
+ :meth:`.Operations.create_check_constraint`. In particular, the
+ following :class:`~sqlalchemy.schema.Column` parameters are
+ **ignored**:
+
+ * :paramref:`~sqlalchemy.schema.Column.primary_key` - SQL databases
+ typically do not support an ALTER operation that can add individual
+ columns one at a time to an existing primary key constraint,
+ therefore it's less ambiguous to use the
+ :meth:`.Operations.create_primary_key` method, which assumes no
+ existing primary key constraint is present.
+ * :paramref:`~sqlalchemy.schema.Column.unique` - use the
+ :meth:`.Operations.create_unique_constraint` method
+ * :paramref:`~sqlalchemy.schema.Column.index` - use the
+ :meth:`.Operations.create_index` method
+
+
+ The provided :class:`~sqlalchemy.schema.Column` object may include a
+ :class:`~sqlalchemy.schema.ForeignKey` constraint directive,
+ referencing a remote table name. For this specific type of constraint,
+ Alembic will automatically emit a second ALTER statement in order to
+ add the single-column FOREIGN KEY constraint separately::
from alembic import op
from sqlalchemy import Column, INTEGER, ForeignKey
@@ -67,11 +95,12 @@ def add_column(
Column("account_id", INTEGER, ForeignKey("accounts.id")),
)
- Note that this statement uses the :class:`~sqlalchemy.schema.Column`
- construct as is from the SQLAlchemy library. In particular,
- default values to be created on the database side are
- specified using the ``server_default`` parameter, and not
- ``default`` which only specifies Python-side defaults::
+ The column argument passed to :meth:`.Operations.add_column` is a
+ :class:`~sqlalchemy.schema.Column` construct, used in the same way it's
+ used in SQLAlchemy. In particular, values or functions to be indicated
+ as producing the column's default value on the database side are
+ specified using the ``server_default`` parameter, and not ``default``
+ which only specifies Python-side defaults::
from alembic import op
from sqlalchemy import Column, TIMESTAMP, func
diff --git a/alembic/operations/ops.py b/alembic/operations/ops.py
index f95ab70..0295ab3 100644
--- a/alembic/operations/ops.py
+++ b/alembic/operations/ops.py
@@ -2012,11 +2012,39 @@ class AddColumnOp(AlterTableOp):
op.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::
+ The :meth:`.Operations.add_column` method typically corresponds
+ to the SQL command "ALTER TABLE... ADD COLUMN". Within the scope
+ of this command, the column's name, datatype, nullability,
+ and optional server-generated defaults may be indicated.
+
+ .. note::
+
+ With the exception of NOT NULL constraints or single-column FOREIGN
+ KEY constraints, other kinds of constraints such as PRIMARY KEY,
+ UNIQUE or CHECK constraints **cannot** be generated using this
+ method; for these constraints, refer to operations such as
+ :meth:`.Operations.create_primary_key` and
+ :meth:`.Operations.create_check_constraint`. In particular, the
+ following :class:`~sqlalchemy.schema.Column` parameters are
+ **ignored**:
+
+ * :paramref:`~sqlalchemy.schema.Column.primary_key` - SQL databases
+ typically do not support an ALTER operation that can add
+ individual columns one at a time to an existing primary key
+ constraint, therefore it's less ambiguous to use the
+ :meth:`.Operations.create_primary_key` method, which assumes no
+ existing primary key constraint is present.
+ * :paramref:`~sqlalchemy.schema.Column.unique` - use the
+ :meth:`.Operations.create_unique_constraint` method
+ * :paramref:`~sqlalchemy.schema.Column.index` - use the
+ :meth:`.Operations.create_index` method
+
+
+ The provided :class:`~sqlalchemy.schema.Column` object may include a
+ :class:`~sqlalchemy.schema.ForeignKey` constraint directive,
+ referencing a remote table name. For this specific type of constraint,
+ Alembic will automatically emit a second ALTER statement in order to
+ add the single-column FOREIGN KEY constraint separately::
from alembic import op
from sqlalchemy import Column, INTEGER, ForeignKey
@@ -2026,11 +2054,12 @@ class AddColumnOp(AlterTableOp):
Column("account_id", INTEGER, ForeignKey("accounts.id")),
)
- Note that this statement uses the :class:`~sqlalchemy.schema.Column`
- construct as is from the SQLAlchemy library. In particular,
- default values to be created on the database side are
- specified using the ``server_default`` parameter, and not
- ``default`` which only specifies Python-side defaults::
+ The column argument passed to :meth:`.Operations.add_column` is a
+ :class:`~sqlalchemy.schema.Column` construct, used in the same way it's
+ used in SQLAlchemy. In particular, values or functions to be indicated
+ as producing the column's default value on the database side are
+ specified using the ``server_default`` parameter, and not ``default``
+ which only specifies Python-side defaults::
from alembic import op
from sqlalchemy import Column, TIMESTAMP, func