sqlspec 0.10.1__py3-none-any.whl → 0.11.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.

@@ -1,14 +1,22 @@
1
+ import logging
1
2
  from contextlib import asynccontextmanager, contextmanager
2
3
  from typing import TYPE_CHECKING, Any, Optional, Union, cast, overload
3
4
 
4
5
  from oracledb import AsyncConnection, AsyncCursor, Connection, Cursor
5
6
 
6
7
  from sqlspec.base import AsyncDriverAdapterProtocol, SyncDriverAdapterProtocol
7
- from sqlspec.mixins import AsyncArrowBulkOperationsMixin, SQLTranslatorMixin, SyncArrowBulkOperationsMixin
8
+ from sqlspec.filters import StatementFilter
9
+ from sqlspec.mixins import (
10
+ AsyncArrowBulkOperationsMixin,
11
+ ResultConverter,
12
+ SQLTranslatorMixin,
13
+ SyncArrowBulkOperationsMixin,
14
+ )
15
+ from sqlspec.statement import SQLStatement
8
16
  from sqlspec.typing import ArrowTable, StatementParameterType, T
9
17
 
10
18
  if TYPE_CHECKING:
11
- from collections.abc import AsyncGenerator, Generator, Sequence
19
+ from collections.abc import AsyncGenerator, Generator, Mapping, Sequence
12
20
 
13
21
  from sqlspec.typing import ModelDTOT
14
22
 
