SQLAlchemy 2.1.0b2__cp313-cp313t-win_arm64.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 (270) hide show
  1. sqlalchemy/__init__.py +298 -0
  2. sqlalchemy/connectors/__init__.py +18 -0
  3. sqlalchemy/connectors/aioodbc.py +171 -0
  4. sqlalchemy/connectors/asyncio.py +476 -0
  5. sqlalchemy/connectors/pyodbc.py +250 -0
  6. sqlalchemy/dialects/__init__.py +62 -0
  7. sqlalchemy/dialects/_typing.py +30 -0
  8. sqlalchemy/dialects/mssql/__init__.py +89 -0
  9. sqlalchemy/dialects/mssql/aioodbc.py +63 -0
  10. sqlalchemy/dialects/mssql/base.py +4166 -0
  11. sqlalchemy/dialects/mssql/information_schema.py +285 -0
  12. sqlalchemy/dialects/mssql/json.py +140 -0
  13. sqlalchemy/dialects/mssql/mssqlpython.py +220 -0
  14. sqlalchemy/dialects/mssql/provision.py +196 -0
  15. sqlalchemy/dialects/mssql/pymssql.py +126 -0
  16. sqlalchemy/dialects/mssql/pyodbc.py +698 -0
  17. sqlalchemy/dialects/mysql/__init__.py +106 -0
  18. sqlalchemy/dialects/mysql/_mariadb_shim.py +312 -0
  19. sqlalchemy/dialects/mysql/aiomysql.py +226 -0
  20. sqlalchemy/dialects/mysql/asyncmy.py +214 -0
  21. sqlalchemy/dialects/mysql/base.py +3877 -0
  22. sqlalchemy/dialects/mysql/cymysql.py +106 -0
  23. sqlalchemy/dialects/mysql/dml.py +279 -0
  24. sqlalchemy/dialects/mysql/enumerated.py +277 -0
  25. sqlalchemy/dialects/mysql/expression.py +146 -0
  26. sqlalchemy/dialects/mysql/json.py +92 -0
  27. sqlalchemy/dialects/mysql/mariadb.py +67 -0
  28. sqlalchemy/dialects/mysql/mariadbconnector.py +330 -0
  29. sqlalchemy/dialects/mysql/mysqlconnector.py +296 -0
  30. sqlalchemy/dialects/mysql/mysqldb.py +312 -0
  31. sqlalchemy/dialects/mysql/provision.py +153 -0
  32. sqlalchemy/dialects/mysql/pymysql.py +157 -0
  33. sqlalchemy/dialects/mysql/pyodbc.py +156 -0
  34. sqlalchemy/dialects/mysql/reflection.py +724 -0
  35. sqlalchemy/dialects/mysql/reserved_words.py +570 -0
  36. sqlalchemy/dialects/mysql/types.py +845 -0
  37. sqlalchemy/dialects/oracle/__init__.py +85 -0
  38. sqlalchemy/dialects/oracle/base.py +3977 -0
  39. sqlalchemy/dialects/oracle/cx_oracle.py +1601 -0
  40. sqlalchemy/dialects/oracle/dictionary.py +507 -0
  41. sqlalchemy/dialects/oracle/json.py +158 -0
  42. sqlalchemy/dialects/oracle/oracledb.py +909 -0
  43. sqlalchemy/dialects/oracle/provision.py +288 -0
  44. sqlalchemy/dialects/oracle/types.py +367 -0
  45. sqlalchemy/dialects/oracle/vector.py +368 -0
  46. sqlalchemy/dialects/postgresql/__init__.py +171 -0
  47. sqlalchemy/dialects/postgresql/_psycopg_common.py +229 -0
  48. sqlalchemy/dialects/postgresql/array.py +534 -0
  49. sqlalchemy/dialects/postgresql/asyncpg.py +1323 -0
  50. sqlalchemy/dialects/postgresql/base.py +5789 -0
  51. sqlalchemy/dialects/postgresql/bitstring.py +327 -0
  52. sqlalchemy/dialects/postgresql/dml.py +360 -0
  53. sqlalchemy/dialects/postgresql/ext.py +593 -0
  54. sqlalchemy/dialects/postgresql/hstore.py +423 -0
  55. sqlalchemy/dialects/postgresql/json.py +408 -0
  56. sqlalchemy/dialects/postgresql/named_types.py +521 -0
  57. sqlalchemy/dialects/postgresql/operators.py +130 -0
  58. sqlalchemy/dialects/postgresql/pg8000.py +670 -0
  59. sqlalchemy/dialects/postgresql/pg_catalog.py +344 -0
  60. sqlalchemy/dialects/postgresql/provision.py +184 -0
  61. sqlalchemy/dialects/postgresql/psycopg.py +799 -0
  62. sqlalchemy/dialects/postgresql/psycopg2.py +860 -0
  63. sqlalchemy/dialects/postgresql/psycopg2cffi.py +61 -0
  64. sqlalchemy/dialects/postgresql/ranges.py +1002 -0
  65. sqlalchemy/dialects/postgresql/types.py +388 -0
  66. sqlalchemy/dialects/sqlite/__init__.py +57 -0
  67. sqlalchemy/dialects/sqlite/aiosqlite.py +321 -0
  68. sqlalchemy/dialects/sqlite/base.py +3063 -0
  69. sqlalchemy/dialects/sqlite/dml.py +279 -0
  70. sqlalchemy/dialects/sqlite/json.py +100 -0
  71. sqlalchemy/dialects/sqlite/provision.py +229 -0
  72. sqlalchemy/dialects/sqlite/pysqlcipher.py +161 -0
  73. sqlalchemy/dialects/sqlite/pysqlite.py +754 -0
  74. sqlalchemy/dialects/type_migration_guidelines.txt +145 -0
  75. sqlalchemy/engine/__init__.py +62 -0
  76. sqlalchemy/engine/_processors_cy.cp313t-win_arm64.pyd +0 -0
  77. sqlalchemy/engine/_processors_cy.py +92 -0
  78. sqlalchemy/engine/_result_cy.cp313t-win_arm64.pyd +0 -0
  79. sqlalchemy/engine/_result_cy.py +633 -0
  80. sqlalchemy/engine/_row_cy.cp313t-win_arm64.pyd +0 -0
  81. sqlalchemy/engine/_row_cy.py +232 -0
  82. sqlalchemy/engine/_util_cy.cp313t-win_arm64.pyd +0 -0
  83. sqlalchemy/engine/_util_cy.py +136 -0
  84. sqlalchemy/engine/base.py +3354 -0
  85. sqlalchemy/engine/characteristics.py +155 -0
  86. sqlalchemy/engine/create.py +877 -0
  87. sqlalchemy/engine/cursor.py +2421 -0
  88. sqlalchemy/engine/default.py +2402 -0
  89. sqlalchemy/engine/events.py +965 -0
  90. sqlalchemy/engine/interfaces.py +3495 -0
  91. sqlalchemy/engine/mock.py +134 -0
  92. sqlalchemy/engine/processors.py +82 -0
  93. sqlalchemy/engine/reflection.py +2100 -0
  94. sqlalchemy/engine/result.py +1966 -0
  95. sqlalchemy/engine/row.py +397 -0
  96. sqlalchemy/engine/strategies.py +16 -0
  97. sqlalchemy/engine/url.py +922 -0
  98. sqlalchemy/engine/util.py +156 -0
  99. sqlalchemy/event/__init__.py +26 -0
  100. sqlalchemy/event/api.py +220 -0
  101. sqlalchemy/event/attr.py +674 -0
  102. sqlalchemy/event/base.py +472 -0
  103. sqlalchemy/event/legacy.py +258 -0
  104. sqlalchemy/event/registry.py +390 -0
  105. sqlalchemy/events.py +17 -0
  106. sqlalchemy/exc.py +922 -0
  107. sqlalchemy/ext/__init__.py +11 -0
  108. sqlalchemy/ext/associationproxy.py +2072 -0
  109. sqlalchemy/ext/asyncio/__init__.py +29 -0
  110. sqlalchemy/ext/asyncio/base.py +281 -0
  111. sqlalchemy/ext/asyncio/engine.py +1487 -0
  112. sqlalchemy/ext/asyncio/exc.py +21 -0
  113. sqlalchemy/ext/asyncio/result.py +994 -0
  114. sqlalchemy/ext/asyncio/scoping.py +1679 -0
  115. sqlalchemy/ext/asyncio/session.py +2007 -0
  116. sqlalchemy/ext/automap.py +1701 -0
  117. sqlalchemy/ext/baked.py +559 -0
  118. sqlalchemy/ext/compiler.py +600 -0
  119. sqlalchemy/ext/declarative/__init__.py +65 -0
  120. sqlalchemy/ext/declarative/extensions.py +560 -0
  121. sqlalchemy/ext/horizontal_shard.py +481 -0
  122. sqlalchemy/ext/hybrid.py +1877 -0
  123. sqlalchemy/ext/indexable.py +364 -0
  124. sqlalchemy/ext/instrumentation.py +450 -0
  125. sqlalchemy/ext/mutable.py +1081 -0
  126. sqlalchemy/ext/orderinglist.py +439 -0
  127. sqlalchemy/ext/serializer.py +185 -0
  128. sqlalchemy/future/__init__.py +16 -0
  129. sqlalchemy/future/engine.py +15 -0
  130. sqlalchemy/inspection.py +174 -0
  131. sqlalchemy/log.py +283 -0
  132. sqlalchemy/orm/__init__.py +176 -0
  133. sqlalchemy/orm/_orm_constructors.py +2694 -0
  134. sqlalchemy/orm/_typing.py +179 -0
  135. sqlalchemy/orm/attributes.py +2868 -0
  136. sqlalchemy/orm/base.py +976 -0
  137. sqlalchemy/orm/bulk_persistence.py +2152 -0
  138. sqlalchemy/orm/clsregistry.py +582 -0
  139. sqlalchemy/orm/collections.py +1568 -0
  140. sqlalchemy/orm/context.py +3471 -0
  141. sqlalchemy/orm/decl_api.py +2280 -0
  142. sqlalchemy/orm/decl_base.py +2309 -0
  143. sqlalchemy/orm/dependency.py +1306 -0
  144. sqlalchemy/orm/descriptor_props.py +1183 -0
  145. sqlalchemy/orm/dynamic.py +307 -0
  146. sqlalchemy/orm/evaluator.py +379 -0
  147. sqlalchemy/orm/events.py +3386 -0
  148. sqlalchemy/orm/exc.py +237 -0
  149. sqlalchemy/orm/identity.py +302 -0
  150. sqlalchemy/orm/instrumentation.py +746 -0
  151. sqlalchemy/orm/interfaces.py +1589 -0
  152. sqlalchemy/orm/loading.py +1684 -0
  153. sqlalchemy/orm/mapped_collection.py +557 -0
  154. sqlalchemy/orm/mapper.py +4411 -0
  155. sqlalchemy/orm/path_registry.py +829 -0
  156. sqlalchemy/orm/persistence.py +1789 -0
  157. sqlalchemy/orm/properties.py +973 -0
  158. sqlalchemy/orm/query.py +3528 -0
  159. sqlalchemy/orm/relationships.py +3570 -0
  160. sqlalchemy/orm/scoping.py +2232 -0
  161. sqlalchemy/orm/session.py +5403 -0
  162. sqlalchemy/orm/state.py +1175 -0
  163. sqlalchemy/orm/state_changes.py +196 -0
  164. sqlalchemy/orm/strategies.py +3492 -0
  165. sqlalchemy/orm/strategy_options.py +2562 -0
  166. sqlalchemy/orm/sync.py +164 -0
  167. sqlalchemy/orm/unitofwork.py +798 -0
  168. sqlalchemy/orm/util.py +2438 -0
  169. sqlalchemy/orm/writeonly.py +694 -0
  170. sqlalchemy/pool/__init__.py +41 -0
  171. sqlalchemy/pool/base.py +1522 -0
  172. sqlalchemy/pool/events.py +375 -0
  173. sqlalchemy/pool/impl.py +582 -0
  174. sqlalchemy/py.typed +0 -0
  175. sqlalchemy/schema.py +74 -0
  176. sqlalchemy/sql/__init__.py +156 -0
  177. sqlalchemy/sql/_annotated_cols.py +397 -0
  178. sqlalchemy/sql/_dml_constructors.py +132 -0
  179. sqlalchemy/sql/_elements_constructors.py +2164 -0
  180. sqlalchemy/sql/_orm_types.py +20 -0
  181. sqlalchemy/sql/_selectable_constructors.py +840 -0
  182. sqlalchemy/sql/_typing.py +487 -0
  183. sqlalchemy/sql/_util_cy.cp313t-win_arm64.pyd +0 -0
  184. sqlalchemy/sql/_util_cy.py +127 -0
  185. sqlalchemy/sql/annotation.py +590 -0
  186. sqlalchemy/sql/base.py +2699 -0
  187. sqlalchemy/sql/cache_key.py +1066 -0
  188. sqlalchemy/sql/coercions.py +1373 -0
  189. sqlalchemy/sql/compiler.py +8327 -0
  190. sqlalchemy/sql/crud.py +1815 -0
  191. sqlalchemy/sql/ddl.py +1928 -0
  192. sqlalchemy/sql/default_comparator.py +654 -0
  193. sqlalchemy/sql/dml.py +1977 -0
  194. sqlalchemy/sql/elements.py +6033 -0
  195. sqlalchemy/sql/events.py +458 -0
  196. sqlalchemy/sql/expression.py +172 -0
  197. sqlalchemy/sql/functions.py +2305 -0
  198. sqlalchemy/sql/lambdas.py +1443 -0
  199. sqlalchemy/sql/naming.py +209 -0
  200. sqlalchemy/sql/operators.py +2897 -0
  201. sqlalchemy/sql/roles.py +332 -0
  202. sqlalchemy/sql/schema.py +6703 -0
  203. sqlalchemy/sql/selectable.py +7553 -0
  204. sqlalchemy/sql/sqltypes.py +4093 -0
  205. sqlalchemy/sql/traversals.py +1042 -0
  206. sqlalchemy/sql/type_api.py +2446 -0
  207. sqlalchemy/sql/util.py +1495 -0
  208. sqlalchemy/sql/visitors.py +1157 -0
  209. sqlalchemy/testing/__init__.py +96 -0
  210. sqlalchemy/testing/assertions.py +1007 -0
  211. sqlalchemy/testing/assertsql.py +519 -0
  212. sqlalchemy/testing/asyncio.py +128 -0
  213. sqlalchemy/testing/config.py +440 -0
  214. sqlalchemy/testing/engines.py +483 -0
  215. sqlalchemy/testing/entities.py +117 -0
  216. sqlalchemy/testing/exclusions.py +476 -0
  217. sqlalchemy/testing/fixtures/__init__.py +30 -0
  218. sqlalchemy/testing/fixtures/base.py +384 -0
  219. sqlalchemy/testing/fixtures/mypy.py +247 -0
  220. sqlalchemy/testing/fixtures/orm.py +227 -0
  221. sqlalchemy/testing/fixtures/sql.py +538 -0
  222. sqlalchemy/testing/pickleable.py +155 -0
  223. sqlalchemy/testing/plugin/__init__.py +6 -0
  224. sqlalchemy/testing/plugin/bootstrap.py +51 -0
  225. sqlalchemy/testing/plugin/plugin_base.py +828 -0
  226. sqlalchemy/testing/plugin/pytestplugin.py +892 -0
  227. sqlalchemy/testing/profiling.py +329 -0
  228. sqlalchemy/testing/provision.py +613 -0
  229. sqlalchemy/testing/requirements.py +1978 -0
  230. sqlalchemy/testing/schema.py +198 -0
  231. sqlalchemy/testing/suite/__init__.py +19 -0
  232. sqlalchemy/testing/suite/test_cte.py +237 -0
  233. sqlalchemy/testing/suite/test_ddl.py +420 -0
  234. sqlalchemy/testing/suite/test_dialect.py +776 -0
  235. sqlalchemy/testing/suite/test_insert.py +630 -0
  236. sqlalchemy/testing/suite/test_reflection.py +3557 -0
  237. sqlalchemy/testing/suite/test_results.py +660 -0
  238. sqlalchemy/testing/suite/test_rowcount.py +258 -0
  239. sqlalchemy/testing/suite/test_select.py +2112 -0
  240. sqlalchemy/testing/suite/test_sequence.py +317 -0
  241. sqlalchemy/testing/suite/test_table_via_select.py +686 -0
  242. sqlalchemy/testing/suite/test_types.py +2271 -0
  243. sqlalchemy/testing/suite/test_unicode_ddl.py +189 -0
  244. sqlalchemy/testing/suite/test_update_delete.py +139 -0
  245. sqlalchemy/testing/util.py +535 -0
  246. sqlalchemy/testing/warnings.py +52 -0
  247. sqlalchemy/types.py +76 -0
  248. sqlalchemy/util/__init__.py +158 -0
  249. sqlalchemy/util/_collections.py +688 -0
  250. sqlalchemy/util/_collections_cy.cp313t-win_arm64.pyd +0 -0
  251. sqlalchemy/util/_collections_cy.pxd +8 -0
  252. sqlalchemy/util/_collections_cy.py +516 -0
  253. sqlalchemy/util/_has_cython.py +46 -0
  254. sqlalchemy/util/_immutabledict_cy.cp313t-win_arm64.pyd +0 -0
  255. sqlalchemy/util/_immutabledict_cy.py +240 -0
  256. sqlalchemy/util/compat.py +299 -0
  257. sqlalchemy/util/concurrency.py +322 -0
  258. sqlalchemy/util/cython.py +79 -0
  259. sqlalchemy/util/deprecations.py +401 -0
  260. sqlalchemy/util/langhelpers.py +2320 -0
  261. sqlalchemy/util/preloaded.py +152 -0
  262. sqlalchemy/util/queue.py +304 -0
  263. sqlalchemy/util/tool_support.py +201 -0
  264. sqlalchemy/util/topological.py +120 -0
  265. sqlalchemy/util/typing.py +711 -0
  266. sqlalchemy-2.1.0b2.dist-info/METADATA +269 -0
  267. sqlalchemy-2.1.0b2.dist-info/RECORD +270 -0
  268. sqlalchemy-2.1.0b2.dist-info/WHEEL +5 -0
  269. sqlalchemy-2.1.0b2.dist-info/licenses/LICENSE +19 -0
  270. sqlalchemy-2.1.0b2.dist-info/top_level.txt +1 -0
