summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy/sql
diff options
context:
space:
mode:
Diffstat (limited to 'lib/sqlalchemy/sql')
-rw-r--r--lib/sqlalchemy/sql/dml.py81
-rw-r--r--lib/sqlalchemy/sql/elements.py1
-rw-r--r--lib/sqlalchemy/sql/schema.py55
-rw-r--r--lib/sqlalchemy/sql/selectable.py251
-rw-r--r--lib/sqlalchemy/sql/type_api.py22
5 files changed, 329 insertions, 81 deletions
diff --git a/lib/sqlalchemy/sql/dml.py b/lib/sqlalchemy/sql/dml.py
index c923bf651..dc2aacbea 100644
--- a/lib/sqlalchemy/sql/dml.py
+++ b/lib/sqlalchemy/sql/dml.py
@@ -582,14 +582,6 @@ class ValuesBase(UpdateBase):
:meth:`_expression.Update.ordered_values`
- .. seealso::
-
- :ref:`inserts_and_updates` - SQL Expression
- Language Tutorial
-
- :func:`_expression.insert` - produce an ``INSERT`` statement
-
- :func:`_expression.update` - produce an ``UPDATE`` statement
"""
if self._select_names:
@@ -777,9 +769,7 @@ class Insert(ValuesBase):
The :class:`_expression.Insert` object is created using the
:func:`_expression.insert()` function.
- .. seealso::
-
- :ref:`coretutorial_insert_expressions`
+ .. note - the __init__() method delivers the docstring for this object
"""
@@ -834,10 +824,26 @@ class Insert(ValuesBase):
):
"""Construct an :class:`_expression.Insert` object.
+ E.g.::
+
+ from sqlalchemy import insert
+
+ stmt = (
+ insert(user_table).
+ values(name='username', fullname='Full Username')
+ )
+
Similar functionality is available via the
:meth:`_expression.TableClause.insert` method on
:class:`_schema.Table`.
+ .. seealso::
+
+ :ref:`coretutorial_insert_expressions` - in the 1.x tutorial
+
+ :ref:`tutorial_core_insert` - in the 2.0 tutorial
+
+
:param table: :class:`_expression.TableClause`
which is the subject of the
insert.
@@ -976,15 +982,15 @@ class DMLWhereBase(object):
_where_criteria = ()
@_generative
- def where(self, whereclause):
- """Return a new construct with the given expression added to
+ def where(self, *whereclause):
+ """Return a new construct with the given expression(s) added to
its WHERE clause, joined to the existing clause via AND, if any.
"""
- self._where_criteria += (
- coercions.expect(roles.WhereHavingRole, whereclause),
- )
+ for criterion in list(whereclause):
+ where_criteria = coercions.expect(roles.WhereHavingRole, criterion)
+ self._where_criteria += (where_criteria,)
def filter(self, *criteria):
"""A synonym for the :meth:`_dml.DMLWhereBase.where` method.
@@ -1032,9 +1038,7 @@ class DMLWhereBase(object):
class Update(DMLWhereBase, ValuesBase):
"""Represent an Update construct.
- The :class:`_expression.Update`
- object is created using the :func:`update()`
- function.
+ .. note - the __init__() method delivers the docstring for this object
"""
@@ -1090,16 +1094,23 @@ class Update(DMLWhereBase, ValuesBase):
from sqlalchemy import update
- stmt = update(users).where(users.c.id==5).\
- values(name='user #5')
+ stmt = (
+ update(user_table).
+ where(user_table.c.id == 5).
+ values(name='user #5')
+ )
Similar functionality is available via the
:meth:`_expression.TableClause.update` method on
- :class:`_schema.Table`::
+ :class:`_schema.Table`.
+
+ .. seealso::
+
+ :ref:`inserts_and_updates` - in the 1.x tutorial
+
+ :ref:`tutorial_core_update_delete` - in the 2.0 tutorial
+
- stmt = users.update().\
- where(users.c.id==5).\
- values(name='user #5')
:param table: A :class:`_schema.Table`
object representing the database
@@ -1279,9 +1290,7 @@ class Update(DMLWhereBase, ValuesBase):
class Delete(DMLWhereBase, UpdateBase):
"""Represent a DELETE construct.
- The :class:`_expression.Delete`
- object is created using the :func:`delete()`
- function.
+ .. note - the __init__() method delivers the docstring for this object
"""
@@ -1317,10 +1326,26 @@ class Delete(DMLWhereBase, UpdateBase):
):
r"""Construct :class:`_expression.Delete` object.
+ E.g.::
+
+ from sqlalchemy import delete
+
+ stmt = (
+ delete(user_table).
+ where(user_table.c.id == 5)
+ )
+
Similar functionality is available via the
:meth:`_expression.TableClause.delete` method on
:class:`_schema.Table`.
+ .. seealso::
+
+ :ref:`inserts_and_updates` - in the 1.x tutorial
+
+ :ref:`tutorial_core_update_delete` - in the 2.0 tutorial
+
+
:param table: The table to delete rows from.
:param whereclause: A :class:`_expression.ClauseElement`
diff --git a/lib/sqlalchemy/sql/elements.py b/lib/sqlalchemy/sql/elements.py
index e268abc8a..550cbea24 100644
--- a/lib/sqlalchemy/sql/elements.py
+++ b/lib/sqlalchemy/sql/elements.py
@@ -1655,7 +1655,6 @@ class TextClause(
:ref:`sqlexpression_text` - in the Core tutorial
- :ref:`orm_tutorial_literal_sql` - in the ORM tutorial
"""
return TextClause(text, bind=bind)
diff --git a/lib/sqlalchemy/sql/schema.py b/lib/sqlalchemy/sql/schema.py
index d764002a6..ccb1dd7e9 100644
--- a/lib/sqlalchemy/sql/schema.py
+++ b/lib/sqlalchemy/sql/schema.py
@@ -638,13 +638,14 @@ class Table(DialectKWArgs, SchemaItem, TableClause):
)
insp = inspection.inspect(autoload_with)
- insp.reflect_table(
- self,
- include_columns,
- exclude_columns,
- resolve_fks,
- _extend_on=_extend_on,
- )
+ with insp._inspection_context() as conn_insp:
+ conn_insp.reflect_table(
+ self,
+ include_columns,
+ exclude_columns,
+ resolve_fks,
+ _extend_on=_extend_on,
+ )
@property
def _sorted_constraints(self):
@@ -2824,7 +2825,16 @@ class DefaultClause(FetchedValue):
class Constraint(DialectKWArgs, SchemaItem):
- """A table-level SQL constraint."""
+ """A table-level SQL constraint.
+
+ :class:`_schema.Constraint` serves as the base class for the series of
+ constraint objects that can be associated with :class:`_schema.Table`
+ objects, including :class:`_schema.PrimaryKeyConstraint`,
+ :class:`_schema.ForeignKeyConstraint`
+ :class:`_schema.UniqueConstraint`, and
+ :class:`_schema.CheckConstraint`.
+
+ """
__visit_name__ = "constraint"
@@ -2856,28 +2866,18 @@ class Constraint(DialectKWArgs, SchemaItem):
.. versionadded:: 1.0.0
- :param _create_rule:
- a callable which is passed the DDLCompiler object during
- compilation. Returns True or False to signal inline generation of
- this Constraint.
-
- The AddConstraint and DropConstraint DDL constructs provide
- DDLElement's more comprehensive "conditional DDL" approach that is
- passed a database connection when DDL is being issued. _create_rule
- is instead called during any CREATE TABLE compilation, where there
- may not be any transaction/connection in progress. However, it
- allows conditional compilation of the constraint even for backends
- which do not support addition of constraints through ALTER TABLE,
- which currently includes SQLite.
-
- _create_rule is used by some types to create constraints.
- Currently, its call signature is subject to change at any time.
-
:param \**dialect_kw: Additional keyword arguments are dialect
specific, and passed in the form ``<dialectname>_<argname>``. See
the documentation regarding an individual dialect at
:ref:`dialect_toplevel` for detail on documented arguments.
+ :param _create_rule:
+ used internally by some datatypes that also create constraints.
+
+ :param _type_bound:
+ used internally to indicate that this constraint is associated with
+ a specific datatype.
+
"""
self.name = name
@@ -4158,7 +4158,10 @@ class MetaData(SchemaItem):
"""
def __repr__(self):
- return "MetaData(bind=%r)" % self.bind
+ if self.bind:
+ return "MetaData(bind=%r)" % self.bind
+ else:
+ return "MetaData()"
def __contains__(self, table_or_key):
if not isinstance(table_or_key, util.string_types):
diff --git a/lib/sqlalchemy/sql/selectable.py b/lib/sqlalchemy/sql/selectable.py
index fd8832400..895a4532b 100644
--- a/lib/sqlalchemy/sql/selectable.py
+++ b/lib/sqlalchemy/sql/selectable.py
@@ -700,8 +700,7 @@ class FromClause(roles.AnonymizedFromClauseRole, Selectable):
@util.memoized_property
def columns(self):
"""A named-based collection of :class:`_expression.ColumnElement`
- objects
- maintained by this :class:`_expression.FromClause`.
+ objects maintained by this :class:`_expression.FromClause`.
The :attr:`.columns`, or :attr:`.c` collection, is the gateway
to the construction of SQL expressions using table-bound or
@@ -709,6 +708,8 @@ class FromClause(roles.AnonymizedFromClauseRole, Selectable):
select(mytable).where(mytable.c.somecolumn == 5)
+ :return: a :class:`.ColumnCollection` object.
+
"""
if "_columns" not in self.__dict__:
@@ -734,8 +735,12 @@ class FromClause(roles.AnonymizedFromClauseRole, Selectable):
@util.memoized_property
def primary_key(self):
- """Return the collection of :class:`_schema.Column` objects
- which comprise the primary key of this FromClause.
+ """Return the iterable collection of :class:`_schema.Column` objects
+ which comprise the primary key of this :class:`_selectable.FromClause`.
+
+ For a :class:`_schema.Table` object, this collection is represented
+ by the :class:`_schema.PrimaryKeyConstraint` which itself is an
+ iterable collection of :class:`_schema.Column` objects.
"""
self._init_collections()
@@ -771,7 +776,16 @@ class FromClause(roles.AnonymizedFromClauseRole, Selectable):
c = property(
attrgetter("columns"),
- doc="An alias for the :attr:`.columns` attribute.",
+ doc="""
+ A named-based collection of :class:`_expression.ColumnElement`
+ objects maintained by this :class:`_expression.FromClause`.
+
+ The :attr:`_sql.FromClause.c` attribute is an alias for the
+ :attr:`_sql.FromClause.columns` atttribute.
+
+ :return: a :class:`.ColumnCollection`
+
+ """,
)
_select_iterable = property(attrgetter("columns"))
@@ -1227,7 +1241,9 @@ class Join(roles.DMLTableRole, FromClause):
)
def bind(self):
"""Return the bound engine associated with either the left or right
- side of this :class:`_sql.Join`."""
+ side of this :class:`_sql.Join`.
+
+ """
return self.left.bind or self.right.bind
@@ -1441,10 +1457,14 @@ class AliasedReturnsRows(NoInit, FromClause):
@property
def description(self):
+ name = self.name
+ if isinstance(name, _anonymous_label):
+ name = "anon_1"
+
if util.py3k:
- return self.name
+ return name
else:
- return self.name.encode("ascii", "backslashreplace")
+ return name.encode("ascii", "backslashreplace")
@property
def original(self):
@@ -1693,8 +1713,18 @@ class CTE(Generative, HasPrefixes, HasSuffixes, AliasedReturnsRows):
"""Represent a Common Table Expression.
The :class:`_expression.CTE` object is obtained using the
- :meth:`_expression.SelectBase.cte` method from any selectable.
- See that method for complete examples.
+ :meth:`_sql.SelectBase.cte` method from any SELECT statement. A less often
+ available syntax also allows use of the :meth:`_sql.HasCTE.cte` method
+ present on :term:`DML` constructs such as :class:`_sql.Insert`,
+ :class:`_sql.Update` and
+ :class:`_sql.Delete`. See the :meth:`_sql.HasCTE.cte` method for
+ usage details on CTEs.
+
+ .. seealso::
+
+ :ref:`tutorial_subqueries_ctes` - in the 2.0 tutorial
+
+ :meth:`_sql.HasCTE.cte` - examples of calling styles
"""
@@ -1955,7 +1985,7 @@ class HasCTE(roles.HasCTERole):
.. seealso::
- :meth:`.orm.query.Query.cte` - ORM version of
+ :meth:`_orm.Query.cte` - ORM version of
:meth:`_expression.HasCTE.cte`.
"""
@@ -2546,10 +2576,29 @@ class SelectBase(
def as_scalar(self):
return self.scalar_subquery()
+ def exists(self):
+ """Return an :class:`_sql.Exists` representation of this selectable,
+ which can be used as a column expression.
+
+ The returned object is an instance of :class:`_sql.Exists`.
+
+ .. seealso::
+
+ :func:`_sql.exists`
+
+ :ref:`tutorial_exists` - in the :term:`2.0 style` tutorial.
+
+ .. versionadded:: 1.4
+
+ """
+ return Exists(self)
+
def scalar_subquery(self):
"""Return a 'scalar' representation of this selectable, which can be
used as a column expression.
+ The returned object is an instance of :class:`_sql.ScalarSelect`.
+
Typically, a select statement which has only one column in its columns
clause is eligible to be used as a scalar expression. The scalar
subquery can then be used in the WHERE clause or columns clause of
@@ -2563,6 +2612,12 @@ class SelectBase(
.. versionchanged: 1.4 - the ``.as_scalar()`` method was renamed to
:meth:`_expression.SelectBase.scalar_subquery`.
+ .. seealso::
+
+ :ref:`tutorial_scalar_subquery` - in the 2.0 tutorial
+
+ :ref:`scalar_selects` - in the 1.x tutorial
+
"""
if self._label_style is not LABEL_STYLE_NONE:
self = self._set_label_style(LABEL_STYLE_NONE)
@@ -3777,12 +3832,12 @@ class SelectState(util.MemoizedSlots, CompileState):
if not len(froms):
raise exc.InvalidRequestError(
- "Select statement '%s"
+ "Select statement '%r"
"' returned no FROM clauses "
"due to auto-correlation; "
"specify correlate(<tables>) "
"to control correlation "
- "manually." % self
+ "manually." % self.statement
)
return froms
@@ -3994,7 +4049,9 @@ class Select(
:func:`_sql.select`
- :ref:`coretutorial_selecting` - in the Core tutorial
+ :ref:`coretutorial_selecting` - in the 1.x tutorial
+
+ :ref:`tutorial_selecting_data` - in the 2.0 tutorial
"""
@@ -4491,8 +4548,8 @@ class Select(
.. seealso::
- :ref:`orm_tutorial_literal_sql` - usage examples in the
- ORM tutorial
+ :ref:`orm_queryguide_selecting_text` - usage examples in the
+ ORM Querying Guide
"""
meth = SelectState.get_plugin_class(self).from_statement
@@ -4548,6 +4605,10 @@ class Select(
.. seealso::
+ :ref:`tutorial_select_join` - in the :doc:`/tutorial/index`
+
+ :ref:`orm_queryguide_joins` - in the :ref:`queryguide_toplevel`
+
:meth:`_expression.Select.join_from`
:meth:`_expression.Select.outerjoin`
@@ -4599,6 +4660,10 @@ class Select(
.. seealso::
+ :ref:`tutorial_select_join` - in the :doc:`/tutorial/index`
+
+ :ref:`orm_queryguide_joins` - in the :ref:`queryguide_toplevel`
+
:meth:`_expression.Select.join`
""" # noqa: E501
@@ -4648,6 +4713,10 @@ class Select(
.. seealso::
+ :ref:`tutorial_select_join` - in the :doc:`/tutorial/index`
+
+ :ref:`orm_queryguide_joins` - in the :ref:`queryguide_toplevel`
+
:meth:`_expression.Select.join`
"""
@@ -4903,7 +4972,7 @@ class Select(
_whereclause = whereclause
@_generative
- def where(self, whereclause):
+ def where(self, *whereclause):
"""Return a new :func:`_expression.select` construct with
the given expression added to
its WHERE clause, joined to the existing clause via AND, if any.
@@ -4911,9 +4980,10 @@ class Select(
"""
assert isinstance(self._where_criteria, tuple)
- self._where_criteria += (
- coercions.expect(roles.WhereHavingRole, whereclause),
- )
+
+ for criterion in list(whereclause):
+ where_criteria = coercions.expect(roles.WhereHavingRole, criterion)
+ self._where_criteria += (where_criteria,)
@_generative
def having(self, having):
@@ -5400,6 +5470,24 @@ class Select(
class ScalarSelect(roles.InElementRole, Generative, Grouping):
+ """Represent a scalar subquery.
+
+
+ A :class:`_sql.ScalarSubquery` is created by invoking the
+ :meth:`_sql.SelectBase.scalar_subquery` method. The object
+ then participates in other SQL expressions as a SQL column expression
+ within the :class:`_sql.ColumnElement` hierarchy.
+
+ .. seealso::
+
+ :meth:`_sql.SelectBase.scalar_subquery`
+
+ :ref:`tutorial_scalar_subquery` - in the 2.0 tutorial
+
+ :ref:`scalar_selects` - in the 1.x tutorial
+
+ """
+
_from_objects = []
_is_from_container = True
_is_implicitly_boolean = False
@@ -5430,9 +5518,79 @@ class ScalarSelect(roles.InElementRole, Generative, Grouping):
def self_group(self, **kwargs):
return self
+ @_generative
+ def correlate(self, *fromclauses):
+ r"""Return a new :class:`_expression.ScalarSelect`
+ which will correlate the given FROM
+ clauses to that of an enclosing :class:`_expression.Select`.
+
+ This method is mirrored from the :meth:`_sql.Select.correlate` method
+ of the underlying :class:`_sql.Select`. The method applies the
+ :meth:_sql.Select.correlate` method, then returns a new
+ :class:`_sql.ScalarSelect` against that statement.
+
+ .. versionadded:: 1.4 Previously, the
+ :meth:`_sql.ScalarSelect.correlate`
+ method was only available from :class:`_sql.Select`.
+
+ :param \*fromclauses: a list of one or more
+ :class:`_expression.FromClause`
+ constructs, or other compatible constructs (i.e. ORM-mapped
+ classes) to become part of the correlate collection.
+
+ .. seealso::
+
+ :meth:`_expression.ScalarSelect.correlate_except`
+
+ :ref:`tutorial_scalar_subquery` - in the 2.0 tutorial
+
+ :ref:`correlated_subqueries` - in the 1.x tutorial
+
+
+ """
+ self.element = self.element.correlate(*fromclauses)
+
+ @_generative
+ def correlate_except(self, *fromclauses):
+ r"""Return a new :class:`_expression.ScalarSelect`
+ which will omit the given FROM
+ clauses from the auto-correlation process.
+
+ This method is mirrored from the
+ :meth:`_sql.Select.correlate_except` method of the underlying
+ :class:`_sql.Select`. The method applies the
+ :meth:_sql.Select.correlate_except` method, then returns a new
+ :class:`_sql.ScalarSelect` against that statement.
+
+ .. versionadded:: 1.4 Previously, the
+ :meth:`_sql.ScalarSelect.correlate_except`
+ method was only available from :class:`_sql.Select`.
+
+ :param \*fromclauses: a list of one or more
+ :class:`_expression.FromClause`
+ constructs, or other compatible constructs (i.e. ORM-mapped
+ classes) to become part of the correlate-exception collection.
+
+ .. seealso::
+
+ :meth:`_expression.ScalarSelect.correlate`
+
+ :ref:`tutorial_scalar_subquery` - in the 2.0 tutorial
+
+ :ref:`correlated_subqueries` - in the 1.x tutorial
+
+
+ """
+
+ self.element = self.element.correlate_except(*fromclauses)
+
class Exists(UnaryExpression):
- """Represent an ``EXISTS`` clause."""
+ """Represent an ``EXISTS`` clause.
+
+ See :func:`_sql.exists` for a description of usage.
+
+ """
_from_objects = []
inherit_cache = True
@@ -5440,12 +5598,23 @@ class Exists(UnaryExpression):
def __init__(self, *args, **kwargs):
"""Construct a new :class:`_expression.Exists` construct.
- The modern form of :func:`.exists` is to invoke with no arguments,
- which will produce an ``"EXISTS *"`` construct. A WHERE clause
- is then added using the :meth:`.Exists.where` method::
+ The :func:`_sql.exists` can be invoked by itself to produce an
+ :class:`_sql.Exists` construct, which will accept simple WHERE
+ criteria::
exists_criteria = exists().where(table1.c.col1 == table2.c.col2)
+ However, for greater flexibility in constructing the SELECT, an
+ existing :class:`_sql.Select` construct may be converted to an
+ :class:`_sql.Exists`, most conveniently by making use of the
+ :meth:`_sql.SelectBase.exists` method::
+
+ exists_criteria = (
+ select(table2.c.col2).
+ where(table1.c.col1 == table2.c.col2).
+ exists()
+ )
+
The EXISTS criteria is then used inside of an enclosing SELECT::
stmt = select(table1.c.col1).where(exists_criteria)
@@ -5453,9 +5622,13 @@ class Exists(UnaryExpression):
The above statement will then be of the form::
SELECT col1 FROM table1 WHERE EXISTS
- (SELECT * FROM table2 WHERE table2.col2 = table1.col1)
+ (SELECT table2.col2 FROM table2 WHERE table2.col2 = table1.col1)
- """
+ .. seealso::
+
+ :ref:`tutorial_exists` - in the :term:`2.0 style` tutorial.
+
+ """ # noqa E501
if args and isinstance(args[0], (SelectBase, ScalarSelect)):
s = args[0]
else:
@@ -5524,6 +5697,13 @@ class Exists(UnaryExpression):
return Select._create_select_from_fromclause(self, [self], **kwargs)
def correlate(self, *fromclause):
+ """Apply correlation to the subquery noted by this :class:`_sql.Exists`.
+
+ .. seealso::
+
+ :meth:`_sql.ScalarSelect.correlate`
+
+ """
e = self._clone()
e.element = self._regroup(
lambda element: element.correlate(*fromclause)
@@ -5531,6 +5711,14 @@ class Exists(UnaryExpression):
return e
def correlate_except(self, *fromclause):
+ """Apply correlation to the subquery noted by this :class:`_sql.Exists`.
+
+ .. seealso::
+
+ :meth:`_sql.ScalarSelect.correlate_except`
+
+ """
+
e = self._clone()
e.element = self._regroup(
lambda element: element.correlate_except(*fromclause)
@@ -5544,6 +5732,11 @@ class Exists(UnaryExpression):
method of the select
statement contained.
+ .. note:: it is typically preferable to build a :class:`_sql.Select`
+ statement first, including the desired WHERE clause, then use the
+ :meth:`_sql.SelectBase.exists` method to produce an
+ :class:`_sql.Exists` object at once.
+
"""
e = self._clone()
e.element = self._regroup(lambda element: element.select_from(*froms))
@@ -5554,6 +5747,12 @@ class Exists(UnaryExpression):
given expression added to
its WHERE clause, joined to the existing clause via AND, if any.
+
+ .. note:: it is typically preferable to build a :class:`_sql.Select`
+ statement first, including the desired WHERE clause, then use the
+ :meth:`_sql.SelectBase.exists` method to produce an
+ :class:`_sql.Exists` object at once.
+
"""
e = self._clone()
e.element = self._regroup(lambda element: element.where(clause))
diff --git a/lib/sqlalchemy/sql/type_api.py b/lib/sqlalchemy/sql/type_api.py
index 614b70a41..bca6e9020 100644
--- a/lib/sqlalchemy/sql/type_api.py
+++ b/lib/sqlalchemy/sql/type_api.py
@@ -456,6 +456,28 @@ class TypeEngine(Traversible):
else:
return self.__class__
+ @classmethod
+ def _is_generic_type(cls):
+ n = cls.__name__
+ return n.upper() != n
+
+ def _generic_type_affinity(self):
+
+ for t in self.__class__.__mro__:
+ if (
+ t.__module__
+ in (
+ "sqlalchemy.sql.sqltypes",
+ "sqlalchemy.sql.type_api",
+ )
+ and t._is_generic_type()
+ ):
+ if t in (TypeEngine, UserDefinedType):
+ return NULLTYPE.__class__
+ return t
+ else:
+ return self.__class__
+
def dialect_impl(self, dialect):
"""Return a dialect-specific implementation for this
:class:`.TypeEngine`.