@@ -17,16 +25,70 @@ __all__ = ("OracleAsyncConnection", "OracleAsyncDriver", "OracleSyncConnection",
17
25
  OracleSyncConnection = Connection
18
26
  OracleAsyncConnection = AsyncConnection
19
27
 
28
+ logger = logging.getLogger("sqlspec")
29
+
30
+
31
+ class OracleDriverBase:
32
+ """Base class for Oracle drivers with common functionality."""
33
+
34
+ dialect: str = "oracle"
35
+
36
+ def _process_sql_params(
37
+ self,
38
+ sql: str,
39
+ parameters: "Optional[StatementParameterType]" = None,
40
+ *filters: "StatementFilter",
41
+ **kwargs: Any,
42
+ ) -> "tuple[str, Optional[Union[tuple[Any, ...], dict[str, Any]]]]":
43
+ """Process SQL and parameters using SQLStatement with dialect support.
44
+
45
+ Args:
46
+ sql: The SQL statement to process.
47
+ parameters: The parameters to bind to the statement.
48
+ *filters: Statement filters to apply.
49
+ **kwargs: Additional keyword arguments.
50
+
51
+ Returns:
52
+ A tuple of (sql, parameters) ready for execution.
53
+ """
54
+ data_params_for_statement: Optional[Union[Mapping[str, Any], Sequence[Any]]] = None
55
+ combined_filters_list: list[StatementFilter] = list(filters)
56
+
57
+ if parameters is not None:
58
+ if isinstance(parameters, StatementFilter):
59
+ combined_filters_list.insert(0, parameters)
60
+ else:
61
+ data_params_for_statement = parameters
62
+ if data_params_for_statement is not None and not isinstance(data_params_for_statement, (list, tuple, dict)):
63
+ data_params_for_statement = (data_params_for_statement,)
64
+
65
+ if isinstance(data_params_for_statement, dict) and not data_params_for_statement and not kwargs:
66
+ return sql, None
67
+
68
+ statement = SQLStatement(sql, data_params_for_statement, kwargs=kwargs, dialect=self.dialect)
69
+ for filter_obj in combined_filters_list:
70
+ statement = statement.apply_filter(filter_obj)
71
+
72
+ processed_sql, processed_params, _ = statement.process()
73
+ if processed_params is None:
74
+ return processed_sql, None
75
+ if isinstance(processed_params, dict):
76
+ return processed_sql, processed_params
77
+ if isinstance(processed_params, (list, tuple)):
78
+ return processed_sql, tuple(processed_params)
79
+ return processed_sql, (processed_params,) # type: ignore[unreachable]
80
+
20
81
 
21
82
  class OracleSyncDriver(
83
+ OracleDriverBase,
22
84
  SyncArrowBulkOperationsMixin["OracleSyncConnection"],
23
85
  SQLTranslatorMixin["OracleSyncConnection"],
24
86
  SyncDriverAdapterProtocol["OracleSyncConnection"],
87
+ ResultConverter,
25
88
  ):
26
89
  """Oracle Sync Driver Adapter."""
27
90
 
28
91
  connection: "OracleSyncConnection"
29
- dialect: str = "oracle"
30
92
 
31
93
  def __init__(self, connection: "OracleSyncConnection") -> None:
32
94
  self.connection = connection
@@ -46,8 +108,7 @@ class OracleSyncDriver(
46
108
  self,
47
109
  sql: str,
48
110
  parameters: "Optional[StatementParameterType]" = None,
49
- /,
50
- *,
111
+ *filters: "StatementFilter",
51
112
  connection: "Optional[OracleSyncConnection]" = None,
52
113
  schema_type: None = None,
53
114
  **kwargs: Any,
@@ -57,8 +118,7 @@ class OracleSyncDriver(
57
118
  self,
58
119
  sql: str,
59
120
  parameters: "Optional[StatementParameterType]" = None,
60
- /,
61
- *,
121
+ *filters: "StatementFilter",
62
122
  connection: "Optional[OracleSyncConnection]" = None,
63
123
  schema_type: "type[ModelDTOT]",
64
124
  **kwargs: Any,
@@ -67,8 +127,7 @@ class OracleSyncDriver(
67
127
  self,
68
128
  sql: str,
69
129
  parameters: "Optional[StatementParameterType]" = None,
70
- /,
71
- *,
130
+ *filters: "StatementFilter",
72
131
  connection: "Optional[OracleSyncConnection]" = None,
73
132
  schema_type: "Optional[type[ModelDTOT]]" = None,
74
133
  **kwargs: Any,
@@ -78,6 +137,7 @@ class OracleSyncDriver(
78
137
  Args:
79
138
  sql: The SQL query string.
80
139
  parameters: The parameters for the query (dict, tuple, list, or None).
140
+ *filters: Statement filters to apply.
81
141
  connection: Optional connection override.
82
142
  schema_type: Optional schema class for the result.
83
143
  **kwargs: Additional keyword arguments to merge with parameters if parameters is a dict.
@@ -86,27 +146,23 @@ class OracleSyncDriver(
86
146
  List of row data as either model instances or dictionaries.
87
147
  """
88
148
  connection = self._connection(connection)
89
- sql, parameters = self._process_sql_params(sql, parameters, **kwargs)
149
+ sql, parameters = self._process_sql_params(sql, parameters, *filters, **kwargs)
90
150
  with self._with_cursor(connection) as cursor:
91
151
  cursor.execute(sql, parameters) # pyright: ignore[reportUnknownMemberType]
92
152
  results = cursor.fetchall() # pyright: ignore[reportUnknownMemberType, reportUnknownVariableType]
93
153
  if not results:
94
154
  return []
95
- # Get column names
155
+ # Get column names from description
96
156
  column_names = [col[0] for col in cursor.description or []] # pyright: ignore[reportUnknownMemberType,reportUnknownVariableType]
97
157
 
98
- if schema_type:
99
- return [cast("ModelDTOT", schema_type(**dict(zip(column_names, row)))) for row in results] # pyright: ignore
100
-
101
- return [dict(zip(column_names, row)) for row in results] # pyright: ignore
158
+ return self.to_schema([dict(zip(column_names, row)) for row in results], schema_type=schema_type)
102
159
 
103
160
  @overload
104
161
  def select_one(
105
162
  self,
106
163
  sql: str,
107
164
  parameters: "Optional[StatementParameterType]" = None,
108
- /,
109
- *,
165
+ *filters: "StatementFilter",
110
166
  connection: "Optional[OracleSyncConnection]" = None,
111
167
  schema_type: None = None,
112
168
  **kwargs: Any,
@@ -116,8 +172,7 @@ class OracleSyncDriver(
116
172
  self,
117
173
  sql: str,
118
174
  parameters: "Optional[StatementParameterType]" = None,
119
- /,
120
- *,
175
+ *filters: "StatementFilter",
121
176
  connection: "Optional[OracleSyncConnection]" = None,
122
177
  schema_type: "type[ModelDTOT]",
123
178
  **kwargs: Any,
@@ -126,8 +181,7 @@ class OracleSyncDriver(
126
181
  self,
127
182
  sql: str,
128
183
  parameters: "Optional[StatementParameterType]" = None,
129
- /,
130
- *,
184
+ *filters: "StatementFilter",
131
185
  connection: "Optional[OracleSyncConnection]" = None,
132
186
  schema_type: "Optional[type[ModelDTOT]]" = None,
133
187
  **kwargs: Any,
@@ -137,6 +191,7 @@ class OracleSyncDriver(
137
191
  Args:
138
192
  sql: The SQL query string.
139
193
  parameters: The parameters for the query (dict, tuple, list, or None).
194
+ *filters: Statement filters to apply.
140
195
  connection: Optional connection override.
141
196
  schema_type: Optional schema class for the result.
142
197
  **kwargs: Additional keyword arguments to merge with parameters if parameters is a dict.
@@ -145,7 +200,7 @@ class OracleSyncDriver(
145
200
  The first row of the query results.
146
201
  """
147
202
  connection = self._connection(connection)
148
- sql, parameters = self._process_sql_params(sql, parameters, **kwargs)
203
+ sql, parameters = self._process_sql_params(sql, parameters, *filters, **kwargs)
149
204
 
150
205
  with self._with_cursor(connection) as cursor:
151
206
  cursor.execute(sql, parameters) # pyright: ignore[reportUnknownMemberType]
@@ -155,18 +210,14 @@ class OracleSyncDriver(
155
210
  # Get column names
156
211
  column_names = [col[0] for col in cursor.description or []] # pyright: ignore[reportUnknownMemberType,reportUnknownVariableType]
157
212
 
158
- if schema_type is not None:
159
- return cast("ModelDTOT", schema_type(**dict(zip(column_names, result)))) # pyright: ignore[reportUnknownArgumentType]
160
- # Always return dictionaries
161
- return dict(zip(column_names, result)) # pyright: ignore[reportUnknownArgumentType,reportUnknownVariableType]
213
+ return self.to_schema(dict(zip(column_names, result)), schema_type=schema_type)
162
214
 
163
215
  @overload
164
216
  def select_one_or_none(
165
217
  self,
166
218
  sql: str,
167
219
  parameters: "Optional[StatementParameterType]" = None,
168
- /,
169
- *,
220
+ *filters: "StatementFilter",
170
221
  connection: "Optional[OracleSyncConnection]" = None,
171
222
  schema_type: None = None,
172
223
  **kwargs: Any,
@@ -176,8 +227,7 @@ class OracleSyncDriver(
176
227
  self,
177
228
  sql: str,
178
229
  parameters: "Optional[StatementParameterType]" = None,
179
- /,
180
- *,
230
+ *filters: "StatementFilter",
181
231
  connection: "Optional[OracleSyncConnection]" = None,
182
232
  schema_type: "type[ModelDTOT]",
183
233
  **kwargs: Any,
@@ -186,42 +236,44 @@ class OracleSyncDriver(
186
236
  self,
187
237
  sql: str,
188
238
  parameters: "Optional[StatementParameterType]" = None,
189
- /,
190
- *,
239
+ *filters: "StatementFilter",
191
240
  connection: "Optional[OracleSyncConnection]" = None,
192
241
  schema_type: "Optional[type[ModelDTOT]]" = None,
193
242
  **kwargs: Any,
194
243
  ) -> "Optional[Union[ModelDTOT, dict[str, Any]]]":
195
- """Fetch one row from the database.
244
+ """Fetch one row from the database or return None if no rows found.
245
+
246
+ Args:
247
+ sql: The SQL query string.
248
+ parameters: The parameters for the query (dict, tuple, list, or None).
249
+ *filters: Statement filters to apply.
250
+ connection: Optional connection override.
251
+ schema_type: Optional schema class for the result.
252
+ **kwargs: Additional keyword arguments to merge with parameters if parameters is a dict.
196
253
 
197
254
  Returns:
198
- The first row of the query results.
255
+ The first row of the query results, or None if no results found.
199
256
  """
200
257
  connection = self._connection(connection)
201
- sql, parameters = self._process_sql_params(sql, parameters, **kwargs)
258
+ sql, parameters = self._process_sql_params(sql, parameters, *filters, **kwargs)
202
259
 
203
260
  with self._with_cursor(connection) as cursor:
204
261
  cursor.execute(sql, parameters) # pyright: ignore[reportUnknownMemberType]
205
262
  result = cursor.fetchone() # pyright: ignore[reportUnknownMemberType, reportUnknownVariableType]
206
-
207
263
  if result is None:
208
264
  return None
209
265
 
210
266
  # Get column names
211
267
  column_names = [col[0] for col in cursor.description or []] # pyright: ignore[reportUnknownMemberType,reportUnknownVariableType]
212
268
 
213
- if schema_type is not None:
214
- return cast("ModelDTOT", schema_type(**dict(zip(column_names, result)))) # pyright: ignore[reportUnknownArgumentType]
215
- # Always return dictionaries
216
- return dict(zip(column_names, result)) # pyright: ignore[reportUnknownArgumentType,reportUnknownVariableType]
269
+ return self.to_schema(dict(zip(column_names, result)), schema_type=schema_type)
217
270
 
218
271
  @overload
219
272
  def select_value(
220
273
  self,
221
274
  sql: str,
222
275
  parameters: "Optional[StatementParameterType]" = None,
223
- /,
224
- *,
276
+ *filters: "StatementFilter",
225
277
  connection: "Optional[OracleSyncConnection]" = None,
226
278
  schema_type: None = None,
227
279
  **kwargs: Any,
@@ -231,8 +283,7 @@ class OracleSyncDriver(
231
283
  self,
232
284
  sql: str,
233
285
  parameters: "Optional[StatementParameterType]" = None,
234
- /,
235
- *,
286
+ *filters: "StatementFilter",
236
287
  connection: "Optional[OracleSyncConnection]" = None,
237
288
  schema_type: "type[T]",
238
289
  **kwargs: Any,
@@ -241,19 +292,26 @@ class OracleSyncDriver(
241
292
  self,
242
293
  sql: str,
243
294
  parameters: "Optional[StatementParameterType]" = None,
244
- /,
245
- *,
295
+ *filters: "StatementFilter",
246
296
  connection: "Optional[OracleSyncConnection]" = None,
247
297
  schema_type: "Optional[type[T]]" = None,
248
298
  **kwargs: Any,
249
299
  ) -> "Union[T, Any]":
250
300
  """Fetch a single value from the database.
251
301
 
302
+ Args:
303
+ sql: The SQL query string.
304
+ parameters: The parameters for the query (dict, tuple, list, or None).
305
+ *filters: Statement filters to apply.
306
+ connection: Optional connection override.
307
+ schema_type: Optional type to convert the result to.
308
+ **kwargs: Additional keyword arguments to merge with parameters if parameters is a dict.
309
+
252
310
  Returns:
253
- The first value from the first row of results, or None if no results.
311
+ The first value of the first row of the query results.
254
312
  """
255
313
  connection = self._connection(connection)
256
- sql, parameters = self._process_sql_params(sql, parameters, **kwargs)
314
+ sql, parameters = self._process_sql_params(sql, parameters, *filters, **kwargs)
257
315
 
258
316
  with self._with_cursor(connection) as cursor:
259
317
  cursor.execute(sql, parameters) # pyright: ignore[reportUnknownMemberType]
@@ -269,8 +327,7 @@ class OracleSyncDriver(
269
327
  self,
270
328
  sql: str,
271
329
  parameters: "Optional[StatementParameterType]" = None,
272
- /,
273
- *,
330
+ *filters: "StatementFilter",
274
331
  connection: "Optional[OracleSyncConnection]" = None,
275
332
  schema_type: None = None,
276
333
  **kwargs: Any,
@@ -280,8 +337,7 @@ class OracleSyncDriver(
280
337
  self,
281
338
  sql: str,
282
339
  parameters: "Optional[StatementParameterType]" = None,
283
- /,
284
- *,
340
+ *filters: "StatementFilter",
285
341
  connection: "Optional[OracleSyncConnection]" = None,
286
342
  schema_type: "type[T]",
287
343
  **kwargs: Any,
@@ -290,24 +346,30 @@ class OracleSyncDriver(
290
346
  self,
291
347
  sql: str,
292
348
  parameters: "Optional[StatementParameterType]" = None,
293
- /,
294
- *,
349
+ *filters: "StatementFilter",
295
350
  connection: "Optional[OracleSyncConnection]" = None,
296
351
  schema_type: "Optional[type[T]]" = None,
297
352
  **kwargs: Any,
298
353
  ) -> "Optional[Union[T, Any]]":
299
- """Fetch a single value from the database.
354
+ """Fetch a single value or None if not found.
355
+
356
+ Args:
357
+ sql: The SQL query string.
358
+ parameters: The parameters for the query (dict, tuple, list, or None).
359
+ *filters: Statement filters to apply.
360
+ connection: Optional connection override.
361
+ schema_type: Optional type to convert the result to.
362
+ **kwargs: Additional keyword arguments to merge with parameters if parameters is a dict.
300
363
 
301
364
  Returns:
302
- The first value from the first row of results, or None if no results.
365
+ The first value of the first row of the query results, or None if no results found.
303
366
  """
304
367
  connection = self._connection(connection)
305
- sql, parameters = self._process_sql_params(sql, parameters, **kwargs)
368
+ sql, parameters = self._process_sql_params(sql, parameters, *filters, **kwargs)
306
369
 
307
370
  with self._with_cursor(connection) as cursor:
308
371
  cursor.execute(sql, parameters) # pyright: ignore[reportUnknownMemberType]
309
372
  result = cursor.fetchone() # pyright: ignore[reportUnknownMemberType, reportUnknownVariableType]
310
-
311
373
  if result is None:
312
374
  return None
313
375
 
@@ -319,30 +381,35 @@ class OracleSyncDriver(
319
381
  self,
320
382
  sql: str,
321
383
  parameters: "Optional[StatementParameterType]" = None,
322
- /,
323
- *,
384
+ *filters: "StatementFilter",
324
385
  connection: "Optional[OracleSyncConnection]" = None,
325
386
  **kwargs: Any,
326
387
  ) -> int:
327
- """Insert, update, or delete data from the database.
388
+ """Execute an insert, update, or delete statement.
389
+
390
+ Args:
391
+ sql: The SQL statement to execute.
392
+ parameters: The parameters for the statement (dict, tuple, list, or None).
393
+ *filters: Statement filters to apply.
394
+ connection: Optional connection override.
395
+ **kwargs: Additional keyword arguments to merge with parameters if parameters is a dict.
328
396
 
329
397
  Returns:
330
- Row count affected by the operation.
398
+ The number of rows affected by the statement.
331
399
  """
332
400
  connection = self._connection(connection)
333
- sql, parameters = self._process_sql_params(sql, parameters, **kwargs)
401
+ sql, parameters = self._process_sql_params(sql, parameters, *filters, **kwargs)
334
402
 
335
403
  with self._with_cursor(connection) as cursor:
336
404
  cursor.execute(sql, parameters) # pyright: ignore[reportUnknownMemberType]
337
- return cursor.rowcount # pyright: ignore[reportUnknownMemberType]
405
+ return cursor.rowcount # pyright: ignore[reportUnknownMemberType, reportUnknownVariableType]
338
406
 
339
407
  @overload
340
408
  def insert_update_delete_returning(
341
409
  self,
342
410
  sql: str,
343
411
  parameters: "Optional[StatementParameterType]" = None,
344
- /,
345
- *,
412
+ *filters: "StatementFilter",
346
413
  connection: "Optional[OracleSyncConnection]" = None,
347
414
  schema_type: None = None,
348
415
  **kwargs: Any,
@@ -352,8 +419,7 @@ class OracleSyncDriver(
352
419
  self,
353
420
  sql: str,
354
421
  parameters: "Optional[StatementParameterType]" = None,
355
- /,
356
- *,
422
+ *filters: "StatementFilter",
357
423
  connection: "Optional[OracleSyncConnection]" = None,
358
424
  schema_type: "type[ModelDTOT]",
359
425
  **kwargs: Any,
@@ -362,8 +428,7 @@ class OracleSyncDriver(
362
428
  self,
363
429
  sql: str,
364
430
  parameters: "Optional[StatementParameterType]" = None,
365
- /,
366
- *,
431
+ *filters: "StatementFilter",
367
432
  connection: "Optional[OracleSyncConnection]" = None,
368
433
  schema_type: "Optional[type[ModelDTOT]]" = None,
369
434
  **kwargs: Any,
@@ -374,7 +439,7 @@ class OracleSyncDriver(
374
439
  The first row of results.
375
440
  """
376
441
  connection = self._connection(connection)
377
- sql, parameters = self._process_sql_params(sql, parameters, **kwargs)
442
+ sql, parameters = self._process_sql_params(sql, parameters, *filters, **kwargs)
378
443
 
379
444
  with self._with_cursor(connection) as cursor:
380
445
  cursor.execute(sql, parameters) # pyright: ignore[reportUnknownMemberType]
@@ -395,15 +460,19 @@ class OracleSyncDriver(
395
460
  self,
396
461
  sql: str,
397
462
  parameters: "Optional[StatementParameterType]" = None,
398
- /,
399
- *,
400
463
  connection: "Optional[OracleSyncConnection]" = None,
401
464
  **kwargs: Any,
402
465
  ) -> str:
403
- """Execute a script.
466
+ """Execute a SQL script.
467
+
468
+ Args:
469
+ sql: The SQL script to execute.
470
+ parameters: The parameters for the script (dict, tuple, list, or None).
471
+ connection: Optional connection override.
472
+ **kwargs: Additional keyword arguments to merge with parameters if parameters is a dict.
404
473
 
405
474
  Returns:
406
- Status message for the operation.
475
+ A success message.
407
476
  """
408
477
  connection = self._connection(connection)
409
478
  sql, parameters = self._process_sql_params(sql, parameters, **kwargs)
@@ -416,8 +485,7 @@ class OracleSyncDriver(
416
485
  self,
417
486
  sql: str,
418
487
  parameters: "Optional[StatementParameterType]" = None,
419
- /,
420
- *,
488
+ *filters: "StatementFilter",
421
489
  connection: "Optional[OracleSyncConnection]" = None,
422
490
  **kwargs: Any,
423
491
  ) -> "ArrowTable": # pyright: ignore[reportUnknownVariableType]
@@ -428,20 +496,32 @@ class OracleSyncDriver(
428
496
  """
429
497
 
430
498
  connection = self._connection(connection)
431
- sql, parameters = self._process_sql_params(sql, parameters, **kwargs)
499
+ sql, parameters = self._process_sql_params(sql, parameters, *filters, **kwargs)
432
500
  results = connection.fetch_df_all(sql, parameters)
433
501
  return cast("ArrowTable", ArrowTable.from_arrays(arrays=results.column_arrays(), names=results.column_names())) # pyright: ignore
434
502
 
503
+ def _connection(self, connection: "Optional[OracleSyncConnection]" = None) -> "OracleSyncConnection":
504
+ """Get the connection to use for the operation.
505
+
506
+ Args:
507
+ connection: Optional connection to use.
508
+
509
+ Returns:
510
+ The connection to use.
511
+ """
512
+ return connection or self.connection
513
+
435
514
 
436
515
  class OracleAsyncDriver(
516
+ OracleDriverBase,
437
517
  AsyncArrowBulkOperationsMixin["OracleAsyncConnection"],
438
518
  SQLTranslatorMixin["OracleAsyncConnection"],
439
519
  AsyncDriverAdapterProtocol["OracleAsyncConnection"],
520
+ ResultConverter,
440
521
  ):
441
522
  """Oracle Async Driver Adapter."""
442
523
 
443
524
  connection: "OracleAsyncConnection"
444
- dialect: str = "oracle"
445
525
 
446
526
  def __init__(self, connection: "OracleAsyncConnection") -> None:
447
527
  self.connection = connection
@@ -461,8 +541,7 @@ class OracleAsyncDriver(
461
541
  self,
462
542
  sql: str,
463
543
  parameters: "Optional[StatementParameterType]" = None,
464
- /,
465
- *,
544
+ *filters: "StatementFilter",
466
545
  connection: "Optional[OracleAsyncConnection]" = None,
467
546
  schema_type: None = None,
468
547
  **kwargs: Any,
@@ -472,8 +551,7 @@ class OracleAsyncDriver(
472
551
  self,
473
552
  sql: str,
474
553
  parameters: "Optional[StatementParameterType]" = None,
475
- /,
476
- *,
554
+ *filters: "StatementFilter",
477
555
  connection: "Optional[OracleAsyncConnection]" = None,
478
556
  schema_type: "type[ModelDTOT]",
479
557
  **kwargs: Any,
@@ -482,40 +560,43 @@ class OracleAsyncDriver(
482
560
  self,
483
561
  sql: str,
484
562
  parameters: "Optional[StatementParameterType]" = None,
485
- /,
486
- *,
563
+ *filters: "StatementFilter",
487
564
  connection: "Optional[OracleAsyncConnection]" = None,
488
565
  schema_type: "Optional[type[ModelDTOT]]" = None,
489
566
  **kwargs: Any,
490
567
  ) -> "Sequence[Union[ModelDTOT, dict[str, Any]]]":
491
568
  """Fetch data from the database.
492
569
 
570
+ Args:
571
+ sql: The SQL query string.
572
+ parameters: The parameters for the query (dict, tuple, list, or None).
573
+ *filters: Statement filters to apply.
574
+ connection: Optional connection override.
575
+ schema_type: Optional schema class for the result.
576
+ **kwargs: Additional keyword arguments to merge with parameters if parameters is a dict.
577
+
493
578
  Returns:
494
579
  List of row data as either model instances or dictionaries.
495
580
  """
496
581
  connection = self._connection(connection)
497
- sql, parameters = self._process_sql_params(sql, parameters, **kwargs)
582
+ sql, parameters = self._process_sql_params(sql, parameters, *filters, **kwargs)
498
583
 
499
584
  async with self._with_cursor(connection) as cursor:
500
585
  await cursor.execute(sql, parameters) # pyright: ignore[reportUnknownMemberType]
501
586
  results = await cursor.fetchall() # pyright: ignore[reportUnknownMemberType, reportUnknownVariableType]
502
587
  if not results:
503
588
  return []
504
- # Get column names
589
+ # Get column names from description
505
590
  column_names = [col[0] for col in cursor.description or []] # pyright: ignore[reportUnknownMemberType,reportUnknownVariableType]
506
591
 
507
- if schema_type:
508
- return [cast("ModelDTOT", schema_type(**dict(zip(column_names, row)))) for row in results] # pyright: ignore
509
-
510
- return [dict(zip(column_names, row)) for row in results] # pyright: ignore
592
+ return self.to_schema([dict(zip(column_names, row)) for row in results], schema_type=schema_type)
511
593
 
512
594
  @overload
513
595
  async def select_one(
514
596
  self,
515
597
  sql: str,
516
598
  parameters: "Optional[StatementParameterType]" = None,
517
- /,
518
- *,
599
+ *filters: "StatementFilter",
519
600
  connection: "Optional[OracleAsyncConnection]" = None,
520
601
  schema_type: None = None,
521
602
  **kwargs: Any,
@@ -525,8 +606,7 @@ class OracleAsyncDriver(
525
606
  self,
526
607
  sql: str,
527
608
  parameters: "Optional[StatementParameterType]" = None,
528
- /,
529
- *,
609
+ *filters: "StatementFilter",
530
610
  connection: "Optional[OracleAsyncConnection]" = None,
531
611
  schema_type: "type[ModelDTOT]",
532
612
  **kwargs: Any,
@@ -535,39 +615,41 @@ class OracleAsyncDriver(
535
615
  self,
536
616
  sql: str,
537
617
  parameters: "Optional[StatementParameterType]" = None,
538
- /,
539
- *,
618
+ *filters: "StatementFilter",
540
619
  connection: "Optional[OracleAsyncConnection]" = None,
541
620
  schema_type: "Optional[type[ModelDTOT]]" = None,
542
621
  **kwargs: Any,
543
622
  ) -> "Union[ModelDTOT, dict[str, Any]]":
544
623
  """Fetch one row from the database.
545
624
 
625
+ Args:
626
+ sql: The SQL query string.
627
+ parameters: The parameters for the query (dict, tuple, list, or None).
628
+ *filters: Statement filters to apply.
629
+ connection: Optional connection override.
630
+ schema_type: Optional schema class for the result.
631
+ **kwargs: Additional keyword arguments to merge with parameters if parameters is a dict.
632
+
546
633
  Returns:
547
634
  The first row of the query results.
548
635
  """
549
636
  connection = self._connection(connection)
550
- sql, parameters = self._process_sql_params(sql, parameters, **kwargs)
637
+ sql, parameters = self._process_sql_params(sql, parameters, *filters, **kwargs)
551
638
 
552
639
  async with self._with_cursor(connection) as cursor:
553
640
  await cursor.execute(sql, parameters) # pyright: ignore[reportUnknownMemberType]
554
641
  result = await cursor.fetchone() # pyright: ignore[reportUnknownMemberType, reportUnknownVariableType]
555
642
  result = self.check_not_found(result) # pyright: ignore[reportUnknownArgumentType]
556
- # Get column names
557
643
  column_names = [col[0] for col in cursor.description or []] # pyright: ignore[reportUnknownMemberType,reportUnknownVariableType]
558
644
 
559
- if schema_type is not None:
560
- return cast("ModelDTOT", schema_type(**dict(zip(column_names, result)))) # pyright: ignore[reportUnknownArgumentType]
561
- # Always return dictionaries
562
- return dict(zip(column_names, result)) # pyright: ignore[reportUnknownArgumentType,reportUnknownVariableType]
645
+ return self.to_schema(dict(zip(column_names, result)), schema_type=schema_type)
563
646
 
564
647
  @overload
565
648
  async def select_one_or_none(
566
649
  self,
567
650
  sql: str,
568
651
  parameters: "Optional[StatementParameterType]" = None,
569
- /,
570
- *,
652
+ *filters: "StatementFilter",
571
653
  connection: "Optional[OracleAsyncConnection]" = None,
572
654
  schema_type: None = None,
573
655
  **kwargs: Any,
@@ -577,8 +659,7 @@ class OracleAsyncDriver(
577
659
  self,
578
660
  sql: str,
579
661
  parameters: "Optional[StatementParameterType]" = None,
580
- /,
581
- *,
662
+ *filters: "StatementFilter",
582
663
  connection: "Optional[OracleAsyncConnection]" = None,
583
664
  schema_type: "type[ModelDTOT]",
584
665
  **kwargs: Any,
@@ -587,42 +668,41 @@ class OracleAsyncDriver(
587
668
  self,
588
669
  sql: str,
589
670
  parameters: "Optional[StatementParameterType]" = None,
590
- /,
591
- *,
671
+ *filters: "StatementFilter",
592
672
  connection: "Optional[OracleAsyncConnection]" = None,
593
673
  schema_type: "Optional[type[ModelDTOT]]" = None,
594
674
  **kwargs: Any,
595
675
  ) -> "Optional[Union[ModelDTOT, dict[str, Any]]]":
596
- """Fetch one row from the database.
676
+ """Fetch one row from the database or return None if no rows found.
677
+
678
+ Args:
679
+ sql: The SQL query string.
680
+ parameters: The parameters for the query (dict, tuple, list, or None).
681
+ *filters: Statement filters to apply.
682
+ connection: Optional connection override.
683
+ schema_type: Optional schema class for the result.
684
+ **kwargs: Additional keyword arguments to merge with parameters if parameters is a dict.
597
685
 
598
686
  Returns:
599
- The first row of the query results.
687
+ The first row of the query results, or None if no results found.
600
688
  """
601
689
  connection = self._connection(connection)
602
- sql, parameters = self._process_sql_params(sql, parameters, **kwargs)
690
+ sql, parameters = self._process_sql_params(sql, parameters, *filters, **kwargs)
603
691
 
604
692
  async with self._with_cursor(connection) as cursor:
605
693
  await cursor.execute(sql, parameters) # pyright: ignore[reportUnknownMemberType]
606
694
  result = await cursor.fetchone() # pyright: ignore[reportUnknownMemberType, reportUnknownVariableType]
607
-
608
695
  if result is None:
609
696
  return None
610
-
611
- # Get column names
612
697
  column_names = [col[0] for col in cursor.description or []] # pyright: ignore[reportUnknownMemberType,reportUnknownVariableType]
613
-
614
- if schema_type is not None:
615
- return cast("ModelDTOT", schema_type(**dict(zip(column_names, result)))) # pyright: ignore[reportUnknownArgumentType]
616
- # Always return dictionaries
617
- return dict(zip(column_names, result)) # pyright: ignore[reportUnknownArgumentType,reportUnknownVariableType]
698
+ return self.to_schema(dict(zip(column_names, result)), schema_type=schema_type)
618
699
 
619
700
  @overload
620
701
  async def select_value(
621
702
  self,
622
703
  sql: str,
623
704
  parameters: "Optional[StatementParameterType]" = None,
624
- /,
625
- *,
705
+ *filters: "StatementFilter",
626
706
  connection: "Optional[OracleAsyncConnection]" = None,
627
707
  schema_type: None = None,
628
708
  **kwargs: Any,
@@ -632,8 +712,7 @@ class OracleAsyncDriver(
632
712
  self,
633
713
  sql: str,
634
714
  parameters: "Optional[StatementParameterType]" = None,
635
- /,
636
- *,
715
+ *filters: "StatementFilter",
637
716
  connection: "Optional[OracleAsyncConnection]" = None,
638
717
  schema_type: "type[T]",
639
718
  **kwargs: Any,
@@ -642,19 +721,26 @@ class OracleAsyncDriver(
642
721
  self,
643
722
  sql: str,
644
723
  parameters: "Optional[StatementParameterType]" = None,
645
- /,
646
- *,
724
+ *filters: "StatementFilter",
647
725
  connection: "Optional[OracleAsyncConnection]" = None,
648
726
  schema_type: "Optional[type[T]]" = None,
649
727
  **kwargs: Any,
650
728
  ) -> "Union[T, Any]":
651
729
  """Fetch a single value from the database.
652
730
 
731
+ Args:
732
+ sql: The SQL query string.
733
+ parameters: The parameters for the query (dict, tuple, list, or None).
734
+ *filters: Statement filters to apply.
735
+ connection: Optional connection override.
736
+ schema_type: Optional type to convert the result to.
737
+ **kwargs: Additional keyword arguments to merge with parameters if parameters is a dict.
738
+
653
739
  Returns:
654
- The first value from the first row of results, or None if no results.
740
+ The first value of the first row of the query results.
655
741
  """
656
742
  connection = self._connection(connection)
657
- sql, parameters = self._process_sql_params(sql, parameters, **kwargs)
743
+ sql, parameters = self._process_sql_params(sql, parameters, *filters, **kwargs)
658
744
 
659
745
  async with self._with_cursor(connection) as cursor:
660
746
  await cursor.execute(sql, parameters) # pyright: ignore[reportUnknownMemberType]
@@ -670,8 +756,7 @@ class OracleAsyncDriver(
670
756
  self,
671
757
  sql: str,
672
758
  parameters: "Optional[StatementParameterType]" = None,
673
- /,
674
- *,
759
+ *filters: "StatementFilter",
675
760
  connection: "Optional[OracleAsyncConnection]" = None,
676
761
  schema_type: None = None,
677
762
  **kwargs: Any,
@@ -681,8 +766,7 @@ class OracleAsyncDriver(
681
766
  self,
682
767
  sql: str,
683
768
  parameters: "Optional[StatementParameterType]" = None,
684
- /,
685
- *,
769
+ *filters: "StatementFilter",
686
770
  connection: "Optional[OracleAsyncConnection]" = None,
687
771
  schema_type: "type[T]",
688
772
  **kwargs: Any,
@@ -691,24 +775,30 @@ class OracleAsyncDriver(
691
775
  self,
692
776
  sql: str,
693
777
  parameters: "Optional[StatementParameterType]" = None,
694
- /,
695
- *,
778
+ *filters: "StatementFilter",
696
779
  connection: "Optional[OracleAsyncConnection]" = None,
697
780
  schema_type: "Optional[type[T]]" = None,
698
781
  **kwargs: Any,
699
782
  ) -> "Optional[Union[T, Any]]":
700
- """Fetch a single value from the database.
783
+ """Fetch a single value or None if not found.
784
+
785
+ Args:
786
+ sql: The SQL query string.
787
+ parameters: The parameters for the query (dict, tuple, list, or None).
788
+ *filters: Statement filters to apply.
789
+ connection: Optional connection override.
790
+ schema_type: Optional type to convert the result to.
791
+ **kwargs: Additional keyword arguments to merge with parameters if parameters is a dict.
701
792
 
702
793
  Returns:
703
- The first value from the first row of results, or None if no results.
794
+ The first value of the first row of the query results, or None if no results found.
704
795
  """
705
796
  connection = self._connection(connection)
706
- sql, parameters = self._process_sql_params(sql, parameters, **kwargs)
797
+ sql, parameters = self._process_sql_params(sql, parameters, *filters, **kwargs)
707
798
 
708
799
  async with self._with_cursor(connection) as cursor:
709
800
  await cursor.execute(sql, parameters) # pyright: ignore[reportUnknownMemberType]
710
801
  result = await cursor.fetchone() # pyright: ignore[reportUnknownMemberType, reportUnknownVariableType]
711
-
712
802
  if result is None:
713
803
  return None
714
804
 
@@ -720,30 +810,35 @@ class OracleAsyncDriver(
720
810
  self,
721
811
  sql: str,
722
812
  parameters: "Optional[StatementParameterType]" = None,
723
- /,
724
- *,
813
+ *filters: "StatementFilter",
725
814
  connection: "Optional[OracleAsyncConnection]" = None,
726
815
  **kwargs: Any,
727
816
  ) -> int:
728
817
  """Insert, update, or delete data from the database.
729
818
 
819
+ Args:
820
+ sql: The SQL statement to execute.
821
+ parameters: The parameters for the statement (dict, tuple, list, or None).
822
+ *filters: Statement filters to apply.
823
+ connection: Optional connection override.
824
+ **kwargs: Additional keyword arguments to merge with parameters if parameters is a dict.
825
+
730
826
  Returns:
731
827
  Row count affected by the operation.
732
828
  """
733
829
  connection = self._connection(connection)
734
- sql, parameters = self._process_sql_params(sql, parameters, **kwargs)
830
+ sql, parameters = self._process_sql_params(sql, parameters, *filters, **kwargs)
735
831
 
736
832
  async with self._with_cursor(connection) as cursor:
737
833
  await cursor.execute(sql, parameters) # pyright: ignore[reportUnknownMemberType]
738
- return cursor.rowcount # pyright: ignore[reportUnknownMemberType]
834
+ return cursor.rowcount # pyright: ignore[reportUnknownMemberType,reportUnknownVariableType]
739
835
 
740
836
  @overload
741
837
  async def insert_update_delete_returning(
742
838
  self,
743
839
  sql: str,
744
840
  parameters: "Optional[StatementParameterType]" = None,
745
- /,
746
- *,
841
+ *filters: "StatementFilter",
747
842
  connection: "Optional[OracleAsyncConnection]" = None,
748
843
  schema_type: None = None,
749
844
  **kwargs: Any,
@@ -753,8 +848,7 @@ class OracleAsyncDriver(
753
848
  self,
754
849
  sql: str,
755
850
  parameters: "Optional[StatementParameterType]" = None,
756
- /,
757
- *,
851
+ *filters: "StatementFilter",
758
852
  connection: "Optional[OracleAsyncConnection]" = None,
759
853
  schema_type: "type[ModelDTOT]",
760
854
  **kwargs: Any,
@@ -763,24 +857,30 @@ class OracleAsyncDriver(
763
857
  self,
764
858
  sql: str,
765
859
  parameters: "Optional[StatementParameterType]" = None,
766
- /,
767
- *,
860
+ *filters: "StatementFilter",
768
861
  connection: "Optional[OracleAsyncConnection]" = None,
769
862
  schema_type: "Optional[type[ModelDTOT]]" = None,
770
863
  **kwargs: Any,
771
864
  ) -> "Optional[Union[dict[str, Any], ModelDTOT]]":
772
865
  """Insert, update, or delete data from the database and return result.
773
866
 
867
+ Args:
868
+ sql: The SQL statement with RETURNING clause.
869
+ parameters: The parameters for the statement (dict, tuple, list, or None).
870
+ *filters: Statement filters to apply.
871
+ connection: Optional connection override.
872
+ schema_type: Optional schema class for the result.
873
+ **kwargs: Additional keyword arguments to merge with parameters if parameters is a dict.
874
+
774
875
  Returns:
775
- The first row of results.
876
+ The returned row data, as either a model instance or dictionary.
776
877
  """
777
878
  connection = self._connection(connection)
778
- sql, parameters = self._process_sql_params(sql, parameters, **kwargs)
879
+ sql, parameters = self._process_sql_params(sql, parameters, *filters, **kwargs)
779
880
 
780
881
  async with self._with_cursor(connection) as cursor:
781
882
  await cursor.execute(sql, parameters) # pyright: ignore[reportUnknownMemberType]
782
883
  result = await cursor.fetchone() # pyright: ignore[reportUnknownMemberType, reportUnknownVariableType]
783
-
784
884
  if result is None:
785
885
  return None
786
886
 
@@ -789,22 +889,25 @@ class OracleAsyncDriver(
789
889
 
790
890
  if schema_type is not None:
791
891
  return cast("ModelDTOT", schema_type(**dict(zip(column_names, result)))) # pyright: ignore[reportUnknownArgumentType]
792
- # Always return dictionaries
793
892
  return dict(zip(column_names, result)) # pyright: ignore[reportUnknownArgumentType,reportUnknownVariableType]
794
893
 
795
894
  async def execute_script(
796
895
  self,
797
896
  sql: str,
798
897
  parameters: "Optional[StatementParameterType]" = None,
799
- /,
800
- *,
801
898
  connection: "Optional[OracleAsyncConnection]" = None,
802
899
  **kwargs: Any,
803
900
  ) -> str:
804
- """Execute a script.
901
+ """Execute a SQL script.
902
+
903
+ Args:
904
+ sql: The SQL script to execute.
905
+ parameters: The parameters for the script (dict, tuple, list, or None).
906
+ connection: Optional connection override.
907
+ **kwargs: Additional keyword arguments to merge with parameters if parameters is a dict.
805
908
 
806
909
  Returns:
807
- Status message for the operation.
910
+ A success message.
808
911
  """
809
912
  connection = self._connection(connection)
810
913
  sql, parameters = self._process_sql_params(sql, parameters, **kwargs)
@@ -813,12 +916,11 @@ class OracleAsyncDriver(
813
916
  await cursor.execute(sql, parameters) # pyright: ignore[reportUnknownMemberType]
814
917
  return str(cursor.rowcount) # pyright: ignore[reportUnknownMemberType]
815
918
 
816
- async def select_arrow( # pyright: ignore[reportUnknownParameterType]
919
+ async def select_arrow(
817
920
  self,
818
921
  sql: str,
819
922
  parameters: "Optional[StatementParameterType]" = None,
820
- /,
821
- *,
923
+ *filters: "StatementFilter",
822
924
  connection: "Optional[OracleAsyncConnection]" = None,
823
925
  **kwargs: Any,
824
926
  ) -> "ArrowTable": # pyright: ignore[reportUnknownVariableType]
@@ -827,6 +929,7 @@ class OracleAsyncDriver(
827
929
  Args:
828
930
  sql: The SQL query string.
829
931
  parameters: Parameters for the query.
932
+ filters: Statement filters to apply.
830
933
  connection: Optional connection override.
831
934
  **kwargs: Additional keyword arguments to merge with parameters if parameters is a dict.
832
935
 
@@ -835,6 +938,17 @@ class OracleAsyncDriver(
835
938
  """
836
939
 
837
940
  connection = self._connection(connection)
838
- sql, parameters = self._process_sql_params(sql, parameters, **kwargs)
941
+ sql, parameters = self._process_sql_params(sql, parameters, *filters, **kwargs)
839
942
  results = await connection.fetch_df_all(sql, parameters)
840
943
  return ArrowTable.from_arrays(arrays=results.column_arrays(), names=results.column_names()) # pyright: ignore
944
+
945
+ def _connection(self, connection: "Optional[OracleAsyncConnection]" = None) -> "OracleAsyncConnection":
946
+ """Get the connection to use for the operation.
947
+
948
+ Args:
949
+ connection: Optional connection to use.
950
+
951
+ Returns:
952
+ The connection to use.
953
+ """
954
+ return connection or self.connection