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/core/result.py
CHANGED
|
@@ -10,17 +10,20 @@ Classes:
|
|
|
10
10
|
"""
|
|
11
11
|
|
|
12
12
|
from abc import ABC, abstractmethod
|
|
13
|
-
from typing import TYPE_CHECKING, Any, Optional,
|
|
13
|
+
from typing import TYPE_CHECKING, Any, Optional, cast, overload
|
|
14
14
|
|
|
15
15
|
from mypy_extensions import mypyc_attr
|
|
16
16
|
from typing_extensions import TypeVar
|
|
17
17
|
|
|
18
18
|
from sqlspec.core.compiler import OperationType
|
|
19
|
+
from sqlspec.utils.module_loader import ensure_pandas, ensure_polars, ensure_pyarrow
|
|
20
|
+
from sqlspec.utils.schema import to_schema
|
|
19
21
|
|
|
20
22
|
if TYPE_CHECKING:
|
|
21
23
|
from collections.abc import Iterator
|
|
22
24
|
|
|
23
25
|
from sqlspec.core.statement import SQL
|
|
26
|
+
from sqlspec.typing import ArrowTable, PandasDataFrame, PolarsDataFrame, SchemaT
|
|
24
27
|
|
|
25
28
|
|
|
26
29
|
__all__ = ("ArrowResult", "SQLResult", "StatementResult")
|
|
@@ -52,8 +55,8 @@ class StatementResult(ABC):
|
|
|
52
55
|
statement: "SQL",
|
|
53
56
|
data: Any = None,
|
|
54
57
|
rows_affected: int = 0,
|
|
55
|
-
last_inserted_id:
|
|
56
|
-
execution_time:
|
|
58
|
+
last_inserted_id: int | str | None = None,
|
|
59
|
+
execution_time: float | None = None,
|
|
57
60
|
metadata: Optional["dict[str, Any]"] = None,
|
|
58
61
|
) -> None:
|
|
59
62
|
"""Initialize statement result.
|
|
@@ -129,19 +132,6 @@ class SQLResult(StatementResult):
|
|
|
129
132
|
The operation_type attribute indicates the nature of the operation.
|
|
130
133
|
|
|
131
134
|
For script execution, tracks multiple statement results and errors.
|
|
132
|
-
|
|
133
|
-
Attributes:
|
|
134
|
-
column_names: Names of columns in the result set.
|
|
135
|
-
error: Exception that occurred during execution.
|
|
136
|
-
errors: List of error messages for script execution.
|
|
137
|
-
has_more: Whether there are additional result pages available.
|
|
138
|
-
inserted_ids: List of IDs from INSERT operations.
|
|
139
|
-
operation_index: Index of operation in a script.
|
|
140
|
-
parameters: Parameters used for the query.
|
|
141
|
-
statement_results: Results from individual statements in a script.
|
|
142
|
-
successful_statements: Count of successful statements in a script.
|
|
143
|
-
total_count: Total number of rows in the complete result set.
|
|
144
|
-
total_statements: Total number of statements in a script.
|
|
145
135
|
"""
|
|
146
136
|
|
|
147
137
|
__slots__ = (
|
|
@@ -164,19 +154,19 @@ class SQLResult(StatementResult):
|
|
|
164
154
|
def __init__(
|
|
165
155
|
self,
|
|
166
156
|
statement: "SQL",
|
|
167
|
-
data:
|
|
157
|
+
data: list[dict[str, Any]] | None = None,
|
|
168
158
|
rows_affected: int = 0,
|
|
169
|
-
last_inserted_id:
|
|
170
|
-
execution_time:
|
|
159
|
+
last_inserted_id: int | str | None = None,
|
|
160
|
+
execution_time: float | None = None,
|
|
171
161
|
metadata: Optional["dict[str, Any]"] = None,
|
|
172
|
-
error:
|
|
162
|
+
error: Exception | None = None,
|
|
173
163
|
operation_type: OperationType = "SELECT",
|
|
174
|
-
operation_index:
|
|
175
|
-
parameters:
|
|
164
|
+
operation_index: int | None = None,
|
|
165
|
+
parameters: Any | None = None,
|
|
176
166
|
column_names: Optional["list[str]"] = None,
|
|
177
|
-
total_count:
|
|
167
|
+
total_count: int | None = None,
|
|
178
168
|
has_more: bool = False,
|
|
179
|
-
inserted_ids: Optional["list[
|
|
169
|
+
inserted_ids: Optional["list[int | str]"] = None,
|
|
180
170
|
statement_results: Optional["list[SQLResult]"] = None,
|
|
181
171
|
errors: Optional["list[str]"] = None,
|
|
182
172
|
total_statements: int = 0,
|
|
@@ -280,15 +270,25 @@ class SQLResult(StatementResult):
|
|
|
280
270
|
|
|
281
271
|
return False
|
|
282
272
|
|
|
283
|
-
|
|
273
|
+
@overload
|
|
274
|
+
def get_data(self, *, schema_type: "type[SchemaT]") -> "list[SchemaT]": ...
|
|
275
|
+
|
|
276
|
+
@overload
|
|
277
|
+
def get_data(self, *, schema_type: None = None) -> "list[dict[str, Any]]": ...
|
|
278
|
+
|
|
279
|
+
def get_data(self, *, schema_type: "type[SchemaT] | None" = None) -> "list[SchemaT] | list[dict[str, Any]]":
|
|
284
280
|
"""Get the data from the result.
|
|
285
281
|
|
|
286
282
|
For regular operations, returns the list of rows.
|
|
287
283
|
For script operations, returns a summary dictionary containing
|
|
288
284
|
execution statistics and results.
|
|
289
285
|
|
|
286
|
+
Args:
|
|
287
|
+
schema_type: Optional schema type to transform the data into.
|
|
288
|
+
Supports Pydantic models, dataclasses, msgspec structs, attrs classes, and TypedDict.
|
|
289
|
+
|
|
290
290
|
Returns:
|
|
291
|
-
List of result rows or script summary.
|
|
291
|
+
List of result rows (optionally transformed to schema_type) or script summary.
|
|
292
292
|
"""
|
|
293
293
|
op_type_upper = self.operation_type.upper()
|
|
294
294
|
if op_type_upper == "SCRIPT":
|
|
@@ -303,7 +303,10 @@ class SQLResult(StatementResult):
|
|
|
303
303
|
"total_rows_affected": self.get_total_rows_affected(),
|
|
304
304
|
}
|
|
305
305
|
]
|
|
306
|
-
|
|
306
|
+
data = cast("list[dict[str, Any]]", self.data or [])
|
|
307
|
+
if schema_type:
|
|
308
|
+
return cast("list[SchemaT]", to_schema(data, schema_type=schema_type))
|
|
309
|
+
return data
|
|
307
310
|
|
|
308
311
|
def add_statement_result(self, result: "SQLResult") -> None:
|
|
309
312
|
"""Add a statement result to the script execution results.
|
|
@@ -348,13 +351,28 @@ class SQLResult(StatementResult):
|
|
|
348
351
|
"""
|
|
349
352
|
return len(self.column_names) if self.column_names else 0
|
|
350
353
|
|
|
351
|
-
|
|
354
|
+
@overload
|
|
355
|
+
def get_first(self, *, schema_type: "type[SchemaT]") -> "SchemaT | None": ...
|
|
356
|
+
|
|
357
|
+
@overload
|
|
358
|
+
def get_first(self, *, schema_type: None = None) -> "dict[str, Any] | None": ...
|
|
359
|
+
|
|
360
|
+
def get_first(self, *, schema_type: "type[SchemaT] | None" = None) -> "SchemaT | dict[str, Any] | None":
|
|
352
361
|
"""Get the first row from the result, if any.
|
|
353
362
|
|
|
363
|
+
Args:
|
|
364
|
+
schema_type: Optional schema type to transform the data into.
|
|
365
|
+
Supports Pydantic models, dataclasses, msgspec structs, attrs classes, and TypedDict.
|
|
366
|
+
|
|
354
367
|
Returns:
|
|
355
|
-
First row or None if no data.
|
|
368
|
+
First row (optionally transformed to schema_type) or None if no data.
|
|
356
369
|
"""
|
|
357
|
-
|
|
370
|
+
if not self.data:
|
|
371
|
+
return None
|
|
372
|
+
row = cast("dict[str, Any]", self.data[0])
|
|
373
|
+
if schema_type:
|
|
374
|
+
return to_schema(row, schema_type=schema_type)
|
|
375
|
+
return row
|
|
358
376
|
|
|
359
377
|
def get_count(self) -> int:
|
|
360
378
|
"""Get the number of rows in the current result set (e.g., a page of data).
|
|
@@ -434,19 +452,42 @@ class SQLResult(StatementResult):
|
|
|
434
452
|
"""
|
|
435
453
|
return iter(self.data or [])
|
|
436
454
|
|
|
437
|
-
|
|
455
|
+
@overload
|
|
456
|
+
def all(self, *, schema_type: "type[SchemaT]") -> "list[SchemaT]": ...
|
|
457
|
+
|
|
458
|
+
@overload
|
|
459
|
+
def all(self, *, schema_type: None = None) -> list[dict[str, Any]]: ...
|
|
460
|
+
|
|
461
|
+
def all(self, *, schema_type: "type[SchemaT] | None" = None) -> "list[SchemaT] | list[dict[str, Any]]":
|
|
438
462
|
"""Return all rows as a list.
|
|
439
463
|
|
|
464
|
+
Args:
|
|
465
|
+
schema_type: Optional schema type to transform the data into.
|
|
466
|
+
Supports Pydantic models, dataclasses, msgspec structs, attrs classes, and TypedDict.
|
|
467
|
+
|
|
440
468
|
Returns:
|
|
441
|
-
List of all rows
|
|
469
|
+
List of all rows (optionally transformed to schema_type)
|
|
442
470
|
"""
|
|
443
|
-
|
|
471
|
+
data = cast("list[dict[str, Any]]", self.data or [])
|
|
472
|
+
if schema_type:
|
|
473
|
+
return cast("list[SchemaT]", to_schema(data, schema_type=schema_type))
|
|
474
|
+
return data
|
|
475
|
+
|
|
476
|
+
@overload
|
|
477
|
+
def one(self, *, schema_type: "type[SchemaT]") -> "SchemaT": ...
|
|
478
|
+
|
|
479
|
+
@overload
|
|
480
|
+
def one(self, *, schema_type: None = None) -> "dict[str, Any]": ...
|
|
444
481
|
|
|
445
|
-
def one(self) -> "dict[str, Any]":
|
|
482
|
+
def one(self, *, schema_type: "type[SchemaT] | None" = None) -> "SchemaT | dict[str, Any]":
|
|
446
483
|
"""Return exactly one row.
|
|
447
484
|
|
|
485
|
+
Args:
|
|
486
|
+
schema_type: Optional schema type to transform the data into.
|
|
487
|
+
Supports Pydantic models, dataclasses, msgspec structs, attrs classes, and TypedDict.
|
|
488
|
+
|
|
448
489
|
Returns:
|
|
449
|
-
The single row
|
|
490
|
+
The single row (optionally transformed to schema_type)
|
|
450
491
|
|
|
451
492
|
Raises:
|
|
452
493
|
ValueError: If no results or more than one result
|
|
@@ -463,13 +504,26 @@ class SQLResult(StatementResult):
|
|
|
463
504
|
msg = f"Multiple results found ({data_len}), exactly one row expected"
|
|
464
505
|
raise ValueError(msg)
|
|
465
506
|
|
|
466
|
-
|
|
507
|
+
row = cast("dict[str, Any]", self.data[0])
|
|
508
|
+
if schema_type:
|
|
509
|
+
return to_schema(row, schema_type=schema_type)
|
|
510
|
+
return row
|
|
511
|
+
|
|
512
|
+
@overload
|
|
513
|
+
def one_or_none(self, *, schema_type: "type[SchemaT]") -> "SchemaT | None": ...
|
|
467
514
|
|
|
468
|
-
|
|
515
|
+
@overload
|
|
516
|
+
def one_or_none(self, *, schema_type: None = None) -> "dict[str, Any] | None": ...
|
|
517
|
+
|
|
518
|
+
def one_or_none(self, *, schema_type: "type[SchemaT] | None" = None) -> "SchemaT | dict[str, Any] | None":
|
|
469
519
|
"""Return at most one row.
|
|
470
520
|
|
|
521
|
+
Args:
|
|
522
|
+
schema_type: Optional schema type to transform the data into.
|
|
523
|
+
Supports Pydantic models, dataclasses, msgspec structs, attrs classes, and TypedDict.
|
|
524
|
+
|
|
471
525
|
Returns:
|
|
472
|
-
The single row or None if no results
|
|
526
|
+
The single row (optionally transformed to schema_type) or None if no results
|
|
473
527
|
|
|
474
528
|
Raises:
|
|
475
529
|
ValueError: If more than one result
|
|
@@ -484,7 +538,10 @@ class SQLResult(StatementResult):
|
|
|
484
538
|
msg = f"Multiple results found ({data_len}), at most one row expected"
|
|
485
539
|
raise ValueError(msg)
|
|
486
540
|
|
|
487
|
-
|
|
541
|
+
row = cast("dict[str, Any]", self.data[0])
|
|
542
|
+
if schema_type:
|
|
543
|
+
return to_schema(row, schema_type=schema_type)
|
|
544
|
+
return row
|
|
488
545
|
|
|
489
546
|
def scalar(self) -> Any:
|
|
490
547
|
"""Return the first column of the first row.
|
|
@@ -527,8 +584,8 @@ class ArrowResult(StatementResult):
|
|
|
527
584
|
statement: "SQL",
|
|
528
585
|
data: Any,
|
|
529
586
|
rows_affected: int = 0,
|
|
530
|
-
last_inserted_id:
|
|
531
|
-
execution_time:
|
|
587
|
+
last_inserted_id: int | str | None = None,
|
|
588
|
+
execution_time: float | None = None,
|
|
532
589
|
metadata: Optional["dict[str, Any]"] = None,
|
|
533
590
|
schema: Optional["dict[str, Any]"] = None,
|
|
534
591
|
) -> None:
|
|
@@ -562,7 +619,7 @@ class ArrowResult(StatementResult):
|
|
|
562
619
|
"""
|
|
563
620
|
return self.data is not None
|
|
564
621
|
|
|
565
|
-
def get_data(self) ->
|
|
622
|
+
def get_data(self) -> "ArrowTable":
|
|
566
623
|
"""Get the Apache Arrow Table from the result.
|
|
567
624
|
|
|
568
625
|
Returns:
|
|
@@ -570,10 +627,19 @@ class ArrowResult(StatementResult):
|
|
|
570
627
|
|
|
571
628
|
Raises:
|
|
572
629
|
ValueError: If no Arrow table is available.
|
|
630
|
+
TypeError: If data is not an Arrow Table.
|
|
573
631
|
"""
|
|
574
632
|
if self.data is None:
|
|
575
633
|
msg = "No Arrow table available for this result"
|
|
576
634
|
raise ValueError(msg)
|
|
635
|
+
|
|
636
|
+
ensure_pyarrow()
|
|
637
|
+
|
|
638
|
+
import pyarrow as pa
|
|
639
|
+
|
|
640
|
+
if not isinstance(self.data, pa.Table):
|
|
641
|
+
msg = f"Expected an Arrow Table, but got {type(self.data).__name__}"
|
|
642
|
+
raise TypeError(msg)
|
|
577
643
|
return self.data
|
|
578
644
|
|
|
579
645
|
@property
|
|
@@ -624,13 +690,134 @@ class ArrowResult(StatementResult):
|
|
|
624
690
|
|
|
625
691
|
return cast("int", self.data.num_columns)
|
|
626
692
|
|
|
693
|
+
def to_pandas(self) -> "PandasDataFrame":
|
|
694
|
+
"""Convert Arrow data to pandas DataFrame.
|
|
695
|
+
|
|
696
|
+
Returns:
|
|
697
|
+
pandas DataFrame containing the result data.
|
|
698
|
+
|
|
699
|
+
Raises:
|
|
700
|
+
ValueError: If no Arrow table is available.
|
|
701
|
+
|
|
702
|
+
Examples:
|
|
703
|
+
>>> result = session.select_to_arrow("SELECT * FROM users")
|
|
704
|
+
>>> df = result.to_pandas()
|
|
705
|
+
>>> print(df.head())
|
|
706
|
+
"""
|
|
707
|
+
if self.data is None:
|
|
708
|
+
msg = "No Arrow table available"
|
|
709
|
+
raise ValueError(msg)
|
|
710
|
+
|
|
711
|
+
ensure_pandas()
|
|
712
|
+
|
|
713
|
+
import pandas as pd
|
|
714
|
+
|
|
715
|
+
result = self.data.to_pandas()
|
|
716
|
+
if not isinstance(result, pd.DataFrame):
|
|
717
|
+
msg = f"Expected a pandas DataFrame, but got {type(result).__name__}"
|
|
718
|
+
raise TypeError(msg)
|
|
719
|
+
return result
|
|
720
|
+
|
|
721
|
+
def to_polars(self) -> "PolarsDataFrame":
|
|
722
|
+
"""Convert Arrow data to Polars DataFrame.
|
|
723
|
+
|
|
724
|
+
Returns:
|
|
725
|
+
Polars DataFrame containing the result data.
|
|
726
|
+
|
|
727
|
+
Raises:
|
|
728
|
+
ValueError: If no Arrow table is available.
|
|
729
|
+
|
|
730
|
+
Examples:
|
|
731
|
+
>>> result = session.select_to_arrow("SELECT * FROM users")
|
|
732
|
+
>>> df = result.to_polars()
|
|
733
|
+
>>> print(df.head())
|
|
734
|
+
"""
|
|
735
|
+
if self.data is None:
|
|
736
|
+
msg = "No Arrow table available"
|
|
737
|
+
raise ValueError(msg)
|
|
738
|
+
|
|
739
|
+
ensure_polars()
|
|
740
|
+
|
|
741
|
+
import polars as pl
|
|
742
|
+
|
|
743
|
+
result = pl.from_arrow(self.data)
|
|
744
|
+
if not isinstance(result, pl.DataFrame):
|
|
745
|
+
msg = f"Expected a Polars DataFrame, but got {type(result).__name__}"
|
|
746
|
+
raise TypeError(msg)
|
|
747
|
+
return result
|
|
748
|
+
|
|
749
|
+
def to_dict(self) -> "list[dict[str, Any]]":
|
|
750
|
+
"""Convert Arrow data to list of dictionaries.
|
|
751
|
+
|
|
752
|
+
Returns:
|
|
753
|
+
List of dictionaries, one per row.
|
|
754
|
+
|
|
755
|
+
Raises:
|
|
756
|
+
ValueError: If no Arrow table is available.
|
|
757
|
+
|
|
758
|
+
Examples:
|
|
759
|
+
>>> result = session.select_to_arrow(
|
|
760
|
+
... "SELECT id, name FROM users"
|
|
761
|
+
... )
|
|
762
|
+
>>> rows = result.to_dict()
|
|
763
|
+
>>> print(rows[0])
|
|
764
|
+
{'id': 1, 'name': 'Alice'}
|
|
765
|
+
"""
|
|
766
|
+
if self.data is None:
|
|
767
|
+
msg = "No Arrow table available"
|
|
768
|
+
raise ValueError(msg)
|
|
769
|
+
|
|
770
|
+
return cast("list[dict[str, Any]]", self.data.to_pylist())
|
|
771
|
+
|
|
772
|
+
def __len__(self) -> int:
|
|
773
|
+
"""Return number of rows in the Arrow table.
|
|
774
|
+
|
|
775
|
+
Returns:
|
|
776
|
+
Number of rows.
|
|
777
|
+
|
|
778
|
+
Raises:
|
|
779
|
+
ValueError: If no Arrow table is available.
|
|
780
|
+
|
|
781
|
+
Examples:
|
|
782
|
+
>>> result = session.select_to_arrow("SELECT * FROM users")
|
|
783
|
+
>>> print(len(result))
|
|
784
|
+
100
|
|
785
|
+
"""
|
|
786
|
+
if self.data is None:
|
|
787
|
+
msg = "No Arrow table available"
|
|
788
|
+
raise ValueError(msg)
|
|
789
|
+
|
|
790
|
+
return cast("int", self.data.num_rows)
|
|
791
|
+
|
|
792
|
+
def __iter__(self) -> "Iterator[dict[str, Any]]":
|
|
793
|
+
"""Iterate over rows as dictionaries.
|
|
794
|
+
|
|
795
|
+
Yields:
|
|
796
|
+
Dictionary for each row.
|
|
797
|
+
|
|
798
|
+
Raises:
|
|
799
|
+
ValueError: If no Arrow table is available.
|
|
800
|
+
|
|
801
|
+
Examples:
|
|
802
|
+
>>> result = session.select_to_arrow(
|
|
803
|
+
... "SELECT id, name FROM users"
|
|
804
|
+
... )
|
|
805
|
+
>>> for row in result:
|
|
806
|
+
... print(row["name"])
|
|
807
|
+
"""
|
|
808
|
+
if self.data is None:
|
|
809
|
+
msg = "No Arrow table available"
|
|
810
|
+
raise ValueError(msg)
|
|
811
|
+
|
|
812
|
+
yield from self.data.to_pylist()
|
|
813
|
+
|
|
627
814
|
|
|
628
815
|
def create_sql_result(
|
|
629
816
|
statement: "SQL",
|
|
630
|
-
data:
|
|
817
|
+
data: list[dict[str, Any]] | None = None,
|
|
631
818
|
rows_affected: int = 0,
|
|
632
|
-
last_inserted_id:
|
|
633
|
-
execution_time:
|
|
819
|
+
last_inserted_id: int | str | None = None,
|
|
820
|
+
execution_time: float | None = None,
|
|
634
821
|
metadata: Optional["dict[str, Any]"] = None,
|
|
635
822
|
**kwargs: Any,
|
|
636
823
|
) -> SQLResult:
|
|
@@ -663,8 +850,8 @@ def create_arrow_result(
|
|
|
663
850
|
statement: "SQL",
|
|
664
851
|
data: Any,
|
|
665
852
|
rows_affected: int = 0,
|
|
666
|
-
last_inserted_id:
|
|
667
|
-
execution_time:
|
|
853
|
+
last_inserted_id: int | str | None = None,
|
|
854
|
+
execution_time: float | None = None,
|
|
668
855
|
metadata: Optional["dict[str, Any]"] = None,
|
|
669
856
|
schema: Optional["dict[str, Any]"] = None,
|
|
670
857
|
) -> ArrowResult:
|
sqlspec/core/splitter.py
CHANGED
|
@@ -16,13 +16,12 @@ MySQL, SQLite, DuckDB, and BigQuery.
|
|
|
16
16
|
import re
|
|
17
17
|
import threading
|
|
18
18
|
from abc import ABC, abstractmethod
|
|
19
|
-
from collections.abc import Generator
|
|
19
|
+
from collections.abc import Callable, Generator
|
|
20
20
|
from enum import Enum
|
|
21
21
|
from re import Pattern
|
|
22
|
-
from typing import Any,
|
|
22
|
+
from typing import Any, Final, TypeAlias, cast
|
|
23
23
|
|
|
24
24
|
from mypy_extensions import mypyc_attr
|
|
25
|
-
from typing_extensions import TypeAlias
|
|
26
25
|
|
|
27
26
|
from sqlspec.core.cache import CacheKey, UnifiedCache
|
|
28
27
|
from sqlspec.utils.logging import get_logger
|
|
@@ -98,9 +97,9 @@ class Token:
|
|
|
98
97
|
return f"Token({self.type.value}, {self.value!r}, {self.line}:{self.column})"
|
|
99
98
|
|
|
100
99
|
|
|
101
|
-
TokenHandler: TypeAlias = Callable[[str, int, int, int],
|
|
102
|
-
TokenPattern: TypeAlias =
|
|
103
|
-
CompiledTokenPattern: TypeAlias =
|
|
100
|
+
TokenHandler: TypeAlias = Callable[[str, int, int, int], Token | None]
|
|
101
|
+
TokenPattern: TypeAlias = str | TokenHandler
|
|
102
|
+
CompiledTokenPattern: TypeAlias = Pattern[str] | TokenHandler
|
|
104
103
|
|
|
105
104
|
|
|
106
105
|
@mypyc_attr(allow_interpreted_subclasses=False)
|
|
@@ -111,13 +110,13 @@ class DialectConfig(ABC):
|
|
|
111
110
|
|
|
112
111
|
def __init__(self) -> None:
|
|
113
112
|
"""Initialize dialect configuration."""
|
|
114
|
-
self._name:
|
|
115
|
-
self._block_starters:
|
|
116
|
-
self._block_enders:
|
|
117
|
-
self._statement_terminators:
|
|
118
|
-
self._batch_separators:
|
|
119
|
-
self._special_terminators:
|
|
120
|
-
self._max_nesting_depth:
|
|
113
|
+
self._name: str | None = None
|
|
114
|
+
self._block_starters: set[str] | None = None
|
|
115
|
+
self._block_enders: set[str] | None = None
|
|
116
|
+
self._statement_terminators: set[str] | None = None
|
|
117
|
+
self._batch_separators: set[str] | None = None
|
|
118
|
+
self._special_terminators: dict[str, Callable[[list[Token], int], bool]] | None = None
|
|
119
|
+
self._max_nesting_depth: int | None = None
|
|
121
120
|
|
|
122
121
|
@property
|
|
123
122
|
@abstractmethod
|
|
@@ -436,7 +435,7 @@ class PostgreSQLDialectConfig(DialectConfig):
|
|
|
436
435
|
return [(TokenType.STRING_LITERAL, self._handle_dollar_quoted_string)]
|
|
437
436
|
|
|
438
437
|
@staticmethod
|
|
439
|
-
def _handle_dollar_quoted_string(text: str, position: int, line: int, column: int) ->
|
|
438
|
+
def _handle_dollar_quoted_string(text: str, position: int, line: int, column: int) -> Token | None:
|
|
440
439
|
"""Handle PostgreSQL dollar-quoted string literals.
|
|
441
440
|
|
|
442
441
|
Parses dollar-quoted strings in the format $tag$content$tag$
|
|
@@ -613,8 +612,8 @@ class BigQueryDialectConfig(DialectConfig):
|
|
|
613
612
|
return self._statement_terminators
|
|
614
613
|
|
|
615
614
|
|
|
616
|
-
_pattern_cache:
|
|
617
|
-
_result_cache:
|
|
615
|
+
_pattern_cache: UnifiedCache | None = None
|
|
616
|
+
_result_cache: UnifiedCache | None = None
|
|
618
617
|
_cache_lock = threading.Lock()
|
|
619
618
|
|
|
620
619
|
|
|
@@ -878,7 +877,7 @@ class StatementSplitter:
|
|
|
878
877
|
return False
|
|
879
878
|
|
|
880
879
|
|
|
881
|
-
def split_sql_script(script: str, dialect:
|
|
880
|
+
def split_sql_script(script: str, dialect: str | None = None, strip_trailing_terminator: bool = False) -> list[str]:
|
|
882
881
|
"""Split SQL script into individual statements.
|
|
883
882
|
|
|
884
883
|
Args:
|