Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/sqlalchemy/dialects/sqlite/dml.py: 65%
49 statements
« prev ^ index » next coverage.py v7.0.1, created at 2022-12-25 06:11 +0000
« prev ^ index » next coverage.py v7.0.1, created at 2022-12-25 06:11 +0000
1# Copyright (C) 2005-2022 the SQLAlchemy authors and contributors
2# <see AUTHORS file>
3#
4# This module is part of SQLAlchemy and is released under
5# the MIT License: https://www.opensource.org/licenses/mit-license.php
7from ... import util
8from ...sql import coercions
9from ...sql import roles
10from ...sql.base import _exclusive_against
11from ...sql.base import _generative
12from ...sql.base import ColumnCollection
13from ...sql.dml import Insert as StandardInsert
14from ...sql.elements import ClauseElement
15from ...sql.expression import alias
16from ...util.langhelpers import public_factory
19__all__ = ("Insert", "insert")
22class Insert(StandardInsert):
23 """SQLite-specific implementation of INSERT.
25 Adds methods for SQLite-specific syntaxes such as ON CONFLICT.
27 The :class:`_sqlite.Insert` object is created using the
28 :func:`sqlalchemy.dialects.sqlite.insert` function.
30 .. versionadded:: 1.4
32 .. seealso::
34 :ref:`sqlite_on_conflict_insert`
36 """
38 stringify_dialect = "sqlite"
39 inherit_cache = False
41 @util.memoized_property
42 def excluded(self):
43 """Provide the ``excluded`` namespace for an ON CONFLICT statement
45 SQLite's ON CONFLICT clause allows reference to the row that would
46 be inserted, known as ``excluded``. This attribute provides
47 all columns in this row to be referenceable.
49 .. tip:: The :attr:`_sqlite.Insert.excluded` attribute is an instance
50 of :class:`_expression.ColumnCollection`, which provides an
51 interface the same as that of the :attr:`_schema.Table.c`
52 collection described at :ref:`metadata_tables_and_columns`.
53 With this collection, ordinary names are accessible like attributes
54 (e.g. ``stmt.excluded.some_column``), but special names and
55 dictionary method names should be accessed using indexed access,
56 such as ``stmt.excluded["column name"]`` or
57 ``stmt.excluded["values"]``. See the docstring for
58 :class:`_expression.ColumnCollection` for further examples.
60 """
61 return alias(self.table, name="excluded").columns
63 _on_conflict_exclusive = _exclusive_against(
64 "_post_values_clause",
65 msgs={
66 "_post_values_clause": "This Insert construct already has "
67 "an ON CONFLICT clause established"
68 },
69 )
71 @_generative
72 @_on_conflict_exclusive
73 def on_conflict_do_update(
74 self,
75 index_elements=None,
76 index_where=None,
77 set_=None,
78 where=None,
79 ):
80 r"""
81 Specifies a DO UPDATE SET action for ON CONFLICT clause.
83 :param index_elements:
84 A sequence consisting of string column names, :class:`_schema.Column`
85 objects, or other column expression objects that will be used
86 to infer a target index or unique constraint.
88 :param index_where:
89 Additional WHERE criterion that can be used to infer a
90 conditional target index.
92 :param set\_:
93 A dictionary or other mapping object
94 where the keys are either names of columns in the target table,
95 or :class:`_schema.Column` objects or other ORM-mapped columns
96 matching that of the target table, and expressions or literals
97 as values, specifying the ``SET`` actions to take.
99 .. versionadded:: 1.4 The
100 :paramref:`_sqlite.Insert.on_conflict_do_update.set_`
101 parameter supports :class:`_schema.Column` objects from the target
102 :class:`_schema.Table` as keys.
104 .. warning:: This dictionary does **not** take into account
105 Python-specified default UPDATE values or generation functions,
106 e.g. those specified using :paramref:`_schema.Column.onupdate`.
107 These values will not be exercised for an ON CONFLICT style of
108 UPDATE, unless they are manually specified in the
109 :paramref:`.Insert.on_conflict_do_update.set_` dictionary.
111 :param where:
112 Optional argument. If present, can be a literal SQL
113 string or an acceptable expression for a ``WHERE`` clause
114 that restricts the rows affected by ``DO UPDATE SET``. Rows
115 not meeting the ``WHERE`` condition will not be updated
116 (effectively a ``DO NOTHING`` for those rows).
118 """
120 self._post_values_clause = OnConflictDoUpdate(
121 index_elements, index_where, set_, where
122 )
124 @_generative
125 @_on_conflict_exclusive
126 def on_conflict_do_nothing(self, index_elements=None, index_where=None):
127 """
128 Specifies a DO NOTHING action for ON CONFLICT clause.
130 :param index_elements:
131 A sequence consisting of string column names, :class:`_schema.Column`
132 objects, or other column expression objects that will be used
133 to infer a target index or unique constraint.
135 :param index_where:
136 Additional WHERE criterion that can be used to infer a
137 conditional target index.
139 """
141 self._post_values_clause = OnConflictDoNothing(
142 index_elements, index_where
143 )
146insert = public_factory(
147 Insert, ".dialects.sqlite.insert", ".dialects.sqlite.Insert"
148)
151class OnConflictClause(ClauseElement):
152 stringify_dialect = "sqlite"
154 def __init__(self, index_elements=None, index_where=None):
156 if index_elements is not None:
157 self.constraint_target = None
158 self.inferred_target_elements = index_elements
159 self.inferred_target_whereclause = index_where
160 else:
161 self.constraint_target = (
162 self.inferred_target_elements
163 ) = self.inferred_target_whereclause = None
166class OnConflictDoNothing(OnConflictClause):
167 __visit_name__ = "on_conflict_do_nothing"
170class OnConflictDoUpdate(OnConflictClause):
171 __visit_name__ = "on_conflict_do_update"
173 def __init__(
174 self,
175 index_elements=None,
176 index_where=None,
177 set_=None,
178 where=None,
179 ):
180 super(OnConflictDoUpdate, self).__init__(
181 index_elements=index_elements,
182 index_where=index_where,
183 )
185 if isinstance(set_, dict):
186 if not set_:
187 raise ValueError("set parameter dictionary must not be empty")
188 elif isinstance(set_, ColumnCollection):
189 set_ = dict(set_)
190 else:
191 raise ValueError(
192 "set parameter must be a non-empty dictionary "
193 "or a ColumnCollection such as the `.c.` collection "
194 "of a Table object"
195 )
196 self.update_values_to_set = [
197 (coercions.expect(roles.DMLColumnRole, key), value)
198 for key, value in set_.items()
199 ]
200 self.update_whereclause = where