SQLAlchemy 2.0.36__cp313-cp313-win32.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (273) hide show
  1. SQLAlchemy-2.0.36.dist-info/LICENSE +19 -0
  2. SQLAlchemy-2.0.36.dist-info/METADATA +243 -0
  3. SQLAlchemy-2.0.36.dist-info/RECORD +273 -0
  4. SQLAlchemy-2.0.36.dist-info/WHEEL +5 -0
  5. SQLAlchemy-2.0.36.dist-info/top_level.txt +1 -0
  6. sqlalchemy/__init__.py +294 -0
  7. sqlalchemy/connectors/__init__.py +18 -0
  8. sqlalchemy/connectors/aioodbc.py +174 -0
  9. sqlalchemy/connectors/asyncio.py +213 -0
  10. sqlalchemy/connectors/pyodbc.py +249 -0
  11. sqlalchemy/cyextension/__init__.py +6 -0
  12. sqlalchemy/cyextension/collections.cp313-win32.pyd +0 -0
  13. sqlalchemy/cyextension/collections.pyx +409 -0
  14. sqlalchemy/cyextension/immutabledict.cp313-win32.pyd +0 -0
  15. sqlalchemy/cyextension/immutabledict.pxd +8 -0
  16. sqlalchemy/cyextension/immutabledict.pyx +133 -0
  17. sqlalchemy/cyextension/processors.cp313-win32.pyd +0 -0
  18. sqlalchemy/cyextension/processors.pyx +68 -0
  19. sqlalchemy/cyextension/resultproxy.cp313-win32.pyd +0 -0
  20. sqlalchemy/cyextension/resultproxy.pyx +102 -0
  21. sqlalchemy/cyextension/util.cp313-win32.pyd +0 -0
  22. sqlalchemy/cyextension/util.pyx +91 -0
  23. sqlalchemy/dialects/__init__.py +61 -0
  24. sqlalchemy/dialects/_typing.py +25 -0
  25. sqlalchemy/dialects/mssql/__init__.py +88 -0
  26. sqlalchemy/dialects/mssql/aioodbc.py +64 -0
  27. sqlalchemy/dialects/mssql/base.py +4010 -0
  28. sqlalchemy/dialects/mssql/information_schema.py +254 -0
  29. sqlalchemy/dialects/mssql/json.py +133 -0
  30. sqlalchemy/dialects/mssql/provision.py +162 -0
  31. sqlalchemy/dialects/mssql/pymssql.py +126 -0
  32. sqlalchemy/dialects/mssql/pyodbc.py +745 -0
  33. sqlalchemy/dialects/mysql/__init__.py +101 -0
  34. sqlalchemy/dialects/mysql/aiomysql.py +333 -0
  35. sqlalchemy/dialects/mysql/asyncmy.py +337 -0
  36. sqlalchemy/dialects/mysql/base.py +3494 -0
  37. sqlalchemy/dialects/mysql/cymysql.py +84 -0
  38. sqlalchemy/dialects/mysql/dml.py +219 -0
  39. sqlalchemy/dialects/mysql/enumerated.py +244 -0
  40. sqlalchemy/dialects/mysql/expression.py +141 -0
  41. sqlalchemy/dialects/mysql/json.py +81 -0
  42. sqlalchemy/dialects/mysql/mariadb.py +32 -0
  43. sqlalchemy/dialects/mysql/mariadbconnector.py +277 -0
  44. sqlalchemy/dialects/mysql/mysqlconnector.py +180 -0
  45. sqlalchemy/dialects/mysql/mysqldb.py +303 -0
  46. sqlalchemy/dialects/mysql/provision.py +110 -0
  47. sqlalchemy/dialects/mysql/pymysql.py +137 -0
  48. sqlalchemy/dialects/mysql/pyodbc.py +138 -0
  49. sqlalchemy/dialects/mysql/reflection.py +677 -0
  50. sqlalchemy/dialects/mysql/reserved_words.py +571 -0
  51. sqlalchemy/dialects/mysql/types.py +774 -0
  52. sqlalchemy/dialects/oracle/__init__.py +67 -0
  53. sqlalchemy/dialects/oracle/base.py +3271 -0
  54. sqlalchemy/dialects/oracle/cx_oracle.py +1483 -0
  55. sqlalchemy/dialects/oracle/dictionary.py +507 -0
  56. sqlalchemy/dialects/oracle/oracledb.py +431 -0
  57. sqlalchemy/dialects/oracle/provision.py +220 -0
  58. sqlalchemy/dialects/oracle/types.py +287 -0
  59. sqlalchemy/dialects/postgresql/__init__.py +167 -0
  60. sqlalchemy/dialects/postgresql/_psycopg_common.py +187 -0
  61. sqlalchemy/dialects/postgresql/array.py +425 -0
  62. sqlalchemy/dialects/postgresql/asyncpg.py +1274 -0
  63. sqlalchemy/dialects/postgresql/base.py +5008 -0
  64. sqlalchemy/dialects/postgresql/dml.py +310 -0
  65. sqlalchemy/dialects/postgresql/ext.py +496 -0
  66. sqlalchemy/dialects/postgresql/hstore.py +397 -0
  67. sqlalchemy/dialects/postgresql/json.py +333 -0
  68. sqlalchemy/dialects/postgresql/named_types.py +509 -0
  69. sqlalchemy/dialects/postgresql/operators.py +129 -0
  70. sqlalchemy/dialects/postgresql/pg8000.py +662 -0
  71. sqlalchemy/dialects/postgresql/pg_catalog.py +300 -0
  72. sqlalchemy/dialects/postgresql/provision.py +175 -0
  73. sqlalchemy/dialects/postgresql/psycopg.py +772 -0
  74. sqlalchemy/dialects/postgresql/psycopg2.py +886 -0
  75. sqlalchemy/dialects/postgresql/psycopg2cffi.py +61 -0
  76. sqlalchemy/dialects/postgresql/ranges.py +1029 -0
  77. sqlalchemy/dialects/postgresql/types.py +303 -0
  78. sqlalchemy/dialects/sqlite/__init__.py +57 -0
  79. sqlalchemy/dialects/sqlite/aiosqlite.py +396 -0
  80. sqlalchemy/dialects/sqlite/base.py +2805 -0
  81. sqlalchemy/dialects/sqlite/dml.py +240 -0
  82. sqlalchemy/dialects/sqlite/json.py +92 -0
  83. sqlalchemy/dialects/sqlite/provision.py +198 -0
  84. sqlalchemy/dialects/sqlite/pysqlcipher.py +155 -0
  85. sqlalchemy/dialects/sqlite/pysqlite.py +756 -0
  86. sqlalchemy/dialects/type_migration_guidelines.txt +145 -0
  87. sqlalchemy/engine/__init__.py +62 -0
  88. sqlalchemy/engine/_py_processors.py +136 -0
  89. sqlalchemy/engine/_py_row.py +128 -0
  90. sqlalchemy/engine/_py_util.py +74 -0
  91. sqlalchemy/engine/base.py +3375 -0
  92. sqlalchemy/engine/characteristics.py +155 -0
  93. sqlalchemy/engine/create.py +875 -0
  94. sqlalchemy/engine/cursor.py +2181 -0
  95. sqlalchemy/engine/default.py +2365 -0
  96. sqlalchemy/engine/events.py +951 -0
  97. sqlalchemy/engine/interfaces.py +3403 -0
  98. sqlalchemy/engine/mock.py +131 -0
  99. sqlalchemy/engine/processors.py +61 -0
  100. sqlalchemy/engine/reflection.py +2098 -0
  101. sqlalchemy/engine/result.py +2382 -0
  102. sqlalchemy/engine/row.py +401 -0
  103. sqlalchemy/engine/strategies.py +19 -0
  104. sqlalchemy/engine/url.py +910 -0
  105. sqlalchemy/engine/util.py +167 -0
  106. sqlalchemy/event/__init__.py +25 -0
  107. sqlalchemy/event/api.py +225 -0
  108. sqlalchemy/event/attr.py +655 -0
  109. sqlalchemy/event/base.py +470 -0
  110. sqlalchemy/event/legacy.py +246 -0
  111. sqlalchemy/event/registry.py +386 -0
  112. sqlalchemy/events.py +17 -0
  113. sqlalchemy/exc.py +830 -0
  114. sqlalchemy/ext/__init__.py +11 -0
  115. sqlalchemy/ext/associationproxy.py +2013 -0
  116. sqlalchemy/ext/asyncio/__init__.py +25 -0
  117. sqlalchemy/ext/asyncio/base.py +279 -0
  118. sqlalchemy/ext/asyncio/engine.py +1466 -0
  119. sqlalchemy/ext/asyncio/exc.py +21 -0
  120. sqlalchemy/ext/asyncio/result.py +961 -0
  121. sqlalchemy/ext/asyncio/scoping.py +1614 -0
  122. sqlalchemy/ext/asyncio/session.py +1936 -0
  123. sqlalchemy/ext/automap.py +1691 -0
  124. sqlalchemy/ext/baked.py +574 -0
  125. sqlalchemy/ext/compiler.py +570 -0
  126. sqlalchemy/ext/declarative/__init__.py +65 -0
  127. sqlalchemy/ext/declarative/extensions.py +548 -0
  128. sqlalchemy/ext/horizontal_shard.py +481 -0
  129. sqlalchemy/ext/hybrid.py +1514 -0
  130. sqlalchemy/ext/indexable.py +341 -0
  131. sqlalchemy/ext/instrumentation.py +450 -0
  132. sqlalchemy/ext/mutable.py +1073 -0
  133. sqlalchemy/ext/mypy/__init__.py +6 -0
  134. sqlalchemy/ext/mypy/apply.py +320 -0
  135. sqlalchemy/ext/mypy/decl_class.py +515 -0
  136. sqlalchemy/ext/mypy/infer.py +590 -0
  137. sqlalchemy/ext/mypy/names.py +335 -0
  138. sqlalchemy/ext/mypy/plugin.py +303 -0
  139. sqlalchemy/ext/mypy/util.py +357 -0
  140. sqlalchemy/ext/orderinglist.py +416 -0
  141. sqlalchemy/ext/serializer.py +181 -0
  142. sqlalchemy/future/__init__.py +16 -0
  143. sqlalchemy/future/engine.py +15 -0
  144. sqlalchemy/inspection.py +174 -0
  145. sqlalchemy/log.py +288 -0
  146. sqlalchemy/orm/__init__.py +170 -0
  147. sqlalchemy/orm/_orm_constructors.py +2571 -0
  148. sqlalchemy/orm/_typing.py +179 -0
  149. sqlalchemy/orm/attributes.py +2835 -0
  150. sqlalchemy/orm/base.py +973 -0
  151. sqlalchemy/orm/bulk_persistence.py +2123 -0
  152. sqlalchemy/orm/clsregistry.py +571 -0
  153. sqlalchemy/orm/collections.py +1620 -0
  154. sqlalchemy/orm/context.py +3268 -0
  155. sqlalchemy/orm/decl_api.py +1883 -0
  156. sqlalchemy/orm/decl_base.py +2190 -0
  157. sqlalchemy/orm/dependency.py +1304 -0
  158. sqlalchemy/orm/descriptor_props.py +1076 -0
  159. sqlalchemy/orm/dynamic.py +300 -0
  160. sqlalchemy/orm/evaluator.py +379 -0
  161. sqlalchemy/orm/events.py +3261 -0
  162. sqlalchemy/orm/exc.py +228 -0
  163. sqlalchemy/orm/identity.py +302 -0
  164. sqlalchemy/orm/instrumentation.py +754 -0
  165. sqlalchemy/orm/interfaces.py +1474 -0
  166. sqlalchemy/orm/loading.py +1682 -0
  167. sqlalchemy/orm/mapped_collection.py +557 -0
  168. sqlalchemy/orm/mapper.py +4432 -0
  169. sqlalchemy/orm/path_registry.py +811 -0
  170. sqlalchemy/orm/persistence.py +1782 -0
  171. sqlalchemy/orm/properties.py +886 -0
  172. sqlalchemy/orm/query.py +3396 -0
  173. sqlalchemy/orm/relationships.py +3500 -0
  174. sqlalchemy/orm/scoping.py +2165 -0
  175. sqlalchemy/orm/session.py +5301 -0
  176. sqlalchemy/orm/state.py +1143 -0
  177. sqlalchemy/orm/state_changes.py +198 -0
  178. sqlalchemy/orm/strategies.py +3473 -0
  179. sqlalchemy/orm/strategy_options.py +2569 -0
  180. sqlalchemy/orm/sync.py +164 -0
  181. sqlalchemy/orm/unitofwork.py +796 -0
  182. sqlalchemy/orm/util.py +2424 -0
  183. sqlalchemy/orm/writeonly.py +678 -0
  184. sqlalchemy/pool/__init__.py +44 -0
  185. sqlalchemy/pool/base.py +1515 -0
  186. sqlalchemy/pool/events.py +370 -0
  187. sqlalchemy/pool/impl.py +581 -0
  188. sqlalchemy/py.typed +0 -0
  189. sqlalchemy/schema.py +70 -0
  190. sqlalchemy/sql/__init__.py +145 -0
  191. sqlalchemy/sql/_dml_constructors.py +140 -0
  192. sqlalchemy/sql/_elements_constructors.py +1850 -0
  193. sqlalchemy/sql/_orm_types.py +20 -0
  194. sqlalchemy/sql/_py_util.py +75 -0
  195. sqlalchemy/sql/_selectable_constructors.py +635 -0
  196. sqlalchemy/sql/_typing.py +460 -0
  197. sqlalchemy/sql/annotation.py +585 -0
  198. sqlalchemy/sql/base.py +2185 -0
  199. sqlalchemy/sql/cache_key.py +1057 -0
  200. sqlalchemy/sql/coercions.py +1405 -0
  201. sqlalchemy/sql/compiler.py +7818 -0
  202. sqlalchemy/sql/crud.py +1669 -0
  203. sqlalchemy/sql/ddl.py +1378 -0
  204. sqlalchemy/sql/default_comparator.py +552 -0
  205. sqlalchemy/sql/dml.py +1817 -0
  206. sqlalchemy/sql/elements.py +5499 -0
  207. sqlalchemy/sql/events.py +455 -0
  208. sqlalchemy/sql/expression.py +162 -0
  209. sqlalchemy/sql/functions.py +2055 -0
  210. sqlalchemy/sql/lambdas.py +1449 -0
  211. sqlalchemy/sql/naming.py +212 -0
  212. sqlalchemy/sql/operators.py +2579 -0
  213. sqlalchemy/sql/roles.py +323 -0
  214. sqlalchemy/sql/schema.py +6158 -0
  215. sqlalchemy/sql/selectable.py +7004 -0
  216. sqlalchemy/sql/sqltypes.py +3827 -0
  217. sqlalchemy/sql/traversals.py +1024 -0
  218. sqlalchemy/sql/type_api.py +2339 -0
  219. sqlalchemy/sql/util.py +1486 -0
  220. sqlalchemy/sql/visitors.py +1165 -0
  221. sqlalchemy/testing/__init__.py +96 -0
  222. sqlalchemy/testing/assertions.py +989 -0
  223. sqlalchemy/testing/assertsql.py +516 -0
  224. sqlalchemy/testing/asyncio.py +135 -0
  225. sqlalchemy/testing/config.py +427 -0
  226. sqlalchemy/testing/engines.py +472 -0
  227. sqlalchemy/testing/entities.py +117 -0
  228. sqlalchemy/testing/exclusions.py +435 -0
  229. sqlalchemy/testing/fixtures/__init__.py +28 -0
  230. sqlalchemy/testing/fixtures/base.py +366 -0
  231. sqlalchemy/testing/fixtures/mypy.py +312 -0
  232. sqlalchemy/testing/fixtures/orm.py +227 -0
  233. sqlalchemy/testing/fixtures/sql.py +503 -0
  234. sqlalchemy/testing/pickleable.py +155 -0
  235. sqlalchemy/testing/plugin/__init__.py +6 -0
  236. sqlalchemy/testing/plugin/bootstrap.py +51 -0
  237. sqlalchemy/testing/plugin/plugin_base.py +779 -0
  238. sqlalchemy/testing/plugin/pytestplugin.py +868 -0
  239. sqlalchemy/testing/profiling.py +324 -0
  240. sqlalchemy/testing/provision.py +496 -0
  241. sqlalchemy/testing/requirements.py +1818 -0
  242. sqlalchemy/testing/schema.py +224 -0
  243. sqlalchemy/testing/suite/__init__.py +19 -0
  244. sqlalchemy/testing/suite/test_cte.py +211 -0
  245. sqlalchemy/testing/suite/test_ddl.py +389 -0
  246. sqlalchemy/testing/suite/test_deprecations.py +153 -0
  247. sqlalchemy/testing/suite/test_dialect.py +740 -0
  248. sqlalchemy/testing/suite/test_insert.py +630 -0
  249. sqlalchemy/testing/suite/test_reflection.py +3225 -0
  250. sqlalchemy/testing/suite/test_results.py +502 -0
  251. sqlalchemy/testing/suite/test_rowcount.py +258 -0
  252. sqlalchemy/testing/suite/test_select.py +1999 -0
  253. sqlalchemy/testing/suite/test_sequence.py +317 -0
  254. sqlalchemy/testing/suite/test_types.py +2141 -0
  255. sqlalchemy/testing/suite/test_unicode_ddl.py +189 -0
  256. sqlalchemy/testing/suite/test_update_delete.py +139 -0
  257. sqlalchemy/testing/util.py +537 -0
  258. sqlalchemy/testing/warnings.py +52 -0
  259. sqlalchemy/types.py +76 -0
  260. sqlalchemy/util/__init__.py +160 -0
  261. sqlalchemy/util/_collections.py +715 -0
  262. sqlalchemy/util/_concurrency_py3k.py +288 -0
  263. sqlalchemy/util/_has_cy.py +40 -0
  264. sqlalchemy/util/_py_collections.py +541 -0
  265. sqlalchemy/util/compat.py +301 -0
  266. sqlalchemy/util/concurrency.py +108 -0
  267. sqlalchemy/util/deprecations.py +401 -0
  268. sqlalchemy/util/langhelpers.py +2218 -0
  269. sqlalchemy/util/preloaded.py +150 -0
  270. sqlalchemy/util/queue.py +322 -0
  271. sqlalchemy/util/tool_support.py +201 -0
  272. sqlalchemy/util/topological.py +120 -0
  273. sqlalchemy/util/typing.py +629 -0
