sqlspec 0.11.0__py3-none-any.whl → 0.12.0__py3-none-any.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.

Potentially problematic release.


This version of sqlspec might be problematic. Click here for more details.

Files changed (155) hide show
  1. sqlspec/__init__.py +16 -3
  2. sqlspec/_serialization.py +3 -10
  3. sqlspec/_sql.py +1147 -0
  4. sqlspec/_typing.py +343 -41
  5. sqlspec/adapters/adbc/__init__.py +2 -6
  6. sqlspec/adapters/adbc/config.py +474 -149
  7. sqlspec/adapters/adbc/driver.py +330 -644
  8. sqlspec/adapters/aiosqlite/__init__.py +2 -6
  9. sqlspec/adapters/aiosqlite/config.py +143 -57
  10. sqlspec/adapters/aiosqlite/driver.py +269 -462
  11. sqlspec/adapters/asyncmy/__init__.py +3 -8
  12. sqlspec/adapters/asyncmy/config.py +247 -202
  13. sqlspec/adapters/asyncmy/driver.py +217 -451
  14. sqlspec/adapters/asyncpg/__init__.py +4 -7
  15. sqlspec/adapters/asyncpg/config.py +329 -176
  16. sqlspec/adapters/asyncpg/driver.py +418 -498
  17. sqlspec/adapters/bigquery/__init__.py +2 -2
  18. sqlspec/adapters/bigquery/config.py +407 -0
  19. sqlspec/adapters/bigquery/driver.py +592 -634
  20. sqlspec/adapters/duckdb/__init__.py +4 -1
  21. sqlspec/adapters/duckdb/config.py +432 -321
  22. sqlspec/adapters/duckdb/driver.py +393 -436
  23. sqlspec/adapters/oracledb/__init__.py +3 -8
  24. sqlspec/adapters/oracledb/config.py +625 -0
  25. sqlspec/adapters/oracledb/driver.py +549 -942
  26. sqlspec/adapters/psqlpy/__init__.py +4 -7
  27. sqlspec/adapters/psqlpy/config.py +372 -203
  28. sqlspec/adapters/psqlpy/driver.py +197 -550
  29. sqlspec/adapters/psycopg/__init__.py +3 -8
  30. sqlspec/adapters/psycopg/config.py +741 -0
  31. sqlspec/adapters/psycopg/driver.py +732 -733
  32. sqlspec/adapters/sqlite/__init__.py +2 -6
  33. sqlspec/adapters/sqlite/config.py +146 -81
  34. sqlspec/adapters/sqlite/driver.py +243 -426
  35. sqlspec/base.py +220 -825
  36. sqlspec/config.py +354 -0
  37. sqlspec/driver/__init__.py +22 -0
  38. sqlspec/driver/_async.py +252 -0
  39. sqlspec/driver/_common.py +338 -0
  40. sqlspec/driver/_sync.py +261 -0
  41. sqlspec/driver/mixins/__init__.py +17 -0
  42. sqlspec/driver/mixins/_pipeline.py +523 -0
  43. sqlspec/driver/mixins/_result_utils.py +122 -0
  44. sqlspec/driver/mixins/_sql_translator.py +35 -0
  45. sqlspec/driver/mixins/_storage.py +993 -0
  46. sqlspec/driver/mixins/_type_coercion.py +131 -0
  47. sqlspec/exceptions.py +299 -7
  48. sqlspec/extensions/aiosql/__init__.py +10 -0
  49. sqlspec/extensions/aiosql/adapter.py +474 -0
  50. sqlspec/extensions/litestar/__init__.py +1 -6
  51. sqlspec/extensions/litestar/_utils.py +1 -5
  52. sqlspec/extensions/litestar/config.py +5 -6
  53. sqlspec/extensions/litestar/handlers.py +13 -12
  54. sqlspec/extensions/litestar/plugin.py +22 -24
  55. sqlspec/extensions/litestar/providers.py +37 -55
  56. sqlspec/loader.py +528 -0
  57. sqlspec/service/__init__.py +3 -0
  58. sqlspec/service/base.py +24 -0
  59. sqlspec/service/pagination.py +26 -0
  60. sqlspec/statement/__init__.py +21 -0
  61. sqlspec/statement/builder/__init__.py +54 -0
  62. sqlspec/statement/builder/_ddl_utils.py +119 -0
  63. sqlspec/statement/builder/_parsing_utils.py +135 -0
  64. sqlspec/statement/builder/base.py +328 -0
  65. sqlspec/statement/builder/ddl.py +1379 -0
  66. sqlspec/statement/builder/delete.py +80 -0
  67. sqlspec/statement/builder/insert.py +274 -0
  68. sqlspec/statement/builder/merge.py +95 -0
  69. sqlspec/statement/builder/mixins/__init__.py +65 -0
  70. sqlspec/statement/builder/mixins/_aggregate_functions.py +151 -0
  71. sqlspec/statement/builder/mixins/_case_builder.py +91 -0
  72. sqlspec/statement/builder/mixins/_common_table_expr.py +91 -0
  73. sqlspec/statement/builder/mixins/_delete_from.py +34 -0
  74. sqlspec/statement/builder/mixins/_from.py +61 -0
  75. sqlspec/statement/builder/mixins/_group_by.py +119 -0
  76. sqlspec/statement/builder/mixins/_having.py +35 -0
  77. sqlspec/statement/builder/mixins/_insert_from_select.py +48 -0
  78. sqlspec/statement/builder/mixins/_insert_into.py +36 -0
  79. sqlspec/statement/builder/mixins/_insert_values.py +69 -0
  80. sqlspec/statement/builder/mixins/_join.py +110 -0
  81. sqlspec/statement/builder/mixins/_limit_offset.py +53 -0
  82. sqlspec/statement/builder/mixins/_merge_clauses.py +405 -0
  83. sqlspec/statement/builder/mixins/_order_by.py +46 -0
  84. sqlspec/statement/builder/mixins/_pivot.py +82 -0
  85. sqlspec/statement/builder/mixins/_returning.py +37 -0
  86. sqlspec/statement/builder/mixins/_select_columns.py +60 -0
  87. sqlspec/statement/builder/mixins/_set_ops.py +122 -0
  88. sqlspec/statement/builder/mixins/_unpivot.py +80 -0
  89. sqlspec/statement/builder/mixins/_update_from.py +54 -0
  90. sqlspec/statement/builder/mixins/_update_set.py +91 -0
  91. sqlspec/statement/builder/mixins/_update_table.py +29 -0
  92. sqlspec/statement/builder/mixins/_where.py +374 -0
  93. sqlspec/statement/builder/mixins/_window_functions.py +86 -0
  94. sqlspec/statement/builder/protocols.py +20 -0
  95. sqlspec/statement/builder/select.py +206 -0
  96. sqlspec/statement/builder/update.py +178 -0
  97. sqlspec/statement/filters.py +571 -0
  98. sqlspec/statement/parameters.py +736 -0
  99. sqlspec/statement/pipelines/__init__.py +67 -0
  100. sqlspec/statement/pipelines/analyzers/__init__.py +9 -0
  101. sqlspec/statement/pipelines/analyzers/_analyzer.py +649 -0
  102. sqlspec/statement/pipelines/base.py +315 -0
  103. sqlspec/statement/pipelines/context.py +119 -0
  104. sqlspec/statement/pipelines/result_types.py +41 -0
  105. sqlspec/statement/pipelines/transformers/__init__.py +8 -0
  106. sqlspec/statement/pipelines/transformers/_expression_simplifier.py +256 -0
  107. sqlspec/statement/pipelines/transformers/_literal_parameterizer.py +623 -0
  108. sqlspec/statement/pipelines/transformers/_remove_comments.py +66 -0
  109. sqlspec/statement/pipelines/transformers/_remove_hints.py +81 -0
  110. sqlspec/statement/pipelines/validators/__init__.py +23 -0
  111. sqlspec/statement/pipelines/validators/_dml_safety.py +275 -0
  112. sqlspec/statement/pipelines/validators/_parameter_style.py +297 -0
  113. sqlspec/statement/pipelines/validators/_performance.py +703 -0
  114. sqlspec/statement/pipelines/validators/_security.py +990 -0
  115. sqlspec/statement/pipelines/validators/base.py +67 -0
  116. sqlspec/statement/result.py +527 -0
  117. sqlspec/statement/splitter.py +701 -0
  118. sqlspec/statement/sql.py +1198 -0
  119. sqlspec/storage/__init__.py +15 -0
  120. sqlspec/storage/backends/__init__.py +0 -0
  121. sqlspec/storage/backends/base.py +166 -0
  122. sqlspec/storage/backends/fsspec.py +315 -0
  123. sqlspec/storage/backends/obstore.py +464 -0
  124. sqlspec/storage/protocol.py +170 -0
  125. sqlspec/storage/registry.py +315 -0
  126. sqlspec/typing.py +157 -36
  127. sqlspec/utils/correlation.py +155 -0
  128. sqlspec/utils/deprecation.py +3 -6
  129. sqlspec/utils/fixtures.py +6 -11
  130. sqlspec/utils/logging.py +135 -0
  131. sqlspec/utils/module_loader.py +45 -43
  132. sqlspec/utils/serializers.py +4 -0
  133. sqlspec/utils/singleton.py +6 -8
  134. sqlspec/utils/sync_tools.py +15 -27
  135. sqlspec/utils/text.py +58 -26
  136. {sqlspec-0.11.0.dist-info → sqlspec-0.12.0.dist-info}/METADATA +100 -26
  137. sqlspec-0.12.0.dist-info/RECORD +145 -0
  138. sqlspec/adapters/bigquery/config/__init__.py +0 -3
  139. sqlspec/adapters/bigquery/config/_common.py +0 -40
  140. sqlspec/adapters/bigquery/config/_sync.py +0 -87
  141. sqlspec/adapters/oracledb/config/__init__.py +0 -9
  142. sqlspec/adapters/oracledb/config/_asyncio.py +0 -186
  143. sqlspec/adapters/oracledb/config/_common.py +0 -131
  144. sqlspec/adapters/oracledb/config/_sync.py +0 -186
  145. sqlspec/adapters/psycopg/config/__init__.py +0 -19
  146. sqlspec/adapters/psycopg/config/_async.py +0 -169
  147. sqlspec/adapters/psycopg/config/_common.py +0 -56
  148. sqlspec/adapters/psycopg/config/_sync.py +0 -168
  149. sqlspec/filters.py +0 -330
  150. sqlspec/mixins.py +0 -306
  151. sqlspec/statement.py +0 -378
  152. sqlspec-0.11.0.dist-info/RECORD +0 -69
  153. {sqlspec-0.11.0.dist-info → sqlspec-0.12.0.dist-info}/WHEEL +0 -0
  154. {sqlspec-0.11.0.dist-info → sqlspec-0.12.0.dist-info}/licenses/LICENSE +0 -0
  155. {sqlspec-0.11.0.dist-info → sqlspec-0.12.0.dist-info}/licenses/NOTICE +0 -0
