sqlspec 0.13.1__py3-none-any.whl → 0.16.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of sqlspec might be problematic. Click here for more details.
- sqlspec/__init__.py +71 -8
- sqlspec/__main__.py +12 -0
- sqlspec/__metadata__.py +1 -3
- sqlspec/_serialization.py +1 -2
- sqlspec/_sql.py +930 -136
- sqlspec/_typing.py +278 -142
- sqlspec/adapters/adbc/__init__.py +4 -3
- sqlspec/adapters/adbc/_types.py +12 -0
- sqlspec/adapters/adbc/config.py +116 -285
- sqlspec/adapters/adbc/driver.py +462 -340
- sqlspec/adapters/aiosqlite/__init__.py +18 -3
- sqlspec/adapters/aiosqlite/_types.py +13 -0
- sqlspec/adapters/aiosqlite/config.py +202 -150
- sqlspec/adapters/aiosqlite/driver.py +226 -247
- sqlspec/adapters/asyncmy/__init__.py +18 -3
- sqlspec/adapters/asyncmy/_types.py +12 -0
- sqlspec/adapters/asyncmy/config.py +80 -199
- sqlspec/adapters/asyncmy/driver.py +257 -215
- sqlspec/adapters/asyncpg/__init__.py +19 -4
- sqlspec/adapters/asyncpg/_types.py +17 -0
- sqlspec/adapters/asyncpg/config.py +81 -214
- sqlspec/adapters/asyncpg/driver.py +284 -359
- sqlspec/adapters/bigquery/__init__.py +17 -3
- sqlspec/adapters/bigquery/_types.py +12 -0
- sqlspec/adapters/bigquery/config.py +191 -299
- sqlspec/adapters/bigquery/driver.py +474 -634
- sqlspec/adapters/duckdb/__init__.py +14 -3
- sqlspec/adapters/duckdb/_types.py +12 -0
- sqlspec/adapters/duckdb/config.py +414 -397
- sqlspec/adapters/duckdb/driver.py +342 -393
- sqlspec/adapters/oracledb/__init__.py +19 -5
- sqlspec/adapters/oracledb/_types.py +14 -0
- sqlspec/adapters/oracledb/config.py +123 -458
- sqlspec/adapters/oracledb/driver.py +505 -531
- sqlspec/adapters/psqlpy/__init__.py +13 -3
- sqlspec/adapters/psqlpy/_types.py +11 -0
- sqlspec/adapters/psqlpy/config.py +93 -307
- sqlspec/adapters/psqlpy/driver.py +504 -213
- sqlspec/adapters/psycopg/__init__.py +19 -5
- sqlspec/adapters/psycopg/_types.py +17 -0
- sqlspec/adapters/psycopg/config.py +143 -472
- sqlspec/adapters/psycopg/driver.py +704 -825
- sqlspec/adapters/sqlite/__init__.py +14 -3
- sqlspec/adapters/sqlite/_types.py +11 -0
- sqlspec/adapters/sqlite/config.py +208 -142
- sqlspec/adapters/sqlite/driver.py +263 -278
- sqlspec/base.py +105 -9
- sqlspec/{statement/builder → builder}/__init__.py +12 -14
- sqlspec/{statement/builder/base.py → builder/_base.py} +184 -86
- sqlspec/{statement/builder/column.py → builder/_column.py} +97 -60
- sqlspec/{statement/builder/ddl.py → builder/_ddl.py} +61 -131
- sqlspec/{statement/builder → builder}/_ddl_utils.py +4 -10
- sqlspec/{statement/builder/delete.py → builder/_delete.py} +10 -30
- sqlspec/builder/_insert.py +421 -0
- sqlspec/builder/_merge.py +71 -0
- sqlspec/{statement/builder → builder}/_parsing_utils.py +49 -26
- sqlspec/builder/_select.py +170 -0
- sqlspec/{statement/builder/update.py → builder/_update.py} +16 -20
- sqlspec/builder/mixins/__init__.py +55 -0
- sqlspec/builder/mixins/_cte_and_set_ops.py +222 -0
- sqlspec/{statement/builder/mixins/_delete_from.py → builder/mixins/_delete_operations.py} +8 -1
- sqlspec/builder/mixins/_insert_operations.py +244 -0
- sqlspec/{statement/builder/mixins/_join.py → builder/mixins/_join_operations.py} +45 -13
- sqlspec/{statement/builder/mixins/_merge_clauses.py → builder/mixins/_merge_operations.py} +188 -30
- sqlspec/builder/mixins/_order_limit_operations.py +135 -0
- sqlspec/builder/mixins/_pivot_operations.py +153 -0
- sqlspec/builder/mixins/_select_operations.py +604 -0
- sqlspec/builder/mixins/_update_operations.py +202 -0
- sqlspec/builder/mixins/_where_clause.py +644 -0
- sqlspec/cli.py +247 -0
- sqlspec/config.py +183 -138
- sqlspec/core/__init__.py +63 -0
- sqlspec/core/cache.py +871 -0
- sqlspec/core/compiler.py +417 -0
- sqlspec/core/filters.py +830 -0
- sqlspec/core/hashing.py +310 -0
- sqlspec/core/parameters.py +1237 -0
- sqlspec/core/result.py +677 -0
- sqlspec/{statement → core}/splitter.py +321 -191
- sqlspec/core/statement.py +676 -0
- sqlspec/driver/__init__.py +7 -10
- sqlspec/driver/_async.py +422 -163
- sqlspec/driver/_common.py +545 -287
- sqlspec/driver/_sync.py +426 -160
- sqlspec/driver/mixins/__init__.py +2 -13
- sqlspec/driver/mixins/_result_tools.py +193 -0
- sqlspec/driver/mixins/_sql_translator.py +65 -14
- sqlspec/exceptions.py +5 -252
- sqlspec/extensions/aiosql/adapter.py +93 -96
- sqlspec/extensions/litestar/__init__.py +2 -1
- sqlspec/extensions/litestar/cli.py +48 -0
- sqlspec/extensions/litestar/config.py +0 -1
- sqlspec/extensions/litestar/handlers.py +15 -26
- sqlspec/extensions/litestar/plugin.py +21 -16
- sqlspec/extensions/litestar/providers.py +17 -52
- sqlspec/loader.py +423 -104
- sqlspec/migrations/__init__.py +35 -0
- sqlspec/migrations/base.py +414 -0
- sqlspec/migrations/commands.py +443 -0
- sqlspec/migrations/loaders.py +402 -0
- sqlspec/migrations/runner.py +213 -0
- sqlspec/migrations/tracker.py +140 -0
- sqlspec/migrations/utils.py +129 -0
- sqlspec/protocols.py +51 -186
- sqlspec/storage/__init__.py +1 -1
- sqlspec/storage/backends/base.py +37 -40
- sqlspec/storage/backends/fsspec.py +136 -112
- sqlspec/storage/backends/obstore.py +138 -160
- sqlspec/storage/capabilities.py +5 -4
- sqlspec/storage/registry.py +57 -106
- sqlspec/typing.py +136 -115
- sqlspec/utils/__init__.py +2 -2
- sqlspec/utils/correlation.py +0 -3
- sqlspec/utils/deprecation.py +6 -6
- sqlspec/utils/fixtures.py +6 -6
- sqlspec/utils/logging.py +0 -2
- sqlspec/utils/module_loader.py +7 -12
- sqlspec/utils/singleton.py +0 -1
- sqlspec/utils/sync_tools.py +17 -38
- sqlspec/utils/text.py +12 -51
- sqlspec/utils/type_guards.py +482 -235
- {sqlspec-0.13.1.dist-info → sqlspec-0.16.2.dist-info}/METADATA +7 -2
- sqlspec-0.16.2.dist-info/RECORD +134 -0
- sqlspec-0.16.2.dist-info/entry_points.txt +2 -0
- sqlspec/driver/connection.py +0 -207
- sqlspec/driver/mixins/_csv_writer.py +0 -91
- sqlspec/driver/mixins/_pipeline.py +0 -512
- sqlspec/driver/mixins/_result_utils.py +0 -140
- sqlspec/driver/mixins/_storage.py +0 -926
- sqlspec/driver/mixins/_type_coercion.py +0 -130
- sqlspec/driver/parameters.py +0 -138
- sqlspec/service/__init__.py +0 -4
- sqlspec/service/_util.py +0 -147
- sqlspec/service/base.py +0 -1131
- sqlspec/service/pagination.py +0 -26
- sqlspec/statement/__init__.py +0 -21
- sqlspec/statement/builder/insert.py +0 -288
- sqlspec/statement/builder/merge.py +0 -95
- sqlspec/statement/builder/mixins/__init__.py +0 -65
- sqlspec/statement/builder/mixins/_aggregate_functions.py +0 -250
- sqlspec/statement/builder/mixins/_case_builder.py +0 -91
- sqlspec/statement/builder/mixins/_common_table_expr.py +0 -90
- sqlspec/statement/builder/mixins/_from.py +0 -63
- sqlspec/statement/builder/mixins/_group_by.py +0 -118
- sqlspec/statement/builder/mixins/_having.py +0 -35
- sqlspec/statement/builder/mixins/_insert_from_select.py +0 -47
- sqlspec/statement/builder/mixins/_insert_into.py +0 -36
- sqlspec/statement/builder/mixins/_insert_values.py +0 -67
- sqlspec/statement/builder/mixins/_limit_offset.py +0 -53
- sqlspec/statement/builder/mixins/_order_by.py +0 -46
- sqlspec/statement/builder/mixins/_pivot.py +0 -79
- sqlspec/statement/builder/mixins/_returning.py +0 -37
- sqlspec/statement/builder/mixins/_select_columns.py +0 -61
- sqlspec/statement/builder/mixins/_set_ops.py +0 -122
- sqlspec/statement/builder/mixins/_unpivot.py +0 -77
- sqlspec/statement/builder/mixins/_update_from.py +0 -55
- sqlspec/statement/builder/mixins/_update_set.py +0 -94
- sqlspec/statement/builder/mixins/_update_table.py +0 -29
- sqlspec/statement/builder/mixins/_where.py +0 -401
- sqlspec/statement/builder/mixins/_window_functions.py +0 -86
- sqlspec/statement/builder/select.py +0 -221
- sqlspec/statement/filters.py +0 -596
- sqlspec/statement/parameter_manager.py +0 -220
- sqlspec/statement/parameters.py +0 -867
- sqlspec/statement/pipelines/__init__.py +0 -210
- sqlspec/statement/pipelines/analyzers/__init__.py +0 -9
- sqlspec/statement/pipelines/analyzers/_analyzer.py +0 -646
- sqlspec/statement/pipelines/context.py +0 -115
- sqlspec/statement/pipelines/transformers/__init__.py +0 -7
- sqlspec/statement/pipelines/transformers/_expression_simplifier.py +0 -88
- sqlspec/statement/pipelines/transformers/_literal_parameterizer.py +0 -1247
- sqlspec/statement/pipelines/transformers/_remove_comments_and_hints.py +0 -76
- sqlspec/statement/pipelines/validators/__init__.py +0 -23
- sqlspec/statement/pipelines/validators/_dml_safety.py +0 -290
- sqlspec/statement/pipelines/validators/_parameter_style.py +0 -370
- sqlspec/statement/pipelines/validators/_performance.py +0 -718
- sqlspec/statement/pipelines/validators/_security.py +0 -967
- sqlspec/statement/result.py +0 -435
- sqlspec/statement/sql.py +0 -1704
- sqlspec/statement/sql_compiler.py +0 -140
- sqlspec/utils/cached_property.py +0 -25
- sqlspec-0.13.1.dist-info/RECORD +0 -150
- {sqlspec-0.13.1.dist-info → sqlspec-0.16.2.dist-info}/WHEEL +0 -0
- {sqlspec-0.13.1.dist-info → sqlspec-0.16.2.dist-info}/licenses/LICENSE +0 -0
- {sqlspec-0.13.1.dist-info → sqlspec-0.16.2.dist-info}/licenses/NOTICE +0 -0
|
@@ -1,130 +0,0 @@
|
|
|
1
|
-
"""Type coercion mixin for database drivers.
|
|
2
|
-
|
|
3
|
-
This module provides a mixin that all database drivers use to handle
|
|
4
|
-
TypedParameter objects and perform appropriate type conversions.
|
|
5
|
-
"""
|
|
6
|
-
|
|
7
|
-
from decimal import Decimal
|
|
8
|
-
from typing import TYPE_CHECKING, Any, Optional, Union
|
|
9
|
-
|
|
10
|
-
from sqlspec.utils.type_guards import has_parameter_value
|
|
11
|
-
|
|
12
|
-
if TYPE_CHECKING:
|
|
13
|
-
from sqlspec.typing import SQLParameterType
|
|
14
|
-
|
|
15
|
-
__all__ = ("TypeCoercionMixin",)
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
class TypeCoercionMixin:
|
|
19
|
-
"""Mixin providing type coercion for database drivers.
|
|
20
|
-
|
|
21
|
-
This mixin is used by all database drivers to handle TypedParameter objects
|
|
22
|
-
and convert values to database-specific types.
|
|
23
|
-
"""
|
|
24
|
-
|
|
25
|
-
__slots__ = ()
|
|
26
|
-
|
|
27
|
-
def _process_parameters(self, parameters: "SQLParameterType") -> "SQLParameterType":
|
|
28
|
-
"""Process parameters, extracting values from TypedParameter objects.
|
|
29
|
-
|
|
30
|
-
This method is called by drivers before executing SQL to handle
|
|
31
|
-
TypedParameter objects and perform necessary type conversions.
|
|
32
|
-
|
|
33
|
-
Args:
|
|
34
|
-
parameters: Raw parameters that may contain TypedParameter objects
|
|
35
|
-
|
|
36
|
-
Returns:
|
|
37
|
-
Processed parameters with TypedParameter values extracted and converted
|
|
38
|
-
"""
|
|
39
|
-
if parameters is None:
|
|
40
|
-
return None
|
|
41
|
-
|
|
42
|
-
if isinstance(parameters, dict):
|
|
43
|
-
return self._process_dict_parameters(parameters)
|
|
44
|
-
if isinstance(parameters, (list, tuple)):
|
|
45
|
-
return self._process_sequence_parameters(parameters)
|
|
46
|
-
# Single scalar parameter
|
|
47
|
-
return self._coerce_parameter_type(parameters)
|
|
48
|
-
|
|
49
|
-
def _process_dict_parameters(self, params: dict[str, Any]) -> dict[str, Any]:
|
|
50
|
-
"""Process dictionary parameters."""
|
|
51
|
-
result = {}
|
|
52
|
-
for key, value in params.items():
|
|
53
|
-
result[key] = self._coerce_parameter_type(value)
|
|
54
|
-
return result
|
|
55
|
-
|
|
56
|
-
def _process_sequence_parameters(self, params: Union[list, tuple]) -> Union[list, tuple]:
|
|
57
|
-
"""Process list/tuple parameters."""
|
|
58
|
-
result = [self._coerce_parameter_type(p) for p in params]
|
|
59
|
-
return tuple(result) if isinstance(params, tuple) else result
|
|
60
|
-
|
|
61
|
-
def _coerce_parameter_type(self, param: Any) -> Any:
|
|
62
|
-
"""Coerce a single parameter to the appropriate database type.
|
|
63
|
-
|
|
64
|
-
This method checks if the parameter is a TypedParameter and extracts
|
|
65
|
-
its value, then applies driver-specific type conversions.
|
|
66
|
-
|
|
67
|
-
Args:
|
|
68
|
-
param: Parameter value or TypedParameter object
|
|
69
|
-
|
|
70
|
-
Returns:
|
|
71
|
-
Coerced parameter value suitable for the database
|
|
72
|
-
"""
|
|
73
|
-
if has_parameter_value(param):
|
|
74
|
-
value = param.value
|
|
75
|
-
type_hint = param.type_hint
|
|
76
|
-
|
|
77
|
-
return self._apply_type_coercion(value, type_hint)
|
|
78
|
-
# Regular parameter - apply default coercion
|
|
79
|
-
return self._apply_type_coercion(param, None)
|
|
80
|
-
|
|
81
|
-
def _apply_type_coercion(self, value: Any, type_hint: Optional[str]) -> Any:
|
|
82
|
-
"""Apply driver-specific type coercion.
|
|
83
|
-
|
|
84
|
-
This method should be overridden by each driver to implement
|
|
85
|
-
database-specific type conversions.
|
|
86
|
-
|
|
87
|
-
Args:
|
|
88
|
-
value: The value to coerce
|
|
89
|
-
type_hint: Optional type hint from TypedParameter
|
|
90
|
-
|
|
91
|
-
Returns:
|
|
92
|
-
Coerced value
|
|
93
|
-
"""
|
|
94
|
-
# Default implementation - override in specific drivers
|
|
95
|
-
# This base implementation handles common cases
|
|
96
|
-
|
|
97
|
-
if value is None:
|
|
98
|
-
return None
|
|
99
|
-
|
|
100
|
-
# Use type hint if available
|
|
101
|
-
if type_hint:
|
|
102
|
-
if type_hint == "boolean":
|
|
103
|
-
return self._coerce_boolean(value)
|
|
104
|
-
if type_hint == "decimal":
|
|
105
|
-
return self._coerce_decimal(value)
|
|
106
|
-
if type_hint == "json":
|
|
107
|
-
return self._coerce_json(value)
|
|
108
|
-
if type_hint.startswith("array"):
|
|
109
|
-
return self._coerce_array(value)
|
|
110
|
-
|
|
111
|
-
# Default: return value as-is
|
|
112
|
-
return value
|
|
113
|
-
|
|
114
|
-
def _coerce_boolean(self, value: Any) -> Any:
|
|
115
|
-
"""Coerce boolean values. Override in drivers without native boolean support."""
|
|
116
|
-
return value
|
|
117
|
-
|
|
118
|
-
def _coerce_decimal(self, value: Any) -> Any:
|
|
119
|
-
"""Coerce decimal values. Override for specific decimal handling."""
|
|
120
|
-
if isinstance(value, str):
|
|
121
|
-
return Decimal(value)
|
|
122
|
-
return value
|
|
123
|
-
|
|
124
|
-
def _coerce_json(self, value: Any) -> Any:
|
|
125
|
-
"""Coerce JSON values. Override for databases needing JSON strings."""
|
|
126
|
-
return value
|
|
127
|
-
|
|
128
|
-
def _coerce_array(self, value: Any) -> Any:
|
|
129
|
-
"""Coerce array values. Override for databases without native array support."""
|
|
130
|
-
return value
|
sqlspec/driver/parameters.py
DELETED
|
@@ -1,138 +0,0 @@
|
|
|
1
|
-
"""Consolidated parameter processing utilities for database drivers.
|
|
2
|
-
|
|
3
|
-
This module provides centralized parameter handling logic to avoid duplication
|
|
4
|
-
across sync and async driver implementations.
|
|
5
|
-
"""
|
|
6
|
-
|
|
7
|
-
from typing import TYPE_CHECKING, Any, Optional, Union
|
|
8
|
-
|
|
9
|
-
from sqlspec.statement.filters import StatementFilter
|
|
10
|
-
from sqlspec.utils.type_guards import is_sync_transaction_capable
|
|
11
|
-
|
|
12
|
-
if TYPE_CHECKING:
|
|
13
|
-
from sqlspec.typing import StatementParameters
|
|
14
|
-
|
|
15
|
-
__all__ = (
|
|
16
|
-
"convert_parameters_to_positional",
|
|
17
|
-
"normalize_parameter_sequence",
|
|
18
|
-
"process_execute_many_parameters",
|
|
19
|
-
"separate_filters_and_parameters",
|
|
20
|
-
"should_use_transaction",
|
|
21
|
-
)
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
def separate_filters_and_parameters(
|
|
25
|
-
parameters: "tuple[Union[StatementParameters, StatementFilter], ...]",
|
|
26
|
-
) -> "tuple[list[StatementFilter], list[Any]]":
|
|
27
|
-
"""Separate filters from parameters in a mixed parameter tuple.
|
|
28
|
-
|
|
29
|
-
Args:
|
|
30
|
-
parameters: Mixed tuple of parameters and filters
|
|
31
|
-
|
|
32
|
-
Returns:
|
|
33
|
-
Tuple of (filters, parameters) lists
|
|
34
|
-
"""
|
|
35
|
-
|
|
36
|
-
filters: list[StatementFilter] = []
|
|
37
|
-
param_values: list[Any] = []
|
|
38
|
-
|
|
39
|
-
for param in parameters:
|
|
40
|
-
if isinstance(param, StatementFilter):
|
|
41
|
-
filters.append(param)
|
|
42
|
-
else:
|
|
43
|
-
param_values.append(param)
|
|
44
|
-
|
|
45
|
-
return filters, param_values
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
def process_execute_many_parameters(
|
|
49
|
-
parameters: "tuple[Union[StatementParameters, StatementFilter], ...]",
|
|
50
|
-
) -> "tuple[list[StatementFilter], Optional[list[Any]]]":
|
|
51
|
-
"""Process parameters for execute_many operations.
|
|
52
|
-
|
|
53
|
-
Args:
|
|
54
|
-
parameters: Mixed tuple of parameters and filters
|
|
55
|
-
|
|
56
|
-
Returns:
|
|
57
|
-
Tuple of (filters, parameter_sequence)
|
|
58
|
-
"""
|
|
59
|
-
filters, param_values = separate_filters_and_parameters(parameters)
|
|
60
|
-
|
|
61
|
-
# Use first parameter as the sequence for execute_many
|
|
62
|
-
param_sequence = param_values[0] if param_values else None
|
|
63
|
-
|
|
64
|
-
# Normalize the parameter sequence
|
|
65
|
-
param_sequence = normalize_parameter_sequence(param_sequence)
|
|
66
|
-
|
|
67
|
-
return filters, param_sequence
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
def normalize_parameter_sequence(params: Any) -> Optional[list[Any]]:
|
|
71
|
-
"""Normalize a parameter sequence to a list format.
|
|
72
|
-
|
|
73
|
-
Args:
|
|
74
|
-
params: Parameter sequence in various formats
|
|
75
|
-
|
|
76
|
-
Returns:
|
|
77
|
-
Normalized list of parameters or None
|
|
78
|
-
"""
|
|
79
|
-
if params is None:
|
|
80
|
-
return None
|
|
81
|
-
|
|
82
|
-
if isinstance(params, list):
|
|
83
|
-
return params
|
|
84
|
-
|
|
85
|
-
if isinstance(params, tuple):
|
|
86
|
-
return list(params)
|
|
87
|
-
|
|
88
|
-
# Check if it's iterable (but not string or dict)
|
|
89
|
-
# Use duck typing to check for iterable protocol
|
|
90
|
-
try:
|
|
91
|
-
iter(params)
|
|
92
|
-
if not isinstance(params, (str, dict)):
|
|
93
|
-
return list(params)
|
|
94
|
-
except TypeError:
|
|
95
|
-
pass
|
|
96
|
-
|
|
97
|
-
# Single parameter, wrap in list
|
|
98
|
-
return [params]
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
def convert_parameters_to_positional(params: "dict[str, Any]", parameter_info: "list[Any]") -> list[Any]:
|
|
102
|
-
"""Convert named parameters to positional based on SQL order.
|
|
103
|
-
|
|
104
|
-
Args:
|
|
105
|
-
params: Dictionary of named parameters
|
|
106
|
-
parameter_info: List of parameter info from SQL parsing
|
|
107
|
-
|
|
108
|
-
Returns:
|
|
109
|
-
List of positional parameters
|
|
110
|
-
"""
|
|
111
|
-
if not params:
|
|
112
|
-
return []
|
|
113
|
-
|
|
114
|
-
# Handle param_0, param_1, etc. pattern
|
|
115
|
-
if all(key.startswith("param_") for key in params):
|
|
116
|
-
return [params[f"param_{i}"] for i in range(len(params))]
|
|
117
|
-
|
|
118
|
-
# Convert based on parameter info order
|
|
119
|
-
# Check for name attribute using getattr with default
|
|
120
|
-
result = []
|
|
121
|
-
for info in parameter_info:
|
|
122
|
-
param_name = getattr(info, "name", None)
|
|
123
|
-
if param_name is not None:
|
|
124
|
-
result.append(params.get(param_name, None))
|
|
125
|
-
return result
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
def should_use_transaction(connection: Any, auto_commit: bool = True) -> bool:
|
|
129
|
-
"""Determine if a transaction should be used.
|
|
130
|
-
|
|
131
|
-
Args:
|
|
132
|
-
connection: Database connection object
|
|
133
|
-
auto_commit: Whether auto-commit is enabled
|
|
134
|
-
|
|
135
|
-
Returns:
|
|
136
|
-
True if transaction capabilities are available and should be used
|
|
137
|
-
"""
|
|
138
|
-
return False if auto_commit else is_sync_transaction_capable(connection)
|
sqlspec/service/__init__.py
DELETED
sqlspec/service/_util.py
DELETED
|
@@ -1,147 +0,0 @@
|
|
|
1
|
-
from collections.abc import Sequence
|
|
2
|
-
from functools import partial
|
|
3
|
-
from typing import Any, Optional, TypeVar, Union, cast, overload
|
|
4
|
-
|
|
5
|
-
from sqlspec.driver.mixins._result_utils import _DEFAULT_TYPE_DECODERS, _default_msgspec_deserializer
|
|
6
|
-
from sqlspec.exceptions import SQLSpecError
|
|
7
|
-
from sqlspec.service.pagination import OffsetPagination
|
|
8
|
-
from sqlspec.statement.filters import FilterTypeT, LimitOffsetFilter, StatementFilter
|
|
9
|
-
from sqlspec.typing import BaseModel, DataclassProtocol, ModelDTOT, ModelT, Struct, convert, get_type_adapter
|
|
10
|
-
from sqlspec.utils.type_guards import is_dataclass, is_msgspec_struct, is_pydantic_model
|
|
11
|
-
|
|
12
|
-
__all__ = ("ResultConverter", "find_filter")
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
T = TypeVar("T")
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
def find_filter(
|
|
19
|
-
filter_type: "type[FilterTypeT]", filters: "Optional[Sequence[StatementFilter]]" = None
|
|
20
|
-
) -> "Optional[FilterTypeT]":
|
|
21
|
-
"""Get the filter specified by filter type from the filters.
|
|
22
|
-
|
|
23
|
-
Args:
|
|
24
|
-
filter_type: The type of filter to find.
|
|
25
|
-
filters: filter types to apply to the query
|
|
26
|
-
|
|
27
|
-
Returns:
|
|
28
|
-
The match filter instance or None
|
|
29
|
-
"""
|
|
30
|
-
if filters is None:
|
|
31
|
-
return None
|
|
32
|
-
return next(
|
|
33
|
-
(cast("Optional[FilterTypeT]", filter_) for filter_ in filters if isinstance(filter_, filter_type)), None
|
|
34
|
-
)
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
# TODO: add overloads for each type of pagination in the future
|
|
38
|
-
class ResultConverter:
|
|
39
|
-
"""Simple mixin to help convert to dictionary or list of dictionaries to specified schema type.
|
|
40
|
-
|
|
41
|
-
Single objects are transformed to the supplied schema type, and lists of objects are transformed into a list of the supplied schema type.
|
|
42
|
-
|
|
43
|
-
Args:
|
|
44
|
-
data: A database model instance or row mapping.
|
|
45
|
-
Type: :class:`~sqlspec.typing.ModelDictT`
|
|
46
|
-
|
|
47
|
-
Returns:
|
|
48
|
-
The converted schema object.
|
|
49
|
-
"""
|
|
50
|
-
|
|
51
|
-
@overload
|
|
52
|
-
def to_schema(
|
|
53
|
-
self,
|
|
54
|
-
data: "ModelT",
|
|
55
|
-
total: "int | None" = None,
|
|
56
|
-
filters: "Sequence[StatementFilter] | None" = None,
|
|
57
|
-
*,
|
|
58
|
-
schema_type: None = None,
|
|
59
|
-
) -> "ModelT": ...
|
|
60
|
-
@overload
|
|
61
|
-
def to_schema(
|
|
62
|
-
self,
|
|
63
|
-
data: "dict[str, Any] | Struct | BaseModel | DataclassProtocol",
|
|
64
|
-
total: "int | None" = None,
|
|
65
|
-
filters: "Sequence[StatementFilter] | None" = None,
|
|
66
|
-
*,
|
|
67
|
-
schema_type: "type[ModelDTOT]",
|
|
68
|
-
) -> "ModelDTOT": ...
|
|
69
|
-
@overload
|
|
70
|
-
def to_schema(
|
|
71
|
-
self,
|
|
72
|
-
data: "Sequence[ModelT]",
|
|
73
|
-
total: "int | None" = None,
|
|
74
|
-
filters: "Sequence[StatementFilter] | None" = None,
|
|
75
|
-
*,
|
|
76
|
-
schema_type: None = None,
|
|
77
|
-
) -> "OffsetPagination[ModelT]": ...
|
|
78
|
-
@overload
|
|
79
|
-
def to_schema(
|
|
80
|
-
self,
|
|
81
|
-
data: "Sequence[dict[str, Any] | Struct | BaseModel | DataclassProtocol]",
|
|
82
|
-
total: "int | None" = None,
|
|
83
|
-
filters: "Sequence[StatementFilter] | None" = None,
|
|
84
|
-
*,
|
|
85
|
-
schema_type: "type[ModelDTOT]",
|
|
86
|
-
) -> "OffsetPagination[ModelDTOT]": ...
|
|
87
|
-
def to_schema(
|
|
88
|
-
self,
|
|
89
|
-
data: "ModelT | Sequence[ModelT] | dict[str, Any] | Struct | BaseModel | DataclassProtocol | Sequence[dict[str, Any] | Struct | BaseModel | DataclassProtocol]",
|
|
90
|
-
total: "int | None" = None,
|
|
91
|
-
filters: "Sequence[StatementFilter] | None" = None,
|
|
92
|
-
*,
|
|
93
|
-
schema_type: "type[ModelDTOT] | None" = None,
|
|
94
|
-
) -> "Union[ModelT, ModelDTOT , OffsetPagination[ModelT] , OffsetPagination[ModelDTOT]]":
|
|
95
|
-
if not isinstance(data, Sequence):
|
|
96
|
-
if schema_type is None:
|
|
97
|
-
return cast("ModelT", data)
|
|
98
|
-
if is_dataclass(schema_type):
|
|
99
|
-
return cast("ModelDTOT", schema_type(**data)) # type: ignore[operator]
|
|
100
|
-
if is_msgspec_struct(schema_type):
|
|
101
|
-
return cast(
|
|
102
|
-
"ModelDTOT",
|
|
103
|
-
convert(
|
|
104
|
-
obj=data,
|
|
105
|
-
type=schema_type,
|
|
106
|
-
from_attributes=True,
|
|
107
|
-
dec_hook=partial(_default_msgspec_deserializer, type_decoders=_DEFAULT_TYPE_DECODERS),
|
|
108
|
-
),
|
|
109
|
-
)
|
|
110
|
-
if is_pydantic_model(schema_type): # pyright: ignore
|
|
111
|
-
return cast(
|
|
112
|
-
"ModelDTOT",
|
|
113
|
-
get_type_adapter(schema_type).validate_python(data, from_attributes=True), # pyright: ignore
|
|
114
|
-
)
|
|
115
|
-
assert isinstance(data, Sequence)
|
|
116
|
-
limit_offset = find_filter(LimitOffsetFilter, filters=filters)
|
|
117
|
-
if schema_type is None:
|
|
118
|
-
return OffsetPagination[ModelT](
|
|
119
|
-
items=cast("list[ModelT]", data),
|
|
120
|
-
limit=limit_offset.limit if limit_offset else len(data),
|
|
121
|
-
offset=limit_offset.offset if limit_offset else 0,
|
|
122
|
-
total=total if total is not None else len(data),
|
|
123
|
-
)
|
|
124
|
-
converted_items: Sequence[ModelDTOT]
|
|
125
|
-
if is_dataclass(schema_type):
|
|
126
|
-
converted_items = [schema_type(**item) for item in data] # type: ignore[operator]
|
|
127
|
-
elif is_msgspec_struct(schema_type):
|
|
128
|
-
converted_items = convert(
|
|
129
|
-
obj=data,
|
|
130
|
-
type=list[schema_type], # type: ignore[valid-type]
|
|
131
|
-
from_attributes=True,
|
|
132
|
-
dec_hook=partial(_default_msgspec_deserializer, type_decoders=_DEFAULT_TYPE_DECODERS),
|
|
133
|
-
)
|
|
134
|
-
elif is_pydantic_model(schema_type): # pyright: ignore
|
|
135
|
-
converted_items = get_type_adapter(list[schema_type]).validate_python(data, from_attributes=True) # type: ignore[valid-type] # pyright: ignore[reportUnknownArgumentType]
|
|
136
|
-
else:
|
|
137
|
-
# This will also catch the case where a single item had an unrecognized schema_type
|
|
138
|
-
# if it somehow bypassed the initial single-item checks.
|
|
139
|
-
msg = "`schema_type` should be a valid Dataclass, Pydantic model or Msgspec struct"
|
|
140
|
-
raise SQLSpecError(msg)
|
|
141
|
-
|
|
142
|
-
return OffsetPagination[ModelDTOT](
|
|
143
|
-
items=cast("list[ModelDTOT]", converted_items),
|
|
144
|
-
limit=limit_offset.limit if limit_offset else len(data),
|
|
145
|
-
offset=limit_offset.offset if limit_offset else 0,
|
|
146
|
-
total=total if total is not None else len(data),
|
|
147
|
-
)
|