sqlspec 0.26.0__py3-none-any.whl → 0.28.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 +55 -25
- sqlspec/_typing.py +155 -52
- sqlspec/adapters/adbc/_types.py +1 -1
- sqlspec/adapters/adbc/adk/__init__.py +5 -0
- sqlspec/adapters/adbc/adk/store.py +880 -0
- sqlspec/adapters/adbc/config.py +62 -12
- sqlspec/adapters/adbc/data_dictionary.py +74 -2
- sqlspec/adapters/adbc/driver.py +226 -58
- sqlspec/adapters/adbc/litestar/__init__.py +5 -0
- sqlspec/adapters/adbc/litestar/store.py +504 -0
- sqlspec/adapters/adbc/type_converter.py +44 -50
- sqlspec/adapters/aiosqlite/_types.py +1 -1
- sqlspec/adapters/aiosqlite/adk/__init__.py +5 -0
- sqlspec/adapters/aiosqlite/adk/store.py +536 -0
- sqlspec/adapters/aiosqlite/config.py +86 -16
- sqlspec/adapters/aiosqlite/data_dictionary.py +34 -2
- sqlspec/adapters/aiosqlite/driver.py +127 -38
- 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 +1 -1
- sqlspec/adapters/asyncmy/adk/__init__.py +5 -0
- sqlspec/adapters/asyncmy/adk/store.py +503 -0
- sqlspec/adapters/asyncmy/config.py +59 -17
- sqlspec/adapters/asyncmy/data_dictionary.py +41 -2
- sqlspec/adapters/asyncmy/driver.py +293 -62
- 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 +460 -0
- sqlspec/adapters/asyncpg/config.py +57 -36
- sqlspec/adapters/asyncpg/data_dictionary.py +48 -2
- sqlspec/adapters/asyncpg/driver.py +153 -23
- 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 +585 -0
- sqlspec/adapters/bigquery/config.py +36 -11
- sqlspec/adapters/bigquery/data_dictionary.py +42 -2
- sqlspec/adapters/bigquery/driver.py +489 -144
- sqlspec/adapters/bigquery/litestar/__init__.py +5 -0
- sqlspec/adapters/bigquery/litestar/store.py +327 -0
- sqlspec/adapters/bigquery/type_converter.py +55 -23
- sqlspec/adapters/duckdb/_types.py +2 -2
- sqlspec/adapters/duckdb/adk/__init__.py +14 -0
- sqlspec/adapters/duckdb/adk/store.py +563 -0
- sqlspec/adapters/duckdb/config.py +79 -21
- sqlspec/adapters/duckdb/data_dictionary.py +41 -2
- sqlspec/adapters/duckdb/driver.py +225 -44
- sqlspec/adapters/duckdb/litestar/__init__.py +5 -0
- sqlspec/adapters/duckdb/litestar/store.py +332 -0
- sqlspec/adapters/duckdb/pool.py +5 -5
- sqlspec/adapters/duckdb/type_converter.py +51 -21
- 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 +1628 -0
- sqlspec/adapters/oracledb/config.py +120 -36
- sqlspec/adapters/oracledb/data_dictionary.py +87 -20
- sqlspec/adapters/oracledb/driver.py +475 -86
- sqlspec/adapters/oracledb/litestar/__init__.py +5 -0
- sqlspec/adapters/oracledb/litestar/store.py +765 -0
- sqlspec/adapters/oracledb/migrations.py +316 -25
- sqlspec/adapters/oracledb/type_converter.py +91 -16
- 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 +483 -0
- sqlspec/adapters/psqlpy/config.py +45 -19
- sqlspec/adapters/psqlpy/data_dictionary.py +48 -2
- sqlspec/adapters/psqlpy/driver.py +108 -41
- sqlspec/adapters/psqlpy/litestar/__init__.py +5 -0
- sqlspec/adapters/psqlpy/litestar/store.py +272 -0
- sqlspec/adapters/psqlpy/type_converter.py +40 -11
- 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 +962 -0
- sqlspec/adapters/psycopg/config.py +65 -37
- sqlspec/adapters/psycopg/data_dictionary.py +91 -3
- sqlspec/adapters/psycopg/driver.py +200 -78
- 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 +582 -0
- sqlspec/adapters/sqlite/config.py +85 -16
- sqlspec/adapters/sqlite/data_dictionary.py +34 -2
- sqlspec/adapters/sqlite/driver.py +120 -52
- sqlspec/adapters/sqlite/litestar/__init__.py +5 -0
- sqlspec/adapters/sqlite/litestar/store.py +318 -0
- sqlspec/adapters/sqlite/pool.py +5 -5
- sqlspec/base.py +45 -26
- sqlspec/builder/__init__.py +73 -4
- sqlspec/builder/_base.py +91 -58
- sqlspec/builder/_column.py +5 -5
- sqlspec/builder/_ddl.py +98 -89
- sqlspec/builder/_delete.py +5 -4
- sqlspec/builder/_dml.py +388 -0
- sqlspec/{_sql.py → builder/_factory.py} +41 -44
- sqlspec/builder/_insert.py +5 -82
- sqlspec/builder/{mixins/_join_operations.py → _join.py} +145 -143
- sqlspec/builder/_merge.py +446 -11
- sqlspec/builder/_parsing_utils.py +9 -11
- sqlspec/builder/_select.py +1313 -25
- sqlspec/builder/_update.py +11 -42
- sqlspec/cli.py +76 -69
- sqlspec/config.py +331 -62
- sqlspec/core/__init__.py +5 -4
- sqlspec/core/cache.py +18 -18
- sqlspec/core/compiler.py +6 -8
- sqlspec/core/filters.py +55 -47
- sqlspec/core/hashing.py +9 -9
- sqlspec/core/parameters.py +76 -45
- sqlspec/core/result.py +234 -47
- sqlspec/core/splitter.py +16 -17
- sqlspec/core/statement.py +32 -31
- sqlspec/core/type_conversion.py +3 -2
- sqlspec/driver/__init__.py +1 -3
- sqlspec/driver/_async.py +183 -160
- sqlspec/driver/_common.py +197 -109
- sqlspec/driver/_sync.py +189 -161
- sqlspec/driver/mixins/_result_tools.py +20 -236
- sqlspec/driver/mixins/_sql_translator.py +4 -4
- sqlspec/exceptions.py +70 -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 +69 -61
- sqlspec/extensions/fastapi/__init__.py +21 -0
- sqlspec/extensions/fastapi/extension.py +331 -0
- sqlspec/extensions/fastapi/providers.py +543 -0
- sqlspec/extensions/flask/__init__.py +36 -0
- sqlspec/extensions/flask/_state.py +71 -0
- sqlspec/extensions/flask/_utils.py +40 -0
- sqlspec/extensions/flask/extension.py +389 -0
- sqlspec/extensions/litestar/__init__.py +21 -4
- sqlspec/extensions/litestar/cli.py +54 -10
- sqlspec/extensions/litestar/config.py +56 -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 +349 -224
- sqlspec/extensions/litestar/providers.py +25 -25
- sqlspec/extensions/litestar/store.py +265 -0
- sqlspec/extensions/starlette/__init__.py +10 -0
- sqlspec/extensions/starlette/_state.py +25 -0
- sqlspec/extensions/starlette/_utils.py +52 -0
- sqlspec/extensions/starlette/extension.py +254 -0
- sqlspec/extensions/starlette/middleware.py +154 -0
- sqlspec/loader.py +30 -49
- sqlspec/migrations/base.py +200 -76
- sqlspec/migrations/commands.py +591 -62
- sqlspec/migrations/context.py +6 -9
- sqlspec/migrations/fix.py +199 -0
- sqlspec/migrations/loaders.py +47 -19
- sqlspec/migrations/runner.py +241 -75
- sqlspec/migrations/tracker.py +237 -21
- sqlspec/migrations/utils.py +51 -3
- sqlspec/migrations/validation.py +177 -0
- sqlspec/protocols.py +106 -36
- sqlspec/storage/_utils.py +85 -0
- sqlspec/storage/backends/fsspec.py +133 -107
- sqlspec/storage/backends/local.py +78 -51
- sqlspec/storage/backends/obstore.py +276 -168
- sqlspec/storage/registry.py +75 -39
- sqlspec/typing.py +30 -84
- sqlspec/utils/__init__.py +25 -4
- sqlspec/utils/arrow_helpers.py +81 -0
- sqlspec/utils/config_resolver.py +6 -6
- 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 +205 -5
- sqlspec/utils/portal.py +311 -0
- sqlspec/utils/schema.py +288 -0
- sqlspec/utils/serializers.py +113 -4
- sqlspec/utils/sync_tools.py +36 -22
- sqlspec/utils/text.py +1 -2
- sqlspec/utils/type_guards.py +136 -20
- sqlspec/utils/version.py +433 -0
- {sqlspec-0.26.0.dist-info → sqlspec-0.28.0.dist-info}/METADATA +41 -22
- sqlspec-0.28.0.dist-info/RECORD +221 -0
- sqlspec/builder/mixins/__init__.py +0 -55
- sqlspec/builder/mixins/_cte_and_set_ops.py +0 -253
- sqlspec/builder/mixins/_delete_operations.py +0 -50
- sqlspec/builder/mixins/_insert_operations.py +0 -282
- sqlspec/builder/mixins/_merge_operations.py +0 -698
- sqlspec/builder/mixins/_order_limit_operations.py +0 -145
- sqlspec/builder/mixins/_pivot_operations.py +0 -157
- sqlspec/builder/mixins/_select_operations.py +0 -930
- sqlspec/builder/mixins/_update_operations.py +0 -199
- sqlspec/builder/mixins/_where_clause.py +0 -1298
- sqlspec-0.26.0.dist-info/RECORD +0 -157
- sqlspec-0.26.0.dist-info/licenses/NOTICE +0 -29
- {sqlspec-0.26.0.dist-info → sqlspec-0.28.0.dist-info}/WHEEL +0 -0
- {sqlspec-0.26.0.dist-info → sqlspec-0.28.0.dist-info}/entry_points.txt +0 -0
- {sqlspec-0.26.0.dist-info → sqlspec-0.28.0.dist-info}/licenses/LICENSE +0 -0
sqlspec/driver/_sync.py
CHANGED
|
@@ -1,14 +1,22 @@
|
|
|
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.
|
|
8
|
-
from sqlspec.driver.
|
|
9
|
-
|
|
7
|
+
from sqlspec.core.result import create_arrow_result
|
|
8
|
+
from sqlspec.driver._common import (
|
|
9
|
+
CommonDriverAttributesMixin,
|
|
10
|
+
DataDictionaryMixin,
|
|
11
|
+
ExecutionResult,
|
|
12
|
+
VersionInfo,
|
|
13
|
+
handle_single_row_error,
|
|
14
|
+
)
|
|
15
|
+
from sqlspec.driver.mixins import SQLTranslatorMixin
|
|
16
|
+
from sqlspec.exceptions import ImproperConfigurationError
|
|
17
|
+
from sqlspec.utils.arrow_helpers import convert_dict_to_arrow
|
|
10
18
|
from sqlspec.utils.logging import get_logger
|
|
11
|
-
from sqlspec.utils.
|
|
19
|
+
from sqlspec.utils.module_loader import ensure_pyarrow
|
|
12
20
|
|
|
13
21
|
if TYPE_CHECKING:
|
|
14
22
|
from collections.abc import Sequence
|
|
@@ -16,7 +24,7 @@ if TYPE_CHECKING:
|
|
|
16
24
|
|
|
17
25
|
from sqlspec.builder import QueryBuilder
|
|
18
26
|
from sqlspec.core import SQLResult, Statement, StatementConfig, StatementFilter
|
|
19
|
-
from sqlspec.typing import
|
|
27
|
+
from sqlspec.typing import SchemaT, StatementParameters
|
|
20
28
|
|
|
21
29
|
_LOGGER_NAME: Final[str] = "sqlspec"
|
|
22
30
|
logger = get_logger(_LOGGER_NAME)
|
|
@@ -29,7 +37,7 @@ EMPTY_FILTERS: Final["list[StatementFilter]"] = []
|
|
|
29
37
|
SyncDriverT = TypeVar("SyncDriverT", bound="SyncDriverAdapterBase")
|
|
30
38
|
|
|
31
39
|
|
|
32
|
-
class SyncDriverAdapterBase(CommonDriverAttributesMixin, SQLTranslatorMixin
|
|
40
|
+
class SyncDriverAdapterBase(CommonDriverAttributesMixin, SQLTranslatorMixin):
|
|
33
41
|
"""Base class for synchronous database drivers."""
|
|
34
42
|
|
|
35
43
|
__slots__ = ()
|
|
@@ -96,7 +104,7 @@ class SyncDriverAdapterBase(CommonDriverAttributesMixin, SQLTranslatorMixin, ToS
|
|
|
96
104
|
"""Commit the current transaction on the current connection."""
|
|
97
105
|
|
|
98
106
|
@abstractmethod
|
|
99
|
-
def _try_special_handling(self, cursor: Any, statement: "SQL") -> "
|
|
107
|
+
def _try_special_handling(self, cursor: Any, statement: "SQL") -> "SQLResult | None":
|
|
100
108
|
"""Hook for database-specific special operations (e.g., PostgreSQL COPY, bulk operations).
|
|
101
109
|
|
|
102
110
|
This method is called first in dispatch_statement_execution() to allow drivers to handle
|
|
@@ -169,10 +177,10 @@ class SyncDriverAdapterBase(CommonDriverAttributesMixin, SQLTranslatorMixin, ToS
|
|
|
169
177
|
|
|
170
178
|
def execute(
|
|
171
179
|
self,
|
|
172
|
-
statement: "
|
|
180
|
+
statement: "SQL | Statement | QueryBuilder",
|
|
173
181
|
/,
|
|
174
|
-
*parameters: "
|
|
175
|
-
statement_config: "
|
|
182
|
+
*parameters: "StatementParameters | StatementFilter",
|
|
183
|
+
statement_config: "StatementConfig | None" = None,
|
|
176
184
|
**kwargs: Any,
|
|
177
185
|
) -> "SQLResult":
|
|
178
186
|
"""Execute a statement with parameter handling."""
|
|
@@ -183,11 +191,11 @@ class SyncDriverAdapterBase(CommonDriverAttributesMixin, SQLTranslatorMixin, ToS
|
|
|
183
191
|
|
|
184
192
|
def execute_many(
|
|
185
193
|
self,
|
|
186
|
-
statement: "
|
|
194
|
+
statement: "SQL | Statement | QueryBuilder",
|
|
187
195
|
/,
|
|
188
196
|
parameters: "Sequence[StatementParameters]",
|
|
189
|
-
*filters: "
|
|
190
|
-
statement_config: "
|
|
197
|
+
*filters: "StatementParameters | StatementFilter",
|
|
198
|
+
statement_config: "StatementConfig | None" = None,
|
|
191
199
|
**kwargs: Any,
|
|
192
200
|
) -> "SQLResult":
|
|
193
201
|
"""Execute statement multiple times with different parameters.
|
|
@@ -206,10 +214,10 @@ class SyncDriverAdapterBase(CommonDriverAttributesMixin, SQLTranslatorMixin, ToS
|
|
|
206
214
|
|
|
207
215
|
def execute_script(
|
|
208
216
|
self,
|
|
209
|
-
statement: "
|
|
217
|
+
statement: "str | SQL",
|
|
210
218
|
/,
|
|
211
|
-
*parameters: "
|
|
212
|
-
statement_config: "
|
|
219
|
+
*parameters: "StatementParameters | StatementFilter",
|
|
220
|
+
statement_config: "StatementConfig | None" = None,
|
|
213
221
|
**kwargs: Any,
|
|
214
222
|
) -> "SQLResult":
|
|
215
223
|
"""Execute a multi-statement script.
|
|
@@ -225,140 +233,215 @@ class SyncDriverAdapterBase(CommonDriverAttributesMixin, SQLTranslatorMixin, ToS
|
|
|
225
233
|
@overload
|
|
226
234
|
def select_one(
|
|
227
235
|
self,
|
|
228
|
-
statement: "
|
|
236
|
+
statement: "Statement | QueryBuilder",
|
|
229
237
|
/,
|
|
230
|
-
*parameters: "
|
|
231
|
-
schema_type: "type[
|
|
232
|
-
statement_config: "
|
|
238
|
+
*parameters: "StatementParameters | StatementFilter",
|
|
239
|
+
schema_type: "type[SchemaT]",
|
|
240
|
+
statement_config: "StatementConfig | None" = None,
|
|
233
241
|
**kwargs: Any,
|
|
234
|
-
) -> "
|
|
242
|
+
) -> "SchemaT": ...
|
|
235
243
|
|
|
236
244
|
@overload
|
|
237
245
|
def select_one(
|
|
238
246
|
self,
|
|
239
|
-
statement: "
|
|
247
|
+
statement: "Statement | QueryBuilder",
|
|
240
248
|
/,
|
|
241
|
-
*parameters: "
|
|
249
|
+
*parameters: "StatementParameters | StatementFilter",
|
|
242
250
|
schema_type: None = None,
|
|
243
|
-
statement_config: "
|
|
251
|
+
statement_config: "StatementConfig | None" = None,
|
|
244
252
|
**kwargs: Any,
|
|
245
253
|
) -> "dict[str, Any]": ...
|
|
246
254
|
|
|
247
255
|
def select_one(
|
|
248
256
|
self,
|
|
249
|
-
statement: "
|
|
257
|
+
statement: "Statement | QueryBuilder",
|
|
250
258
|
/,
|
|
251
|
-
*parameters: "
|
|
252
|
-
schema_type: "
|
|
253
|
-
statement_config: "
|
|
259
|
+
*parameters: "StatementParameters | StatementFilter",
|
|
260
|
+
schema_type: "type[SchemaT] | None" = None,
|
|
261
|
+
statement_config: "StatementConfig | None" = None,
|
|
254
262
|
**kwargs: Any,
|
|
255
|
-
) -> "
|
|
263
|
+
) -> "SchemaT | dict[str, Any]":
|
|
256
264
|
"""Execute a select statement and return exactly one row.
|
|
257
265
|
|
|
258
266
|
Raises an exception if no rows or more than one row is returned.
|
|
259
267
|
"""
|
|
260
268
|
result = self.execute(statement, *parameters, statement_config=statement_config, **kwargs)
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
if data_len > 1:
|
|
266
|
-
self._raise_expected_one_row(data_len)
|
|
267
|
-
first_row = data[0]
|
|
268
|
-
return self.to_schema(first_row, schema_type=schema_type) if schema_type else first_row
|
|
269
|
+
try:
|
|
270
|
+
return result.one(schema_type=schema_type)
|
|
271
|
+
except ValueError as error:
|
|
272
|
+
handle_single_row_error(error)
|
|
269
273
|
|
|
270
274
|
@overload
|
|
271
275
|
def select_one_or_none(
|
|
272
276
|
self,
|
|
273
|
-
statement: "
|
|
277
|
+
statement: "Statement | QueryBuilder",
|
|
274
278
|
/,
|
|
275
|
-
*parameters: "
|
|
276
|
-
schema_type: "type[
|
|
277
|
-
statement_config: "
|
|
279
|
+
*parameters: "StatementParameters | StatementFilter",
|
|
280
|
+
schema_type: "type[SchemaT]",
|
|
281
|
+
statement_config: "StatementConfig | None" = None,
|
|
278
282
|
**kwargs: Any,
|
|
279
|
-
) -> "
|
|
283
|
+
) -> "SchemaT | None": ...
|
|
280
284
|
|
|
281
285
|
@overload
|
|
282
286
|
def select_one_or_none(
|
|
283
287
|
self,
|
|
284
|
-
statement: "
|
|
288
|
+
statement: "Statement | QueryBuilder",
|
|
285
289
|
/,
|
|
286
|
-
*parameters: "
|
|
290
|
+
*parameters: "StatementParameters | StatementFilter",
|
|
287
291
|
schema_type: None = None,
|
|
288
|
-
statement_config: "
|
|
292
|
+
statement_config: "StatementConfig | None" = None,
|
|
289
293
|
**kwargs: Any,
|
|
290
|
-
) -> "
|
|
294
|
+
) -> "dict[str, Any] | None": ...
|
|
291
295
|
|
|
292
296
|
def select_one_or_none(
|
|
293
297
|
self,
|
|
294
|
-
statement: "
|
|
298
|
+
statement: "Statement | QueryBuilder",
|
|
295
299
|
/,
|
|
296
|
-
*parameters: "
|
|
297
|
-
schema_type: "
|
|
298
|
-
statement_config: "
|
|
300
|
+
*parameters: "StatementParameters | StatementFilter",
|
|
301
|
+
schema_type: "type[SchemaT] | None" = None,
|
|
302
|
+
statement_config: "StatementConfig | None" = None,
|
|
299
303
|
**kwargs: Any,
|
|
300
|
-
) -> "
|
|
304
|
+
) -> "SchemaT | dict[str, Any] | None":
|
|
301
305
|
"""Execute a select statement and return at most one row.
|
|
302
306
|
|
|
303
307
|
Returns None if no rows are found.
|
|
304
308
|
Raises an exception if more than one row is returned.
|
|
305
309
|
"""
|
|
306
310
|
result = self.execute(statement, *parameters, statement_config=statement_config, **kwargs)
|
|
307
|
-
|
|
308
|
-
data_len: int = len(data)
|
|
309
|
-
if data_len == 0:
|
|
310
|
-
return None
|
|
311
|
-
if data_len > 1:
|
|
312
|
-
self._raise_expected_at_most_one_row(data_len)
|
|
313
|
-
first_row = data[0]
|
|
314
|
-
return cast(
|
|
315
|
-
"Optional[Union[dict[str, Any], ModelDTOT]]",
|
|
316
|
-
self.to_schema(first_row, schema_type=schema_type) if schema_type else first_row,
|
|
317
|
-
)
|
|
311
|
+
return result.one_or_none(schema_type=schema_type)
|
|
318
312
|
|
|
319
313
|
@overload
|
|
320
314
|
def select(
|
|
321
315
|
self,
|
|
322
|
-
statement: "
|
|
316
|
+
statement: "Statement | QueryBuilder",
|
|
323
317
|
/,
|
|
324
|
-
*parameters: "
|
|
325
|
-
schema_type: "type[
|
|
326
|
-
statement_config: "
|
|
318
|
+
*parameters: "StatementParameters | StatementFilter",
|
|
319
|
+
schema_type: "type[SchemaT]",
|
|
320
|
+
statement_config: "StatementConfig | None" = None,
|
|
327
321
|
**kwargs: Any,
|
|
328
|
-
) -> "list[
|
|
322
|
+
) -> "list[SchemaT]": ...
|
|
329
323
|
|
|
330
324
|
@overload
|
|
331
325
|
def select(
|
|
332
326
|
self,
|
|
333
|
-
statement: "
|
|
327
|
+
statement: "Statement | QueryBuilder",
|
|
334
328
|
/,
|
|
335
|
-
*parameters: "
|
|
329
|
+
*parameters: "StatementParameters | StatementFilter",
|
|
336
330
|
schema_type: None = None,
|
|
337
|
-
statement_config: "
|
|
331
|
+
statement_config: "StatementConfig | None" = None,
|
|
338
332
|
**kwargs: Any,
|
|
339
333
|
) -> "list[dict[str, Any]]": ...
|
|
340
334
|
|
|
341
335
|
def select(
|
|
342
336
|
self,
|
|
343
|
-
statement: "
|
|
337
|
+
statement: "Statement | QueryBuilder",
|
|
344
338
|
/,
|
|
345
|
-
*parameters: "
|
|
346
|
-
schema_type: "
|
|
347
|
-
statement_config: "
|
|
339
|
+
*parameters: "StatementParameters | StatementFilter",
|
|
340
|
+
schema_type: "type[SchemaT] | None" = None,
|
|
341
|
+
statement_config: "StatementConfig | None" = None,
|
|
348
342
|
**kwargs: Any,
|
|
349
|
-
) -> "
|
|
343
|
+
) -> "list[SchemaT] | list[dict[str, Any]]":
|
|
350
344
|
"""Execute a select statement and return all rows."""
|
|
351
345
|
result = self.execute(statement, *parameters, statement_config=statement_config, **kwargs)
|
|
352
|
-
return
|
|
353
|
-
|
|
346
|
+
return result.get_data(schema_type=schema_type)
|
|
347
|
+
|
|
348
|
+
def select_to_arrow(
|
|
349
|
+
self,
|
|
350
|
+
statement: "Statement | QueryBuilder",
|
|
351
|
+
/,
|
|
352
|
+
*parameters: "StatementParameters | StatementFilter",
|
|
353
|
+
statement_config: "StatementConfig | None" = None,
|
|
354
|
+
return_format: str = "table",
|
|
355
|
+
native_only: bool = False,
|
|
356
|
+
batch_size: int | None = None,
|
|
357
|
+
arrow_schema: Any = None,
|
|
358
|
+
**kwargs: Any,
|
|
359
|
+
) -> "Any":
|
|
360
|
+
"""Execute query and return results as Apache Arrow format.
|
|
361
|
+
|
|
362
|
+
This base implementation uses the conversion path: execute() → dict → Arrow.
|
|
363
|
+
Adapters with native Arrow support (ADBC, DuckDB, BigQuery) override this
|
|
364
|
+
method to use zero-copy native paths for 5-10x performance improvement.
|
|
365
|
+
|
|
366
|
+
Args:
|
|
367
|
+
statement: SQL query string, Statement, or QueryBuilder
|
|
368
|
+
*parameters: Query parameters (same format as execute()/select())
|
|
369
|
+
statement_config: Optional statement configuration override
|
|
370
|
+
return_format: "table" for pyarrow.Table (default), "reader" for RecordBatchReader,
|
|
371
|
+
"batches" for iterator of RecordBatches
|
|
372
|
+
native_only: If True, raise error if native Arrow unavailable (default: False)
|
|
373
|
+
batch_size: Rows per batch for "batches" format (default: None = all rows)
|
|
374
|
+
arrow_schema: Optional pyarrow.Schema for type casting
|
|
375
|
+
**kwargs: Additional keyword arguments
|
|
376
|
+
|
|
377
|
+
Returns:
|
|
378
|
+
ArrowResult containing pyarrow.Table, RecordBatchReader, or RecordBatches
|
|
379
|
+
|
|
380
|
+
Raises:
|
|
381
|
+
MissingDependencyError: If pyarrow not installed
|
|
382
|
+
ImproperConfigurationError: If native_only=True and adapter doesn't support native Arrow
|
|
383
|
+
SQLExecutionError: If query execution fails
|
|
384
|
+
|
|
385
|
+
Examples:
|
|
386
|
+
>>> result = driver.select_to_arrow(
|
|
387
|
+
... "SELECT * FROM users WHERE age > ?", 18
|
|
388
|
+
... )
|
|
389
|
+
>>> df = result.to_pandas()
|
|
390
|
+
>>> print(df.head())
|
|
391
|
+
|
|
392
|
+
>>> # Force native Arrow path (raises error if unavailable)
|
|
393
|
+
>>> result = driver.select_to_arrow(
|
|
394
|
+
... "SELECT * FROM users", native_only=True
|
|
395
|
+
... )
|
|
396
|
+
"""
|
|
397
|
+
# Check pyarrow is available
|
|
398
|
+
ensure_pyarrow()
|
|
399
|
+
|
|
400
|
+
# Check if native_only requested but not supported
|
|
401
|
+
if native_only:
|
|
402
|
+
msg = (
|
|
403
|
+
f"Adapter '{self.__class__.__name__}' does not support native Arrow results. "
|
|
404
|
+
f"Use native_only=False to allow conversion path, or switch to an adapter "
|
|
405
|
+
f"with native Arrow support (ADBC, DuckDB, BigQuery)."
|
|
406
|
+
)
|
|
407
|
+
raise ImproperConfigurationError(msg)
|
|
408
|
+
|
|
409
|
+
# Execute query using standard path
|
|
410
|
+
result = self.execute(statement, *parameters, statement_config=statement_config, **kwargs)
|
|
411
|
+
|
|
412
|
+
# Convert dict results to Arrow
|
|
413
|
+
arrow_data = convert_dict_to_arrow(
|
|
414
|
+
result.data,
|
|
415
|
+
return_format=return_format, # type: ignore[arg-type]
|
|
416
|
+
batch_size=batch_size,
|
|
417
|
+
)
|
|
418
|
+
|
|
419
|
+
# Apply schema casting if requested
|
|
420
|
+
if arrow_schema is not None:
|
|
421
|
+
import pyarrow as pa
|
|
422
|
+
|
|
423
|
+
if not isinstance(arrow_schema, pa.Schema):
|
|
424
|
+
msg = f"arrow_schema must be a pyarrow.Schema, got {type(arrow_schema).__name__}"
|
|
425
|
+
raise TypeError(msg)
|
|
426
|
+
|
|
427
|
+
arrow_data = arrow_data.cast(arrow_schema)
|
|
428
|
+
|
|
429
|
+
# Create ArrowResult
|
|
430
|
+
return create_arrow_result(
|
|
431
|
+
statement=result.statement,
|
|
432
|
+
data=arrow_data,
|
|
433
|
+
rows_affected=result.rows_affected,
|
|
434
|
+
last_inserted_id=result.last_inserted_id,
|
|
435
|
+
execution_time=result.execution_time,
|
|
436
|
+
metadata=result.metadata,
|
|
354
437
|
)
|
|
355
438
|
|
|
356
439
|
def select_value(
|
|
357
440
|
self,
|
|
358
|
-
statement: "
|
|
441
|
+
statement: "Statement | QueryBuilder",
|
|
359
442
|
/,
|
|
360
|
-
*parameters: "
|
|
361
|
-
statement_config: "
|
|
443
|
+
*parameters: "StatementParameters | StatementFilter",
|
|
444
|
+
statement_config: "StatementConfig | None" = None,
|
|
362
445
|
**kwargs: Any,
|
|
363
446
|
) -> Any:
|
|
364
447
|
"""Execute a select statement and return a single scalar value.
|
|
@@ -368,28 +451,16 @@ class SyncDriverAdapterBase(CommonDriverAttributesMixin, SQLTranslatorMixin, ToS
|
|
|
368
451
|
"""
|
|
369
452
|
result = self.execute(statement, *parameters, statement_config=statement_config, **kwargs)
|
|
370
453
|
try:
|
|
371
|
-
|
|
372
|
-
except ValueError as
|
|
373
|
-
|
|
374
|
-
if not row:
|
|
375
|
-
self._raise_no_rows_found()
|
|
376
|
-
if is_dict_row(row):
|
|
377
|
-
if not row:
|
|
378
|
-
self._raise_row_no_columns()
|
|
379
|
-
return next(iter(row.values()))
|
|
380
|
-
if is_indexable_row(row):
|
|
381
|
-
if not row:
|
|
382
|
-
self._raise_row_no_columns()
|
|
383
|
-
return row[0]
|
|
384
|
-
self._raise_unexpected_row_type(type(row))
|
|
385
|
-
return None
|
|
454
|
+
return result.scalar()
|
|
455
|
+
except ValueError as error:
|
|
456
|
+
handle_single_row_error(error)
|
|
386
457
|
|
|
387
458
|
def select_value_or_none(
|
|
388
459
|
self,
|
|
389
|
-
statement: "
|
|
460
|
+
statement: "Statement | QueryBuilder",
|
|
390
461
|
/,
|
|
391
|
-
*parameters: "
|
|
392
|
-
statement_config: "
|
|
462
|
+
*parameters: "StatementParameters | StatementFilter",
|
|
463
|
+
statement_config: "StatementConfig | None" = None,
|
|
393
464
|
**kwargs: Any,
|
|
394
465
|
) -> Any:
|
|
395
466
|
"""Execute a select statement and return a single scalar value or None.
|
|
@@ -399,54 +470,39 @@ class SyncDriverAdapterBase(CommonDriverAttributesMixin, SQLTranslatorMixin, ToS
|
|
|
399
470
|
Raises an exception if more than one row is returned.
|
|
400
471
|
"""
|
|
401
472
|
result = self.execute(statement, *parameters, statement_config=statement_config, **kwargs)
|
|
402
|
-
|
|
403
|
-
data_len: int = len(data)
|
|
404
|
-
if data_len == 0:
|
|
405
|
-
return None
|
|
406
|
-
if data_len > 1:
|
|
407
|
-
msg = f"Expected at most one row, found {data_len}"
|
|
408
|
-
raise ValueError(msg)
|
|
409
|
-
row = data[0]
|
|
410
|
-
if isinstance(row, dict):
|
|
411
|
-
if not row:
|
|
412
|
-
return None
|
|
413
|
-
return next(iter(row.values()))
|
|
414
|
-
if isinstance(row, (tuple, list)):
|
|
415
|
-
return row[0]
|
|
416
|
-
msg = f"Cannot extract value from row type {type(row).__name__}"
|
|
417
|
-
raise TypeError(msg)
|
|
473
|
+
return result.scalar_or_none()
|
|
418
474
|
|
|
419
475
|
@overload
|
|
420
476
|
def select_with_total(
|
|
421
477
|
self,
|
|
422
|
-
statement: "
|
|
478
|
+
statement: "Statement | QueryBuilder",
|
|
423
479
|
/,
|
|
424
|
-
*parameters: "
|
|
425
|
-
schema_type: "type[
|
|
426
|
-
statement_config: "
|
|
480
|
+
*parameters: "StatementParameters | StatementFilter",
|
|
481
|
+
schema_type: "type[SchemaT]",
|
|
482
|
+
statement_config: "StatementConfig | None" = None,
|
|
427
483
|
**kwargs: Any,
|
|
428
|
-
) -> "tuple[list[
|
|
484
|
+
) -> "tuple[list[SchemaT], int]": ...
|
|
429
485
|
|
|
430
486
|
@overload
|
|
431
487
|
def select_with_total(
|
|
432
488
|
self,
|
|
433
|
-
statement: "
|
|
489
|
+
statement: "Statement | QueryBuilder",
|
|
434
490
|
/,
|
|
435
|
-
*parameters: "
|
|
491
|
+
*parameters: "StatementParameters | StatementFilter",
|
|
436
492
|
schema_type: None = None,
|
|
437
|
-
statement_config: "
|
|
493
|
+
statement_config: "StatementConfig | None" = None,
|
|
438
494
|
**kwargs: Any,
|
|
439
495
|
) -> "tuple[list[dict[str, Any]], int]": ...
|
|
440
496
|
|
|
441
497
|
def select_with_total(
|
|
442
498
|
self,
|
|
443
|
-
statement: "
|
|
499
|
+
statement: "Statement | QueryBuilder",
|
|
444
500
|
/,
|
|
445
|
-
*parameters: "
|
|
446
|
-
schema_type: "
|
|
447
|
-
statement_config: "
|
|
501
|
+
*parameters: "StatementParameters | StatementFilter",
|
|
502
|
+
schema_type: "type[SchemaT] | None" = None,
|
|
503
|
+
statement_config: "StatementConfig | None" = None,
|
|
448
504
|
**kwargs: Any,
|
|
449
|
-
) -> "tuple[
|
|
505
|
+
) -> "tuple[list[SchemaT] | list[dict[str, Any]], int]":
|
|
450
506
|
"""Execute a select statement and return both the data and total count.
|
|
451
507
|
|
|
452
508
|
This method is designed for pagination scenarios where you need both
|
|
@@ -470,42 +526,14 @@ class SyncDriverAdapterBase(CommonDriverAttributesMixin, SQLTranslatorMixin, ToS
|
|
|
470
526
|
count_result = self.dispatch_statement_execution(self._create_count_query(sql_statement), self.connection)
|
|
471
527
|
select_result = self.execute(sql_statement)
|
|
472
528
|
|
|
473
|
-
return (
|
|
474
|
-
|
|
475
|
-
def _raise_no_rows_found(self) -> NoReturn:
|
|
476
|
-
msg = "No rows found"
|
|
477
|
-
raise NotFoundError(msg)
|
|
478
|
-
|
|
479
|
-
def _raise_no_rows_found_from_exception(self, e: ValueError) -> NoReturn:
|
|
480
|
-
msg = "No rows found"
|
|
481
|
-
raise NotFoundError(msg) from e
|
|
482
|
-
|
|
483
|
-
def _raise_expected_one_row(self, data_len: int) -> NoReturn:
|
|
484
|
-
msg = f"Expected exactly one row, found {data_len}"
|
|
485
|
-
raise ValueError(msg)
|
|
486
|
-
|
|
487
|
-
def _raise_expected_at_most_one_row(self, data_len: int) -> NoReturn:
|
|
488
|
-
msg = f"Expected at most one row, found {data_len}"
|
|
489
|
-
raise ValueError(msg)
|
|
490
|
-
|
|
491
|
-
def _raise_row_no_columns(self) -> NoReturn:
|
|
492
|
-
msg = "Row has no columns"
|
|
493
|
-
raise ValueError(msg)
|
|
494
|
-
|
|
495
|
-
def _raise_unexpected_row_type(self, row_type: type) -> NoReturn:
|
|
496
|
-
msg = f"Unexpected row type: {row_type}"
|
|
497
|
-
raise ValueError(msg)
|
|
498
|
-
|
|
499
|
-
def _raise_cannot_extract_value_from_row_type(self, type_name: str) -> NoReturn:
|
|
500
|
-
msg = f"Cannot extract value from row type {type_name}"
|
|
501
|
-
raise TypeError(msg)
|
|
529
|
+
return (select_result.get_data(schema_type=schema_type), count_result.scalar())
|
|
502
530
|
|
|
503
531
|
|
|
504
532
|
class SyncDataDictionaryBase(DataDictionaryMixin):
|
|
505
533
|
"""Base class for synchronous data dictionary implementations."""
|
|
506
534
|
|
|
507
535
|
@abstractmethod
|
|
508
|
-
def get_version(self, driver: "SyncDriverAdapterBase") -> "
|
|
536
|
+
def get_version(self, driver: "SyncDriverAdapterBase") -> "VersionInfo | None":
|
|
509
537
|
"""Get database version information.
|
|
510
538
|
|
|
511
539
|
Args:
|
|
@@ -539,7 +567,7 @@ class SyncDataDictionaryBase(DataDictionaryMixin):
|
|
|
539
567
|
Database-specific type name
|
|
540
568
|
"""
|
|
541
569
|
|
|
542
|
-
def get_tables(self, driver: "SyncDriverAdapterBase", schema: "
|
|
570
|
+
def get_tables(self, driver: "SyncDriverAdapterBase", schema: "str | None" = None) -> "list[str]":
|
|
543
571
|
"""Get list of tables in schema.
|
|
544
572
|
|
|
545
573
|
Args:
|
|
@@ -553,7 +581,7 @@ class SyncDataDictionaryBase(DataDictionaryMixin):
|
|
|
553
581
|
return []
|
|
554
582
|
|
|
555
583
|
def get_columns(
|
|
556
|
-
self, driver: "SyncDriverAdapterBase", table: str, schema: "
|
|
584
|
+
self, driver: "SyncDriverAdapterBase", table: str, schema: "str | None" = None
|
|
557
585
|
) -> "list[dict[str, Any]]":
|
|
558
586
|
"""Get column information for a table.
|
|
559
587
|
|
|
@@ -569,7 +597,7 @@ class SyncDataDictionaryBase(DataDictionaryMixin):
|
|
|
569
597
|
return []
|
|
570
598
|
|
|
571
599
|
def get_indexes(
|
|
572
|
-
self, driver: "SyncDriverAdapterBase", table: str, schema: "
|
|
600
|
+
self, driver: "SyncDriverAdapterBase", table: str, schema: "str | None" = None
|
|
573
601
|
) -> "list[dict[str, Any]]":
|
|
574
602
|
"""Get index information for a table.
|
|
575
603
|
|