sqlspec 0.3.0__py3-none-any.whl → 0.5.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/_serialization.py +1 -1
- sqlspec/_typing.py +58 -2
- sqlspec/adapters/adbc/config.py +8 -10
- sqlspec/adapters/aiosqlite/config.py +4 -21
- sqlspec/adapters/asyncmy/config.py +12 -25
- sqlspec/adapters/asyncpg/config.py +15 -21
- sqlspec/adapters/duckdb/__init__.py +3 -0
- sqlspec/adapters/duckdb/config.py +130 -29
- sqlspec/adapters/oracledb/__init__.py +1 -1
- sqlspec/adapters/oracledb/config/_asyncio.py +14 -14
- sqlspec/adapters/oracledb/config/_common.py +9 -9
- sqlspec/adapters/oracledb/config/_sync.py +9 -13
- sqlspec/adapters/psycopg/config/__init__.py +2 -2
- sqlspec/adapters/psycopg/config/_async.py +8 -14
- sqlspec/adapters/psycopg/config/_common.py +6 -5
- sqlspec/adapters/psycopg/config/_sync.py +8 -14
- sqlspec/adapters/sqlite/config.py +6 -23
- sqlspec/base.py +87 -0
- sqlspec/filters.py +8 -5
- sqlspec/typing.py +248 -32
- sqlspec/utils/deprecation.py +111 -0
- sqlspec/utils/fixtures.py +66 -0
- sqlspec/utils/module_loader.py +94 -0
- sqlspec/utils/text.py +46 -0
- sqlspec-0.5.0.dist-info/METADATA +126 -0
- sqlspec-0.5.0.dist-info/RECORD +44 -0
- sqlspec/config.py +0 -16
- sqlspec/utils/dataclass.py +0 -138
- sqlspec/utils/empty.py +0 -18
- sqlspec-0.3.0.dist-info/METADATA +0 -84
- sqlspec-0.3.0.dist-info/RECORD +0 -42
- {sqlspec-0.3.0.dist-info → sqlspec-0.5.0.dist-info}/WHEEL +0 -0
- {sqlspec-0.3.0.dist-info → sqlspec-0.5.0.dist-info}/licenses/NOTICE +0 -0
|
@@ -5,8 +5,8 @@ from typing import TYPE_CHECKING, Generic, TypeVar
|
|
|
5
5
|
|
|
6
6
|
from oracledb import ConnectionPool
|
|
7
7
|
|
|
8
|
-
from sqlspec.
|
|
9
|
-
from sqlspec.
|
|
8
|
+
from sqlspec.base import DatabaseConfigProtocol, GenericDatabaseConfig, GenericPoolConfig
|
|
9
|
+
from sqlspec.typing import Empty
|
|
10
10
|
|
|
11
11
|
if TYPE_CHECKING:
|
|
12
12
|
import ssl
|
|
@@ -17,7 +17,7 @@ if TYPE_CHECKING:
|
|
|
17
17
|
from oracledb.connection import AsyncConnection, Connection
|
|
18
18
|
from oracledb.pool import AsyncConnectionPool, ConnectionPool
|
|
19
19
|
|
|
20
|
-
from sqlspec.
|
|
20
|
+
from sqlspec.typing import EmptyType
|
|
21
21
|
|
|
22
22
|
__all__ = (
|
|
23
23
|
"OracleGenericDatabaseConfig",
|
|
@@ -32,7 +32,7 @@ PoolT = TypeVar("PoolT", bound="ConnectionPool | AsyncConnectionPool")
|
|
|
32
32
|
|
|
33
33
|
|
|
34
34
|
@dataclass
|
|
35
|
-
class OracleGenericPoolConfig(Generic[
|
|
35
|
+
class OracleGenericPoolConfig(Generic[ConnectionT, PoolT], GenericPoolConfig):
|
|
36
36
|
"""Configuration for Oracle database connection pools.
|
|
37
37
|
|
|
38
38
|
This class provides configuration options for both synchronous and asynchronous Oracle
|
|
@@ -58,7 +58,7 @@ class OracleGenericPoolConfig(Generic[PoolT, ConnectionT], GenericPoolConfig):
|
|
|
58
58
|
"""New password for password change operations"""
|
|
59
59
|
wallet_password: str | EmptyType = Empty
|
|
60
60
|
"""Password for accessing Oracle Wallet"""
|
|
61
|
-
access_token: str | tuple | Callable | EmptyType = Empty
|
|
61
|
+
access_token: str | tuple[str, ...] | Callable[[], str] | EmptyType = Empty
|
|
62
62
|
"""Token for token-based authentication"""
|
|
63
63
|
host: str | EmptyType = Empty
|
|
64
64
|
"""Database server hostname"""
|
|
@@ -112,11 +112,11 @@ class OracleGenericPoolConfig(Generic[PoolT, ConnectionT], GenericPoolConfig):
|
|
|
112
112
|
"""If True, allows connections with different tags"""
|
|
113
113
|
config_dir: str | EmptyType = Empty
|
|
114
114
|
"""Directory containing Oracle configuration files"""
|
|
115
|
-
appcontext: list | EmptyType = Empty
|
|
115
|
+
appcontext: list[str] | EmptyType = Empty
|
|
116
116
|
"""Application context list"""
|
|
117
|
-
shardingkey: list | EmptyType = Empty
|
|
117
|
+
shardingkey: list[str] | EmptyType = Empty
|
|
118
118
|
"""Sharding key list"""
|
|
119
|
-
supershardingkey: list | EmptyType = Empty
|
|
119
|
+
supershardingkey: list[str] | EmptyType = Empty
|
|
120
120
|
"""Super sharding key list"""
|
|
121
121
|
debug_jdwp: str | EmptyType = Empty
|
|
122
122
|
"""JDWP debugging string"""
|
|
@@ -137,7 +137,7 @@ class OracleGenericPoolConfig(Generic[PoolT, ConnectionT], GenericPoolConfig):
|
|
|
137
137
|
|
|
138
138
|
|
|
139
139
|
@dataclass
|
|
140
|
-
class OracleGenericDatabaseConfig(
|
|
140
|
+
class OracleGenericDatabaseConfig(DatabaseConfigProtocol[ConnectionT, PoolT], GenericDatabaseConfig):
|
|
141
141
|
"""Oracle database Configuration.
|
|
142
142
|
|
|
143
143
|
This class provides the base configuration for Oracle database connections, extending
|
|
@@ -13,7 +13,7 @@ from sqlspec.adapters.oracledb.config._common import (
|
|
|
13
13
|
OracleGenericPoolConfig,
|
|
14
14
|
)
|
|
15
15
|
from sqlspec.exceptions import ImproperConfigurationError
|
|
16
|
-
from sqlspec.
|
|
16
|
+
from sqlspec.typing import dataclass_to_dict
|
|
17
17
|
|
|
18
18
|
if TYPE_CHECKING:
|
|
19
19
|
from collections.abc import Generator
|
|
@@ -26,14 +26,17 @@ __all__ = (
|
|
|
26
26
|
|
|
27
27
|
|
|
28
28
|
@dataclass
|
|
29
|
-
class OracleSyncPoolConfig(OracleGenericPoolConfig[
|
|
29
|
+
class OracleSyncPoolConfig(OracleGenericPoolConfig[Connection, ConnectionPool]):
|
|
30
30
|
"""Sync Oracle Pool Config"""
|
|
31
31
|
|
|
32
32
|
|
|
33
33
|
@dataclass
|
|
34
|
-
class OracleSyncDatabaseConfig(OracleGenericDatabaseConfig[
|
|
34
|
+
class OracleSyncDatabaseConfig(OracleGenericDatabaseConfig[Connection, ConnectionPool]):
|
|
35
35
|
"""Oracle database Configuration."""
|
|
36
36
|
|
|
37
|
+
__is_async__ = False
|
|
38
|
+
__supports_connection_pooling__ = True
|
|
39
|
+
|
|
37
40
|
pool_config: OracleSyncPoolConfig | None = None
|
|
38
41
|
"""Oracle Pool configuration"""
|
|
39
42
|
pool_instance: ConnectionPool | None = None
|
|
@@ -51,7 +54,7 @@ class OracleSyncDatabaseConfig(OracleGenericDatabaseConfig[ConnectionPool, Conne
|
|
|
51
54
|
function.
|
|
52
55
|
"""
|
|
53
56
|
if self.pool_config:
|
|
54
|
-
return
|
|
57
|
+
return dataclass_to_dict(self.pool_config, exclude_empty=True, convert_nested=False)
|
|
55
58
|
msg = "'pool_config' methods can not be used when a 'pool_instance' is provided."
|
|
56
59
|
raise ImproperConfigurationError(msg)
|
|
57
60
|
|
|
@@ -70,18 +73,11 @@ class OracleSyncDatabaseConfig(OracleGenericDatabaseConfig[ConnectionPool, Conne
|
|
|
70
73
|
|
|
71
74
|
pool_config = self.pool_config_dict
|
|
72
75
|
self.pool_instance = oracledb_create_pool(**pool_config)
|
|
73
|
-
if self.pool_instance is None:
|
|
76
|
+
if self.pool_instance is None: # pyright: ignore[reportUnnecessaryComparison]
|
|
74
77
|
msg = "Could not configure the 'pool_instance'. Please check your configuration."
|
|
75
78
|
raise ImproperConfigurationError(msg)
|
|
76
79
|
return self.pool_instance
|
|
77
80
|
|
|
78
|
-
def lifespan(self, *args: Any, **kwargs: Any) -> Generator[None, None, None]:
|
|
79
|
-
db_pool = self.create_pool()
|
|
80
|
-
try:
|
|
81
|
-
yield
|
|
82
|
-
finally:
|
|
83
|
-
db_pool.close()
|
|
84
|
-
|
|
85
81
|
def provide_pool(self, *args: Any, **kwargs: Any) -> ConnectionPool:
|
|
86
82
|
"""Create a pool instance.
|
|
87
83
|
|
|
@@ -98,5 +94,5 @@ class OracleSyncDatabaseConfig(OracleGenericDatabaseConfig[ConnectionPool, Conne
|
|
|
98
94
|
A connection instance.
|
|
99
95
|
"""
|
|
100
96
|
db_pool = self.provide_pool(*args, **kwargs)
|
|
101
|
-
with db_pool.acquire() as connection:
|
|
97
|
+
with db_pool.acquire() as connection: # pyright: ignore[reportUnknownMemberType]
|
|
102
98
|
yield connection
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
from ._async import PsycoPgAsyncDatabaseConfig, PsycoPgAsyncPoolConfig
|
|
2
|
-
from ._sync import PsycoPgSyncDatabaseConfig, PsycoPgSyncPoolConfig
|
|
1
|
+
from sqlspec.adapters.psycopg.config._async import PsycoPgAsyncDatabaseConfig, PsycoPgAsyncPoolConfig
|
|
2
|
+
from sqlspec.adapters.psycopg.config._sync import PsycoPgSyncDatabaseConfig, PsycoPgSyncPoolConfig
|
|
3
3
|
|
|
4
4
|
__all__ = (
|
|
5
5
|
"PsycoPgAsyncDatabaseConfig",
|
|
@@ -12,7 +12,7 @@ from sqlspec.adapters.psycopg.config._common import (
|
|
|
12
12
|
PsycoPgGenericPoolConfig,
|
|
13
13
|
)
|
|
14
14
|
from sqlspec.exceptions import ImproperConfigurationError
|
|
15
|
-
from sqlspec.
|
|
15
|
+
from sqlspec.typing import dataclass_to_dict
|
|
16
16
|
|
|
17
17
|
if TYPE_CHECKING:
|
|
18
18
|
from collections.abc import AsyncGenerator, Awaitable
|
|
@@ -26,14 +26,17 @@ __all__ = (
|
|
|
26
26
|
|
|
27
27
|
|
|
28
28
|
@dataclass
|
|
29
|
-
class PsycoPgAsyncPoolConfig(PsycoPgGenericPoolConfig[
|
|
29
|
+
class PsycoPgAsyncPoolConfig(PsycoPgGenericPoolConfig[AsyncConnection, AsyncConnectionPool]):
|
|
30
30
|
"""Async Psycopg Pool Config"""
|
|
31
31
|
|
|
32
32
|
|
|
33
33
|
@dataclass
|
|
34
|
-
class PsycoPgAsyncDatabaseConfig(PsycoPgGenericDatabaseConfig[
|
|
34
|
+
class PsycoPgAsyncDatabaseConfig(PsycoPgGenericDatabaseConfig[AsyncConnection, AsyncConnectionPool]):
|
|
35
35
|
"""Async Psycopg database Configuration."""
|
|
36
36
|
|
|
37
|
+
__is_async__ = True
|
|
38
|
+
__supports_connection_pooling__ = True
|
|
39
|
+
|
|
37
40
|
pool_config: PsycoPgAsyncPoolConfig | None = None
|
|
38
41
|
"""Psycopg Pool configuration"""
|
|
39
42
|
pool_instance: AsyncConnectionPool | None = None
|
|
@@ -43,7 +46,7 @@ class PsycoPgAsyncDatabaseConfig(PsycoPgGenericDatabaseConfig[AsyncConnectionPoo
|
|
|
43
46
|
def pool_config_dict(self) -> dict[str, Any]:
|
|
44
47
|
"""Return the pool configuration as a dict."""
|
|
45
48
|
if self.pool_config:
|
|
46
|
-
return
|
|
49
|
+
return dataclass_to_dict(self.pool_config, exclude_empty=True, convert_nested=False)
|
|
47
50
|
msg = "'pool_config' methods can not be used when a 'pool_instance' is provided."
|
|
48
51
|
raise ImproperConfigurationError(msg)
|
|
49
52
|
|
|
@@ -58,20 +61,11 @@ class PsycoPgAsyncDatabaseConfig(PsycoPgGenericDatabaseConfig[AsyncConnectionPoo
|
|
|
58
61
|
|
|
59
62
|
pool_config = self.pool_config_dict
|
|
60
63
|
self.pool_instance = AsyncConnectionPool(**pool_config)
|
|
61
|
-
if self.pool_instance is None:
|
|
64
|
+
if self.pool_instance is None: # pyright: ignore[reportUnnecessaryComparison]
|
|
62
65
|
msg = "Could not configure the 'pool_instance'. Please check your configuration." # type: ignore[unreachable]
|
|
63
66
|
raise ImproperConfigurationError(msg)
|
|
64
67
|
return self.pool_instance
|
|
65
68
|
|
|
66
|
-
@asynccontextmanager
|
|
67
|
-
async def lifespan(self, *args: Any, **kwargs: Any) -> AsyncGenerator[None, None]:
|
|
68
|
-
"""Manage the lifecycle of the connection pool."""
|
|
69
|
-
pool = await self.create_pool()
|
|
70
|
-
try:
|
|
71
|
-
yield
|
|
72
|
-
finally:
|
|
73
|
-
await pool.close()
|
|
74
|
-
|
|
75
69
|
def provide_pool(self, *args: Any, **kwargs: Any) -> Awaitable[AsyncConnectionPool]:
|
|
76
70
|
"""Create and return a connection pool."""
|
|
77
71
|
return self.create_pool()
|
|
@@ -3,8 +3,8 @@ from __future__ import annotations
|
|
|
3
3
|
from dataclasses import dataclass
|
|
4
4
|
from typing import TYPE_CHECKING, Generic, TypeVar
|
|
5
5
|
|
|
6
|
-
from sqlspec.
|
|
7
|
-
from sqlspec.
|
|
6
|
+
from sqlspec.base import DatabaseConfigProtocol, GenericDatabaseConfig, GenericPoolConfig
|
|
7
|
+
from sqlspec.typing import Empty
|
|
8
8
|
|
|
9
9
|
if TYPE_CHECKING:
|
|
10
10
|
from collections.abc import Callable
|
|
@@ -13,7 +13,8 @@ if TYPE_CHECKING:
|
|
|
13
13
|
from psycopg import AsyncConnection, Connection
|
|
14
14
|
from psycopg_pool import AsyncConnectionPool, ConnectionPool
|
|
15
15
|
|
|
16
|
-
from sqlspec.
|
|
16
|
+
from sqlspec.typing import EmptyType
|
|
17
|
+
|
|
17
18
|
|
|
18
19
|
__all__ = (
|
|
19
20
|
"PsycoPgGenericDatabaseConfig",
|
|
@@ -26,7 +27,7 @@ PoolT = TypeVar("PoolT", bound="ConnectionPool | AsyncConnectionPool")
|
|
|
26
27
|
|
|
27
28
|
|
|
28
29
|
@dataclass
|
|
29
|
-
class PsycoPgGenericPoolConfig(Generic[
|
|
30
|
+
class PsycoPgGenericPoolConfig(Generic[ConnectionT, PoolT], GenericPoolConfig):
|
|
30
31
|
"""Configuration for Psycopg connection pools.
|
|
31
32
|
|
|
32
33
|
This class provides configuration options for both synchronous and asynchronous Psycopg
|
|
@@ -61,7 +62,7 @@ class PsycoPgGenericPoolConfig(Generic[PoolT, ConnectionT], GenericPoolConfig):
|
|
|
61
62
|
|
|
62
63
|
|
|
63
64
|
@dataclass
|
|
64
|
-
class PsycoPgGenericDatabaseConfig(
|
|
65
|
+
class PsycoPgGenericDatabaseConfig(DatabaseConfigProtocol[ConnectionT, PoolT], GenericDatabaseConfig):
|
|
65
66
|
"""Psycopg database Configuration.
|
|
66
67
|
|
|
67
68
|
This class provides the base configuration for Psycopg database connections, extending
|
|
@@ -12,7 +12,7 @@ from sqlspec.adapters.psycopg.config._common import (
|
|
|
12
12
|
PsycoPgGenericPoolConfig,
|
|
13
13
|
)
|
|
14
14
|
from sqlspec.exceptions import ImproperConfigurationError
|
|
15
|
-
from sqlspec.
|
|
15
|
+
from sqlspec.typing import dataclass_to_dict
|
|
16
16
|
|
|
17
17
|
if TYPE_CHECKING:
|
|
18
18
|
from collections.abc import Generator
|
|
@@ -26,14 +26,17 @@ __all__ = (
|
|
|
26
26
|
|
|
27
27
|
|
|
28
28
|
@dataclass
|
|
29
|
-
class PsycoPgSyncPoolConfig(PsycoPgGenericPoolConfig[
|
|
29
|
+
class PsycoPgSyncPoolConfig(PsycoPgGenericPoolConfig[Connection, ConnectionPool]):
|
|
30
30
|
"""Sync Psycopg Pool Config"""
|
|
31
31
|
|
|
32
32
|
|
|
33
33
|
@dataclass
|
|
34
|
-
class PsycoPgSyncDatabaseConfig(PsycoPgGenericDatabaseConfig[
|
|
34
|
+
class PsycoPgSyncDatabaseConfig(PsycoPgGenericDatabaseConfig[Connection, ConnectionPool]):
|
|
35
35
|
"""Sync Psycopg database Configuration."""
|
|
36
36
|
|
|
37
|
+
__is_async__ = False
|
|
38
|
+
__supports_connection_pooling__ = True
|
|
39
|
+
|
|
37
40
|
pool_config: PsycoPgSyncPoolConfig | None = None
|
|
38
41
|
"""Psycopg Pool configuration"""
|
|
39
42
|
pool_instance: ConnectionPool | None = None
|
|
@@ -43,7 +46,7 @@ class PsycoPgSyncDatabaseConfig(PsycoPgGenericDatabaseConfig[ConnectionPool, Con
|
|
|
43
46
|
def pool_config_dict(self) -> dict[str, Any]:
|
|
44
47
|
"""Return the pool configuration as a dict."""
|
|
45
48
|
if self.pool_config:
|
|
46
|
-
return
|
|
49
|
+
return dataclass_to_dict(self.pool_config, exclude_empty=True, convert_nested=False)
|
|
47
50
|
msg = "'pool_config' methods can not be used when a 'pool_instance' is provided."
|
|
48
51
|
raise ImproperConfigurationError(msg)
|
|
49
52
|
|
|
@@ -58,20 +61,11 @@ class PsycoPgSyncDatabaseConfig(PsycoPgGenericDatabaseConfig[ConnectionPool, Con
|
|
|
58
61
|
|
|
59
62
|
pool_config = self.pool_config_dict
|
|
60
63
|
self.pool_instance = ConnectionPool(**pool_config)
|
|
61
|
-
if self.pool_instance is None:
|
|
64
|
+
if self.pool_instance is None: # pyright: ignore[reportUnnecessaryComparison]
|
|
62
65
|
msg = "Could not configure the 'pool_instance'. Please check your configuration." # type: ignore[unreachable]
|
|
63
66
|
raise ImproperConfigurationError(msg)
|
|
64
67
|
return self.pool_instance
|
|
65
68
|
|
|
66
|
-
@contextmanager
|
|
67
|
-
def lifespan(self, *args: Any, **kwargs: Any) -> Generator[None, None, None]:
|
|
68
|
-
"""Manage the lifecycle of the connection pool."""
|
|
69
|
-
pool = self.create_pool()
|
|
70
|
-
try:
|
|
71
|
-
yield
|
|
72
|
-
finally:
|
|
73
|
-
pool.close()
|
|
74
|
-
|
|
75
69
|
def provide_pool(self, *args: Any, **kwargs: Any) -> ConnectionPool:
|
|
76
70
|
"""Create and return a connection pool."""
|
|
77
71
|
return self.create_pool()
|
|
@@ -4,10 +4,9 @@ from contextlib import contextmanager
|
|
|
4
4
|
from dataclasses import dataclass
|
|
5
5
|
from typing import TYPE_CHECKING, Any, Literal
|
|
6
6
|
|
|
7
|
-
from sqlspec.
|
|
7
|
+
from sqlspec.base import GenericDatabaseConfig, NoPoolConfig
|
|
8
8
|
from sqlspec.exceptions import ImproperConfigurationError
|
|
9
|
-
from sqlspec.
|
|
10
|
-
from sqlspec.utils.empty import Empty, EmptyType
|
|
9
|
+
from sqlspec.typing import Empty, EmptyType, dataclass_to_dict
|
|
11
10
|
|
|
12
11
|
if TYPE_CHECKING:
|
|
13
12
|
from collections.abc import Generator
|
|
@@ -17,7 +16,7 @@ __all__ = ("SqliteConfig",)
|
|
|
17
16
|
|
|
18
17
|
|
|
19
18
|
@dataclass
|
|
20
|
-
class SqliteConfig(GenericDatabaseConfig):
|
|
19
|
+
class SqliteConfig(NoPoolConfig["Connection"], GenericDatabaseConfig):
|
|
21
20
|
"""Configuration for SQLite database connections.
|
|
22
21
|
|
|
23
22
|
This class provides configuration options for SQLite database connections, wrapping all parameters
|
|
@@ -26,7 +25,7 @@ class SqliteConfig(GenericDatabaseConfig):
|
|
|
26
25
|
For details see: https://docs.python.org/3/library/sqlite3.html#sqlite3.connect
|
|
27
26
|
"""
|
|
28
27
|
|
|
29
|
-
database: str
|
|
28
|
+
database: str = ":memory:"
|
|
30
29
|
"""The path to the database file to be opened. Pass ":memory:" to open a connection to a database that resides in RAM instead of on disk."""
|
|
31
30
|
|
|
32
31
|
timeout: float | EmptyType = Empty
|
|
@@ -57,7 +56,7 @@ class SqliteConfig(GenericDatabaseConfig):
|
|
|
57
56
|
Returns:
|
|
58
57
|
A string keyed dict of config kwargs for the sqlite3.connect() function.
|
|
59
58
|
"""
|
|
60
|
-
return
|
|
59
|
+
return dataclass_to_dict(self, exclude_empty=True, convert_nested=False)
|
|
61
60
|
|
|
62
61
|
def create_connection(self) -> Connection:
|
|
63
62
|
"""Create and return a new database connection.
|
|
@@ -71,27 +70,11 @@ class SqliteConfig(GenericDatabaseConfig):
|
|
|
71
70
|
import sqlite3
|
|
72
71
|
|
|
73
72
|
try:
|
|
74
|
-
return sqlite3.connect(**self.connection_config_dict)
|
|
73
|
+
return sqlite3.connect(**self.connection_config_dict) # type: ignore[no-any-return,unused-ignore]
|
|
75
74
|
except Exception as e:
|
|
76
75
|
msg = f"Could not configure the SQLite connection. Error: {e!s}"
|
|
77
76
|
raise ImproperConfigurationError(msg) from e
|
|
78
77
|
|
|
79
|
-
@contextmanager
|
|
80
|
-
def lifespan(self, *args: Any, **kwargs: Any) -> Generator[None, None, None]:
|
|
81
|
-
"""Manage the lifecycle of a database connection.
|
|
82
|
-
|
|
83
|
-
Yields:
|
|
84
|
-
None
|
|
85
|
-
|
|
86
|
-
Raises:
|
|
87
|
-
ImproperConfigurationError: If the connection could not be established.
|
|
88
|
-
"""
|
|
89
|
-
connection = self.create_connection()
|
|
90
|
-
try:
|
|
91
|
-
yield
|
|
92
|
-
finally:
|
|
93
|
-
connection.close()
|
|
94
|
-
|
|
95
78
|
@contextmanager
|
|
96
79
|
def provide_connection(self, *args: Any, **kwargs: Any) -> Generator[Connection, None, None]:
|
|
97
80
|
"""Create and provide a database connection.
|
sqlspec/base.py
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
from abc import ABC, abstractmethod
|
|
2
|
+
from collections.abc import AsyncGenerator, Awaitable, Generator
|
|
3
|
+
from contextlib import AbstractAsyncContextManager, AbstractContextManager
|
|
4
|
+
from dataclasses import dataclass
|
|
5
|
+
from typing import Any, ClassVar, Generic, TypeVar, Union
|
|
6
|
+
|
|
7
|
+
__all__ = (
|
|
8
|
+
"DatabaseConfigProtocol",
|
|
9
|
+
"GenericPoolConfig",
|
|
10
|
+
"NoPoolConfig",
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
ConnectionT = TypeVar("ConnectionT")
|
|
14
|
+
PoolT = TypeVar("PoolT")
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@dataclass
|
|
18
|
+
class DatabaseConfigProtocol(Generic[ConnectionT, PoolT], ABC):
|
|
19
|
+
"""Protocol defining the interface for database configurations."""
|
|
20
|
+
|
|
21
|
+
__is_async__: ClassVar[bool] = False
|
|
22
|
+
__supports_connection_pooling__: ClassVar[bool] = False
|
|
23
|
+
|
|
24
|
+
@abstractmethod
|
|
25
|
+
def create_connection(self) -> Union[ConnectionT, Awaitable[ConnectionT]]:
|
|
26
|
+
"""Create and return a new database connection."""
|
|
27
|
+
raise NotImplementedError
|
|
28
|
+
|
|
29
|
+
@abstractmethod
|
|
30
|
+
def provide_connection(
|
|
31
|
+
self, *args: Any, **kwargs: Any
|
|
32
|
+
) -> Union[
|
|
33
|
+
Generator[ConnectionT, None, None],
|
|
34
|
+
AsyncGenerator[ConnectionT, None],
|
|
35
|
+
AbstractContextManager[ConnectionT],
|
|
36
|
+
AbstractAsyncContextManager[ConnectionT],
|
|
37
|
+
]:
|
|
38
|
+
"""Provide a database connection context manager."""
|
|
39
|
+
raise NotImplementedError
|
|
40
|
+
|
|
41
|
+
@property
|
|
42
|
+
@abstractmethod
|
|
43
|
+
def connection_config_dict(self) -> dict[str, Any]:
|
|
44
|
+
"""Return the connection configuration as a dict."""
|
|
45
|
+
raise NotImplementedError
|
|
46
|
+
|
|
47
|
+
@abstractmethod
|
|
48
|
+
def create_pool(self) -> Union[PoolT, Awaitable[PoolT]]:
|
|
49
|
+
"""Create and return connection pool."""
|
|
50
|
+
raise NotImplementedError
|
|
51
|
+
|
|
52
|
+
@abstractmethod
|
|
53
|
+
def provide_pool(
|
|
54
|
+
self, *args: Any, **kwargs: Any
|
|
55
|
+
) -> Union[PoolT, Awaitable[PoolT], AbstractContextManager[PoolT], AbstractAsyncContextManager[PoolT]]:
|
|
56
|
+
"""Provide pool instance."""
|
|
57
|
+
raise NotImplementedError
|
|
58
|
+
|
|
59
|
+
@property
|
|
60
|
+
def is_async(self) -> bool:
|
|
61
|
+
"""Return whether the configuration is for an async database."""
|
|
62
|
+
return self.__is_async__
|
|
63
|
+
|
|
64
|
+
@property
|
|
65
|
+
def support_connection_pooling(self) -> bool:
|
|
66
|
+
"""Return whether the configuration supports connection pooling."""
|
|
67
|
+
return self.__supports_connection_pooling__
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
class NoPoolConfig(DatabaseConfigProtocol[ConnectionT, None]):
|
|
71
|
+
"""Base class for database configurations that do not implement a pool."""
|
|
72
|
+
|
|
73
|
+
def create_pool(self) -> None:
|
|
74
|
+
"""This database backend has not implemented the pooling configurations."""
|
|
75
|
+
|
|
76
|
+
def provide_pool(self, *args: Any, **kwargs: Any) -> None:
|
|
77
|
+
"""This database backend has not implemented the pooling configurations."""
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
@dataclass
|
|
81
|
+
class GenericPoolConfig:
|
|
82
|
+
"""Generic Database Pool Configuration."""
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
@dataclass
|
|
86
|
+
class GenericDatabaseConfig:
|
|
87
|
+
"""Generic Database Configuration."""
|
sqlspec/filters.py
CHANGED
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
-
from abc import ABC
|
|
5
|
+
from abc import ABC
|
|
6
6
|
from collections import abc # noqa: TC003
|
|
7
7
|
from dataclasses import dataclass
|
|
8
8
|
from datetime import datetime # noqa: TC003
|
|
9
|
-
from typing import Generic, Literal
|
|
9
|
+
from typing import Generic, Literal, Protocol
|
|
10
10
|
|
|
11
11
|
from typing_extensions import TypeVar
|
|
12
12
|
|
|
@@ -25,11 +25,14 @@ __all__ = (
|
|
|
25
25
|
)
|
|
26
26
|
|
|
27
27
|
T = TypeVar("T")
|
|
28
|
+
StatementT = TypeVar("StatementT", bound="str")
|
|
28
29
|
|
|
29
30
|
|
|
30
|
-
class StatementFilter(
|
|
31
|
-
|
|
32
|
-
|
|
31
|
+
class StatementFilter(Protocol):
|
|
32
|
+
"""Protocol for filters that can be appended to a statement."""
|
|
33
|
+
|
|
34
|
+
def append_to_statement(self, statement: StatementT) -> StatementT:
|
|
35
|
+
"""Append the filter to the statement."""
|
|
33
36
|
return statement
|
|
34
37
|
|
|
35
38
|
|