sqlspec 0.9.0__py3-none-any.whl → 0.10.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 +2 -1
- sqlspec/adapters/adbc/__init__.py +2 -1
- sqlspec/adapters/adbc/config.py +7 -13
- sqlspec/adapters/adbc/driver.py +160 -21
- sqlspec/adapters/aiosqlite/__init__.py +2 -1
- sqlspec/adapters/aiosqlite/config.py +10 -12
- sqlspec/adapters/aiosqlite/driver.py +160 -22
- sqlspec/adapters/asyncmy/__init__.py +2 -1
- sqlspec/adapters/asyncmy/driver.py +158 -22
- sqlspec/adapters/asyncpg/config.py +1 -3
- sqlspec/adapters/asyncpg/driver.py +143 -5
- sqlspec/adapters/bigquery/__init__.py +4 -0
- sqlspec/adapters/bigquery/config/__init__.py +3 -0
- sqlspec/adapters/bigquery/config/_common.py +40 -0
- sqlspec/adapters/bigquery/config/_sync.py +87 -0
- sqlspec/adapters/bigquery/driver.py +701 -0
- sqlspec/adapters/duckdb/__init__.py +2 -1
- sqlspec/adapters/duckdb/config.py +17 -18
- sqlspec/adapters/duckdb/driver.py +165 -27
- sqlspec/adapters/oracledb/__init__.py +8 -1
- sqlspec/adapters/oracledb/config/_asyncio.py +7 -8
- sqlspec/adapters/oracledb/config/_sync.py +6 -7
- sqlspec/adapters/oracledb/driver.py +311 -42
- sqlspec/adapters/psqlpy/__init__.py +9 -0
- sqlspec/adapters/psqlpy/config.py +11 -19
- sqlspec/adapters/psqlpy/driver.py +171 -19
- sqlspec/adapters/psycopg/__init__.py +8 -1
- sqlspec/adapters/psycopg/config/__init__.py +10 -0
- sqlspec/adapters/psycopg/config/_async.py +6 -7
- sqlspec/adapters/psycopg/config/_sync.py +7 -8
- sqlspec/adapters/psycopg/driver.py +344 -86
- sqlspec/adapters/sqlite/__init__.py +2 -1
- sqlspec/adapters/sqlite/config.py +12 -11
- sqlspec/adapters/sqlite/driver.py +160 -51
- sqlspec/base.py +402 -63
- sqlspec/exceptions.py +9 -0
- sqlspec/extensions/litestar/config.py +3 -11
- sqlspec/extensions/litestar/handlers.py +2 -1
- sqlspec/extensions/litestar/plugin.py +6 -2
- sqlspec/mixins.py +156 -0
- sqlspec/typing.py +19 -1
- {sqlspec-0.9.0.dist-info → sqlspec-0.10.0.dist-info}/METADATA +147 -3
- sqlspec-0.10.0.dist-info/RECORD +67 -0
- sqlspec-0.9.0.dist-info/RECORD +0 -61
- {sqlspec-0.9.0.dist-info → sqlspec-0.10.0.dist-info}/WHEEL +0 -0
- {sqlspec-0.9.0.dist-info → sqlspec-0.10.0.dist-info}/licenses/LICENSE +0 -0
- {sqlspec-0.9.0.dist-info → sqlspec-0.10.0.dist-info}/licenses/NOTICE +0 -0
|
@@ -1,19 +1,22 @@
|
|
|
1
1
|
import logging
|
|
2
2
|
import re
|
|
3
|
-
from typing import TYPE_CHECKING, Any, Optional, Union, cast
|
|
3
|
+
from typing import TYPE_CHECKING, Any, Optional, Union, cast, overload
|
|
4
4
|
|
|
5
5
|
from asyncpg import Connection
|
|
6
6
|
from typing_extensions import TypeAlias
|
|
7
7
|
|
|
8
|
-
from sqlspec.base import AsyncDriverAdapterProtocol
|
|
8
|
+
from sqlspec.base import AsyncDriverAdapterProtocol
|
|
9
9
|
from sqlspec.exceptions import SQLParsingError
|
|
10
|
+
from sqlspec.mixins import SQLTranslatorMixin
|
|
10
11
|
from sqlspec.statement import PARAM_REGEX, SQLStatement
|
|
11
12
|
|
|
12
13
|
if TYPE_CHECKING:
|
|
14
|
+
from collections.abc import Sequence
|
|
15
|
+
|
|
13
16
|
from asyncpg.connection import Connection
|
|
14
17
|
from asyncpg.pool import PoolConnectionProxy
|
|
15
18
|
|
|
16
|
-
from sqlspec.typing import ModelDTOT, StatementParameterType
|
|
19
|
+
from sqlspec.typing import ModelDTOT, StatementParameterType, T
|
|
17
20
|
|
|
18
21
|
__all__ = ("AsyncpgConnection", "AsyncpgDriver")
|
|
19
22
|
|
|
@@ -33,7 +36,10 @@ QMARK_REGEX = re.compile(
|
|
|
33
36
|
AsyncpgConnection: TypeAlias = "Union[Connection[Any], PoolConnectionProxy[Any]]" # pyright: ignore[reportMissingTypeArgument]
|
|
34
37
|
|
|
35
38
|
|
|
36
|
-
class AsyncpgDriver(
|
|
39
|
+
class AsyncpgDriver(
|
|
40
|
+
SQLTranslatorMixin["AsyncpgConnection"],
|
|
41
|
+
AsyncDriverAdapterProtocol["AsyncpgConnection"],
|
|
42
|
+
):
|
|
37
43
|
"""AsyncPG Postgres Driver Adapter."""
|
|
38
44
|
|
|
39
45
|
connection: "AsyncpgConnection"
|
|
@@ -196,6 +202,28 @@ class AsyncpgDriver(AsyncDriverAdapterProtocol["AsyncpgConnection"]):
|
|
|
196
202
|
# No parameters provided and none found in SQL, return original SQL from SQLStatement and empty tuple
|
|
197
203
|
return sql, () # asyncpg expects a sequence, even if empty
|
|
198
204
|
|
|
205
|
+
@overload
|
|
206
|
+
async def select(
|
|
207
|
+
self,
|
|
208
|
+
sql: str,
|
|
209
|
+
parameters: "Optional[StatementParameterType]" = None,
|
|
210
|
+
/,
|
|
211
|
+
*,
|
|
212
|
+
connection: "Optional[AsyncpgConnection]" = None,
|
|
213
|
+
schema_type: None = None,
|
|
214
|
+
**kwargs: Any,
|
|
215
|
+
) -> "Sequence[dict[str, Any]]": ...
|
|
216
|
+
@overload
|
|
217
|
+
async def select(
|
|
218
|
+
self,
|
|
219
|
+
sql: str,
|
|
220
|
+
parameters: "Optional[StatementParameterType]" = None,
|
|
221
|
+
/,
|
|
222
|
+
*,
|
|
223
|
+
connection: "Optional[AsyncpgConnection]" = None,
|
|
224
|
+
schema_type: "type[ModelDTOT]",
|
|
225
|
+
**kwargs: Any,
|
|
226
|
+
) -> "Sequence[ModelDTOT]": ...
|
|
199
227
|
async def select(
|
|
200
228
|
self,
|
|
201
229
|
sql: str,
|
|
@@ -205,7 +233,7 @@ class AsyncpgDriver(AsyncDriverAdapterProtocol["AsyncpgConnection"]):
|
|
|
205
233
|
connection: Optional["AsyncpgConnection"] = None,
|
|
206
234
|
schema_type: "Optional[type[ModelDTOT]]" = None,
|
|
207
235
|
**kwargs: Any,
|
|
208
|
-
) -> "
|
|
236
|
+
) -> "Sequence[Union[ModelDTOT, dict[str, Any]]]":
|
|
209
237
|
"""Fetch data from the database.
|
|
210
238
|
|
|
211
239
|
Args:
|
|
@@ -229,6 +257,28 @@ class AsyncpgDriver(AsyncDriverAdapterProtocol["AsyncpgConnection"]):
|
|
|
229
257
|
return [dict(row.items()) for row in results] # pyright: ignore[reportUnknownMemberType, reportUnknownVariableType]
|
|
230
258
|
return [cast("ModelDTOT", schema_type(**dict(row.items()))) for row in results] # pyright: ignore[reportUnknownMemberType, reportUnknownVariableType]
|
|
231
259
|
|
|
260
|
+
@overload
|
|
261
|
+
async def select_one(
|
|
262
|
+
self,
|
|
263
|
+
sql: str,
|
|
264
|
+
parameters: "Optional[StatementParameterType]" = None,
|
|
265
|
+
/,
|
|
266
|
+
*,
|
|
267
|
+
connection: "Optional[AsyncpgConnection]" = None,
|
|
268
|
+
schema_type: None = None,
|
|
269
|
+
**kwargs: Any,
|
|
270
|
+
) -> "dict[str, Any]": ...
|
|
271
|
+
@overload
|
|
272
|
+
async def select_one(
|
|
273
|
+
self,
|
|
274
|
+
sql: str,
|
|
275
|
+
parameters: "Optional[StatementParameterType]" = None,
|
|
276
|
+
/,
|
|
277
|
+
*,
|
|
278
|
+
connection: "Optional[AsyncpgConnection]" = None,
|
|
279
|
+
schema_type: "type[ModelDTOT]",
|
|
280
|
+
**kwargs: Any,
|
|
281
|
+
) -> "ModelDTOT": ...
|
|
232
282
|
async def select_one(
|
|
233
283
|
self,
|
|
234
284
|
sql: str,
|
|
@@ -262,6 +312,28 @@ class AsyncpgDriver(AsyncDriverAdapterProtocol["AsyncpgConnection"]):
|
|
|
262
312
|
return dict(result.items()) # type: ignore[attr-defined]
|
|
263
313
|
return cast("ModelDTOT", schema_type(**dict(result.items()))) # type: ignore[attr-defined]
|
|
264
314
|
|
|
315
|
+
@overload
|
|
316
|
+
async def select_one_or_none(
|
|
317
|
+
self,
|
|
318
|
+
sql: str,
|
|
319
|
+
parameters: "Optional[StatementParameterType]" = None,
|
|
320
|
+
/,
|
|
321
|
+
*,
|
|
322
|
+
connection: "Optional[AsyncpgConnection]" = None,
|
|
323
|
+
schema_type: None = None,
|
|
324
|
+
**kwargs: Any,
|
|
325
|
+
) -> "Optional[dict[str, Any]]": ...
|
|
326
|
+
@overload
|
|
327
|
+
async def select_one_or_none(
|
|
328
|
+
self,
|
|
329
|
+
sql: str,
|
|
330
|
+
parameters: "Optional[StatementParameterType]" = None,
|
|
331
|
+
/,
|
|
332
|
+
*,
|
|
333
|
+
connection: "Optional[AsyncpgConnection]" = None,
|
|
334
|
+
schema_type: "type[ModelDTOT]",
|
|
335
|
+
**kwargs: Any,
|
|
336
|
+
) -> "Optional[ModelDTOT]": ...
|
|
265
337
|
async def select_one_or_none(
|
|
266
338
|
self,
|
|
267
339
|
sql: str,
|
|
@@ -295,6 +367,28 @@ class AsyncpgDriver(AsyncDriverAdapterProtocol["AsyncpgConnection"]):
|
|
|
295
367
|
return dict(result.items())
|
|
296
368
|
return cast("ModelDTOT", schema_type(**dict(result.items())))
|
|
297
369
|
|
|
370
|
+
@overload
|
|
371
|
+
async def select_value(
|
|
372
|
+
self,
|
|
373
|
+
sql: str,
|
|
374
|
+
parameters: "Optional[StatementParameterType]" = None,
|
|
375
|
+
/,
|
|
376
|
+
*,
|
|
377
|
+
connection: "Optional[AsyncpgConnection]" = None,
|
|
378
|
+
schema_type: None = None,
|
|
379
|
+
**kwargs: Any,
|
|
380
|
+
) -> "Any": ...
|
|
381
|
+
@overload
|
|
382
|
+
async def select_value(
|
|
383
|
+
self,
|
|
384
|
+
sql: str,
|
|
385
|
+
parameters: "Optional[StatementParameterType]" = None,
|
|
386
|
+
/,
|
|
387
|
+
*,
|
|
388
|
+
connection: "Optional[AsyncpgConnection]" = None,
|
|
389
|
+
schema_type: "type[T]",
|
|
390
|
+
**kwargs: Any,
|
|
391
|
+
) -> "T": ...
|
|
298
392
|
async def select_value(
|
|
299
393
|
self,
|
|
300
394
|
sql: str,
|
|
@@ -326,6 +420,28 @@ class AsyncpgDriver(AsyncDriverAdapterProtocol["AsyncpgConnection"]):
|
|
|
326
420
|
return result
|
|
327
421
|
return schema_type(result) # type: ignore[call-arg]
|
|
328
422
|
|
|
423
|
+
@overload
|
|
424
|
+
async def select_value_or_none(
|
|
425
|
+
self,
|
|
426
|
+
sql: str,
|
|
427
|
+
parameters: "Optional[StatementParameterType]" = None,
|
|
428
|
+
/,
|
|
429
|
+
*,
|
|
430
|
+
connection: "Optional[AsyncpgConnection]" = None,
|
|
431
|
+
schema_type: None = None,
|
|
432
|
+
**kwargs: Any,
|
|
433
|
+
) -> "Optional[Any]": ...
|
|
434
|
+
@overload
|
|
435
|
+
async def select_value_or_none(
|
|
436
|
+
self,
|
|
437
|
+
sql: str,
|
|
438
|
+
parameters: "Optional[StatementParameterType]" = None,
|
|
439
|
+
/,
|
|
440
|
+
*,
|
|
441
|
+
connection: "Optional[AsyncpgConnection]" = None,
|
|
442
|
+
schema_type: "type[T]",
|
|
443
|
+
**kwargs: Any,
|
|
444
|
+
) -> "Optional[T]": ...
|
|
329
445
|
async def select_value_or_none(
|
|
330
446
|
self,
|
|
331
447
|
sql: str,
|
|
@@ -381,6 +497,28 @@ class AsyncpgDriver(AsyncDriverAdapterProtocol["AsyncpgConnection"]):
|
|
|
381
497
|
except (ValueError, IndexError, AttributeError):
|
|
382
498
|
return -1 # Fallback if we can't parse the status
|
|
383
499
|
|
|
500
|
+
@overload
|
|
501
|
+
async def insert_update_delete_returning(
|
|
502
|
+
self,
|
|
503
|
+
sql: str,
|
|
504
|
+
parameters: "Optional[StatementParameterType]" = None,
|
|
505
|
+
/,
|
|
506
|
+
*,
|
|
507
|
+
connection: "Optional[AsyncpgConnection]" = None,
|
|
508
|
+
schema_type: None = None,
|
|
509
|
+
**kwargs: Any,
|
|
510
|
+
) -> "dict[str, Any]": ...
|
|
511
|
+
@overload
|
|
512
|
+
async def insert_update_delete_returning(
|
|
513
|
+
self,
|
|
514
|
+
sql: str,
|
|
515
|
+
parameters: "Optional[StatementParameterType]" = None,
|
|
516
|
+
/,
|
|
517
|
+
*,
|
|
518
|
+
connection: "Optional[AsyncpgConnection]" = None,
|
|
519
|
+
schema_type: "type[ModelDTOT]",
|
|
520
|
+
**kwargs: Any,
|
|
521
|
+
) -> "ModelDTOT": ...
|
|
384
522
|
async def insert_update_delete_returning(
|
|
385
523
|
self,
|
|
386
524
|
sql: str,
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
from dataclasses import dataclass, field
|
|
2
|
+
from typing import TYPE_CHECKING, Optional
|
|
3
|
+
|
|
4
|
+
from google.cloud.bigquery import LoadJobConfig, QueryJobConfig
|
|
5
|
+
|
|
6
|
+
if TYPE_CHECKING:
|
|
7
|
+
from google.api_core.client_info import ClientInfo
|
|
8
|
+
from google.api_core.client_options import ClientOptions
|
|
9
|
+
from google.auth.credentials import Credentials
|
|
10
|
+
|
|
11
|
+
__all__ = ("BigQueryConnectionConfigCommon",)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@dataclass
|
|
15
|
+
class BigQueryConnectionConfigCommon:
|
|
16
|
+
"""Common configuration options for BigQuery."""
|
|
17
|
+
|
|
18
|
+
project: "Optional[str]" = field(default=None)
|
|
19
|
+
"""Google Cloud project ID."""
|
|
20
|
+
location: "Optional[str]" = field(default=None)
|
|
21
|
+
"""Default geographic location for jobs and datasets."""
|
|
22
|
+
credentials: "Optional[Credentials]" = field(default=None, hash=False)
|
|
23
|
+
"""Credentials to use for authentication."""
|
|
24
|
+
dataset_id: "Optional[str]" = field(default=None)
|
|
25
|
+
"""Default dataset ID to use if not specified in queries."""
|
|
26
|
+
credentials_path: "Optional[str]" = field(default=None)
|
|
27
|
+
"""Path to Google Cloud service account key file (JSON). If None, attempts default authentication."""
|
|
28
|
+
client_options: "Optional[ClientOptions]" = field(default=None, hash=False)
|
|
29
|
+
"""Client options used to set user options on the client (e.g., api_endpoint)."""
|
|
30
|
+
default_query_job_config: "Optional[QueryJobConfig]" = field(default=None, hash=False)
|
|
31
|
+
"""Default QueryJobConfig settings."""
|
|
32
|
+
default_load_job_config: "Optional[LoadJobConfig]" = field(default=None, hash=False)
|
|
33
|
+
"""Default LoadJobConfig settings."""
|
|
34
|
+
client_info: "Optional[ClientInfo]" = field(default=None, hash=False)
|
|
35
|
+
"""Client info used to send a user-agent string along with API requests."""
|
|
36
|
+
|
|
37
|
+
def __post_init__(self) -> None:
|
|
38
|
+
"""Post-initialization hook."""
|
|
39
|
+
if self.default_query_job_config is None:
|
|
40
|
+
self.default_query_job_config = QueryJobConfig(default_dataset=self.dataset_id)
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import contextlib
|
|
2
|
+
from dataclasses import dataclass, field
|
|
3
|
+
from typing import TYPE_CHECKING, Any, Optional
|
|
4
|
+
|
|
5
|
+
from sqlspec.adapters.bigquery.config._common import BigQueryConnectionConfigCommon
|
|
6
|
+
from sqlspec.adapters.bigquery.driver import BigQueryConnection, BigQueryDriver
|
|
7
|
+
from sqlspec.base import NoPoolSyncConfig
|
|
8
|
+
from sqlspec.typing import dataclass_to_dict
|
|
9
|
+
|
|
10
|
+
if TYPE_CHECKING:
|
|
11
|
+
from collections.abc import Iterator
|
|
12
|
+
|
|
13
|
+
__all__ = ("BigQueryConfig", "BigQueryConnectionConfig")
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class BigQueryConnectionConfig(BigQueryConnectionConfigCommon):
|
|
17
|
+
"""BigQuery Connection Configuration."""
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
@dataclass
|
|
21
|
+
class BigQueryConfig(NoPoolSyncConfig["BigQueryConnection", "BigQueryDriver"]):
|
|
22
|
+
"""BigQuery Synchronous Driver Configuration."""
|
|
23
|
+
|
|
24
|
+
connection_config: "BigQueryConnectionConfig" = field(default_factory=BigQueryConnectionConfig)
|
|
25
|
+
"""BigQuery Connection Configuration."""
|
|
26
|
+
driver_type: "type[BigQueryDriver]" = field(init=False, repr=False, default=BigQueryDriver)
|
|
27
|
+
"""BigQuery Driver Type."""
|
|
28
|
+
connection_type: "type[BigQueryConnection]" = field(init=False, repr=False, default=BigQueryConnection)
|
|
29
|
+
"""BigQuery Connection Type."""
|
|
30
|
+
pool_instance: "None" = field(init=False, repr=False, default=None, hash=False)
|
|
31
|
+
"""This is set to have a init=False since BigQuery does not support pooling."""
|
|
32
|
+
connection_instance: "Optional[BigQueryConnection]" = field(init=False, repr=False, default=None, hash=False)
|
|
33
|
+
"""BigQuery Connection Instance."""
|
|
34
|
+
|
|
35
|
+
@property
|
|
36
|
+
def connection_config_dict(self) -> "dict[str, Any]":
|
|
37
|
+
"""Return the connection configuration as a dict.
|
|
38
|
+
|
|
39
|
+
Returns:
|
|
40
|
+
A string keyed dict of config kwargs for the BigQueryConnection constructor.
|
|
41
|
+
"""
|
|
42
|
+
return dataclass_to_dict(
|
|
43
|
+
self.connection_config,
|
|
44
|
+
exclude_empty=True,
|
|
45
|
+
exclude_none=True,
|
|
46
|
+
exclude={"dataset_id", "credentials_path"},
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
def create_connection(self) -> "BigQueryConnection":
|
|
50
|
+
"""Create a BigQuery Client instance.
|
|
51
|
+
|
|
52
|
+
Returns:
|
|
53
|
+
A BigQuery Client instance.
|
|
54
|
+
"""
|
|
55
|
+
if self.connection_instance is not None:
|
|
56
|
+
return self.connection_instance
|
|
57
|
+
|
|
58
|
+
self.connection_instance = self.connection_type(**self.connection_config_dict)
|
|
59
|
+
return self.connection_instance
|
|
60
|
+
|
|
61
|
+
@contextlib.contextmanager
|
|
62
|
+
def provide_connection(self, *args: Any, **kwargs: Any) -> "Iterator[BigQueryConnection]":
|
|
63
|
+
"""Provide a BigQuery client within a context manager.
|
|
64
|
+
|
|
65
|
+
Args:
|
|
66
|
+
*args: Additional arguments to pass to the connection.
|
|
67
|
+
**kwargs: Additional keyword arguments to pass to the connection.
|
|
68
|
+
|
|
69
|
+
Yields:
|
|
70
|
+
An iterator of BigQuery Client instances.
|
|
71
|
+
"""
|
|
72
|
+
conn = self.create_connection()
|
|
73
|
+
yield conn
|
|
74
|
+
|
|
75
|
+
@contextlib.contextmanager
|
|
76
|
+
def provide_session(self, *args: Any, **kwargs: Any) -> "Iterator[BigQueryDriver]":
|
|
77
|
+
"""Provide a BigQuery driver session within a context manager.
|
|
78
|
+
|
|
79
|
+
Args:
|
|
80
|
+
*args: Additional arguments to pass to the driver.
|
|
81
|
+
**kwargs: Additional keyword arguments to pass to the driver.
|
|
82
|
+
|
|
83
|
+
Yields:
|
|
84
|
+
An iterator of BigQueryDriver instances.
|
|
85
|
+
"""
|
|
86
|
+
conn = self.create_connection()
|
|
87
|
+
yield self.driver_type(connection=conn)
|