@@ -1,9 +1,4 @@
1
- from sqlspec.adapters.oracledb.config import (
2
- OracleAsyncConfig,
3
- OracleAsyncPoolConfig,
4
- OracleSyncConfig,
5
- OracleSyncPoolConfig,
6
- )
1
+ from sqlspec.adapters.oracledb.config import CONNECTION_FIELDS, POOL_FIELDS, OracleAsyncConfig, OracleSyncConfig
7
2
  from sqlspec.adapters.oracledb.driver import (
8
3
  OracleAsyncConnection,
9
4
  OracleAsyncDriver,
@@ -12,12 +7,12 @@ from sqlspec.adapters.oracledb.driver import (
12
7
  )
13
8
 
14
9
  __all__ = (
10
+ "CONNECTION_FIELDS",
11
+ "POOL_FIELDS",
15
12
  "OracleAsyncConfig",
16
13
  "OracleAsyncConnection",
17
14
  "OracleAsyncDriver",
18
- "OracleAsyncPoolConfig",
19
15
  "OracleSyncConfig",
20
16
  "OracleSyncConnection",
21
17
  "OracleSyncDriver",
22
- "OracleSyncPoolConfig",
23
18
  )
@@ -0,0 +1,625 @@
1
+ """OracleDB database configuration with direct field-based configuration."""
2
+
3
+ import contextlib
4
+ import logging
5
+ from collections.abc import AsyncGenerator
6
+ from contextlib import asynccontextmanager
7
+ from dataclasses import replace
8
+ from typing import TYPE_CHECKING, Any, ClassVar, Optional, cast
9
+
10
+ import oracledb
11
+
12
+ from sqlspec.adapters.oracledb.driver import (
13
+ OracleAsyncConnection,
14
+ OracleAsyncDriver,
15
+ OracleSyncConnection,
16
+ OracleSyncDriver,
17
+ )
18
+ from sqlspec.config import AsyncDatabaseConfig, SyncDatabaseConfig
19
+ from sqlspec.statement.sql import SQLConfig
20
+ from sqlspec.typing import DictRow, Empty
21
+
22
+ if TYPE_CHECKING:
23
+ from collections.abc import Callable, Generator
24
+
25
+ from oracledb import AuthMode
26
+ from oracledb.pool import AsyncConnectionPool, ConnectionPool
27
+ from sqlglot.dialects.dialect import DialectType
28
+
29
+
30
+ __all__ = ("CONNECTION_FIELDS", "POOL_FIELDS", "OracleAsyncConfig", "OracleSyncConfig")
31
+
32
+ logger = logging.getLogger(__name__)
33
+
34
+ CONNECTION_FIELDS = frozenset(
35
+ {
36
+ "dsn",
37
+ "user",
38
+ "password",
39
+ "host",
40
+ "port",
41
+ "service_name",
42
+ "sid",
43
+ "wallet_location",
44
+ "wallet_password",
45
+ "config_dir",
46
+ "tcp_connect_timeout",
47
+ "retry_count",
48
+ "retry_delay",
49
+ "mode",
50
+ "events",
51
+ "edition",
52
+ }
53
+ )
54
+
55
+ POOL_FIELDS = CONNECTION_FIELDS.union(
56
+ {
57
+ "min",
58
+ "max",
59
+ "increment",
60
+ "threaded",
61
+ "getmode",
62
+ "homogeneous",
63
+ "timeout",
64
+ "wait_timeout",
65
+ "max_lifetime_session",
66
+ "session_callback",
67
+ "max_sessions_per_shard",
68
+ "soda_metadata_cache",
69
+ "ping_interval",
70
+ }
71
+ )
72
+
73
+
74
+ class OracleSyncConfig(SyncDatabaseConfig[OracleSyncConnection, "ConnectionPool", OracleSyncDriver]):
75
+ """Configuration for Oracle synchronous database connections with direct field-based configuration."""
76
+
77
+ __slots__ = (
78
+ "_dialect",
79
+ "config_dir",
80
+ "default_row_type",
81
+ "dsn",
82
+ "edition",
83
+ "events",
84
+ "extras",
85
+ "getmode",
86
+ "homogeneous",
87
+ "host",
88
+ "increment",
89
+ "max",
90
+ "max_lifetime_session",
91
+ "max_sessions_per_shard",
92
+ "min",
93
+ "mode",
94
+ "password",
95
+ "ping_interval",
96
+ "pool_instance",
97
+ "port",
98
+ "retry_count",
99
+ "retry_delay",
100
+ "service_name",
101
+ "session_callback",
102
+ "sid",
103
+ "soda_metadata_cache",
104
+ "statement_config",
105
+ "tcp_connect_timeout",
106
+ "threaded",
107
+ "timeout",
108
+ "user",
109
+ "wait_timeout",
110
+ "wallet_location",
111
+ "wallet_password",
112
+ )
113
+
114
+ is_async: ClassVar[bool] = False
115
+ supports_connection_pooling: ClassVar[bool] = True
116
+
117
+ driver_type: type[OracleSyncDriver] = OracleSyncDriver
118
+ connection_type: type[OracleSyncConnection] = OracleSyncConnection
119
+
120
+ # Parameter style support information
121
+ supported_parameter_styles: ClassVar[tuple[str, ...]] = ("named_colon", "positional_colon")
122
+ """OracleDB supports :name (named_colon) and :1 (positional_colon) parameter styles."""
123
+
124
+ preferred_parameter_style: ClassVar[str] = "named_colon"
125
+ """OracleDB's preferred parameter style is :name (named_colon)."""
126
+
127
+ def __init__(
128
+ self,
129
+ statement_config: "Optional[SQLConfig]" = None,
130
+ default_row_type: "type[DictRow]" = DictRow,
131
+ # Connection parameters
132
+ dsn: Optional[str] = None,
133
+ user: Optional[str] = None,
134
+ password: Optional[str] = None,
135
+ host: Optional[str] = None,
136
+ port: Optional[int] = None,
137
+ service_name: Optional[str] = None,
138
+ sid: Optional[str] = None,
139
+ wallet_location: Optional[str] = None,
140
+ wallet_password: Optional[str] = None,
141
+ config_dir: Optional[str] = None,
142
+ tcp_connect_timeout: Optional[float] = None,
143
+ retry_count: Optional[int] = None,
144
+ retry_delay: Optional[int] = None,
145
+ mode: Optional["AuthMode"] = None,
146
+ events: Optional[bool] = None,
147
+ edition: Optional[str] = None,
148
+ # Pool parameters
149
+ min: Optional[int] = None,
150
+ max: Optional[int] = None,
151
+ increment: Optional[int] = None,
152
+ threaded: Optional[bool] = None,
153
+ getmode: Optional[int] = None,
154
+ homogeneous: Optional[bool] = None,
155
+ timeout: Optional[int] = None,
156
+ wait_timeout: Optional[int] = None,
157
+ max_lifetime_session: Optional[int] = None,
158
+ session_callback: Optional["Callable[[Any, Any], None]"] = None,
159
+ max_sessions_per_shard: Optional[int] = None,
160
+ soda_metadata_cache: Optional[bool] = None,
161
+ ping_interval: Optional[int] = None,
162
+ pool_instance: Optional["ConnectionPool"] = None,
163
+ **kwargs: Any,
164
+ ) -> None:
165
+ """Initialize Oracle synchronous configuration.
166
+
167
+ Args:
168
+ statement_config: Default SQL statement configuration
169
+ default_row_type: Default row type for results
170
+ dsn: Connection string for the database
171
+ user: Username for database authentication
172
+ password: Password for database authentication
173
+ host: Database server hostname
174
+ port: Database server port number
175
+ service_name: Oracle service name
176
+ sid: Oracle System ID (SID)
177
+ wallet_location: Location of Oracle Wallet
178
+ wallet_password: Password for accessing Oracle Wallet
179
+ config_dir: Directory containing Oracle configuration files
180
+ tcp_connect_timeout: Timeout for establishing TCP connections
181
+ retry_count: Number of attempts to connect
182
+ retry_delay: Time in seconds between connection attempts
183
+ mode: Session mode (SYSDBA, SYSOPER, etc.)
184
+ events: If True, enables Oracle events for FAN and RLB
185
+ edition: Edition name for edition-based redefinition
186
+ min: Minimum number of connections in the pool
187
+ max: Maximum number of connections in the pool
188
+ increment: Number of connections to create when pool needs to grow
189
+ threaded: Whether the pool should be threaded
190
+ getmode: How connections are returned from the pool
191
+ homogeneous: Whether all connections use the same credentials
192
+ timeout: Time in seconds after which idle connections are closed
193
+ wait_timeout: Time in seconds to wait for an available connection
194
+ max_lifetime_session: Maximum time in seconds that a connection can remain in the pool
195
+ session_callback: Callback function called when a connection is returned to the pool
196
+ max_sessions_per_shard: Maximum number of sessions per shard
197
+ soda_metadata_cache: Whether to enable SODA metadata caching
198
+ ping_interval: Interval for pinging pooled connections
199
+ pool_instance: Optional existing connection pool instance
200
+ **kwargs: Additional parameters (stored in extras)
201
+ """
202
+ # Store connection parameters as instance attributes
203
+ self.dsn = dsn
204
+ self.user = user
205
+ self.password = password
206
+ self.host = host
207
+ self.port = port
208
+ self.service_name = service_name
209
+ self.sid = sid
210
+ self.wallet_location = wallet_location
211
+ self.wallet_password = wallet_password
212
+ self.config_dir = config_dir
213
+ self.tcp_connect_timeout = tcp_connect_timeout
214
+ self.retry_count = retry_count
215
+ self.retry_delay = retry_delay
216
+ self.mode = mode
217
+ self.events = events
218
+ self.edition = edition
219
+
220
+ # Store pool parameters as instance attributes
221
+ self.min = min
222
+ self.max = max
223
+ self.increment = increment
224
+ self.threaded = threaded
225
+ self.getmode = getmode
226
+ self.homogeneous = homogeneous
227
+ self.timeout = timeout
228
+ self.wait_timeout = wait_timeout
229
+ self.max_lifetime_session = max_lifetime_session
230
+ self.session_callback = session_callback
231
+ self.max_sessions_per_shard = max_sessions_per_shard
232
+ self.soda_metadata_cache = soda_metadata_cache
233
+ self.ping_interval = ping_interval
234
+
235
+ self.extras = kwargs or {}
236
+
237
+ # Store other config
238
+ self.statement_config = statement_config or SQLConfig()
239
+ self.default_row_type = default_row_type
240
+ self.pool_instance = pool_instance
241
+ self._dialect: DialectType = None
242
+
243
+ super().__init__()
244
+
245
+ def _create_pool(self) -> "ConnectionPool":
246
+ """Create the actual connection pool."""
247
+
248
+ return oracledb.create_pool(**self.connection_config_dict)
249
+
250
+ def _close_pool(self) -> None:
251
+ """Close the actual connection pool."""
252
+ if self.pool_instance:
253
+ self.pool_instance.close()
254
+
255
+ def create_connection(self) -> OracleSyncConnection:
256
+ """Create a single connection (not from pool).
257
+
258
+ Returns:
259
+ An Oracle Connection instance.
260
+ """
261
+ if self.pool_instance is None:
262
+ self.pool_instance = self.create_pool()
263
+ return self.pool_instance.acquire()
264
+
265
+ @contextlib.contextmanager
266
+ def provide_connection(self, *args: Any, **kwargs: Any) -> "Generator[OracleSyncConnection, None, None]":
267
+ """Provide a connection context manager.
268
+
269
+ Args:
270
+ *args: Additional arguments.
271
+ **kwargs: Additional keyword arguments.
272
+
273
+ Yields:
274
+ An Oracle Connection instance.
275
+ """
276
+ if self.pool_instance is None:
277
+ self.pool_instance = self.create_pool()
278
+ conn = self.pool_instance.acquire()
279
+ try:
280
+ yield conn
281
+ finally:
282
+ self.pool_instance.release(conn)
283
+
284
+ @contextlib.contextmanager
285
+ def provide_session(self, *args: Any, **kwargs: Any) -> "Generator[OracleSyncDriver, None, None]":
286
+ """Provide a driver session context manager.
287
+
288
+ Args:
289
+ *args: Additional arguments.
290
+ **kwargs: Additional keyword arguments.
291
+
292
+ Yields:
293
+ An OracleSyncDriver instance.
294
+ """
295
+ with self.provide_connection(*args, **kwargs) as conn:
296
+ # Create statement config with parameter style info if not already set
297
+ statement_config = self.statement_config
298
+ if statement_config.allowed_parameter_styles is None:
299
+ statement_config = replace(
300
+ statement_config,
301
+ allowed_parameter_styles=self.supported_parameter_styles,
302
+ target_parameter_style=self.preferred_parameter_style,
303
+ )
304
+
305
+ driver = self.driver_type(connection=conn, config=statement_config)
306
+ yield driver
307
+
308
+ def provide_pool(self, *args: Any, **kwargs: Any) -> "ConnectionPool":
309
+ """Provide pool instance.
310
+
311
+ Returns:
312
+ The connection pool.
313
+ """
314
+ if not self.pool_instance:
315
+ self.pool_instance = self.create_pool()
316
+ return self.pool_instance
317
+
318
+ @property
319
+ def connection_config_dict(self) -> dict[str, Any]:
320
+ """Return the connection configuration as a dict for Oracle operations.
321
+
322
+ Returns all configuration parameters merged together.
323
+ """
324
+ # Gather non-None parameters from all fields (connection + pool)
325
+ config = {
326
+ field: getattr(self, field)
327
+ for field in CONNECTION_FIELDS
328
+ if getattr(self, field, None) is not None and getattr(self, field) is not Empty
329
+ }
330
+
331
+ # Merge extras parameters
332
+ config.update(self.extras)
333
+
334
+ return config
335
+
336
+ @property
337
+ def pool_config_dict(self) -> dict[str, Any]:
338
+ """Return the pool configuration as a dict for Oracle operations.
339
+
340
+ Returns all configuration parameters merged together.
341
+ """
342
+ # Gather non-None parameters from all fields (connection + pool)
343
+ config = {
344
+ field: getattr(self, field)
345
+ for field in POOL_FIELDS
346
+ if getattr(self, field, None) is not None and getattr(self, field) is not Empty
347
+ }
348
+
349
+ # Merge extras parameters
350
+ config.update(self.extras)
351
+
352
+ return config
353
+
354
+
355
+ class OracleAsyncConfig(AsyncDatabaseConfig[OracleAsyncConnection, "AsyncConnectionPool", OracleAsyncDriver]):
356
+ """Configuration for Oracle asynchronous database connections with direct field-based configuration."""
357
+
358
+ __slots__ = (
359
+ "_dialect",
360
+ "config_dir",
361
+ "default_row_type",
362
+ "dsn",
363
+ "edition",
364
+ "events",
365
+ "extras",
366
+ "getmode",
367
+ "homogeneous",
368
+ "host",
369
+ "increment",
370
+ "max",
371
+ "max_lifetime_session",
372
+ "max_sessions_per_shard",
373
+ "min",
374
+ "mode",
375
+ "password",
376
+ "ping_interval",
377
+ "pool_instance",
378
+ "port",
379
+ "retry_count",
380
+ "retry_delay",
381
+ "service_name",
382
+ "session_callback",
383
+ "sid",
384
+ "soda_metadata_cache",
385
+ "statement_config",
386
+ "tcp_connect_timeout",
387
+ "threaded",
388
+ "timeout",
389
+ "user",
390
+ "wait_timeout",
391
+ "wallet_location",
392
+ "wallet_password",
393
+ )
394
+
395
+ is_async: ClassVar[bool] = True
396
+ supports_connection_pooling: ClassVar[bool] = True
397
+
398
+ connection_type: type[OracleAsyncConnection] = OracleAsyncConnection
399
+ driver_type: type[OracleAsyncDriver] = OracleAsyncDriver
400
+
401
+ # Parameter style support information
402
+ supported_parameter_styles: ClassVar[tuple[str, ...]] = ("named_colon", "positional_colon")
403
+ """OracleDB supports :name (named_colon) and :1 (positional_colon) parameter styles."""
404
+
405
+ preferred_parameter_style: ClassVar[str] = "named_colon"
406
+ """OracleDB's preferred parameter style is :name (named_colon)."""
407
+
408
+ def __init__(
409
+ self,
410
+ statement_config: "Optional[SQLConfig]" = None,
411
+ default_row_type: "type[DictRow]" = DictRow,
412
+ # Connection parameters
413
+ dsn: Optional[str] = None,
414
+ user: Optional[str] = None,
415
+ password: Optional[str] = None,
416
+ host: Optional[str] = None,
417
+ port: Optional[int] = None,
418
+ service_name: Optional[str] = None,
419
+ sid: Optional[str] = None,
420
+ wallet_location: Optional[str] = None,
421
+ wallet_password: Optional[str] = None,
422
+ config_dir: Optional[str] = None,
423
+ tcp_connect_timeout: Optional[float] = None,
424
+ retry_count: Optional[int] = None,
425
+ retry_delay: Optional[int] = None,
426
+ mode: Optional["AuthMode"] = None,
427
+ events: Optional[bool] = None,
428
+ edition: Optional[str] = None,
429
+ # Pool parameters
430
+ min: Optional[int] = None,
431
+ max: Optional[int] = None,
432
+ increment: Optional[int] = None,
433
+ threaded: Optional[bool] = None,
434
+ getmode: Optional[int] = None,
435
+ homogeneous: Optional[bool] = None,
436
+ timeout: Optional[int] = None,
437
+ wait_timeout: Optional[int] = None,
438
+ max_lifetime_session: Optional[int] = None,
439
+ session_callback: Optional["Callable[[Any, Any], None]"] = None,
440
+ max_sessions_per_shard: Optional[int] = None,
441
+ soda_metadata_cache: Optional[bool] = None,
442
+ ping_interval: Optional[int] = None,
443
+ pool_instance: Optional["AsyncConnectionPool"] = None,
444
+ **kwargs: Any,
445
+ ) -> None:
446
+ """Initialize Oracle asynchronous configuration.
447
+
448
+ Args:
449
+ statement_config: Default SQL statement configuration
450
+ default_row_type: Default row type for results
451
+ dsn: Connection string for the database
452
+ user: Username for database authentication
453
+ password: Password for database authentication
454
+ host: Database server hostname
455
+ port: Database server port number
456
+ service_name: Oracle service name
457
+ sid: Oracle System ID (SID)
458
+ wallet_location: Location of Oracle Wallet
459
+ wallet_password: Password for accessing Oracle Wallet
460
+ config_dir: Directory containing Oracle configuration files
461
+ tcp_connect_timeout: Timeout for establishing TCP connections
462
+ retry_count: Number of attempts to connect
463
+ retry_delay: Time in seconds between connection attempts
464
+ mode: Session mode (SYSDBA, SYSOPER, etc.)
465
+ events: If True, enables Oracle events for FAN and RLB
466
+ edition: Edition name for edition-based redefinition
467
+ min: Minimum number of connections in the pool
468
+ max: Maximum number of connections in the pool
469
+ increment: Number of connections to create when pool needs to grow
470
+ threaded: Whether the pool should be threaded
471
+ getmode: How connections are returned from the pool
472
+ homogeneous: Whether all connections use the same credentials
473
+ timeout: Time in seconds after which idle connections are closed
474
+ wait_timeout: Time in seconds to wait for an available connection
475
+ max_lifetime_session: Maximum time in seconds that a connection can remain in the pool
476
+ session_callback: Callback function called when a connection is returned to the pool
477
+ max_sessions_per_shard: Maximum number of sessions per shard
478
+ soda_metadata_cache: Whether to enable SODA metadata caching
479
+ ping_interval: Interval for pinging pooled connections
480
+ pool_instance: Optional existing async connection pool instance
481
+ **kwargs: Additional parameters (stored in extras)
482
+ """
483
+ # Store connection parameters as instance attributes
484
+ self.dsn = dsn
485
+ self.user = user
486
+ self.password = password
487
+ self.host = host
488
+ self.port = port
489
+ self.service_name = service_name
490
+ self.sid = sid
491
+ self.wallet_location = wallet_location
492
+ self.wallet_password = wallet_password
493
+ self.config_dir = config_dir
494
+ self.tcp_connect_timeout = tcp_connect_timeout
495
+ self.retry_count = retry_count
496
+ self.retry_delay = retry_delay
497
+ self.mode = mode
498
+ self.events = events
499
+ self.edition = edition
500
+
501
+ # Store pool parameters as instance attributes
502
+ self.min = min
503
+ self.max = max
504
+ self.increment = increment
505
+ self.threaded = threaded
506
+ self.getmode = getmode
507
+ self.homogeneous = homogeneous
508
+ self.timeout = timeout
509
+ self.wait_timeout = wait_timeout
510
+ self.max_lifetime_session = max_lifetime_session
511
+ self.session_callback = session_callback
512
+ self.max_sessions_per_shard = max_sessions_per_shard
513
+ self.soda_metadata_cache = soda_metadata_cache
514
+ self.ping_interval = ping_interval
515
+
516
+ self.extras = kwargs or {}
517
+
518
+ # Store other config
519
+ self.statement_config = statement_config or SQLConfig()
520
+ self.default_row_type = default_row_type
521
+ self.pool_instance: Optional[AsyncConnectionPool] = pool_instance
522
+ self._dialect: DialectType = None
523
+
524
+ super().__init__()
525
+
526
+ @property
527
+ def connection_config_dict(self) -> dict[str, Any]:
528
+ """Return the connection configuration as a dict for Oracle async operations.
529
+
530
+ Returns all configuration parameters merged together.
531
+ """
532
+ # Gather non-None parameters
533
+ config = {field: getattr(self, field) for field in CONNECTION_FIELDS if getattr(self, field, None) is not None}
534
+
535
+ # Merge extras parameters
536
+ config.update(self.extras)
537
+
538
+ return config
539
+
540
+ @property
541
+ def pool_config_dict(self) -> dict[str, Any]:
542
+ """Return the connection configuration as a dict for Oracle async operations.
543
+
544
+ Returns all configuration parameters merged together.
545
+ """
546
+ # Gather non-None parameters
547
+ config = {field: getattr(self, field) for field in POOL_FIELDS if getattr(self, field, None) is not None}
548
+
549
+ # Merge extras parameters
550
+ config.update(self.extras)
551
+
552
+ return config
553
+
554
+ async def _create_pool(self) -> "AsyncConnectionPool":
555
+ """Create the actual async connection pool."""
556
+
557
+ return oracledb.create_pool_async(**self.pool_config_dict)
558
+
559
+ async def _close_pool(self) -> None:
560
+ """Close the actual async connection pool."""
561
+ if self.pool_instance:
562
+ await self.pool_instance.close()
563
+
564
+ async def create_connection(self) -> OracleAsyncConnection:
565
+ """Create a single async connection (not from pool).
566
+
567
+ Returns:
568
+ An Oracle AsyncConnection instance.
569
+ """
570
+ if self.pool_instance is None:
571
+ self.pool_instance = await self.create_pool()
572
+ return cast("OracleAsyncConnection", await self.pool_instance.acquire())
573
+
574
+ @asynccontextmanager
575
+ async def provide_connection(self, *args: Any, **kwargs: Any) -> AsyncGenerator[OracleAsyncConnection, None]:
576
+ """Provide an async connection context manager.
577
+
578
+ Args:
579
+ *args: Additional arguments.
580
+ **kwargs: Additional keyword arguments.
581
+
582
+ Yields:
583
+ An Oracle AsyncConnection instance.
584
+ """
585
+ if self.pool_instance is None:
586
+ self.pool_instance = await self.create_pool()
587
+ conn = await self.pool_instance.acquire()
588
+ try:
589
+ yield conn
590
+ finally:
591
+ await self.pool_instance.release(conn)
592
+
593
+ @asynccontextmanager
594
+ async def provide_session(self, *args: Any, **kwargs: Any) -> AsyncGenerator[OracleAsyncDriver, None]:
595
+ """Provide an async driver session context manager.
596
+
597
+ Args:
598
+ *args: Additional arguments.
599
+ **kwargs: Additional keyword arguments.
600
+
601
+ Yields:
602
+ An OracleAsyncDriver instance.
603
+ """
604
+ async with self.provide_connection(*args, **kwargs) as conn:
605
+ # Create statement config with parameter style info if not already set
606
+ statement_config = self.statement_config
607
+ if statement_config.allowed_parameter_styles is None:
608
+ statement_config = replace(
609
+ statement_config,
610
+ allowed_parameter_styles=self.supported_parameter_styles,
611
+ target_parameter_style=self.preferred_parameter_style,
612
+ )
613
+
614
+ driver = self.driver_type(connection=conn, config=statement_config)
615
+ yield driver
616
+
617
+ async def provide_pool(self, *args: Any, **kwargs: Any) -> "AsyncConnectionPool":
618
+ """Provide async pool instance.
619
+
620
+ Returns:
621
+ The async connection pool.
622
+ """
623
+ if not self.pool_instance:
624
+ self.pool_instance = await self.create_pool()
625
+ return self.pool_instance