@@ -0,0 +1,593 @@
1
+ # dialects/postgresql/ext.py
2
+ # Copyright (C) 2005-2026 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
+ # mypy: ignore-errors
8
+ from __future__ import annotations
9
+
10
+ from typing import Any
11
+ from typing import Iterable
12
+ from typing import List
13
+ from typing import Optional
14
+ from typing import overload
15
+ from typing import Sequence
16
+ from typing import Tuple
17
+ from typing import TYPE_CHECKING
18
+ from typing import TypeVar
19
+
20
+ from . import types
21
+ from .array import ARRAY
22
+ from ... import exc
23
+ from ...sql import coercions
24
+ from ...sql import elements
25
+ from ...sql import expression
26
+ from ...sql import functions
27
+ from ...sql import roles
28
+ from ...sql import schema
29
+ from ...sql.base import SyntaxExtension
30
+ from ...sql.schema import ColumnCollectionConstraint
31
+ from ...sql.sqltypes import TEXT
32
+ from ...sql.visitors import InternalTraversal
33
+
34
+ if TYPE_CHECKING:
35
+ from ...sql._typing import _ColumnExpressionArgument
36
+ from ...sql._typing import _DDLColumnArgument
37
+ from ...sql.elements import ClauseElement
38
+ from ...sql.elements import ColumnElement
39
+ from ...sql.operators import OperatorType
40
+ from ...sql.selectable import FromClause
41
+ from ...sql.visitors import _CloneCallableType
42
+ from ...sql.visitors import _TraverseInternalsType
43
+
44
+ _T = TypeVar("_T", bound=Any)
45
+
46
+
47
+ class aggregate_order_by(expression.ColumnElement[_T]):
48
+ """Represent a PostgreSQL aggregate order by expression.
49
+
50
+ E.g.::
51
+
52
+ from sqlalchemy.dialects.postgresql import aggregate_order_by
53
+
54
+ expr = func.array_agg(aggregate_order_by(table.c.a, table.c.b.desc()))
55
+ stmt = select(expr)
56
+
57
+ would represent the expression:
58
+
59
+ .. sourcecode:: sql
60
+
61
+ SELECT array_agg(a ORDER BY b DESC) FROM table;
62
+
63
+ .. legacy:: An improved dialect-agnostic form of this function is now
64
+ available in Core by calling the
65
+ :meth:`_functions.Function.aggregate_order_by` method on any function
66
+ defined by the backend as an aggregate function.
67
+
68
+ .. seealso::
69
+
70
+ :func:`_sql.aggregate_order_by` - Core level function
71
+
72
+ :class:`_functions.array_agg`
73
+
74
+ """
75
+
76
+ __visit_name__ = "aggregate_order_by"
77
+
78
+ stringify_dialect = "postgresql"
79
+ _traverse_internals: _TraverseInternalsType = [
80
+ ("target", InternalTraversal.dp_clauseelement),
81
+ ("type", InternalTraversal.dp_type),
82
+ ("order_by", InternalTraversal.dp_clauseelement),
83
+ ]
84
+
85
+ @overload
86
+ def __init__(
87
+ self,
88
+ target: ColumnElement[_T],
89
+ *order_by: _ColumnExpressionArgument[Any],
90
+ ): ...
91
+
92
+ @overload
93
+ def __init__(
94
+ self,
95
+ target: _ColumnExpressionArgument[_T],
96
+ *order_by: _ColumnExpressionArgument[Any],
97
+ ): ...
98
+
99
+ def __init__(
100
+ self,
101
+ target: _ColumnExpressionArgument[_T],
102
+ *order_by: _ColumnExpressionArgument[Any],
103
+ ):
104
+ self.target: ClauseElement = coercions.expect(
105
+ roles.ExpressionElementRole, target
106
+ )
107
+ self.type = self.target.type
108
+
109
+ _lob = len(order_by)
110
+ self.order_by: ClauseElement
111
+ if _lob == 0:
112
+ raise TypeError("at least one ORDER BY element is required")
113
+ elif _lob == 1:
114
+ self.order_by = coercions.expect(
115
+ roles.ExpressionElementRole, order_by[0]
116
+ )
117
+ else:
118
+ self.order_by = elements.ClauseList(
119
+ *order_by, _literal_as_text_role=roles.ExpressionElementRole
120
+ )
121
+
122
+ def self_group(
123
+ self, against: Optional[OperatorType] = None
124
+ ) -> ClauseElement:
125
+ return self
126
+
127
+ def get_children(self, **kwargs: Any) -> Iterable[ClauseElement]:
128
+ return self.target, self.order_by
129
+
130
+ def _copy_internals(
131
+ self, clone: _CloneCallableType = elements._clone, **kw: Any
132
+ ) -> None:
133
+ self.target = clone(self.target, **kw)
134
+ self.order_by = clone(self.order_by, **kw)
135
+
136
+ @property
137
+ def _from_objects(self) -> List[FromClause]:
138
+ return self.target._from_objects + self.order_by._from_objects
139
+
140
+
141
+ class ExcludeConstraint(ColumnCollectionConstraint):
142
+ """A table-level EXCLUDE constraint.
143
+
144
+ Defines an EXCLUDE constraint as described in the `PostgreSQL
145
+ documentation`__.
146
+
147
+ __ https://www.postgresql.org/docs/current/static/sql-createtable.html#SQL-CREATETABLE-EXCLUDE
148
+
149
+ """ # noqa
150
+
151
+ __visit_name__ = "exclude_constraint"
152
+
153
+ where = None
154
+ inherit_cache = False
155
+
156
+ create_drop_stringify_dialect = "postgresql"
157
+
158
+ @elements._document_text_coercion(
159
+ "where",
160
+ ":class:`.ExcludeConstraint`",
161
+ ":paramref:`.ExcludeConstraint.where`",
162
+ )
163
+ def __init__(
164
+ self, *elements: Tuple[_DDLColumnArgument, str], **kw: Any
165
+ ) -> None:
166
+ r"""
167
+ Create an :class:`.ExcludeConstraint` object.
168
+
169
+ E.g.::
170
+
171
+ const = ExcludeConstraint(
172
+ (Column("period"), "&&"),
173
+ (Column("group"), "="),
174
+ where=(Column("group") != "some group"),
175
+ ops={"group": "my_operator_class"},
176
+ )
177
+
178
+ The constraint is normally embedded into the :class:`_schema.Table`
179
+ construct
180
+ directly, or added later using :meth:`.append_constraint`::
181
+
182
+ some_table = Table(
183
+ "some_table",
184
+ metadata,
185
+ Column("id", Integer, primary_key=True),
186
+ Column("period", TSRANGE()),
187
+ Column("group", String),
188
+ )
189
+
190
+ some_table.append_constraint(
191
+ ExcludeConstraint(
192
+ (some_table.c.period, "&&"),
193
+ (some_table.c.group, "="),
194
+ where=some_table.c.group != "some group",
195
+ name="some_table_excl_const",
196
+ ops={"group": "my_operator_class"},
197
+ )
198
+ )
199
+
200
+ The exclude constraint defined in this example requires the
201
+ ``btree_gist`` extension, that can be created using the
202
+ command ``CREATE EXTENSION btree_gist;``.
203
+
204
+ :param \*elements:
205
+
206
+ A sequence of two tuples of the form ``(column, operator)`` where
207
+ "column" is either a :class:`_schema.Column` object, or a SQL
208
+ expression element (e.g. ``func.int8range(table.from, table.to)``)
209
+ or the name of a column as string, and "operator" is a string
210
+ containing the operator to use (e.g. `"&&"` or `"="`).
211
+
212
+ In order to specify a column name when a :class:`_schema.Column`
213
+ object is not available, while ensuring
214
+ that any necessary quoting rules take effect, an ad-hoc
215
+ :class:`_schema.Column` or :func:`_expression.column`
216
+ object should be used.
217
+ The ``column`` may also be a string SQL expression when
218
+ passed as :func:`_expression.literal_column` or
219
+ :func:`_expression.text`
220
+
221
+ :param name:
222
+ Optional, the in-database name of this constraint.
223
+
224
+ :param deferrable:
225
+ Optional bool. If set, emit DEFERRABLE or NOT DEFERRABLE when
226
+ issuing DDL for this constraint.
227
+
228
+ :param initially:
229
+ Optional string. If set, emit INITIALLY <value> when issuing DDL
230
+ for this constraint.
231
+
232
+ :param using:
233
+ Optional string. If set, emit USING <index_method> when issuing DDL
234
+ for this constraint. Defaults to 'gist'.
235
+
236
+ :param where:
237
+ Optional SQL expression construct or literal SQL string.
238
+ If set, emit WHERE <predicate> when issuing DDL
239
+ for this constraint.
240
+
241
+ :param ops:
242
+ Optional dictionary. Used to define operator classes for the
243
+ elements; works the same way as that of the
244
+ :ref:`postgresql_ops <postgresql_operator_classes>`
245
+ parameter specified to the :class:`_schema.Index` construct.
246
+
247
+ .. seealso::
248
+
249
+ :ref:`postgresql_operator_classes` - general description of how
250
+ PostgreSQL operator classes are specified.
251
+
252
+ """
253
+ columns = []
254
+ render_exprs = []
255
+ self.operators = {}
256
+
257
+ expressions, operators = zip(*elements)
258
+
259
+ for (expr, column, strname, add_element), operator in zip(
260
+ coercions.expect_col_expression_collection(
261
+ roles.DDLConstraintColumnRole, expressions
262
+ ),
263
+ operators,
264
+ ):
265
+ if add_element is not None:
266
+ columns.append(add_element)
267
+
268
+ name = column.name if column is not None else strname
269
+
270
+ if name is not None:
271
+ # backwards compat
272
+ self.operators[name] = operator
273
+
274
+ render_exprs.append((expr, name, operator))
275
+
276
+ self._render_exprs = render_exprs
277
+
278
+ ColumnCollectionConstraint.__init__(
279
+ self,
280
+ *columns,
281
+ name=kw.get("name"),
282
+ deferrable=kw.get("deferrable"),
283
+ initially=kw.get("initially"),
284
+ )
285
+ self.using = kw.get("using", "gist")
286
+ where = kw.get("where")
287
+ if where is not None:
288
+ self.where = coercions.expect(roles.StatementOptionRole, where)
289
+
290
+ self.ops = kw.get("ops", {})
291
+
292
+ def _set_parent(self, table, **kw):
293
+ super()._set_parent(table)
294
+
295
+ self._render_exprs = [
296
+ (
297
+ expr if not isinstance(expr, str) else table.c[expr],
298
+ name,
299
+ operator,
300
+ )
301
+ for expr, name, operator in (self._render_exprs)
302
+ ]
303
+
304
+ def _copy(self, target_table=None, **kw):
305
+ elements = [
306
+ (
307
+ schema._copy_expression(expr, self.parent, target_table),
308
+ operator,
309
+ )
310
+ for expr, _, operator in self._render_exprs
311
+ ]
312
+ c = self.__class__(
313
+ *elements,
314
+ name=self.name,
315
+ deferrable=self.deferrable,
316
+ initially=self.initially,
317
+ where=self.where,
318
+ using=self.using,
319
+ )
320
+ c.dispatch._update(self.dispatch)
321
+ return c
322
+
323
+
324
+ def array_agg(*arg, **kw):
325
+ """PostgreSQL-specific form of :class:`_functions.array_agg`, ensures
326
+ return type is :class:`_postgresql.ARRAY` and not
327
+ the plain :class:`_types.ARRAY`, unless an explicit ``type_``
328
+ is passed.
329
+
330
+ """
331
+ kw["_default_array_type"] = ARRAY
332
+ return functions.func.array_agg(*arg, **kw)
333
+
334
+
335
+ class _regconfig_fn(functions.GenericFunction[_T]):
336
+ inherit_cache = True
337
+
338
+ def __init__(self, *args, **kwargs):
339
+ args = list(args)
340
+ if len(args) > 1:
341
+ initial_arg = coercions.expect(
342
+ roles.ExpressionElementRole,
343
+ args.pop(0),
344
+ name=getattr(self, "name", None),
345
+ apply_propagate_attrs=self,
346
+ type_=types.REGCONFIG,
347
+ )
348
+ initial_arg = [initial_arg]
349
+ else:
350
+ initial_arg = []
351
+
352
+ addtl_args = [
353
+ coercions.expect(
354
+ roles.ExpressionElementRole,
355
+ c,
356
+ name=getattr(self, "name", None),
357
+ apply_propagate_attrs=self,
358
+ )
359
+ for c in args
360
+ ]
361
+ super().__init__(*(initial_arg + addtl_args), **kwargs)
362
+
363
+
364
+ class to_tsvector(_regconfig_fn):
365
+ """The PostgreSQL ``to_tsvector`` SQL function.
366
+
367
+ This function applies automatic casting of the REGCONFIG argument
368
+ to use the :class:`_postgresql.REGCONFIG` datatype automatically,
369
+ and applies a return type of :class:`_postgresql.TSVECTOR`.
370
+
371
+ Assuming the PostgreSQL dialect has been imported, either by invoking
372
+ ``from sqlalchemy.dialects import postgresql``, or by creating a PostgreSQL
373
+ engine using ``create_engine("postgresql...")``,
374
+ :class:`_postgresql.to_tsvector` will be used automatically when invoking
375
+ ``sqlalchemy.func.to_tsvector()``, ensuring the correct argument and return
376
+ type handlers are used at compile and execution time.
377
+
378
+ .. versionadded:: 2.0.0rc1
379
+
380
+ """
381
+
382
+ inherit_cache = True
383
+ type = types.TSVECTOR
384
+
385
+
386
+ class to_tsquery(_regconfig_fn):
387
+ """The PostgreSQL ``to_tsquery`` SQL function.
388
+
389
+ This function applies automatic casting of the REGCONFIG argument
390
+ to use the :class:`_postgresql.REGCONFIG` datatype automatically,
391
+ and applies a return type of :class:`_postgresql.TSQUERY`.
392
+
393
+ Assuming the PostgreSQL dialect has been imported, either by invoking
394
+ ``from sqlalchemy.dialects import postgresql``, or by creating a PostgreSQL
395
+ engine using ``create_engine("postgresql...")``,
396
+ :class:`_postgresql.to_tsquery` will be used automatically when invoking
397
+ ``sqlalchemy.func.to_tsquery()``, ensuring the correct argument and return
398
+ type handlers are used at compile and execution time.
399
+
400
+ .. versionadded:: 2.0.0rc1
401
+
402
+ """
403
+
404
+ inherit_cache = True
405
+ type = types.TSQUERY
406
+
407
+
408
+ class plainto_tsquery(_regconfig_fn):
409
+ """The PostgreSQL ``plainto_tsquery`` SQL function.
410
+
411
+ This function applies automatic casting of the REGCONFIG argument
412
+ to use the :class:`_postgresql.REGCONFIG` datatype automatically,
413
+ and applies a return type of :class:`_postgresql.TSQUERY`.
414
+
415
+ Assuming the PostgreSQL dialect has been imported, either by invoking
416
+ ``from sqlalchemy.dialects import postgresql``, or by creating a PostgreSQL
417
+ engine using ``create_engine("postgresql...")``,
418
+ :class:`_postgresql.plainto_tsquery` will be used automatically when
419
+ invoking ``sqlalchemy.func.plainto_tsquery()``, ensuring the correct
420
+ argument and return type handlers are used at compile and execution time.
421
+
422
+ .. versionadded:: 2.0.0rc1
423
+
424
+ """
425
+
426
+ inherit_cache = True
427
+ type = types.TSQUERY
428
+
429
+
430
+ class phraseto_tsquery(_regconfig_fn):
431
+ """The PostgreSQL ``phraseto_tsquery`` SQL function.
432
+
433
+ This function applies automatic casting of the REGCONFIG argument
434
+ to use the :class:`_postgresql.REGCONFIG` datatype automatically,
435
+ and applies a return type of :class:`_postgresql.TSQUERY`.
436
+
437
+ Assuming the PostgreSQL dialect has been imported, either by invoking
438
+ ``from sqlalchemy.dialects import postgresql``, or by creating a PostgreSQL
439
+ engine using ``create_engine("postgresql...")``,
440
+ :class:`_postgresql.phraseto_tsquery` will be used automatically when
441
+ invoking ``sqlalchemy.func.phraseto_tsquery()``, ensuring the correct
442
+ argument and return type handlers are used at compile and execution time.
443
+
444
+ .. versionadded:: 2.0.0rc1
445
+
446
+ """
447
+
448
+ inherit_cache = True
449
+ type = types.TSQUERY
450
+
451
+
452
+ class websearch_to_tsquery(_regconfig_fn):
453
+ """The PostgreSQL ``websearch_to_tsquery`` SQL function.
454
+
455
+ This function applies automatic casting of the REGCONFIG argument
456
+ to use the :class:`_postgresql.REGCONFIG` datatype automatically,
457
+ and applies a return type of :class:`_postgresql.TSQUERY`.
458
+
459
+ Assuming the PostgreSQL dialect has been imported, either by invoking
460
+ ``from sqlalchemy.dialects import postgresql``, or by creating a PostgreSQL
461
+ engine using ``create_engine("postgresql...")``,
462
+ :class:`_postgresql.websearch_to_tsquery` will be used automatically when
463
+ invoking ``sqlalchemy.func.websearch_to_tsquery()``, ensuring the correct
464
+ argument and return type handlers are used at compile and execution time.
465
+
466
+ .. versionadded:: 2.0.0rc1
467
+
468
+ """
469
+
470
+ inherit_cache = True
471
+ type = types.TSQUERY
472
+
473
+
474
+ class ts_headline(_regconfig_fn):
475
+ """The PostgreSQL ``ts_headline`` SQL function.
476
+
477
+ This function applies automatic casting of the REGCONFIG argument
478
+ to use the :class:`_postgresql.REGCONFIG` datatype automatically,
479
+ and applies a return type of :class:`_types.TEXT`.
480
+
481
+ Assuming the PostgreSQL dialect has been imported, either by invoking
482
+ ``from sqlalchemy.dialects import postgresql``, or by creating a PostgreSQL
483
+ engine using ``create_engine("postgresql...")``,
484
+ :class:`_postgresql.ts_headline` will be used automatically when invoking
485
+ ``sqlalchemy.func.ts_headline()``, ensuring the correct argument and return
486
+ type handlers are used at compile and execution time.
487
+
488
+ .. versionadded:: 2.0.0rc1
489
+
490
+ """
491
+
492
+ inherit_cache = True
493
+ type = TEXT
494
+
495
+ def __init__(self, *args, **kwargs):
496
+ args = list(args)
497
+
498
+ # parse types according to
499
+ # https://www.postgresql.org/docs/current/textsearch-controls.html#TEXTSEARCH-HEADLINE
500
+ if len(args) < 2:
501
+ # invalid args; don't do anything
502
+ has_regconfig = False
503
+ elif (
504
+ isinstance(args[1], elements.ColumnElement)
505
+ and args[1].type._type_affinity is types.TSQUERY
506
+ ):
507
+ # tsquery is second argument, no regconfig argument
508
+ has_regconfig = False
509
+ else:
510
+ has_regconfig = True
511
+
512
+ if has_regconfig:
513
+ initial_arg = coercions.expect(
514
+ roles.ExpressionElementRole,
515
+ args.pop(0),
516
+ apply_propagate_attrs=self,
517
+ name=getattr(self, "name", None),
518
+ type_=types.REGCONFIG,
519
+ )
520
+ initial_arg = [initial_arg]
521
+ else:
522
+ initial_arg = []
523
+
524
+ addtl_args = [
525
+ coercions.expect(
526
+ roles.ExpressionElementRole,
527
+ c,
528
+ name=getattr(self, "name", None),
529
+ apply_propagate_attrs=self,
530
+ )
531
+ for c in args
532
+ ]
533
+ super().__init__(*(initial_arg + addtl_args), **kwargs)
534
+
535
+
536
+ def distinct_on(*expr: _ColumnExpressionArgument[Any]) -> DistinctOnClause:
537
+ """apply a DISTINCT_ON to a SELECT statement
538
+
539
+ e.g.::
540
+
541
+ stmt = select(tbl).ext(distinct_on(t.c.some_col))
542
+
543
+ this supersedes the previous approach of using
544
+ ``select(tbl).distinct(t.c.some_col))`` to apply a similar construct.
545
+
546
+ .. versionadded:: 2.1
547
+
548
+ """
549
+ return DistinctOnClause(expr)
550
+
551
+
552
+ class DistinctOnClause(SyntaxExtension, expression.ClauseElement):
553
+ stringify_dialect = "postgresql"
554
+ __visit_name__ = "postgresql_distinct_on"
555
+
556
+ _traverse_internals: _TraverseInternalsType = [
557
+ ("_distinct_on", InternalTraversal.dp_clauseelement_tuple),
558
+ ]
559
+
560
+ def __init__(self, distinct_on: Sequence[_ColumnExpressionArgument[Any]]):
561
+ self._distinct_on = tuple(
562
+ coercions.expect(roles.ByOfRole, e, apply_propagate_attrs=self)
563
+ for e in distinct_on
564
+ )
565
+
566
+ def apply_to_select(self, select_stmt: expression.Select[Any]) -> None:
567
+ if select_stmt._distinct_on:
568
+ raise exc.InvalidRequestError(
569
+ "Cannot mix ``select.ext(distinct_on(...))`` and "
570
+ "``select.distinct(...)``"
571
+ )
572
+ # mark this select as a distinct
573
+ select_stmt.distinct.non_generative(select_stmt)
574
+
575
+ select_stmt.apply_syntax_extension_point(
576
+ self._merge_other_distinct, "pre_columns"
577
+ )
578
+
579
+ def _merge_other_distinct(
580
+ self, existing: Sequence[elements.ClauseElement]
581
+ ) -> Sequence[elements.ClauseElement]:
582
+ res = []
583
+ to_merge = ()
584
+ for e in existing:
585
+ if isinstance(e, DistinctOnClause):
586
+ to_merge += e._distinct_on
587
+ else:
588
+ res.append(e)
589
+ if to_merge:
590
+ res.append(DistinctOnClause(to_merge + self._distinct_on))
591
+ else:
592
+ res.append(self)
593
+ return res