sqlspec 0.16.0__py3-none-any.whl → 0.16.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 +448 -15
- sqlspec/builder/_base.py +77 -44
- sqlspec/builder/_column.py +0 -4
- sqlspec/builder/_ddl.py +15 -52
- sqlspec/builder/_ddl_utils.py +0 -1
- sqlspec/builder/_delete.py +4 -5
- sqlspec/builder/_insert.py +59 -44
- sqlspec/builder/_merge.py +17 -2
- sqlspec/builder/_parsing_utils.py +11 -11
- sqlspec/builder/_select.py +29 -33
- sqlspec/builder/_update.py +4 -2
- sqlspec/builder/mixins/_cte_and_set_ops.py +47 -20
- sqlspec/builder/mixins/_delete_operations.py +6 -1
- sqlspec/builder/mixins/_insert_operations.py +126 -34
- sqlspec/builder/mixins/_join_operations.py +11 -4
- sqlspec/builder/mixins/_merge_operations.py +81 -21
- sqlspec/builder/mixins/_order_limit_operations.py +15 -3
- sqlspec/builder/mixins/_pivot_operations.py +11 -2
- sqlspec/builder/mixins/_select_operations.py +12 -8
- sqlspec/builder/mixins/_update_operations.py +37 -14
- sqlspec/builder/mixins/_where_clause.py +55 -43
- sqlspec/core/cache.py +26 -28
- sqlspec/core/compiler.py +58 -37
- sqlspec/core/parameters.py +80 -52
- sqlspec/core/result.py +30 -17
- sqlspec/core/statement.py +31 -21
- sqlspec/driver/_async.py +76 -46
- sqlspec/driver/_common.py +25 -6
- sqlspec/driver/_sync.py +73 -43
- sqlspec/driver/mixins/_result_tools.py +51 -22
- sqlspec/driver/mixins/_sql_translator.py +61 -11
- sqlspec/protocols.py +7 -0
- sqlspec/utils/type_guards.py +7 -3
- {sqlspec-0.16.0.dist-info → sqlspec-0.16.1.dist-info}/METADATA +1 -1
- {sqlspec-0.16.0.dist-info → sqlspec-0.16.1.dist-info}/RECORD +39 -39
- {sqlspec-0.16.0.dist-info → sqlspec-0.16.1.dist-info}/WHEEL +0 -0
- {sqlspec-0.16.0.dist-info → sqlspec-0.16.1.dist-info}/entry_points.txt +0 -0
- {sqlspec-0.16.0.dist-info → sqlspec-0.16.1.dist-info}/licenses/LICENSE +0 -0
- {sqlspec-0.16.0.dist-info → sqlspec-0.16.1.dist-info}/licenses/NOTICE +0 -0
sqlspec/driver/_async.py
CHANGED
|
@@ -5,7 +5,7 @@ including connection management, transaction support, and result processing.
|
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
7
|
from abc import abstractmethod
|
|
8
|
-
from typing import TYPE_CHECKING, Any, Optional, Union, cast, overload
|
|
8
|
+
from typing import TYPE_CHECKING, Any, Final, NoReturn, Optional, Union, cast, overload
|
|
9
9
|
|
|
10
10
|
from sqlspec.core import SQL, Statement
|
|
11
11
|
from sqlspec.driver._common import CommonDriverAttributesMixin, ExecutionResult
|
|
@@ -20,14 +20,15 @@ if TYPE_CHECKING:
|
|
|
20
20
|
|
|
21
21
|
from sqlspec.builder import QueryBuilder
|
|
22
22
|
from sqlspec.core import SQLResult, StatementConfig, StatementFilter
|
|
23
|
-
from sqlspec.typing import ModelDTOT,
|
|
23
|
+
from sqlspec.typing import ModelDTOT, StatementParameters
|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
_LOGGER_NAME: Final[str] = "sqlspec"
|
|
26
|
+
logger = get_logger(_LOGGER_NAME)
|
|
26
27
|
|
|
27
28
|
__all__ = ("AsyncDriverAdapterBase",)
|
|
28
29
|
|
|
29
30
|
|
|
30
|
-
EMPTY_FILTERS: "list[StatementFilter]" = []
|
|
31
|
+
EMPTY_FILTERS: Final["list[StatementFilter]"] = []
|
|
31
32
|
|
|
32
33
|
|
|
33
34
|
class AsyncDriverAdapterBase(CommonDriverAttributesMixin, SQLTranslatorMixin, ToSchemaMixin):
|
|
@@ -128,12 +129,16 @@ class AsyncDriverAdapterBase(CommonDriverAttributesMixin, SQLTranslatorMixin, To
|
|
|
128
129
|
sql, prepared_parameters = self._get_compiled_sql(statement, self.statement_config)
|
|
129
130
|
statements = self.split_script_statements(sql, self.statement_config, strip_trailing_semicolon=True)
|
|
130
131
|
|
|
132
|
+
statement_count: int = len(statements)
|
|
133
|
+
successful_count: int = 0
|
|
134
|
+
|
|
131
135
|
for stmt in statements:
|
|
132
136
|
single_stmt = statement.copy(statement=stmt, parameters=prepared_parameters)
|
|
133
137
|
await self._execute_statement(cursor, single_stmt)
|
|
138
|
+
successful_count += 1
|
|
134
139
|
|
|
135
140
|
return self.create_execution_result(
|
|
136
|
-
cursor, statement_count=
|
|
141
|
+
cursor, statement_count=statement_count, successful_statements=successful_count, is_script_result=True
|
|
137
142
|
)
|
|
138
143
|
|
|
139
144
|
@abstractmethod
|
|
@@ -214,8 +219,8 @@ class AsyncDriverAdapterBase(CommonDriverAttributesMixin, SQLTranslatorMixin, To
|
|
|
214
219
|
By default, validates each statement and logs warnings for dangerous
|
|
215
220
|
operations. Use suppress_warnings=True for migrations and admin scripts.
|
|
216
221
|
"""
|
|
217
|
-
|
|
218
|
-
sql_statement = self.prepare_statement(statement, parameters, statement_config=
|
|
222
|
+
config = statement_config or self.statement_config
|
|
223
|
+
sql_statement = self.prepare_statement(statement, parameters, statement_config=config, kwargs=kwargs)
|
|
219
224
|
|
|
220
225
|
return await self.dispatch_statement_execution(statement=sql_statement.as_script(), connection=self.connection)
|
|
221
226
|
|
|
@@ -239,7 +244,7 @@ class AsyncDriverAdapterBase(CommonDriverAttributesMixin, SQLTranslatorMixin, To
|
|
|
239
244
|
schema_type: None = None,
|
|
240
245
|
statement_config: "Optional[StatementConfig]" = None,
|
|
241
246
|
**kwargs: Any,
|
|
242
|
-
) -> "
|
|
247
|
+
) -> "dict[str, Any]": ...
|
|
243
248
|
|
|
244
249
|
async def select_one(
|
|
245
250
|
self,
|
|
@@ -249,23 +254,20 @@ class AsyncDriverAdapterBase(CommonDriverAttributesMixin, SQLTranslatorMixin, To
|
|
|
249
254
|
schema_type: "Optional[type[ModelDTOT]]" = None,
|
|
250
255
|
statement_config: "Optional[StatementConfig]" = None,
|
|
251
256
|
**kwargs: Any,
|
|
252
|
-
) -> "Union[
|
|
257
|
+
) -> "Union[dict[str, Any], ModelDTOT]":
|
|
253
258
|
"""Execute a select statement and return exactly one row.
|
|
254
259
|
|
|
255
260
|
Raises an exception if no rows or more than one row is returned.
|
|
256
261
|
"""
|
|
257
262
|
result = await self.execute(statement, *parameters, statement_config=statement_config, **kwargs)
|
|
258
263
|
data = result.get_data()
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
if
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
return
|
|
266
|
-
"Union[ModelT, RowT, ModelDTOT]",
|
|
267
|
-
self.to_schema(data[0], schema_type=schema_type) if schema_type else data[0],
|
|
268
|
-
)
|
|
264
|
+
data_len: int = len(data)
|
|
265
|
+
if data_len == 0:
|
|
266
|
+
self._raise_no_rows_found()
|
|
267
|
+
if data_len > 1:
|
|
268
|
+
self._raise_expected_one_row(data_len)
|
|
269
|
+
first_row = data[0]
|
|
270
|
+
return self.to_schema(first_row, schema_type=schema_type) if schema_type else first_row
|
|
269
271
|
|
|
270
272
|
@overload
|
|
271
273
|
async def select_one_or_none(
|
|
@@ -287,7 +289,7 @@ class AsyncDriverAdapterBase(CommonDriverAttributesMixin, SQLTranslatorMixin, To
|
|
|
287
289
|
schema_type: None = None,
|
|
288
290
|
statement_config: "Optional[StatementConfig]" = None,
|
|
289
291
|
**kwargs: Any,
|
|
290
|
-
) -> "Optional[
|
|
292
|
+
) -> "Optional[dict[str, Any]]": ...
|
|
291
293
|
|
|
292
294
|
async def select_one_or_none(
|
|
293
295
|
self,
|
|
@@ -297,7 +299,7 @@ class AsyncDriverAdapterBase(CommonDriverAttributesMixin, SQLTranslatorMixin, To
|
|
|
297
299
|
schema_type: "Optional[type[ModelDTOT]]" = None,
|
|
298
300
|
statement_config: "Optional[StatementConfig]" = None,
|
|
299
301
|
**kwargs: Any,
|
|
300
|
-
) -> "Optional[Union[
|
|
302
|
+
) -> "Optional[Union[dict[str, Any], ModelDTOT]]":
|
|
301
303
|
"""Execute a select statement and return at most one row.
|
|
302
304
|
|
|
303
305
|
Returns None if no rows are found.
|
|
@@ -305,12 +307,16 @@ class AsyncDriverAdapterBase(CommonDriverAttributesMixin, SQLTranslatorMixin, To
|
|
|
305
307
|
"""
|
|
306
308
|
result = await self.execute(statement, *parameters, statement_config=statement_config, **kwargs)
|
|
307
309
|
data = result.get_data()
|
|
308
|
-
|
|
310
|
+
data_len: int = len(data)
|
|
311
|
+
if data_len == 0:
|
|
309
312
|
return None
|
|
310
|
-
if
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
return cast(
|
|
313
|
+
if data_len > 1:
|
|
314
|
+
self._raise_expected_at_most_one_row(data_len)
|
|
315
|
+
first_row = data[0]
|
|
316
|
+
return cast(
|
|
317
|
+
"Optional[Union[dict[str, Any], ModelDTOT]]",
|
|
318
|
+
self.to_schema(first_row, schema_type=schema_type) if schema_type else first_row,
|
|
319
|
+
)
|
|
314
320
|
|
|
315
321
|
@overload
|
|
316
322
|
async def select(
|
|
@@ -332,7 +338,8 @@ class AsyncDriverAdapterBase(CommonDriverAttributesMixin, SQLTranslatorMixin, To
|
|
|
332
338
|
schema_type: None = None,
|
|
333
339
|
statement_config: "Optional[StatementConfig]" = None,
|
|
334
340
|
**kwargs: Any,
|
|
335
|
-
) -> "list[
|
|
341
|
+
) -> "list[dict[str, Any]]": ...
|
|
342
|
+
|
|
336
343
|
async def select(
|
|
337
344
|
self,
|
|
338
345
|
statement: "Union[Statement, QueryBuilder]",
|
|
@@ -341,12 +348,11 @@ class AsyncDriverAdapterBase(CommonDriverAttributesMixin, SQLTranslatorMixin, To
|
|
|
341
348
|
schema_type: "Optional[type[ModelDTOT]]" = None,
|
|
342
349
|
statement_config: "Optional[StatementConfig]" = None,
|
|
343
350
|
**kwargs: Any,
|
|
344
|
-
) -> "Union[list[
|
|
351
|
+
) -> "Union[list[dict[str, Any]], list[ModelDTOT]]":
|
|
345
352
|
"""Execute a select statement and return all rows."""
|
|
346
353
|
result = await self.execute(statement, *parameters, statement_config=statement_config, **kwargs)
|
|
347
354
|
return cast(
|
|
348
|
-
"Union[list[
|
|
349
|
-
self.to_schema(cast("list[ModelT]", result.get_data()), schema_type=schema_type),
|
|
355
|
+
"Union[list[dict[str, Any]], list[ModelDTOT]]", self.to_schema(result.get_data(), schema_type=schema_type)
|
|
350
356
|
)
|
|
351
357
|
|
|
352
358
|
async def select_value(
|
|
@@ -366,23 +372,19 @@ class AsyncDriverAdapterBase(CommonDriverAttributesMixin, SQLTranslatorMixin, To
|
|
|
366
372
|
try:
|
|
367
373
|
row = result.one()
|
|
368
374
|
except ValueError as e:
|
|
369
|
-
|
|
370
|
-
raise NotFoundError(msg) from e
|
|
375
|
+
self._raise_no_rows_found_from_exception(e)
|
|
371
376
|
if not row:
|
|
372
|
-
|
|
373
|
-
raise NotFoundError(msg)
|
|
377
|
+
self._raise_no_rows_found()
|
|
374
378
|
if is_dict_row(row):
|
|
375
379
|
if not row:
|
|
376
|
-
|
|
377
|
-
raise ValueError(msg)
|
|
380
|
+
self._raise_row_no_columns()
|
|
378
381
|
return next(iter(row.values()))
|
|
379
382
|
if is_indexable_row(row):
|
|
380
383
|
if not row:
|
|
381
|
-
|
|
382
|
-
raise ValueError(msg)
|
|
384
|
+
self._raise_row_no_columns()
|
|
383
385
|
return row[0]
|
|
384
|
-
|
|
385
|
-
|
|
386
|
+
self._raise_unexpected_row_type(type(row))
|
|
387
|
+
return None
|
|
386
388
|
|
|
387
389
|
async def select_value_or_none(
|
|
388
390
|
self,
|
|
@@ -400,11 +402,11 @@ class AsyncDriverAdapterBase(CommonDriverAttributesMixin, SQLTranslatorMixin, To
|
|
|
400
402
|
"""
|
|
401
403
|
result = await self.execute(statement, *parameters, statement_config=statement_config, **kwargs)
|
|
402
404
|
data = result.get_data()
|
|
403
|
-
|
|
405
|
+
data_len: int = len(data)
|
|
406
|
+
if data_len == 0:
|
|
404
407
|
return None
|
|
405
|
-
if
|
|
406
|
-
|
|
407
|
-
raise ValueError(msg)
|
|
408
|
+
if data_len > 1:
|
|
409
|
+
self._raise_expected_at_most_one_row(data_len)
|
|
408
410
|
row = data[0]
|
|
409
411
|
if is_dict_row(row):
|
|
410
412
|
if not row:
|
|
@@ -412,8 +414,8 @@ class AsyncDriverAdapterBase(CommonDriverAttributesMixin, SQLTranslatorMixin, To
|
|
|
412
414
|
return next(iter(row.values()))
|
|
413
415
|
if is_indexable_row(row):
|
|
414
416
|
return row[0]
|
|
415
|
-
|
|
416
|
-
|
|
417
|
+
self._raise_cannot_extract_value_from_row_type(type(row).__name__)
|
|
418
|
+
return None
|
|
417
419
|
|
|
418
420
|
@overload
|
|
419
421
|
async def select_with_total(
|
|
@@ -470,3 +472,31 @@ class AsyncDriverAdapterBase(CommonDriverAttributesMixin, SQLTranslatorMixin, To
|
|
|
470
472
|
select_result = await self.execute(sql_statement)
|
|
471
473
|
|
|
472
474
|
return (self.to_schema(select_result.get_data(), schema_type=schema_type), count_result.scalar())
|
|
475
|
+
|
|
476
|
+
def _raise_no_rows_found(self) -> NoReturn:
|
|
477
|
+
msg = "No rows found"
|
|
478
|
+
raise NotFoundError(msg)
|
|
479
|
+
|
|
480
|
+
def _raise_no_rows_found_from_exception(self, e: ValueError) -> NoReturn:
|
|
481
|
+
msg = "No rows found"
|
|
482
|
+
raise NotFoundError(msg) from e
|
|
483
|
+
|
|
484
|
+
def _raise_expected_one_row(self, data_len: int) -> NoReturn:
|
|
485
|
+
msg = f"Expected exactly one row, found {data_len}"
|
|
486
|
+
raise ValueError(msg)
|
|
487
|
+
|
|
488
|
+
def _raise_expected_at_most_one_row(self, data_len: int) -> NoReturn:
|
|
489
|
+
msg = f"Expected at most one row, found {data_len}"
|
|
490
|
+
raise ValueError(msg)
|
|
491
|
+
|
|
492
|
+
def _raise_row_no_columns(self) -> NoReturn:
|
|
493
|
+
msg = "Row has no columns"
|
|
494
|
+
raise ValueError(msg)
|
|
495
|
+
|
|
496
|
+
def _raise_unexpected_row_type(self, row_type: type) -> NoReturn:
|
|
497
|
+
msg = f"Unexpected row type: {row_type}"
|
|
498
|
+
raise ValueError(msg)
|
|
499
|
+
|
|
500
|
+
def _raise_cannot_extract_value_from_row_type(self, type_name: str) -> NoReturn:
|
|
501
|
+
msg = f"Cannot extract value from row type {type_name}"
|
|
502
|
+
raise TypeError(msg)
|
sqlspec/driver/_common.py
CHANGED
|
@@ -17,7 +17,9 @@ from sqlspec.exceptions import ImproperConfigurationError
|
|
|
17
17
|
from sqlspec.utils.logging import get_logger
|
|
18
18
|
|
|
19
19
|
if TYPE_CHECKING:
|
|
20
|
-
from
|
|
20
|
+
from collections.abc import Sequence
|
|
21
|
+
|
|
22
|
+
from sqlspec.core.filters import FilterTypeT, StatementFilter
|
|
21
23
|
from sqlspec.typing import StatementParameters
|
|
22
24
|
|
|
23
25
|
|
|
@@ -424,10 +426,9 @@ class CommonDriverAttributesMixin:
|
|
|
424
426
|
if isinstance(parameters, dict):
|
|
425
427
|
if not parameters:
|
|
426
428
|
return []
|
|
427
|
-
if (
|
|
428
|
-
statement_config.parameter_config.supported_execution_parameter_styles
|
|
429
|
-
|
|
430
|
-
in statement_config.parameter_config.supported_execution_parameter_styles
|
|
429
|
+
if statement_config.parameter_config.supported_execution_parameter_styles and (
|
|
430
|
+
ParameterStyle.NAMED_PYFORMAT in statement_config.parameter_config.supported_execution_parameter_styles
|
|
431
|
+
or ParameterStyle.NAMED_COLON in statement_config.parameter_config.supported_execution_parameter_styles
|
|
431
432
|
):
|
|
432
433
|
return {k: apply_type_coercion(v) for k, v in parameters.items()}
|
|
433
434
|
if statement_config.parameter_config.default_parameter_style in {
|
|
@@ -577,6 +578,24 @@ class CommonDriverAttributesMixin:
|
|
|
577
578
|
|
|
578
579
|
return max(style_counts.keys(), key=lambda style: (style_counts[style], -precedence.get(style, 99)))
|
|
579
580
|
|
|
581
|
+
@staticmethod
|
|
582
|
+
def find_filter(
|
|
583
|
+
filter_type: "type[FilterTypeT]",
|
|
584
|
+
filters: "Sequence[StatementFilter | StatementParameters] | Sequence[StatementFilter]",
|
|
585
|
+
) -> "FilterTypeT | None":
|
|
586
|
+
"""Get the filter specified by filter type from the filters.
|
|
587
|
+
|
|
588
|
+
Args:
|
|
589
|
+
filter_type: The type of filter to find.
|
|
590
|
+
filters: filter types to apply to the query
|
|
591
|
+
|
|
592
|
+
Returns:
|
|
593
|
+
The match filter instance or None
|
|
594
|
+
"""
|
|
595
|
+
return next(
|
|
596
|
+
(cast("FilterTypeT | None", filter_) for filter_ in filters if isinstance(filter_, filter_type)), None
|
|
597
|
+
)
|
|
598
|
+
|
|
580
599
|
def _create_count_query(self, original_sql: "SQL") -> "SQL":
|
|
581
600
|
"""Create a COUNT query from the original SQL statement.
|
|
582
601
|
|
|
@@ -586,7 +605,7 @@ class CommonDriverAttributesMixin:
|
|
|
586
605
|
if not original_sql.expression:
|
|
587
606
|
msg = "Cannot create COUNT query from empty SQL expression"
|
|
588
607
|
raise ImproperConfigurationError(msg)
|
|
589
|
-
expr = original_sql.expression
|
|
608
|
+
expr = original_sql.expression
|
|
590
609
|
|
|
591
610
|
if isinstance(expr, exp.Select):
|
|
592
611
|
if expr.args.get("group"):
|
sqlspec/driver/_sync.py
CHANGED
|
@@ -5,7 +5,7 @@ including connection management, transaction support, and result processing.
|
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
7
|
from abc import abstractmethod
|
|
8
|
-
from typing import TYPE_CHECKING, Any, Optional, Union, cast, overload
|
|
8
|
+
from typing import TYPE_CHECKING, Any, Final, NoReturn, Optional, Union, cast, overload
|
|
9
9
|
|
|
10
10
|
from sqlspec.core import SQL
|
|
11
11
|
from sqlspec.driver._common import CommonDriverAttributesMixin, ExecutionResult
|
|
@@ -20,14 +20,15 @@ if TYPE_CHECKING:
|
|
|
20
20
|
|
|
21
21
|
from sqlspec.builder import QueryBuilder
|
|
22
22
|
from sqlspec.core import SQLResult, Statement, StatementConfig, StatementFilter
|
|
23
|
-
from sqlspec.typing import ModelDTOT,
|
|
23
|
+
from sqlspec.typing import ModelDTOT, StatementParameters
|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
_LOGGER_NAME: Final[str] = "sqlspec"
|
|
26
|
+
logger = get_logger(_LOGGER_NAME)
|
|
26
27
|
|
|
27
28
|
__all__ = ("SyncDriverAdapterBase",)
|
|
28
29
|
|
|
29
30
|
|
|
30
|
-
EMPTY_FILTERS: "list[StatementFilter]" = []
|
|
31
|
+
EMPTY_FILTERS: Final["list[StatementFilter]"] = []
|
|
31
32
|
|
|
32
33
|
|
|
33
34
|
class SyncDriverAdapterBase(CommonDriverAttributesMixin, SQLTranslatorMixin, ToSchemaMixin):
|
|
@@ -128,12 +129,16 @@ class SyncDriverAdapterBase(CommonDriverAttributesMixin, SQLTranslatorMixin, ToS
|
|
|
128
129
|
sql, prepared_parameters = self._get_compiled_sql(statement, self.statement_config)
|
|
129
130
|
statements = self.split_script_statements(sql, self.statement_config, strip_trailing_semicolon=True)
|
|
130
131
|
|
|
132
|
+
statement_count: int = len(statements)
|
|
133
|
+
successful_count: int = 0
|
|
134
|
+
|
|
131
135
|
for stmt in statements:
|
|
132
136
|
single_stmt = statement.copy(statement=stmt, parameters=prepared_parameters)
|
|
133
137
|
self._execute_statement(cursor, single_stmt)
|
|
138
|
+
successful_count += 1
|
|
134
139
|
|
|
135
140
|
return self.create_execution_result(
|
|
136
|
-
cursor, statement_count=
|
|
141
|
+
cursor, statement_count=statement_count, successful_statements=successful_count, is_script_result=True
|
|
137
142
|
)
|
|
138
143
|
|
|
139
144
|
@abstractmethod
|
|
@@ -214,8 +219,8 @@ class SyncDriverAdapterBase(CommonDriverAttributesMixin, SQLTranslatorMixin, ToS
|
|
|
214
219
|
By default, validates each statement and logs warnings for dangerous
|
|
215
220
|
operations. Use suppress_warnings=True for migrations and admin scripts.
|
|
216
221
|
"""
|
|
217
|
-
|
|
218
|
-
sql_statement = self.prepare_statement(statement, parameters, statement_config=
|
|
222
|
+
config = statement_config or self.statement_config
|
|
223
|
+
sql_statement = self.prepare_statement(statement, parameters, statement_config=config, kwargs=kwargs)
|
|
219
224
|
|
|
220
225
|
return self.dispatch_statement_execution(statement=sql_statement.as_script(), connection=self.connection)
|
|
221
226
|
|
|
@@ -239,7 +244,7 @@ class SyncDriverAdapterBase(CommonDriverAttributesMixin, SQLTranslatorMixin, ToS
|
|
|
239
244
|
schema_type: None = None,
|
|
240
245
|
statement_config: "Optional[StatementConfig]" = None,
|
|
241
246
|
**kwargs: Any,
|
|
242
|
-
) -> "
|
|
247
|
+
) -> "dict[str, Any]": ...
|
|
243
248
|
|
|
244
249
|
def select_one(
|
|
245
250
|
self,
|
|
@@ -249,23 +254,20 @@ class SyncDriverAdapterBase(CommonDriverAttributesMixin, SQLTranslatorMixin, ToS
|
|
|
249
254
|
schema_type: "Optional[type[ModelDTOT]]" = None,
|
|
250
255
|
statement_config: "Optional[StatementConfig]" = None,
|
|
251
256
|
**kwargs: Any,
|
|
252
|
-
) -> "Union[
|
|
257
|
+
) -> "Union[dict[str, Any], ModelDTOT]":
|
|
253
258
|
"""Execute a select statement and return exactly one row.
|
|
254
259
|
|
|
255
260
|
Raises an exception if no rows or more than one row is returned.
|
|
256
261
|
"""
|
|
257
262
|
result = self.execute(statement, *parameters, statement_config=statement_config, **kwargs)
|
|
258
263
|
data = result.get_data()
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
if
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
return
|
|
266
|
-
"Union[ModelT, RowT, ModelDTOT]",
|
|
267
|
-
self.to_schema(data[0], schema_type=schema_type) if schema_type else data[0],
|
|
268
|
-
)
|
|
264
|
+
data_len: int = len(data)
|
|
265
|
+
if data_len == 0:
|
|
266
|
+
self._raise_no_rows_found()
|
|
267
|
+
if data_len > 1:
|
|
268
|
+
self._raise_expected_one_row(data_len)
|
|
269
|
+
first_row = data[0]
|
|
270
|
+
return self.to_schema(first_row, schema_type=schema_type) if schema_type else first_row
|
|
269
271
|
|
|
270
272
|
@overload
|
|
271
273
|
def select_one_or_none(
|
|
@@ -287,7 +289,7 @@ class SyncDriverAdapterBase(CommonDriverAttributesMixin, SQLTranslatorMixin, ToS
|
|
|
287
289
|
schema_type: None = None,
|
|
288
290
|
statement_config: "Optional[StatementConfig]" = None,
|
|
289
291
|
**kwargs: Any,
|
|
290
|
-
) -> "Optional[
|
|
292
|
+
) -> "Optional[dict[str, Any]]": ...
|
|
291
293
|
|
|
292
294
|
def select_one_or_none(
|
|
293
295
|
self,
|
|
@@ -297,7 +299,7 @@ class SyncDriverAdapterBase(CommonDriverAttributesMixin, SQLTranslatorMixin, ToS
|
|
|
297
299
|
schema_type: "Optional[type[ModelDTOT]]" = None,
|
|
298
300
|
statement_config: "Optional[StatementConfig]" = None,
|
|
299
301
|
**kwargs: Any,
|
|
300
|
-
) -> "Optional[Union[
|
|
302
|
+
) -> "Optional[Union[dict[str, Any], ModelDTOT]]":
|
|
301
303
|
"""Execute a select statement and return at most one row.
|
|
302
304
|
|
|
303
305
|
Returns None if no rows are found.
|
|
@@ -305,12 +307,16 @@ class SyncDriverAdapterBase(CommonDriverAttributesMixin, SQLTranslatorMixin, ToS
|
|
|
305
307
|
"""
|
|
306
308
|
result = self.execute(statement, *parameters, statement_config=statement_config, **kwargs)
|
|
307
309
|
data = result.get_data()
|
|
308
|
-
|
|
310
|
+
data_len: int = len(data)
|
|
311
|
+
if data_len == 0:
|
|
309
312
|
return None
|
|
310
|
-
if
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
return cast(
|
|
313
|
+
if data_len > 1:
|
|
314
|
+
self._raise_expected_at_most_one_row(data_len)
|
|
315
|
+
first_row = data[0]
|
|
316
|
+
return cast(
|
|
317
|
+
"Optional[Union[dict[str, Any], ModelDTOT]]",
|
|
318
|
+
self.to_schema(first_row, schema_type=schema_type) if schema_type else first_row,
|
|
319
|
+
)
|
|
314
320
|
|
|
315
321
|
@overload
|
|
316
322
|
def select(
|
|
@@ -332,7 +338,7 @@ class SyncDriverAdapterBase(CommonDriverAttributesMixin, SQLTranslatorMixin, ToS
|
|
|
332
338
|
schema_type: None = None,
|
|
333
339
|
statement_config: "Optional[StatementConfig]" = None,
|
|
334
340
|
**kwargs: Any,
|
|
335
|
-
) -> "list[
|
|
341
|
+
) -> "list[dict[str, Any]]": ...
|
|
336
342
|
|
|
337
343
|
def select(
|
|
338
344
|
self,
|
|
@@ -342,12 +348,11 @@ class SyncDriverAdapterBase(CommonDriverAttributesMixin, SQLTranslatorMixin, ToS
|
|
|
342
348
|
schema_type: "Optional[type[ModelDTOT]]" = None,
|
|
343
349
|
statement_config: "Optional[StatementConfig]" = None,
|
|
344
350
|
**kwargs: Any,
|
|
345
|
-
) -> "Union[list[
|
|
351
|
+
) -> "Union[list[dict[str, Any]], list[ModelDTOT]]":
|
|
346
352
|
"""Execute a select statement and return all rows."""
|
|
347
353
|
result = self.execute(statement, *parameters, statement_config=statement_config, **kwargs)
|
|
348
354
|
return cast(
|
|
349
|
-
"Union[list[
|
|
350
|
-
self.to_schema(cast("list[ModelT]", result.get_data()), schema_type=schema_type),
|
|
355
|
+
"Union[list[dict[str, Any]], list[ModelDTOT]]", self.to_schema(result.get_data(), schema_type=schema_type)
|
|
351
356
|
)
|
|
352
357
|
|
|
353
358
|
def select_value(
|
|
@@ -367,23 +372,19 @@ class SyncDriverAdapterBase(CommonDriverAttributesMixin, SQLTranslatorMixin, ToS
|
|
|
367
372
|
try:
|
|
368
373
|
row = result.one()
|
|
369
374
|
except ValueError as e:
|
|
370
|
-
|
|
371
|
-
raise NotFoundError(msg) from e
|
|
375
|
+
self._raise_no_rows_found_from_exception(e)
|
|
372
376
|
if not row:
|
|
373
|
-
|
|
374
|
-
raise NotFoundError(msg)
|
|
377
|
+
self._raise_no_rows_found()
|
|
375
378
|
if is_dict_row(row):
|
|
376
379
|
if not row:
|
|
377
|
-
|
|
378
|
-
raise ValueError(msg)
|
|
380
|
+
self._raise_row_no_columns()
|
|
379
381
|
return next(iter(row.values()))
|
|
380
382
|
if is_indexable_row(row):
|
|
381
383
|
if not row:
|
|
382
|
-
|
|
383
|
-
raise ValueError(msg)
|
|
384
|
+
self._raise_row_no_columns()
|
|
384
385
|
return row[0]
|
|
385
|
-
|
|
386
|
-
|
|
386
|
+
self._raise_unexpected_row_type(type(row))
|
|
387
|
+
return None
|
|
387
388
|
|
|
388
389
|
def select_value_or_none(
|
|
389
390
|
self,
|
|
@@ -401,10 +402,11 @@ class SyncDriverAdapterBase(CommonDriverAttributesMixin, SQLTranslatorMixin, ToS
|
|
|
401
402
|
"""
|
|
402
403
|
result = self.execute(statement, *parameters, statement_config=statement_config, **kwargs)
|
|
403
404
|
data = result.get_data()
|
|
404
|
-
|
|
405
|
+
data_len: int = len(data)
|
|
406
|
+
if data_len == 0:
|
|
405
407
|
return None
|
|
406
|
-
if
|
|
407
|
-
msg = f"Expected at most one row, found {
|
|
408
|
+
if data_len > 1:
|
|
409
|
+
msg = f"Expected at most one row, found {data_len}"
|
|
408
410
|
raise ValueError(msg)
|
|
409
411
|
row = data[0]
|
|
410
412
|
if isinstance(row, dict):
|
|
@@ -471,3 +473,31 @@ class SyncDriverAdapterBase(CommonDriverAttributesMixin, SQLTranslatorMixin, ToS
|
|
|
471
473
|
select_result = self.execute(sql_statement)
|
|
472
474
|
|
|
473
475
|
return (self.to_schema(select_result.get_data(), schema_type=schema_type), count_result.scalar())
|
|
476
|
+
|
|
477
|
+
def _raise_no_rows_found(self) -> NoReturn:
|
|
478
|
+
msg = "No rows found"
|
|
479
|
+
raise NotFoundError(msg)
|
|
480
|
+
|
|
481
|
+
def _raise_no_rows_found_from_exception(self, e: ValueError) -> NoReturn:
|
|
482
|
+
msg = "No rows found"
|
|
483
|
+
raise NotFoundError(msg) from e
|
|
484
|
+
|
|
485
|
+
def _raise_expected_one_row(self, data_len: int) -> NoReturn:
|
|
486
|
+
msg = f"Expected exactly one row, found {data_len}"
|
|
487
|
+
raise ValueError(msg)
|
|
488
|
+
|
|
489
|
+
def _raise_expected_at_most_one_row(self, data_len: int) -> NoReturn:
|
|
490
|
+
msg = f"Expected at most one row, found {data_len}"
|
|
491
|
+
raise ValueError(msg)
|
|
492
|
+
|
|
493
|
+
def _raise_row_no_columns(self) -> NoReturn:
|
|
494
|
+
msg = "Row has no columns"
|
|
495
|
+
raise ValueError(msg)
|
|
496
|
+
|
|
497
|
+
def _raise_unexpected_row_type(self, row_type: type) -> NoReturn:
|
|
498
|
+
msg = f"Unexpected row type: {row_type}"
|
|
499
|
+
raise ValueError(msg)
|
|
500
|
+
|
|
501
|
+
def _raise_cannot_extract_value_from_row_type(self, type_name: str) -> NoReturn:
|
|
502
|
+
msg = f"Cannot extract value from row type {type_name}"
|
|
503
|
+
raise TypeError(msg)
|