SQLAlchemy 2.0.47__cp313-cp313t-win32.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (274) hide show
  1. sqlalchemy/__init__.py +283 -0
  2. sqlalchemy/connectors/__init__.py +18 -0
  3. sqlalchemy/connectors/aioodbc.py +184 -0
  4. sqlalchemy/connectors/asyncio.py +429 -0
  5. sqlalchemy/connectors/pyodbc.py +250 -0
  6. sqlalchemy/cyextension/__init__.py +6 -0
  7. sqlalchemy/cyextension/collections.cp313t-win32.pyd +0 -0
  8. sqlalchemy/cyextension/collections.pyx +409 -0
  9. sqlalchemy/cyextension/immutabledict.cp313t-win32.pyd +0 -0
  10. sqlalchemy/cyextension/immutabledict.pxd +8 -0
  11. sqlalchemy/cyextension/immutabledict.pyx +133 -0
  12. sqlalchemy/cyextension/processors.cp313t-win32.pyd +0 -0
  13. sqlalchemy/cyextension/processors.pyx +68 -0
  14. sqlalchemy/cyextension/resultproxy.cp313t-win32.pyd +0 -0
  15. sqlalchemy/cyextension/resultproxy.pyx +102 -0
  16. sqlalchemy/cyextension/util.cp313t-win32.pyd +0 -0
  17. sqlalchemy/cyextension/util.pyx +90 -0
  18. sqlalchemy/dialects/__init__.py +62 -0
  19. sqlalchemy/dialects/_typing.py +30 -0
  20. sqlalchemy/dialects/mssql/__init__.py +88 -0
  21. sqlalchemy/dialects/mssql/aioodbc.py +63 -0
  22. sqlalchemy/dialects/mssql/base.py +4093 -0
  23. sqlalchemy/dialects/mssql/information_schema.py +285 -0
  24. sqlalchemy/dialects/mssql/json.py +129 -0
  25. sqlalchemy/dialects/mssql/provision.py +185 -0
  26. sqlalchemy/dialects/mssql/pymssql.py +126 -0
  27. sqlalchemy/dialects/mssql/pyodbc.py +760 -0
  28. sqlalchemy/dialects/mysql/__init__.py +104 -0
  29. sqlalchemy/dialects/mysql/aiomysql.py +250 -0
  30. sqlalchemy/dialects/mysql/asyncmy.py +231 -0
  31. sqlalchemy/dialects/mysql/base.py +3949 -0
  32. sqlalchemy/dialects/mysql/cymysql.py +106 -0
  33. sqlalchemy/dialects/mysql/dml.py +225 -0
  34. sqlalchemy/dialects/mysql/enumerated.py +282 -0
  35. sqlalchemy/dialects/mysql/expression.py +146 -0
  36. sqlalchemy/dialects/mysql/json.py +91 -0
  37. sqlalchemy/dialects/mysql/mariadb.py +72 -0
  38. sqlalchemy/dialects/mysql/mariadbconnector.py +322 -0
  39. sqlalchemy/dialects/mysql/mysqlconnector.py +302 -0
  40. sqlalchemy/dialects/mysql/mysqldb.py +314 -0
  41. sqlalchemy/dialects/mysql/provision.py +153 -0
  42. sqlalchemy/dialects/mysql/pymysql.py +158 -0
  43. sqlalchemy/dialects/mysql/pyodbc.py +157 -0
  44. sqlalchemy/dialects/mysql/reflection.py +727 -0
  45. sqlalchemy/dialects/mysql/reserved_words.py +570 -0
  46. sqlalchemy/dialects/mysql/types.py +835 -0
  47. sqlalchemy/dialects/oracle/__init__.py +81 -0
  48. sqlalchemy/dialects/oracle/base.py +3802 -0
  49. sqlalchemy/dialects/oracle/cx_oracle.py +1555 -0
  50. sqlalchemy/dialects/oracle/dictionary.py +507 -0
  51. sqlalchemy/dialects/oracle/oracledb.py +941 -0
  52. sqlalchemy/dialects/oracle/provision.py +297 -0
  53. sqlalchemy/dialects/oracle/types.py +316 -0
  54. sqlalchemy/dialects/oracle/vector.py +365 -0
  55. sqlalchemy/dialects/postgresql/__init__.py +167 -0
  56. sqlalchemy/dialects/postgresql/_psycopg_common.py +189 -0
  57. sqlalchemy/dialects/postgresql/array.py +519 -0
  58. sqlalchemy/dialects/postgresql/asyncpg.py +1284 -0
  59. sqlalchemy/dialects/postgresql/base.py +5378 -0
  60. sqlalchemy/dialects/postgresql/dml.py +339 -0
  61. sqlalchemy/dialects/postgresql/ext.py +540 -0
  62. sqlalchemy/dialects/postgresql/hstore.py +406 -0
  63. sqlalchemy/dialects/postgresql/json.py +404 -0
  64. sqlalchemy/dialects/postgresql/named_types.py +524 -0
  65. sqlalchemy/dialects/postgresql/operators.py +129 -0
  66. sqlalchemy/dialects/postgresql/pg8000.py +669 -0
  67. sqlalchemy/dialects/postgresql/pg_catalog.py +326 -0
  68. sqlalchemy/dialects/postgresql/provision.py +183 -0
  69. sqlalchemy/dialects/postgresql/psycopg.py +862 -0
  70. sqlalchemy/dialects/postgresql/psycopg2.py +892 -0
  71. sqlalchemy/dialects/postgresql/psycopg2cffi.py +61 -0
  72. sqlalchemy/dialects/postgresql/ranges.py +1031 -0
  73. sqlalchemy/dialects/postgresql/types.py +313 -0
  74. sqlalchemy/dialects/sqlite/__init__.py +57 -0
  75. sqlalchemy/dialects/sqlite/aiosqlite.py +482 -0
  76. sqlalchemy/dialects/sqlite/base.py +3056 -0
  77. sqlalchemy/dialects/sqlite/dml.py +263 -0
  78. sqlalchemy/dialects/sqlite/json.py +92 -0
  79. sqlalchemy/dialects/sqlite/provision.py +229 -0
  80. sqlalchemy/dialects/sqlite/pysqlcipher.py +157 -0
  81. sqlalchemy/dialects/sqlite/pysqlite.py +756 -0
  82. sqlalchemy/dialects/type_migration_guidelines.txt +145 -0
  83. sqlalchemy/engine/__init__.py +62 -0
  84. sqlalchemy/engine/_py_processors.py +136 -0
  85. sqlalchemy/engine/_py_row.py +128 -0
  86. sqlalchemy/engine/_py_util.py +74 -0
  87. sqlalchemy/engine/base.py +3390 -0
  88. sqlalchemy/engine/characteristics.py +155 -0
  89. sqlalchemy/engine/create.py +893 -0
  90. sqlalchemy/engine/cursor.py +2298 -0
  91. sqlalchemy/engine/default.py +2394 -0
  92. sqlalchemy/engine/events.py +965 -0
  93. sqlalchemy/engine/interfaces.py +3471 -0
  94. sqlalchemy/engine/mock.py +134 -0
  95. sqlalchemy/engine/processors.py +61 -0
  96. sqlalchemy/engine/reflection.py +2102 -0
  97. sqlalchemy/engine/result.py +2399 -0
  98. sqlalchemy/engine/row.py +400 -0
  99. sqlalchemy/engine/strategies.py +16 -0
  100. sqlalchemy/engine/url.py +924 -0
  101. sqlalchemy/engine/util.py +167 -0
  102. sqlalchemy/event/__init__.py +26 -0
  103. sqlalchemy/event/api.py +220 -0
  104. sqlalchemy/event/attr.py +676 -0
  105. sqlalchemy/event/base.py +472 -0
  106. sqlalchemy/event/legacy.py +258 -0
  107. sqlalchemy/event/registry.py +390 -0
  108. sqlalchemy/events.py +17 -0
  109. sqlalchemy/exc.py +832 -0
  110. sqlalchemy/ext/__init__.py +11 -0
  111. sqlalchemy/ext/associationproxy.py +2027 -0
  112. sqlalchemy/ext/asyncio/__init__.py +25 -0
  113. sqlalchemy/ext/asyncio/base.py +281 -0
  114. sqlalchemy/ext/asyncio/engine.py +1471 -0
  115. sqlalchemy/ext/asyncio/exc.py +21 -0
  116. sqlalchemy/ext/asyncio/result.py +965 -0
  117. sqlalchemy/ext/asyncio/scoping.py +1599 -0
  118. sqlalchemy/ext/asyncio/session.py +1947 -0
  119. sqlalchemy/ext/automap.py +1701 -0
  120. sqlalchemy/ext/baked.py +570 -0
  121. sqlalchemy/ext/compiler.py +600 -0
  122. sqlalchemy/ext/declarative/__init__.py +65 -0
  123. sqlalchemy/ext/declarative/extensions.py +564 -0
  124. sqlalchemy/ext/horizontal_shard.py +478 -0
  125. sqlalchemy/ext/hybrid.py +1535 -0
  126. sqlalchemy/ext/indexable.py +364 -0
  127. sqlalchemy/ext/instrumentation.py +450 -0
  128. sqlalchemy/ext/mutable.py +1085 -0
  129. sqlalchemy/ext/mypy/__init__.py +6 -0
  130. sqlalchemy/ext/mypy/apply.py +324 -0
  131. sqlalchemy/ext/mypy/decl_class.py +515 -0
  132. sqlalchemy/ext/mypy/infer.py +590 -0
  133. sqlalchemy/ext/mypy/names.py +335 -0
  134. sqlalchemy/ext/mypy/plugin.py +303 -0
  135. sqlalchemy/ext/mypy/util.py +357 -0
  136. sqlalchemy/ext/orderinglist.py +439 -0
  137. sqlalchemy/ext/serializer.py +185 -0
  138. sqlalchemy/future/__init__.py +16 -0
  139. sqlalchemy/future/engine.py +15 -0
  140. sqlalchemy/inspection.py +174 -0
  141. sqlalchemy/log.py +288 -0
  142. sqlalchemy/orm/__init__.py +171 -0
  143. sqlalchemy/orm/_orm_constructors.py +2661 -0
  144. sqlalchemy/orm/_typing.py +179 -0
  145. sqlalchemy/orm/attributes.py +2845 -0
  146. sqlalchemy/orm/base.py +971 -0
  147. sqlalchemy/orm/bulk_persistence.py +2135 -0
  148. sqlalchemy/orm/clsregistry.py +571 -0
  149. sqlalchemy/orm/collections.py +1627 -0
  150. sqlalchemy/orm/context.py +3334 -0
  151. sqlalchemy/orm/decl_api.py +2004 -0
  152. sqlalchemy/orm/decl_base.py +2192 -0
  153. sqlalchemy/orm/dependency.py +1302 -0
  154. sqlalchemy/orm/descriptor_props.py +1092 -0
  155. sqlalchemy/orm/dynamic.py +300 -0
  156. sqlalchemy/orm/evaluator.py +379 -0
  157. sqlalchemy/orm/events.py +3252 -0
  158. sqlalchemy/orm/exc.py +237 -0
  159. sqlalchemy/orm/identity.py +302 -0
  160. sqlalchemy/orm/instrumentation.py +754 -0
  161. sqlalchemy/orm/interfaces.py +1496 -0
  162. sqlalchemy/orm/loading.py +1686 -0
  163. sqlalchemy/orm/mapped_collection.py +557 -0
  164. sqlalchemy/orm/mapper.py +4444 -0
  165. sqlalchemy/orm/path_registry.py +809 -0
  166. sqlalchemy/orm/persistence.py +1788 -0
  167. sqlalchemy/orm/properties.py +935 -0
  168. sqlalchemy/orm/query.py +3459 -0
  169. sqlalchemy/orm/relationships.py +3508 -0
  170. sqlalchemy/orm/scoping.py +2148 -0
  171. sqlalchemy/orm/session.py +5280 -0
  172. sqlalchemy/orm/state.py +1168 -0
  173. sqlalchemy/orm/state_changes.py +196 -0
  174. sqlalchemy/orm/strategies.py +3470 -0
  175. sqlalchemy/orm/strategy_options.py +2568 -0
  176. sqlalchemy/orm/sync.py +164 -0
  177. sqlalchemy/orm/unitofwork.py +796 -0
  178. sqlalchemy/orm/util.py +2403 -0
  179. sqlalchemy/orm/writeonly.py +674 -0
  180. sqlalchemy/pool/__init__.py +44 -0
  181. sqlalchemy/pool/base.py +1524 -0
  182. sqlalchemy/pool/events.py +375 -0
  183. sqlalchemy/pool/impl.py +588 -0
  184. sqlalchemy/py.typed +0 -0
  185. sqlalchemy/schema.py +69 -0
  186. sqlalchemy/sql/__init__.py +145 -0
  187. sqlalchemy/sql/_dml_constructors.py +132 -0
  188. sqlalchemy/sql/_elements_constructors.py +1872 -0
  189. sqlalchemy/sql/_orm_types.py +20 -0
  190. sqlalchemy/sql/_py_util.py +75 -0
  191. sqlalchemy/sql/_selectable_constructors.py +763 -0
  192. sqlalchemy/sql/_typing.py +482 -0
  193. sqlalchemy/sql/annotation.py +587 -0
  194. sqlalchemy/sql/base.py +2293 -0
  195. sqlalchemy/sql/cache_key.py +1057 -0
  196. sqlalchemy/sql/coercions.py +1404 -0
  197. sqlalchemy/sql/compiler.py +8081 -0
  198. sqlalchemy/sql/crud.py +1752 -0
  199. sqlalchemy/sql/ddl.py +1444 -0
  200. sqlalchemy/sql/default_comparator.py +551 -0
  201. sqlalchemy/sql/dml.py +1850 -0
  202. sqlalchemy/sql/elements.py +5589 -0
  203. sqlalchemy/sql/events.py +458 -0
  204. sqlalchemy/sql/expression.py +159 -0
  205. sqlalchemy/sql/functions.py +2158 -0
  206. sqlalchemy/sql/lambdas.py +1442 -0
  207. sqlalchemy/sql/naming.py +209 -0
  208. sqlalchemy/sql/operators.py +2623 -0
  209. sqlalchemy/sql/roles.py +323 -0
  210. sqlalchemy/sql/schema.py +6222 -0
  211. sqlalchemy/sql/selectable.py +7265 -0
  212. sqlalchemy/sql/sqltypes.py +3930 -0
  213. sqlalchemy/sql/traversals.py +1024 -0
  214. sqlalchemy/sql/type_api.py +2368 -0
  215. sqlalchemy/sql/util.py +1485 -0
  216. sqlalchemy/sql/visitors.py +1164 -0
  217. sqlalchemy/testing/__init__.py +96 -0
  218. sqlalchemy/testing/assertions.py +994 -0
  219. sqlalchemy/testing/assertsql.py +520 -0
  220. sqlalchemy/testing/asyncio.py +135 -0
  221. sqlalchemy/testing/config.py +434 -0
  222. sqlalchemy/testing/engines.py +483 -0
  223. sqlalchemy/testing/entities.py +117 -0
  224. sqlalchemy/testing/exclusions.py +476 -0
  225. sqlalchemy/testing/fixtures/__init__.py +28 -0
  226. sqlalchemy/testing/fixtures/base.py +384 -0
  227. sqlalchemy/testing/fixtures/mypy.py +332 -0
  228. sqlalchemy/testing/fixtures/orm.py +227 -0
  229. sqlalchemy/testing/fixtures/sql.py +482 -0
  230. sqlalchemy/testing/pickleable.py +155 -0
  231. sqlalchemy/testing/plugin/__init__.py +6 -0
  232. sqlalchemy/testing/plugin/bootstrap.py +51 -0
  233. sqlalchemy/testing/plugin/plugin_base.py +828 -0
  234. sqlalchemy/testing/plugin/pytestplugin.py +892 -0
  235. sqlalchemy/testing/profiling.py +329 -0
  236. sqlalchemy/testing/provision.py +603 -0
  237. sqlalchemy/testing/requirements.py +1945 -0
  238. sqlalchemy/testing/schema.py +198 -0
  239. sqlalchemy/testing/suite/__init__.py +19 -0
  240. sqlalchemy/testing/suite/test_cte.py +237 -0
  241. sqlalchemy/testing/suite/test_ddl.py +389 -0
  242. sqlalchemy/testing/suite/test_deprecations.py +153 -0
  243. sqlalchemy/testing/suite/test_dialect.py +776 -0
  244. sqlalchemy/testing/suite/test_insert.py +630 -0
  245. sqlalchemy/testing/suite/test_reflection.py +3557 -0
  246. sqlalchemy/testing/suite/test_results.py +504 -0
  247. sqlalchemy/testing/suite/test_rowcount.py +258 -0
  248. sqlalchemy/testing/suite/test_select.py +2010 -0
  249. sqlalchemy/testing/suite/test_sequence.py +317 -0
  250. sqlalchemy/testing/suite/test_types.py +2147 -0
  251. sqlalchemy/testing/suite/test_unicode_ddl.py +189 -0
  252. sqlalchemy/testing/suite/test_update_delete.py +139 -0
  253. sqlalchemy/testing/util.py +535 -0
  254. sqlalchemy/testing/warnings.py +52 -0
  255. sqlalchemy/types.py +74 -0
  256. sqlalchemy/util/__init__.py +162 -0
  257. sqlalchemy/util/_collections.py +712 -0
  258. sqlalchemy/util/_concurrency_py3k.py +288 -0
  259. sqlalchemy/util/_has_cy.py +40 -0
  260. sqlalchemy/util/_py_collections.py +541 -0
  261. sqlalchemy/util/compat.py +421 -0
  262. sqlalchemy/util/concurrency.py +110 -0
  263. sqlalchemy/util/deprecations.py +401 -0
  264. sqlalchemy/util/langhelpers.py +2203 -0
  265. sqlalchemy/util/preloaded.py +150 -0
  266. sqlalchemy/util/queue.py +322 -0
  267. sqlalchemy/util/tool_support.py +201 -0
  268. sqlalchemy/util/topological.py +120 -0
  269. sqlalchemy/util/typing.py +734 -0
  270. sqlalchemy-2.0.47.dist-info/METADATA +243 -0
  271. sqlalchemy-2.0.47.dist-info/RECORD +274 -0
  272. sqlalchemy-2.0.47.dist-info/WHEEL +5 -0
  273. sqlalchemy-2.0.47.dist-info/licenses/LICENSE +19 -0
  274. sqlalchemy-2.0.47.dist-info/top_level.txt +1 -0
