sqlspec 0.25.0__py3-none-any.whl → 0.27.0__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 +7 -15
- sqlspec/_serialization.py +256 -24
- sqlspec/_typing.py +71 -52
- sqlspec/adapters/adbc/_types.py +1 -1
- sqlspec/adapters/adbc/adk/__init__.py +5 -0
- sqlspec/adapters/adbc/adk/store.py +870 -0
- sqlspec/adapters/adbc/config.py +69 -12
- sqlspec/adapters/adbc/data_dictionary.py +340 -0
- sqlspec/adapters/adbc/driver.py +266 -58
- sqlspec/adapters/adbc/litestar/__init__.py +5 -0
- sqlspec/adapters/adbc/litestar/store.py +504 -0
- sqlspec/adapters/adbc/type_converter.py +153 -0
- sqlspec/adapters/aiosqlite/_types.py +1 -1
- sqlspec/adapters/aiosqlite/adk/__init__.py +5 -0
- sqlspec/adapters/aiosqlite/adk/store.py +527 -0
- sqlspec/adapters/aiosqlite/config.py +88 -15
- sqlspec/adapters/aiosqlite/data_dictionary.py +149 -0
- sqlspec/adapters/aiosqlite/driver.py +143 -40
- sqlspec/adapters/aiosqlite/litestar/__init__.py +5 -0
- sqlspec/adapters/aiosqlite/litestar/store.py +281 -0
- sqlspec/adapters/aiosqlite/pool.py +7 -7
- sqlspec/adapters/asyncmy/__init__.py +7 -1
- sqlspec/adapters/asyncmy/_types.py +2 -2
- sqlspec/adapters/asyncmy/adk/__init__.py +5 -0
- sqlspec/adapters/asyncmy/adk/store.py +493 -0
- sqlspec/adapters/asyncmy/config.py +68 -23
- sqlspec/adapters/asyncmy/data_dictionary.py +161 -0
- sqlspec/adapters/asyncmy/driver.py +313 -58
- sqlspec/adapters/asyncmy/litestar/__init__.py +5 -0
- sqlspec/adapters/asyncmy/litestar/store.py +296 -0
- sqlspec/adapters/asyncpg/__init__.py +2 -1
- sqlspec/adapters/asyncpg/_type_handlers.py +71 -0
- sqlspec/adapters/asyncpg/_types.py +11 -7
- sqlspec/adapters/asyncpg/adk/__init__.py +5 -0
- sqlspec/adapters/asyncpg/adk/store.py +450 -0
- sqlspec/adapters/asyncpg/config.py +59 -35
- sqlspec/adapters/asyncpg/data_dictionary.py +173 -0
- sqlspec/adapters/asyncpg/driver.py +170 -25
- sqlspec/adapters/asyncpg/litestar/__init__.py +5 -0
- sqlspec/adapters/asyncpg/litestar/store.py +253 -0
- sqlspec/adapters/bigquery/_types.py +1 -1
- sqlspec/adapters/bigquery/adk/__init__.py +5 -0
- sqlspec/adapters/bigquery/adk/store.py +576 -0
- sqlspec/adapters/bigquery/config.py +27 -10
- sqlspec/adapters/bigquery/data_dictionary.py +149 -0
- sqlspec/adapters/bigquery/driver.py +368 -142
- sqlspec/adapters/bigquery/litestar/__init__.py +5 -0
- sqlspec/adapters/bigquery/litestar/store.py +327 -0
- sqlspec/adapters/bigquery/type_converter.py +125 -0
- sqlspec/adapters/duckdb/_types.py +1 -1
- sqlspec/adapters/duckdb/adk/__init__.py +14 -0
- sqlspec/adapters/duckdb/adk/store.py +553 -0
- sqlspec/adapters/duckdb/config.py +80 -20
- sqlspec/adapters/duckdb/data_dictionary.py +163 -0
- sqlspec/adapters/duckdb/driver.py +167 -45
- sqlspec/adapters/duckdb/litestar/__init__.py +5 -0
- sqlspec/adapters/duckdb/litestar/store.py +332 -0
- sqlspec/adapters/duckdb/pool.py +4 -4
- sqlspec/adapters/duckdb/type_converter.py +133 -0
- sqlspec/adapters/oracledb/_numpy_handlers.py +133 -0
- sqlspec/adapters/oracledb/_types.py +20 -2
- sqlspec/adapters/oracledb/adk/__init__.py +5 -0
- sqlspec/adapters/oracledb/adk/store.py +1745 -0
- sqlspec/adapters/oracledb/config.py +122 -32
- sqlspec/adapters/oracledb/data_dictionary.py +509 -0
- sqlspec/adapters/oracledb/driver.py +353 -91
- sqlspec/adapters/oracledb/litestar/__init__.py +5 -0
- sqlspec/adapters/oracledb/litestar/store.py +767 -0
- sqlspec/adapters/oracledb/migrations.py +348 -73
- sqlspec/adapters/oracledb/type_converter.py +207 -0
- sqlspec/adapters/psqlpy/_type_handlers.py +44 -0
- sqlspec/adapters/psqlpy/_types.py +2 -1
- sqlspec/adapters/psqlpy/adk/__init__.py +5 -0
- sqlspec/adapters/psqlpy/adk/store.py +482 -0
- sqlspec/adapters/psqlpy/config.py +46 -17
- sqlspec/adapters/psqlpy/data_dictionary.py +172 -0
- sqlspec/adapters/psqlpy/driver.py +123 -209
- sqlspec/adapters/psqlpy/litestar/__init__.py +5 -0
- sqlspec/adapters/psqlpy/litestar/store.py +272 -0
- sqlspec/adapters/psqlpy/type_converter.py +102 -0
- sqlspec/adapters/psycopg/_type_handlers.py +80 -0
- sqlspec/adapters/psycopg/_types.py +2 -1
- sqlspec/adapters/psycopg/adk/__init__.py +5 -0
- sqlspec/adapters/psycopg/adk/store.py +944 -0
- sqlspec/adapters/psycopg/config.py +69 -35
- sqlspec/adapters/psycopg/data_dictionary.py +331 -0
- sqlspec/adapters/psycopg/driver.py +238 -81
- sqlspec/adapters/psycopg/litestar/__init__.py +5 -0
- sqlspec/adapters/psycopg/litestar/store.py +554 -0
- sqlspec/adapters/sqlite/__init__.py +2 -1
- sqlspec/adapters/sqlite/_type_handlers.py +86 -0
- sqlspec/adapters/sqlite/_types.py +1 -1
- sqlspec/adapters/sqlite/adk/__init__.py +5 -0
- sqlspec/adapters/sqlite/adk/store.py +572 -0
- sqlspec/adapters/sqlite/config.py +87 -15
- sqlspec/adapters/sqlite/data_dictionary.py +149 -0
- sqlspec/adapters/sqlite/driver.py +137 -54
- sqlspec/adapters/sqlite/litestar/__init__.py +5 -0
- sqlspec/adapters/sqlite/litestar/store.py +318 -0
- sqlspec/adapters/sqlite/pool.py +18 -9
- sqlspec/base.py +45 -26
- sqlspec/builder/__init__.py +73 -4
- sqlspec/builder/_base.py +162 -89
- sqlspec/builder/_column.py +62 -29
- sqlspec/builder/_ddl.py +180 -121
- sqlspec/builder/_delete.py +5 -4
- sqlspec/builder/_dml.py +388 -0
- sqlspec/{_sql.py → builder/_factory.py} +53 -94
- sqlspec/builder/_insert.py +32 -131
- sqlspec/builder/_join.py +375 -0
- sqlspec/builder/_merge.py +446 -11
- sqlspec/builder/_parsing_utils.py +111 -17
- sqlspec/builder/_select.py +1457 -24
- sqlspec/builder/_update.py +11 -42
- sqlspec/cli.py +307 -194
- sqlspec/config.py +252 -67
- sqlspec/core/__init__.py +5 -4
- sqlspec/core/cache.py +17 -17
- sqlspec/core/compiler.py +62 -9
- sqlspec/core/filters.py +37 -37
- sqlspec/core/hashing.py +9 -9
- sqlspec/core/parameters.py +83 -48
- sqlspec/core/result.py +102 -46
- sqlspec/core/splitter.py +16 -17
- sqlspec/core/statement.py +36 -30
- sqlspec/core/type_conversion.py +235 -0
- sqlspec/driver/__init__.py +7 -6
- sqlspec/driver/_async.py +188 -151
- sqlspec/driver/_common.py +285 -80
- sqlspec/driver/_sync.py +188 -152
- sqlspec/driver/mixins/_result_tools.py +20 -236
- sqlspec/driver/mixins/_sql_translator.py +4 -4
- sqlspec/exceptions.py +75 -7
- sqlspec/extensions/adk/__init__.py +53 -0
- sqlspec/extensions/adk/_types.py +51 -0
- sqlspec/extensions/adk/converters.py +172 -0
- sqlspec/extensions/adk/migrations/0001_create_adk_tables.py +144 -0
- sqlspec/extensions/adk/migrations/__init__.py +0 -0
- sqlspec/extensions/adk/service.py +181 -0
- sqlspec/extensions/adk/store.py +536 -0
- sqlspec/extensions/aiosql/adapter.py +73 -53
- sqlspec/extensions/litestar/__init__.py +21 -4
- sqlspec/extensions/litestar/cli.py +54 -10
- sqlspec/extensions/litestar/config.py +59 -266
- sqlspec/extensions/litestar/handlers.py +46 -17
- sqlspec/extensions/litestar/migrations/0001_create_session_table.py +137 -0
- sqlspec/extensions/litestar/migrations/__init__.py +3 -0
- sqlspec/extensions/litestar/plugin.py +324 -223
- sqlspec/extensions/litestar/providers.py +25 -25
- sqlspec/extensions/litestar/store.py +265 -0
- sqlspec/loader.py +30 -49
- sqlspec/migrations/__init__.py +4 -3
- sqlspec/migrations/base.py +302 -39
- sqlspec/migrations/commands.py +611 -144
- sqlspec/migrations/context.py +142 -0
- sqlspec/migrations/fix.py +199 -0
- sqlspec/migrations/loaders.py +68 -23
- sqlspec/migrations/runner.py +543 -107
- sqlspec/migrations/tracker.py +237 -21
- sqlspec/migrations/utils.py +51 -3
- sqlspec/migrations/validation.py +177 -0
- sqlspec/protocols.py +66 -36
- sqlspec/storage/_utils.py +98 -0
- sqlspec/storage/backends/fsspec.py +134 -106
- sqlspec/storage/backends/local.py +78 -51
- sqlspec/storage/backends/obstore.py +278 -162
- sqlspec/storage/registry.py +75 -39
- sqlspec/typing.py +16 -84
- sqlspec/utils/config_resolver.py +153 -0
- sqlspec/utils/correlation.py +4 -5
- sqlspec/utils/data_transformation.py +3 -2
- sqlspec/utils/deprecation.py +9 -8
- sqlspec/utils/fixtures.py +4 -4
- sqlspec/utils/logging.py +46 -6
- sqlspec/utils/module_loader.py +2 -2
- sqlspec/utils/schema.py +288 -0
- sqlspec/utils/serializers.py +50 -2
- sqlspec/utils/sync_tools.py +21 -17
- sqlspec/utils/text.py +1 -2
- sqlspec/utils/type_guards.py +111 -20
- sqlspec/utils/version.py +433 -0
- {sqlspec-0.25.0.dist-info → sqlspec-0.27.0.dist-info}/METADATA +40 -21
- sqlspec-0.27.0.dist-info/RECORD +207 -0
- sqlspec/builder/mixins/__init__.py +0 -55
- sqlspec/builder/mixins/_cte_and_set_ops.py +0 -254
- sqlspec/builder/mixins/_delete_operations.py +0 -50
- sqlspec/builder/mixins/_insert_operations.py +0 -282
- sqlspec/builder/mixins/_join_operations.py +0 -389
- sqlspec/builder/mixins/_merge_operations.py +0 -592
- sqlspec/builder/mixins/_order_limit_operations.py +0 -152
- sqlspec/builder/mixins/_pivot_operations.py +0 -157
- sqlspec/builder/mixins/_select_operations.py +0 -936
- sqlspec/builder/mixins/_update_operations.py +0 -218
- sqlspec/builder/mixins/_where_clause.py +0 -1304
- sqlspec-0.25.0.dist-info/RECORD +0 -139
- sqlspec-0.25.0.dist-info/licenses/NOTICE +0 -29
- {sqlspec-0.25.0.dist-info → sqlspec-0.27.0.dist-info}/WHEEL +0 -0
- {sqlspec-0.25.0.dist-info → sqlspec-0.27.0.dist-info}/entry_points.txt +0 -0
- {sqlspec-0.25.0.dist-info → sqlspec-0.27.0.dist-info}/licenses/LICENSE +0 -0
sqlspec/driver/_sync.py
CHANGED
|
@@ -1,14 +1,18 @@
|
|
|
1
1
|
"""Synchronous driver protocol implementation."""
|
|
2
2
|
|
|
3
3
|
from abc import abstractmethod
|
|
4
|
-
from typing import TYPE_CHECKING, Any, Final,
|
|
4
|
+
from typing import TYPE_CHECKING, Any, Final, TypeVar, overload
|
|
5
5
|
|
|
6
6
|
from sqlspec.core import SQL
|
|
7
|
-
from sqlspec.driver._common import
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
from sqlspec.driver._common import (
|
|
8
|
+
CommonDriverAttributesMixin,
|
|
9
|
+
DataDictionaryMixin,
|
|
10
|
+
ExecutionResult,
|
|
11
|
+
VersionInfo,
|
|
12
|
+
handle_single_row_error,
|
|
13
|
+
)
|
|
14
|
+
from sqlspec.driver.mixins import SQLTranslatorMixin
|
|
10
15
|
from sqlspec.utils.logging import get_logger
|
|
11
|
-
from sqlspec.utils.type_guards import is_dict_row, is_indexable_row
|
|
12
16
|
|
|
13
17
|
if TYPE_CHECKING:
|
|
14
18
|
from collections.abc import Sequence
|
|
@@ -16,22 +20,33 @@ if TYPE_CHECKING:
|
|
|
16
20
|
|
|
17
21
|
from sqlspec.builder import QueryBuilder
|
|
18
22
|
from sqlspec.core import SQLResult, Statement, StatementConfig, StatementFilter
|
|
19
|
-
from sqlspec.typing import
|
|
23
|
+
from sqlspec.typing import SchemaT, StatementParameters
|
|
20
24
|
|
|
21
25
|
_LOGGER_NAME: Final[str] = "sqlspec"
|
|
22
26
|
logger = get_logger(_LOGGER_NAME)
|
|
23
27
|
|
|
24
|
-
__all__ = ("SyncDriverAdapterBase",)
|
|
28
|
+
__all__ = ("SyncDataDictionaryBase", "SyncDriverAdapterBase", "SyncDriverT")
|
|
25
29
|
|
|
26
30
|
|
|
27
31
|
EMPTY_FILTERS: Final["list[StatementFilter]"] = []
|
|
28
32
|
|
|
33
|
+
SyncDriverT = TypeVar("SyncDriverT", bound="SyncDriverAdapterBase")
|
|
29
34
|
|
|
30
|
-
|
|
35
|
+
|
|
36
|
+
class SyncDriverAdapterBase(CommonDriverAttributesMixin, SQLTranslatorMixin):
|
|
31
37
|
"""Base class for synchronous database drivers."""
|
|
32
38
|
|
|
33
39
|
__slots__ = ()
|
|
34
40
|
|
|
41
|
+
@property
|
|
42
|
+
@abstractmethod
|
|
43
|
+
def data_dictionary(self) -> "SyncDataDictionaryBase":
|
|
44
|
+
"""Get the data dictionary for this driver.
|
|
45
|
+
|
|
46
|
+
Returns:
|
|
47
|
+
Data dictionary instance for metadata queries
|
|
48
|
+
"""
|
|
49
|
+
|
|
35
50
|
def dispatch_statement_execution(self, statement: "SQL", connection: "Any") -> "SQLResult":
|
|
36
51
|
"""Central execution dispatcher using the Template Method Pattern.
|
|
37
52
|
|
|
@@ -85,7 +100,7 @@ class SyncDriverAdapterBase(CommonDriverAttributesMixin, SQLTranslatorMixin, ToS
|
|
|
85
100
|
"""Commit the current transaction on the current connection."""
|
|
86
101
|
|
|
87
102
|
@abstractmethod
|
|
88
|
-
def _try_special_handling(self, cursor: Any, statement: "SQL") -> "
|
|
103
|
+
def _try_special_handling(self, cursor: Any, statement: "SQL") -> "SQLResult | None":
|
|
89
104
|
"""Hook for database-specific special operations (e.g., PostgreSQL COPY, bulk operations).
|
|
90
105
|
|
|
91
106
|
This method is called first in dispatch_statement_execution() to allow drivers to handle
|
|
@@ -158,10 +173,10 @@ class SyncDriverAdapterBase(CommonDriverAttributesMixin, SQLTranslatorMixin, ToS
|
|
|
158
173
|
|
|
159
174
|
def execute(
|
|
160
175
|
self,
|
|
161
|
-
statement: "
|
|
176
|
+
statement: "SQL | Statement | QueryBuilder",
|
|
162
177
|
/,
|
|
163
|
-
*parameters: "
|
|
164
|
-
statement_config: "
|
|
178
|
+
*parameters: "StatementParameters | StatementFilter",
|
|
179
|
+
statement_config: "StatementConfig | None" = None,
|
|
165
180
|
**kwargs: Any,
|
|
166
181
|
) -> "SQLResult":
|
|
167
182
|
"""Execute a statement with parameter handling."""
|
|
@@ -172,11 +187,11 @@ class SyncDriverAdapterBase(CommonDriverAttributesMixin, SQLTranslatorMixin, ToS
|
|
|
172
187
|
|
|
173
188
|
def execute_many(
|
|
174
189
|
self,
|
|
175
|
-
statement: "
|
|
190
|
+
statement: "SQL | Statement | QueryBuilder",
|
|
176
191
|
/,
|
|
177
192
|
parameters: "Sequence[StatementParameters]",
|
|
178
|
-
*filters: "
|
|
179
|
-
statement_config: "
|
|
193
|
+
*filters: "StatementParameters | StatementFilter",
|
|
194
|
+
statement_config: "StatementConfig | None" = None,
|
|
180
195
|
**kwargs: Any,
|
|
181
196
|
) -> "SQLResult":
|
|
182
197
|
"""Execute statement multiple times with different parameters.
|
|
@@ -195,10 +210,10 @@ class SyncDriverAdapterBase(CommonDriverAttributesMixin, SQLTranslatorMixin, ToS
|
|
|
195
210
|
|
|
196
211
|
def execute_script(
|
|
197
212
|
self,
|
|
198
|
-
statement: "
|
|
213
|
+
statement: "str | SQL",
|
|
199
214
|
/,
|
|
200
|
-
*parameters: "
|
|
201
|
-
statement_config: "
|
|
215
|
+
*parameters: "StatementParameters | StatementFilter",
|
|
216
|
+
statement_config: "StatementConfig | None" = None,
|
|
202
217
|
**kwargs: Any,
|
|
203
218
|
) -> "SQLResult":
|
|
204
219
|
"""Execute a multi-statement script.
|
|
@@ -214,140 +229,124 @@ class SyncDriverAdapterBase(CommonDriverAttributesMixin, SQLTranslatorMixin, ToS
|
|
|
214
229
|
@overload
|
|
215
230
|
def select_one(
|
|
216
231
|
self,
|
|
217
|
-
statement: "
|
|
232
|
+
statement: "Statement | QueryBuilder",
|
|
218
233
|
/,
|
|
219
|
-
*parameters: "
|
|
220
|
-
schema_type: "type[
|
|
221
|
-
statement_config: "
|
|
234
|
+
*parameters: "StatementParameters | StatementFilter",
|
|
235
|
+
schema_type: "type[SchemaT]",
|
|
236
|
+
statement_config: "StatementConfig | None" = None,
|
|
222
237
|
**kwargs: Any,
|
|
223
|
-
) -> "
|
|
238
|
+
) -> "SchemaT": ...
|
|
224
239
|
|
|
225
240
|
@overload
|
|
226
241
|
def select_one(
|
|
227
242
|
self,
|
|
228
|
-
statement: "
|
|
243
|
+
statement: "Statement | QueryBuilder",
|
|
229
244
|
/,
|
|
230
|
-
*parameters: "
|
|
245
|
+
*parameters: "StatementParameters | StatementFilter",
|
|
231
246
|
schema_type: None = None,
|
|
232
|
-
statement_config: "
|
|
247
|
+
statement_config: "StatementConfig | None" = None,
|
|
233
248
|
**kwargs: Any,
|
|
234
249
|
) -> "dict[str, Any]": ...
|
|
235
250
|
|
|
236
251
|
def select_one(
|
|
237
252
|
self,
|
|
238
|
-
statement: "
|
|
253
|
+
statement: "Statement | QueryBuilder",
|
|
239
254
|
/,
|
|
240
|
-
*parameters: "
|
|
241
|
-
schema_type: "
|
|
242
|
-
statement_config: "
|
|
255
|
+
*parameters: "StatementParameters | StatementFilter",
|
|
256
|
+
schema_type: "type[SchemaT] | None" = None,
|
|
257
|
+
statement_config: "StatementConfig | None" = None,
|
|
243
258
|
**kwargs: Any,
|
|
244
|
-
) -> "
|
|
259
|
+
) -> "SchemaT | dict[str, Any]":
|
|
245
260
|
"""Execute a select statement and return exactly one row.
|
|
246
261
|
|
|
247
262
|
Raises an exception if no rows or more than one row is returned.
|
|
248
263
|
"""
|
|
249
264
|
result = self.execute(statement, *parameters, statement_config=statement_config, **kwargs)
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
if data_len > 1:
|
|
255
|
-
self._raise_expected_one_row(data_len)
|
|
256
|
-
first_row = data[0]
|
|
257
|
-
return self.to_schema(first_row, schema_type=schema_type) if schema_type else first_row
|
|
265
|
+
try:
|
|
266
|
+
return result.one(schema_type=schema_type)
|
|
267
|
+
except ValueError as error:
|
|
268
|
+
handle_single_row_error(error)
|
|
258
269
|
|
|
259
270
|
@overload
|
|
260
271
|
def select_one_or_none(
|
|
261
272
|
self,
|
|
262
|
-
statement: "
|
|
273
|
+
statement: "Statement | QueryBuilder",
|
|
263
274
|
/,
|
|
264
|
-
*parameters: "
|
|
265
|
-
schema_type: "type[
|
|
266
|
-
statement_config: "
|
|
275
|
+
*parameters: "StatementParameters | StatementFilter",
|
|
276
|
+
schema_type: "type[SchemaT]",
|
|
277
|
+
statement_config: "StatementConfig | None" = None,
|
|
267
278
|
**kwargs: Any,
|
|
268
|
-
) -> "
|
|
279
|
+
) -> "SchemaT | None": ...
|
|
269
280
|
|
|
270
281
|
@overload
|
|
271
282
|
def select_one_or_none(
|
|
272
283
|
self,
|
|
273
|
-
statement: "
|
|
284
|
+
statement: "Statement | QueryBuilder",
|
|
274
285
|
/,
|
|
275
|
-
*parameters: "
|
|
286
|
+
*parameters: "StatementParameters | StatementFilter",
|
|
276
287
|
schema_type: None = None,
|
|
277
|
-
statement_config: "
|
|
288
|
+
statement_config: "StatementConfig | None" = None,
|
|
278
289
|
**kwargs: Any,
|
|
279
|
-
) -> "
|
|
290
|
+
) -> "dict[str, Any] | None": ...
|
|
280
291
|
|
|
281
292
|
def select_one_or_none(
|
|
282
293
|
self,
|
|
283
|
-
statement: "
|
|
294
|
+
statement: "Statement | QueryBuilder",
|
|
284
295
|
/,
|
|
285
|
-
*parameters: "
|
|
286
|
-
schema_type: "
|
|
287
|
-
statement_config: "
|
|
296
|
+
*parameters: "StatementParameters | StatementFilter",
|
|
297
|
+
schema_type: "type[SchemaT] | None" = None,
|
|
298
|
+
statement_config: "StatementConfig | None" = None,
|
|
288
299
|
**kwargs: Any,
|
|
289
|
-
) -> "
|
|
300
|
+
) -> "SchemaT | dict[str, Any] | None":
|
|
290
301
|
"""Execute a select statement and return at most one row.
|
|
291
302
|
|
|
292
303
|
Returns None if no rows are found.
|
|
293
304
|
Raises an exception if more than one row is returned.
|
|
294
305
|
"""
|
|
295
306
|
result = self.execute(statement, *parameters, statement_config=statement_config, **kwargs)
|
|
296
|
-
|
|
297
|
-
data_len: int = len(data)
|
|
298
|
-
if data_len == 0:
|
|
299
|
-
return None
|
|
300
|
-
if data_len > 1:
|
|
301
|
-
self._raise_expected_at_most_one_row(data_len)
|
|
302
|
-
first_row = data[0]
|
|
303
|
-
return cast(
|
|
304
|
-
"Optional[Union[dict[str, Any], ModelDTOT]]",
|
|
305
|
-
self.to_schema(first_row, schema_type=schema_type) if schema_type else first_row,
|
|
306
|
-
)
|
|
307
|
+
return result.one_or_none(schema_type=schema_type)
|
|
307
308
|
|
|
308
309
|
@overload
|
|
309
310
|
def select(
|
|
310
311
|
self,
|
|
311
|
-
statement: "
|
|
312
|
+
statement: "Statement | QueryBuilder",
|
|
312
313
|
/,
|
|
313
|
-
*parameters: "
|
|
314
|
-
schema_type: "type[
|
|
315
|
-
statement_config: "
|
|
314
|
+
*parameters: "StatementParameters | StatementFilter",
|
|
315
|
+
schema_type: "type[SchemaT]",
|
|
316
|
+
statement_config: "StatementConfig | None" = None,
|
|
316
317
|
**kwargs: Any,
|
|
317
|
-
) -> "list[
|
|
318
|
+
) -> "list[SchemaT]": ...
|
|
318
319
|
|
|
319
320
|
@overload
|
|
320
321
|
def select(
|
|
321
322
|
self,
|
|
322
|
-
statement: "
|
|
323
|
+
statement: "Statement | QueryBuilder",
|
|
323
324
|
/,
|
|
324
|
-
*parameters: "
|
|
325
|
+
*parameters: "StatementParameters | StatementFilter",
|
|
325
326
|
schema_type: None = None,
|
|
326
|
-
statement_config: "
|
|
327
|
+
statement_config: "StatementConfig | None" = None,
|
|
327
328
|
**kwargs: Any,
|
|
328
329
|
) -> "list[dict[str, Any]]": ...
|
|
329
330
|
|
|
330
331
|
def select(
|
|
331
332
|
self,
|
|
332
|
-
statement: "
|
|
333
|
+
statement: "Statement | QueryBuilder",
|
|
333
334
|
/,
|
|
334
|
-
*parameters: "
|
|
335
|
-
schema_type: "
|
|
336
|
-
statement_config: "
|
|
335
|
+
*parameters: "StatementParameters | StatementFilter",
|
|
336
|
+
schema_type: "type[SchemaT] | None" = None,
|
|
337
|
+
statement_config: "StatementConfig | None" = None,
|
|
337
338
|
**kwargs: Any,
|
|
338
|
-
) -> "
|
|
339
|
+
) -> "list[SchemaT] | list[dict[str, Any]]":
|
|
339
340
|
"""Execute a select statement and return all rows."""
|
|
340
341
|
result = self.execute(statement, *parameters, statement_config=statement_config, **kwargs)
|
|
341
|
-
return
|
|
342
|
-
"Union[list[dict[str, Any]], list[ModelDTOT]]", self.to_schema(result.get_data(), schema_type=schema_type)
|
|
343
|
-
)
|
|
342
|
+
return result.get_data(schema_type=schema_type)
|
|
344
343
|
|
|
345
344
|
def select_value(
|
|
346
345
|
self,
|
|
347
|
-
statement: "
|
|
346
|
+
statement: "Statement | QueryBuilder",
|
|
348
347
|
/,
|
|
349
|
-
*parameters: "
|
|
350
|
-
statement_config: "
|
|
348
|
+
*parameters: "StatementParameters | StatementFilter",
|
|
349
|
+
statement_config: "StatementConfig | None" = None,
|
|
351
350
|
**kwargs: Any,
|
|
352
351
|
) -> Any:
|
|
353
352
|
"""Execute a select statement and return a single scalar value.
|
|
@@ -357,28 +356,16 @@ class SyncDriverAdapterBase(CommonDriverAttributesMixin, SQLTranslatorMixin, ToS
|
|
|
357
356
|
"""
|
|
358
357
|
result = self.execute(statement, *parameters, statement_config=statement_config, **kwargs)
|
|
359
358
|
try:
|
|
360
|
-
|
|
361
|
-
except ValueError as
|
|
362
|
-
|
|
363
|
-
if not row:
|
|
364
|
-
self._raise_no_rows_found()
|
|
365
|
-
if is_dict_row(row):
|
|
366
|
-
if not row:
|
|
367
|
-
self._raise_row_no_columns()
|
|
368
|
-
return next(iter(row.values()))
|
|
369
|
-
if is_indexable_row(row):
|
|
370
|
-
if not row:
|
|
371
|
-
self._raise_row_no_columns()
|
|
372
|
-
return row[0]
|
|
373
|
-
self._raise_unexpected_row_type(type(row))
|
|
374
|
-
return None
|
|
359
|
+
return result.scalar()
|
|
360
|
+
except ValueError as error:
|
|
361
|
+
handle_single_row_error(error)
|
|
375
362
|
|
|
376
363
|
def select_value_or_none(
|
|
377
364
|
self,
|
|
378
|
-
statement: "
|
|
365
|
+
statement: "Statement | QueryBuilder",
|
|
379
366
|
/,
|
|
380
|
-
*parameters: "
|
|
381
|
-
statement_config: "
|
|
367
|
+
*parameters: "StatementParameters | StatementFilter",
|
|
368
|
+
statement_config: "StatementConfig | None" = None,
|
|
382
369
|
**kwargs: Any,
|
|
383
370
|
) -> Any:
|
|
384
371
|
"""Execute a select statement and return a single scalar value or None.
|
|
@@ -388,54 +375,39 @@ class SyncDriverAdapterBase(CommonDriverAttributesMixin, SQLTranslatorMixin, ToS
|
|
|
388
375
|
Raises an exception if more than one row is returned.
|
|
389
376
|
"""
|
|
390
377
|
result = self.execute(statement, *parameters, statement_config=statement_config, **kwargs)
|
|
391
|
-
|
|
392
|
-
data_len: int = len(data)
|
|
393
|
-
if data_len == 0:
|
|
394
|
-
return None
|
|
395
|
-
if data_len > 1:
|
|
396
|
-
msg = f"Expected at most one row, found {data_len}"
|
|
397
|
-
raise ValueError(msg)
|
|
398
|
-
row = data[0]
|
|
399
|
-
if isinstance(row, dict):
|
|
400
|
-
if not row:
|
|
401
|
-
return None
|
|
402
|
-
return next(iter(row.values()))
|
|
403
|
-
if isinstance(row, (tuple, list)):
|
|
404
|
-
return row[0]
|
|
405
|
-
msg = f"Cannot extract value from row type {type(row).__name__}"
|
|
406
|
-
raise TypeError(msg)
|
|
378
|
+
return result.scalar_or_none()
|
|
407
379
|
|
|
408
380
|
@overload
|
|
409
381
|
def select_with_total(
|
|
410
382
|
self,
|
|
411
|
-
statement: "
|
|
383
|
+
statement: "Statement | QueryBuilder",
|
|
412
384
|
/,
|
|
413
|
-
*parameters: "
|
|
414
|
-
schema_type: "type[
|
|
415
|
-
statement_config: "
|
|
385
|
+
*parameters: "StatementParameters | StatementFilter",
|
|
386
|
+
schema_type: "type[SchemaT]",
|
|
387
|
+
statement_config: "StatementConfig | None" = None,
|
|
416
388
|
**kwargs: Any,
|
|
417
|
-
) -> "tuple[list[
|
|
389
|
+
) -> "tuple[list[SchemaT], int]": ...
|
|
418
390
|
|
|
419
391
|
@overload
|
|
420
392
|
def select_with_total(
|
|
421
393
|
self,
|
|
422
|
-
statement: "
|
|
394
|
+
statement: "Statement | QueryBuilder",
|
|
423
395
|
/,
|
|
424
|
-
*parameters: "
|
|
396
|
+
*parameters: "StatementParameters | StatementFilter",
|
|
425
397
|
schema_type: None = None,
|
|
426
|
-
statement_config: "
|
|
398
|
+
statement_config: "StatementConfig | None" = None,
|
|
427
399
|
**kwargs: Any,
|
|
428
400
|
) -> "tuple[list[dict[str, Any]], int]": ...
|
|
429
401
|
|
|
430
402
|
def select_with_total(
|
|
431
403
|
self,
|
|
432
|
-
statement: "
|
|
404
|
+
statement: "Statement | QueryBuilder",
|
|
433
405
|
/,
|
|
434
|
-
*parameters: "
|
|
435
|
-
schema_type: "
|
|
436
|
-
statement_config: "
|
|
406
|
+
*parameters: "StatementParameters | StatementFilter",
|
|
407
|
+
schema_type: "type[SchemaT] | None" = None,
|
|
408
|
+
statement_config: "StatementConfig | None" = None,
|
|
437
409
|
**kwargs: Any,
|
|
438
|
-
) -> "tuple[
|
|
410
|
+
) -> "tuple[list[SchemaT] | list[dict[str, Any]], int]":
|
|
439
411
|
"""Execute a select statement and return both the data and total count.
|
|
440
412
|
|
|
441
413
|
This method is designed for pagination scenarios where you need both
|
|
@@ -459,32 +431,96 @@ class SyncDriverAdapterBase(CommonDriverAttributesMixin, SQLTranslatorMixin, ToS
|
|
|
459
431
|
count_result = self.dispatch_statement_execution(self._create_count_query(sql_statement), self.connection)
|
|
460
432
|
select_result = self.execute(sql_statement)
|
|
461
433
|
|
|
462
|
-
return (
|
|
434
|
+
return (select_result.get_data(schema_type=schema_type), count_result.scalar())
|
|
435
|
+
|
|
436
|
+
|
|
437
|
+
class SyncDataDictionaryBase(DataDictionaryMixin):
|
|
438
|
+
"""Base class for synchronous data dictionary implementations."""
|
|
439
|
+
|
|
440
|
+
@abstractmethod
|
|
441
|
+
def get_version(self, driver: "SyncDriverAdapterBase") -> "VersionInfo | None":
|
|
442
|
+
"""Get database version information.
|
|
443
|
+
|
|
444
|
+
Args:
|
|
445
|
+
driver: Sync database driver instance
|
|
463
446
|
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
447
|
+
Returns:
|
|
448
|
+
Version information or None if detection fails
|
|
449
|
+
"""
|
|
467
450
|
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
451
|
+
@abstractmethod
|
|
452
|
+
def get_feature_flag(self, driver: "SyncDriverAdapterBase", feature: str) -> bool:
|
|
453
|
+
"""Check if database supports a specific feature.
|
|
471
454
|
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
455
|
+
Args:
|
|
456
|
+
driver: Sync database driver instance
|
|
457
|
+
feature: Feature name to check
|
|
475
458
|
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
459
|
+
Returns:
|
|
460
|
+
True if feature is supported, False otherwise
|
|
461
|
+
"""
|
|
479
462
|
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
463
|
+
@abstractmethod
|
|
464
|
+
def get_optimal_type(self, driver: "SyncDriverAdapterBase", type_category: str) -> str:
|
|
465
|
+
"""Get optimal database type for a category.
|
|
483
466
|
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
467
|
+
Args:
|
|
468
|
+
driver: Sync database driver instance
|
|
469
|
+
type_category: Type category (e.g., 'json', 'uuid', 'boolean')
|
|
487
470
|
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
471
|
+
Returns:
|
|
472
|
+
Database-specific type name
|
|
473
|
+
"""
|
|
474
|
+
|
|
475
|
+
def get_tables(self, driver: "SyncDriverAdapterBase", schema: "str | None" = None) -> "list[str]":
|
|
476
|
+
"""Get list of tables in schema.
|
|
477
|
+
|
|
478
|
+
Args:
|
|
479
|
+
driver: Sync database driver instance
|
|
480
|
+
schema: Schema name (None for default)
|
|
481
|
+
|
|
482
|
+
Returns:
|
|
483
|
+
List of table names
|
|
484
|
+
"""
|
|
485
|
+
_ = driver, schema
|
|
486
|
+
return []
|
|
487
|
+
|
|
488
|
+
def get_columns(
|
|
489
|
+
self, driver: "SyncDriverAdapterBase", table: str, schema: "str | None" = None
|
|
490
|
+
) -> "list[dict[str, Any]]":
|
|
491
|
+
"""Get column information for a table.
|
|
492
|
+
|
|
493
|
+
Args:
|
|
494
|
+
driver: Sync database driver instance
|
|
495
|
+
table: Table name
|
|
496
|
+
schema: Schema name (None for default)
|
|
497
|
+
|
|
498
|
+
Returns:
|
|
499
|
+
List of column metadata dictionaries
|
|
500
|
+
"""
|
|
501
|
+
_ = driver, table, schema
|
|
502
|
+
return []
|
|
503
|
+
|
|
504
|
+
def get_indexes(
|
|
505
|
+
self, driver: "SyncDriverAdapterBase", table: str, schema: "str | None" = None
|
|
506
|
+
) -> "list[dict[str, Any]]":
|
|
507
|
+
"""Get index information for a table.
|
|
508
|
+
|
|
509
|
+
Args:
|
|
510
|
+
driver: Sync database driver instance
|
|
511
|
+
table: Table name
|
|
512
|
+
schema: Schema name (None for default)
|
|
513
|
+
|
|
514
|
+
Returns:
|
|
515
|
+
List of index metadata dictionaries
|
|
516
|
+
"""
|
|
517
|
+
_ = driver, table, schema
|
|
518
|
+
return []
|
|
519
|
+
|
|
520
|
+
def list_available_features(self) -> "list[str]":
|
|
521
|
+
"""List all features that can be checked via get_feature_flag.
|
|
522
|
+
|
|
523
|
+
Returns:
|
|
524
|
+
List of feature names this data dictionary supports
|
|
525
|
+
"""
|
|
526
|
+
return self.get_default_features()
|