SQLAlchemy 2.0.36__cp313-cp313-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 (273) hide show
  1. SQLAlchemy-2.0.36.dist-info/LICENSE +19 -0
  2. SQLAlchemy-2.0.36.dist-info/METADATA +243 -0
  3. SQLAlchemy-2.0.36.dist-info/RECORD +273 -0
  4. SQLAlchemy-2.0.36.dist-info/WHEEL +5 -0
  5. SQLAlchemy-2.0.36.dist-info/top_level.txt +1 -0
  6. sqlalchemy/__init__.py +294 -0
  7. sqlalchemy/connectors/__init__.py +18 -0
  8. sqlalchemy/connectors/aioodbc.py +174 -0
  9. sqlalchemy/connectors/asyncio.py +213 -0
  10. sqlalchemy/connectors/pyodbc.py +249 -0
  11. sqlalchemy/cyextension/__init__.py +6 -0
  12. sqlalchemy/cyextension/collections.cp313-win32.pyd +0 -0
  13. sqlalchemy/cyextension/collections.pyx +409 -0
  14. sqlalchemy/cyextension/immutabledict.cp313-win32.pyd +0 -0
  15. sqlalchemy/cyextension/immutabledict.pxd +8 -0
  16. sqlalchemy/cyextension/immutabledict.pyx +133 -0
  17. sqlalchemy/cyextension/processors.cp313-win32.pyd +0 -0
  18. sqlalchemy/cyextension/processors.pyx +68 -0
  19. sqlalchemy/cyextension/resultproxy.cp313-win32.pyd +0 -0
  20. sqlalchemy/cyextension/resultproxy.pyx +102 -0
  21. sqlalchemy/cyextension/util.cp313-win32.pyd +0 -0
  22. sqlalchemy/cyextension/util.pyx +91 -0
  23. sqlalchemy/dialects/__init__.py +61 -0
  24. sqlalchemy/dialects/_typing.py +25 -0
  25. sqlalchemy/dialects/mssql/__init__.py +88 -0
  26. sqlalchemy/dialects/mssql/aioodbc.py +64 -0
  27. sqlalchemy/dialects/mssql/base.py +4010 -0
  28. sqlalchemy/dialects/mssql/information_schema.py +254 -0
  29. sqlalchemy/dialects/mssql/json.py +133 -0
  30. sqlalchemy/dialects/mssql/provision.py +162 -0
  31. sqlalchemy/dialects/mssql/pymssql.py +126 -0
  32. sqlalchemy/dialects/mssql/pyodbc.py +745 -0
  33. sqlalchemy/dialects/mysql/__init__.py +101 -0
  34. sqlalchemy/dialects/mysql/aiomysql.py +333 -0
  35. sqlalchemy/dialects/mysql/asyncmy.py +337 -0
  36. sqlalchemy/dialects/mysql/base.py +3494 -0
  37. sqlalchemy/dialects/mysql/cymysql.py +84 -0
  38. sqlalchemy/dialects/mysql/dml.py +219 -0
  39. sqlalchemy/dialects/mysql/enumerated.py +244 -0
  40. sqlalchemy/dialects/mysql/expression.py +141 -0
  41. sqlalchemy/dialects/mysql/json.py +81 -0
  42. sqlalchemy/dialects/mysql/mariadb.py +32 -0
  43. sqlalchemy/dialects/mysql/mariadbconnector.py +277 -0
  44. sqlalchemy/dialects/mysql/mysqlconnector.py +180 -0
  45. sqlalchemy/dialects/mysql/mysqldb.py +303 -0
  46. sqlalchemy/dialects/mysql/provision.py +110 -0
  47. sqlalchemy/dialects/mysql/pymysql.py +137 -0
  48. sqlalchemy/dialects/mysql/pyodbc.py +138 -0
  49. sqlalchemy/dialects/mysql/reflection.py +677 -0
  50. sqlalchemy/dialects/mysql/reserved_words.py +571 -0
  51. sqlalchemy/dialects/mysql/types.py +774 -0
  52. sqlalchemy/dialects/oracle/__init__.py +67 -0
  53. sqlalchemy/dialects/oracle/base.py +3271 -0
  54. sqlalchemy/dialects/oracle/cx_oracle.py +1483 -0
  55. sqlalchemy/dialects/oracle/dictionary.py +507 -0
  56. sqlalchemy/dialects/oracle/oracledb.py +431 -0
  57. sqlalchemy/dialects/oracle/provision.py +220 -0
  58. sqlalchemy/dialects/oracle/types.py +287 -0
  59. sqlalchemy/dialects/postgresql/__init__.py +167 -0
  60. sqlalchemy/dialects/postgresql/_psycopg_common.py +187 -0
  61. sqlalchemy/dialects/postgresql/array.py +425 -0
  62. sqlalchemy/dialects/postgresql/asyncpg.py +1274 -0
  63. sqlalchemy/dialects/postgresql/base.py +5008 -0
  64. sqlalchemy/dialects/postgresql/dml.py +310 -0
  65. sqlalchemy/dialects/postgresql/ext.py +496 -0
  66. sqlalchemy/dialects/postgresql/hstore.py +397 -0
  67. sqlalchemy/dialects/postgresql/json.py +333 -0
  68. sqlalchemy/dialects/postgresql/named_types.py +509 -0
  69. sqlalchemy/dialects/postgresql/operators.py +129 -0
  70. sqlalchemy/dialects/postgresql/pg8000.py +662 -0
  71. sqlalchemy/dialects/postgresql/pg_catalog.py +300 -0
  72. sqlalchemy/dialects/postgresql/provision.py +175 -0
  73. sqlalchemy/dialects/postgresql/psycopg.py +772 -0
  74. sqlalchemy/dialects/postgresql/psycopg2.py +886 -0
  75. sqlalchemy/dialects/postgresql/psycopg2cffi.py +61 -0
  76. sqlalchemy/dialects/postgresql/ranges.py +1029 -0
  77. sqlalchemy/dialects/postgresql/types.py +303 -0
  78. sqlalchemy/dialects/sqlite/__init__.py +57 -0
  79. sqlalchemy/dialects/sqlite/aiosqlite.py +396 -0
  80. sqlalchemy/dialects/sqlite/base.py +2805 -0
  81. sqlalchemy/dialects/sqlite/dml.py +240 -0
  82. sqlalchemy/dialects/sqlite/json.py +92 -0
  83. sqlalchemy/dialects/sqlite/provision.py +198 -0
  84. sqlalchemy/dialects/sqlite/pysqlcipher.py +155 -0
  85. sqlalchemy/dialects/sqlite/pysqlite.py +756 -0
  86. sqlalchemy/dialects/type_migration_guidelines.txt +145 -0
  87. sqlalchemy/engine/__init__.py +62 -0
  88. sqlalchemy/engine/_py_processors.py +136 -0
  89. sqlalchemy/engine/_py_row.py +128 -0
  90. sqlalchemy/engine/_py_util.py +74 -0
  91. sqlalchemy/engine/base.py +3375 -0
  92. sqlalchemy/engine/characteristics.py +155 -0
  93. sqlalchemy/engine/create.py +875 -0
  94. sqlalchemy/engine/cursor.py +2181 -0
  95. sqlalchemy/engine/default.py +2365 -0
  96. sqlalchemy/engine/events.py +951 -0
  97. sqlalchemy/engine/interfaces.py +3403 -0
  98. sqlalchemy/engine/mock.py +131 -0
  99. sqlalchemy/engine/processors.py +61 -0
  100. sqlalchemy/engine/reflection.py +2098 -0
  101. sqlalchemy/engine/result.py +2382 -0
  102. sqlalchemy/engine/row.py +401 -0
  103. sqlalchemy/engine/strategies.py +19 -0
  104. sqlalchemy/engine/url.py +910 -0
  105. sqlalchemy/engine/util.py +167 -0
  106. sqlalchemy/event/__init__.py +25 -0
  107. sqlalchemy/event/api.py +225 -0
  108. sqlalchemy/event/attr.py +655 -0
  109. sqlalchemy/event/base.py +470 -0
  110. sqlalchemy/event/legacy.py +246 -0
  111. sqlalchemy/event/registry.py +386 -0
  112. sqlalchemy/events.py +17 -0
  113. sqlalchemy/exc.py +830 -0
  114. sqlalchemy/ext/__init__.py +11 -0
  115. sqlalchemy/ext/associationproxy.py +2013 -0
  116. sqlalchemy/ext/asyncio/__init__.py +25 -0
  117. sqlalchemy/ext/asyncio/base.py +279 -0
  118. sqlalchemy/ext/asyncio/engine.py +1466 -0
  119. sqlalchemy/ext/asyncio/exc.py +21 -0
  120. sqlalchemy/ext/asyncio/result.py +961 -0
  121. sqlalchemy/ext/asyncio/scoping.py +1614 -0
  122. sqlalchemy/ext/asyncio/session.py +1936 -0
  123. sqlalchemy/ext/automap.py +1691 -0
  124. sqlalchemy/ext/baked.py +574 -0
  125. sqlalchemy/ext/compiler.py +570 -0
  126. sqlalchemy/ext/declarative/__init__.py +65 -0
  127. sqlalchemy/ext/declarative/extensions.py +548 -0
  128. sqlalchemy/ext/horizontal_shard.py +481 -0
  129. sqlalchemy/ext/hybrid.py +1514 -0
  130. sqlalchemy/ext/indexable.py +341 -0
  131. sqlalchemy/ext/instrumentation.py +450 -0
  132. sqlalchemy/ext/mutable.py +1073 -0
  133. sqlalchemy/ext/mypy/__init__.py +6 -0
  134. sqlalchemy/ext/mypy/apply.py +320 -0
  135. sqlalchemy/ext/mypy/decl_class.py +515 -0
  136. sqlalchemy/ext/mypy/infer.py +590 -0
  137. sqlalchemy/ext/mypy/names.py +335 -0
  138. sqlalchemy/ext/mypy/plugin.py +303 -0
  139. sqlalchemy/ext/mypy/util.py +357 -0
  140. sqlalchemy/ext/orderinglist.py +416 -0
  141. sqlalchemy/ext/serializer.py +181 -0
  142. sqlalchemy/future/__init__.py +16 -0
  143. sqlalchemy/future/engine.py +15 -0
  144. sqlalchemy/inspection.py +174 -0
  145. sqlalchemy/log.py +288 -0
  146. sqlalchemy/orm/__init__.py +170 -0
  147. sqlalchemy/orm/_orm_constructors.py +2571 -0
  148. sqlalchemy/orm/_typing.py +179 -0
  149. sqlalchemy/orm/attributes.py +2835 -0
  150. sqlalchemy/orm/base.py +973 -0
  151. sqlalchemy/orm/bulk_persistence.py +2123 -0
  152. sqlalchemy/orm/clsregistry.py +571 -0
  153. sqlalchemy/orm/collections.py +1620 -0
  154. sqlalchemy/orm/context.py +3268 -0
  155. sqlalchemy/orm/decl_api.py +1883 -0
  156. sqlalchemy/orm/decl_base.py +2190 -0
  157. sqlalchemy/orm/dependency.py +1304 -0
  158. sqlalchemy/orm/descriptor_props.py +1076 -0
  159. sqlalchemy/orm/dynamic.py +300 -0
  160. sqlalchemy/orm/evaluator.py +379 -0
  161. sqlalchemy/orm/events.py +3261 -0
  162. sqlalchemy/orm/exc.py +228 -0
  163. sqlalchemy/orm/identity.py +302 -0
  164. sqlalchemy/orm/instrumentation.py +754 -0
  165. sqlalchemy/orm/interfaces.py +1474 -0
  166. sqlalchemy/orm/loading.py +1682 -0
  167. sqlalchemy/orm/mapped_collection.py +557 -0
  168. sqlalchemy/orm/mapper.py +4432 -0
  169. sqlalchemy/orm/path_registry.py +811 -0
  170. sqlalchemy/orm/persistence.py +1782 -0
  171. sqlalchemy/orm/properties.py +886 -0
  172. sqlalchemy/orm/query.py +3396 -0
  173. sqlalchemy/orm/relationships.py +3500 -0
  174. sqlalchemy/orm/scoping.py +2165 -0
  175. sqlalchemy/orm/session.py +5301 -0
  176. sqlalchemy/orm/state.py +1143 -0
  177. sqlalchemy/orm/state_changes.py +198 -0
  178. sqlalchemy/orm/strategies.py +3473 -0
  179. sqlalchemy/orm/strategy_options.py +2569 -0
  180. sqlalchemy/orm/sync.py +164 -0
  181. sqlalchemy/orm/unitofwork.py +796 -0
  182. sqlalchemy/orm/util.py +2424 -0
  183. sqlalchemy/orm/writeonly.py +678 -0
  184. sqlalchemy/pool/__init__.py +44 -0
  185. sqlalchemy/pool/base.py +1515 -0
  186. sqlalchemy/pool/events.py +370 -0
  187. sqlalchemy/pool/impl.py +581 -0
  188. sqlalchemy/py.typed +0 -0
  189. sqlalchemy/schema.py +70 -0
  190. sqlalchemy/sql/__init__.py +145 -0
  191. sqlalchemy/sql/_dml_constructors.py +140 -0
  192. sqlalchemy/sql/_elements_constructors.py +1850 -0
  193. sqlalchemy/sql/_orm_types.py +20 -0
  194. sqlalchemy/sql/_py_util.py +75 -0
  195. sqlalchemy/sql/_selectable_constructors.py +635 -0
  196. sqlalchemy/sql/_typing.py +460 -0
  197. sqlalchemy/sql/annotation.py +585 -0
  198. sqlalchemy/sql/base.py +2185 -0
  199. sqlalchemy/sql/cache_key.py +1057 -0
  200. sqlalchemy/sql/coercions.py +1405 -0
  201. sqlalchemy/sql/compiler.py +7818 -0
  202. sqlalchemy/sql/crud.py +1669 -0
  203. sqlalchemy/sql/ddl.py +1378 -0
  204. sqlalchemy/sql/default_comparator.py +552 -0
  205. sqlalchemy/sql/dml.py +1817 -0
  206. sqlalchemy/sql/elements.py +5499 -0
  207. sqlalchemy/sql/events.py +455 -0
  208. sqlalchemy/sql/expression.py +162 -0
  209. sqlalchemy/sql/functions.py +2055 -0
  210. sqlalchemy/sql/lambdas.py +1449 -0
  211. sqlalchemy/sql/naming.py +212 -0
  212. sqlalchemy/sql/operators.py +2579 -0
  213. sqlalchemy/sql/roles.py +323 -0
  214. sqlalchemy/sql/schema.py +6158 -0
  215. sqlalchemy/sql/selectable.py +7004 -0
  216. sqlalchemy/sql/sqltypes.py +3827 -0
  217. sqlalchemy/sql/traversals.py +1024 -0
  218. sqlalchemy/sql/type_api.py +2339 -0
  219. sqlalchemy/sql/util.py +1486 -0
  220. sqlalchemy/sql/visitors.py +1165 -0
  221. sqlalchemy/testing/__init__.py +96 -0
  222. sqlalchemy/testing/assertions.py +989 -0
  223. sqlalchemy/testing/assertsql.py +516 -0
  224. sqlalchemy/testing/asyncio.py +135 -0
  225. sqlalchemy/testing/config.py +427 -0
  226. sqlalchemy/testing/engines.py +472 -0
  227. sqlalchemy/testing/entities.py +117 -0
  228. sqlalchemy/testing/exclusions.py +435 -0
  229. sqlalchemy/testing/fixtures/__init__.py +28 -0
  230. sqlalchemy/testing/fixtures/base.py +366 -0
  231. sqlalchemy/testing/fixtures/mypy.py +312 -0
  232. sqlalchemy/testing/fixtures/orm.py +227 -0
  233. sqlalchemy/testing/fixtures/sql.py +503 -0
  234. sqlalchemy/testing/pickleable.py +155 -0
  235. sqlalchemy/testing/plugin/__init__.py +6 -0
  236. sqlalchemy/testing/plugin/bootstrap.py +51 -0
  237. sqlalchemy/testing/plugin/plugin_base.py +779 -0
  238. sqlalchemy/testing/plugin/pytestplugin.py +868 -0
  239. sqlalchemy/testing/profiling.py +324 -0
  240. sqlalchemy/testing/provision.py +496 -0
  241. sqlalchemy/testing/requirements.py +1818 -0
  242. sqlalchemy/testing/schema.py +224 -0
  243. sqlalchemy/testing/suite/__init__.py +19 -0
  244. sqlalchemy/testing/suite/test_cte.py +211 -0
  245. sqlalchemy/testing/suite/test_ddl.py +389 -0
  246. sqlalchemy/testing/suite/test_deprecations.py +153 -0
  247. sqlalchemy/testing/suite/test_dialect.py +740 -0
  248. sqlalchemy/testing/suite/test_insert.py +630 -0
  249. sqlalchemy/testing/suite/test_reflection.py +3225 -0
  250. sqlalchemy/testing/suite/test_results.py +502 -0
  251. sqlalchemy/testing/suite/test_rowcount.py +258 -0
  252. sqlalchemy/testing/suite/test_select.py +1999 -0
  253. sqlalchemy/testing/suite/test_sequence.py +317 -0
  254. sqlalchemy/testing/suite/test_types.py +2141 -0
  255. sqlalchemy/testing/suite/test_unicode_ddl.py +189 -0
  256. sqlalchemy/testing/suite/test_update_delete.py +139 -0
  257. sqlalchemy/testing/util.py +537 -0
  258. sqlalchemy/testing/warnings.py +52 -0
  259. sqlalchemy/types.py +76 -0
  260. sqlalchemy/util/__init__.py +160 -0
  261. sqlalchemy/util/_collections.py +715 -0
  262. sqlalchemy/util/_concurrency_py3k.py +288 -0
  263. sqlalchemy/util/_has_cy.py +40 -0
  264. sqlalchemy/util/_py_collections.py +541 -0
  265. sqlalchemy/util/compat.py +301 -0
  266. sqlalchemy/util/concurrency.py +108 -0
  267. sqlalchemy/util/deprecations.py +401 -0
  268. sqlalchemy/util/langhelpers.py +2218 -0
  269. sqlalchemy/util/preloaded.py +150 -0
  270. sqlalchemy/util/queue.py +322 -0
  271. sqlalchemy/util/tool_support.py +201 -0
  272. sqlalchemy/util/topological.py +120 -0
  273. sqlalchemy/util/typing.py +629 -0
