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,534 @@
1
+ # dialects/postgresql/array.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
+
8
+
9
+ from __future__ import annotations
10
+
11
+ import re
12
+ from typing import Any as typing_Any
13
+ from typing import Iterable
14
+ from typing import Optional
15
+ from typing import Sequence
16
+ from typing import TYPE_CHECKING
17
+ from typing import TypeVar
18
+ from typing import Union
19
+
20
+ from .operators import CONTAINED_BY
21
+ from .operators import CONTAINS
22
+ from .operators import OVERLAP
23
+ from ... import types as sqltypes
24
+ from ... import util
25
+ from ...sql import expression
26
+ from ...sql import operators
27
+ from ...sql.visitors import InternalTraversal
28
+
29
+ if TYPE_CHECKING:
30
+ from ...engine.interfaces import Dialect
31
+ from ...sql._typing import _ColumnExpressionArgument
32
+ from ...sql._typing import _TypeEngineArgument
33
+ from ...sql.elements import ColumnElement
34
+ from ...sql.elements import Grouping
35
+ from ...sql.expression import BindParameter
36
+ from ...sql.operators import OperatorType
37
+ from ...sql.selectable import _SelectIterable
38
+ from ...sql.type_api import _BindProcessorType
39
+ from ...sql.type_api import _LiteralProcessorType
40
+ from ...sql.type_api import _ResultProcessorType
41
+ from ...sql.type_api import TypeEngine
42
+ from ...sql.visitors import _TraverseInternalsType
43
+ from ...util.typing import Self
44
+
45
+
46
+ _T = TypeVar("_T", bound=typing_Any)
47
+ _CT = TypeVar("_CT", bound=typing_Any)
48
+
49
+
50
+ def Any(
51
+ other: typing_Any,
52
+ arrexpr: _ColumnExpressionArgument[_T],
53
+ operator: OperatorType = operators.eq,
54
+ ) -> ColumnElement[bool]:
55
+ """A synonym for the ARRAY-level :meth:`.ARRAY.Comparator.any` method.
56
+ See that method for details.
57
+
58
+ .. deprecated:: 2.1
59
+
60
+ The :meth:`_types.ARRAY.Comparator.any` and
61
+ :meth:`_types.ARRAY.Comparator.all` methods for arrays are deprecated
62
+ for removal, along with the PG-specific :func:`_postgresql.Any` and
63
+ :func:`_postgresql.All` functions. See :func:`_sql.any_` and
64
+ :func:`_sql.all_` functions for modern use.
65
+
66
+
67
+ """
68
+
69
+ return arrexpr.any(other, operator) # type: ignore[no-any-return, union-attr] # noqa: E501
70
+
71
+
72
+ def All(
73
+ other: typing_Any,
74
+ arrexpr: _ColumnExpressionArgument[_T],
75
+ operator: OperatorType = operators.eq,
76
+ ) -> ColumnElement[bool]:
77
+ """A synonym for the ARRAY-level :meth:`.ARRAY.Comparator.all` method.
78
+ See that method for details.
79
+
80
+ .. deprecated:: 2.1
81
+
82
+ The :meth:`_types.ARRAY.Comparator.any` and
83
+ :meth:`_types.ARRAY.Comparator.all` methods for arrays are deprecated
84
+ for removal, along with the PG-specific :func:`_postgresql.Any` and
85
+ :func:`_postgresql.All` functions. See :func:`_sql.any_` and
86
+ :func:`_sql.all_` functions for modern use.
87
+
88
+ """
89
+
90
+ return arrexpr.all(other, operator) # type: ignore[no-any-return, union-attr] # noqa: E501
91
+
92
+
93
+ class array(expression.ExpressionClauseList[_T]):
94
+ """A PostgreSQL ARRAY literal.
95
+
96
+ This is used to produce ARRAY literals in SQL expressions, e.g.::
97
+
98
+ from sqlalchemy.dialects.postgresql import array
99
+ from sqlalchemy.dialects import postgresql
100
+ from sqlalchemy import select, func
101
+
102
+ stmt = select(array([1, 2]) + array([3, 4, 5]))
103
+
104
+ print(stmt.compile(dialect=postgresql.dialect()))
105
+
106
+ Produces the SQL:
107
+
108
+ .. sourcecode:: sql
109
+
110
+ SELECT ARRAY[%(param_1)s, %(param_2)s] ||
111
+ ARRAY[%(param_3)s, %(param_4)s, %(param_5)s]) AS anon_1
112
+
113
+ An instance of :class:`.array` will always have the datatype
114
+ :class:`_types.ARRAY`. The "inner" type of the array is inferred from the
115
+ values present, unless the :paramref:`_postgresql.array.type_` keyword
116
+ argument is passed::
117
+
118
+ array(["foo", "bar"], type_=CHAR)
119
+
120
+ When constructing an empty array, the :paramref:`_postgresql.array.type_`
121
+ argument is particularly important as PostgreSQL server typically requires
122
+ a cast to be rendered for the inner type in order to render an empty array.
123
+ SQLAlchemy's compilation for the empty array will produce this cast so
124
+ that::
125
+
126
+ stmt = array([], type_=Integer)
127
+ print(stmt.compile(dialect=postgresql.dialect()))
128
+
129
+ Produces:
130
+
131
+ .. sourcecode:: sql
132
+
133
+ ARRAY[]::INTEGER[]
134
+
135
+ As required by PostgreSQL for empty arrays.
136
+
137
+ .. versionadded:: 2.0.40 added support to render empty PostgreSQL array
138
+ literals with a required cast.
139
+
140
+ Multidimensional arrays are produced by nesting :class:`.array` constructs.
141
+ The dimensionality of the final :class:`_types.ARRAY`
142
+ type is calculated by
143
+ recursively adding the dimensions of the inner :class:`_types.ARRAY`
144
+ type::
145
+
146
+ stmt = select(
147
+ array(
148
+ [array([1, 2]), array([3, 4]), array([column("q"), column("x")])]
149
+ )
150
+ )
151
+ print(stmt.compile(dialect=postgresql.dialect()))
152
+
153
+ Produces:
154
+
155
+ .. sourcecode:: sql
156
+
157
+ SELECT ARRAY[
158
+ ARRAY[%(param_1)s, %(param_2)s],
159
+ ARRAY[%(param_3)s, %(param_4)s],
160
+ ARRAY[q, x]
161
+ ] AS anon_1
162
+
163
+ .. seealso::
164
+
165
+ :class:`_postgresql.ARRAY`
166
+
167
+ """ # noqa: E501
168
+
169
+ __visit_name__ = "array"
170
+
171
+ stringify_dialect = "postgresql"
172
+
173
+ _traverse_internals: _TraverseInternalsType = [
174
+ ("clauses", InternalTraversal.dp_clauseelement_tuple),
175
+ ("type", InternalTraversal.dp_type),
176
+ ]
177
+
178
+ def __init__(
179
+ self,
180
+ clauses: Iterable[_T],
181
+ *,
182
+ type_: Optional[_TypeEngineArgument[_T]] = None,
183
+ **kw: typing_Any,
184
+ ):
185
+ r"""Construct an ARRAY literal.
186
+
187
+ :param clauses: iterable, such as a list, containing elements to be
188
+ rendered in the array
189
+ :param type\_: optional type. If omitted, the type is inferred
190
+ from the contents of the array.
191
+
192
+ """
193
+ super().__init__(operators.comma_op, *clauses, **kw)
194
+
195
+ main_type = (
196
+ type_
197
+ if type_ is not None
198
+ else self.clauses[0].type if self.clauses else sqltypes.NULLTYPE
199
+ )
200
+
201
+ if isinstance(main_type, ARRAY):
202
+ self.type = ARRAY(
203
+ main_type.item_type,
204
+ dimensions=(
205
+ main_type.dimensions + 1
206
+ if main_type.dimensions is not None
207
+ else 2
208
+ ),
209
+ ) # type: ignore[assignment]
210
+ else:
211
+ self.type = ARRAY(main_type) # type: ignore[assignment]
212
+
213
+ @property
214
+ def _select_iterable(self) -> _SelectIterable:
215
+ return (self,)
216
+
217
+ def _bind_param(
218
+ self,
219
+ operator: OperatorType,
220
+ obj: typing_Any,
221
+ type_: Optional[TypeEngine[_T]] = None,
222
+ _assume_scalar: bool = False,
223
+ ) -> BindParameter[_T]:
224
+ if _assume_scalar or operator is operators.getitem:
225
+ return expression.BindParameter(
226
+ None,
227
+ obj,
228
+ _compared_to_operator=operator,
229
+ type_=type_,
230
+ _compared_to_type=self.type,
231
+ unique=True,
232
+ )
233
+
234
+ else:
235
+ return array(
236
+ [
237
+ self._bind_param(
238
+ operator, o, _assume_scalar=True, type_=type_
239
+ )
240
+ for o in obj
241
+ ]
242
+ ) # type: ignore[return-value]
243
+
244
+ def self_group(
245
+ self, against: Optional[OperatorType] = None
246
+ ) -> Union[Self, Grouping[_T]]:
247
+ if against in (operators.any_op, operators.all_op, operators.getitem):
248
+ return expression.Grouping(self)
249
+ else:
250
+ return self
251
+
252
+
253
+ class ARRAY(sqltypes.ARRAY[_T]):
254
+ """PostgreSQL ARRAY type.
255
+
256
+ The :class:`_postgresql.ARRAY` type is constructed in the same way
257
+ as the core :class:`_types.ARRAY` type; a member type is required, and a
258
+ number of dimensions is recommended if the type is to be used for more
259
+ than one dimension::
260
+
261
+ from sqlalchemy.dialects import postgresql
262
+
263
+ mytable = Table(
264
+ "mytable",
265
+ metadata,
266
+ Column("data", postgresql.ARRAY(Integer, dimensions=2)),
267
+ )
268
+
269
+ The :class:`_postgresql.ARRAY` type provides all operations defined on the
270
+ core :class:`_types.ARRAY` type, including support for "dimensions",
271
+ indexed access, and simple matching such as
272
+ :meth:`.types.ARRAY.Comparator.any` and
273
+ :meth:`.types.ARRAY.Comparator.all`. :class:`_postgresql.ARRAY`
274
+ class also
275
+ provides PostgreSQL-specific methods for containment operations, including
276
+ :meth:`.postgresql.ARRAY.Comparator.contains`
277
+ :meth:`.postgresql.ARRAY.Comparator.contained_by`, and
278
+ :meth:`.postgresql.ARRAY.Comparator.overlap`, e.g.::
279
+
280
+ mytable.c.data.contains([1, 2])
281
+
282
+ Indexed access is one-based by default, to match that of PostgreSQL;
283
+ for zero-based indexed access, set
284
+ :paramref:`_postgresql.ARRAY.zero_indexes`.
285
+
286
+ Additionally, the :class:`_postgresql.ARRAY`
287
+ type does not work directly in
288
+ conjunction with the :class:`.ENUM` type. For a workaround, see the
289
+ special type at :ref:`postgresql_array_of_enum`.
290
+
291
+ .. container:: topic
292
+
293
+ **Detecting Changes in ARRAY columns when using the ORM**
294
+
295
+ The :class:`_postgresql.ARRAY` type, when used with the SQLAlchemy ORM,
296
+ does not detect in-place mutations to the array. In order to detect
297
+ these, the :mod:`sqlalchemy.ext.mutable` extension must be used, using
298
+ the :class:`.MutableList` class::
299
+
300
+ from sqlalchemy.dialects.postgresql import ARRAY
301
+ from sqlalchemy.ext.mutable import MutableList
302
+
303
+
304
+ class SomeOrmClass(Base):
305
+ # ...
306
+
307
+ data = Column(MutableList.as_mutable(ARRAY(Integer)))
308
+
309
+ This extension will allow "in-place" changes such to the array
310
+ such as ``.append()`` to produce events which will be detected by the
311
+ unit of work. Note that changes to elements **inside** the array,
312
+ including subarrays that are mutated in place, are **not** detected.
313
+
314
+ Alternatively, assigning a new array value to an ORM element that
315
+ replaces the old one will always trigger a change event.
316
+
317
+ .. seealso::
318
+
319
+ :class:`_types.ARRAY` - base array type
320
+
321
+ :class:`_postgresql.array` - produces a literal array value.
322
+
323
+ """
324
+
325
+ def __init__(
326
+ self,
327
+ item_type: _TypeEngineArgument[_T],
328
+ as_tuple: bool = False,
329
+ dimensions: Optional[int] = None,
330
+ zero_indexes: bool = False,
331
+ ):
332
+ """Construct an ARRAY.
333
+
334
+ E.g.::
335
+
336
+ Column("myarray", ARRAY(Integer))
337
+
338
+ Arguments are:
339
+
340
+ :param item_type: The data type of items of this array. Note that
341
+ dimensionality is irrelevant here, so multi-dimensional arrays like
342
+ ``INTEGER[][]``, are constructed as ``ARRAY(Integer)``, not as
343
+ ``ARRAY(ARRAY(Integer))`` or such.
344
+
345
+ :param as_tuple=False: Specify whether return results
346
+ should be converted to tuples from lists. DBAPIs such
347
+ as psycopg2 return lists by default. When tuples are
348
+ returned, the results are hashable.
349
+
350
+ :param dimensions: if non-None, the ARRAY will assume a fixed
351
+ number of dimensions. This will cause the DDL emitted for this
352
+ ARRAY to include the exact number of bracket clauses ``[]``,
353
+ and will also optimize the performance of the type overall.
354
+ Note that PG arrays are always implicitly "non-dimensioned",
355
+ meaning they can store any number of dimensions no matter how
356
+ they were declared.
357
+
358
+ :param zero_indexes=False: when True, index values will be converted
359
+ between Python zero-based and PostgreSQL one-based indexes, e.g.
360
+ a value of one will be added to all index values before passing
361
+ to the database.
362
+
363
+ """
364
+ if isinstance(item_type, ARRAY):
365
+ raise ValueError(
366
+ "Do not nest ARRAY types; ARRAY(basetype) "
367
+ "handles multi-dimensional arrays of basetype"
368
+ )
369
+ if isinstance(item_type, type):
370
+ item_type = item_type()
371
+ self.item_type = item_type
372
+ self.as_tuple = as_tuple
373
+ self.dimensions = dimensions
374
+ self.zero_indexes = zero_indexes
375
+
376
+ class Comparator(sqltypes.ARRAY.Comparator[_CT]):
377
+ """Define comparison operations for :class:`_types.ARRAY`.
378
+
379
+ Note that these operations are in addition to those provided
380
+ by the base :class:`.types.ARRAY.Comparator` class, including
381
+ :meth:`.types.ARRAY.Comparator.any` and
382
+ :meth:`.types.ARRAY.Comparator.all`.
383
+
384
+ """
385
+
386
+ def contains(
387
+ self, other: typing_Any, **kwargs: typing_Any
388
+ ) -> ColumnElement[bool]:
389
+ """Boolean expression. Test if elements are a superset of the
390
+ elements of the argument array expression.
391
+
392
+ kwargs may be ignored by this operator but are required for API
393
+ conformance.
394
+ """
395
+ return self.operate(CONTAINS, other, result_type=sqltypes.Boolean)
396
+
397
+ def contained_by(self, other: typing_Any) -> ColumnElement[bool]:
398
+ """Boolean expression. Test if elements are a proper subset of the
399
+ elements of the argument array expression.
400
+ """
401
+ return self.operate(
402
+ CONTAINED_BY, other, result_type=sqltypes.Boolean
403
+ )
404
+
405
+ def overlap(self, other: typing_Any) -> ColumnElement[bool]:
406
+ """Boolean expression. Test if array has elements in common with
407
+ an argument array expression.
408
+ """
409
+ return self.operate(OVERLAP, other, result_type=sqltypes.Boolean)
410
+
411
+ comparator_factory = Comparator
412
+
413
+ @util.memoized_property
414
+ def _against_native_enum(self) -> bool:
415
+ return (
416
+ isinstance(self.item_type, sqltypes.Enum)
417
+ and self.item_type.native_enum
418
+ )
419
+
420
+ def literal_processor(
421
+ self, dialect: Dialect
422
+ ) -> Optional[_LiteralProcessorType[_T]]:
423
+ item_proc = self.item_type.dialect_impl(dialect).literal_processor(
424
+ dialect
425
+ )
426
+ if item_proc is None:
427
+ return None
428
+
429
+ def to_str(elements: Iterable[typing_Any]) -> str:
430
+ return f"ARRAY[{', '.join(elements)}]"
431
+
432
+ def process(value: Sequence[typing_Any]) -> str:
433
+ inner = self._apply_item_processor(
434
+ value, item_proc, self.dimensions, to_str
435
+ )
436
+ return inner
437
+
438
+ return process
439
+
440
+ def bind_processor(
441
+ self, dialect: Dialect
442
+ ) -> Optional[_BindProcessorType[Sequence[typing_Any]]]:
443
+ item_proc = self.item_type.dialect_impl(dialect).bind_processor(
444
+ dialect
445
+ )
446
+
447
+ def process(
448
+ value: Optional[Sequence[typing_Any]],
449
+ ) -> Optional[list[typing_Any]]:
450
+ if value is None:
451
+ return value
452
+ else:
453
+ return self._apply_item_processor(
454
+ value, item_proc, self.dimensions, list
455
+ )
456
+
457
+ return process
458
+
459
+ def result_processor(
460
+ self, dialect: Dialect, coltype: object
461
+ ) -> _ResultProcessorType[Sequence[typing_Any]]:
462
+ item_proc = self.item_type.dialect_impl(dialect).result_processor(
463
+ dialect, coltype
464
+ )
465
+
466
+ def process(
467
+ value: Sequence[typing_Any],
468
+ ) -> Optional[Sequence[typing_Any]]:
469
+ if value is None:
470
+ return value
471
+ else:
472
+ return self._apply_item_processor(
473
+ value,
474
+ item_proc,
475
+ self.dimensions,
476
+ tuple if self.as_tuple else list,
477
+ )
478
+
479
+ if self._against_native_enum:
480
+ super_rp = process
481
+ pattern = re.compile(r"^{(.*)}$")
482
+
483
+ def handle_raw_string(value: str) -> Sequence[Optional[str]]:
484
+ inner = pattern.match(value).group(1) # type: ignore[union-attr] # noqa: E501
485
+ return _split_enum_values(inner)
486
+
487
+ def process(
488
+ value: Sequence[typing_Any],
489
+ ) -> Optional[Sequence[typing_Any]]:
490
+ if value is None:
491
+ return value
492
+ # isinstance(value, str) is required to handle
493
+ # the case where a TypeDecorator for and Array of Enum is
494
+ # used like was required in sa < 1.3.17
495
+ return super_rp(
496
+ handle_raw_string(value)
497
+ if isinstance(value, str)
498
+ else value
499
+ )
500
+
501
+ return process
502
+
503
+
504
+ def _split_enum_values(array_string: str) -> Sequence[Optional[str]]:
505
+ if '"' not in array_string:
506
+ # no escape char is present so it can just split on the comma
507
+ return [
508
+ r if r != "NULL" else None
509
+ for r in (array_string.split(",") if array_string else [])
510
+ ]
511
+
512
+ # handles quoted strings from:
513
+ # r'abc,"quoted","also\\\\quoted", "quoted, comma", "esc \" quot", qpr'
514
+ # returns
515
+ # ['abc', 'quoted', 'also\\quoted', 'quoted, comma', 'esc " quot', 'qpr']
516
+ text = array_string.replace(r"\"", "_$ESC_QUOTE$_")
517
+ text = text.replace(r"\\", "\\")
518
+ result = []
519
+ on_quotes = re.split(r'(")', text)
520
+ in_quotes = False
521
+ for tok in on_quotes:
522
+ if tok == '"':
523
+ in_quotes = not in_quotes
524
+ elif in_quotes:
525
+ result.append(tok.replace("_$ESC_QUOTE$_", '"'))
526
+ else:
527
+ # interpret NULL (without quotes!) as None
528
+ result.extend(
529
+ [
530
+ r if r != "NULL" else None
531
+ for r in re.findall(r"([^\s,]+),?", tok)
532
+ ]
533
+ )
534
+ return result