sqlspec 0.12.2__py3-none-any.whl → 0.13.1__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/_sql.py +21 -180
- sqlspec/adapters/adbc/config.py +10 -12
- sqlspec/adapters/adbc/driver.py +120 -118
- sqlspec/adapters/aiosqlite/config.py +16 -3
- sqlspec/adapters/aiosqlite/driver.py +100 -130
- sqlspec/adapters/asyncmy/config.py +17 -4
- sqlspec/adapters/asyncmy/driver.py +123 -135
- sqlspec/adapters/asyncpg/config.py +17 -29
- sqlspec/adapters/asyncpg/driver.py +98 -140
- sqlspec/adapters/bigquery/config.py +4 -5
- sqlspec/adapters/bigquery/driver.py +125 -167
- sqlspec/adapters/duckdb/config.py +3 -6
- sqlspec/adapters/duckdb/driver.py +114 -111
- sqlspec/adapters/oracledb/config.py +32 -5
- sqlspec/adapters/oracledb/driver.py +242 -259
- sqlspec/adapters/psqlpy/config.py +18 -9
- sqlspec/adapters/psqlpy/driver.py +118 -93
- sqlspec/adapters/psycopg/config.py +44 -31
- sqlspec/adapters/psycopg/driver.py +283 -236
- sqlspec/adapters/sqlite/config.py +3 -3
- sqlspec/adapters/sqlite/driver.py +103 -97
- sqlspec/config.py +0 -4
- sqlspec/driver/_async.py +89 -98
- sqlspec/driver/_common.py +52 -17
- sqlspec/driver/_sync.py +81 -105
- sqlspec/driver/connection.py +207 -0
- sqlspec/driver/mixins/_csv_writer.py +91 -0
- sqlspec/driver/mixins/_pipeline.py +38 -49
- sqlspec/driver/mixins/_result_utils.py +27 -9
- sqlspec/driver/mixins/_storage.py +67 -181
- sqlspec/driver/mixins/_type_coercion.py +3 -4
- sqlspec/driver/parameters.py +138 -0
- sqlspec/exceptions.py +10 -2
- sqlspec/extensions/aiosql/adapter.py +0 -10
- sqlspec/extensions/litestar/handlers.py +0 -1
- sqlspec/extensions/litestar/plugin.py +0 -3
- sqlspec/extensions/litestar/providers.py +0 -14
- sqlspec/loader.py +25 -90
- sqlspec/protocols.py +542 -0
- sqlspec/service/__init__.py +3 -2
- sqlspec/service/_util.py +147 -0
- sqlspec/service/base.py +1116 -9
- sqlspec/statement/builder/__init__.py +42 -32
- sqlspec/statement/builder/_ddl_utils.py +0 -10
- sqlspec/statement/builder/_parsing_utils.py +10 -4
- sqlspec/statement/builder/base.py +67 -22
- sqlspec/statement/builder/column.py +283 -0
- sqlspec/statement/builder/ddl.py +91 -67
- sqlspec/statement/builder/delete.py +23 -7
- sqlspec/statement/builder/insert.py +29 -15
- sqlspec/statement/builder/merge.py +4 -4
- sqlspec/statement/builder/mixins/_aggregate_functions.py +113 -14
- sqlspec/statement/builder/mixins/_common_table_expr.py +0 -1
- sqlspec/statement/builder/mixins/_delete_from.py +1 -1
- sqlspec/statement/builder/mixins/_from.py +10 -8
- sqlspec/statement/builder/mixins/_group_by.py +0 -1
- sqlspec/statement/builder/mixins/_insert_from_select.py +0 -1
- sqlspec/statement/builder/mixins/_insert_values.py +0 -2
- sqlspec/statement/builder/mixins/_join.py +20 -13
- sqlspec/statement/builder/mixins/_limit_offset.py +3 -3
- sqlspec/statement/builder/mixins/_merge_clauses.py +3 -4
- sqlspec/statement/builder/mixins/_order_by.py +2 -2
- sqlspec/statement/builder/mixins/_pivot.py +4 -7
- sqlspec/statement/builder/mixins/_select_columns.py +6 -5
- sqlspec/statement/builder/mixins/_unpivot.py +6 -9
- sqlspec/statement/builder/mixins/_update_from.py +2 -1
- sqlspec/statement/builder/mixins/_update_set.py +11 -8
- sqlspec/statement/builder/mixins/_where.py +61 -34
- sqlspec/statement/builder/select.py +32 -17
- sqlspec/statement/builder/update.py +25 -11
- sqlspec/statement/filters.py +39 -14
- sqlspec/statement/parameter_manager.py +220 -0
- sqlspec/statement/parameters.py +210 -79
- sqlspec/statement/pipelines/__init__.py +166 -23
- sqlspec/statement/pipelines/analyzers/_analyzer.py +21 -20
- sqlspec/statement/pipelines/context.py +35 -39
- sqlspec/statement/pipelines/transformers/__init__.py +2 -3
- sqlspec/statement/pipelines/transformers/_expression_simplifier.py +19 -187
- sqlspec/statement/pipelines/transformers/_literal_parameterizer.py +628 -58
- sqlspec/statement/pipelines/transformers/_remove_comments_and_hints.py +76 -0
- sqlspec/statement/pipelines/validators/_dml_safety.py +33 -18
- sqlspec/statement/pipelines/validators/_parameter_style.py +87 -14
- sqlspec/statement/pipelines/validators/_performance.py +38 -23
- sqlspec/statement/pipelines/validators/_security.py +39 -62
- sqlspec/statement/result.py +37 -129
- sqlspec/statement/splitter.py +0 -12
- sqlspec/statement/sql.py +863 -391
- sqlspec/statement/sql_compiler.py +140 -0
- sqlspec/storage/__init__.py +10 -2
- sqlspec/storage/backends/fsspec.py +53 -8
- sqlspec/storage/backends/obstore.py +15 -19
- sqlspec/storage/capabilities.py +101 -0
- sqlspec/storage/registry.py +56 -83
- sqlspec/typing.py +6 -434
- sqlspec/utils/cached_property.py +25 -0
- sqlspec/utils/correlation.py +0 -2
- sqlspec/utils/logging.py +0 -6
- sqlspec/utils/sync_tools.py +0 -4
- sqlspec/utils/text.py +0 -5
- sqlspec/utils/type_guards.py +892 -0
- {sqlspec-0.12.2.dist-info → sqlspec-0.13.1.dist-info}/METADATA +1 -1
- sqlspec-0.13.1.dist-info/RECORD +150 -0
- sqlspec/statement/builder/protocols.py +0 -20
- sqlspec/statement/pipelines/base.py +0 -315
- sqlspec/statement/pipelines/result_types.py +0 -41
- sqlspec/statement/pipelines/transformers/_remove_comments.py +0 -66
- sqlspec/statement/pipelines/transformers/_remove_hints.py +0 -81
- sqlspec/statement/pipelines/validators/base.py +0 -67
- sqlspec/storage/protocol.py +0 -173
- sqlspec-0.12.2.dist-info/RECORD +0 -145
- {sqlspec-0.12.2.dist-info → sqlspec-0.13.1.dist-info}/WHEEL +0 -0
- {sqlspec-0.12.2.dist-info → sqlspec-0.13.1.dist-info}/licenses/LICENSE +0 -0
- {sqlspec-0.12.2.dist-info → sqlspec-0.13.1.dist-info}/licenses/NOTICE +0 -0
|
@@ -3,12 +3,13 @@ import uuid
|
|
|
3
3
|
from collections.abc import Generator
|
|
4
4
|
from contextlib import contextmanager
|
|
5
5
|
from pathlib import Path
|
|
6
|
-
from typing import TYPE_CHECKING, Any, ClassVar, Optional, Union
|
|
6
|
+
from typing import TYPE_CHECKING, Any, ClassVar, Optional, Union
|
|
7
7
|
|
|
8
8
|
from duckdb import DuckDBPyConnection
|
|
9
9
|
from sqlglot import exp
|
|
10
10
|
|
|
11
11
|
from sqlspec.driver import SyncDriverAdapterProtocol
|
|
12
|
+
from sqlspec.driver.connection import managed_transaction_sync
|
|
12
13
|
from sqlspec.driver.mixins import (
|
|
13
14
|
SQLTranslatorMixin,
|
|
14
15
|
SyncPipelinedExecutionMixin,
|
|
@@ -16,10 +17,11 @@ from sqlspec.driver.mixins import (
|
|
|
16
17
|
ToSchemaMixin,
|
|
17
18
|
TypeCoercionMixin,
|
|
18
19
|
)
|
|
20
|
+
from sqlspec.driver.parameters import normalize_parameter_sequence
|
|
19
21
|
from sqlspec.statement.parameters import ParameterStyle
|
|
20
|
-
from sqlspec.statement.result import ArrowResult,
|
|
22
|
+
from sqlspec.statement.result import ArrowResult, SQLResult
|
|
21
23
|
from sqlspec.statement.sql import SQL, SQLConfig
|
|
22
|
-
from sqlspec.typing import ArrowTable, DictRow,
|
|
24
|
+
from sqlspec.typing import ArrowTable, DictRow, RowT
|
|
23
25
|
from sqlspec.utils.logging import get_logger
|
|
24
26
|
|
|
25
27
|
if TYPE_CHECKING:
|
|
@@ -82,136 +84,129 @@ class DuckDBDriver(
|
|
|
82
84
|
|
|
83
85
|
def _execute_statement(
|
|
84
86
|
self, statement: SQL, connection: Optional["DuckDBConnection"] = None, **kwargs: Any
|
|
85
|
-
) ->
|
|
87
|
+
) -> SQLResult[RowT]:
|
|
86
88
|
if statement.is_script:
|
|
87
89
|
sql, _ = statement.compile(placeholder_style=ParameterStyle.STATIC)
|
|
88
90
|
return self._execute_script(sql, connection=connection, **kwargs)
|
|
89
91
|
|
|
92
|
+
sql, params = statement.compile(placeholder_style=self.default_parameter_style)
|
|
93
|
+
params = self._process_parameters(params)
|
|
94
|
+
|
|
90
95
|
if statement.is_many:
|
|
91
|
-
sql, params = statement.compile(placeholder_style=self.default_parameter_style)
|
|
92
|
-
params = self._process_parameters(params)
|
|
93
96
|
return self._execute_many(sql, params, connection=connection, **kwargs)
|
|
94
97
|
|
|
95
|
-
sql, params = statement.compile(placeholder_style=self.default_parameter_style)
|
|
96
|
-
params = self._process_parameters(params)
|
|
97
98
|
return self._execute(sql, params, statement, connection=connection, **kwargs)
|
|
98
99
|
|
|
99
100
|
def _execute(
|
|
100
101
|
self, sql: str, parameters: Any, statement: SQL, connection: Optional["DuckDBConnection"] = None, **kwargs: Any
|
|
101
|
-
) ->
|
|
102
|
-
|
|
102
|
+
) -> SQLResult[RowT]:
|
|
103
|
+
# Use provided connection or driver's default connection
|
|
104
|
+
conn = connection if connection is not None else self._connection(None)
|
|
105
|
+
|
|
106
|
+
with managed_transaction_sync(conn, auto_commit=True) as txn_conn:
|
|
107
|
+
# Normalize parameters using consolidated utility
|
|
108
|
+
normalized_params = normalize_parameter_sequence(parameters)
|
|
109
|
+
final_params = normalized_params or []
|
|
110
|
+
|
|
111
|
+
if self.returns_rows(statement.expression):
|
|
112
|
+
result = txn_conn.execute(sql, final_params)
|
|
113
|
+
fetched_data = result.fetchall()
|
|
114
|
+
column_names = [col[0] for col in result.description or []]
|
|
115
|
+
|
|
116
|
+
if fetched_data and isinstance(fetched_data[0], tuple):
|
|
117
|
+
dict_data = [dict(zip(column_names, row)) for row in fetched_data]
|
|
118
|
+
else:
|
|
119
|
+
dict_data = fetched_data
|
|
120
|
+
|
|
121
|
+
return SQLResult[RowT](
|
|
122
|
+
statement=statement,
|
|
123
|
+
data=dict_data, # type: ignore[arg-type]
|
|
124
|
+
column_names=column_names,
|
|
125
|
+
rows_affected=len(dict_data),
|
|
126
|
+
operation_type="SELECT",
|
|
127
|
+
)
|
|
103
128
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
return {"rows_affected": rows_affected}
|
|
129
|
+
with self._get_cursor(txn_conn) as cursor:
|
|
130
|
+
cursor.execute(sql, final_params)
|
|
131
|
+
# DuckDB returns -1 for rowcount on DML operations
|
|
132
|
+
# However, fetchone() returns the actual affected row count as (count,)
|
|
133
|
+
rows_affected = cursor.rowcount
|
|
134
|
+
if rows_affected < 0:
|
|
135
|
+
try:
|
|
136
|
+
fetch_result = cursor.fetchone()
|
|
137
|
+
if fetch_result and isinstance(fetch_result, (tuple, list)) and len(fetch_result) > 0:
|
|
138
|
+
rows_affected = fetch_result[0]
|
|
139
|
+
else:
|
|
140
|
+
rows_affected = 0
|
|
141
|
+
except Exception:
|
|
142
|
+
rows_affected = 1
|
|
143
|
+
|
|
144
|
+
return SQLResult(
|
|
145
|
+
statement=statement,
|
|
146
|
+
data=[],
|
|
147
|
+
rows_affected=rows_affected,
|
|
148
|
+
operation_type=self._determine_operation_type(statement),
|
|
149
|
+
metadata={"status_message": "OK"},
|
|
150
|
+
)
|
|
127
151
|
|
|
128
152
|
def _execute_many(
|
|
129
153
|
self, sql: str, param_list: Any, connection: Optional["DuckDBConnection"] = None, **kwargs: Any
|
|
130
|
-
) ->
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
# DuckDB
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
154
|
+
) -> SQLResult[RowT]:
|
|
155
|
+
# Use provided connection or driver's default connection
|
|
156
|
+
conn = connection if connection is not None else self._connection(None)
|
|
157
|
+
|
|
158
|
+
with managed_transaction_sync(conn, auto_commit=True) as txn_conn:
|
|
159
|
+
# Normalize parameter list using consolidated utility
|
|
160
|
+
normalized_param_list = normalize_parameter_sequence(param_list)
|
|
161
|
+
final_param_list = normalized_param_list or []
|
|
162
|
+
|
|
163
|
+
# DuckDB throws an error if executemany is called with empty parameter list
|
|
164
|
+
if not final_param_list:
|
|
165
|
+
return SQLResult(
|
|
166
|
+
statement=SQL(sql, _dialect=self.dialect),
|
|
167
|
+
data=[],
|
|
168
|
+
rows_affected=0,
|
|
169
|
+
operation_type="EXECUTE",
|
|
170
|
+
metadata={"status_message": "OK"},
|
|
171
|
+
)
|
|
172
|
+
|
|
173
|
+
with self._get_cursor(txn_conn) as cursor:
|
|
174
|
+
cursor.executemany(sql, final_param_list)
|
|
175
|
+
# DuckDB returns -1 for rowcount on DML operations
|
|
176
|
+
# For executemany, fetchone() only returns the count from the last operation,
|
|
177
|
+
# so use parameter list length as the most accurate estimate
|
|
178
|
+
rows_affected = cursor.rowcount if cursor.rowcount >= 0 else len(final_param_list)
|
|
179
|
+
return SQLResult(
|
|
180
|
+
statement=SQL(sql, _dialect=self.dialect),
|
|
181
|
+
data=[],
|
|
182
|
+
rows_affected=rows_affected,
|
|
183
|
+
operation_type="EXECUTE",
|
|
184
|
+
metadata={"status_message": "OK"},
|
|
185
|
+
)
|
|
144
186
|
|
|
145
187
|
def _execute_script(
|
|
146
188
|
self, script: str, connection: Optional["DuckDBConnection"] = None, **kwargs: Any
|
|
147
|
-
) ->
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
cursor.execute(script)
|
|
151
|
-
|
|
152
|
-
return {
|
|
153
|
-
"statements_executed": -1,
|
|
154
|
-
"status_message": "Script executed successfully.",
|
|
155
|
-
"description": "The script was sent to the database.",
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
def _wrap_select_result(
|
|
159
|
-
self, statement: SQL, result: "SelectResultDict", schema_type: Optional[type[ModelDTOT]] = None, **kwargs: Any
|
|
160
|
-
) -> Union[SQLResult[ModelDTOT], SQLResult[RowT]]:
|
|
161
|
-
fetched_tuples = result["data"]
|
|
162
|
-
column_names = result["column_names"]
|
|
163
|
-
rows_affected = result["rows_affected"]
|
|
164
|
-
|
|
165
|
-
rows_as_dicts: list[dict[str, Any]] = [dict(zip(column_names, row)) for row in fetched_tuples]
|
|
166
|
-
|
|
167
|
-
logger.debug("Query returned %d rows", len(rows_as_dicts))
|
|
168
|
-
|
|
169
|
-
if schema_type:
|
|
170
|
-
converted_data = self.to_schema(data=rows_as_dicts, schema_type=schema_type)
|
|
171
|
-
return SQLResult[ModelDTOT](
|
|
172
|
-
statement=statement,
|
|
173
|
-
data=list(converted_data),
|
|
174
|
-
column_names=column_names,
|
|
175
|
-
rows_affected=rows_affected,
|
|
176
|
-
operation_type="SELECT",
|
|
177
|
-
)
|
|
189
|
+
) -> SQLResult[RowT]:
|
|
190
|
+
# Use provided connection or driver's default connection
|
|
191
|
+
conn = connection if connection is not None else self._connection(None)
|
|
178
192
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
column_names=column_names,
|
|
183
|
-
rows_affected=rows_affected,
|
|
184
|
-
operation_type="SELECT",
|
|
185
|
-
)
|
|
193
|
+
with managed_transaction_sync(conn, auto_commit=True) as txn_conn:
|
|
194
|
+
with self._get_cursor(txn_conn) as cursor:
|
|
195
|
+
cursor.execute(script)
|
|
186
196
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
) -> SQLResult[RowT]:
|
|
190
|
-
operation_type = "UNKNOWN"
|
|
191
|
-
if statement.expression:
|
|
192
|
-
operation_type = str(statement.expression.key).upper()
|
|
193
|
-
|
|
194
|
-
if "statements_executed" in result:
|
|
195
|
-
script_result = cast("ScriptResultDict", result)
|
|
196
|
-
return SQLResult[RowT](
|
|
197
|
-
statement=statement,
|
|
197
|
+
return SQLResult(
|
|
198
|
+
statement=SQL(script, _dialect=self.dialect).as_script(),
|
|
198
199
|
data=[],
|
|
199
200
|
rows_affected=0,
|
|
200
|
-
operation_type=
|
|
201
|
-
metadata={
|
|
201
|
+
operation_type="SCRIPT",
|
|
202
|
+
metadata={
|
|
203
|
+
"status_message": "Script executed successfully.",
|
|
204
|
+
"description": "The script was sent to the database.",
|
|
205
|
+
},
|
|
206
|
+
total_statements=-1,
|
|
207
|
+
successful_statements=-1,
|
|
202
208
|
)
|
|
203
209
|
|
|
204
|
-
dml_result = cast("DMLResultDict", result)
|
|
205
|
-
rows_affected = dml_result.get("rows_affected", -1)
|
|
206
|
-
status_message = dml_result.get("status_message", "")
|
|
207
|
-
return SQLResult[RowT](
|
|
208
|
-
statement=statement,
|
|
209
|
-
data=[],
|
|
210
|
-
rows_affected=rows_affected,
|
|
211
|
-
operation_type=operation_type,
|
|
212
|
-
metadata={"status_message": status_message},
|
|
213
|
-
)
|
|
214
|
-
|
|
215
210
|
# ============================================================================
|
|
216
211
|
# DuckDB Native Arrow Support
|
|
217
212
|
# ============================================================================
|
|
@@ -353,7 +348,11 @@ class DuckDBDriver(
|
|
|
353
348
|
rows = [{col: arrow_dict[col][i] for col in column_names} for i in range(num_rows)]
|
|
354
349
|
|
|
355
350
|
return SQLResult[dict[str, Any]](
|
|
356
|
-
statement=SQL(query
|
|
351
|
+
statement=SQL(query, _dialect=self.dialect),
|
|
352
|
+
data=rows,
|
|
353
|
+
column_names=column_names,
|
|
354
|
+
rows_affected=num_rows,
|
|
355
|
+
operation_type="SELECT",
|
|
357
356
|
)
|
|
358
357
|
|
|
359
358
|
def _write_parquet_native(
|
|
@@ -381,6 +380,10 @@ class DuckDBDriver(
|
|
|
381
380
|
with contextlib.suppress(Exception):
|
|
382
381
|
conn.unregister(temp_name)
|
|
383
382
|
|
|
383
|
+
def _connection(self, connection: Optional["DuckDBConnection"] = None) -> "DuckDBConnection":
|
|
384
|
+
"""Get the connection to use for the operation."""
|
|
385
|
+
return connection or self.connection
|
|
386
|
+
|
|
384
387
|
def _ingest_arrow_table(self, table: "ArrowTable", table_name: str, mode: str = "create", **options: Any) -> int:
|
|
385
388
|
"""DuckDB-optimized Arrow table ingestion using native registration."""
|
|
386
389
|
self._ensure_pyarrow_installed()
|
|
@@ -409,7 +412,7 @@ class DuckDBDriver(
|
|
|
409
412
|
msg = f"Unsupported mode: {mode}"
|
|
410
413
|
raise ValueError(msg)
|
|
411
414
|
|
|
412
|
-
result = self.execute(SQL(sql_expr.sql(dialect=self.dialect)))
|
|
415
|
+
result = self.execute(SQL(sql_expr.sql(dialect=self.dialect), _dialect=self.dialect))
|
|
413
416
|
return result.rows_affected or table.num_rows
|
|
414
417
|
finally:
|
|
415
418
|
with contextlib.suppress(Exception):
|
|
@@ -4,7 +4,6 @@ import contextlib
|
|
|
4
4
|
import logging
|
|
5
5
|
from collections.abc import AsyncGenerator
|
|
6
6
|
from contextlib import asynccontextmanager
|
|
7
|
-
from dataclasses import replace
|
|
8
7
|
from typing import TYPE_CHECKING, Any, ClassVar, Optional, cast
|
|
9
8
|
|
|
10
9
|
import oracledb
|
|
@@ -293,15 +292,16 @@ class OracleSyncConfig(SyncDatabaseConfig[OracleSyncConnection, "ConnectionPool"
|
|
|
293
292
|
An OracleSyncDriver instance.
|
|
294
293
|
"""
|
|
295
294
|
with self.provide_connection(*args, **kwargs) as conn:
|
|
296
|
-
# Create statement config with parameter style info if not already set
|
|
297
295
|
statement_config = self.statement_config
|
|
296
|
+
# Inject parameter style info if not already set
|
|
298
297
|
if statement_config.allowed_parameter_styles is None:
|
|
298
|
+
from dataclasses import replace
|
|
299
|
+
|
|
299
300
|
statement_config = replace(
|
|
300
301
|
statement_config,
|
|
301
302
|
allowed_parameter_styles=self.supported_parameter_styles,
|
|
302
303
|
target_parameter_style=self.preferred_parameter_style,
|
|
303
304
|
)
|
|
304
|
-
|
|
305
305
|
driver = self.driver_type(connection=conn, config=statement_config)
|
|
306
306
|
yield driver
|
|
307
307
|
|
|
@@ -315,6 +315,19 @@ class OracleSyncConfig(SyncDatabaseConfig[OracleSyncConnection, "ConnectionPool"
|
|
|
315
315
|
self.pool_instance = self.create_pool()
|
|
316
316
|
return self.pool_instance
|
|
317
317
|
|
|
318
|
+
def get_signature_namespace(self) -> "dict[str, type[Any]]":
|
|
319
|
+
"""Get the signature namespace for OracleDB types.
|
|
320
|
+
|
|
321
|
+
This provides all OracleDB-specific types that Litestar needs to recognize
|
|
322
|
+
to avoid serialization attempts.
|
|
323
|
+
|
|
324
|
+
Returns:
|
|
325
|
+
Dictionary mapping type names to types.
|
|
326
|
+
"""
|
|
327
|
+
namespace = super().get_signature_namespace()
|
|
328
|
+
namespace.update({"OracleSyncConnection": OracleSyncConnection, "OracleAsyncConnection": OracleAsyncConnection})
|
|
329
|
+
return namespace
|
|
330
|
+
|
|
318
331
|
@property
|
|
319
332
|
def connection_config_dict(self) -> dict[str, Any]:
|
|
320
333
|
"""Return the connection configuration as a dict for Oracle operations.
|
|
@@ -602,15 +615,16 @@ class OracleAsyncConfig(AsyncDatabaseConfig[OracleAsyncConnection, "AsyncConnect
|
|
|
602
615
|
An OracleAsyncDriver instance.
|
|
603
616
|
"""
|
|
604
617
|
async with self.provide_connection(*args, **kwargs) as conn:
|
|
605
|
-
# Create statement config with parameter style info if not already set
|
|
606
618
|
statement_config = self.statement_config
|
|
619
|
+
# Inject parameter style info if not already set
|
|
607
620
|
if statement_config.allowed_parameter_styles is None:
|
|
621
|
+
from dataclasses import replace
|
|
622
|
+
|
|
608
623
|
statement_config = replace(
|
|
609
624
|
statement_config,
|
|
610
625
|
allowed_parameter_styles=self.supported_parameter_styles,
|
|
611
626
|
target_parameter_style=self.preferred_parameter_style,
|
|
612
627
|
)
|
|
613
|
-
|
|
614
628
|
driver = self.driver_type(connection=conn, config=statement_config)
|
|
615
629
|
yield driver
|
|
616
630
|
|
|
@@ -623,3 +637,16 @@ class OracleAsyncConfig(AsyncDatabaseConfig[OracleAsyncConnection, "AsyncConnect
|
|
|
623
637
|
if not self.pool_instance:
|
|
624
638
|
self.pool_instance = await self.create_pool()
|
|
625
639
|
return self.pool_instance
|
|
640
|
+
|
|
641
|
+
def get_signature_namespace(self) -> "dict[str, type[Any]]":
|
|
642
|
+
"""Get the signature namespace for OracleDB async types.
|
|
643
|
+
|
|
644
|
+
This provides all OracleDB async-specific types that Litestar needs to recognize
|
|
645
|
+
to avoid serialization attempts.
|
|
646
|
+
|
|
647
|
+
Returns:
|
|
648
|
+
Dictionary mapping type names to types.
|
|
649
|
+
"""
|
|
650
|
+
namespace = super().get_signature_namespace()
|
|
651
|
+
namespace.update({"OracleSyncConnection": OracleSyncConnection, "OracleAsyncConnection": OracleAsyncConnection})
|
|
652
|
+
return namespace
|