SQLAlchemy 2.1.0rc1__cp315-cp315-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 (276) hide show
  1. sqlalchemy/__init__.py +299 -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 +248 -0
  6. sqlalchemy/dialects/__init__.py +62 -0
  7. sqlalchemy/dialects/_typing.py +29 -0
  8. sqlalchemy/dialects/mssql/__init__.py +88 -0
  9. sqlalchemy/dialects/mssql/aioodbc.py +63 -0
  10. sqlalchemy/dialects/mssql/base.py +4833 -0
  11. sqlalchemy/dialects/mssql/information_schema.py +345 -0
  12. sqlalchemy/dialects/mssql/json.py +140 -0
  13. sqlalchemy/dialects/mssql/mssqlpython.py +242 -0
  14. sqlalchemy/dialects/mssql/provision.py +196 -0
  15. sqlalchemy/dialects/mssql/pymssql.py +130 -0
  16. sqlalchemy/dialects/mssql/pyodbc.py +697 -0
  17. sqlalchemy/dialects/mysql/__init__.py +106 -0
  18. sqlalchemy/dialects/mysql/_mariadb_shim.py +312 -0
  19. sqlalchemy/dialects/mysql/aiomysql.py +260 -0
  20. sqlalchemy/dialects/mysql/asyncmy.py +241 -0
  21. sqlalchemy/dialects/mysql/base.py +3896 -0
  22. sqlalchemy/dialects/mysql/cymysql.py +107 -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 +314 -0
  29. sqlalchemy/dialects/mysql/mysqlconnector.py +291 -0
  30. sqlalchemy/dialects/mysql/mysqldb.py +318 -0
  31. sqlalchemy/dialects/mysql/provision.py +153 -0
  32. sqlalchemy/dialects/mysql/pymysql.py +188 -0
  33. sqlalchemy/dialects/mysql/pyodbc.py +157 -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 +3847 -0
  39. sqlalchemy/dialects/oracle/cx_oracle.py +1736 -0
  40. sqlalchemy/dialects/oracle/dictionary.py +507 -0
  41. sqlalchemy/dialects/oracle/json.py +157 -0
  42. sqlalchemy/dialects/oracle/oracledb.py +898 -0
  43. sqlalchemy/dialects/oracle/provision.py +288 -0
  44. sqlalchemy/dialects/oracle/types.py +367 -0
  45. sqlalchemy/dialects/oracle/vector.py +366 -0
  46. sqlalchemy/dialects/postgresql/__init__.py +170 -0
  47. sqlalchemy/dialects/postgresql/_psycopg_common.py +232 -0
  48. sqlalchemy/dialects/postgresql/array.py +534 -0
  49. sqlalchemy/dialects/postgresql/asyncpg.py +1318 -0
  50. sqlalchemy/dialects/postgresql/base.py +5935 -0
  51. sqlalchemy/dialects/postgresql/bitstring.py +327 -0
  52. sqlalchemy/dialects/postgresql/dml.py +360 -0
  53. sqlalchemy/dialects/postgresql/ext.py +599 -0
  54. sqlalchemy/dialects/postgresql/hstore.py +422 -0
  55. sqlalchemy/dialects/postgresql/json.py +411 -0
  56. sqlalchemy/dialects/postgresql/named_types.py +535 -0
  57. sqlalchemy/dialects/postgresql/operators.py +129 -0
  58. sqlalchemy/dialects/postgresql/pg8000.py +655 -0
  59. sqlalchemy/dialects/postgresql/pg_catalog.py +345 -0
  60. sqlalchemy/dialects/postgresql/provision.py +202 -0
  61. sqlalchemy/dialects/postgresql/psycopg.py +800 -0
  62. sqlalchemy/dialects/postgresql/psycopg2.py +860 -0
  63. sqlalchemy/dialects/postgresql/psycopg2cffi.py +62 -0
  64. sqlalchemy/dialects/postgresql/ranges.py +1002 -0
  65. sqlalchemy/dialects/postgresql/types.py +388 -0
  66. sqlalchemy/dialects/sqlite/__init__.py +59 -0
  67. sqlalchemy/dialects/sqlite/aiosqlite.py +375 -0
  68. sqlalchemy/dialects/sqlite/base.py +3103 -0
  69. sqlalchemy/dialects/sqlite/dml.py +314 -0
  70. sqlalchemy/dialects/sqlite/json.py +134 -0
  71. sqlalchemy/dialects/sqlite/provision.py +237 -0
  72. sqlalchemy/dialects/sqlite/pysqlcipher.py +166 -0
  73. sqlalchemy/dialects/sqlite/pysqlite.py +959 -0
  74. sqlalchemy/dialects/type_migration_guidelines.txt +145 -0
  75. sqlalchemy/engine/__init__.py +62 -0
  76. sqlalchemy/engine/_processors_cy.cp315-win_arm64.pyd +0 -0
  77. sqlalchemy/engine/_processors_cy.py +92 -0
  78. sqlalchemy/engine/_result_cy.cp315-win_arm64.pyd +0 -0
  79. sqlalchemy/engine/_result_cy.py +711 -0
  80. sqlalchemy/engine/_row_cy.cp315-win_arm64.pyd +0 -0
  81. sqlalchemy/engine/_row_cy.py +232 -0
  82. sqlalchemy/engine/_util_cy.cp315-win_arm64.pyd +0 -0
  83. sqlalchemy/engine/_util_cy.py +136 -0
  84. sqlalchemy/engine/base.py +3357 -0
  85. sqlalchemy/engine/characteristics.py +155 -0
  86. sqlalchemy/engine/create.py +877 -0
  87. sqlalchemy/engine/cursor.py +2425 -0
  88. sqlalchemy/engine/default.py +2627 -0
  89. sqlalchemy/engine/events.py +965 -0
  90. sqlalchemy/engine/interfaces.py +3636 -0
  91. sqlalchemy/engine/mock.py +133 -0
  92. sqlalchemy/engine/processors.py +83 -0
  93. sqlalchemy/engine/reflection.py +2141 -0
  94. sqlalchemy/engine/result.py +2012 -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 +164 -0
  99. sqlalchemy/event/__init__.py +26 -0
  100. sqlalchemy/event/api.py +220 -0
  101. sqlalchemy/event/attr.py +675 -0
  102. sqlalchemy/event/base.py +473 -0
  103. sqlalchemy/event/legacy.py +259 -0
  104. sqlalchemy/event/registry.py +391 -0
  105. sqlalchemy/events.py +17 -0
  106. sqlalchemy/exc.py +939 -0
  107. sqlalchemy/ext/__init__.py +10 -0
  108. sqlalchemy/ext/associationproxy.py +2073 -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 +2006 -0
  116. sqlalchemy/ext/automap.py +1702 -0
  117. sqlalchemy/ext/baked.py +558 -0
  118. sqlalchemy/ext/compiler.py +601 -0
  119. sqlalchemy/ext/declarative/__init__.py +65 -0
  120. sqlalchemy/ext/declarative/extensions.py +561 -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 +440 -0
  127. sqlalchemy/ext/serializer.py +184 -0
  128. sqlalchemy/future/__init__.py +17 -0
  129. sqlalchemy/future/engine.py +15 -0
  130. sqlalchemy/inspection.py +188 -0
  131. sqlalchemy/log.py +279 -0
  132. sqlalchemy/orm/__init__.py +176 -0
  133. sqlalchemy/orm/_orm_constructors.py +2694 -0
  134. sqlalchemy/orm/_typing.py +180 -0
  135. sqlalchemy/orm/attributes.py +2868 -0
  136. sqlalchemy/orm/base.py +991 -0
  137. sqlalchemy/orm/bulk_persistence.py +2168 -0
  138. sqlalchemy/orm/clsregistry.py +630 -0
  139. sqlalchemy/orm/collections.py +1569 -0
  140. sqlalchemy/orm/context.py +3475 -0
  141. sqlalchemy/orm/decl_api.py +2283 -0
  142. sqlalchemy/orm/decl_base.py +2320 -0
  143. sqlalchemy/orm/dependency.py +1306 -0
  144. sqlalchemy/orm/descriptor_props.py +1183 -0
  145. sqlalchemy/orm/dynamic.py +306 -0
  146. sqlalchemy/orm/evaluator.py +378 -0
  147. sqlalchemy/orm/events.py +3387 -0
  148. sqlalchemy/orm/exc.py +237 -0
  149. sqlalchemy/orm/identity.py +302 -0
  150. sqlalchemy/orm/instrumentation.py +749 -0
  151. sqlalchemy/orm/interfaces.py +1595 -0
  152. sqlalchemy/orm/loading.py +1712 -0
  153. sqlalchemy/orm/mapped_collection.py +557 -0
  154. sqlalchemy/orm/mapper.py +4465 -0
  155. sqlalchemy/orm/path_registry.py +907 -0
  156. sqlalchemy/orm/persistence.py +1790 -0
  157. sqlalchemy/orm/properties.py +972 -0
  158. sqlalchemy/orm/query.py +3528 -0
  159. sqlalchemy/orm/relationships.py +3608 -0
  160. sqlalchemy/orm/scoping.py +2233 -0
  161. sqlalchemy/orm/session.py +5468 -0
  162. sqlalchemy/orm/state.py +1175 -0
  163. sqlalchemy/orm/state_changes.py +196 -0
  164. sqlalchemy/orm/strategies.py +3552 -0
  165. sqlalchemy/orm/strategy_options.py +2648 -0
  166. sqlalchemy/orm/sync.py +164 -0
  167. sqlalchemy/orm/unitofwork.py +797 -0
  168. sqlalchemy/orm/util.py +2461 -0
  169. sqlalchemy/orm/writeonly.py +701 -0
  170. sqlalchemy/pool/__init__.py +41 -0
  171. sqlalchemy/pool/base.py +1540 -0
  172. sqlalchemy/pool/events.py +375 -0
  173. sqlalchemy/pool/impl.py +583 -0
  174. sqlalchemy/py.typed +0 -0
  175. sqlalchemy/schema.py +75 -0
  176. sqlalchemy/sql/__init__.py +156 -0
  177. sqlalchemy/sql/_annotated_cols.py +402 -0
  178. sqlalchemy/sql/_cache_key_cy.cp315-win_arm64.pyd +0 -0
  179. sqlalchemy/sql/_cache_key_cy.py +363 -0
  180. sqlalchemy/sql/_dml_constructors.py +132 -0
  181. sqlalchemy/sql/_elements_constructors.py +2190 -0
  182. sqlalchemy/sql/_orm_types.py +19 -0
  183. sqlalchemy/sql/_selectable_constructors.py +840 -0
  184. sqlalchemy/sql/_typing.py +500 -0
  185. sqlalchemy/sql/_util_cy.cp315-win_arm64.pyd +0 -0
  186. sqlalchemy/sql/_util_cy.pxd +11 -0
  187. sqlalchemy/sql/_util_cy.py +127 -0
  188. sqlalchemy/sql/annotation.py +590 -0
  189. sqlalchemy/sql/base.py +2702 -0
  190. sqlalchemy/sql/cache_key.py +915 -0
  191. sqlalchemy/sql/coercions.py +1373 -0
  192. sqlalchemy/sql/compiler.py +8453 -0
  193. sqlalchemy/sql/crud.py +1816 -0
  194. sqlalchemy/sql/ddl.py +1962 -0
  195. sqlalchemy/sql/default_comparator.py +660 -0
  196. sqlalchemy/sql/dml.py +2018 -0
  197. sqlalchemy/sql/elements.py +6057 -0
  198. sqlalchemy/sql/events.py +458 -0
  199. sqlalchemy/sql/expression.py +171 -0
  200. sqlalchemy/sql/functions.py +2380 -0
  201. sqlalchemy/sql/lambdas.py +1442 -0
  202. sqlalchemy/sql/naming.py +204 -0
  203. sqlalchemy/sql/operators.py +2909 -0
  204. sqlalchemy/sql/roles.py +332 -0
  205. sqlalchemy/sql/schema.py +7075 -0
  206. sqlalchemy/sql/selectable.py +7634 -0
  207. sqlalchemy/sql/sqltypes.py +4130 -0
  208. sqlalchemy/sql/traversals.py +1041 -0
  209. sqlalchemy/sql/type_api.py +2450 -0
  210. sqlalchemy/sql/util.py +1496 -0
  211. sqlalchemy/sql/visitors.py +1153 -0
  212. sqlalchemy/testing/__init__.py +97 -0
  213. sqlalchemy/testing/assertions.py +1007 -0
  214. sqlalchemy/testing/assertsql.py +519 -0
  215. sqlalchemy/testing/asyncio.py +128 -0
  216. sqlalchemy/testing/cancellation.py +237 -0
  217. sqlalchemy/testing/config.py +440 -0
  218. sqlalchemy/testing/engines.py +482 -0
  219. sqlalchemy/testing/entities.py +117 -0
  220. sqlalchemy/testing/exclusions.py +501 -0
  221. sqlalchemy/testing/fixtures/__init__.py +30 -0
  222. sqlalchemy/testing/fixtures/base.py +426 -0
  223. sqlalchemy/testing/fixtures/mypy.py +247 -0
  224. sqlalchemy/testing/fixtures/orm.py +227 -0
  225. sqlalchemy/testing/fixtures/sql.py +538 -0
  226. sqlalchemy/testing/pickleable.py +155 -0
  227. sqlalchemy/testing/plugin/__init__.py +6 -0
  228. sqlalchemy/testing/plugin/bootstrap.py +50 -0
  229. sqlalchemy/testing/plugin/plugin_base.py +828 -0
  230. sqlalchemy/testing/plugin/pytestplugin.py +896 -0
  231. sqlalchemy/testing/profiles_file.py +350 -0
  232. sqlalchemy/testing/profiling.py +294 -0
  233. sqlalchemy/testing/provision.py +633 -0
  234. sqlalchemy/testing/requirements.py +1971 -0
  235. sqlalchemy/testing/schema.py +198 -0
  236. sqlalchemy/testing/suite/__init__.py +19 -0
  237. sqlalchemy/testing/suite/test_cte.py +237 -0
  238. sqlalchemy/testing/suite/test_ddl.py +420 -0
  239. sqlalchemy/testing/suite/test_dialect.py +776 -0
  240. sqlalchemy/testing/suite/test_insert.py +630 -0
  241. sqlalchemy/testing/suite/test_reflection.py +3815 -0
  242. sqlalchemy/testing/suite/test_results.py +660 -0
  243. sqlalchemy/testing/suite/test_rowcount.py +258 -0
  244. sqlalchemy/testing/suite/test_select.py +2112 -0
  245. sqlalchemy/testing/suite/test_sequence.py +317 -0
  246. sqlalchemy/testing/suite/test_table_via_select.py +686 -0
  247. sqlalchemy/testing/suite/test_types.py +2271 -0
  248. sqlalchemy/testing/suite/test_unicode_ddl.py +189 -0
  249. sqlalchemy/testing/suite/test_update_delete.py +139 -0
  250. sqlalchemy/testing/util.py +575 -0
  251. sqlalchemy/testing/warnings.py +52 -0
  252. sqlalchemy/types.py +75 -0
  253. sqlalchemy/util/__init__.py +165 -0
  254. sqlalchemy/util/_collections.py +688 -0
  255. sqlalchemy/util/_collections_cy.cp315-win_arm64.pyd +0 -0
  256. sqlalchemy/util/_collections_cy.pxd +8 -0
  257. sqlalchemy/util/_collections_cy.py +516 -0
  258. sqlalchemy/util/_has_cython.py +48 -0
  259. sqlalchemy/util/_immutabledict_cy.cp315-win_arm64.pyd +0 -0
  260. sqlalchemy/util/_immutabledict_cy.py +240 -0
  261. sqlalchemy/util/compat.py +298 -0
  262. sqlalchemy/util/concurrency.py +272 -0
  263. sqlalchemy/util/cython.py +95 -0
  264. sqlalchemy/util/deprecations.py +401 -0
  265. sqlalchemy/util/langhelpers.py +2797 -0
  266. sqlalchemy/util/preloaded.py +153 -0
  267. sqlalchemy/util/queue.py +304 -0
  268. sqlalchemy/util/tool_support.py +202 -0
  269. sqlalchemy/util/topological.py +120 -0
  270. sqlalchemy/util/typing.py +709 -0
  271. sqlalchemy-2.1.0rc1.dist-info/METADATA +270 -0
  272. sqlalchemy-2.1.0rc1.dist-info/RECORD +276 -0
  273. sqlalchemy-2.1.0rc1.dist-info/WHEEL +5 -0
  274. sqlalchemy-2.1.0rc1.dist-info/licenses/AUTHORS +30 -0
  275. sqlalchemy-2.1.0rc1.dist-info/licenses/LICENSE +19 -0
  276. sqlalchemy-2.1.0rc1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,599 @@
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 info: Optional data dictionary which will be populated into the
233
+ :attr:`.SchemaItem.info` attribute of this object.
234
+
235
+ .. versionadded:: 2.0.50
236
+
237
+ :param using:
238
+ Optional string. If set, emit USING <index_method> when issuing DDL
239
+ for this constraint. Defaults to 'gist'.
240
+
241
+ :param where:
242
+ Optional SQL expression construct or literal SQL string.
243
+ If set, emit WHERE <predicate> when issuing DDL
244
+ for this constraint.
245
+
246
+ :param ops:
247
+ Optional dictionary. Used to define operator classes for the
248
+ elements; works the same way as that of the
249
+ :ref:`postgresql_ops <postgresql_operator_classes>`
250
+ parameter specified to the :class:`_schema.Index` construct.
251
+
252
+ .. seealso::
253
+
254
+ :ref:`postgresql_operator_classes` - general description of how
255
+ PostgreSQL operator classes are specified.
256
+
257
+ """
258
+ columns = []
259
+ render_exprs = []
260
+ self.operators = {}
261
+
262
+ expressions, operators = zip(*elements)
263
+
264
+ for (expr, column, strname, add_element), operator in zip(
265
+ coercions.expect_col_expression_collection(
266
+ roles.DDLConstraintColumnRole, expressions
267
+ ),
268
+ operators,
269
+ ):
270
+ if add_element is not None:
271
+ columns.append(add_element)
272
+
273
+ name = column.name if column is not None else strname
274
+
275
+ if name is not None:
276
+ # backwards compat
277
+ self.operators[name] = operator
278
+
279
+ render_exprs.append((expr, name, operator))
280
+
281
+ self._render_exprs = render_exprs
282
+
283
+ ColumnCollectionConstraint.__init__(
284
+ self,
285
+ *columns,
286
+ name=kw.get("name"),
287
+ deferrable=kw.get("deferrable"),
288
+ initially=kw.get("initially"),
289
+ info=kw.get("info"),
290
+ )
291
+ self.using = kw.get("using", "gist")
292
+ where = kw.get("where")
293
+ if where is not None:
294
+ self.where = coercions.expect(roles.StatementOptionRole, where)
295
+
296
+ self.ops = kw.get("ops", {})
297
+
298
+ def _set_parent(self, table, **kw):
299
+ super()._set_parent(table)
300
+
301
+ self._render_exprs = [
302
+ (
303
+ expr if not isinstance(expr, str) else table.c[expr],
304
+ name,
305
+ operator,
306
+ )
307
+ for expr, name, operator in (self._render_exprs)
308
+ ]
309
+
310
+ def _copy(self, target_table=None, **kw):
311
+ elements = [
312
+ (
313
+ schema._copy_expression(expr, self.parent, target_table),
314
+ operator,
315
+ )
316
+ for expr, _, operator in self._render_exprs
317
+ ]
318
+ c = self.__class__(
319
+ *elements,
320
+ name=self.name,
321
+ deferrable=self.deferrable,
322
+ initially=self.initially,
323
+ where=self.where,
324
+ using=self.using,
325
+ )
326
+ c.dispatch._update(self.dispatch)
327
+ return c
328
+
329
+
330
+ def array_agg(*arg, **kw):
331
+ """PostgreSQL-specific form of :class:`_functions.array_agg`, ensures
332
+ return type is :class:`_postgresql.ARRAY` and not
333
+ the plain :class:`_types.ARRAY`, unless an explicit ``type_``
334
+ is passed.
335
+
336
+ """
337
+ kw["_default_array_type"] = ARRAY
338
+ return functions.func.array_agg(*arg, **kw)
339
+
340
+
341
+ class _regconfig_fn(functions.GenericFunction[_T]):
342
+ inherit_cache = True
343
+
344
+ def __init__(self, *args, **kwargs):
345
+ args = list(args)
346
+ if len(args) > 1:
347
+ initial_arg = coercions.expect(
348
+ roles.ExpressionElementRole,
349
+ args.pop(0),
350
+ name=getattr(self, "name", None),
351
+ apply_propagate_attrs=self,
352
+ type_=types.REGCONFIG,
353
+ )
354
+ initial_arg = [initial_arg]
355
+ else:
356
+ initial_arg = []
357
+
358
+ addtl_args = [
359
+ coercions.expect(
360
+ roles.ExpressionElementRole,
361
+ c,
362
+ name=getattr(self, "name", None),
363
+ apply_propagate_attrs=self,
364
+ )
365
+ for c in args
366
+ ]
367
+ super().__init__(*(initial_arg + addtl_args), **kwargs)
368
+
369
+
370
+ class to_tsvector(_regconfig_fn):
371
+ """The PostgreSQL ``to_tsvector`` SQL function.
372
+
373
+ This function applies automatic casting of the REGCONFIG argument
374
+ to use the :class:`_postgresql.REGCONFIG` datatype automatically,
375
+ and applies a return type of :class:`_postgresql.TSVECTOR`.
376
+
377
+ Assuming the PostgreSQL dialect has been imported, either by invoking
378
+ ``from sqlalchemy.dialects import postgresql``, or by creating a PostgreSQL
379
+ engine using ``create_engine("postgresql...")``,
380
+ :class:`_postgresql.to_tsvector` will be used automatically when invoking
381
+ ``sqlalchemy.func.to_tsvector()``, ensuring the correct argument and return
382
+ type handlers are used at compile and execution time.
383
+
384
+ .. versionadded:: 2.0.0rc1
385
+
386
+ """
387
+
388
+ inherit_cache = True
389
+ type = types.TSVECTOR
390
+
391
+
392
+ class to_tsquery(_regconfig_fn):
393
+ """The PostgreSQL ``to_tsquery`` SQL function.
394
+
395
+ This function applies automatic casting of the REGCONFIG argument
396
+ to use the :class:`_postgresql.REGCONFIG` datatype automatically,
397
+ and applies a return type of :class:`_postgresql.TSQUERY`.
398
+
399
+ Assuming the PostgreSQL dialect has been imported, either by invoking
400
+ ``from sqlalchemy.dialects import postgresql``, or by creating a PostgreSQL
401
+ engine using ``create_engine("postgresql...")``,
402
+ :class:`_postgresql.to_tsquery` will be used automatically when invoking
403
+ ``sqlalchemy.func.to_tsquery()``, ensuring the correct argument and return
404
+ type handlers are used at compile and execution time.
405
+
406
+ .. versionadded:: 2.0.0rc1
407
+
408
+ """
409
+
410
+ inherit_cache = True
411
+ type = types.TSQUERY
412
+
413
+
414
+ class plainto_tsquery(_regconfig_fn):
415
+ """The PostgreSQL ``plainto_tsquery`` SQL function.
416
+
417
+ This function applies automatic casting of the REGCONFIG argument
418
+ to use the :class:`_postgresql.REGCONFIG` datatype automatically,
419
+ and applies a return type of :class:`_postgresql.TSQUERY`.
420
+
421
+ Assuming the PostgreSQL dialect has been imported, either by invoking
422
+ ``from sqlalchemy.dialects import postgresql``, or by creating a PostgreSQL
423
+ engine using ``create_engine("postgresql...")``,
424
+ :class:`_postgresql.plainto_tsquery` will be used automatically when
425
+ invoking ``sqlalchemy.func.plainto_tsquery()``, ensuring the correct
426
+ argument and return type handlers are used at compile and execution time.
427
+
428
+ .. versionadded:: 2.0.0rc1
429
+
430
+ """
431
+
432
+ inherit_cache = True
433
+ type = types.TSQUERY
434
+
435
+
436
+ class phraseto_tsquery(_regconfig_fn):
437
+ """The PostgreSQL ``phraseto_tsquery`` SQL function.
438
+
439
+ This function applies automatic casting of the REGCONFIG argument
440
+ to use the :class:`_postgresql.REGCONFIG` datatype automatically,
441
+ and applies a return type of :class:`_postgresql.TSQUERY`.
442
+
443
+ Assuming the PostgreSQL dialect has been imported, either by invoking
444
+ ``from sqlalchemy.dialects import postgresql``, or by creating a PostgreSQL
445
+ engine using ``create_engine("postgresql...")``,
446
+ :class:`_postgresql.phraseto_tsquery` will be used automatically when
447
+ invoking ``sqlalchemy.func.phraseto_tsquery()``, ensuring the correct
448
+ argument and return type handlers are used at compile and execution time.
449
+
450
+ .. versionadded:: 2.0.0rc1
451
+
452
+ """
453
+
454
+ inherit_cache = True
455
+ type = types.TSQUERY
456
+
457
+
458
+ class websearch_to_tsquery(_regconfig_fn):
459
+ """The PostgreSQL ``websearch_to_tsquery`` SQL function.
460
+
461
+ This function applies automatic casting of the REGCONFIG argument
462
+ to use the :class:`_postgresql.REGCONFIG` datatype automatically,
463
+ and applies a return type of :class:`_postgresql.TSQUERY`.
464
+
465
+ Assuming the PostgreSQL dialect has been imported, either by invoking
466
+ ``from sqlalchemy.dialects import postgresql``, or by creating a PostgreSQL
467
+ engine using ``create_engine("postgresql...")``,
468
+ :class:`_postgresql.websearch_to_tsquery` will be used automatically when
469
+ invoking ``sqlalchemy.func.websearch_to_tsquery()``, ensuring the correct
470
+ argument and return type handlers are used at compile and execution time.
471
+
472
+ .. versionadded:: 2.0.0rc1
473
+
474
+ """
475
+
476
+ inherit_cache = True
477
+ type = types.TSQUERY
478
+
479
+
480
+ class ts_headline(_regconfig_fn):
481
+ """The PostgreSQL ``ts_headline`` SQL function.
482
+
483
+ This function applies automatic casting of the REGCONFIG argument
484
+ to use the :class:`_postgresql.REGCONFIG` datatype automatically,
485
+ and applies a return type of :class:`_types.TEXT`.
486
+
487
+ Assuming the PostgreSQL dialect has been imported, either by invoking
488
+ ``from sqlalchemy.dialects import postgresql``, or by creating a PostgreSQL
489
+ engine using ``create_engine("postgresql...")``,
490
+ :class:`_postgresql.ts_headline` will be used automatically when invoking
491
+ ``sqlalchemy.func.ts_headline()``, ensuring the correct argument and return
492
+ type handlers are used at compile and execution time.
493
+
494
+ .. versionadded:: 2.0.0rc1
495
+
496
+ """
497
+
498
+ inherit_cache = True
499
+ type = TEXT
500
+
501
+ def __init__(self, *args, **kwargs):
502
+ args = list(args)
503
+
504
+ # parse types according to
505
+ # https://www.postgresql.org/docs/current/textsearch-controls.html#TEXTSEARCH-HEADLINE
506
+ if len(args) < 2:
507
+ # invalid args; don't do anything
508
+ has_regconfig = False
509
+ elif (
510
+ isinstance(args[1], elements.ColumnElement)
511
+ and args[1].type._type_affinity is types.TSQUERY
512
+ ):
513
+ # tsquery is second argument, no regconfig argument
514
+ has_regconfig = False
515
+ else:
516
+ has_regconfig = True
517
+
518
+ if has_regconfig:
519
+ initial_arg = coercions.expect(
520
+ roles.ExpressionElementRole,
521
+ args.pop(0),
522
+ apply_propagate_attrs=self,
523
+ name=getattr(self, "name", None),
524
+ type_=types.REGCONFIG,
525
+ )
526
+ initial_arg = [initial_arg]
527
+ else:
528
+ initial_arg = []
529
+
530
+ addtl_args = [
531
+ coercions.expect(
532
+ roles.ExpressionElementRole,
533
+ c,
534
+ name=getattr(self, "name", None),
535
+ apply_propagate_attrs=self,
536
+ )
537
+ for c in args
538
+ ]
539
+ super().__init__(*(initial_arg + addtl_args), **kwargs)
540
+
541
+
542
+ def distinct_on(*expr: _ColumnExpressionArgument[Any]) -> DistinctOnClause:
543
+ """apply a DISTINCT_ON to a SELECT statement
544
+
545
+ e.g.::
546
+
547
+ stmt = select(tbl).ext(distinct_on(t.c.some_col))
548
+
549
+ this supersedes the previous approach of using
550
+ ``select(tbl).distinct(t.c.some_col))`` to apply a similar construct.
551
+
552
+ .. versionadded:: 2.1
553
+
554
+ """
555
+ return DistinctOnClause(expr)
556
+
557
+
558
+ class DistinctOnClause(SyntaxExtension, expression.ClauseElement):
559
+ stringify_dialect = "postgresql"
560
+ __visit_name__ = "postgresql_distinct_on"
561
+
562
+ _traverse_internals: _TraverseInternalsType = [
563
+ ("_distinct_on", InternalTraversal.dp_clauseelement_tuple),
564
+ ]
565
+
566
+ def __init__(self, distinct_on: Sequence[_ColumnExpressionArgument[Any]]):
567
+ self._distinct_on = tuple(
568
+ coercions.expect(roles.ByOfRole, e, apply_propagate_attrs=self)
569
+ for e in distinct_on
570
+ )
571
+
572
+ def apply_to_select(self, select_stmt: expression.Select[Any]) -> None:
573
+ if select_stmt._distinct_on:
574
+ raise exc.InvalidRequestError(
575
+ "Cannot mix ``select.ext(distinct_on(...))`` and "
576
+ "``select.distinct(...)``"
577
+ )
578
+ # mark this select as a distinct
579
+ select_stmt.distinct.non_generative(select_stmt)
580
+
581
+ select_stmt.apply_syntax_extension_point(
582
+ self._merge_other_distinct, "pre_columns"
583
+ )
584
+
585
+ def _merge_other_distinct(
586
+ self, existing: Sequence[elements.ClauseElement]
587
+ ) -> Sequence[elements.ClauseElement]:
588
+ res = []
589
+ to_merge = ()
590
+ for e in existing:
591
+ if isinstance(e, DistinctOnClause):
592
+ to_merge += e._distinct_on
593
+ else:
594
+ res.append(e)
595
+ if to_merge:
596
+ res.append(DistinctOnClause(to_merge + self._distinct_on))
597
+ else:
598
+ res.append(self)
599
+ return res