@@ -0,0 +1,310 @@
1
+ # dialects/postgresql/dml.py
2
+ # Copyright (C) 2005-2024 the SQLAlchemy authors and contributors
3
+ # <see AUTHORS file>
4
+ #
5
+ # This module is part of SQLAlchemy and is released under
6
+ # the MIT License: https://www.opensource.org/licenses/mit-license.php
7
+ from __future__ import annotations
8
+
9
+ from typing import Any
10
+ from typing import Optional
11
+
12
+ from . import ext
13
+ from .._typing import _OnConflictConstraintT
14
+ from .._typing import _OnConflictIndexElementsT
15
+ from .._typing import _OnConflictIndexWhereT
16
+ from .._typing import _OnConflictSetT
17
+ from .._typing import _OnConflictWhereT
18
+ from ... import util
19
+ from ...sql import coercions
20
+ from ...sql import roles
21
+ from ...sql import schema
22
+ from ...sql._typing import _DMLTableArgument
23
+ from ...sql.base import _exclusive_against
24
+ from ...sql.base import _generative
25
+ from ...sql.base import ColumnCollection
26
+ from ...sql.base import ReadOnlyColumnCollection
27
+ from ...sql.dml import Insert as StandardInsert
28
+ from ...sql.elements import ClauseElement
29
+ from ...sql.elements import KeyedColumnElement
30
+ from ...sql.expression import alias
31
+ from ...util.typing import Self
32
+
33
+
34
+ __all__ = ("Insert", "insert")
35
+
36
+
37
+ def insert(table: _DMLTableArgument) -> Insert:
38
+ """Construct a PostgreSQL-specific variant :class:`_postgresql.Insert`
39
+ construct.
40
+
41
+ .. container:: inherited_member
42
+
43
+ The :func:`sqlalchemy.dialects.postgresql.insert` function creates
44
+ a :class:`sqlalchemy.dialects.postgresql.Insert`. This class is based
45
+ on the dialect-agnostic :class:`_sql.Insert` construct which may
46
+ be constructed using the :func:`_sql.insert` function in
47
+ SQLAlchemy Core.
48
+
49
+ The :class:`_postgresql.Insert` construct includes additional methods
50
+ :meth:`_postgresql.Insert.on_conflict_do_update`,
51
+ :meth:`_postgresql.Insert.on_conflict_do_nothing`.
52
+
53
+ """
54
+ return Insert(table)
55
+
56
+
57
+ class Insert(StandardInsert):
58
+ """PostgreSQL-specific implementation of INSERT.
59
+
60
+ Adds methods for PG-specific syntaxes such as ON CONFLICT.
61
+
62
+ The :class:`_postgresql.Insert` object is created using the
63
+ :func:`sqlalchemy.dialects.postgresql.insert` function.
64
+
65
+ """
66
+
67
+ stringify_dialect = "postgresql"
68
+ inherit_cache = False
69
+
70
+ @util.memoized_property
71
+ def excluded(
72
+ self,
73
+ ) -> ReadOnlyColumnCollection[str, KeyedColumnElement[Any]]:
74
+ """Provide the ``excluded`` namespace for an ON CONFLICT statement
75
+
76
+ PG's ON CONFLICT clause allows reference to the row that would
77
+ be inserted, known as ``excluded``. This attribute provides
78
+ all columns in this row to be referenceable.
79
+
80
+ .. tip:: The :attr:`_postgresql.Insert.excluded` attribute is an
81
+ instance of :class:`_expression.ColumnCollection`, which provides
82
+ an interface the same as that of the :attr:`_schema.Table.c`
83
+ collection described at :ref:`metadata_tables_and_columns`.
84
+ With this collection, ordinary names are accessible like attributes
85
+ (e.g. ``stmt.excluded.some_column``), but special names and
86
+ dictionary method names should be accessed using indexed access,
87
+ such as ``stmt.excluded["column name"]`` or
88
+ ``stmt.excluded["values"]``. See the docstring for
89
+ :class:`_expression.ColumnCollection` for further examples.
90
+
91
+ .. seealso::
92
+
93
+ :ref:`postgresql_insert_on_conflict` - example of how
94
+ to use :attr:`_expression.Insert.excluded`
95
+
96
+ """
97
+ return alias(self.table, name="excluded").columns
98
+
99
+ _on_conflict_exclusive = _exclusive_against(
100
+ "_post_values_clause",
101
+ msgs={
102
+ "_post_values_clause": "This Insert construct already has "
103
+ "an ON CONFLICT clause established"
104
+ },
105
+ )
106
+
107
+ @_generative
108
+ @_on_conflict_exclusive
109
+ def on_conflict_do_update(
110
+ self,
111
+ constraint: _OnConflictConstraintT = None,
112
+ index_elements: _OnConflictIndexElementsT = None,
113
+ index_where: _OnConflictIndexWhereT = None,
114
+ set_: _OnConflictSetT = None,
115
+ where: _OnConflictWhereT = None,
116
+ ) -> Self:
117
+ r"""
118
+ Specifies a DO UPDATE SET action for ON CONFLICT clause.
119
+
120
+ Either the ``constraint`` or ``index_elements`` argument is
121
+ required, but only one of these can be specified.
122
+
123
+ :param constraint:
124
+ The name of a unique or exclusion constraint on the table,
125
+ or the constraint object itself if it has a .name attribute.
126
+
127
+ :param index_elements:
128
+ A sequence consisting of string column names, :class:`_schema.Column`
129
+ objects, or other column expression objects that will be used
130
+ to infer a target index.
131
+
132
+ :param index_where:
133
+ Additional WHERE criterion that can be used to infer a
134
+ conditional target index.
135
+
136
+ :param set\_:
137
+ A dictionary or other mapping object
138
+ where the keys are either names of columns in the target table,
139
+ or :class:`_schema.Column` objects or other ORM-mapped columns
140
+ matching that of the target table, and expressions or literals
141
+ as values, specifying the ``SET`` actions to take.
142
+
143
+ .. versionadded:: 1.4 The
144
+ :paramref:`_postgresql.Insert.on_conflict_do_update.set_`
145
+ parameter supports :class:`_schema.Column` objects from the target
146
+ :class:`_schema.Table` as keys.
147
+
148
+ .. warning:: This dictionary does **not** take into account
149
+ Python-specified default UPDATE values or generation functions,
150
+ e.g. those specified using :paramref:`_schema.Column.onupdate`.
151
+ These values will not be exercised for an ON CONFLICT style of
152
+ UPDATE, unless they are manually specified in the
153
+ :paramref:`.Insert.on_conflict_do_update.set_` dictionary.
154
+
155
+ :param where:
156
+ Optional argument. If present, can be a literal SQL
157
+ string or an acceptable expression for a ``WHERE`` clause
158
+ that restricts the rows affected by ``DO UPDATE SET``. Rows
159
+ not meeting the ``WHERE`` condition will not be updated
160
+ (effectively a ``DO NOTHING`` for those rows).
161
+
162
+
163
+ .. seealso::
164
+
165
+ :ref:`postgresql_insert_on_conflict`
166
+
167
+ """
168
+ self._post_values_clause = OnConflictDoUpdate(
169
+ constraint, index_elements, index_where, set_, where
170
+ )
171
+ return self
172
+
173
+ @_generative
174
+ @_on_conflict_exclusive
175
+ def on_conflict_do_nothing(
176
+ self,
177
+ constraint: _OnConflictConstraintT = None,
178
+ index_elements: _OnConflictIndexElementsT = None,
179
+ index_where: _OnConflictIndexWhereT = None,
180
+ ) -> Self:
181
+ """
182
+ Specifies a DO NOTHING action for ON CONFLICT clause.
183
+
184
+ The ``constraint`` and ``index_elements`` arguments
185
+ are optional, but only one of these can be specified.
186
+
187
+ :param constraint:
188
+ The name of a unique or exclusion constraint on the table,
189
+ or the constraint object itself if it has a .name attribute.
190
+
191
+ :param index_elements:
192
+ A sequence consisting of string column names, :class:`_schema.Column`
193
+ objects, or other column expression objects that will be used
194
+ to infer a target index.
195
+
196
+ :param index_where:
197
+ Additional WHERE criterion that can be used to infer a
198
+ conditional target index.
199
+
200
+ .. seealso::
201
+
202
+ :ref:`postgresql_insert_on_conflict`
203
+
204
+ """
205
+ self._post_values_clause = OnConflictDoNothing(
206
+ constraint, index_elements, index_where
207
+ )
208
+ return self
209
+
210
+
211
+ class OnConflictClause(ClauseElement):
212
+ stringify_dialect = "postgresql"
213
+
214
+ constraint_target: Optional[str]
215
+ inferred_target_elements: _OnConflictIndexElementsT
216
+ inferred_target_whereclause: _OnConflictIndexWhereT
217
+
218
+ def __init__(
219
+ self,
220
+ constraint: _OnConflictConstraintT = None,
221
+ index_elements: _OnConflictIndexElementsT = None,
222
+ index_where: _OnConflictIndexWhereT = None,
223
+ ):
224
+ if constraint is not None:
225
+ if not isinstance(constraint, str) and isinstance(
226
+ constraint,
227
+ (schema.Constraint, ext.ExcludeConstraint),
228
+ ):
229
+ constraint = getattr(constraint, "name") or constraint
230
+
231
+ if constraint is not None:
232
+ if index_elements is not None:
233
+ raise ValueError(
234
+ "'constraint' and 'index_elements' are mutually exclusive"
235
+ )
236
+
237
+ if isinstance(constraint, str):
238
+ self.constraint_target = constraint
239
+ self.inferred_target_elements = None
240
+ self.inferred_target_whereclause = None
241
+ elif isinstance(constraint, schema.Index):
242
+ index_elements = constraint.expressions
243
+ index_where = constraint.dialect_options["postgresql"].get(
244
+ "where"
245
+ )
246
+ elif isinstance(constraint, ext.ExcludeConstraint):
247
+ index_elements = constraint.columns
248
+ index_where = constraint.where
249
+ else:
250
+ index_elements = constraint.columns
251
+ index_where = constraint.dialect_options["postgresql"].get(
252
+ "where"
253
+ )
254
+
255
+ if index_elements is not None:
256
+ self.constraint_target = None
257
+ self.inferred_target_elements = index_elements
258
+ self.inferred_target_whereclause = index_where
259
+ elif constraint is None:
260
+ self.constraint_target = self.inferred_target_elements = (
261
+ self.inferred_target_whereclause
262
+ ) = None
263
+
264
+
265
+ class OnConflictDoNothing(OnConflictClause):
266
+ __visit_name__ = "on_conflict_do_nothing"
267
+
268
+
269
+ class OnConflictDoUpdate(OnConflictClause):
270
+ __visit_name__ = "on_conflict_do_update"
271
+
272
+ def __init__(
273
+ self,
274
+ constraint: _OnConflictConstraintT = None,
275
+ index_elements: _OnConflictIndexElementsT = None,
276
+ index_where: _OnConflictIndexWhereT = None,
277
+ set_: _OnConflictSetT = None,
278
+ where: _OnConflictWhereT = None,
279
+ ):
280
+ super().__init__(
281
+ constraint=constraint,
282
+ index_elements=index_elements,
283
+ index_where=index_where,
284
+ )
285
+
286
+ if (
287
+ self.inferred_target_elements is None
288
+ and self.constraint_target is None
289
+ ):
290
+ raise ValueError(
291
+ "Either constraint or index_elements, "
292
+ "but not both, must be specified unless DO NOTHING"
293
+ )
294
+
295
+ if isinstance(set_, dict):
296
+ if not set_:
297
+ raise ValueError("set parameter dictionary must not be empty")
298
+ elif isinstance(set_, ColumnCollection):
299
+ set_ = dict(set_)
300
+ else:
301
+ raise ValueError(
302
+ "set parameter must be a non-empty dictionary "
303
+ "or a ColumnCollection such as the `.c.` collection "
304
+ "of a Table object"
305
+ )
306
+ self.update_values_to_set = [
307
+ (coercions.expect(roles.DMLColumnRole, key), value)
308
+ for key, value in set_.items()
309
+ ]
310
+ self.update_whereclause = where