sqlspec 0.17.1__py3-none-any.whl → 0.19.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.
- sqlspec/__init__.py +1 -1
- sqlspec/_sql.py +54 -159
- sqlspec/adapters/adbc/config.py +24 -30
- sqlspec/adapters/adbc/driver.py +42 -61
- sqlspec/adapters/aiosqlite/config.py +5 -10
- sqlspec/adapters/aiosqlite/driver.py +9 -25
- sqlspec/adapters/aiosqlite/pool.py +43 -35
- sqlspec/adapters/asyncmy/config.py +10 -7
- sqlspec/adapters/asyncmy/driver.py +18 -39
- sqlspec/adapters/asyncpg/config.py +4 -0
- sqlspec/adapters/asyncpg/driver.py +32 -79
- sqlspec/adapters/bigquery/config.py +12 -65
- sqlspec/adapters/bigquery/driver.py +39 -133
- sqlspec/adapters/duckdb/config.py +11 -15
- sqlspec/adapters/duckdb/driver.py +61 -85
- sqlspec/adapters/duckdb/pool.py +2 -5
- sqlspec/adapters/oracledb/_types.py +8 -1
- sqlspec/adapters/oracledb/config.py +55 -38
- sqlspec/adapters/oracledb/driver.py +35 -92
- sqlspec/adapters/oracledb/migrations.py +257 -0
- sqlspec/adapters/psqlpy/config.py +13 -9
- sqlspec/adapters/psqlpy/driver.py +28 -103
- sqlspec/adapters/psycopg/config.py +9 -5
- sqlspec/adapters/psycopg/driver.py +107 -175
- sqlspec/adapters/sqlite/config.py +7 -5
- sqlspec/adapters/sqlite/driver.py +37 -73
- sqlspec/adapters/sqlite/pool.py +3 -12
- sqlspec/base.py +19 -22
- sqlspec/builder/__init__.py +1 -1
- sqlspec/builder/_base.py +34 -20
- sqlspec/builder/_ddl.py +407 -183
- sqlspec/builder/_insert.py +1 -1
- sqlspec/builder/mixins/_insert_operations.py +26 -6
- sqlspec/builder/mixins/_merge_operations.py +1 -1
- sqlspec/builder/mixins/_select_operations.py +1 -5
- sqlspec/cli.py +281 -33
- sqlspec/config.py +183 -14
- sqlspec/core/__init__.py +89 -14
- sqlspec/core/cache.py +57 -104
- sqlspec/core/compiler.py +57 -112
- sqlspec/core/filters.py +1 -21
- sqlspec/core/hashing.py +13 -47
- sqlspec/core/parameters.py +272 -261
- sqlspec/core/result.py +12 -27
- sqlspec/core/splitter.py +17 -21
- sqlspec/core/statement.py +150 -159
- sqlspec/driver/_async.py +2 -15
- sqlspec/driver/_common.py +16 -95
- sqlspec/driver/_sync.py +2 -15
- sqlspec/driver/mixins/_result_tools.py +8 -29
- sqlspec/driver/mixins/_sql_translator.py +6 -8
- sqlspec/exceptions.py +1 -2
- sqlspec/extensions/litestar/plugin.py +15 -8
- sqlspec/loader.py +43 -115
- sqlspec/migrations/__init__.py +1 -1
- sqlspec/migrations/base.py +34 -45
- sqlspec/migrations/commands.py +34 -15
- sqlspec/migrations/loaders.py +1 -1
- sqlspec/migrations/runner.py +104 -19
- sqlspec/migrations/tracker.py +49 -2
- sqlspec/protocols.py +3 -6
- sqlspec/storage/__init__.py +4 -4
- sqlspec/storage/backends/fsspec.py +5 -6
- sqlspec/storage/backends/obstore.py +7 -8
- sqlspec/storage/registry.py +3 -3
- sqlspec/utils/__init__.py +2 -2
- sqlspec/utils/logging.py +6 -10
- sqlspec/utils/sync_tools.py +27 -4
- sqlspec/utils/text.py +6 -1
- {sqlspec-0.17.1.dist-info → sqlspec-0.19.0.dist-info}/METADATA +1 -1
- sqlspec-0.19.0.dist-info/RECORD +138 -0
- sqlspec/builder/_ddl_utils.py +0 -103
- sqlspec-0.17.1.dist-info/RECORD +0 -138
- {sqlspec-0.17.1.dist-info → sqlspec-0.19.0.dist-info}/WHEEL +0 -0
- {sqlspec-0.17.1.dist-info → sqlspec-0.19.0.dist-info}/entry_points.txt +0 -0
- {sqlspec-0.17.1.dist-info → sqlspec-0.19.0.dist-info}/licenses/LICENSE +0 -0
- {sqlspec-0.17.1.dist-info → sqlspec-0.19.0.dist-info}/licenses/NOTICE +0 -0
|
@@ -1,17 +1,15 @@
|
|
|
1
|
-
"""
|
|
2
|
-
|
|
3
|
-
This driver
|
|
4
|
-
-
|
|
5
|
-
-
|
|
6
|
-
-
|
|
7
|
-
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
-
|
|
11
|
-
-
|
|
12
|
-
- DuckDB
|
|
13
|
-
- MyPyC-optimized performance patterns
|
|
14
|
-
- Zero-copy data access where possible
|
|
1
|
+
"""DuckDB driver implementation.
|
|
2
|
+
|
|
3
|
+
This driver provides:
|
|
4
|
+
- SQL compilation with single-pass processing
|
|
5
|
+
- Memory-efficient design with __slots__
|
|
6
|
+
- Statement caching for repeated execution
|
|
7
|
+
- Backward compatibility with existing functionality
|
|
8
|
+
|
|
9
|
+
Features:
|
|
10
|
+
- Integration with sqlspec.core modules
|
|
11
|
+
- Parameter processing with type coercion
|
|
12
|
+
- DuckDB resource management
|
|
15
13
|
- Multi-parameter style support
|
|
16
14
|
"""
|
|
17
15
|
|
|
@@ -38,37 +36,32 @@ __all__ = ("DuckDBCursor", "DuckDBDriver", "DuckDBExceptionHandler", "duckdb_sta
|
|
|
38
36
|
|
|
39
37
|
logger = get_logger("adapters.duckdb")
|
|
40
38
|
|
|
41
|
-
|
|
39
|
+
|
|
42
40
|
duckdb_statement_config = StatementConfig(
|
|
43
41
|
dialect="duckdb",
|
|
44
42
|
parameter_config=ParameterStyleConfig(
|
|
45
43
|
default_parameter_style=ParameterStyle.QMARK,
|
|
46
44
|
supported_parameter_styles={ParameterStyle.QMARK, ParameterStyle.NUMERIC, ParameterStyle.NAMED_DOLLAR},
|
|
47
45
|
default_execution_parameter_style=ParameterStyle.QMARK,
|
|
48
|
-
supported_execution_parameter_styles={
|
|
49
|
-
ParameterStyle.QMARK,
|
|
50
|
-
ParameterStyle.NUMERIC,
|
|
51
|
-
ParameterStyle.NAMED_DOLLAR,
|
|
52
|
-
},
|
|
46
|
+
supported_execution_parameter_styles={ParameterStyle.QMARK, ParameterStyle.NUMERIC},
|
|
53
47
|
type_coercion_map={},
|
|
54
48
|
has_native_list_expansion=True,
|
|
55
49
|
needs_static_script_compilation=False,
|
|
56
50
|
preserve_parameter_format=True,
|
|
57
|
-
allow_mixed_parameter_styles=False,
|
|
51
|
+
allow_mixed_parameter_styles=False,
|
|
58
52
|
),
|
|
59
|
-
# Core processing features enabled for performance
|
|
60
53
|
enable_parsing=True,
|
|
61
54
|
enable_validation=True,
|
|
62
55
|
enable_caching=True,
|
|
63
56
|
enable_parameter_type_wrapping=True,
|
|
64
57
|
)
|
|
65
58
|
|
|
66
|
-
|
|
59
|
+
|
|
67
60
|
MODIFYING_OPERATIONS: Final[tuple[str, ...]] = ("INSERT", "UPDATE", "DELETE")
|
|
68
61
|
|
|
69
62
|
|
|
70
63
|
class DuckDBCursor:
|
|
71
|
-
"""Context manager for DuckDB cursor management
|
|
64
|
+
"""Context manager for DuckDB cursor management."""
|
|
72
65
|
|
|
73
66
|
__slots__ = ("connection", "cursor")
|
|
74
67
|
|
|
@@ -81,7 +74,7 @@ class DuckDBCursor:
|
|
|
81
74
|
return self.cursor
|
|
82
75
|
|
|
83
76
|
def __exit__(self, exc_type: Any, exc_val: Any, exc_tb: Any) -> None:
|
|
84
|
-
_ = (exc_type, exc_val, exc_tb)
|
|
77
|
+
_ = (exc_type, exc_val, exc_tb)
|
|
85
78
|
if self.cursor is not None:
|
|
86
79
|
self.cursor.close()
|
|
87
80
|
|
|
@@ -133,34 +126,33 @@ class DuckDBExceptionHandler:
|
|
|
133
126
|
|
|
134
127
|
|
|
135
128
|
class DuckDBDriver(SyncDriverAdapterBase):
|
|
136
|
-
"""
|
|
129
|
+
"""DuckDB driver implementation.
|
|
137
130
|
|
|
138
|
-
This driver
|
|
131
|
+
This driver uses the core module system for SQL processing:
|
|
139
132
|
|
|
140
|
-
|
|
141
|
-
-
|
|
142
|
-
-
|
|
143
|
-
-
|
|
144
|
-
-
|
|
145
|
-
- DuckDB
|
|
133
|
+
Features:
|
|
134
|
+
- SQL compilation with single-pass processing
|
|
135
|
+
- Memory-efficient design with __slots__
|
|
136
|
+
- Statement caching for repeated execution
|
|
137
|
+
- Parameter processing with type coercion
|
|
138
|
+
- DuckDB resource management
|
|
146
139
|
|
|
147
|
-
Core Integration
|
|
148
|
-
- sqlspec.core.statement for
|
|
149
|
-
- sqlspec.core.parameters for
|
|
150
|
-
- sqlspec.core.cache for
|
|
151
|
-
- sqlspec.core.config for
|
|
140
|
+
Core Integration:
|
|
141
|
+
- sqlspec.core.statement for SQL processing
|
|
142
|
+
- sqlspec.core.parameters for parameter handling
|
|
143
|
+
- sqlspec.core.cache for statement caching
|
|
144
|
+
- sqlspec.core.config for configuration management
|
|
152
145
|
|
|
153
|
-
DuckDB
|
|
146
|
+
DuckDB Support:
|
|
154
147
|
- Multi-parameter style support (QMARK, NUMERIC, NAMED_DOLLAR)
|
|
155
|
-
-
|
|
156
|
-
-
|
|
148
|
+
- Script execution with statement splitting
|
|
149
|
+
- Batch operations with row counting
|
|
157
150
|
- DuckDB-specific exception handling
|
|
158
151
|
|
|
159
152
|
Compatibility:
|
|
160
|
-
-
|
|
161
|
-
-
|
|
162
|
-
-
|
|
163
|
-
- Preserved transaction management patterns
|
|
153
|
+
- Backward compatibility with existing DuckDB driver interface
|
|
154
|
+
- StatementConfig API compatibility
|
|
155
|
+
- Transaction management patterns
|
|
164
156
|
"""
|
|
165
157
|
|
|
166
158
|
__slots__ = ()
|
|
@@ -172,21 +164,20 @@ class DuckDBDriver(SyncDriverAdapterBase):
|
|
|
172
164
|
statement_config: "Optional[StatementConfig]" = None,
|
|
173
165
|
driver_features: "Optional[dict[str, Any]]" = None,
|
|
174
166
|
) -> None:
|
|
175
|
-
# Enhanced configuration with global settings integration
|
|
176
167
|
if statement_config is None:
|
|
177
168
|
cache_config = get_cache_config()
|
|
178
|
-
|
|
169
|
+
updated_config = duckdb_statement_config.replace(
|
|
179
170
|
enable_caching=cache_config.compiled_cache_enabled,
|
|
180
|
-
enable_parsing=True,
|
|
181
|
-
enable_validation=True,
|
|
182
|
-
dialect="duckdb",
|
|
171
|
+
enable_parsing=True,
|
|
172
|
+
enable_validation=True,
|
|
173
|
+
dialect="duckdb",
|
|
183
174
|
)
|
|
184
|
-
statement_config =
|
|
175
|
+
statement_config = updated_config
|
|
185
176
|
|
|
186
177
|
super().__init__(connection=connection, statement_config=statement_config, driver_features=driver_features)
|
|
187
178
|
|
|
188
179
|
def with_cursor(self, connection: "DuckDBConnection") -> "DuckDBCursor":
|
|
189
|
-
"""Create context manager for DuckDB cursor
|
|
180
|
+
"""Create context manager for DuckDB cursor."""
|
|
190
181
|
return DuckDBCursor(connection)
|
|
191
182
|
|
|
192
183
|
def handle_database_exceptions(self) -> "AbstractContextManager[None]":
|
|
@@ -206,14 +197,14 @@ class DuckDBDriver(SyncDriverAdapterBase):
|
|
|
206
197
|
Returns:
|
|
207
198
|
None for standard execution (no special operations)
|
|
208
199
|
"""
|
|
209
|
-
_ = (cursor, statement)
|
|
200
|
+
_ = (cursor, statement)
|
|
210
201
|
return None
|
|
211
202
|
|
|
212
203
|
def _is_modifying_operation(self, statement: SQL) -> bool:
|
|
213
|
-
"""Check if the SQL statement is a modifying operation
|
|
204
|
+
"""Check if the SQL statement is a modifying operation.
|
|
214
205
|
|
|
215
206
|
Uses both AST-based detection (when available) and SQL text analysis
|
|
216
|
-
|
|
207
|
+
to identify operation type.
|
|
217
208
|
|
|
218
209
|
Args:
|
|
219
210
|
statement: SQL statement to analyze
|
|
@@ -221,20 +212,19 @@ class DuckDBDriver(SyncDriverAdapterBase):
|
|
|
221
212
|
Returns:
|
|
222
213
|
True if the operation modifies data (INSERT/UPDATE/DELETE)
|
|
223
214
|
"""
|
|
224
|
-
|
|
215
|
+
|
|
225
216
|
expression = statement.expression
|
|
226
217
|
if expression and isinstance(expression, (exp.Insert, exp.Update, exp.Delete)):
|
|
227
218
|
return True
|
|
228
219
|
|
|
229
|
-
# Fallback to SQL text analysis for comprehensive detection
|
|
230
220
|
sql_upper = statement.sql.strip().upper()
|
|
231
221
|
return any(sql_upper.startswith(op) for op in MODIFYING_OPERATIONS)
|
|
232
222
|
|
|
233
223
|
def _execute_script(self, cursor: Any, statement: SQL) -> "ExecutionResult":
|
|
234
|
-
"""Execute SQL script
|
|
224
|
+
"""Execute SQL script with statement splitting and parameter handling.
|
|
235
225
|
|
|
236
|
-
Uses core module
|
|
237
|
-
Handles DuckDB
|
|
226
|
+
Uses core module for statement parsing and parameter processing.
|
|
227
|
+
Handles DuckDB script execution requirements with parameter support.
|
|
238
228
|
|
|
239
229
|
Args:
|
|
240
230
|
cursor: DuckDB cursor object
|
|
@@ -250,7 +240,6 @@ class DuckDBDriver(SyncDriverAdapterBase):
|
|
|
250
240
|
last_result = None
|
|
251
241
|
|
|
252
242
|
for stmt in statements:
|
|
253
|
-
# Execute each statement with parameters (DuckDB supports parameters in script statements)
|
|
254
243
|
last_result = cursor.execute(stmt, prepared_parameters or ())
|
|
255
244
|
successful_count += 1
|
|
256
245
|
|
|
@@ -259,35 +248,30 @@ class DuckDBDriver(SyncDriverAdapterBase):
|
|
|
259
248
|
)
|
|
260
249
|
|
|
261
250
|
def _execute_many(self, cursor: Any, statement: SQL) -> "ExecutionResult":
|
|
262
|
-
"""Execute SQL with multiple parameter sets using
|
|
251
|
+
"""Execute SQL with multiple parameter sets using batch processing.
|
|
263
252
|
|
|
264
|
-
|
|
265
|
-
|
|
253
|
+
Uses DuckDB's executemany for batch operations with
|
|
254
|
+
row counting for both modifying and non-modifying operations.
|
|
266
255
|
|
|
267
256
|
Args:
|
|
268
257
|
cursor: DuckDB cursor object
|
|
269
258
|
statement: SQL statement with multiple parameter sets
|
|
270
259
|
|
|
271
260
|
Returns:
|
|
272
|
-
ExecutionResult with
|
|
261
|
+
ExecutionResult with batch execution metadata
|
|
273
262
|
"""
|
|
274
263
|
sql, prepared_parameters = self._get_compiled_sql(statement, self.statement_config)
|
|
275
264
|
|
|
276
265
|
if prepared_parameters:
|
|
277
|
-
# Use DuckDB's efficient executemany for batch operations
|
|
278
266
|
cursor.executemany(sql, prepared_parameters)
|
|
279
267
|
|
|
280
|
-
# Enhanced row counting based on operation type
|
|
281
268
|
if self._is_modifying_operation(statement):
|
|
282
|
-
# For modifying operations, count equals number of parameter sets
|
|
283
269
|
row_count = len(prepared_parameters)
|
|
284
270
|
else:
|
|
285
|
-
# For non-modifying operations, attempt to fetch result count
|
|
286
271
|
try:
|
|
287
272
|
result = cursor.fetchone()
|
|
288
273
|
row_count = int(result[0]) if result and isinstance(result, tuple) and len(result) == 1 else 0
|
|
289
274
|
except Exception:
|
|
290
|
-
# Fallback to cursor.rowcount or 0
|
|
291
275
|
row_count = max(cursor.rowcount, 0) if hasattr(cursor, "rowcount") else 0
|
|
292
276
|
else:
|
|
293
277
|
row_count = 0
|
|
@@ -295,32 +279,28 @@ class DuckDBDriver(SyncDriverAdapterBase):
|
|
|
295
279
|
return self.create_execution_result(cursor, rowcount_override=row_count, is_many_result=True)
|
|
296
280
|
|
|
297
281
|
def _execute_statement(self, cursor: Any, statement: SQL) -> "ExecutionResult":
|
|
298
|
-
"""Execute single SQL statement with
|
|
282
|
+
"""Execute single SQL statement with data handling.
|
|
299
283
|
|
|
300
|
-
Uses core processing for
|
|
301
|
-
Handles both SELECT queries and non-SELECT operations
|
|
284
|
+
Uses core processing for parameter handling and result processing.
|
|
285
|
+
Handles both SELECT queries and non-SELECT operations.
|
|
302
286
|
|
|
303
287
|
Args:
|
|
304
288
|
cursor: DuckDB cursor object
|
|
305
289
|
statement: SQL statement to execute
|
|
306
290
|
|
|
307
291
|
Returns:
|
|
308
|
-
ExecutionResult with
|
|
292
|
+
ExecutionResult with execution metadata
|
|
309
293
|
"""
|
|
310
294
|
sql, prepared_parameters = self._get_compiled_sql(statement, self.statement_config)
|
|
311
295
|
cursor.execute(sql, prepared_parameters or ())
|
|
312
296
|
|
|
313
|
-
# Enhanced SELECT result processing
|
|
314
297
|
if statement.returns_rows():
|
|
315
298
|
fetched_data = cursor.fetchall()
|
|
316
299
|
column_names = [col[0] for col in cursor.description or []]
|
|
317
300
|
|
|
318
|
-
# Efficient data conversion handling multiple formats
|
|
319
301
|
if fetched_data and isinstance(fetched_data[0], tuple):
|
|
320
|
-
# Convert tuple rows to dictionaries for consistent interface
|
|
321
302
|
dict_data = [dict(zip(column_names, row)) for row in fetched_data]
|
|
322
303
|
else:
|
|
323
|
-
# Data already in appropriate format
|
|
324
304
|
dict_data = fetched_data
|
|
325
305
|
|
|
326
306
|
return self.create_execution_result(
|
|
@@ -331,20 +311,16 @@ class DuckDBDriver(SyncDriverAdapterBase):
|
|
|
331
311
|
is_select_result=True,
|
|
332
312
|
)
|
|
333
313
|
|
|
334
|
-
# Enhanced non-SELECT result processing with multiple row count strategies
|
|
335
314
|
try:
|
|
336
|
-
# Try to fetch result for operations that return row counts
|
|
337
315
|
result = cursor.fetchone()
|
|
338
316
|
row_count = int(result[0]) if result and isinstance(result, tuple) and len(result) == 1 else 0
|
|
339
317
|
except Exception:
|
|
340
|
-
# Fallback to cursor.rowcount or 0 for operations without result sets
|
|
341
318
|
row_count = max(cursor.rowcount, 0) if hasattr(cursor, "rowcount") else 0
|
|
342
319
|
|
|
343
320
|
return self.create_execution_result(cursor, rowcount_override=row_count)
|
|
344
321
|
|
|
345
|
-
# Transaction management with enhanced error handling
|
|
346
322
|
def begin(self) -> None:
|
|
347
|
-
"""Begin a database transaction
|
|
323
|
+
"""Begin a database transaction."""
|
|
348
324
|
try:
|
|
349
325
|
self.connection.execute("BEGIN TRANSACTION")
|
|
350
326
|
except duckdb.Error as e:
|
|
@@ -352,7 +328,7 @@ class DuckDBDriver(SyncDriverAdapterBase):
|
|
|
352
328
|
raise SQLSpecError(msg) from e
|
|
353
329
|
|
|
354
330
|
def rollback(self) -> None:
|
|
355
|
-
"""Rollback the current transaction
|
|
331
|
+
"""Rollback the current transaction."""
|
|
356
332
|
try:
|
|
357
333
|
self.connection.rollback()
|
|
358
334
|
except duckdb.Error as e:
|
|
@@ -360,7 +336,7 @@ class DuckDBDriver(SyncDriverAdapterBase):
|
|
|
360
336
|
raise SQLSpecError(msg) from e
|
|
361
337
|
|
|
362
338
|
def commit(self) -> None:
|
|
363
|
-
"""Commit the current transaction
|
|
339
|
+
"""Commit the current transaction."""
|
|
364
340
|
try:
|
|
365
341
|
self.connection.commit()
|
|
366
342
|
except duckdb.Error as e:
|
sqlspec/adapters/duckdb/pool.py
CHANGED
|
@@ -25,7 +25,7 @@ __all__ = ("DuckDBConnectionPool",)
|
|
|
25
25
|
|
|
26
26
|
|
|
27
27
|
class DuckDBConnectionPool:
|
|
28
|
-
"""Thread-local connection manager for DuckDB
|
|
28
|
+
"""Thread-local connection manager for DuckDB.
|
|
29
29
|
|
|
30
30
|
Uses thread-local storage to ensure each thread gets its own DuckDB connection,
|
|
31
31
|
preventing the thread-safety issues that cause segmentation faults when
|
|
@@ -54,7 +54,7 @@ class DuckDBConnectionPool:
|
|
|
54
54
|
extensions: "Optional[list[dict[str, Any]]]" = None,
|
|
55
55
|
secrets: "Optional[list[dict[str, Any]]]" = None,
|
|
56
56
|
on_connection_create: "Optional[Callable[[DuckDBConnection], None]]" = None,
|
|
57
|
-
**kwargs: Any,
|
|
57
|
+
**kwargs: Any,
|
|
58
58
|
) -> None:
|
|
59
59
|
"""Initialize the thread-local connection manager.
|
|
60
60
|
|
|
@@ -159,7 +159,6 @@ class DuckDBConnectionPool:
|
|
|
159
159
|
self._thread_local.connection = self._create_connection()
|
|
160
160
|
self._thread_local.created_at = time.time()
|
|
161
161
|
|
|
162
|
-
# Check if connection needs recycling
|
|
163
162
|
if self._recycle > 0 and time.time() - self._thread_local.created_at > self._recycle:
|
|
164
163
|
with suppress(Exception):
|
|
165
164
|
self._thread_local.connection.close()
|
|
@@ -207,7 +206,6 @@ class DuckDBConnectionPool:
|
|
|
207
206
|
try:
|
|
208
207
|
yield connection
|
|
209
208
|
except Exception:
|
|
210
|
-
# On error, close and recreate connection for this thread
|
|
211
209
|
self._close_thread_connection()
|
|
212
210
|
raise
|
|
213
211
|
|
|
@@ -240,4 +238,3 @@ class DuckDBConnectionPool:
|
|
|
240
238
|
Args:
|
|
241
239
|
connection: The connection to release (ignored)
|
|
242
240
|
"""
|
|
243
|
-
# No-op: thread-local connections are managed per-thread
|
|
@@ -3,12 +3,19 @@ from typing import TYPE_CHECKING
|
|
|
3
3
|
from oracledb import AsyncConnection, Connection
|
|
4
4
|
|
|
5
5
|
if TYPE_CHECKING:
|
|
6
|
+
from oracledb.pool import AsyncConnectionPool, ConnectionPool
|
|
6
7
|
from typing_extensions import TypeAlias
|
|
7
8
|
|
|
8
9
|
OracleSyncConnection: TypeAlias = Connection
|
|
9
10
|
OracleAsyncConnection: TypeAlias = AsyncConnection
|
|
11
|
+
OracleSyncConnectionPool: TypeAlias = ConnectionPool
|
|
12
|
+
OracleAsyncConnectionPool: TypeAlias = AsyncConnectionPool
|
|
10
13
|
else:
|
|
14
|
+
from oracledb.pool import AsyncConnectionPool, ConnectionPool
|
|
15
|
+
|
|
11
16
|
OracleSyncConnection = Connection
|
|
12
17
|
OracleAsyncConnection = AsyncConnection
|
|
18
|
+
OracleSyncConnectionPool = ConnectionPool
|
|
19
|
+
OracleAsyncConnectionPool = AsyncConnectionPool
|
|
13
20
|
|
|
14
|
-
__all__ = ("OracleAsyncConnection", "OracleSyncConnection")
|
|
21
|
+
__all__ = ("OracleAsyncConnection", "OracleAsyncConnectionPool", "OracleSyncConnection", "OracleSyncConnectionPool")
|
|
@@ -8,7 +8,12 @@ from typing import TYPE_CHECKING, Any, ClassVar, Optional, TypedDict, Union, cas
|
|
|
8
8
|
import oracledb
|
|
9
9
|
from typing_extensions import NotRequired
|
|
10
10
|
|
|
11
|
-
from sqlspec.adapters.oracledb._types import
|
|
11
|
+
from sqlspec.adapters.oracledb._types import (
|
|
12
|
+
OracleAsyncConnection,
|
|
13
|
+
OracleAsyncConnectionPool,
|
|
14
|
+
OracleSyncConnection,
|
|
15
|
+
OracleSyncConnectionPool,
|
|
16
|
+
)
|
|
12
17
|
from sqlspec.adapters.oracledb.driver import (
|
|
13
18
|
OracleAsyncCursor,
|
|
14
19
|
OracleAsyncDriver,
|
|
@@ -16,13 +21,13 @@ from sqlspec.adapters.oracledb.driver import (
|
|
|
16
21
|
OracleSyncDriver,
|
|
17
22
|
oracledb_statement_config,
|
|
18
23
|
)
|
|
24
|
+
from sqlspec.adapters.oracledb.migrations import OracleAsyncMigrationTracker, OracleSyncMigrationTracker
|
|
19
25
|
from sqlspec.config import AsyncDatabaseConfig, SyncDatabaseConfig
|
|
20
26
|
|
|
21
27
|
if TYPE_CHECKING:
|
|
22
28
|
from collections.abc import AsyncGenerator, Callable, Generator
|
|
23
29
|
|
|
24
30
|
from oracledb import AuthMode
|
|
25
|
-
from oracledb.pool import AsyncConnectionPool, ConnectionPool
|
|
26
31
|
|
|
27
32
|
from sqlspec.core.statement import StatementConfig
|
|
28
33
|
|
|
@@ -72,29 +77,34 @@ class OraclePoolParams(OracleConnectionParams, total=False):
|
|
|
72
77
|
extra: NotRequired[dict[str, Any]]
|
|
73
78
|
|
|
74
79
|
|
|
75
|
-
class OracleSyncConfig(SyncDatabaseConfig[OracleSyncConnection, "
|
|
76
|
-
"""Configuration for Oracle synchronous database connections
|
|
80
|
+
class OracleSyncConfig(SyncDatabaseConfig[OracleSyncConnection, "OracleSyncConnectionPool", OracleSyncDriver]):
|
|
81
|
+
"""Configuration for Oracle synchronous database connections."""
|
|
82
|
+
|
|
83
|
+
__slots__ = ()
|
|
77
84
|
|
|
78
85
|
driver_type: ClassVar[type[OracleSyncDriver]] = OracleSyncDriver
|
|
79
86
|
connection_type: "ClassVar[type[OracleSyncConnection]]" = OracleSyncConnection
|
|
87
|
+
migration_tracker_type: "ClassVar[type[OracleSyncMigrationTracker]]" = OracleSyncMigrationTracker
|
|
80
88
|
|
|
81
89
|
def __init__(
|
|
82
90
|
self,
|
|
83
91
|
*,
|
|
84
|
-
pool_instance: "Optional[ConnectionPool]" = None,
|
|
85
92
|
pool_config: "Optional[Union[OraclePoolParams, dict[str, Any]]]" = None,
|
|
86
|
-
|
|
93
|
+
pool_instance: "Optional[OracleSyncConnectionPool]" = None,
|
|
87
94
|
migration_config: Optional[dict[str, Any]] = None,
|
|
95
|
+
statement_config: "Optional[StatementConfig]" = None,
|
|
96
|
+
driver_features: "Optional[dict[str, Any]]" = None,
|
|
88
97
|
) -> None:
|
|
89
98
|
"""Initialize Oracle synchronous configuration.
|
|
90
99
|
|
|
91
100
|
Args:
|
|
92
101
|
pool_config: Pool configuration parameters
|
|
93
102
|
pool_instance: Existing pool instance to use
|
|
94
|
-
statement_config: Default SQL statement configuration
|
|
95
103
|
migration_config: Migration configuration
|
|
104
|
+
statement_config: Default SQL statement configuration
|
|
105
|
+
driver_features: Optional driver feature configuration
|
|
96
106
|
"""
|
|
97
|
-
|
|
107
|
+
|
|
98
108
|
processed_pool_config: dict[str, Any] = dict(pool_config) if pool_config else {}
|
|
99
109
|
if "extra" in processed_pool_config:
|
|
100
110
|
extras = processed_pool_config.pop("extra")
|
|
@@ -105,9 +115,10 @@ class OracleSyncConfig(SyncDatabaseConfig[OracleSyncConnection, "ConnectionPool"
|
|
|
105
115
|
pool_instance=pool_instance,
|
|
106
116
|
migration_config=migration_config,
|
|
107
117
|
statement_config=statement_config,
|
|
118
|
+
driver_features=driver_features or {},
|
|
108
119
|
)
|
|
109
120
|
|
|
110
|
-
def _create_pool(self) -> "
|
|
121
|
+
def _create_pool(self) -> "OracleSyncConnectionPool":
|
|
111
122
|
"""Create the actual connection pool."""
|
|
112
123
|
|
|
113
124
|
return oracledb.create_pool(**dict(self.pool_config))
|
|
@@ -128,13 +139,9 @@ class OracleSyncConfig(SyncDatabaseConfig[OracleSyncConnection, "ConnectionPool"
|
|
|
128
139
|
return self.pool_instance.acquire()
|
|
129
140
|
|
|
130
141
|
@contextlib.contextmanager
|
|
131
|
-
def provide_connection(self
|
|
142
|
+
def provide_connection(self) -> "Generator[OracleSyncConnection, None, None]":
|
|
132
143
|
"""Provide a connection context manager.
|
|
133
144
|
|
|
134
|
-
Args:
|
|
135
|
-
*args: Additional arguments.
|
|
136
|
-
**kwargs: Additional keyword arguments.
|
|
137
|
-
|
|
138
145
|
Yields:
|
|
139
146
|
An Oracle Connection instance.
|
|
140
147
|
"""
|
|
@@ -153,17 +160,18 @@ class OracleSyncConfig(SyncDatabaseConfig[OracleSyncConnection, "ConnectionPool"
|
|
|
153
160
|
"""Provide a driver session context manager.
|
|
154
161
|
|
|
155
162
|
Args:
|
|
156
|
-
*args:
|
|
163
|
+
*args: Positional arguments (unused).
|
|
157
164
|
statement_config: Optional statement configuration override.
|
|
158
|
-
**kwargs:
|
|
165
|
+
**kwargs: Keyword arguments (unused).
|
|
159
166
|
|
|
160
167
|
Yields:
|
|
161
168
|
An OracleSyncDriver instance.
|
|
162
169
|
"""
|
|
163
|
-
|
|
170
|
+
_ = (args, kwargs) # Mark as intentionally unused
|
|
171
|
+
with self.provide_connection() as conn:
|
|
164
172
|
yield self.driver_type(connection=conn, statement_config=statement_config or self.statement_config)
|
|
165
173
|
|
|
166
|
-
def provide_pool(self
|
|
174
|
+
def provide_pool(self) -> "OracleSyncConnectionPool":
|
|
167
175
|
"""Provide pool instance.
|
|
168
176
|
|
|
169
177
|
Returns:
|
|
@@ -176,8 +184,7 @@ class OracleSyncConfig(SyncDatabaseConfig[OracleSyncConnection, "ConnectionPool"
|
|
|
176
184
|
def get_signature_namespace(self) -> "dict[str, type[Any]]":
|
|
177
185
|
"""Get the signature namespace for OracleDB types.
|
|
178
186
|
|
|
179
|
-
|
|
180
|
-
to avoid serialization attempts.
|
|
187
|
+
Provides OracleDB-specific types for Litestar framework recognition.
|
|
181
188
|
|
|
182
189
|
Returns:
|
|
183
190
|
Dictionary mapping type names to types.
|
|
@@ -188,35 +195,42 @@ class OracleSyncConfig(SyncDatabaseConfig[OracleSyncConnection, "ConnectionPool"
|
|
|
188
195
|
{
|
|
189
196
|
"OracleSyncConnection": OracleSyncConnection,
|
|
190
197
|
"OracleAsyncConnection": OracleAsyncConnection,
|
|
198
|
+
"OracleSyncConnectionPool": OracleSyncConnectionPool,
|
|
199
|
+
"OracleAsyncConnectionPool": OracleAsyncConnectionPool,
|
|
191
200
|
"OracleSyncCursor": OracleSyncCursor,
|
|
192
201
|
}
|
|
193
202
|
)
|
|
194
203
|
return namespace
|
|
195
204
|
|
|
196
205
|
|
|
197
|
-
class OracleAsyncConfig(AsyncDatabaseConfig[OracleAsyncConnection, "
|
|
198
|
-
"""Configuration for Oracle asynchronous database connections
|
|
206
|
+
class OracleAsyncConfig(AsyncDatabaseConfig[OracleAsyncConnection, "OracleAsyncConnectionPool", OracleAsyncDriver]):
|
|
207
|
+
"""Configuration for Oracle asynchronous database connections."""
|
|
208
|
+
|
|
209
|
+
__slots__ = ()
|
|
199
210
|
|
|
200
211
|
connection_type: "ClassVar[type[OracleAsyncConnection]]" = OracleAsyncConnection
|
|
201
212
|
driver_type: ClassVar[type[OracleAsyncDriver]] = OracleAsyncDriver
|
|
213
|
+
migration_tracker_type: "ClassVar[type[OracleAsyncMigrationTracker]]" = OracleAsyncMigrationTracker
|
|
202
214
|
|
|
203
215
|
def __init__(
|
|
204
216
|
self,
|
|
205
217
|
*,
|
|
206
218
|
pool_config: "Optional[Union[OraclePoolParams, dict[str, Any]]]" = None,
|
|
207
|
-
pool_instance: "Optional[
|
|
208
|
-
statement_config: "Optional[StatementConfig]" = None,
|
|
219
|
+
pool_instance: "Optional[OracleAsyncConnectionPool]" = None,
|
|
209
220
|
migration_config: Optional[dict[str, Any]] = None,
|
|
221
|
+
statement_config: "Optional[StatementConfig]" = None,
|
|
222
|
+
driver_features: "Optional[dict[str, Any]]" = None,
|
|
210
223
|
) -> None:
|
|
211
224
|
"""Initialize Oracle asynchronous configuration.
|
|
212
225
|
|
|
213
226
|
Args:
|
|
214
227
|
pool_config: Pool configuration parameters
|
|
215
228
|
pool_instance: Existing pool instance to use
|
|
216
|
-
statement_config: Default SQL statement configuration
|
|
217
229
|
migration_config: Migration configuration
|
|
230
|
+
statement_config: Default SQL statement configuration
|
|
231
|
+
driver_features: Optional driver feature configuration
|
|
218
232
|
"""
|
|
219
|
-
|
|
233
|
+
|
|
220
234
|
processed_pool_config: dict[str, Any] = dict(pool_config) if pool_config else {}
|
|
221
235
|
if "extra" in processed_pool_config:
|
|
222
236
|
extras = processed_pool_config.pop("extra")
|
|
@@ -227,9 +241,10 @@ class OracleAsyncConfig(AsyncDatabaseConfig[OracleAsyncConnection, "AsyncConnect
|
|
|
227
241
|
pool_instance=pool_instance,
|
|
228
242
|
migration_config=migration_config,
|
|
229
243
|
statement_config=statement_config or oracledb_statement_config,
|
|
244
|
+
driver_features=driver_features or {},
|
|
230
245
|
)
|
|
231
246
|
|
|
232
|
-
async def _create_pool(self) -> "
|
|
247
|
+
async def _create_pool(self) -> "OracleAsyncConnectionPool":
|
|
233
248
|
"""Create the actual async connection pool."""
|
|
234
249
|
|
|
235
250
|
return oracledb.create_pool_async(**dict(self.pool_config))
|
|
@@ -239,6 +254,10 @@ class OracleAsyncConfig(AsyncDatabaseConfig[OracleAsyncConnection, "AsyncConnect
|
|
|
239
254
|
if self.pool_instance:
|
|
240
255
|
await self.pool_instance.close()
|
|
241
256
|
|
|
257
|
+
async def close_pool(self) -> None:
|
|
258
|
+
"""Close the connection pool."""
|
|
259
|
+
await self._close_pool()
|
|
260
|
+
|
|
242
261
|
async def create_connection(self) -> OracleAsyncConnection:
|
|
243
262
|
"""Create a single async connection (not from pool).
|
|
244
263
|
|
|
@@ -250,13 +269,9 @@ class OracleAsyncConfig(AsyncDatabaseConfig[OracleAsyncConnection, "AsyncConnect
|
|
|
250
269
|
return cast("OracleAsyncConnection", await self.pool_instance.acquire())
|
|
251
270
|
|
|
252
271
|
@asynccontextmanager
|
|
253
|
-
async def provide_connection(self
|
|
272
|
+
async def provide_connection(self) -> "AsyncGenerator[OracleAsyncConnection, None]":
|
|
254
273
|
"""Provide an async connection context manager.
|
|
255
274
|
|
|
256
|
-
Args:
|
|
257
|
-
*args: Additional arguments.
|
|
258
|
-
**kwargs: Additional keyword arguments.
|
|
259
|
-
|
|
260
275
|
Yields:
|
|
261
276
|
An Oracle AsyncConnection instance.
|
|
262
277
|
"""
|
|
@@ -275,17 +290,18 @@ class OracleAsyncConfig(AsyncDatabaseConfig[OracleAsyncConnection, "AsyncConnect
|
|
|
275
290
|
"""Provide an async driver session context manager.
|
|
276
291
|
|
|
277
292
|
Args:
|
|
278
|
-
*args:
|
|
293
|
+
*args: Positional arguments (unused).
|
|
279
294
|
statement_config: Optional statement configuration override.
|
|
280
|
-
**kwargs:
|
|
295
|
+
**kwargs: Keyword arguments (unused).
|
|
281
296
|
|
|
282
297
|
Yields:
|
|
283
298
|
An OracleAsyncDriver instance.
|
|
284
299
|
"""
|
|
285
|
-
|
|
300
|
+
_ = (args, kwargs) # Mark as intentionally unused
|
|
301
|
+
async with self.provide_connection() as conn:
|
|
286
302
|
yield self.driver_type(connection=conn, statement_config=statement_config or self.statement_config)
|
|
287
303
|
|
|
288
|
-
async def provide_pool(self
|
|
304
|
+
async def provide_pool(self) -> "OracleAsyncConnectionPool":
|
|
289
305
|
"""Provide async pool instance.
|
|
290
306
|
|
|
291
307
|
Returns:
|
|
@@ -298,8 +314,7 @@ class OracleAsyncConfig(AsyncDatabaseConfig[OracleAsyncConnection, "AsyncConnect
|
|
|
298
314
|
def get_signature_namespace(self) -> "dict[str, type[Any]]":
|
|
299
315
|
"""Get the signature namespace for OracleDB async types.
|
|
300
316
|
|
|
301
|
-
|
|
302
|
-
to avoid serialization attempts.
|
|
317
|
+
Provides OracleDB async-specific types for Litestar framework recognition.
|
|
303
318
|
|
|
304
319
|
Returns:
|
|
305
320
|
Dictionary mapping type names to types.
|
|
@@ -310,6 +325,8 @@ class OracleAsyncConfig(AsyncDatabaseConfig[OracleAsyncConnection, "AsyncConnect
|
|
|
310
325
|
{
|
|
311
326
|
"OracleSyncConnection": OracleSyncConnection,
|
|
312
327
|
"OracleAsyncConnection": OracleAsyncConnection,
|
|
328
|
+
"OracleSyncConnectionPool": OracleSyncConnectionPool,
|
|
329
|
+
"OracleAsyncConnectionPool": OracleAsyncConnectionPool,
|
|
313
330
|
"OracleSyncCursor": OracleSyncCursor,
|
|
314
331
|
"OracleAsyncCursor": OracleAsyncCursor,
|
|
315
332
|
}
|