sqlspec 0.8.0__py3-none-any.whl → 0.9.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/_typing.py +39 -6
- sqlspec/adapters/adbc/__init__.py +2 -2
- sqlspec/adapters/adbc/config.py +34 -11
- sqlspec/adapters/adbc/driver.py +167 -108
- sqlspec/adapters/aiosqlite/__init__.py +2 -2
- sqlspec/adapters/aiosqlite/config.py +2 -2
- sqlspec/adapters/aiosqlite/driver.py +28 -39
- sqlspec/adapters/asyncmy/__init__.py +3 -3
- sqlspec/adapters/asyncmy/config.py +11 -12
- sqlspec/adapters/asyncmy/driver.py +25 -34
- sqlspec/adapters/asyncpg/__init__.py +5 -5
- sqlspec/adapters/asyncpg/config.py +17 -19
- sqlspec/adapters/asyncpg/driver.py +249 -93
- sqlspec/adapters/duckdb/__init__.py +2 -2
- sqlspec/adapters/duckdb/config.py +2 -2
- sqlspec/adapters/duckdb/driver.py +49 -49
- sqlspec/adapters/oracledb/__init__.py +8 -8
- sqlspec/adapters/oracledb/config/__init__.py +6 -6
- sqlspec/adapters/oracledb/config/_asyncio.py +9 -10
- sqlspec/adapters/oracledb/config/_sync.py +8 -9
- sqlspec/adapters/oracledb/driver.py +114 -41
- sqlspec/adapters/psqlpy/__init__.py +0 -0
- sqlspec/adapters/psqlpy/config.py +258 -0
- sqlspec/adapters/psqlpy/driver.py +335 -0
- sqlspec/adapters/psycopg/__init__.py +10 -5
- sqlspec/adapters/psycopg/config/__init__.py +6 -6
- sqlspec/adapters/psycopg/config/_async.py +12 -12
- sqlspec/adapters/psycopg/config/_sync.py +13 -13
- sqlspec/adapters/psycopg/driver.py +180 -218
- sqlspec/adapters/sqlite/__init__.py +2 -2
- sqlspec/adapters/sqlite/config.py +2 -2
- sqlspec/adapters/sqlite/driver.py +43 -41
- sqlspec/base.py +275 -153
- sqlspec/exceptions.py +30 -0
- sqlspec/extensions/litestar/config.py +6 -0
- sqlspec/extensions/litestar/handlers.py +25 -0
- sqlspec/extensions/litestar/plugin.py +6 -1
- sqlspec/statement.py +373 -0
- sqlspec/typing.py +10 -1
- {sqlspec-0.8.0.dist-info → sqlspec-0.9.0.dist-info}/METADATA +4 -1
- sqlspec-0.9.0.dist-info/RECORD +61 -0
- sqlspec-0.8.0.dist-info/RECORD +0 -57
- {sqlspec-0.8.0.dist-info → sqlspec-0.9.0.dist-info}/WHEEL +0 -0
- {sqlspec-0.8.0.dist-info → sqlspec-0.9.0.dist-info}/licenses/LICENSE +0 -0
- {sqlspec-0.8.0.dist-info → sqlspec-0.9.0.dist-info}/licenses/NOTICE +0 -0
sqlspec/base.py
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
# ruff: noqa: PLR6301
|
|
2
2
|
import re
|
|
3
3
|
from abc import ABC, abstractmethod
|
|
4
|
-
from collections.abc import
|
|
5
|
-
from contextlib import AbstractAsyncContextManager, AbstractContextManager
|
|
4
|
+
from collections.abc import Awaitable
|
|
6
5
|
from dataclasses import dataclass, field
|
|
7
6
|
from typing import (
|
|
7
|
+
TYPE_CHECKING,
|
|
8
8
|
Annotated,
|
|
9
9
|
Any,
|
|
10
10
|
ClassVar,
|
|
@@ -17,15 +17,28 @@ from typing import (
|
|
|
17
17
|
)
|
|
18
18
|
|
|
19
19
|
from sqlspec.exceptions import NotFoundError
|
|
20
|
+
from sqlspec.statement import SQLStatement
|
|
20
21
|
from sqlspec.typing import ModelDTOT, StatementParameterType
|
|
21
22
|
|
|
23
|
+
if TYPE_CHECKING:
|
|
24
|
+
from contextlib import AbstractAsyncContextManager, AbstractContextManager
|
|
25
|
+
|
|
26
|
+
from pyarrow import Table as ArrowTable
|
|
27
|
+
|
|
22
28
|
__all__ = (
|
|
29
|
+
"AsyncArrowBulkOperationsMixin",
|
|
23
30
|
"AsyncDatabaseConfig",
|
|
31
|
+
"AsyncDriverAdapterProtocol",
|
|
32
|
+
"CommonDriverAttributes",
|
|
24
33
|
"DatabaseConfigProtocol",
|
|
25
34
|
"GenericPoolConfig",
|
|
26
35
|
"NoPoolAsyncConfig",
|
|
27
36
|
"NoPoolSyncConfig",
|
|
37
|
+
"SQLSpec",
|
|
38
|
+
"SQLStatement",
|
|
39
|
+
"SyncArrowBulkOperationsMixin",
|
|
28
40
|
"SyncDatabaseConfig",
|
|
41
|
+
"SyncDriverAdapterProtocol",
|
|
29
42
|
)
|
|
30
43
|
|
|
31
44
|
T = TypeVar("T")
|
|
@@ -39,13 +52,15 @@ ConfigT = TypeVar(
|
|
|
39
52
|
bound="Union[Union[AsyncDatabaseConfig[Any, Any, Any], NoPoolAsyncConfig[Any, Any]], SyncDatabaseConfig[Any, Any, Any], NoPoolSyncConfig[Any, Any]]",
|
|
40
53
|
)
|
|
41
54
|
DriverT = TypeVar("DriverT", bound="Union[SyncDriverAdapterProtocol[Any], AsyncDriverAdapterProtocol[Any]]")
|
|
42
|
-
|
|
43
|
-
# Regex to find :param style placeholders, avoiding those inside quotes
|
|
44
|
-
# Handles basic cases, might need refinement for complex SQL
|
|
55
|
+
# Regex to find :param or %(param)s style placeholders, skipping those inside quotes
|
|
45
56
|
PARAM_REGEX = re.compile(
|
|
46
|
-
r"
|
|
47
|
-
|
|
48
|
-
|
|
57
|
+
r"""
|
|
58
|
+
(?P<dquote>"([^"]|\\")*") | # Double-quoted strings
|
|
59
|
+
(?P<squote>'([^']|\\')*') | # Single-quoted strings
|
|
60
|
+
: (?P<var_name_colon>[a-zA-Z_][a-zA-Z0-9_]*) | # :var_name
|
|
61
|
+
% \( (?P<var_name_perc>[a-zA-Z_][a-zA-Z0-9_]*) \) s # %(var_name)s
|
|
62
|
+
""",
|
|
63
|
+
re.VERBOSE,
|
|
49
64
|
)
|
|
50
65
|
|
|
51
66
|
|
|
@@ -56,14 +71,14 @@ class DatabaseConfigProtocol(ABC, Generic[ConnectionT, PoolT, DriverT]):
|
|
|
56
71
|
connection_type: "type[ConnectionT]" = field(init=False)
|
|
57
72
|
driver_type: "type[DriverT]" = field(init=False)
|
|
58
73
|
pool_instance: "Optional[PoolT]" = field(default=None)
|
|
59
|
-
__is_async__: ClassVar[bool] = False
|
|
60
|
-
__supports_connection_pooling__: ClassVar[bool] = False
|
|
74
|
+
__is_async__: "ClassVar[bool]" = False
|
|
75
|
+
__supports_connection_pooling__: "ClassVar[bool]" = False
|
|
61
76
|
|
|
62
77
|
def __hash__(self) -> int:
|
|
63
78
|
return id(self)
|
|
64
79
|
|
|
65
80
|
@abstractmethod
|
|
66
|
-
def create_connection(self) -> Union[ConnectionT, Awaitable[ConnectionT]]:
|
|
81
|
+
def create_connection(self) -> "Union[ConnectionT, Awaitable[ConnectionT]]":
|
|
67
82
|
"""Create and return a new database connection."""
|
|
68
83
|
raise NotImplementedError
|
|
69
84
|
|
|
@@ -72,28 +87,32 @@ class DatabaseConfigProtocol(ABC, Generic[ConnectionT, PoolT, DriverT]):
|
|
|
72
87
|
self,
|
|
73
88
|
*args: Any,
|
|
74
89
|
**kwargs: Any,
|
|
75
|
-
) -> Union[
|
|
76
|
-
Generator[ConnectionT, None, None],
|
|
77
|
-
AsyncGenerator[ConnectionT, None],
|
|
78
|
-
AbstractContextManager[ConnectionT],
|
|
79
|
-
AbstractAsyncContextManager[ConnectionT],
|
|
80
|
-
]:
|
|
90
|
+
) -> "Union[AbstractContextManager[ConnectionT], AbstractAsyncContextManager[ConnectionT]]":
|
|
81
91
|
"""Provide a database connection context manager."""
|
|
82
92
|
raise NotImplementedError
|
|
83
93
|
|
|
94
|
+
@abstractmethod
|
|
95
|
+
def provide_session(
|
|
96
|
+
self,
|
|
97
|
+
*args: Any,
|
|
98
|
+
**kwargs: Any,
|
|
99
|
+
) -> "Union[AbstractContextManager[DriverT], AbstractAsyncContextManager[DriverT]]":
|
|
100
|
+
"""Provide a database session context manager."""
|
|
101
|
+
raise NotImplementedError
|
|
102
|
+
|
|
84
103
|
@property
|
|
85
104
|
@abstractmethod
|
|
86
|
-
def connection_config_dict(self) -> dict[str, Any]:
|
|
105
|
+
def connection_config_dict(self) -> "dict[str, Any]":
|
|
87
106
|
"""Return the connection configuration as a dict."""
|
|
88
107
|
raise NotImplementedError
|
|
89
108
|
|
|
90
109
|
@abstractmethod
|
|
91
|
-
def create_pool(self) -> Union[PoolT, Awaitable[PoolT]]:
|
|
110
|
+
def create_pool(self) -> "Union[PoolT, Awaitable[PoolT]]":
|
|
92
111
|
"""Create and return connection pool."""
|
|
93
112
|
raise NotImplementedError
|
|
94
113
|
|
|
95
114
|
@abstractmethod
|
|
96
|
-
def close_pool(self) -> Optional[Awaitable[None]]:
|
|
115
|
+
def close_pool(self) -> "Optional[Awaitable[None]]":
|
|
97
116
|
"""Terminate the connection pool."""
|
|
98
117
|
raise NotImplementedError
|
|
99
118
|
|
|
@@ -102,7 +121,7 @@ class DatabaseConfigProtocol(ABC, Generic[ConnectionT, PoolT, DriverT]):
|
|
|
102
121
|
self,
|
|
103
122
|
*args: Any,
|
|
104
123
|
**kwargs: Any,
|
|
105
|
-
) -> Union[PoolT, Awaitable[PoolT], AbstractContextManager[PoolT], AbstractAsyncContextManager[PoolT]]:
|
|
124
|
+
) -> "Union[PoolT, Awaitable[PoolT], AbstractContextManager[PoolT], AbstractAsyncContextManager[PoolT]]":
|
|
106
125
|
"""Provide pool instance."""
|
|
107
126
|
raise NotImplementedError
|
|
108
127
|
|
|
@@ -185,18 +204,15 @@ class SQLSpec:
|
|
|
185
204
|
self._configs: dict[Any, DatabaseConfigProtocol[Any, Any, Any]] = {}
|
|
186
205
|
|
|
187
206
|
@overload
|
|
188
|
-
def add_config(self, config: SyncConfigT) -> type[SyncConfigT]: ...
|
|
207
|
+
def add_config(self, config: "SyncConfigT") -> "type[SyncConfigT]": ...
|
|
189
208
|
|
|
190
209
|
@overload
|
|
191
|
-
def add_config(self, config: AsyncConfigT) -> type[AsyncConfigT]: ...
|
|
210
|
+
def add_config(self, config: "AsyncConfigT") -> "type[AsyncConfigT]": ...
|
|
192
211
|
|
|
193
212
|
def add_config(
|
|
194
213
|
self,
|
|
195
|
-
config: Union[
|
|
196
|
-
|
|
197
|
-
AsyncConfigT,
|
|
198
|
-
],
|
|
199
|
-
) -> Union[Annotated[type[SyncConfigT], int], Annotated[type[AsyncConfigT], int]]: # pyright: ignore[reportInvalidTypeVarUse]
|
|
214
|
+
config: "Union[SyncConfigT, AsyncConfigT]",
|
|
215
|
+
) -> "Union[Annotated[type[SyncConfigT], int], Annotated[type[AsyncConfigT], int]]": # pyright: ignore[reportInvalidTypeVarUse]
|
|
200
216
|
"""Add a new configuration to the manager.
|
|
201
217
|
|
|
202
218
|
Returns:
|
|
@@ -207,15 +223,15 @@ class SQLSpec:
|
|
|
207
223
|
return key # type: ignore[return-value] # pyright: ignore[reportReturnType]
|
|
208
224
|
|
|
209
225
|
@overload
|
|
210
|
-
def get_config(self, name: type[SyncConfigT]) -> SyncConfigT: ...
|
|
226
|
+
def get_config(self, name: "type[SyncConfigT]") -> "SyncConfigT": ...
|
|
211
227
|
|
|
212
228
|
@overload
|
|
213
|
-
def get_config(self, name: type[AsyncConfigT]) -> AsyncConfigT: ...
|
|
229
|
+
def get_config(self, name: "type[AsyncConfigT]") -> "AsyncConfigT": ...
|
|
214
230
|
|
|
215
231
|
def get_config(
|
|
216
232
|
self,
|
|
217
|
-
name: Union[type[DatabaseConfigProtocol[ConnectionT, PoolT, DriverT]], Any],
|
|
218
|
-
) -> DatabaseConfigProtocol[ConnectionT, PoolT, DriverT]:
|
|
233
|
+
name: "Union[type[DatabaseConfigProtocol[ConnectionT, PoolT, DriverT]], Any]",
|
|
234
|
+
) -> "DatabaseConfigProtocol[ConnectionT, PoolT, DriverT]":
|
|
219
235
|
"""Retrieve a configuration by its type.
|
|
220
236
|
|
|
221
237
|
Returns:
|
|
@@ -234,61 +250,135 @@ class SQLSpec:
|
|
|
234
250
|
def get_connection(
|
|
235
251
|
self,
|
|
236
252
|
name: Union[
|
|
237
|
-
type[NoPoolSyncConfig[ConnectionT, DriverT]],
|
|
238
|
-
type[SyncDatabaseConfig[ConnectionT, PoolT, DriverT]], # pyright: ignore[reportInvalidTypeVarUse]
|
|
253
|
+
"type[NoPoolSyncConfig[ConnectionT, DriverT]]",
|
|
254
|
+
"type[SyncDatabaseConfig[ConnectionT, PoolT, DriverT]]", # pyright: ignore[reportInvalidTypeVarUse]
|
|
239
255
|
],
|
|
240
|
-
) -> ConnectionT: ...
|
|
256
|
+
) -> "ConnectionT": ...
|
|
241
257
|
|
|
242
258
|
@overload
|
|
243
259
|
def get_connection(
|
|
244
260
|
self,
|
|
245
261
|
name: Union[
|
|
246
|
-
type[NoPoolAsyncConfig[ConnectionT, DriverT]],
|
|
247
|
-
type[AsyncDatabaseConfig[ConnectionT, PoolT, DriverT]], # pyright: ignore[reportInvalidTypeVarUse]
|
|
262
|
+
"type[NoPoolAsyncConfig[ConnectionT, DriverT]]",
|
|
263
|
+
"type[AsyncDatabaseConfig[ConnectionT, PoolT, DriverT]]", # pyright: ignore[reportInvalidTypeVarUse]
|
|
248
264
|
],
|
|
249
|
-
) -> Awaitable[ConnectionT]: ...
|
|
265
|
+
) -> "Awaitable[ConnectionT]": ...
|
|
250
266
|
|
|
251
267
|
def get_connection(
|
|
252
268
|
self,
|
|
253
269
|
name: Union[
|
|
254
|
-
type[NoPoolSyncConfig[ConnectionT, DriverT]],
|
|
255
|
-
type[NoPoolAsyncConfig[ConnectionT, DriverT]],
|
|
256
|
-
type[SyncDatabaseConfig[ConnectionT, PoolT, DriverT]],
|
|
257
|
-
type[AsyncDatabaseConfig[ConnectionT, PoolT, DriverT]],
|
|
270
|
+
"type[NoPoolSyncConfig[ConnectionT, DriverT]]",
|
|
271
|
+
"type[NoPoolAsyncConfig[ConnectionT, DriverT]]",
|
|
272
|
+
"type[SyncDatabaseConfig[ConnectionT, PoolT, DriverT]]",
|
|
273
|
+
"type[AsyncDatabaseConfig[ConnectionT, PoolT, DriverT]]",
|
|
258
274
|
],
|
|
259
|
-
) -> Union[ConnectionT, Awaitable[ConnectionT]]:
|
|
260
|
-
"""Create and return a connection from the specified configuration.
|
|
275
|
+
) -> "Union[ConnectionT, Awaitable[ConnectionT]]":
|
|
276
|
+
"""Create and return a new database connection from the specified configuration.
|
|
261
277
|
|
|
262
278
|
Args:
|
|
263
279
|
name: The configuration type to use for creating the connection.
|
|
264
280
|
|
|
265
281
|
Returns:
|
|
266
|
-
Either a connection instance or an awaitable that resolves to a connection
|
|
267
|
-
depending on whether the configuration is sync or async.
|
|
282
|
+
Either a connection instance or an awaitable that resolves to a connection instance.
|
|
268
283
|
"""
|
|
269
284
|
config = self.get_config(name)
|
|
270
285
|
return config.create_connection()
|
|
271
286
|
|
|
287
|
+
def get_session(
|
|
288
|
+
self,
|
|
289
|
+
name: Union[
|
|
290
|
+
"type[NoPoolSyncConfig[ConnectionT, DriverT]]",
|
|
291
|
+
"type[NoPoolAsyncConfig[ConnectionT, DriverT]]",
|
|
292
|
+
"type[SyncDatabaseConfig[ConnectionT, PoolT, DriverT]]",
|
|
293
|
+
"type[AsyncDatabaseConfig[ConnectionT, PoolT, DriverT]]",
|
|
294
|
+
],
|
|
295
|
+
) -> "Union[DriverT, Awaitable[DriverT]]":
|
|
296
|
+
"""Create and return a new database session from the specified configuration.
|
|
297
|
+
|
|
298
|
+
Args:
|
|
299
|
+
name: The configuration type to use for creating the session.
|
|
300
|
+
|
|
301
|
+
Returns:
|
|
302
|
+
Either a driver instance or an awaitable that resolves to a driver instance.
|
|
303
|
+
"""
|
|
304
|
+
config = self.get_config(name)
|
|
305
|
+
connection = self.get_connection(name)
|
|
306
|
+
if isinstance(connection, Awaitable):
|
|
307
|
+
|
|
308
|
+
async def _create_session() -> DriverT:
|
|
309
|
+
return cast("DriverT", config.driver_type(await connection)) # pyright: ignore
|
|
310
|
+
|
|
311
|
+
return _create_session()
|
|
312
|
+
return cast("DriverT", config.driver_type(connection)) # pyright: ignore
|
|
313
|
+
|
|
314
|
+
def provide_connection(
|
|
315
|
+
self,
|
|
316
|
+
name: Union[
|
|
317
|
+
"type[NoPoolSyncConfig[ConnectionT, DriverT]]",
|
|
318
|
+
"type[NoPoolAsyncConfig[ConnectionT, DriverT]]",
|
|
319
|
+
"type[SyncDatabaseConfig[ConnectionT, PoolT, DriverT]]",
|
|
320
|
+
"type[AsyncDatabaseConfig[ConnectionT, PoolT, DriverT]]",
|
|
321
|
+
],
|
|
322
|
+
*args: Any,
|
|
323
|
+
**kwargs: Any,
|
|
324
|
+
) -> "Union[AbstractContextManager[ConnectionT], AbstractAsyncContextManager[ConnectionT]]":
|
|
325
|
+
"""Create and provide a database connection from the specified configuration.
|
|
326
|
+
|
|
327
|
+
Args:
|
|
328
|
+
name: The configuration type to use for creating the connection.
|
|
329
|
+
*args: Positional arguments to pass to the configuration's provide_connection method.
|
|
330
|
+
**kwargs: Keyword arguments to pass to the configuration's provide_connection method.
|
|
331
|
+
|
|
332
|
+
Returns:
|
|
333
|
+
Either a synchronous or asynchronous context manager that provides a database connection.
|
|
334
|
+
"""
|
|
335
|
+
config = self.get_config(name)
|
|
336
|
+
return config.provide_connection(*args, **kwargs)
|
|
337
|
+
|
|
338
|
+
def provide_session(
|
|
339
|
+
self,
|
|
340
|
+
name: Union[
|
|
341
|
+
"type[NoPoolSyncConfig[ConnectionT, DriverT]]",
|
|
342
|
+
"type[NoPoolAsyncConfig[ConnectionT, DriverT]]",
|
|
343
|
+
"type[SyncDatabaseConfig[ConnectionT, PoolT, DriverT]]",
|
|
344
|
+
"type[AsyncDatabaseConfig[ConnectionT, PoolT, DriverT]]",
|
|
345
|
+
],
|
|
346
|
+
*args: Any,
|
|
347
|
+
**kwargs: Any,
|
|
348
|
+
) -> "Union[AbstractContextManager[DriverT], AbstractAsyncContextManager[DriverT]]":
|
|
349
|
+
"""Create and provide a database session from the specified configuration.
|
|
350
|
+
|
|
351
|
+
Args:
|
|
352
|
+
name: The configuration type to use for creating the session.
|
|
353
|
+
*args: Positional arguments to pass to the configuration's provide_session method.
|
|
354
|
+
**kwargs: Keyword arguments to pass to the configuration's provide_session method.
|
|
355
|
+
|
|
356
|
+
Returns:
|
|
357
|
+
Either a synchronous or asynchronous context manager that provides a database session.
|
|
358
|
+
"""
|
|
359
|
+
config = self.get_config(name)
|
|
360
|
+
return config.provide_session(*args, **kwargs)
|
|
361
|
+
|
|
272
362
|
@overload
|
|
273
363
|
def get_pool(
|
|
274
|
-
self, name: type[Union[NoPoolSyncConfig[ConnectionT, DriverT], NoPoolAsyncConfig[ConnectionT, DriverT]]]
|
|
275
|
-
) -> None: ... # pyright: ignore[reportInvalidTypeVarUse]
|
|
364
|
+
self, name: "type[Union[NoPoolSyncConfig[ConnectionT, DriverT], NoPoolAsyncConfig[ConnectionT, DriverT]]]"
|
|
365
|
+
) -> "None": ... # pyright: ignore[reportInvalidTypeVarUse]
|
|
276
366
|
|
|
277
367
|
@overload
|
|
278
|
-
def get_pool(self, name: type[SyncDatabaseConfig[ConnectionT, PoolT, DriverT]]) -> type[PoolT]: ... # pyright: ignore[reportInvalidTypeVarUse]
|
|
368
|
+
def get_pool(self, name: "type[SyncDatabaseConfig[ConnectionT, PoolT, DriverT]]") -> "type[PoolT]": ... # pyright: ignore[reportInvalidTypeVarUse]
|
|
279
369
|
|
|
280
370
|
@overload
|
|
281
|
-
def get_pool(self, name: type[AsyncDatabaseConfig[ConnectionT, PoolT, DriverT]]) -> Awaitable[type[PoolT]]: ... # pyright: ignore[reportInvalidTypeVarUse]
|
|
371
|
+
def get_pool(self, name: "type[AsyncDatabaseConfig[ConnectionT, PoolT, DriverT]]") -> "Awaitable[type[PoolT]]": ... # pyright: ignore[reportInvalidTypeVarUse]
|
|
282
372
|
|
|
283
373
|
def get_pool(
|
|
284
374
|
self,
|
|
285
375
|
name: Union[
|
|
286
|
-
type[NoPoolSyncConfig[ConnectionT, DriverT]],
|
|
287
|
-
type[NoPoolAsyncConfig[ConnectionT, DriverT]],
|
|
288
|
-
type[SyncDatabaseConfig[ConnectionT, PoolT, DriverT]],
|
|
289
|
-
type[AsyncDatabaseConfig[ConnectionT, PoolT, DriverT]],
|
|
376
|
+
"type[NoPoolSyncConfig[ConnectionT, DriverT]]",
|
|
377
|
+
"type[NoPoolAsyncConfig[ConnectionT, DriverT]]",
|
|
378
|
+
"type[SyncDatabaseConfig[ConnectionT, PoolT, DriverT]]",
|
|
379
|
+
"type[AsyncDatabaseConfig[ConnectionT, PoolT, DriverT]]",
|
|
290
380
|
],
|
|
291
|
-
) -> Union[type[PoolT], Awaitable[type[PoolT]], None]:
|
|
381
|
+
) -> "Union[type[PoolT], Awaitable[type[PoolT]], None]":
|
|
292
382
|
"""Create and return a connection pool from the specified configuration.
|
|
293
383
|
|
|
294
384
|
Args:
|
|
@@ -306,12 +396,12 @@ class SQLSpec:
|
|
|
306
396
|
def close_pool(
|
|
307
397
|
self,
|
|
308
398
|
name: Union[
|
|
309
|
-
type[NoPoolSyncConfig[ConnectionT, DriverT]],
|
|
310
|
-
type[NoPoolAsyncConfig[ConnectionT, DriverT]],
|
|
311
|
-
type[SyncDatabaseConfig[ConnectionT, PoolT, DriverT]],
|
|
312
|
-
type[AsyncDatabaseConfig[ConnectionT, PoolT, DriverT]],
|
|
399
|
+
"type[NoPoolSyncConfig[ConnectionT, DriverT]]",
|
|
400
|
+
"type[NoPoolAsyncConfig[ConnectionT, DriverT]]",
|
|
401
|
+
"type[SyncDatabaseConfig[ConnectionT, PoolT, DriverT]]",
|
|
402
|
+
"type[AsyncDatabaseConfig[ConnectionT, PoolT, DriverT]]",
|
|
313
403
|
],
|
|
314
|
-
) -> Optional[Awaitable[None]]:
|
|
404
|
+
) -> "Optional[Awaitable[None]]":
|
|
315
405
|
"""Close the connection pool for the specified configuration.
|
|
316
406
|
|
|
317
407
|
Args:
|
|
@@ -329,10 +419,12 @@ class SQLSpec:
|
|
|
329
419
|
class CommonDriverAttributes(Generic[ConnectionT]):
|
|
330
420
|
"""Common attributes and methods for driver adapters."""
|
|
331
421
|
|
|
332
|
-
|
|
333
|
-
"""The
|
|
422
|
+
dialect: str
|
|
423
|
+
"""The SQL dialect supported by the underlying database driver (e.g., 'postgres', 'mysql')."""
|
|
334
424
|
connection: ConnectionT
|
|
335
425
|
"""The connection to the underlying database."""
|
|
426
|
+
__supports_arrow__: ClassVar[bool] = False
|
|
427
|
+
"""Indicates if the driver supports Apache Arrow operations."""
|
|
336
428
|
|
|
337
429
|
def _connection(self, connection: "Optional[ConnectionT]" = None) -> "ConnectionT":
|
|
338
430
|
return connection if connection is not None else self.connection
|
|
@@ -355,99 +447,70 @@ class CommonDriverAttributes(Generic[ConnectionT]):
|
|
|
355
447
|
raise NotFoundError(msg)
|
|
356
448
|
return item_or_none
|
|
357
449
|
|
|
358
|
-
def
|
|
359
|
-
|
|
360
|
-
|
|
450
|
+
def _process_sql_params(
|
|
451
|
+
self, sql: str, parameters: "Optional[StatementParameterType]" = None, /, **kwargs: Any
|
|
452
|
+
) -> "tuple[str, Optional[Union[tuple[Any, ...], list[Any], dict[str, Any]]]]":
|
|
453
|
+
"""Process SQL query and parameters using SQLStatement for validation and formatting.
|
|
361
454
|
|
|
362
455
|
Args:
|
|
363
456
|
sql: The SQL query string.
|
|
457
|
+
parameters: Parameters for the query.
|
|
458
|
+
**kwargs: Additional keyword arguments to merge with parameters if parameters is a dict.
|
|
364
459
|
|
|
365
460
|
Returns:
|
|
366
|
-
|
|
461
|
+
A tuple containing the processed SQL query and parameters.
|
|
367
462
|
"""
|
|
368
|
-
|
|
463
|
+
# Instantiate SQLStatement with parameters and kwargs for internal merging
|
|
464
|
+
stmt = SQLStatement(sql=sql, parameters=parameters, dialect=self.dialect, kwargs=kwargs or None)
|
|
465
|
+
# Process uses the merged parameters internally
|
|
466
|
+
return stmt.process()
|
|
369
467
|
|
|
370
|
-
def _process_sql_params(
|
|
371
|
-
self, sql: str, parameters: "Optional[StatementParameterType]" = None
|
|
372
|
-
) -> "tuple[str, Optional[Union[tuple[Any, ...], list[Any], dict[str, Any]]]]":
|
|
373
|
-
"""Process SQL query and parameters for DB-API execution.
|
|
374
468
|
|
|
375
|
-
|
|
376
|
-
|
|
469
|
+
class SyncArrowBulkOperationsMixin(Generic[ConnectionT]):
|
|
470
|
+
"""Mixin for sync drivers supporting bulk Apache Arrow operations."""
|
|
471
|
+
|
|
472
|
+
__supports_arrow__: "ClassVar[bool]" = True
|
|
473
|
+
|
|
474
|
+
@abstractmethod
|
|
475
|
+
def select_arrow( # pyright: ignore[reportUnknownParameterType]
|
|
476
|
+
self,
|
|
477
|
+
sql: str,
|
|
478
|
+
parameters: "Optional[StatementParameterType]" = None,
|
|
479
|
+
/,
|
|
480
|
+
*,
|
|
481
|
+
connection: "Optional[ConnectionT]" = None,
|
|
482
|
+
**kwargs: Any,
|
|
483
|
+
) -> "ArrowTable": # pyright: ignore[reportUnknownReturnType]
|
|
484
|
+
"""Execute a SQL query and return results as an Apache Arrow Table.
|
|
377
485
|
|
|
378
486
|
Args:
|
|
379
487
|
sql: The SQL query string.
|
|
380
|
-
parameters:
|
|
488
|
+
parameters: Parameters for the query.
|
|
489
|
+
connection: Optional connection override.
|
|
490
|
+
**kwargs: Additional keyword arguments to merge with parameters if parameters is a dict.
|
|
381
491
|
|
|
382
492
|
Returns:
|
|
383
|
-
|
|
384
|
-
(always a tuple or None if the input was a dictionary, otherwise the original type).
|
|
385
|
-
|
|
386
|
-
Raises:
|
|
387
|
-
ValueError: If a named parameter in the SQL is not found in the dictionary
|
|
388
|
-
or if a parameter in the dictionary is not used in the SQL.
|
|
493
|
+
An Apache Arrow Table containing the query results.
|
|
389
494
|
"""
|
|
390
|
-
|
|
391
|
-
# If parameters are not a dict, or empty dict, assume positional/no params
|
|
392
|
-
# Let the underlying driver handle tuples/lists directly
|
|
393
|
-
return self._process_sql_statement(sql), parameters
|
|
394
|
-
|
|
395
|
-
processed_sql = ""
|
|
396
|
-
processed_params_list: list[Any] = []
|
|
397
|
-
last_end = 0
|
|
398
|
-
found_params: set[str] = set()
|
|
399
|
-
|
|
400
|
-
for match in PARAM_REGEX.finditer(sql):
|
|
401
|
-
if match.group("dquote") is not None or match.group("squote") is not None:
|
|
402
|
-
# Skip placeholders within quotes
|
|
403
|
-
continue
|
|
404
|
-
|
|
405
|
-
var_name = match.group("var_name")
|
|
406
|
-
if var_name is None: # Should not happen with the regex, but safeguard
|
|
407
|
-
continue
|
|
408
|
-
|
|
409
|
-
if var_name not in parameters:
|
|
410
|
-
msg = f"Named parameter ':{var_name}' found in SQL but not provided in parameters dictionary."
|
|
411
|
-
raise ValueError(msg)
|
|
412
|
-
|
|
413
|
-
# Append segment before the placeholder + the leading character + the driver's positional placeholder
|
|
414
|
-
# The match.start("var_name") -1 includes the character before the ':'
|
|
415
|
-
processed_sql += sql[last_end : match.start("var_name")] + self.param_style
|
|
416
|
-
processed_params_list.append(parameters[var_name])
|
|
417
|
-
found_params.add(var_name)
|
|
418
|
-
last_end = match.end("var_name")
|
|
419
|
-
|
|
420
|
-
# Append the rest of the SQL string
|
|
421
|
-
processed_sql += sql[last_end:]
|
|
422
|
-
|
|
423
|
-
# Check if all provided parameters were used
|
|
424
|
-
unused_params = set(parameters.keys()) - found_params
|
|
425
|
-
if unused_params:
|
|
426
|
-
msg = f"Parameters provided but not found in SQL: {unused_params}"
|
|
427
|
-
# Depending on desired strictness, this could be a warning or an error
|
|
428
|
-
# For now, let's raise an error for clarity
|
|
429
|
-
raise ValueError(msg)
|
|
430
|
-
|
|
431
|
-
processed_params = tuple(processed_params_list)
|
|
432
|
-
# Pass the processed SQL through the driver-specific processor if needed
|
|
433
|
-
final_sql = self._process_sql_statement(processed_sql)
|
|
434
|
-
return final_sql, processed_params
|
|
495
|
+
raise NotImplementedError
|
|
435
496
|
|
|
436
497
|
|
|
437
498
|
class SyncDriverAdapterProtocol(CommonDriverAttributes[ConnectionT], ABC, Generic[ConnectionT]):
|
|
438
|
-
connection: ConnectionT
|
|
499
|
+
connection: "ConnectionT"
|
|
439
500
|
|
|
440
|
-
def __init__(self, connection: ConnectionT) -> None:
|
|
501
|
+
def __init__(self, connection: "ConnectionT", **kwargs: Any) -> None:
|
|
441
502
|
self.connection = connection
|
|
442
503
|
|
|
443
504
|
@abstractmethod
|
|
444
505
|
def select(
|
|
445
506
|
self,
|
|
446
507
|
sql: str,
|
|
447
|
-
parameters: Optional[StatementParameterType] = None,
|
|
508
|
+
parameters: "Optional[StatementParameterType]" = None,
|
|
448
509
|
/,
|
|
449
|
-
|
|
510
|
+
*,
|
|
511
|
+
connection: "Optional[ConnectionT]" = None,
|
|
450
512
|
schema_type: Optional[type[ModelDTOT]] = None,
|
|
513
|
+
**kwargs: Any,
|
|
451
514
|
) -> "list[Union[ModelDTOT, dict[str, Any]]]": ...
|
|
452
515
|
|
|
453
516
|
@abstractmethod
|
|
@@ -456,8 +519,10 @@ class SyncDriverAdapterProtocol(CommonDriverAttributes[ConnectionT], ABC, Generi
|
|
|
456
519
|
sql: str,
|
|
457
520
|
parameters: Optional[StatementParameterType] = None,
|
|
458
521
|
/,
|
|
522
|
+
*,
|
|
459
523
|
connection: Optional[ConnectionT] = None,
|
|
460
524
|
schema_type: Optional[type[ModelDTOT]] = None,
|
|
525
|
+
**kwargs: Any,
|
|
461
526
|
) -> "Union[ModelDTOT, dict[str, Any]]": ...
|
|
462
527
|
|
|
463
528
|
@abstractmethod
|
|
@@ -466,8 +531,10 @@ class SyncDriverAdapterProtocol(CommonDriverAttributes[ConnectionT], ABC, Generi
|
|
|
466
531
|
sql: str,
|
|
467
532
|
parameters: Optional[StatementParameterType] = None,
|
|
468
533
|
/,
|
|
534
|
+
*,
|
|
469
535
|
connection: Optional[ConnectionT] = None,
|
|
470
536
|
schema_type: Optional[type[ModelDTOT]] = None,
|
|
537
|
+
**kwargs: Any,
|
|
471
538
|
) -> "Optional[Union[ModelDTOT, dict[str, Any]]]": ...
|
|
472
539
|
|
|
473
540
|
@abstractmethod
|
|
@@ -476,8 +543,10 @@ class SyncDriverAdapterProtocol(CommonDriverAttributes[ConnectionT], ABC, Generi
|
|
|
476
543
|
sql: str,
|
|
477
544
|
parameters: Optional[StatementParameterType] = None,
|
|
478
545
|
/,
|
|
546
|
+
*,
|
|
479
547
|
connection: Optional[ConnectionT] = None,
|
|
480
548
|
schema_type: Optional[type[T]] = None,
|
|
549
|
+
**kwargs: Any,
|
|
481
550
|
) -> "Union[Any, T]": ...
|
|
482
551
|
|
|
483
552
|
@abstractmethod
|
|
@@ -486,8 +555,10 @@ class SyncDriverAdapterProtocol(CommonDriverAttributes[ConnectionT], ABC, Generi
|
|
|
486
555
|
sql: str,
|
|
487
556
|
parameters: Optional[StatementParameterType] = None,
|
|
488
557
|
/,
|
|
558
|
+
*,
|
|
489
559
|
connection: Optional[ConnectionT] = None,
|
|
490
560
|
schema_type: Optional[type[T]] = None,
|
|
561
|
+
**kwargs: Any,
|
|
491
562
|
) -> "Optional[Union[Any, T]]": ...
|
|
492
563
|
|
|
493
564
|
@abstractmethod
|
|
@@ -496,7 +567,9 @@ class SyncDriverAdapterProtocol(CommonDriverAttributes[ConnectionT], ABC, Generi
|
|
|
496
567
|
sql: str,
|
|
497
568
|
parameters: Optional[StatementParameterType] = None,
|
|
498
569
|
/,
|
|
570
|
+
*,
|
|
499
571
|
connection: Optional[ConnectionT] = None,
|
|
572
|
+
**kwargs: Any,
|
|
500
573
|
) -> int: ...
|
|
501
574
|
|
|
502
575
|
@abstractmethod
|
|
@@ -505,8 +578,10 @@ class SyncDriverAdapterProtocol(CommonDriverAttributes[ConnectionT], ABC, Generi
|
|
|
505
578
|
sql: str,
|
|
506
579
|
parameters: Optional[StatementParameterType] = None,
|
|
507
580
|
/,
|
|
581
|
+
*,
|
|
508
582
|
connection: Optional[ConnectionT] = None,
|
|
509
583
|
schema_type: Optional[type[ModelDTOT]] = None,
|
|
584
|
+
**kwargs: Any,
|
|
510
585
|
) -> "Optional[Union[dict[str, Any], ModelDTOT]]": ...
|
|
511
586
|
|
|
512
587
|
@abstractmethod
|
|
@@ -515,92 +590,139 @@ class SyncDriverAdapterProtocol(CommonDriverAttributes[ConnectionT], ABC, Generi
|
|
|
515
590
|
sql: str,
|
|
516
591
|
parameters: Optional[StatementParameterType] = None,
|
|
517
592
|
/,
|
|
593
|
+
*,
|
|
518
594
|
connection: Optional[ConnectionT] = None,
|
|
595
|
+
**kwargs: Any,
|
|
519
596
|
) -> str: ...
|
|
520
597
|
|
|
521
598
|
|
|
599
|
+
class AsyncArrowBulkOperationsMixin(Generic[ConnectionT]):
|
|
600
|
+
"""Mixin for async drivers supporting bulk Apache Arrow operations."""
|
|
601
|
+
|
|
602
|
+
__supports_arrow__: "ClassVar[bool]" = True
|
|
603
|
+
|
|
604
|
+
@abstractmethod
|
|
605
|
+
async def select_arrow( # pyright: ignore[reportUnknownParameterType]
|
|
606
|
+
self,
|
|
607
|
+
sql: str,
|
|
608
|
+
parameters: "Optional[StatementParameterType]" = None,
|
|
609
|
+
/,
|
|
610
|
+
*,
|
|
611
|
+
connection: "Optional[ConnectionT]" = None,
|
|
612
|
+
**kwargs: Any,
|
|
613
|
+
) -> "ArrowTable": # pyright: ignore[reportUnknownReturnType]
|
|
614
|
+
"""Execute a SQL query and return results as an Apache Arrow Table.
|
|
615
|
+
|
|
616
|
+
Args:
|
|
617
|
+
sql: The SQL query string.
|
|
618
|
+
parameters: Parameters for the query.
|
|
619
|
+
connection: Optional connection override.
|
|
620
|
+
**kwargs: Additional keyword arguments to merge with parameters if parameters is a dict.
|
|
621
|
+
|
|
622
|
+
Returns:
|
|
623
|
+
An Apache Arrow Table containing the query results.
|
|
624
|
+
"""
|
|
625
|
+
raise NotImplementedError
|
|
626
|
+
|
|
627
|
+
|
|
522
628
|
class AsyncDriverAdapterProtocol(CommonDriverAttributes[ConnectionT], ABC, Generic[ConnectionT]):
|
|
523
|
-
connection: ConnectionT
|
|
629
|
+
connection: "ConnectionT"
|
|
524
630
|
|
|
525
|
-
def __init__(self, connection: ConnectionT) -> None:
|
|
631
|
+
def __init__(self, connection: "ConnectionT") -> None:
|
|
526
632
|
self.connection = connection
|
|
527
633
|
|
|
528
634
|
@abstractmethod
|
|
529
635
|
async def select(
|
|
530
636
|
self,
|
|
531
637
|
sql: str,
|
|
532
|
-
parameters: Optional[StatementParameterType] = None,
|
|
638
|
+
parameters: "Optional[StatementParameterType]" = None,
|
|
533
639
|
/,
|
|
534
|
-
|
|
535
|
-
|
|
640
|
+
*,
|
|
641
|
+
connection: "Optional[ConnectionT]" = None,
|
|
642
|
+
schema_type: "Optional[type[ModelDTOT]]" = None,
|
|
643
|
+
**kwargs: Any,
|
|
536
644
|
) -> "list[Union[ModelDTOT, dict[str, Any]]]": ...
|
|
537
645
|
|
|
538
646
|
@abstractmethod
|
|
539
647
|
async def select_one(
|
|
540
648
|
self,
|
|
541
649
|
sql: str,
|
|
542
|
-
parameters: Optional[StatementParameterType] = None,
|
|
650
|
+
parameters: "Optional[StatementParameterType]" = None,
|
|
543
651
|
/,
|
|
544
|
-
|
|
545
|
-
|
|
652
|
+
*,
|
|
653
|
+
connection: "Optional[ConnectionT]" = None,
|
|
654
|
+
schema_type: "Optional[type[ModelDTOT]]" = None,
|
|
655
|
+
**kwargs: Any,
|
|
546
656
|
) -> "Union[ModelDTOT, dict[str, Any]]": ...
|
|
547
657
|
|
|
548
658
|
@abstractmethod
|
|
549
659
|
async def select_one_or_none(
|
|
550
660
|
self,
|
|
551
661
|
sql: str,
|
|
552
|
-
parameters: Optional[StatementParameterType] = None,
|
|
662
|
+
parameters: "Optional[StatementParameterType]" = None,
|
|
553
663
|
/,
|
|
554
|
-
|
|
555
|
-
|
|
664
|
+
*,
|
|
665
|
+
connection: "Optional[ConnectionT]" = None,
|
|
666
|
+
schema_type: "Optional[type[ModelDTOT]]" = None,
|
|
667
|
+
**kwargs: Any,
|
|
556
668
|
) -> "Optional[Union[ModelDTOT, dict[str, Any]]]": ...
|
|
557
669
|
|
|
558
670
|
@abstractmethod
|
|
559
671
|
async def select_value(
|
|
560
672
|
self,
|
|
561
673
|
sql: str,
|
|
562
|
-
parameters: Optional[StatementParameterType] = None,
|
|
674
|
+
parameters: "Optional[StatementParameterType]" = None,
|
|
563
675
|
/,
|
|
564
|
-
|
|
565
|
-
|
|
676
|
+
*,
|
|
677
|
+
connection: "Optional[ConnectionT]" = None,
|
|
678
|
+
schema_type: "Optional[type[T]]" = None,
|
|
679
|
+
**kwargs: Any,
|
|
566
680
|
) -> "Union[Any, T]": ...
|
|
567
681
|
|
|
568
682
|
@abstractmethod
|
|
569
683
|
async def select_value_or_none(
|
|
570
684
|
self,
|
|
571
685
|
sql: str,
|
|
572
|
-
parameters: Optional[StatementParameterType] = None,
|
|
686
|
+
parameters: "Optional[StatementParameterType]" = None,
|
|
573
687
|
/,
|
|
574
|
-
|
|
575
|
-
|
|
688
|
+
*,
|
|
689
|
+
connection: "Optional[ConnectionT]" = None,
|
|
690
|
+
schema_type: "Optional[type[T]]" = None,
|
|
691
|
+
**kwargs: Any,
|
|
576
692
|
) -> "Optional[Union[Any, T]]": ...
|
|
577
693
|
|
|
578
694
|
@abstractmethod
|
|
579
695
|
async def insert_update_delete(
|
|
580
696
|
self,
|
|
581
697
|
sql: str,
|
|
582
|
-
parameters: Optional[StatementParameterType] = None,
|
|
698
|
+
parameters: "Optional[StatementParameterType]" = None,
|
|
583
699
|
/,
|
|
584
|
-
|
|
700
|
+
*,
|
|
701
|
+
connection: "Optional[ConnectionT]" = None,
|
|
702
|
+
**kwargs: Any,
|
|
585
703
|
) -> int: ...
|
|
586
704
|
|
|
587
705
|
@abstractmethod
|
|
588
706
|
async def insert_update_delete_returning(
|
|
589
707
|
self,
|
|
590
708
|
sql: str,
|
|
591
|
-
parameters: Optional[StatementParameterType] = None,
|
|
709
|
+
parameters: "Optional[StatementParameterType]" = None,
|
|
592
710
|
/,
|
|
593
|
-
|
|
594
|
-
|
|
711
|
+
*,
|
|
712
|
+
connection: "Optional[ConnectionT]" = None,
|
|
713
|
+
schema_type: "Optional[type[ModelDTOT]]" = None,
|
|
714
|
+
**kwargs: Any,
|
|
595
715
|
) -> "Optional[Union[dict[str, Any], ModelDTOT]]": ...
|
|
596
716
|
|
|
597
717
|
@abstractmethod
|
|
598
718
|
async def execute_script(
|
|
599
719
|
self,
|
|
600
720
|
sql: str,
|
|
601
|
-
parameters: Optional[StatementParameterType] = None,
|
|
721
|
+
parameters: "Optional[StatementParameterType]" = None,
|
|
602
722
|
/,
|
|
603
|
-
|
|
723
|
+
*,
|
|
724
|
+
connection: "Optional[ConnectionT]" = None,
|
|
725
|
+
**kwargs: Any,
|
|
604
726
|
) -> str: ...
|
|
605
727
|
|
|
606
728
|
|