diff options
author | mike bayer <mike_mp@zzzcomputing.com> | 2020-03-24 19:55:44 +0000 |
---|---|---|
committer | Gerrit Code Review <gerrit@bbpush.zzzcomputing.com> | 2020-03-24 19:55:44 +0000 |
commit | 7ab1a62d886a9fe40eb368bbbe73b6436b9cbb4b (patch) | |
tree | de7a5d1cdf9538474f56eba42afb1c6a540c4da6 /lib/sqlalchemy/sql/selectable.py | |
parent | fa1f67a01e80367d73cf5d1d93b6f7f51dc1746b (diff) | |
parent | 8e3a05ab987dcb783385e555aa607248df1469ca (diff) | |
download | sqlalchemy-7ab1a62d886a9fe40eb368bbbe73b6436b9cbb4b.tar.gz |
Merge "Implement SQL VALUES in core."
Diffstat (limited to 'lib/sqlalchemy/sql/selectable.py')
-rw-r--r-- | lib/sqlalchemy/sql/selectable.py | 122 |
1 files changed, 122 insertions, 0 deletions
diff --git a/lib/sqlalchemy/sql/selectable.py b/lib/sqlalchemy/sql/selectable.py index 3c8990a84..a44b079c4 100644 --- a/lib/sqlalchemy/sql/selectable.py +++ b/lib/sqlalchemy/sql/selectable.py @@ -46,6 +46,7 @@ from .elements import ColumnClause from .elements import GroupedElement from .elements import Grouping from .elements import literal_column +from .elements import Tuple from .elements import UnaryExpression from .visitors import InternalTraversal from .. import exc @@ -2010,6 +2011,127 @@ class ForUpdateArg(ClauseElement): self.of = None +class Values(Generative, FromClause): + """represent a ``VALUES`` construct that can be used as a FROM element + in a statement. + + The :class:`.Values` object is created from the + :func:`~.sql.expression.values` function. + + .. versionadded:: 1.4 + + """ + + named_with_column = True + __visit_name__ = "values" + + _data = () + + _traverse_internals = [ + ("_column_args", InternalTraversal.dp_clauseelement_list,), + ("_data", InternalTraversal.dp_clauseelement_list), + ("name", InternalTraversal.dp_string), + ("literal_binds", InternalTraversal.dp_boolean), + ] + + def __init__(self, *columns, **kw): + r"""Construct a :class:`.Values` construct. + + The column expressions and the actual data for + :class:`.Values` are given in two separate steps. The + constructor receives the column expressions typically as + :func:`.column` constructs, and the data is then passed via the + :meth:`.Values.data` method as a list, which can be called multiple + times to add more data, e.g.:: + + from sqlalchemy import column + from sqlalchemy import values + + value_expr = values( + column('id', Integer), + column('name', Integer), + name="my_values" + ).data( + [(1, 'name1'), (2, 'name2'), (3, 'name3')] + ) + + :param \*columns: column expressions, typically composed using + :func:`.column` objects. + + :param name: the name for this VALUES construct. If omitted, the + VALUES construct will be unnamed in a SQL expression. Different + backends may have different requirements here. + + :param literal_binds: Defaults to False. Whether or not to render + the data values inline in the SQL output, rather than using bound + parameters. + + """ + + super(Values, self).__init__() + self._column_args = columns + self.name = kw.pop("name", None) + self.literal_binds = kw.pop("literal_binds", False) + self.named_with_column = self.name is not None + + @_generative + def alias(self, name, **kw): + """Return a new :class:`.Values` construct that is a copy of this + one with the given name. + + This method is a VALUES-specific specialization of the + :class:`.FromClause.alias` method. + + .. seealso:: + + :ref:`core_tutorial_aliases` + + :func:`~.expression.alias` + + """ + self.name = name + self.named_with_column = self.name is not None + + @_generative + def lateral(self, name=None): + """Return a new :class:`.Values` with the lateral flag set, so that + it renders as LATERAL. + + .. seealso:: + + :func:`~.expression.lateral` + + """ + self._is_lateral = True + if name is not None: + self.name = name + + @_generative + def data(self, values): + """Return a new :class:`.Values` construct, adding the given data + to the data list. + + E.g.:: + + my_values = my_values.data([(1, 'value 1'), (2, 'value2')]) + + :param values: a sequence (i.e. list) of tuples that map to the + column expressions given in the :class:`.Values` constructor. + + """ + + self._data += tuple(Tuple(*row).self_group() for row in values) + + def _populate_column_collection(self): + for c in self._column_args: + self._columns.add(c) + c.table = self + + @property + def _from_objects(self): + return [self] + + class SelectBase( roles.SelectStatementRole, roles.DMLSelectRole, |