sqlspec 0.11.0__py3-none-any.whl → 0.12.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 +16 -3
- sqlspec/_serialization.py +3 -10
- sqlspec/_sql.py +1147 -0
- sqlspec/_typing.py +343 -41
- sqlspec/adapters/adbc/__init__.py +2 -6
- sqlspec/adapters/adbc/config.py +474 -149
- sqlspec/adapters/adbc/driver.py +330 -644
- sqlspec/adapters/aiosqlite/__init__.py +2 -6
- sqlspec/adapters/aiosqlite/config.py +143 -57
- sqlspec/adapters/aiosqlite/driver.py +269 -462
- sqlspec/adapters/asyncmy/__init__.py +3 -8
- sqlspec/adapters/asyncmy/config.py +247 -202
- sqlspec/adapters/asyncmy/driver.py +217 -451
- sqlspec/adapters/asyncpg/__init__.py +4 -7
- sqlspec/adapters/asyncpg/config.py +329 -176
- sqlspec/adapters/asyncpg/driver.py +418 -498
- sqlspec/adapters/bigquery/__init__.py +2 -2
- sqlspec/adapters/bigquery/config.py +407 -0
- sqlspec/adapters/bigquery/driver.py +592 -634
- sqlspec/adapters/duckdb/__init__.py +4 -1
- sqlspec/adapters/duckdb/config.py +432 -321
- sqlspec/adapters/duckdb/driver.py +393 -436
- sqlspec/adapters/oracledb/__init__.py +3 -8
- sqlspec/adapters/oracledb/config.py +625 -0
- sqlspec/adapters/oracledb/driver.py +549 -942
- sqlspec/adapters/psqlpy/__init__.py +4 -7
- sqlspec/adapters/psqlpy/config.py +372 -203
- sqlspec/adapters/psqlpy/driver.py +197 -550
- sqlspec/adapters/psycopg/__init__.py +3 -8
- sqlspec/adapters/psycopg/config.py +741 -0
- sqlspec/adapters/psycopg/driver.py +732 -733
- sqlspec/adapters/sqlite/__init__.py +2 -6
- sqlspec/adapters/sqlite/config.py +146 -81
- sqlspec/adapters/sqlite/driver.py +243 -426
- sqlspec/base.py +220 -825
- sqlspec/config.py +354 -0
- sqlspec/driver/__init__.py +22 -0
- sqlspec/driver/_async.py +252 -0
- sqlspec/driver/_common.py +338 -0
- sqlspec/driver/_sync.py +261 -0
- sqlspec/driver/mixins/__init__.py +17 -0
- sqlspec/driver/mixins/_pipeline.py +523 -0
- sqlspec/driver/mixins/_result_utils.py +122 -0
- sqlspec/driver/mixins/_sql_translator.py +35 -0
- sqlspec/driver/mixins/_storage.py +993 -0
- sqlspec/driver/mixins/_type_coercion.py +131 -0
- sqlspec/exceptions.py +299 -7
- sqlspec/extensions/aiosql/__init__.py +10 -0
- sqlspec/extensions/aiosql/adapter.py +474 -0
- sqlspec/extensions/litestar/__init__.py +1 -6
- sqlspec/extensions/litestar/_utils.py +1 -5
- sqlspec/extensions/litestar/config.py +5 -6
- sqlspec/extensions/litestar/handlers.py +13 -12
- sqlspec/extensions/litestar/plugin.py +22 -24
- sqlspec/extensions/litestar/providers.py +37 -55
- sqlspec/loader.py +528 -0
- sqlspec/service/__init__.py +3 -0
- sqlspec/service/base.py +24 -0
- sqlspec/service/pagination.py +26 -0
- sqlspec/statement/__init__.py +21 -0
- sqlspec/statement/builder/__init__.py +54 -0
- sqlspec/statement/builder/_ddl_utils.py +119 -0
- sqlspec/statement/builder/_parsing_utils.py +135 -0
- sqlspec/statement/builder/base.py +328 -0
- sqlspec/statement/builder/ddl.py +1379 -0
- sqlspec/statement/builder/delete.py +80 -0
- sqlspec/statement/builder/insert.py +274 -0
- sqlspec/statement/builder/merge.py +95 -0
- sqlspec/statement/builder/mixins/__init__.py +65 -0
- sqlspec/statement/builder/mixins/_aggregate_functions.py +151 -0
- sqlspec/statement/builder/mixins/_case_builder.py +91 -0
- sqlspec/statement/builder/mixins/_common_table_expr.py +91 -0
- sqlspec/statement/builder/mixins/_delete_from.py +34 -0
- sqlspec/statement/builder/mixins/_from.py +61 -0
- sqlspec/statement/builder/mixins/_group_by.py +119 -0
- sqlspec/statement/builder/mixins/_having.py +35 -0
- sqlspec/statement/builder/mixins/_insert_from_select.py +48 -0
- sqlspec/statement/builder/mixins/_insert_into.py +36 -0
- sqlspec/statement/builder/mixins/_insert_values.py +69 -0
- sqlspec/statement/builder/mixins/_join.py +110 -0
- sqlspec/statement/builder/mixins/_limit_offset.py +53 -0
- sqlspec/statement/builder/mixins/_merge_clauses.py +405 -0
- sqlspec/statement/builder/mixins/_order_by.py +46 -0
- sqlspec/statement/builder/mixins/_pivot.py +82 -0
- sqlspec/statement/builder/mixins/_returning.py +37 -0
- sqlspec/statement/builder/mixins/_select_columns.py +60 -0
- sqlspec/statement/builder/mixins/_set_ops.py +122 -0
- sqlspec/statement/builder/mixins/_unpivot.py +80 -0
- sqlspec/statement/builder/mixins/_update_from.py +54 -0
- sqlspec/statement/builder/mixins/_update_set.py +91 -0
- sqlspec/statement/builder/mixins/_update_table.py +29 -0
- sqlspec/statement/builder/mixins/_where.py +374 -0
- sqlspec/statement/builder/mixins/_window_functions.py +86 -0
- sqlspec/statement/builder/protocols.py +20 -0
- sqlspec/statement/builder/select.py +206 -0
- sqlspec/statement/builder/update.py +178 -0
- sqlspec/statement/filters.py +571 -0
- sqlspec/statement/parameters.py +736 -0
- sqlspec/statement/pipelines/__init__.py +67 -0
- sqlspec/statement/pipelines/analyzers/__init__.py +9 -0
- sqlspec/statement/pipelines/analyzers/_analyzer.py +649 -0
- sqlspec/statement/pipelines/base.py +315 -0
- sqlspec/statement/pipelines/context.py +119 -0
- sqlspec/statement/pipelines/result_types.py +41 -0
- sqlspec/statement/pipelines/transformers/__init__.py +8 -0
- sqlspec/statement/pipelines/transformers/_expression_simplifier.py +256 -0
- sqlspec/statement/pipelines/transformers/_literal_parameterizer.py +623 -0
- sqlspec/statement/pipelines/transformers/_remove_comments.py +66 -0
- sqlspec/statement/pipelines/transformers/_remove_hints.py +81 -0
- sqlspec/statement/pipelines/validators/__init__.py +23 -0
- sqlspec/statement/pipelines/validators/_dml_safety.py +275 -0
- sqlspec/statement/pipelines/validators/_parameter_style.py +297 -0
- sqlspec/statement/pipelines/validators/_performance.py +703 -0
- sqlspec/statement/pipelines/validators/_security.py +990 -0
- sqlspec/statement/pipelines/validators/base.py +67 -0
- sqlspec/statement/result.py +527 -0
- sqlspec/statement/splitter.py +701 -0
- sqlspec/statement/sql.py +1198 -0
- sqlspec/storage/__init__.py +15 -0
- sqlspec/storage/backends/__init__.py +0 -0
- sqlspec/storage/backends/base.py +166 -0
- sqlspec/storage/backends/fsspec.py +315 -0
- sqlspec/storage/backends/obstore.py +464 -0
- sqlspec/storage/protocol.py +170 -0
- sqlspec/storage/registry.py +315 -0
- sqlspec/typing.py +157 -36
- sqlspec/utils/correlation.py +155 -0
- sqlspec/utils/deprecation.py +3 -6
- sqlspec/utils/fixtures.py +6 -11
- sqlspec/utils/logging.py +135 -0
- sqlspec/utils/module_loader.py +45 -43
- sqlspec/utils/serializers.py +4 -0
- sqlspec/utils/singleton.py +6 -8
- sqlspec/utils/sync_tools.py +15 -27
- sqlspec/utils/text.py +58 -26
- {sqlspec-0.11.0.dist-info → sqlspec-0.12.0.dist-info}/METADATA +100 -26
- sqlspec-0.12.0.dist-info/RECORD +145 -0
- sqlspec/adapters/bigquery/config/__init__.py +0 -3
- sqlspec/adapters/bigquery/config/_common.py +0 -40
- sqlspec/adapters/bigquery/config/_sync.py +0 -87
- sqlspec/adapters/oracledb/config/__init__.py +0 -9
- sqlspec/adapters/oracledb/config/_asyncio.py +0 -186
- sqlspec/adapters/oracledb/config/_common.py +0 -131
- sqlspec/adapters/oracledb/config/_sync.py +0 -186
- sqlspec/adapters/psycopg/config/__init__.py +0 -19
- sqlspec/adapters/psycopg/config/_async.py +0 -169
- sqlspec/adapters/psycopg/config/_common.py +0 -56
- sqlspec/adapters/psycopg/config/_sync.py +0 -168
- sqlspec/filters.py +0 -330
- sqlspec/mixins.py +0 -306
- sqlspec/statement.py +0 -378
- sqlspec-0.11.0.dist-info/RECORD +0 -69
- {sqlspec-0.11.0.dist-info → sqlspec-0.12.0.dist-info}/WHEEL +0 -0
- {sqlspec-0.11.0.dist-info → sqlspec-0.12.0.dist-info}/licenses/LICENSE +0 -0
- {sqlspec-0.11.0.dist-info → sqlspec-0.12.0.dist-info}/licenses/NOTICE +0 -0
|
@@ -1,169 +0,0 @@
|
|
|
1
|
-
from contextlib import asynccontextmanager
|
|
2
|
-
from dataclasses import dataclass, field
|
|
3
|
-
from typing import TYPE_CHECKING, Any, Optional
|
|
4
|
-
|
|
5
|
-
from psycopg_pool import AsyncConnectionPool
|
|
6
|
-
|
|
7
|
-
from sqlspec.adapters.psycopg.config._common import PsycopgGenericPoolConfig
|
|
8
|
-
from sqlspec.adapters.psycopg.driver import PsycopgAsyncConnection, PsycopgAsyncDriver
|
|
9
|
-
from sqlspec.base import AsyncDatabaseConfig
|
|
10
|
-
from sqlspec.exceptions import ImproperConfigurationError
|
|
11
|
-
from sqlspec.typing import dataclass_to_dict
|
|
12
|
-
|
|
13
|
-
if TYPE_CHECKING:
|
|
14
|
-
from collections.abc import AsyncGenerator, Awaitable
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
__all__ = (
|
|
18
|
-
"PsycopgAsyncConfig",
|
|
19
|
-
"PsycopgAsyncPoolConfig",
|
|
20
|
-
)
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
@dataclass
|
|
24
|
-
class PsycopgAsyncPoolConfig(PsycopgGenericPoolConfig[PsycopgAsyncConnection, AsyncConnectionPool]):
|
|
25
|
-
"""Async Psycopg Pool Config"""
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
@dataclass
|
|
29
|
-
class PsycopgAsyncConfig(AsyncDatabaseConfig[PsycopgAsyncConnection, AsyncConnectionPool, PsycopgAsyncDriver]):
|
|
30
|
-
"""Async Psycopg database Configuration.
|
|
31
|
-
|
|
32
|
-
This class provides the base configuration for Psycopg database connections, extending
|
|
33
|
-
the generic database configuration with Psycopg-specific settings.([1](https://www.psycopg.org/psycopg3/docs/api/connections.html))
|
|
34
|
-
|
|
35
|
-
The configuration supports all standard Psycopg connection parameters and can be used
|
|
36
|
-
with both synchronous and asynchronous connections.([2](https://www.psycopg.org/psycopg3/docs/api/connections.html))
|
|
37
|
-
"""
|
|
38
|
-
|
|
39
|
-
pool_config: "Optional[PsycopgAsyncPoolConfig]" = None
|
|
40
|
-
"""Psycopg Pool configuration"""
|
|
41
|
-
pool_instance: "Optional[AsyncConnectionPool]" = None
|
|
42
|
-
"""Optional pool to use"""
|
|
43
|
-
connection_type: "type[PsycopgAsyncConnection]" = field(init=False, default_factory=lambda: PsycopgAsyncConnection) # type: ignore[assignment]
|
|
44
|
-
"""Type of the connection object"""
|
|
45
|
-
driver_type: "type[PsycopgAsyncDriver]" = field(init=False, default_factory=lambda: PsycopgAsyncDriver) # type: ignore[type-abstract,unused-ignore]
|
|
46
|
-
"""Type of the driver object"""
|
|
47
|
-
|
|
48
|
-
@property
|
|
49
|
-
def connection_config_dict(self) -> "dict[str, Any]":
|
|
50
|
-
"""Return the connection configuration as a dict.
|
|
51
|
-
|
|
52
|
-
Returns:
|
|
53
|
-
A string keyed dict of config kwargs for the psycopg.connect function.
|
|
54
|
-
|
|
55
|
-
Raises:
|
|
56
|
-
ImproperConfigurationError: If the connection configuration is not provided.
|
|
57
|
-
"""
|
|
58
|
-
if self.pool_config:
|
|
59
|
-
# Filter out pool-specific parameters
|
|
60
|
-
pool_only_params = {
|
|
61
|
-
"min_size",
|
|
62
|
-
"max_size",
|
|
63
|
-
"name",
|
|
64
|
-
"timeout",
|
|
65
|
-
"reconnect_timeout",
|
|
66
|
-
"max_idle",
|
|
67
|
-
"max_lifetime",
|
|
68
|
-
}
|
|
69
|
-
return dataclass_to_dict(
|
|
70
|
-
self.pool_config,
|
|
71
|
-
exclude_empty=True,
|
|
72
|
-
convert_nested=False,
|
|
73
|
-
exclude=pool_only_params.union({"pool_instance", "connection_type", "driver_type", "open"}),
|
|
74
|
-
)
|
|
75
|
-
msg = "You must provide a 'pool_config' for this adapter."
|
|
76
|
-
raise ImproperConfigurationError(msg)
|
|
77
|
-
|
|
78
|
-
@property
|
|
79
|
-
def pool_config_dict(self) -> "dict[str, Any]":
|
|
80
|
-
"""Return the pool configuration as a dict.
|
|
81
|
-
|
|
82
|
-
Raises:
|
|
83
|
-
ImproperConfigurationError: If pool_config is not set but pool_instance is provided.
|
|
84
|
-
"""
|
|
85
|
-
if self.pool_config:
|
|
86
|
-
return dataclass_to_dict(
|
|
87
|
-
self.pool_config,
|
|
88
|
-
exclude_empty=True,
|
|
89
|
-
convert_nested=False,
|
|
90
|
-
exclude={"pool_instance", "connection_type", "driver_type"},
|
|
91
|
-
)
|
|
92
|
-
msg = "'pool_config' methods can not be used when a 'pool_instance' is provided."
|
|
93
|
-
raise ImproperConfigurationError(msg)
|
|
94
|
-
|
|
95
|
-
async def create_connection(self) -> "PsycopgAsyncConnection":
|
|
96
|
-
"""Create and return a new psycopg async connection from the pool.
|
|
97
|
-
|
|
98
|
-
Returns:
|
|
99
|
-
An AsyncConnection instance.
|
|
100
|
-
|
|
101
|
-
Raises:
|
|
102
|
-
ImproperConfigurationError: If the connection could not be created.
|
|
103
|
-
"""
|
|
104
|
-
try:
|
|
105
|
-
pool = await self.provide_pool()
|
|
106
|
-
return await pool.getconn()
|
|
107
|
-
except Exception as e:
|
|
108
|
-
msg = f"Could not configure the Psycopg connection. Error: {e!s}"
|
|
109
|
-
raise ImproperConfigurationError(msg) from e
|
|
110
|
-
|
|
111
|
-
async def create_pool(self) -> "AsyncConnectionPool":
|
|
112
|
-
"""Create and return a connection pool.
|
|
113
|
-
|
|
114
|
-
Returns:
|
|
115
|
-
AsyncConnectionPool: The configured connection pool.
|
|
116
|
-
|
|
117
|
-
Raises:
|
|
118
|
-
ImproperConfigurationError: If neither pool_config nor pool_instance are provided
|
|
119
|
-
or if pool creation fails.
|
|
120
|
-
"""
|
|
121
|
-
if self.pool_instance is not None:
|
|
122
|
-
return self.pool_instance
|
|
123
|
-
|
|
124
|
-
if self.pool_config is None:
|
|
125
|
-
msg = "One of 'pool_config' or 'pool_instance' must be provided."
|
|
126
|
-
raise ImproperConfigurationError(msg)
|
|
127
|
-
|
|
128
|
-
pool_config = self.pool_config_dict
|
|
129
|
-
self.pool_instance = AsyncConnectionPool(open=False, **pool_config)
|
|
130
|
-
if self.pool_instance is None: # pyright: ignore[reportUnnecessaryComparison]
|
|
131
|
-
msg = "Could not configure the 'pool_instance'. Please check your configuration." # type: ignore[unreachable]
|
|
132
|
-
raise ImproperConfigurationError(msg)
|
|
133
|
-
await self.pool_instance.open()
|
|
134
|
-
return self.pool_instance
|
|
135
|
-
|
|
136
|
-
def provide_pool(self, *args: "Any", **kwargs: "Any") -> "Awaitable[AsyncConnectionPool]":
|
|
137
|
-
"""Create and return a connection pool.
|
|
138
|
-
|
|
139
|
-
Returns:
|
|
140
|
-
Awaitable[AsyncConnectionPool]: The configured connection pool.
|
|
141
|
-
"""
|
|
142
|
-
return self.create_pool()
|
|
143
|
-
|
|
144
|
-
@asynccontextmanager
|
|
145
|
-
async def provide_connection(self, *args: "Any", **kwargs: "Any") -> "AsyncGenerator[PsycopgAsyncConnection, None]":
|
|
146
|
-
"""Create and provide a database connection.
|
|
147
|
-
|
|
148
|
-
Yields:
|
|
149
|
-
AsyncConnection: A database connection from the pool.
|
|
150
|
-
"""
|
|
151
|
-
pool = await self.provide_pool(*args, **kwargs)
|
|
152
|
-
async with pool, pool.connection() as connection:
|
|
153
|
-
yield connection
|
|
154
|
-
|
|
155
|
-
@asynccontextmanager
|
|
156
|
-
async def provide_session(self, *args: "Any", **kwargs: "Any") -> "AsyncGenerator[PsycopgAsyncDriver, None]":
|
|
157
|
-
"""Create and provide a database session.
|
|
158
|
-
|
|
159
|
-
Yields:
|
|
160
|
-
PsycopgAsyncDriver: A driver instance with an active connection.
|
|
161
|
-
"""
|
|
162
|
-
async with self.provide_connection(*args, **kwargs) as connection:
|
|
163
|
-
yield self.driver_type(connection)
|
|
164
|
-
|
|
165
|
-
async def close_pool(self) -> None:
|
|
166
|
-
"""Close the connection pool."""
|
|
167
|
-
if self.pool_instance is not None:
|
|
168
|
-
await self.pool_instance.close()
|
|
169
|
-
self.pool_instance = None
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
from dataclasses import dataclass
|
|
2
|
-
from typing import TYPE_CHECKING, Generic, TypeVar, Union
|
|
3
|
-
|
|
4
|
-
from sqlspec.base import GenericPoolConfig
|
|
5
|
-
from sqlspec.typing import Empty
|
|
6
|
-
|
|
7
|
-
if TYPE_CHECKING:
|
|
8
|
-
from collections.abc import Callable
|
|
9
|
-
from typing import Any
|
|
10
|
-
|
|
11
|
-
from psycopg import AsyncConnection, Connection
|
|
12
|
-
from psycopg_pool import AsyncConnectionPool, ConnectionPool
|
|
13
|
-
|
|
14
|
-
from sqlspec.typing import EmptyType
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
__all__ = ("PsycopgGenericPoolConfig",)
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
ConnectionT = TypeVar("ConnectionT", bound="Union[Connection, AsyncConnection]")
|
|
21
|
-
PoolT = TypeVar("PoolT", bound="Union[ConnectionPool, AsyncConnectionPool]")
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
@dataclass
|
|
25
|
-
class PsycopgGenericPoolConfig(GenericPoolConfig, Generic[ConnectionT, PoolT]):
|
|
26
|
-
"""Configuration for Psycopg connection pools.
|
|
27
|
-
|
|
28
|
-
This class provides configuration options for both synchronous and asynchronous Psycopg
|
|
29
|
-
database connection pools. It supports all standard Psycopg connection parameters and pool-specific
|
|
30
|
-
settings.([1](https://www.psycopg.org/psycopg3/docs/api/pool.html))
|
|
31
|
-
"""
|
|
32
|
-
|
|
33
|
-
conninfo: "Union[str, EmptyType]" = Empty
|
|
34
|
-
"""Connection string in libpq format"""
|
|
35
|
-
kwargs: "Union[dict[str, Any], EmptyType]" = Empty
|
|
36
|
-
"""Additional connection parameters"""
|
|
37
|
-
min_size: "Union[int, EmptyType]" = Empty
|
|
38
|
-
"""Minimum number of connections in the pool"""
|
|
39
|
-
max_size: "Union[int, EmptyType]" = Empty
|
|
40
|
-
"""Maximum number of connections in the pool"""
|
|
41
|
-
name: "Union[str, EmptyType]" = Empty
|
|
42
|
-
"""Name of the connection pool"""
|
|
43
|
-
timeout: "Union[float, EmptyType]" = Empty
|
|
44
|
-
"""Timeout for acquiring connections"""
|
|
45
|
-
max_waiting: "Union[int, EmptyType]" = Empty
|
|
46
|
-
"""Maximum number of waiting clients"""
|
|
47
|
-
max_lifetime: "Union[float, EmptyType]" = Empty
|
|
48
|
-
"""Maximum connection lifetime"""
|
|
49
|
-
max_idle: "Union[float, EmptyType]" = Empty
|
|
50
|
-
"""Maximum idle time for connections"""
|
|
51
|
-
reconnect_timeout: "Union[float, EmptyType]" = Empty
|
|
52
|
-
"""Time between reconnection attempts"""
|
|
53
|
-
num_workers: "Union[int, EmptyType]" = Empty
|
|
54
|
-
"""Number of background workers"""
|
|
55
|
-
configure: "Union[Callable[[ConnectionT], None], EmptyType]" = Empty
|
|
56
|
-
"""Callback to configure new connections"""
|
|
@@ -1,168 +0,0 @@
|
|
|
1
|
-
from contextlib import contextmanager
|
|
2
|
-
from dataclasses import dataclass, field
|
|
3
|
-
from typing import TYPE_CHECKING, Any, Optional
|
|
4
|
-
|
|
5
|
-
from psycopg_pool import ConnectionPool
|
|
6
|
-
|
|
7
|
-
from sqlspec.adapters.psycopg.config._common import PsycopgGenericPoolConfig
|
|
8
|
-
from sqlspec.adapters.psycopg.driver import PsycopgSyncConnection, PsycopgSyncDriver
|
|
9
|
-
from sqlspec.base import SyncDatabaseConfig
|
|
10
|
-
from sqlspec.exceptions import ImproperConfigurationError
|
|
11
|
-
from sqlspec.typing import dataclass_to_dict
|
|
12
|
-
|
|
13
|
-
if TYPE_CHECKING:
|
|
14
|
-
from collections.abc import Generator
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
__all__ = (
|
|
18
|
-
"PsycopgSyncConfig",
|
|
19
|
-
"PsycopgSyncPoolConfig",
|
|
20
|
-
)
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
@dataclass
|
|
24
|
-
class PsycopgSyncPoolConfig(PsycopgGenericPoolConfig[PsycopgSyncConnection, ConnectionPool]):
|
|
25
|
-
"""Sync Psycopg Pool Config"""
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
@dataclass
|
|
29
|
-
class PsycopgSyncConfig(SyncDatabaseConfig[PsycopgSyncConnection, ConnectionPool, PsycopgSyncDriver]):
|
|
30
|
-
"""Sync Psycopg database Configuration.
|
|
31
|
-
This class provides the base configuration for Psycopg database connections, extending
|
|
32
|
-
the generic database configuration with Psycopg-specific settings.([1](https://www.psycopg.org/psycopg3/docs/api/connections.html))
|
|
33
|
-
|
|
34
|
-
The configuration supports all standard Psycopg connection parameters and can be used
|
|
35
|
-
with both synchronous and asynchronous connections.([2](https://www.psycopg.org/psycopg3/docs/api/connections.html))
|
|
36
|
-
"""
|
|
37
|
-
|
|
38
|
-
pool_config: "Optional[PsycopgSyncPoolConfig]" = None
|
|
39
|
-
"""Psycopg Pool configuration"""
|
|
40
|
-
pool_instance: "Optional[ConnectionPool]" = None
|
|
41
|
-
"""Optional pool to use"""
|
|
42
|
-
connection_type: "type[PsycopgSyncConnection]" = field(init=False, default_factory=lambda: PsycopgSyncConnection) # type: ignore[assignment]
|
|
43
|
-
"""Type of the connection object"""
|
|
44
|
-
driver_type: "type[PsycopgSyncDriver]" = field(init=False, default_factory=lambda: PsycopgSyncDriver) # type: ignore[type-abstract,unused-ignore]
|
|
45
|
-
"""Type of the driver object"""
|
|
46
|
-
|
|
47
|
-
@property
|
|
48
|
-
def connection_config_dict(self) -> "dict[str, Any]":
|
|
49
|
-
"""Return the connection configuration as a dict.
|
|
50
|
-
|
|
51
|
-
Returns:
|
|
52
|
-
A string keyed dict of config kwargs for the psycopg.connect function.
|
|
53
|
-
|
|
54
|
-
Raises:
|
|
55
|
-
ImproperConfigurationError: If the connection configuration is not provided.
|
|
56
|
-
"""
|
|
57
|
-
if self.pool_config:
|
|
58
|
-
# Filter out pool-specific parameters
|
|
59
|
-
pool_only_params = {
|
|
60
|
-
"min_size",
|
|
61
|
-
"max_size",
|
|
62
|
-
"name",
|
|
63
|
-
"timeout",
|
|
64
|
-
"reconnect_timeout",
|
|
65
|
-
"max_idle",
|
|
66
|
-
"max_lifetime",
|
|
67
|
-
}
|
|
68
|
-
return dataclass_to_dict(
|
|
69
|
-
self.pool_config,
|
|
70
|
-
exclude_empty=True,
|
|
71
|
-
convert_nested=False,
|
|
72
|
-
exclude=pool_only_params.union({"pool_instance", "connection_type", "driver_type", "open"}),
|
|
73
|
-
)
|
|
74
|
-
msg = "You must provide a 'pool_config' for this adapter."
|
|
75
|
-
raise ImproperConfigurationError(msg)
|
|
76
|
-
|
|
77
|
-
@property
|
|
78
|
-
def pool_config_dict(self) -> "dict[str, Any]":
|
|
79
|
-
"""Return the pool configuration as a dict.
|
|
80
|
-
|
|
81
|
-
Raises:
|
|
82
|
-
ImproperConfigurationError: If pool_config is not provided and instead pool_instance is used.
|
|
83
|
-
"""
|
|
84
|
-
if self.pool_config:
|
|
85
|
-
return dataclass_to_dict(
|
|
86
|
-
self.pool_config,
|
|
87
|
-
exclude_empty=True,
|
|
88
|
-
convert_nested=False,
|
|
89
|
-
exclude={"pool_instance", "connection_type", "driver_type", "open"},
|
|
90
|
-
)
|
|
91
|
-
msg = "'pool_config' methods can not be used when a 'pool_instance' is provided."
|
|
92
|
-
raise ImproperConfigurationError(msg)
|
|
93
|
-
|
|
94
|
-
def create_connection(self) -> "PsycopgSyncConnection":
|
|
95
|
-
"""Create and return a new psycopg connection from the pool.
|
|
96
|
-
|
|
97
|
-
Returns:
|
|
98
|
-
A Connection instance.
|
|
99
|
-
|
|
100
|
-
Raises:
|
|
101
|
-
ImproperConfigurationError: If the connection could not be created.
|
|
102
|
-
"""
|
|
103
|
-
try:
|
|
104
|
-
pool = self.provide_pool()
|
|
105
|
-
return pool.getconn()
|
|
106
|
-
except Exception as e:
|
|
107
|
-
msg = f"Could not configure the Psycopg connection. Error: {e!s}"
|
|
108
|
-
raise ImproperConfigurationError(msg) from e
|
|
109
|
-
|
|
110
|
-
def create_pool(self) -> "ConnectionPool":
|
|
111
|
-
"""Create and return a connection pool.
|
|
112
|
-
|
|
113
|
-
Returns:
|
|
114
|
-
ConnectionPool: The configured connection pool instance.
|
|
115
|
-
|
|
116
|
-
Raises:
|
|
117
|
-
ImproperConfigurationError: If neither pool_config nor pool_instance is provided,
|
|
118
|
-
or if the pool could not be configured.
|
|
119
|
-
"""
|
|
120
|
-
if self.pool_instance is not None:
|
|
121
|
-
return self.pool_instance
|
|
122
|
-
|
|
123
|
-
if self.pool_config is None:
|
|
124
|
-
msg = "One of 'pool_config' or 'pool_instance' must be provided."
|
|
125
|
-
raise ImproperConfigurationError(msg)
|
|
126
|
-
|
|
127
|
-
pool_config = self.pool_config_dict
|
|
128
|
-
self.pool_instance = ConnectionPool(open=False, **pool_config)
|
|
129
|
-
if self.pool_instance is None: # pyright: ignore[reportUnnecessaryComparison]
|
|
130
|
-
msg = "Could not configure the 'pool_instance'. Please check your configuration." # type: ignore[unreachable]
|
|
131
|
-
raise ImproperConfigurationError(msg)
|
|
132
|
-
self.pool_instance.open()
|
|
133
|
-
return self.pool_instance
|
|
134
|
-
|
|
135
|
-
def provide_pool(self, *args: "Any", **kwargs: "Any") -> "ConnectionPool":
|
|
136
|
-
"""Create and return a connection pool.
|
|
137
|
-
|
|
138
|
-
Returns:
|
|
139
|
-
ConnectionPool: The configured connection pool instance.
|
|
140
|
-
"""
|
|
141
|
-
return self.create_pool()
|
|
142
|
-
|
|
143
|
-
@contextmanager
|
|
144
|
-
def provide_connection(self, *args: "Any", **kwargs: "Any") -> "Generator[PsycopgSyncConnection, None, None]":
|
|
145
|
-
"""Create and provide a database connection.
|
|
146
|
-
|
|
147
|
-
Yields:
|
|
148
|
-
PsycopgSyncConnection: A database connection from the pool.
|
|
149
|
-
"""
|
|
150
|
-
pool = self.provide_pool(*args, **kwargs)
|
|
151
|
-
with pool, pool.connection() as connection:
|
|
152
|
-
yield connection
|
|
153
|
-
|
|
154
|
-
@contextmanager
|
|
155
|
-
def provide_session(self, *args: "Any", **kwargs: "Any") -> "Generator[PsycopgSyncDriver, None, None]":
|
|
156
|
-
"""Create and provide a database session.
|
|
157
|
-
|
|
158
|
-
Yields:
|
|
159
|
-
PsycopgSyncDriver: A driver instance with an active connection.
|
|
160
|
-
"""
|
|
161
|
-
with self.provide_connection(*args, **kwargs) as connection:
|
|
162
|
-
yield self.driver_type(connection)
|
|
163
|
-
|
|
164
|
-
def close_pool(self) -> None:
|
|
165
|
-
"""Close the connection pool."""
|
|
166
|
-
if self.pool_instance is not None:
|
|
167
|
-
self.pool_instance.close()
|
|
168
|
-
self.pool_instance = None
|