sqlspec 0.13.0__py3-none-any.whl → 0.14.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 +39 -1
- sqlspec/adapters/adbc/config.py +4 -40
- sqlspec/adapters/adbc/driver.py +29 -16
- sqlspec/adapters/aiosqlite/config.py +15 -20
- sqlspec/adapters/aiosqlite/driver.py +36 -18
- sqlspec/adapters/asyncmy/config.py +16 -33
- sqlspec/adapters/asyncmy/driver.py +23 -16
- sqlspec/adapters/asyncpg/config.py +19 -61
- sqlspec/adapters/asyncpg/driver.py +41 -18
- sqlspec/adapters/bigquery/config.py +2 -43
- sqlspec/adapters/bigquery/driver.py +26 -14
- sqlspec/adapters/duckdb/config.py +2 -49
- sqlspec/adapters/duckdb/driver.py +35 -16
- sqlspec/adapters/oracledb/config.py +30 -83
- sqlspec/adapters/oracledb/driver.py +54 -27
- sqlspec/adapters/psqlpy/config.py +17 -57
- sqlspec/adapters/psqlpy/driver.py +28 -8
- sqlspec/adapters/psycopg/config.py +30 -73
- sqlspec/adapters/psycopg/driver.py +69 -24
- sqlspec/adapters/sqlite/config.py +3 -21
- sqlspec/adapters/sqlite/driver.py +50 -26
- sqlspec/cli.py +248 -0
- sqlspec/config.py +18 -20
- sqlspec/driver/_async.py +28 -10
- sqlspec/driver/_common.py +5 -4
- sqlspec/driver/_sync.py +28 -10
- sqlspec/driver/mixins/__init__.py +6 -0
- sqlspec/driver/mixins/_cache.py +114 -0
- sqlspec/driver/mixins/_pipeline.py +0 -4
- sqlspec/{service/base.py → driver/mixins/_query_tools.py} +86 -421
- sqlspec/driver/mixins/_result_utils.py +0 -2
- sqlspec/driver/mixins/_sql_translator.py +0 -2
- sqlspec/driver/mixins/_storage.py +4 -18
- sqlspec/driver/mixins/_type_coercion.py +0 -2
- sqlspec/driver/parameters.py +4 -4
- sqlspec/extensions/aiosql/adapter.py +4 -4
- sqlspec/extensions/litestar/__init__.py +2 -1
- sqlspec/extensions/litestar/cli.py +48 -0
- sqlspec/extensions/litestar/plugin.py +3 -0
- sqlspec/loader.py +1 -1
- sqlspec/migrations/__init__.py +23 -0
- sqlspec/migrations/base.py +390 -0
- sqlspec/migrations/commands.py +525 -0
- sqlspec/migrations/runner.py +215 -0
- sqlspec/migrations/tracker.py +153 -0
- sqlspec/migrations/utils.py +89 -0
- sqlspec/protocols.py +37 -3
- sqlspec/statement/builder/__init__.py +8 -8
- sqlspec/statement/builder/{column.py → _column.py} +82 -52
- sqlspec/statement/builder/{ddl.py → _ddl.py} +5 -5
- sqlspec/statement/builder/_ddl_utils.py +1 -1
- sqlspec/statement/builder/{delete.py → _delete.py} +1 -1
- sqlspec/statement/builder/{insert.py → _insert.py} +1 -1
- sqlspec/statement/builder/{merge.py → _merge.py} +1 -1
- sqlspec/statement/builder/_parsing_utils.py +5 -3
- sqlspec/statement/builder/{select.py → _select.py} +59 -61
- sqlspec/statement/builder/{update.py → _update.py} +2 -2
- sqlspec/statement/builder/mixins/__init__.py +24 -30
- sqlspec/statement/builder/mixins/{_set_ops.py → _cte_and_set_ops.py} +86 -2
- sqlspec/statement/builder/mixins/{_delete_from.py → _delete_operations.py} +2 -0
- sqlspec/statement/builder/mixins/{_insert_values.py → _insert_operations.py} +70 -1
- sqlspec/statement/builder/mixins/{_merge_clauses.py → _merge_operations.py} +2 -0
- sqlspec/statement/builder/mixins/_order_limit_operations.py +123 -0
- sqlspec/statement/builder/mixins/{_pivot.py → _pivot_operations.py} +71 -2
- sqlspec/statement/builder/mixins/_select_operations.py +612 -0
- sqlspec/statement/builder/mixins/{_update_set.py → _update_operations.py} +73 -2
- sqlspec/statement/builder/mixins/_where_clause.py +536 -0
- sqlspec/statement/cache.py +50 -0
- sqlspec/statement/filters.py +37 -8
- sqlspec/statement/parameters.py +154 -25
- sqlspec/statement/pipelines/__init__.py +1 -1
- sqlspec/statement/pipelines/context.py +4 -4
- sqlspec/statement/pipelines/transformers/_expression_simplifier.py +3 -3
- sqlspec/statement/pipelines/validators/_parameter_style.py +22 -22
- sqlspec/statement/pipelines/validators/_performance.py +1 -5
- sqlspec/statement/sql.py +246 -176
- sqlspec/utils/__init__.py +2 -1
- sqlspec/utils/statement_hashing.py +203 -0
- sqlspec/utils/type_guards.py +32 -0
- {sqlspec-0.13.0.dist-info → sqlspec-0.14.0.dist-info}/METADATA +1 -1
- sqlspec-0.14.0.dist-info/RECORD +143 -0
- sqlspec-0.14.0.dist-info/entry_points.txt +2 -0
- sqlspec/service/__init__.py +0 -4
- sqlspec/service/_util.py +0 -147
- sqlspec/service/pagination.py +0 -26
- sqlspec/statement/builder/mixins/_aggregate_functions.py +0 -250
- sqlspec/statement/builder/mixins/_case_builder.py +0 -91
- sqlspec/statement/builder/mixins/_common_table_expr.py +0 -90
- sqlspec/statement/builder/mixins/_from.py +0 -63
- sqlspec/statement/builder/mixins/_group_by.py +0 -118
- sqlspec/statement/builder/mixins/_having.py +0 -35
- sqlspec/statement/builder/mixins/_insert_from_select.py +0 -47
- sqlspec/statement/builder/mixins/_insert_into.py +0 -36
- sqlspec/statement/builder/mixins/_limit_offset.py +0 -53
- sqlspec/statement/builder/mixins/_order_by.py +0 -46
- sqlspec/statement/builder/mixins/_returning.py +0 -37
- sqlspec/statement/builder/mixins/_select_columns.py +0 -61
- sqlspec/statement/builder/mixins/_unpivot.py +0 -77
- sqlspec/statement/builder/mixins/_update_from.py +0 -55
- sqlspec/statement/builder/mixins/_update_table.py +0 -29
- sqlspec/statement/builder/mixins/_where.py +0 -401
- sqlspec/statement/builder/mixins/_window_functions.py +0 -86
- sqlspec/statement/parameter_manager.py +0 -220
- sqlspec/statement/sql_compiler.py +0 -140
- sqlspec-0.13.0.dist-info/RECORD +0 -150
- /sqlspec/statement/builder/{base.py → _base.py} +0 -0
- /sqlspec/statement/builder/mixins/{_join.py → _join_operations.py} +0 -0
- {sqlspec-0.13.0.dist-info → sqlspec-0.14.0.dist-info}/WHEEL +0 -0
- {sqlspec-0.13.0.dist-info → sqlspec-0.14.0.dist-info}/licenses/LICENSE +0 -0
- {sqlspec-0.13.0.dist-info → sqlspec-0.14.0.dist-info}/licenses/NOTICE +0 -0
|
@@ -9,6 +9,7 @@ from psqlpy import Connection
|
|
|
9
9
|
from sqlspec.driver import AsyncDriverAdapterProtocol
|
|
10
10
|
from sqlspec.driver.connection import managed_transaction_async
|
|
11
11
|
from sqlspec.driver.mixins import (
|
|
12
|
+
AsyncAdapterCacheMixin,
|
|
12
13
|
AsyncPipelinedExecutionMixin,
|
|
13
14
|
AsyncStorageMixin,
|
|
14
15
|
SQLTranslatorMixin,
|
|
@@ -31,6 +32,7 @@ logger = logging.getLogger("sqlspec")
|
|
|
31
32
|
|
|
32
33
|
class PsqlpyDriver(
|
|
33
34
|
AsyncDriverAdapterProtocol[PsqlpyConnection, RowT],
|
|
35
|
+
AsyncAdapterCacheMixin,
|
|
34
36
|
SQLTranslatorMixin,
|
|
35
37
|
TypeCoercionMixin,
|
|
36
38
|
AsyncStorageMixin,
|
|
@@ -45,7 +47,6 @@ class PsqlpyDriver(
|
|
|
45
47
|
dialect: "DialectType" = "postgres"
|
|
46
48
|
supported_parameter_styles: "tuple[ParameterStyle, ...]" = (ParameterStyle.NUMERIC,)
|
|
47
49
|
default_parameter_style: ParameterStyle = ParameterStyle.NUMERIC
|
|
48
|
-
__slots__ = ()
|
|
49
50
|
|
|
50
51
|
def __init__(
|
|
51
52
|
self,
|
|
@@ -79,7 +80,7 @@ class PsqlpyDriver(
|
|
|
79
80
|
self, statement: SQL, connection: Optional[PsqlpyConnection] = None, **kwargs: Any
|
|
80
81
|
) -> SQLResult[RowT]:
|
|
81
82
|
if statement.is_script:
|
|
82
|
-
sql, _ =
|
|
83
|
+
sql, _ = self._get_compiled_sql(statement, ParameterStyle.STATIC)
|
|
83
84
|
return await self._execute_script(sql, connection=connection, **kwargs)
|
|
84
85
|
|
|
85
86
|
# Detect parameter styles in the SQL
|
|
@@ -106,7 +107,7 @@ class PsqlpyDriver(
|
|
|
106
107
|
break
|
|
107
108
|
|
|
108
109
|
# Compile with the determined style
|
|
109
|
-
sql, params =
|
|
110
|
+
sql, params = self._get_compiled_sql(statement, target_style)
|
|
110
111
|
params = self._process_parameters(params)
|
|
111
112
|
|
|
112
113
|
if statement.is_many:
|
|
@@ -198,16 +199,35 @@ class PsqlpyDriver(
|
|
|
198
199
|
conn = connection if connection is not None else self._connection(None)
|
|
199
200
|
|
|
200
201
|
async with managed_transaction_async(conn, auto_commit=True) as txn_conn:
|
|
201
|
-
#
|
|
202
|
-
|
|
202
|
+
# Split script into individual statements for validation
|
|
203
|
+
statements = self._split_script_statements(script)
|
|
204
|
+
suppress_warnings = kwargs.get("_suppress_warnings", False)
|
|
205
|
+
|
|
206
|
+
executed_count = 0
|
|
207
|
+
total_rows = 0
|
|
208
|
+
|
|
209
|
+
# Execute each statement individually for better control and validation
|
|
210
|
+
for statement in statements:
|
|
211
|
+
if statement.strip():
|
|
212
|
+
# Validate each statement unless warnings suppressed
|
|
213
|
+
if not suppress_warnings:
|
|
214
|
+
# Run validation through pipeline
|
|
215
|
+
temp_sql = SQL(statement, config=self.config)
|
|
216
|
+
temp_sql._ensure_processed()
|
|
217
|
+
# Validation errors are logged as warnings by default
|
|
218
|
+
|
|
219
|
+
await txn_conn.execute(statement)
|
|
220
|
+
executed_count += 1
|
|
221
|
+
# psqlpy doesn't provide row count from execute()
|
|
222
|
+
|
|
203
223
|
return SQLResult(
|
|
204
224
|
statement=SQL(script, _dialect=self.dialect).as_script(),
|
|
205
225
|
data=[],
|
|
206
|
-
rows_affected=
|
|
226
|
+
rows_affected=total_rows,
|
|
207
227
|
operation_type="SCRIPT",
|
|
208
228
|
metadata={"status_message": "SCRIPT EXECUTED"},
|
|
209
|
-
total_statements
|
|
210
|
-
successful_statements
|
|
229
|
+
total_statements=executed_count,
|
|
230
|
+
successful_statements=executed_count,
|
|
211
231
|
)
|
|
212
232
|
|
|
213
233
|
async def _ingest_arrow_table(self, table: "Any", table_name: str, mode: str = "append", **options: Any) -> int:
|
|
@@ -22,7 +22,6 @@ if TYPE_CHECKING:
|
|
|
22
22
|
from collections.abc import AsyncGenerator, Callable, Generator
|
|
23
23
|
|
|
24
24
|
from psycopg import Connection
|
|
25
|
-
from sqlglot.dialects.dialect import DialectType
|
|
26
25
|
|
|
27
26
|
logger = logging.getLogger("sqlspec.adapters.psycopg")
|
|
28
27
|
|
|
@@ -67,39 +66,6 @@ __all__ = ("CONNECTION_FIELDS", "POOL_FIELDS", "PsycopgAsyncConfig", "PsycopgSyn
|
|
|
67
66
|
class PsycopgSyncConfig(SyncDatabaseConfig[PsycopgSyncConnection, ConnectionPool, PsycopgSyncDriver]):
|
|
68
67
|
"""Configuration for Psycopg synchronous database connections with direct field-based configuration."""
|
|
69
68
|
|
|
70
|
-
__slots__ = (
|
|
71
|
-
"_dialect",
|
|
72
|
-
"application_name",
|
|
73
|
-
"autocommit",
|
|
74
|
-
"configure",
|
|
75
|
-
"connect_timeout",
|
|
76
|
-
"conninfo",
|
|
77
|
-
"dbname",
|
|
78
|
-
"default_row_type",
|
|
79
|
-
"extras",
|
|
80
|
-
"host",
|
|
81
|
-
"kwargs",
|
|
82
|
-
"max_idle",
|
|
83
|
-
"max_lifetime",
|
|
84
|
-
"max_size",
|
|
85
|
-
"max_waiting",
|
|
86
|
-
"min_size",
|
|
87
|
-
"name",
|
|
88
|
-
"num_workers",
|
|
89
|
-
"options",
|
|
90
|
-
"password",
|
|
91
|
-
"pool_instance",
|
|
92
|
-
"port",
|
|
93
|
-
"reconnect_timeout",
|
|
94
|
-
"sslcert",
|
|
95
|
-
"sslkey",
|
|
96
|
-
"sslmode",
|
|
97
|
-
"sslrootcert",
|
|
98
|
-
"statement_config",
|
|
99
|
-
"timeout",
|
|
100
|
-
"user",
|
|
101
|
-
)
|
|
102
|
-
|
|
103
69
|
is_async: ClassVar[bool] = False
|
|
104
70
|
supports_connection_pooling: ClassVar[bool] = True
|
|
105
71
|
|
|
@@ -110,7 +76,7 @@ class PsycopgSyncConfig(SyncDatabaseConfig[PsycopgSyncConnection, ConnectionPool
|
|
|
110
76
|
supported_parameter_styles: ClassVar[tuple[str, ...]] = ("pyformat_positional", "pyformat_named")
|
|
111
77
|
"""Psycopg supports %s (positional) and %(name)s (named) parameter styles."""
|
|
112
78
|
|
|
113
|
-
|
|
79
|
+
default_parameter_style: ClassVar[str] = "pyformat_positional"
|
|
114
80
|
"""Psycopg's native parameter style is %s (pyformat positional)."""
|
|
115
81
|
|
|
116
82
|
def __init__(
|
|
@@ -216,7 +182,6 @@ class PsycopgSyncConfig(SyncDatabaseConfig[PsycopgSyncConnection, ConnectionPool
|
|
|
216
182
|
# Store other config
|
|
217
183
|
self.statement_config = statement_config or SQLConfig()
|
|
218
184
|
self.default_row_type = default_row_type
|
|
219
|
-
self._dialect: DialectType = None
|
|
220
185
|
|
|
221
186
|
super().__init__()
|
|
222
187
|
|
|
@@ -385,7 +350,7 @@ class PsycopgSyncConfig(SyncDatabaseConfig[PsycopgSyncConnection, ConnectionPool
|
|
|
385
350
|
statement_config = replace(
|
|
386
351
|
statement_config,
|
|
387
352
|
allowed_parameter_styles=self.supported_parameter_styles,
|
|
388
|
-
|
|
353
|
+
default_parameter_style=self.default_parameter_style,
|
|
389
354
|
)
|
|
390
355
|
driver = self.driver_type(connection=conn, config=statement_config)
|
|
391
356
|
yield driver
|
|
@@ -400,43 +365,23 @@ class PsycopgSyncConfig(SyncDatabaseConfig[PsycopgSyncConnection, ConnectionPool
|
|
|
400
365
|
self.pool_instance = self.create_pool()
|
|
401
366
|
return self.pool_instance
|
|
402
367
|
|
|
368
|
+
def get_signature_namespace(self) -> "dict[str, type[Any]]":
|
|
369
|
+
"""Get the signature namespace for Psycopg types.
|
|
370
|
+
|
|
371
|
+
This provides all Psycopg-specific types that Litestar needs to recognize
|
|
372
|
+
to avoid serialization attempts.
|
|
373
|
+
|
|
374
|
+
Returns:
|
|
375
|
+
Dictionary mapping type names to types.
|
|
376
|
+
"""
|
|
377
|
+
namespace = super().get_signature_namespace()
|
|
378
|
+
namespace.update({"PsycopgSyncConnection": PsycopgSyncConnection})
|
|
379
|
+
return namespace
|
|
380
|
+
|
|
403
381
|
|
|
404
382
|
class PsycopgAsyncConfig(AsyncDatabaseConfig[PsycopgAsyncConnection, AsyncConnectionPool, PsycopgAsyncDriver]):
|
|
405
383
|
"""Configuration for Psycopg asynchronous database connections with direct field-based configuration."""
|
|
406
384
|
|
|
407
|
-
__slots__ = (
|
|
408
|
-
"_dialect",
|
|
409
|
-
"application_name",
|
|
410
|
-
"autocommit",
|
|
411
|
-
"configure",
|
|
412
|
-
"connect_timeout",
|
|
413
|
-
"conninfo",
|
|
414
|
-
"dbname",
|
|
415
|
-
"default_row_type",
|
|
416
|
-
"extras",
|
|
417
|
-
"host",
|
|
418
|
-
"kwargs",
|
|
419
|
-
"max_idle",
|
|
420
|
-
"max_lifetime",
|
|
421
|
-
"max_size",
|
|
422
|
-
"max_waiting",
|
|
423
|
-
"min_size",
|
|
424
|
-
"name",
|
|
425
|
-
"num_workers",
|
|
426
|
-
"options",
|
|
427
|
-
"password",
|
|
428
|
-
"pool_instance",
|
|
429
|
-
"port",
|
|
430
|
-
"reconnect_timeout",
|
|
431
|
-
"sslcert",
|
|
432
|
-
"sslkey",
|
|
433
|
-
"sslmode",
|
|
434
|
-
"sslrootcert",
|
|
435
|
-
"statement_config",
|
|
436
|
-
"timeout",
|
|
437
|
-
"user",
|
|
438
|
-
)
|
|
439
|
-
|
|
440
385
|
is_async: ClassVar[bool] = True
|
|
441
386
|
supports_connection_pooling: ClassVar[bool] = True
|
|
442
387
|
|
|
@@ -448,7 +393,7 @@ class PsycopgAsyncConfig(AsyncDatabaseConfig[PsycopgAsyncConnection, AsyncConnec
|
|
|
448
393
|
supported_parameter_styles: ClassVar[tuple[str, ...]] = ("pyformat_positional", "pyformat_named")
|
|
449
394
|
"""Psycopg supports %s (pyformat_positional) and %(name)s (pyformat_named) parameter styles."""
|
|
450
395
|
|
|
451
|
-
|
|
396
|
+
default_parameter_style: ClassVar[str] = "pyformat_positional"
|
|
452
397
|
"""Psycopg's preferred parameter style is %s (pyformat_positional)."""
|
|
453
398
|
|
|
454
399
|
def __init__(
|
|
@@ -554,7 +499,6 @@ class PsycopgAsyncConfig(AsyncDatabaseConfig[PsycopgAsyncConnection, AsyncConnec
|
|
|
554
499
|
# Store other config
|
|
555
500
|
self.statement_config = statement_config or SQLConfig()
|
|
556
501
|
self.default_row_type = default_row_type
|
|
557
|
-
self._dialect: DialectType = None
|
|
558
502
|
|
|
559
503
|
super().__init__()
|
|
560
504
|
|
|
@@ -713,7 +657,7 @@ class PsycopgAsyncConfig(AsyncDatabaseConfig[PsycopgAsyncConnection, AsyncConnec
|
|
|
713
657
|
statement_config = replace(
|
|
714
658
|
statement_config,
|
|
715
659
|
allowed_parameter_styles=self.supported_parameter_styles,
|
|
716
|
-
|
|
660
|
+
default_parameter_style=self.default_parameter_style,
|
|
717
661
|
)
|
|
718
662
|
driver = self.driver_type(connection=conn, config=statement_config)
|
|
719
663
|
yield driver
|
|
@@ -727,3 +671,16 @@ class PsycopgAsyncConfig(AsyncDatabaseConfig[PsycopgAsyncConnection, AsyncConnec
|
|
|
727
671
|
if not self.pool_instance:
|
|
728
672
|
self.pool_instance = await self.create_pool()
|
|
729
673
|
return self.pool_instance
|
|
674
|
+
|
|
675
|
+
def get_signature_namespace(self) -> "dict[str, type[Any]]":
|
|
676
|
+
"""Get the signature namespace for Psycopg async types.
|
|
677
|
+
|
|
678
|
+
This provides all Psycopg async-specific types that Litestar needs to recognize
|
|
679
|
+
to avoid serialization attempts.
|
|
680
|
+
|
|
681
|
+
Returns:
|
|
682
|
+
Dictionary mapping type names to types.
|
|
683
|
+
"""
|
|
684
|
+
namespace = super().get_signature_namespace()
|
|
685
|
+
namespace.update({"PsycopgAsyncConnection": PsycopgAsyncConnection})
|
|
686
|
+
return namespace
|
|
@@ -13,15 +13,17 @@ from sqlglot.dialects.dialect import DialectType
|
|
|
13
13
|
from sqlspec.driver import AsyncDriverAdapterProtocol, SyncDriverAdapterProtocol
|
|
14
14
|
from sqlspec.driver.connection import managed_transaction_async, managed_transaction_sync
|
|
15
15
|
from sqlspec.driver.mixins import (
|
|
16
|
+
AsyncAdapterCacheMixin,
|
|
16
17
|
AsyncPipelinedExecutionMixin,
|
|
17
18
|
AsyncStorageMixin,
|
|
18
19
|
SQLTranslatorMixin,
|
|
20
|
+
SyncAdapterCacheMixin,
|
|
19
21
|
SyncPipelinedExecutionMixin,
|
|
20
22
|
SyncStorageMixin,
|
|
21
23
|
ToSchemaMixin,
|
|
22
24
|
TypeCoercionMixin,
|
|
23
25
|
)
|
|
24
|
-
from sqlspec.driver.parameters import
|
|
26
|
+
from sqlspec.driver.parameters import convert_parameter_sequence
|
|
25
27
|
from sqlspec.exceptions import PipelineExecutionError
|
|
26
28
|
from sqlspec.statement.parameters import ParameterStyle, ParameterValidator
|
|
27
29
|
from sqlspec.statement.result import ArrowResult, SQLResult
|
|
@@ -43,6 +45,7 @@ PsycopgAsyncConnection = AsyncConnection[PsycopgDictRow]
|
|
|
43
45
|
|
|
44
46
|
class PsycopgSyncDriver(
|
|
45
47
|
SyncDriverAdapterProtocol[PsycopgSyncConnection, RowT],
|
|
48
|
+
SyncAdapterCacheMixin,
|
|
46
49
|
SQLTranslatorMixin,
|
|
47
50
|
TypeCoercionMixin,
|
|
48
51
|
SyncStorageMixin,
|
|
@@ -57,7 +60,6 @@ class PsycopgSyncDriver(
|
|
|
57
60
|
ParameterStyle.NAMED_PYFORMAT,
|
|
58
61
|
)
|
|
59
62
|
default_parameter_style: ParameterStyle = ParameterStyle.POSITIONAL_PYFORMAT
|
|
60
|
-
__slots__ = ()
|
|
61
63
|
|
|
62
64
|
def __init__(
|
|
63
65
|
self,
|
|
@@ -77,7 +79,7 @@ class PsycopgSyncDriver(
|
|
|
77
79
|
self, statement: SQL, connection: Optional[PsycopgSyncConnection] = None, **kwargs: Any
|
|
78
80
|
) -> SQLResult[RowT]:
|
|
79
81
|
if statement.is_script:
|
|
80
|
-
sql, _ =
|
|
82
|
+
sql, _ = self._get_compiled_sql(statement, ParameterStyle.STATIC)
|
|
81
83
|
return self._execute_script(sql, connection=connection, **kwargs)
|
|
82
84
|
|
|
83
85
|
detected_styles = set()
|
|
@@ -105,7 +107,7 @@ class PsycopgSyncDriver(
|
|
|
105
107
|
sql = statement.to_sql(placeholder_style=target_style)
|
|
106
108
|
params = kwargs_params
|
|
107
109
|
else:
|
|
108
|
-
sql, params =
|
|
110
|
+
sql, params = self._get_compiled_sql(statement, target_style)
|
|
109
111
|
if params is not None:
|
|
110
112
|
processed_params = [self._process_parameters(param_set) for param_set in params]
|
|
111
113
|
params = processed_params
|
|
@@ -120,7 +122,7 @@ class PsycopgSyncDriver(
|
|
|
120
122
|
sql = statement.to_sql(placeholder_style=target_style)
|
|
121
123
|
params = kwargs_params
|
|
122
124
|
else:
|
|
123
|
-
sql, params =
|
|
125
|
+
sql, params = self._get_compiled_sql(statement, target_style)
|
|
124
126
|
params = self._process_parameters(params)
|
|
125
127
|
|
|
126
128
|
# Fix over-nested parameters for Psycopg
|
|
@@ -231,8 +233,8 @@ class PsycopgSyncDriver(
|
|
|
231
233
|
|
|
232
234
|
with managed_transaction_sync(conn, auto_commit=True) as txn_conn:
|
|
233
235
|
# Normalize parameter list using consolidated utility
|
|
234
|
-
|
|
235
|
-
final_param_list =
|
|
236
|
+
converted_param_list = convert_parameter_sequence(param_list)
|
|
237
|
+
final_param_list = converted_param_list or []
|
|
236
238
|
|
|
237
239
|
with self._get_cursor(txn_conn) as cursor:
|
|
238
240
|
cursor.executemany(sql, final_param_list)
|
|
@@ -256,15 +258,37 @@ class PsycopgSyncDriver(
|
|
|
256
258
|
conn = connection if connection is not None else self._connection(None)
|
|
257
259
|
|
|
258
260
|
with managed_transaction_sync(conn, auto_commit=True) as txn_conn, self._get_cursor(txn_conn) as cursor:
|
|
259
|
-
|
|
261
|
+
# Split script into individual statements for validation
|
|
262
|
+
statements = self._split_script_statements(script)
|
|
263
|
+
suppress_warnings = kwargs.get("_suppress_warnings", False)
|
|
264
|
+
|
|
265
|
+
executed_count = 0
|
|
266
|
+
total_rows = 0
|
|
267
|
+
last_status = None
|
|
268
|
+
|
|
269
|
+
# Execute each statement individually for better control and validation
|
|
270
|
+
for statement in statements:
|
|
271
|
+
if statement.strip():
|
|
272
|
+
# Validate each statement unless warnings suppressed
|
|
273
|
+
if not suppress_warnings:
|
|
274
|
+
# Run validation through pipeline
|
|
275
|
+
temp_sql = SQL(statement, config=self.config)
|
|
276
|
+
temp_sql._ensure_processed()
|
|
277
|
+
# Validation errors are logged as warnings by default
|
|
278
|
+
|
|
279
|
+
cursor.execute(statement)
|
|
280
|
+
executed_count += 1
|
|
281
|
+
total_rows += cursor.rowcount or 0
|
|
282
|
+
last_status = cursor.statusmessage
|
|
283
|
+
|
|
260
284
|
return SQLResult(
|
|
261
285
|
statement=SQL(script, _dialect=self.dialect).as_script(),
|
|
262
286
|
data=[],
|
|
263
|
-
rows_affected=
|
|
287
|
+
rows_affected=total_rows,
|
|
264
288
|
operation_type="SCRIPT",
|
|
265
|
-
metadata={"status_message":
|
|
266
|
-
total_statements=
|
|
267
|
-
successful_statements=
|
|
289
|
+
metadata={"status_message": last_status or "SCRIPT EXECUTED"},
|
|
290
|
+
total_statements=executed_count,
|
|
291
|
+
successful_statements=executed_count,
|
|
268
292
|
)
|
|
269
293
|
|
|
270
294
|
def _ingest_arrow_table(self, table: "Any", table_name: str, mode: str = "append", **options: Any) -> int:
|
|
@@ -471,6 +495,7 @@ class PsycopgSyncDriver(
|
|
|
471
495
|
|
|
472
496
|
class PsycopgAsyncDriver(
|
|
473
497
|
AsyncDriverAdapterProtocol[PsycopgAsyncConnection, RowT],
|
|
498
|
+
AsyncAdapterCacheMixin,
|
|
474
499
|
SQLTranslatorMixin,
|
|
475
500
|
TypeCoercionMixin,
|
|
476
501
|
AsyncStorageMixin,
|
|
@@ -485,7 +510,6 @@ class PsycopgAsyncDriver(
|
|
|
485
510
|
ParameterStyle.NAMED_PYFORMAT,
|
|
486
511
|
)
|
|
487
512
|
default_parameter_style: ParameterStyle = ParameterStyle.POSITIONAL_PYFORMAT
|
|
488
|
-
__slots__ = ()
|
|
489
513
|
|
|
490
514
|
def __init__(
|
|
491
515
|
self,
|
|
@@ -505,7 +529,7 @@ class PsycopgAsyncDriver(
|
|
|
505
529
|
self, statement: SQL, connection: Optional[PsycopgAsyncConnection] = None, **kwargs: Any
|
|
506
530
|
) -> SQLResult[RowT]:
|
|
507
531
|
if statement.is_script:
|
|
508
|
-
sql, _ =
|
|
532
|
+
sql, _ = self._get_compiled_sql(statement, ParameterStyle.STATIC)
|
|
509
533
|
return await self._execute_script(sql, connection=connection, **kwargs)
|
|
510
534
|
|
|
511
535
|
detected_styles = set()
|
|
@@ -535,8 +559,7 @@ class PsycopgAsyncDriver(
|
|
|
535
559
|
sql = statement.to_sql(placeholder_style=target_style)
|
|
536
560
|
params = kwargs_params
|
|
537
561
|
else:
|
|
538
|
-
sql,
|
|
539
|
-
params = statement.parameters
|
|
562
|
+
sql, params = self._get_compiled_sql(statement, target_style)
|
|
540
563
|
if params is not None:
|
|
541
564
|
processed_params = [self._process_parameters(param_set) for param_set in params]
|
|
542
565
|
params = processed_params
|
|
@@ -560,7 +583,7 @@ class PsycopgAsyncDriver(
|
|
|
560
583
|
sql = statement.to_sql(placeholder_style=target_style)
|
|
561
584
|
params = kwargs_params
|
|
562
585
|
else:
|
|
563
|
-
sql, params =
|
|
586
|
+
sql, params = self._get_compiled_sql(statement, target_style)
|
|
564
587
|
params = self._process_parameters(params)
|
|
565
588
|
|
|
566
589
|
# Fix over-nested parameters for Psycopg
|
|
@@ -683,8 +706,8 @@ class PsycopgAsyncDriver(
|
|
|
683
706
|
|
|
684
707
|
async with managed_transaction_async(conn, auto_commit=True) as txn_conn:
|
|
685
708
|
# Normalize parameter list using consolidated utility
|
|
686
|
-
|
|
687
|
-
final_param_list =
|
|
709
|
+
converted_param_list = convert_parameter_sequence(param_list)
|
|
710
|
+
final_param_list = converted_param_list or []
|
|
688
711
|
|
|
689
712
|
async with txn_conn.cursor() as cursor:
|
|
690
713
|
await cursor.executemany(cast("Query", sql), final_param_list)
|
|
@@ -703,15 +726,37 @@ class PsycopgAsyncDriver(
|
|
|
703
726
|
conn = connection if connection is not None else self._connection(None)
|
|
704
727
|
|
|
705
728
|
async with managed_transaction_async(conn, auto_commit=True) as txn_conn, txn_conn.cursor() as cursor:
|
|
706
|
-
|
|
729
|
+
# Split script into individual statements for validation
|
|
730
|
+
statements = self._split_script_statements(script)
|
|
731
|
+
suppress_warnings = kwargs.get("_suppress_warnings", False)
|
|
732
|
+
|
|
733
|
+
executed_count = 0
|
|
734
|
+
total_rows = 0
|
|
735
|
+
last_status = None
|
|
736
|
+
|
|
737
|
+
# Execute each statement individually for better control and validation
|
|
738
|
+
for statement in statements:
|
|
739
|
+
if statement.strip():
|
|
740
|
+
# Validate each statement unless warnings suppressed
|
|
741
|
+
if not suppress_warnings:
|
|
742
|
+
# Run validation through pipeline
|
|
743
|
+
temp_sql = SQL(statement, config=self.config)
|
|
744
|
+
temp_sql._ensure_processed()
|
|
745
|
+
# Validation errors are logged as warnings by default
|
|
746
|
+
|
|
747
|
+
await cursor.execute(cast("Query", statement))
|
|
748
|
+
executed_count += 1
|
|
749
|
+
total_rows += cursor.rowcount or 0
|
|
750
|
+
last_status = cursor.statusmessage
|
|
751
|
+
|
|
707
752
|
return SQLResult(
|
|
708
753
|
statement=SQL(script, _dialect=self.dialect).as_script(),
|
|
709
754
|
data=[],
|
|
710
|
-
rows_affected=
|
|
755
|
+
rows_affected=total_rows,
|
|
711
756
|
operation_type="SCRIPT",
|
|
712
|
-
metadata={"status_message":
|
|
713
|
-
total_statements=
|
|
714
|
-
successful_statements=
|
|
757
|
+
metadata={"status_message": last_status or "SCRIPT EXECUTED"},
|
|
758
|
+
total_statements=executed_count,
|
|
759
|
+
successful_statements=executed_count,
|
|
715
760
|
)
|
|
716
761
|
|
|
717
762
|
async def _fetch_arrow_table(self, sql: SQL, connection: "Optional[Any]" = None, **kwargs: Any) -> "ArrowResult":
|
|
@@ -13,7 +13,6 @@ from sqlspec.typing import DictRow
|
|
|
13
13
|
if TYPE_CHECKING:
|
|
14
14
|
from collections.abc import Generator
|
|
15
15
|
|
|
16
|
-
from sqlglot.dialects.dialect import DialectType
|
|
17
16
|
|
|
18
17
|
logger = logging.getLogger(__name__)
|
|
19
18
|
|
|
@@ -36,26 +35,10 @@ __all__ = ("CONNECTION_FIELDS", "SqliteConfig", "sqlite3")
|
|
|
36
35
|
class SqliteConfig(NoPoolSyncConfig[SqliteConnection, SqliteDriver]):
|
|
37
36
|
"""Configuration for SQLite database connections with direct field-based configuration."""
|
|
38
37
|
|
|
39
|
-
__slots__ = (
|
|
40
|
-
"_dialect",
|
|
41
|
-
"cached_statements",
|
|
42
|
-
"check_same_thread",
|
|
43
|
-
"database",
|
|
44
|
-
"default_row_type",
|
|
45
|
-
"detect_types",
|
|
46
|
-
"extras",
|
|
47
|
-
"factory",
|
|
48
|
-
"isolation_level",
|
|
49
|
-
"pool_instance",
|
|
50
|
-
"statement_config",
|
|
51
|
-
"timeout",
|
|
52
|
-
"uri",
|
|
53
|
-
)
|
|
54
|
-
|
|
55
38
|
driver_type: type[SqliteDriver] = SqliteDriver
|
|
56
39
|
connection_type: type[SqliteConnection] = SqliteConnection
|
|
57
40
|
supported_parameter_styles: ClassVar[tuple[str, ...]] = ("qmark", "named_colon")
|
|
58
|
-
|
|
41
|
+
default_parameter_style: ClassVar[str] = "qmark"
|
|
59
42
|
|
|
60
43
|
def __init__(
|
|
61
44
|
self,
|
|
@@ -65,7 +48,7 @@ class SqliteConfig(NoPoolSyncConfig[SqliteConnection, SqliteDriver]):
|
|
|
65
48
|
# SQLite connection parameters
|
|
66
49
|
timeout: Optional[float] = None,
|
|
67
50
|
detect_types: Optional[int] = None,
|
|
68
|
-
isolation_level:
|
|
51
|
+
isolation_level: Union[None, str] = None,
|
|
69
52
|
check_same_thread: Optional[bool] = None,
|
|
70
53
|
factory: Optional[type[SqliteConnection]] = None,
|
|
71
54
|
cached_statements: Optional[int] = None,
|
|
@@ -106,7 +89,6 @@ class SqliteConfig(NoPoolSyncConfig[SqliteConnection, SqliteDriver]):
|
|
|
106
89
|
# Store other config
|
|
107
90
|
self.statement_config = statement_config or SQLConfig()
|
|
108
91
|
self.default_row_type = default_row_type
|
|
109
|
-
self._dialect: DialectType = None
|
|
110
92
|
super().__init__()
|
|
111
93
|
|
|
112
94
|
@property
|
|
@@ -169,6 +151,6 @@ class SqliteConfig(NoPoolSyncConfig[SqliteConnection, SqliteDriver]):
|
|
|
169
151
|
statement_config = replace(
|
|
170
152
|
statement_config,
|
|
171
153
|
allowed_parameter_styles=self.supported_parameter_styles,
|
|
172
|
-
|
|
154
|
+
default_parameter_style=self.default_parameter_style,
|
|
173
155
|
)
|
|
174
156
|
yield self.driver_type(connection=connection, config=statement_config)
|