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.

Files changed (113) hide show
  1. sqlspec/_sql.py +21 -180
  2. sqlspec/adapters/adbc/config.py +10 -12
  3. sqlspec/adapters/adbc/driver.py +120 -118
  4. sqlspec/adapters/aiosqlite/config.py +16 -3
  5. sqlspec/adapters/aiosqlite/driver.py +100 -130
  6. sqlspec/adapters/asyncmy/config.py +17 -4
  7. sqlspec/adapters/asyncmy/driver.py +123 -135
  8. sqlspec/adapters/asyncpg/config.py +17 -29
  9. sqlspec/adapters/asyncpg/driver.py +98 -140
  10. sqlspec/adapters/bigquery/config.py +4 -5
  11. sqlspec/adapters/bigquery/driver.py +125 -167
  12. sqlspec/adapters/duckdb/config.py +3 -6
  13. sqlspec/adapters/duckdb/driver.py +114 -111
  14. sqlspec/adapters/oracledb/config.py +32 -5
  15. sqlspec/adapters/oracledb/driver.py +242 -259
  16. sqlspec/adapters/psqlpy/config.py +18 -9
  17. sqlspec/adapters/psqlpy/driver.py +118 -93
  18. sqlspec/adapters/psycopg/config.py +44 -31
  19. sqlspec/adapters/psycopg/driver.py +283 -236
  20. sqlspec/adapters/sqlite/config.py +3 -3
  21. sqlspec/adapters/sqlite/driver.py +103 -97
  22. sqlspec/config.py +0 -4
  23. sqlspec/driver/_async.py +89 -98
  24. sqlspec/driver/_common.py +52 -17
  25. sqlspec/driver/_sync.py +81 -105
  26. sqlspec/driver/connection.py +207 -0
  27. sqlspec/driver/mixins/_csv_writer.py +91 -0
  28. sqlspec/driver/mixins/_pipeline.py +38 -49
  29. sqlspec/driver/mixins/_result_utils.py +27 -9
  30. sqlspec/driver/mixins/_storage.py +67 -181
  31. sqlspec/driver/mixins/_type_coercion.py +3 -4
  32. sqlspec/driver/parameters.py +138 -0
  33. sqlspec/exceptions.py +10 -2
  34. sqlspec/extensions/aiosql/adapter.py +0 -10
  35. sqlspec/extensions/litestar/handlers.py +0 -1
  36. sqlspec/extensions/litestar/plugin.py +0 -3
  37. sqlspec/extensions/litestar/providers.py +0 -14
  38. sqlspec/loader.py +25 -90
  39. sqlspec/protocols.py +542 -0
  40. sqlspec/service/__init__.py +3 -2
  41. sqlspec/service/_util.py +147 -0
  42. sqlspec/service/base.py +1116 -9
  43. sqlspec/statement/builder/__init__.py +42 -32
  44. sqlspec/statement/builder/_ddl_utils.py +0 -10
  45. sqlspec/statement/builder/_parsing_utils.py +10 -4
  46. sqlspec/statement/builder/base.py +67 -22
  47. sqlspec/statement/builder/column.py +283 -0
  48. sqlspec/statement/builder/ddl.py +91 -67
  49. sqlspec/statement/builder/delete.py +23 -7
  50. sqlspec/statement/builder/insert.py +29 -15
  51. sqlspec/statement/builder/merge.py +4 -4
  52. sqlspec/statement/builder/mixins/_aggregate_functions.py +113 -14
  53. sqlspec/statement/builder/mixins/_common_table_expr.py +0 -1
  54. sqlspec/statement/builder/mixins/_delete_from.py +1 -1
  55. sqlspec/statement/builder/mixins/_from.py +10 -8
  56. sqlspec/statement/builder/mixins/_group_by.py +0 -1
  57. sqlspec/statement/builder/mixins/_insert_from_select.py +0 -1
  58. sqlspec/statement/builder/mixins/_insert_values.py +0 -2
  59. sqlspec/statement/builder/mixins/_join.py +20 -13
  60. sqlspec/statement/builder/mixins/_limit_offset.py +3 -3
  61. sqlspec/statement/builder/mixins/_merge_clauses.py +3 -4
  62. sqlspec/statement/builder/mixins/_order_by.py +2 -2
  63. sqlspec/statement/builder/mixins/_pivot.py +4 -7
  64. sqlspec/statement/builder/mixins/_select_columns.py +6 -5
  65. sqlspec/statement/builder/mixins/_unpivot.py +6 -9
  66. sqlspec/statement/builder/mixins/_update_from.py +2 -1
  67. sqlspec/statement/builder/mixins/_update_set.py +11 -8
  68. sqlspec/statement/builder/mixins/_where.py +61 -34
  69. sqlspec/statement/builder/select.py +32 -17
  70. sqlspec/statement/builder/update.py +25 -11
  71. sqlspec/statement/filters.py +39 -14
  72. sqlspec/statement/parameter_manager.py +220 -0
  73. sqlspec/statement/parameters.py +210 -79
  74. sqlspec/statement/pipelines/__init__.py +166 -23
  75. sqlspec/statement/pipelines/analyzers/_analyzer.py +21 -20
  76. sqlspec/statement/pipelines/context.py +35 -39
  77. sqlspec/statement/pipelines/transformers/__init__.py +2 -3
  78. sqlspec/statement/pipelines/transformers/_expression_simplifier.py +19 -187
  79. sqlspec/statement/pipelines/transformers/_literal_parameterizer.py +628 -58
  80. sqlspec/statement/pipelines/transformers/_remove_comments_and_hints.py +76 -0
  81. sqlspec/statement/pipelines/validators/_dml_safety.py +33 -18
  82. sqlspec/statement/pipelines/validators/_parameter_style.py +87 -14
  83. sqlspec/statement/pipelines/validators/_performance.py +38 -23
  84. sqlspec/statement/pipelines/validators/_security.py +39 -62
  85. sqlspec/statement/result.py +37 -129
  86. sqlspec/statement/splitter.py +0 -12
  87. sqlspec/statement/sql.py +863 -391
  88. sqlspec/statement/sql_compiler.py +140 -0
  89. sqlspec/storage/__init__.py +10 -2
  90. sqlspec/storage/backends/fsspec.py +53 -8
  91. sqlspec/storage/backends/obstore.py +15 -19
  92. sqlspec/storage/capabilities.py +101 -0
  93. sqlspec/storage/registry.py +56 -83
  94. sqlspec/typing.py +6 -434
  95. sqlspec/utils/cached_property.py +25 -0
  96. sqlspec/utils/correlation.py +0 -2
  97. sqlspec/utils/logging.py +0 -6
  98. sqlspec/utils/sync_tools.py +0 -4
  99. sqlspec/utils/text.py +0 -5
  100. sqlspec/utils/type_guards.py +892 -0
  101. {sqlspec-0.12.2.dist-info → sqlspec-0.13.1.dist-info}/METADATA +1 -1
  102. sqlspec-0.13.1.dist-info/RECORD +150 -0
  103. sqlspec/statement/builder/protocols.py +0 -20
  104. sqlspec/statement/pipelines/base.py +0 -315
  105. sqlspec/statement/pipelines/result_types.py +0 -41
  106. sqlspec/statement/pipelines/transformers/_remove_comments.py +0 -66
  107. sqlspec/statement/pipelines/transformers/_remove_hints.py +0 -81
  108. sqlspec/statement/pipelines/validators/base.py +0 -67
  109. sqlspec/storage/protocol.py +0 -173
  110. sqlspec-0.12.2.dist-info/RECORD +0 -145
  111. {sqlspec-0.12.2.dist-info → sqlspec-0.13.1.dist-info}/WHEEL +0 -0
  112. {sqlspec-0.12.2.dist-info → sqlspec-0.13.1.dist-info}/licenses/LICENSE +0 -0
  113. {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, cast
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, DMLResultDict, ScriptResultDict, SelectResultDict, SQLResult
22
+ from sqlspec.statement.result import ArrowResult, SQLResult
21
23
  from sqlspec.statement.sql import SQL, SQLConfig
22
- from sqlspec.typing import ArrowTable, DictRow, ModelDTOT, RowT
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
- ) -> "Union[SelectResultDict, DMLResultDict, ScriptResultDict]":
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
- ) -> "Union[SelectResultDict, DMLResultDict]":
102
- conn = self._connection(connection)
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
- if self.returns_rows(statement.expression):
105
- result = conn.execute(sql, parameters or [])
106
- fetched_data = result.fetchall()
107
- column_names = [col[0] for col in result.description or []]
108
- return {"data": fetched_data, "column_names": column_names, "rows_affected": len(fetched_data)}
109
-
110
- with self._get_cursor(conn) as cursor:
111
- cursor.execute(sql, parameters or [])
112
- # DuckDB returns -1 for rowcount on DML operations
113
- # However, fetchone() returns the actual affected row count as (count,)
114
- rows_affected = cursor.rowcount
115
- if rows_affected < 0:
116
- try:
117
- # Get actual affected row count from fetchone()
118
- fetch_result = cursor.fetchone()
119
- if fetch_result and isinstance(fetch_result, (tuple, list)) and len(fetch_result) > 0:
120
- rows_affected = fetch_result[0]
121
- else:
122
- rows_affected = 0
123
- except Exception:
124
- # Fallback to 1 if fetchone fails
125
- rows_affected = 1
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
- ) -> "DMLResultDict":
131
- conn = self._connection(connection)
132
- param_list = param_list or []
133
-
134
- # DuckDB throws an error if executemany is called with empty parameter list
135
- if not param_list:
136
- return {"rows_affected": 0}
137
- with self._get_cursor(conn) as cursor:
138
- cursor.executemany(sql, param_list)
139
- # DuckDB returns -1 for rowcount on DML operations
140
- # For executemany, fetchone() only returns the count from the last operation,
141
- # so use parameter list length as the most accurate estimate
142
- rows_affected = cursor.rowcount if cursor.rowcount >= 0 else len(param_list)
143
- return {"rows_affected": rows_affected}
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
- ) -> "ScriptResultDict":
148
- conn = self._connection(connection)
149
- with self._get_cursor(conn) as cursor:
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
- return SQLResult[RowT](
180
- statement=statement,
181
- data=rows_as_dicts,
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
- def _wrap_execute_result(
188
- self, statement: SQL, result: "Union[DMLResultDict, ScriptResultDict]", **kwargs: Any
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=operation_type or "SCRIPT",
201
- metadata={"status_message": script_result.get("status_message", "")},
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), data=rows, column_names=column_names, rows_affected=num_rows, operation_type="SELECT"
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