@@ -0,0 +1,509 @@
1
+ # dialects/postgresql/named_types.py
2
+ # Copyright (C) 2005-2024 the SQLAlchemy authors and contributors
3
+ # <see AUTHORS file>
4
+ #
5
+ # This module is part of SQLAlchemy and is released under
6
+ # the MIT License: https://www.opensource.org/licenses/mit-license.php
7
+ # mypy: ignore-errors
8
+ from __future__ import annotations
9
+
10
+ from typing import Any
11
+ from typing import Optional
12
+ from typing import Type
13
+ from typing import TYPE_CHECKING
14
+ from typing import Union
15
+
16
+ from ... import schema
17
+ from ... import util
18
+ from ...sql import coercions
19
+ from ...sql import elements
20
+ from ...sql import roles
21
+ from ...sql import sqltypes
22
+ from ...sql import type_api
23
+ from ...sql.base import _NoArg
24
+ from ...sql.ddl import InvokeCreateDDLBase
25
+ from ...sql.ddl import InvokeDropDDLBase
26
+
27
+ if TYPE_CHECKING:
28
+ from ...sql._typing import _TypeEngineArgument
29
+
30
+
31
+ class NamedType(sqltypes.TypeEngine):
32
+ """Base for named types."""
33
+
34
+ __abstract__ = True
35
+ DDLGenerator: Type[NamedTypeGenerator]
36
+ DDLDropper: Type[NamedTypeDropper]
37
+ create_type: bool
38
+
39
+ def create(self, bind, checkfirst=True, **kw):
40
+ """Emit ``CREATE`` DDL for this type.
41
+
42
+ :param bind: a connectable :class:`_engine.Engine`,
43
+ :class:`_engine.Connection`, or similar object to emit
44
+ SQL.
45
+ :param checkfirst: if ``True``, a query against
46
+ the PG catalog will be first performed to see
47
+ if the type does not exist already before
48
+ creating.
49
+
50
+ """
51
+ bind._run_ddl_visitor(self.DDLGenerator, self, checkfirst=checkfirst)
52
+
53
+ def drop(self, bind, checkfirst=True, **kw):
54
+ """Emit ``DROP`` DDL for this type.
55
+
56
+ :param bind: a connectable :class:`_engine.Engine`,
57
+ :class:`_engine.Connection`, or similar object to emit
58
+ SQL.
59
+ :param checkfirst: if ``True``, a query against
60
+ the PG catalog will be first performed to see
61
+ if the type actually exists before dropping.
62
+
63
+ """
64
+ bind._run_ddl_visitor(self.DDLDropper, self, checkfirst=checkfirst)
65
+
66
+ def _check_for_name_in_memos(self, checkfirst, kw):
67
+ """Look in the 'ddl runner' for 'memos', then
68
+ note our name in that collection.
69
+
70
+ This to ensure a particular named type is operated
71
+ upon only once within any kind of create/drop
72
+ sequence without relying upon "checkfirst".
73
+
74
+ """
75
+ if not self.create_type:
76
+ return True
77
+ if "_ddl_runner" in kw:
78
+ ddl_runner = kw["_ddl_runner"]
79
+ type_name = f"pg_{self.__visit_name__}"
80
+ if type_name in ddl_runner.memo:
81
+ existing = ddl_runner.memo[type_name]
82
+ else:
83
+ existing = ddl_runner.memo[type_name] = set()
84
+ present = (self.schema, self.name) in existing
85
+ existing.add((self.schema, self.name))
86
+ return present
87
+ else:
88
+ return False
89
+
90
+ def _on_table_create(self, target, bind, checkfirst=False, **kw):
91
+ if (
92
+ checkfirst
93
+ or (
94
+ not self.metadata
95
+ and not kw.get("_is_metadata_operation", False)
96
+ )
97
+ ) and not self._check_for_name_in_memos(checkfirst, kw):
98
+ self.create(bind=bind, checkfirst=checkfirst)
99
+
100
+ def _on_table_drop(self, target, bind, checkfirst=False, **kw):
101
+ if (
102
+ not self.metadata
103
+ and not kw.get("_is_metadata_operation", False)
104
+ and not self._check_for_name_in_memos(checkfirst, kw)
105
+ ):
106
+ self.drop(bind=bind, checkfirst=checkfirst)
107
+
108
+ def _on_metadata_create(self, target, bind, checkfirst=False, **kw):
109
+ if not self._check_for_name_in_memos(checkfirst, kw):
110
+ self.create(bind=bind, checkfirst=checkfirst)
111
+
112
+ def _on_metadata_drop(self, target, bind, checkfirst=False, **kw):
113
+ if not self._check_for_name_in_memos(checkfirst, kw):
114
+ self.drop(bind=bind, checkfirst=checkfirst)
115
+
116
+
117
+ class NamedTypeGenerator(InvokeCreateDDLBase):
118
+ def __init__(self, dialect, connection, checkfirst=False, **kwargs):
119
+ super().__init__(connection, **kwargs)
120
+ self.checkfirst = checkfirst
121
+
122
+ def _can_create_type(self, type_):
123
+ if not self.checkfirst:
124
+ return True
125
+
126
+ effective_schema = self.connection.schema_for_object(type_)
127
+ return not self.connection.dialect.has_type(
128
+ self.connection, type_.name, schema=effective_schema
129
+ )
130
+
131
+
132
+ class NamedTypeDropper(InvokeDropDDLBase):
133
+ def __init__(self, dialect, connection, checkfirst=False, **kwargs):
134
+ super().__init__(connection, **kwargs)
135
+ self.checkfirst = checkfirst
136
+
137
+ def _can_drop_type(self, type_):
138
+ if not self.checkfirst:
139
+ return True
140
+
141
+ effective_schema = self.connection.schema_for_object(type_)
142
+ return self.connection.dialect.has_type(
143
+ self.connection, type_.name, schema=effective_schema
144
+ )
145
+
146
+
147
+ class EnumGenerator(NamedTypeGenerator):
148
+ def visit_enum(self, enum):
149
+ if not self._can_create_type(enum):
150
+ return
151
+
152
+ with self.with_ddl_events(enum):
153
+ self.connection.execute(CreateEnumType(enum))
154
+
155
+
156
+ class EnumDropper(NamedTypeDropper):
157
+ def visit_enum(self, enum):
158
+ if not self._can_drop_type(enum):
159
+ return
160
+
161
+ with self.with_ddl_events(enum):
162
+ self.connection.execute(DropEnumType(enum))
163
+
164
+
165
+ class ENUM(NamedType, type_api.NativeForEmulated, sqltypes.Enum):
166
+ """PostgreSQL ENUM type.
167
+
168
+ This is a subclass of :class:`_types.Enum` which includes
169
+ support for PG's ``CREATE TYPE`` and ``DROP TYPE``.
170
+
171
+ When the builtin type :class:`_types.Enum` is used and the
172
+ :paramref:`.Enum.native_enum` flag is left at its default of
173
+ True, the PostgreSQL backend will use a :class:`_postgresql.ENUM`
174
+ type as the implementation, so the special create/drop rules
175
+ will be used.
176
+
177
+ The create/drop behavior of ENUM is necessarily intricate, due to the
178
+ awkward relationship the ENUM type has in relationship to the
179
+ parent table, in that it may be "owned" by just a single table, or
180
+ may be shared among many tables.
181
+
182
+ When using :class:`_types.Enum` or :class:`_postgresql.ENUM`
183
+ in an "inline" fashion, the ``CREATE TYPE`` and ``DROP TYPE`` is emitted
184
+ corresponding to when the :meth:`_schema.Table.create` and
185
+ :meth:`_schema.Table.drop`
186
+ methods are called::
187
+
188
+ table = Table('sometable', metadata,
189
+ Column('some_enum', ENUM('a', 'b', 'c', name='myenum'))
190
+ )
191
+
192
+ table.create(engine) # will emit CREATE ENUM and CREATE TABLE
193
+ table.drop(engine) # will emit DROP TABLE and DROP ENUM
194
+
195
+ To use a common enumerated type between multiple tables, the best
196
+ practice is to declare the :class:`_types.Enum` or
197
+ :class:`_postgresql.ENUM` independently, and associate it with the
198
+ :class:`_schema.MetaData` object itself::
199
+
200
+ my_enum = ENUM('a', 'b', 'c', name='myenum', metadata=metadata)
201
+
202
+ t1 = Table('sometable_one', metadata,
203
+ Column('some_enum', myenum)
204
+ )
205
+
206
+ t2 = Table('sometable_two', metadata,
207
+ Column('some_enum', myenum)
208
+ )
209
+
210
+ When this pattern is used, care must still be taken at the level
211
+ of individual table creates. Emitting CREATE TABLE without also
212
+ specifying ``checkfirst=True`` will still cause issues::
213
+
214
+ t1.create(engine) # will fail: no such type 'myenum'
215
+
216
+ If we specify ``checkfirst=True``, the individual table-level create
217
+ operation will check for the ``ENUM`` and create if not exists::
218
+
219
+ # will check if enum exists, and emit CREATE TYPE if not
220
+ t1.create(engine, checkfirst=True)
221
+
222
+ When using a metadata-level ENUM type, the type will always be created
223
+ and dropped if either the metadata-wide create/drop is called::
224
+
225
+ metadata.create_all(engine) # will emit CREATE TYPE
226
+ metadata.drop_all(engine) # will emit DROP TYPE
227
+
228
+ The type can also be created and dropped directly::
229
+
230
+ my_enum.create(engine)
231
+ my_enum.drop(engine)
232
+
233
+ """
234
+
235
+ native_enum = True
236
+ DDLGenerator = EnumGenerator
237
+ DDLDropper = EnumDropper
238
+
239
+ def __init__(
240
+ self,
241
+ *enums,
242
+ name: Union[str, _NoArg, None] = _NoArg.NO_ARG,
243
+ create_type: bool = True,
244
+ **kw,
245
+ ):
246
+ """Construct an :class:`_postgresql.ENUM`.
247
+
248
+ Arguments are the same as that of
249
+ :class:`_types.Enum`, but also including
250
+ the following parameters.
251
+
252
+ :param create_type: Defaults to True.
253
+ Indicates that ``CREATE TYPE`` should be
254
+ emitted, after optionally checking for the
255
+ presence of the type, when the parent
256
+ table is being created; and additionally
257
+ that ``DROP TYPE`` is called when the table
258
+ is dropped. When ``False``, no check
259
+ will be performed and no ``CREATE TYPE``
260
+ or ``DROP TYPE`` is emitted, unless
261
+ :meth:`~.postgresql.ENUM.create`
262
+ or :meth:`~.postgresql.ENUM.drop`
263
+ are called directly.
264
+ Setting to ``False`` is helpful
265
+ when invoking a creation scheme to a SQL file
266
+ without access to the actual database -
267
+ the :meth:`~.postgresql.ENUM.create` and
268
+ :meth:`~.postgresql.ENUM.drop` methods can
269
+ be used to emit SQL to a target bind.
270
+
271
+ """
272
+ native_enum = kw.pop("native_enum", None)
273
+ if native_enum is False:
274
+ util.warn(
275
+ "the native_enum flag does not apply to the "
276
+ "sqlalchemy.dialects.postgresql.ENUM datatype; this type "
277
+ "always refers to ENUM. Use sqlalchemy.types.Enum for "
278
+ "non-native enum."
279
+ )
280
+ self.create_type = create_type
281
+ if name is not _NoArg.NO_ARG:
282
+ kw["name"] = name
283
+ super().__init__(*enums, **kw)
284
+
285
+ def coerce_compared_value(self, op, value):
286
+ super_coerced_type = super().coerce_compared_value(op, value)
287
+ if (
288
+ super_coerced_type._type_affinity
289
+ is type_api.STRINGTYPE._type_affinity
290
+ ):
291
+ return self
292
+ else:
293
+ return super_coerced_type
294
+
295
+ @classmethod
296
+ def __test_init__(cls):
297
+ return cls(name="name")
298
+
299
+ @classmethod
300
+ def adapt_emulated_to_native(cls, impl, **kw):
301
+ """Produce a PostgreSQL native :class:`_postgresql.ENUM` from plain
302
+ :class:`.Enum`.
303
+
304
+ """
305
+ kw.setdefault("validate_strings", impl.validate_strings)
306
+ kw.setdefault("name", impl.name)
307
+ kw.setdefault("schema", impl.schema)
308
+ kw.setdefault("inherit_schema", impl.inherit_schema)
309
+ kw.setdefault("metadata", impl.metadata)
310
+ kw.setdefault("_create_events", False)
311
+ kw.setdefault("values_callable", impl.values_callable)
312
+ kw.setdefault("omit_aliases", impl._omit_aliases)
313
+ kw.setdefault("_adapted_from", impl)
314
+ if type_api._is_native_for_emulated(impl.__class__):
315
+ kw.setdefault("create_type", impl.create_type)
316
+
317
+ return cls(**kw)
318
+
319
+ def create(self, bind=None, checkfirst=True):
320
+ """Emit ``CREATE TYPE`` for this
321
+ :class:`_postgresql.ENUM`.
322
+
323
+ If the underlying dialect does not support
324
+ PostgreSQL CREATE TYPE, no action is taken.
325
+
326
+ :param bind: a connectable :class:`_engine.Engine`,
327
+ :class:`_engine.Connection`, or similar object to emit
328
+ SQL.
329
+ :param checkfirst: if ``True``, a query against
330
+ the PG catalog will be first performed to see
331
+ if the type does not exist already before
332
+ creating.
333
+
334
+ """
335
+ if not bind.dialect.supports_native_enum:
336
+ return
337
+
338
+ super().create(bind, checkfirst=checkfirst)
339
+
340
+ def drop(self, bind=None, checkfirst=True):
341
+ """Emit ``DROP TYPE`` for this
342
+ :class:`_postgresql.ENUM`.
343
+
344
+ If the underlying dialect does not support
345
+ PostgreSQL DROP TYPE, no action is taken.
346
+
347
+ :param bind: a connectable :class:`_engine.Engine`,
348
+ :class:`_engine.Connection`, or similar object to emit
349
+ SQL.
350
+ :param checkfirst: if ``True``, a query against
351
+ the PG catalog will be first performed to see
352
+ if the type actually exists before dropping.
353
+
354
+ """
355
+ if not bind.dialect.supports_native_enum:
356
+ return
357
+
358
+ super().drop(bind, checkfirst=checkfirst)
359
+
360
+ def get_dbapi_type(self, dbapi):
361
+ """dont return dbapi.STRING for ENUM in PostgreSQL, since that's
362
+ a different type"""
363
+
364
+ return None
365
+
366
+
367
+ class DomainGenerator(NamedTypeGenerator):
368
+ def visit_DOMAIN(self, domain):
369
+ if not self._can_create_type(domain):
370
+ return
371
+ with self.with_ddl_events(domain):
372
+ self.connection.execute(CreateDomainType(domain))
373
+
374
+
375
+ class DomainDropper(NamedTypeDropper):
376
+ def visit_DOMAIN(self, domain):
377
+ if not self._can_drop_type(domain):
378
+ return
379
+
380
+ with self.with_ddl_events(domain):
381
+ self.connection.execute(DropDomainType(domain))
382
+
383
+
384
+ class DOMAIN(NamedType, sqltypes.SchemaType):
385
+ r"""Represent the DOMAIN PostgreSQL type.
386
+
387
+ A domain is essentially a data type with optional constraints
388
+ that restrict the allowed set of values. E.g.::
389
+
390
+ PositiveInt = DOMAIN(
391
+ "pos_int", Integer, check="VALUE > 0", not_null=True
392
+ )
393
+
394
+ UsPostalCode = DOMAIN(
395
+ "us_postal_code",
396
+ Text,
397
+ check="VALUE ~ '^\d{5}$' OR VALUE ~ '^\d{5}-\d{4}$'"
398
+ )
399
+
400
+ See the `PostgreSQL documentation`__ for additional details
401
+
402
+ __ https://www.postgresql.org/docs/current/sql-createdomain.html
403
+
404
+ .. versionadded:: 2.0
405
+
406
+ """
407
+
408
+ DDLGenerator = DomainGenerator
409
+ DDLDropper = DomainDropper
410
+
411
+ __visit_name__ = "DOMAIN"
412
+
413
+ def __init__(
414
+ self,
415
+ name: str,
416
+ data_type: _TypeEngineArgument[Any],
417
+ *,
418
+ collation: Optional[str] = None,
419
+ default: Union[elements.TextClause, str, None] = None,
420
+ constraint_name: Optional[str] = None,
421
+ not_null: Optional[bool] = None,
422
+ check: Union[elements.TextClause, str, None] = None,
423
+ create_type: bool = True,
424
+ **kw: Any,
425
+ ):
426
+ """
427
+ Construct a DOMAIN.
428
+
429
+ :param name: the name of the domain
430
+ :param data_type: The underlying data type of the domain.
431
+ This can include array specifiers.
432
+ :param collation: An optional collation for the domain.
433
+ If no collation is specified, the underlying data type's default
434
+ collation is used. The underlying type must be collatable if
435
+ ``collation`` is specified.
436
+ :param default: The DEFAULT clause specifies a default value for
437
+ columns of the domain data type. The default should be a string
438
+ or a :func:`_expression.text` value.
439
+ If no default value is specified, then the default value is
440
+ the null value.
441
+ :param constraint_name: An optional name for a constraint.
442
+ If not specified, the backend generates a name.
443
+ :param not_null: Values of this domain are prevented from being null.
444
+ By default domain are allowed to be null. If not specified
445
+ no nullability clause will be emitted.
446
+ :param check: CHECK clause specify integrity constraint or test
447
+ which values of the domain must satisfy. A constraint must be
448
+ an expression producing a Boolean result that can use the key
449
+ word VALUE to refer to the value being tested.
450
+ Differently from PostgreSQL, only a single check clause is
451
+ currently allowed in SQLAlchemy.
452
+ :param schema: optional schema name
453
+ :param metadata: optional :class:`_schema.MetaData` object which
454
+ this :class:`_postgresql.DOMAIN` will be directly associated
455
+ :param create_type: Defaults to True.
456
+ Indicates that ``CREATE TYPE`` should be emitted, after optionally
457
+ checking for the presence of the type, when the parent table is
458
+ being created; and additionally that ``DROP TYPE`` is called
459
+ when the table is dropped.
460
+
461
+ """
462
+ self.data_type = type_api.to_instance(data_type)
463
+ self.default = default
464
+ self.collation = collation
465
+ self.constraint_name = constraint_name
466
+ self.not_null = bool(not_null)
467
+ if check is not None:
468
+ check = coercions.expect(roles.DDLExpressionRole, check)
469
+ self.check = check
470
+ self.create_type = create_type
471
+ super().__init__(name=name, **kw)
472
+
473
+ @classmethod
474
+ def __test_init__(cls):
475
+ return cls("name", sqltypes.Integer)
476
+
477
+ def adapt(self, impl, **kw):
478
+ if self.default:
479
+ kw["default"] = self.default
480
+ if self.constraint_name is not None:
481
+ kw["constraint_name"] = self.constraint_name
482
+ if self.not_null:
483
+ kw["not_null"] = self.not_null
484
+ if self.check is not None:
485
+ kw["check"] = str(self.check)
486
+ if self.create_type:
487
+ kw["create_type"] = self.create_type
488
+
489
+ return super().adapt(impl, **kw)
490
+
491
+
492
+ class CreateEnumType(schema._CreateDropBase):
493
+ __visit_name__ = "create_enum_type"
494
+
495
+
496
+ class DropEnumType(schema._CreateDropBase):
497
+ __visit_name__ = "drop_enum_type"
498
+
499
+
500
+ class CreateDomainType(schema._CreateDropBase):
501
+ """Represent a CREATE DOMAIN statement."""
502
+
503
+ __visit_name__ = "create_domain_type"
504
+
505
+
506
+ class DropDomainType(schema._CreateDropBase):
507
+ """Represent a DROP DOMAIN statement."""
508
+
509
+ __visit_name__ = "drop_domain_type"
@@ -0,0 +1,129 @@
1
+ # dialects/postgresql/operators.py
2
+ # Copyright (C) 2005-2024 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
+ )