@@ -0,0 +1,524 @@
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 schema
19
+ from ... import util
20
+ from ...sql import coercions
21
+ from ...sql import elements
22
+ from ...sql import roles
23
+ from ...sql import sqltypes
24
+ from ...sql import type_api
25
+ from ...sql.base import _NoArg
26
+ from ...sql.ddl import InvokeCreateDDLBase
27
+ from ...sql.ddl import InvokeDropDDLBase
28
+
29
+ if TYPE_CHECKING:
30
+ from ...sql._typing import _CreateDropBind
31
+ from ...sql._typing import _TypeEngineArgument
32
+
33
+
34
+ class NamedType(schema.SchemaVisitable, sqltypes.TypeEngine):
35
+ """Base for named types."""
36
+
37
+ __abstract__ = True
38
+ DDLGenerator: Type[NamedTypeGenerator]
39
+ DDLDropper: Type[NamedTypeDropper]
40
+ create_type: bool
41
+
42
+ def create(
43
+ self, bind: _CreateDropBind, checkfirst: bool = True, **kw: Any
44
+ ) -> None:
45
+ """Emit ``CREATE`` DDL for this type.
46
+
47
+ :param bind: a connectable :class:`_engine.Engine`,
48
+ :class:`_engine.Connection`, or similar object to emit
49
+ SQL.
50
+ :param checkfirst: if ``True``, a query against
51
+ the PG catalog will be first performed to see
52
+ if the type does not exist already before
53
+ creating.
54
+
55
+ """
56
+ bind._run_ddl_visitor(self.DDLGenerator, self, checkfirst=checkfirst)
57
+
58
+ def drop(
59
+ self, bind: _CreateDropBind, checkfirst: bool = True, **kw: Any
60
+ ) -> None:
61
+ """Emit ``DROP`` DDL for this type.
62
+
63
+ :param bind: a connectable :class:`_engine.Engine`,
64
+ :class:`_engine.Connection`, or similar object to emit
65
+ SQL.
66
+ :param checkfirst: if ``True``, a query against
67
+ the PG catalog will be first performed to see
68
+ if the type actually exists before dropping.
69
+
70
+ """
71
+ bind._run_ddl_visitor(self.DDLDropper, self, checkfirst=checkfirst)
72
+
73
+ def _check_for_name_in_memos(
74
+ self, checkfirst: bool, kw: Dict[str, Any]
75
+ ) -> bool:
76
+ """Look in the 'ddl runner' for 'memos', then
77
+ note our name in that collection.
78
+
79
+ This to ensure a particular named type is operated
80
+ upon only once within any kind of create/drop
81
+ sequence without relying upon "checkfirst".
82
+
83
+ """
84
+ if not self.create_type:
85
+ return True
86
+ if "_ddl_runner" in kw:
87
+ ddl_runner = kw["_ddl_runner"]
88
+ type_name = f"pg_{self.__visit_name__}"
89
+ if type_name in ddl_runner.memo:
90
+ existing = ddl_runner.memo[type_name]
91
+ else:
92
+ existing = ddl_runner.memo[type_name] = set()
93
+ present = (self.schema, self.name) in existing
94
+ existing.add((self.schema, self.name))
95
+ return present
96
+ else:
97
+ return False
98
+
99
+ def _on_table_create(
100
+ self,
101
+ target: Any,
102
+ bind: _CreateDropBind,
103
+ checkfirst: bool = False,
104
+ **kw: Any,
105
+ ) -> None:
106
+ if (
107
+ checkfirst
108
+ or (
109
+ not self.metadata
110
+ and not kw.get("_is_metadata_operation", False)
111
+ )
112
+ ) and not self._check_for_name_in_memos(checkfirst, kw):
113
+ self.create(bind=bind, checkfirst=checkfirst)
114
+
115
+ def _on_table_drop(
116
+ self,
117
+ target: Any,
118
+ bind: _CreateDropBind,
119
+ checkfirst: bool = False,
120
+ **kw: Any,
121
+ ) -> None:
122
+ if (
123
+ not self.metadata
124
+ and not kw.get("_is_metadata_operation", False)
125
+ and not self._check_for_name_in_memos(checkfirst, kw)
126
+ ):
127
+ self.drop(bind=bind, checkfirst=checkfirst)
128
+
129
+ def _on_metadata_create(
130
+ self,
131
+ target: Any,
132
+ bind: _CreateDropBind,
133
+ checkfirst: bool = False,
134
+ **kw: Any,
135
+ ) -> None:
136
+ if not self._check_for_name_in_memos(checkfirst, kw):
137
+ self.create(bind=bind, checkfirst=checkfirst)
138
+
139
+ def _on_metadata_drop(
140
+ self,
141
+ target: Any,
142
+ bind: _CreateDropBind,
143
+ checkfirst: bool = False,
144
+ **kw: Any,
145
+ ) -> None:
146
+ if not self._check_for_name_in_memos(checkfirst, kw):
147
+ self.drop(bind=bind, checkfirst=checkfirst)
148
+
149
+
150
+ class NamedTypeGenerator(InvokeCreateDDLBase):
151
+ def __init__(self, dialect, connection, checkfirst=False, **kwargs):
152
+ super().__init__(connection, **kwargs)
153
+ self.checkfirst = checkfirst
154
+
155
+ def _can_create_type(self, type_):
156
+ if not self.checkfirst:
157
+ return True
158
+
159
+ effective_schema = self.connection.schema_for_object(type_)
160
+ return not self.connection.dialect.has_type(
161
+ self.connection, type_.name, schema=effective_schema
162
+ )
163
+
164
+
165
+ class NamedTypeDropper(InvokeDropDDLBase):
166
+ def __init__(self, dialect, connection, checkfirst=False, **kwargs):
167
+ super().__init__(connection, **kwargs)
168
+ self.checkfirst = checkfirst
169
+
170
+ def _can_drop_type(self, type_):
171
+ if not self.checkfirst:
172
+ return True
173
+
174
+ effective_schema = self.connection.schema_for_object(type_)
175
+ return self.connection.dialect.has_type(
176
+ self.connection, type_.name, schema=effective_schema
177
+ )
178
+
179
+
180
+ class EnumGenerator(NamedTypeGenerator):
181
+ def visit_enum(self, enum):
182
+ if not self._can_create_type(enum):
183
+ return
184
+
185
+ with self.with_ddl_events(enum):
186
+ self.connection.execute(CreateEnumType(enum))
187
+
188
+
189
+ class EnumDropper(NamedTypeDropper):
190
+ def visit_enum(self, enum):
191
+ if not self._can_drop_type(enum):
192
+ return
193
+
194
+ with self.with_ddl_events(enum):
195
+ self.connection.execute(DropEnumType(enum))
196
+
197
+
198
+ class ENUM(NamedType, type_api.NativeForEmulated, sqltypes.Enum):
199
+ """PostgreSQL ENUM type.
200
+
201
+ This is a subclass of :class:`_types.Enum` which includes
202
+ support for PG's ``CREATE TYPE`` and ``DROP TYPE``.
203
+
204
+ When the builtin type :class:`_types.Enum` is used and the
205
+ :paramref:`.Enum.native_enum` flag is left at its default of
206
+ True, the PostgreSQL backend will use a :class:`_postgresql.ENUM`
207
+ type as the implementation, so the special create/drop rules
208
+ will be used.
209
+
210
+ The create/drop behavior of ENUM is necessarily intricate, due to the
211
+ awkward relationship the ENUM type has in relationship to the
212
+ parent table, in that it may be "owned" by just a single table, or
213
+ may be shared among many tables.
214
+
215
+ When using :class:`_types.Enum` or :class:`_postgresql.ENUM`
216
+ in an "inline" fashion, the ``CREATE TYPE`` and ``DROP TYPE`` is emitted
217
+ corresponding to when the :meth:`_schema.Table.create` and
218
+ :meth:`_schema.Table.drop`
219
+ methods are called::
220
+
221
+ table = Table(
222
+ "sometable",
223
+ metadata,
224
+ Column("some_enum", ENUM("a", "b", "c", name="myenum")),
225
+ )
226
+
227
+ table.create(engine) # will emit CREATE ENUM and CREATE TABLE
228
+ table.drop(engine) # will emit DROP TABLE and DROP ENUM
229
+
230
+ To use a common enumerated type between multiple tables, the best
231
+ practice is to declare the :class:`_types.Enum` or
232
+ :class:`_postgresql.ENUM` independently, and associate it with the
233
+ :class:`_schema.MetaData` object itself::
234
+
235
+ my_enum = ENUM("a", "b", "c", name="myenum", metadata=metadata)
236
+
237
+ t1 = Table("sometable_one", metadata, Column("some_enum", myenum))
238
+
239
+ t2 = Table("sometable_two", metadata, Column("some_enum", myenum))
240
+
241
+ When this pattern is used, care must still be taken at the level
242
+ of individual table creates. Emitting CREATE TABLE without also
243
+ specifying ``checkfirst=True`` will still cause issues::
244
+
245
+ t1.create(engine) # will fail: no such type 'myenum'
246
+
247
+ If we specify ``checkfirst=True``, the individual table-level create
248
+ operation will check for the ``ENUM`` and create if not exists::
249
+
250
+ # will check if enum exists, and emit CREATE TYPE if not
251
+ t1.create(engine, checkfirst=True)
252
+
253
+ When using a metadata-level ENUM type, the type will always be created
254
+ and dropped if either the metadata-wide create/drop is called::
255
+
256
+ metadata.create_all(engine) # will emit CREATE TYPE
257
+ metadata.drop_all(engine) # will emit DROP TYPE
258
+
259
+ The type can also be created and dropped directly::
260
+
261
+ my_enum.create(engine)
262
+ my_enum.drop(engine)
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; and additionally
288
+ that ``DROP TYPE`` is called when the table
289
+ is dropped. When ``False``, no check
290
+ will be performed and no ``CREATE TYPE``
291
+ or ``DROP TYPE`` is emitted, unless
292
+ :meth:`~.postgresql.ENUM.create`
293
+ or :meth:`~.postgresql.ENUM.drop`
294
+ are called directly.
295
+ Setting to ``False`` is helpful
296
+ when invoking a creation scheme to a SQL file
297
+ without access to the actual database -
298
+ the :meth:`~.postgresql.ENUM.create` and
299
+ :meth:`~.postgresql.ENUM.drop` methods can
300
+ be used to emit SQL to a target bind.
301
+
302
+ """
303
+ native_enum = kw.pop("native_enum", None)
304
+ if native_enum is False:
305
+ util.warn(
306
+ "the native_enum flag does not apply to the "
307
+ "sqlalchemy.dialects.postgresql.ENUM datatype; this type "
308
+ "always refers to ENUM. Use sqlalchemy.types.Enum for "
309
+ "non-native enum."
310
+ )
311
+ self.create_type = create_type
312
+ if name is not _NoArg.NO_ARG:
313
+ kw["name"] = name
314
+ super().__init__(*enums, **kw)
315
+
316
+ def coerce_compared_value(self, op, value):
317
+ super_coerced_type = super().coerce_compared_value(op, value)
318
+ if (
319
+ super_coerced_type._type_affinity
320
+ is type_api.STRINGTYPE._type_affinity
321
+ ):
322
+ return self
323
+ else:
324
+ return super_coerced_type
325
+
326
+ @classmethod
327
+ def __test_init__(cls):
328
+ return cls(name="name")
329
+
330
+ @classmethod
331
+ def adapt_emulated_to_native(cls, impl, **kw):
332
+ """Produce a PostgreSQL native :class:`_postgresql.ENUM` from plain
333
+ :class:`.Enum`.
334
+
335
+ """
336
+ kw.setdefault("validate_strings", impl.validate_strings)
337
+ kw.setdefault("name", impl.name)
338
+ kw.setdefault("schema", impl.schema)
339
+ kw.setdefault("inherit_schema", impl.inherit_schema)
340
+ kw.setdefault("metadata", impl.metadata)
341
+ kw.setdefault("_create_events", False)
342
+ kw.setdefault("values_callable", impl.values_callable)
343
+ kw.setdefault("omit_aliases", impl._omit_aliases)
344
+ kw.setdefault("_adapted_from", impl)
345
+ if type_api._is_native_for_emulated(impl.__class__):
346
+ kw.setdefault("create_type", impl.create_type)
347
+
348
+ return cls(**kw)
349
+
350
+ def create(self, bind: _CreateDropBind, checkfirst: bool = True) -> None:
351
+ """Emit ``CREATE TYPE`` for this
352
+ :class:`_postgresql.ENUM`.
353
+
354
+ If the underlying dialect does not support
355
+ PostgreSQL CREATE TYPE, no action is taken.
356
+
357
+ :param bind: a connectable :class:`_engine.Engine`,
358
+ :class:`_engine.Connection`, or similar object to emit
359
+ SQL.
360
+ :param checkfirst: if ``True``, a query against
361
+ the PG catalog will be first performed to see
362
+ if the type does not exist already before
363
+ creating.
364
+
365
+ """
366
+ if not bind.dialect.supports_native_enum:
367
+ return
368
+
369
+ super().create(bind, checkfirst=checkfirst)
370
+
371
+ def drop(self, bind: _CreateDropBind, checkfirst: bool = True) -> None:
372
+ """Emit ``DROP TYPE`` for this
373
+ :class:`_postgresql.ENUM`.
374
+
375
+ If the underlying dialect does not support
376
+ PostgreSQL DROP TYPE, no action is taken.
377
+
378
+ :param bind: a connectable :class:`_engine.Engine`,
379
+ :class:`_engine.Connection`, or similar object to emit
380
+ SQL.
381
+ :param checkfirst: if ``True``, a query against
382
+ the PG catalog will be first performed to see
383
+ if the type actually exists before dropping.
384
+
385
+ """
386
+ if not bind.dialect.supports_native_enum:
387
+ return
388
+
389
+ super().drop(bind, checkfirst=checkfirst)
390
+
391
+ def get_dbapi_type(self, dbapi: ModuleType) -> None:
392
+ """dont return dbapi.STRING for ENUM in PostgreSQL, since that's
393
+ a different type"""
394
+
395
+ return None
396
+
397
+
398
+ class DomainGenerator(NamedTypeGenerator):
399
+ def visit_DOMAIN(self, domain):
400
+ if not self._can_create_type(domain):
401
+ return
402
+ with self.with_ddl_events(domain):
403
+ self.connection.execute(CreateDomainType(domain))
404
+
405
+
406
+ class DomainDropper(NamedTypeDropper):
407
+ def visit_DOMAIN(self, domain):
408
+ if not self._can_drop_type(domain):
409
+ return
410
+
411
+ with self.with_ddl_events(domain):
412
+ self.connection.execute(DropDomainType(domain))
413
+
414
+
415
+ class DOMAIN(NamedType, sqltypes.SchemaType):
416
+ r"""Represent the DOMAIN PostgreSQL type.
417
+
418
+ A domain is essentially a data type with optional constraints
419
+ that restrict the allowed set of values. E.g.::
420
+
421
+ PositiveInt = DOMAIN("pos_int", Integer, check="VALUE > 0", not_null=True)
422
+
423
+ UsPostalCode = DOMAIN(
424
+ "us_postal_code",
425
+ Text,
426
+ check="VALUE ~ '^\d{5}$' OR VALUE ~ '^\d{5}-\d{4}$'",
427
+ )
428
+
429
+ See the `PostgreSQL documentation`__ for additional details
430
+
431
+ __ https://www.postgresql.org/docs/current/sql-createdomain.html
432
+
433
+ .. versionadded:: 2.0
434
+
435
+ """ # noqa: E501
436
+
437
+ DDLGenerator = DomainGenerator
438
+ DDLDropper = DomainDropper
439
+
440
+ __visit_name__ = "DOMAIN"
441
+
442
+ def __init__(
443
+ self,
444
+ name: str,
445
+ data_type: _TypeEngineArgument[Any],
446
+ *,
447
+ collation: 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 default: The DEFAULT clause specifies a default value for
466
+ columns of the domain data type. The default should be a string
467
+ or a :func:`_expression.text` value.
468
+ If no default value is specified, then the default value is
469
+ the null value.
470
+ :param constraint_name: An optional name for a constraint.
471
+ If not specified, the backend generates a name.
472
+ :param not_null: Values of this domain are prevented from being null.
473
+ By default domain are allowed to be null. If not specified
474
+ no nullability clause will be emitted.
475
+ :param check: CHECK clause specify integrity constraint or test
476
+ which values of the domain must satisfy. A constraint must be
477
+ an expression producing a Boolean result that can use the key
478
+ word VALUE to refer to the value being tested.
479
+ Differently from PostgreSQL, only a single check clause is
480
+ currently allowed in SQLAlchemy.
481
+ :param schema: optional schema name
482
+ :param metadata: optional :class:`_schema.MetaData` object which
483
+ this :class:`_postgresql.DOMAIN` will be directly associated
484
+ :param create_type: Defaults to True.
485
+ Indicates that ``CREATE TYPE`` should be emitted, after optionally
486
+ checking for the presence of the type, when the parent table is
487
+ being created; and additionally that ``DROP TYPE`` is called
488
+ when the table is dropped.
489
+
490
+ """
491
+ self.data_type = type_api.to_instance(data_type)
492
+ self.default = default
493
+ self.collation = collation
494
+ self.constraint_name = constraint_name
495
+ self.not_null = bool(not_null)
496
+ if check is not None:
497
+ check = coercions.expect(roles.DDLExpressionRole, check)
498
+ self.check = check
499
+ self.create_type = create_type
500
+ super().__init__(name=name, **kw)
501
+
502
+ @classmethod
503
+ def __test_init__(cls):
504
+ return cls("name", sqltypes.Integer)
505
+
506
+
507
+ class CreateEnumType(schema._CreateDropBase):
508
+ __visit_name__ = "create_enum_type"
509
+
510
+
511
+ class DropEnumType(schema._CreateDropBase):
512
+ __visit_name__ = "drop_enum_type"
513
+
514
+
515
+ class CreateDomainType(schema._CreateDropBase):
516
+ """Represent a CREATE DOMAIN statement."""
517
+
518
+ __visit_name__ = "create_domain_type"
519
+
520
+
521
+ class DropDomainType(schema._CreateDropBase):
522
+ """Represent a DROP DOMAIN statement."""
523
+
524
+ __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
+
11
+ _getitem_precedence = operators._PRECEDENCE[operators.json_getitem_op]
12
+ _eq_precedence = operators._PRECEDENCE[operators.eq]
13
+
14
+ # JSON + JSONB
15
+ ASTEXT = operators.custom_op(
16
+ "->>",
17
+ precedence=_getitem_precedence,
18
+ natural_self_precedent=True,
19
+ eager_grouping=True,
20
+ )
21
+
22
+ JSONPATH_ASTEXT = operators.custom_op(
23
+ "#>>",
24
+ precedence=_getitem_precedence,
25
+ natural_self_precedent=True,
26
+ eager_grouping=True,
27
+ )
28
+
29
+ # JSONB + HSTORE
30
+ HAS_KEY = operators.custom_op(
31
+ "?",
32
+ precedence=_eq_precedence,
33
+ natural_self_precedent=True,
34
+ eager_grouping=True,
35
+ is_comparison=True,
36
+ )
37
+
38
+ HAS_ALL = operators.custom_op(
39
+ "?&",
40
+ precedence=_eq_precedence,
41
+ natural_self_precedent=True,
42
+ eager_grouping=True,
43
+ is_comparison=True,
44
+ )
45
+
46
+ HAS_ANY = operators.custom_op(
47
+ "?|",
48
+ precedence=_eq_precedence,
49
+ natural_self_precedent=True,
50
+ eager_grouping=True,
51
+ is_comparison=True,
52
+ )
53
+
54
+ # JSONB
55
+ DELETE_PATH = operators.custom_op(
56
+ "#-",
57
+ precedence=_getitem_precedence,
58
+ natural_self_precedent=True,
59
+ eager_grouping=True,
60
+ )
61
+
62
+ PATH_EXISTS = operators.custom_op(
63
+ "@?",
64
+ precedence=_eq_precedence,
65
+ natural_self_precedent=True,
66
+ eager_grouping=True,
67
+ is_comparison=True,
68
+ )
69
+
70
+ PATH_MATCH = operators.custom_op(
71
+ "@@",
72
+ precedence=_eq_precedence,
73
+ natural_self_precedent=True,
74
+ eager_grouping=True,
75
+ is_comparison=True,
76
+ )
77
+
78
+ # JSONB + ARRAY + HSTORE + RANGE
79
+ CONTAINS = operators.custom_op(
80
+ "@>",
81
+ precedence=_eq_precedence,
82
+ natural_self_precedent=True,
83
+ eager_grouping=True,
84
+ is_comparison=True,
85
+ )
86
+
87
+ CONTAINED_BY = operators.custom_op(
88
+ "<@",
89
+ precedence=_eq_precedence,
90
+ natural_self_precedent=True,
91
+ eager_grouping=True,
92
+ is_comparison=True,
93
+ )
94
+
95
+ # ARRAY + RANGE
96
+ OVERLAP = operators.custom_op(
97
+ "&&",
98
+ precedence=_eq_precedence,
99
+ is_comparison=True,
100
+ )
101
+
102
+ # RANGE
103
+ STRICTLY_LEFT_OF = operators.custom_op(
104
+ "<<", precedence=_eq_precedence, is_comparison=True
105
+ )
106
+
107
+ STRICTLY_RIGHT_OF = operators.custom_op(
108
+ ">>", precedence=_eq_precedence, is_comparison=True
109
+ )
110
+
111
+ NOT_EXTEND_RIGHT_OF = operators.custom_op(
112
+ "&<", precedence=_eq_precedence, is_comparison=True
113
+ )
114
+
115
+ NOT_EXTEND_LEFT_OF = operators.custom_op(
116
+ "&>", precedence=_eq_precedence, is_comparison=True
117
+ )
118
+
119
+ ADJACENT_TO = operators.custom_op(
120
+ "-|-", precedence=_eq_precedence, is_comparison=True
121
+ )
122
+
123
+ # HSTORE
124
+ GETITEM = operators.custom_op(
125
+ "->",
126
+ precedence=_getitem_precedence,
127
+ natural_self_precedent=True,
128
+ eager_grouping=True,
129
+ )