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,535 @@
1
+ # dialects/postgresql/named_types.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 types import ModuleType
11
+ from typing import Any
12
+ from typing import Dict
13
+ from typing import Optional
14
+ from typing import Type
15
+ from typing import TYPE_CHECKING
16
+ from typing import Union
17
+
18
+ from ... import exc
19
+ from ... import schema
20
+ from ... import util
21
+ from ...sql import coercions
22
+ from ...sql import elements
23
+ from ...sql import roles
24
+ from ...sql import sqltypes
25
+ from ...sql import type_api
26
+ from ...sql.base import _NoArg
27
+ from ...sql.ddl import CheckFirst
28
+ from ...sql.ddl import InvokeCreateDDLBase
29
+ from ...sql.ddl import InvokeDropDDLBase
30
+
31
+ if TYPE_CHECKING:
32
+ from ...sql._typing import _CreateDropBind
33
+ from ...sql._typing import _TypeEngineArgument
34
+
35
+
36
+ class NamedType(schema.SchemaVisitable, sqltypes.TypeEngine):
37
+ """Base for named types."""
38
+
39
+ __abstract__ = True
40
+ DDLGenerator: Type[NamedTypeGenerator]
41
+ DDLDropper: Type[NamedTypeDropper]
42
+ create_type: bool
43
+
44
+ def create(
45
+ self, bind: _CreateDropBind, checkfirst: bool = True, **kw: Any
46
+ ) -> None:
47
+ """Emit ``CREATE`` DDL for this type.
48
+
49
+ :param bind: a connectable :class:`_engine.Engine`,
50
+ :class:`_engine.Connection`, or similar object to emit
51
+ SQL.
52
+ :param checkfirst: if ``True``, a query against
53
+ the PG catalog will be first performed to see
54
+ if the type does not exist already before
55
+ creating.
56
+
57
+ """
58
+ bind._run_ddl_visitor(self.DDLGenerator, self, checkfirst=checkfirst)
59
+
60
+ def drop(
61
+ self, bind: _CreateDropBind, checkfirst: bool = True, **kw: Any
62
+ ) -> None:
63
+ """Emit ``DROP`` DDL for this type.
64
+
65
+ :param bind: a connectable :class:`_engine.Engine`,
66
+ :class:`_engine.Connection`, or similar object to emit
67
+ SQL.
68
+ :param checkfirst: if ``True``, a query against
69
+ the PG catalog will be first performed to see
70
+ if the type actually exists before dropping.
71
+
72
+ """
73
+ bind._run_ddl_visitor(self.DDLDropper, self, checkfirst=checkfirst)
74
+
75
+ def _check_for_name_in_memos(
76
+ self, checkfirst: CheckFirst, kw: Dict[str, Any]
77
+ ) -> bool:
78
+ """Look in the 'ddl runner' for 'memos', then
79
+ note our name in that collection.
80
+
81
+ This to ensure a particular named type is operated
82
+ upon only once within any kind of create/drop
83
+ sequence without relying upon "checkfirst".
84
+
85
+ """
86
+ if not self.create_type:
87
+ return True
88
+ if "_ddl_runner" in kw:
89
+ ddl_runner = kw["_ddl_runner"]
90
+ type_name = f"pg_{self.__visit_name__}"
91
+ if type_name in ddl_runner.memo:
92
+ existing = ddl_runner.memo[type_name]
93
+ else:
94
+ existing = ddl_runner.memo[type_name] = set()
95
+ present = (self.schema, self.name) in existing
96
+ existing.add((self.schema, self.name))
97
+ return present
98
+ else:
99
+ return False
100
+
101
+ def _on_table_create(
102
+ self,
103
+ target: schema.Table,
104
+ bind: _CreateDropBind,
105
+ checkfirst: Union[bool, CheckFirst] = CheckFirst.NONE,
106
+ **kw: Any,
107
+ ) -> None:
108
+ checkfirst = CheckFirst(checkfirst) & CheckFirst.TYPES
109
+ if not self._check_for_name_in_memos(checkfirst, kw):
110
+ self.create(bind=bind, checkfirst=bool(checkfirst))
111
+
112
+ def _on_table_drop(
113
+ self,
114
+ target: Any,
115
+ bind: _CreateDropBind,
116
+ checkfirst: CheckFirst = CheckFirst.NONE,
117
+ **kw: Any,
118
+ ) -> None:
119
+ # do nothing since the enum is attached to a metadata
120
+ assert self.metadata is not None
121
+
122
+ def _on_metadata_create(
123
+ self,
124
+ target: schema.MetaData,
125
+ bind: _CreateDropBind,
126
+ checkfirst: Union[bool, CheckFirst] = CheckFirst.NONE,
127
+ **kw: Any,
128
+ ) -> None:
129
+ checkfirst = CheckFirst(checkfirst) & CheckFirst.TYPES
130
+ if not self._check_for_name_in_memos(checkfirst, kw):
131
+ self.create(bind=bind, checkfirst=bool(checkfirst))
132
+
133
+ def _on_metadata_drop(
134
+ self,
135
+ target: schema.MetaData,
136
+ bind: _CreateDropBind,
137
+ checkfirst: Union[bool, CheckFirst] = CheckFirst.NONE,
138
+ **kw: Any,
139
+ ) -> None:
140
+ checkfirst = CheckFirst(checkfirst) & CheckFirst.TYPES
141
+ if not self._check_for_name_in_memos(checkfirst, kw):
142
+ self.drop(bind=bind, checkfirst=bool(checkfirst))
143
+
144
+
145
+ class NamedTypeGenerator(InvokeCreateDDLBase):
146
+ def __init__(self, dialect, connection, checkfirst=False, **kwargs):
147
+ super().__init__(connection, **kwargs)
148
+ self.checkfirst = checkfirst
149
+
150
+ def _can_create_type(self, type_):
151
+ if not self.checkfirst:
152
+ return True
153
+
154
+ effective_schema = self.connection.schema_for_object(type_)
155
+ return not self.connection.dialect.has_type(
156
+ self.connection, type_.name, schema=effective_schema
157
+ )
158
+
159
+
160
+ class NamedTypeDropper(InvokeDropDDLBase):
161
+ def __init__(self, dialect, connection, checkfirst=False, **kwargs):
162
+ super().__init__(connection, **kwargs)
163
+ self.checkfirst = checkfirst
164
+
165
+ def _can_drop_type(self, type_):
166
+ if not self.checkfirst:
167
+ return True
168
+
169
+ effective_schema = self.connection.schema_for_object(type_)
170
+ return self.connection.dialect.has_type(
171
+ self.connection, type_.name, schema=effective_schema
172
+ )
173
+
174
+
175
+ class EnumGenerator(NamedTypeGenerator):
176
+ def visit_enum(self, enum):
177
+ if not self._can_create_type(enum):
178
+ return
179
+
180
+ with self.with_ddl_events(enum):
181
+ self.connection.execute(CreateEnumType(enum))
182
+
183
+
184
+ class EnumDropper(NamedTypeDropper):
185
+ def visit_enum(self, enum):
186
+ if not self._can_drop_type(enum):
187
+ return
188
+
189
+ with self.with_ddl_events(enum):
190
+ self.connection.execute(DropEnumType(enum))
191
+
192
+
193
+ class ENUM(NamedType, type_api.NativeForEmulated, sqltypes.Enum):
194
+ """PostgreSQL ENUM type.
195
+
196
+ This is a subclass of :class:`_types.Enum` which includes
197
+ support for PG's ``CREATE TYPE`` and ``DROP TYPE``.
198
+
199
+ When the builtin type :class:`_types.Enum` is used and the
200
+ :paramref:`.Enum.native_enum` flag is left at its default of
201
+ True, the PostgreSQL backend will use a :class:`_postgresql.ENUM`
202
+ type as the implementation, so the special create/drop rules
203
+ will be used.
204
+
205
+ The create/drop behavior of ENUM tries to follow the PostgreSQL behavior,
206
+ with an usability improvement indicated below.
207
+
208
+ When using :class:`_types.Enum` or :class:`_postgresql.ENUM`
209
+ in an "inline" fashion, the ``CREATE TYPE`` is emitted
210
+ corresponding to when the :meth:`_schema.Table.create` method is called::
211
+
212
+ table = Table(
213
+ "sometable",
214
+ metadata,
215
+ Column("some_enum", ENUM("a", "b", "c", name="myenum")),
216
+ )
217
+
218
+ # will check if enum exists and emit CREATE ENUM then CREATE TABLE
219
+ table.create(engine)
220
+ table.drop(engine) # will *not* drop the enum.
221
+
222
+ The enum will not be dropped when the table is dropped, since it's
223
+ associated with the metadata, not the table itself. Call drop on the
224
+ :class:`_postgresql.ENUM` directly to drop the type::
225
+
226
+ metadata.get_schema_object_by_name("enum", "myenum").drop(engine)
227
+
228
+ To use a common enumerated type between multiple tables, the best
229
+ practice is to declare the :class:`_types.Enum` or
230
+ :class:`_postgresql.ENUM` independently::
231
+
232
+ my_enum = ENUM("a", "b", "c", name="myenum", metadata=metadata)
233
+
234
+ t1 = Table("sometable_one", metadata, Column("some_enum", myenum))
235
+
236
+ t2 = Table("sometable_two", metadata, Column("some_enum", myenum))
237
+
238
+ Like before, the type will be created if it does not exist::
239
+
240
+ # will check if enum exists and emit CREATE ENUM then CREATE TABLE
241
+ t1.create(engine)
242
+
243
+ The type will always be created and dropped if either the metadata-wide
244
+ create/drop is called::
245
+
246
+ metadata.create_all(engine) # will emit CREATE TYPE
247
+ metadata.drop_all(engine) # will emit DROP TYPE
248
+
249
+ The type can also be created and dropped directly::
250
+
251
+ my_enum.create(engine)
252
+ my_enum.drop(engine)
253
+
254
+ .. versionchanged:: 2.1 The behavior of :class:`_postgresql.ENUM` and
255
+ other named types has been changed to better reflect how PostgreSQL
256
+ handles CREATE TYPE and DROP TYPE operations.
257
+ Named types are still created when needed during table
258
+ creation if they do not already exist. However, they are no longer
259
+ dropped for an individual :meth:`.Table.drop` operation, since the type
260
+ may be referenced by other tables as well. Instead,
261
+ :meth:`.Enum.drop` may be used or :meth:`.MetaData.drop_all` will drop
262
+ all associated types.
263
+
264
+ """
265
+
266
+ native_enum = True
267
+ DDLGenerator = EnumGenerator
268
+ DDLDropper = EnumDropper
269
+
270
+ def __init__(
271
+ self,
272
+ *enums,
273
+ name: Union[str, _NoArg, None] = _NoArg.NO_ARG,
274
+ create_type: bool = True,
275
+ **kw,
276
+ ):
277
+ """Construct an :class:`_postgresql.ENUM`.
278
+
279
+ Arguments are the same as that of
280
+ :class:`_types.Enum`, but also including
281
+ the following parameters.
282
+
283
+ :param create_type: Defaults to True.
284
+ Indicates that ``CREATE TYPE`` should be
285
+ emitted, after optionally checking for the
286
+ presence of the type, when the parent
287
+ table is being created. When ``False``, no check
288
+ will be performed and no ``CREATE TYPE``
289
+ or ``DROP TYPE`` is emitted, unless
290
+ :meth:`~.postgresql.ENUM.create`
291
+ or :meth:`~.postgresql.ENUM.drop`
292
+ are called directly.
293
+ Setting to ``False`` is helpful
294
+ when invoking a creation scheme to a SQL file
295
+ without access to the actual database -
296
+ the :meth:`~.postgresql.ENUM.create` and
297
+ :meth:`~.postgresql.ENUM.drop` methods can
298
+ be used to emit SQL to a target bind.
299
+
300
+ """
301
+ native_enum = kw.pop("native_enum", None)
302
+ if native_enum is False:
303
+ util.warn(
304
+ "the native_enum flag does not apply to the "
305
+ "sqlalchemy.dialects.postgresql.ENUM datatype; this type "
306
+ "always refers to ENUM. Use sqlalchemy.types.Enum for "
307
+ "non-native enum."
308
+ )
309
+ if name is not _NoArg.NO_ARG:
310
+ kw["name"] = name
311
+ kw["create_type"] = create_type
312
+ super().__init__(*enums, **kw)
313
+
314
+ def coerce_compared_value(self, op, value):
315
+ super_coerced_type = super().coerce_compared_value(op, value)
316
+ if (
317
+ super_coerced_type._type_affinity
318
+ is type_api.STRINGTYPE._type_affinity
319
+ ):
320
+ return self
321
+ else:
322
+ return super_coerced_type
323
+
324
+ @classmethod
325
+ def __test_init__(cls):
326
+ return cls(name="name")
327
+
328
+ @classmethod
329
+ def adapt_emulated_to_native(cls, impl, **kw):
330
+ """Produce a PostgreSQL native :class:`_postgresql.ENUM` from plain
331
+ :class:`.Enum`.
332
+
333
+ """
334
+ kw.setdefault("validate_strings", impl.validate_strings)
335
+ kw.setdefault("name", impl.name)
336
+ kw.setdefault("create_type", impl.create_type)
337
+ kw.setdefault("schema", impl.schema)
338
+ kw.setdefault("metadata", impl.metadata)
339
+ kw.setdefault("_create_events", False)
340
+ kw.setdefault("values_callable", impl.values_callable)
341
+ kw.setdefault("omit_aliases", impl._omit_aliases)
342
+ kw.setdefault("_adapted_from", impl)
343
+
344
+ return cls(**kw)
345
+
346
+ def create(self, bind: _CreateDropBind, checkfirst: bool = True) -> None:
347
+ """Emit ``CREATE TYPE`` for this
348
+ :class:`_postgresql.ENUM`.
349
+
350
+ If the underlying dialect does not support
351
+ PostgreSQL CREATE TYPE, no action is taken.
352
+
353
+ :param bind: a connectable :class:`_engine.Engine`,
354
+ :class:`_engine.Connection`, or similar object to emit
355
+ SQL.
356
+ :param checkfirst: if ``True``, a query against
357
+ the PG catalog will be first performed to see
358
+ if the type does not exist already before
359
+ creating.
360
+
361
+ """
362
+ if not bind.dialect.supports_native_enum:
363
+ return
364
+
365
+ super().create(bind, checkfirst=checkfirst)
366
+
367
+ def drop(self, bind: _CreateDropBind, checkfirst: bool = True) -> None:
368
+ """Emit ``DROP TYPE`` for this
369
+ :class:`_postgresql.ENUM`.
370
+
371
+ If the underlying dialect does not support
372
+ PostgreSQL DROP TYPE, no action is taken.
373
+
374
+ :param bind: a connectable :class:`_engine.Engine`,
375
+ :class:`_engine.Connection`, or similar object to emit
376
+ SQL.
377
+ :param checkfirst: if ``True``, a query against
378
+ the PG catalog will be first performed to see
379
+ if the type actually exists before dropping.
380
+
381
+ """
382
+ if not bind.dialect.supports_native_enum:
383
+ return
384
+
385
+ super().drop(bind, checkfirst=checkfirst)
386
+
387
+ def get_dbapi_type(self, dbapi: ModuleType) -> None:
388
+ """dont return dbapi.STRING for ENUM in PostgreSQL, since that's
389
+ a different type"""
390
+
391
+ return None
392
+
393
+
394
+ class DomainGenerator(NamedTypeGenerator):
395
+ def visit_DOMAIN(self, domain):
396
+ if not self._can_create_type(domain):
397
+ return
398
+ with self.with_ddl_events(domain):
399
+ self.connection.execute(CreateDomainType(domain))
400
+
401
+
402
+ class DomainDropper(NamedTypeDropper):
403
+ def visit_DOMAIN(self, domain):
404
+ if not self._can_drop_type(domain):
405
+ return
406
+
407
+ with self.with_ddl_events(domain):
408
+ self.connection.execute(DropDomainType(domain))
409
+
410
+
411
+ class DOMAIN(NamedType, sqltypes.SchemaType):
412
+ r"""Represent the DOMAIN PostgreSQL type.
413
+
414
+ A domain is essentially a data type with optional constraints
415
+ that restrict the allowed set of values. E.g.::
416
+
417
+ PositiveInt = DOMAIN("pos_int", Integer, check="VALUE > 0", not_null=True)
418
+
419
+ UsPostalCode = DOMAIN(
420
+ "us_postal_code",
421
+ Text,
422
+ check="VALUE ~ '^\d{5}$' OR VALUE ~ '^\d{5}-\d{4}$'",
423
+ )
424
+
425
+ :class:`_postgresql.DOMAIN` has the same create/drop behavior specified
426
+ in :class:`_postgresql.ENUM`.
427
+
428
+ See the `PostgreSQL documentation`__ for additional details
429
+
430
+ __ https://www.postgresql.org/docs/current/sql-createdomain.html
431
+
432
+ .. versionadded:: 2.0
433
+
434
+ """ # noqa: E501
435
+
436
+ DDLGenerator = DomainGenerator
437
+ DDLDropper = DomainDropper
438
+
439
+ __visit_name__ = "DOMAIN"
440
+
441
+ def __init__(
442
+ self,
443
+ name: str,
444
+ data_type: _TypeEngineArgument[Any],
445
+ *,
446
+ collation: Optional[str] = None,
447
+ collation_schema: Optional[str] = None,
448
+ default: Union[elements.TextClause, str, None] = None,
449
+ constraint_name: Optional[str] = None,
450
+ not_null: Optional[bool] = None,
451
+ check: Union[elements.TextClause, str, None] = None,
452
+ create_type: bool = True,
453
+ **kw: Any,
454
+ ):
455
+ """
456
+ Construct a DOMAIN.
457
+
458
+ :param name: the name of the domain
459
+ :param data_type: The underlying data type of the domain.
460
+ This can include array specifiers.
461
+ :param collation: An optional collation for the domain.
462
+ If no collation is specified, the underlying data type's default
463
+ collation is used. The underlying type must be collatable if
464
+ ``collation`` is specified.
465
+ :param collation_schema: Optional, the name of the schema in which
466
+ :paramref:`.DOMAIN.collation` is defined. Requires that
467
+ :paramref:`.DOMAIN.collation` is also present.
468
+
469
+ .. versionadded:: 2.1
470
+
471
+ :param default: The DEFAULT clause specifies a default value for
472
+ columns of the domain data type. The default should be a string
473
+ or a :func:`_expression.text` value.
474
+ If no default value is specified, then the default value is
475
+ the null value.
476
+ :param constraint_name: An optional name for a constraint.
477
+ If not specified, the backend generates a name.
478
+ :param not_null: Values of this domain are prevented from being null.
479
+ By default domain are allowed to be null. If not specified
480
+ no nullability clause will be emitted.
481
+ :param check: CHECK clause specify integrity constraint or test
482
+ which values of the domain must satisfy. A constraint must be
483
+ an expression producing a Boolean result that can use the key
484
+ word VALUE to refer to the value being tested.
485
+ Differently from PostgreSQL, only a single check clause is
486
+ currently allowed in SQLAlchemy.
487
+ :param schema: optional schema name
488
+ :param metadata: optional :class:`_schema.MetaData` object which
489
+ this :class:`_postgresql.DOMAIN` will be directly associated
490
+ :param create_type: Defaults to True.
491
+ Indicates that ``CREATE TYPE`` should be emitted, after optionally
492
+ checking for the presence of the type, when the parent table is
493
+ being created; and additionally that ``DROP TYPE`` is called
494
+ when the table is dropped.
495
+
496
+ """
497
+ self.data_type = type_api.to_instance(data_type)
498
+ self.default = default
499
+ self.collation = collation
500
+ if collation_schema is not None and collation is None:
501
+ raise exc.ArgumentError(
502
+ "the 'collation_schema' parameter of DOMAIN requires "
503
+ "the 'collation' parameter to also be present"
504
+ )
505
+ self.collation_schema = collation_schema
506
+ self.constraint_name = constraint_name
507
+ self.not_null = bool(not_null)
508
+ if check is not None:
509
+ check = coercions.expect(roles.DDLExpressionRole, check)
510
+ self.check = check
511
+ super().__init__(name=name, create_type=create_type, **kw)
512
+
513
+ @classmethod
514
+ def __test_init__(cls):
515
+ return cls("name", sqltypes.Integer)
516
+
517
+
518
+ class CreateEnumType(schema._CreateDropBase):
519
+ __visit_name__ = "create_enum_type"
520
+
521
+
522
+ class DropEnumType(schema._CreateDropBase):
523
+ __visit_name__ = "drop_enum_type"
524
+
525
+
526
+ class CreateDomainType(schema._CreateDropBase):
527
+ """Represent a CREATE DOMAIN statement."""
528
+
529
+ __visit_name__ = "create_domain_type"
530
+
531
+
532
+ class DropDomainType(schema._CreateDropBase):
533
+ """Represent a DROP DOMAIN statement."""
534
+
535
+ __visit_name__ = "drop_domain_type"
@@ -0,0 +1,129 @@
1
+ # dialects/postgresql/operators.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 ...sql import operators
9
+
10
+ _getitem_precedence = operators._PRECEDENCE[operators.json_getitem_op]
11
+ _eq_precedence = operators._PRECEDENCE[operators.eq]
12
+
13
+ # JSON + JSONB
14
+ ASTEXT = operators.custom_op(
15
+ "->>",
16
+ precedence=_getitem_precedence,
17
+ natural_self_precedent=True,
18
+ eager_grouping=True,
19
+ )
20
+
21
+ JSONPATH_ASTEXT = operators.custom_op(
22
+ "#>>",
23
+ precedence=_getitem_precedence,
24
+ natural_self_precedent=True,
25
+ eager_grouping=True,
26
+ )
27
+
28
+ # JSONB + HSTORE
29
+ HAS_KEY = operators.custom_op(
30
+ "?",
31
+ precedence=_eq_precedence,
32
+ natural_self_precedent=True,
33
+ eager_grouping=True,
34
+ is_comparison=True,
35
+ )
36
+
37
+ HAS_ALL = operators.custom_op(
38
+ "?&",
39
+ precedence=_eq_precedence,
40
+ natural_self_precedent=True,
41
+ eager_grouping=True,
42
+ is_comparison=True,
43
+ )
44
+
45
+ HAS_ANY = operators.custom_op(
46
+ "?|",
47
+ precedence=_eq_precedence,
48
+ natural_self_precedent=True,
49
+ eager_grouping=True,
50
+ is_comparison=True,
51
+ )
52
+
53
+ # JSONB
54
+ DELETE_PATH = operators.custom_op(
55
+ "#-",
56
+ precedence=_getitem_precedence,
57
+ natural_self_precedent=True,
58
+ eager_grouping=True,
59
+ )
60
+
61
+ PATH_EXISTS = operators.custom_op(
62
+ "@?",
63
+ precedence=_eq_precedence,
64
+ natural_self_precedent=True,
65
+ eager_grouping=True,
66
+ is_comparison=True,
67
+ )
68
+
69
+ PATH_MATCH = operators.custom_op(
70
+ "@@",
71
+ precedence=_eq_precedence,
72
+ natural_self_precedent=True,
73
+ eager_grouping=True,
74
+ is_comparison=True,
75
+ )
76
+
77
+ # JSONB + ARRAY + HSTORE + RANGE
78
+ CONTAINS = operators.custom_op(
79
+ "@>",
80
+ precedence=_eq_precedence,
81
+ natural_self_precedent=True,
82
+ eager_grouping=True,
83
+ is_comparison=True,
84
+ )
85
+
86
+ CONTAINED_BY = operators.custom_op(
87
+ "<@",
88
+ precedence=_eq_precedence,
89
+ natural_self_precedent=True,
90
+ eager_grouping=True,
91
+ is_comparison=True,
92
+ )
93
+
94
+ # ARRAY + RANGE
95
+ OVERLAP = operators.custom_op(
96
+ "&&",
97
+ precedence=_eq_precedence,
98
+ is_comparison=True,
99
+ )
100
+
101
+ # RANGE
102
+ STRICTLY_LEFT_OF = operators.custom_op(
103
+ "<<", precedence=_eq_precedence, is_comparison=True
104
+ )
105
+
106
+ STRICTLY_RIGHT_OF = operators.custom_op(
107
+ ">>", precedence=_eq_precedence, is_comparison=True
108
+ )
109
+
110
+ NOT_EXTEND_RIGHT_OF = operators.custom_op(
111
+ "&<", precedence=_eq_precedence, is_comparison=True
112
+ )
113
+
114
+ NOT_EXTEND_LEFT_OF = operators.custom_op(
115
+ "&>", precedence=_eq_precedence, is_comparison=True
116
+ )
117
+
118
+ ADJACENT_TO = operators.custom_op(
119
+ "-|-", precedence=_eq_precedence, is_comparison=True
120
+ )
121
+
122
+ # HSTORE
123
+ GETITEM = operators.custom_op(
124
+ "->",
125
+ precedence=_getitem_precedence,
126
+ natural_self_precedent=True,
127
+ eager_grouping=True,
128
+ visit_name="hstore_getitem",
129
+ )