sqlspec 0.16.1__cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.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.
- 51ff5a9eadfdefd49f98__mypyc.cpython-39-aarch64-linux-gnu.so +0 -0
- sqlspec/__init__.py +92 -0
- sqlspec/__main__.py +12 -0
- sqlspec/__metadata__.py +14 -0
- sqlspec/_serialization.py +77 -0
- sqlspec/_sql.py +1780 -0
- sqlspec/_typing.py +680 -0
- sqlspec/adapters/__init__.py +0 -0
- sqlspec/adapters/adbc/__init__.py +5 -0
- sqlspec/adapters/adbc/_types.py +12 -0
- sqlspec/adapters/adbc/config.py +361 -0
- sqlspec/adapters/adbc/driver.py +512 -0
- sqlspec/adapters/aiosqlite/__init__.py +19 -0
- sqlspec/adapters/aiosqlite/_types.py +13 -0
- sqlspec/adapters/aiosqlite/config.py +253 -0
- sqlspec/adapters/aiosqlite/driver.py +248 -0
- sqlspec/adapters/asyncmy/__init__.py +19 -0
- sqlspec/adapters/asyncmy/_types.py +12 -0
- sqlspec/adapters/asyncmy/config.py +180 -0
- sqlspec/adapters/asyncmy/driver.py +274 -0
- sqlspec/adapters/asyncpg/__init__.py +21 -0
- sqlspec/adapters/asyncpg/_types.py +17 -0
- sqlspec/adapters/asyncpg/config.py +229 -0
- sqlspec/adapters/asyncpg/driver.py +344 -0
- sqlspec/adapters/bigquery/__init__.py +18 -0
- sqlspec/adapters/bigquery/_types.py +12 -0
- sqlspec/adapters/bigquery/config.py +298 -0
- sqlspec/adapters/bigquery/driver.py +558 -0
- sqlspec/adapters/duckdb/__init__.py +22 -0
- sqlspec/adapters/duckdb/_types.py +12 -0
- sqlspec/adapters/duckdb/config.py +504 -0
- sqlspec/adapters/duckdb/driver.py +368 -0
- sqlspec/adapters/oracledb/__init__.py +32 -0
- sqlspec/adapters/oracledb/_types.py +14 -0
- sqlspec/adapters/oracledb/config.py +317 -0
- sqlspec/adapters/oracledb/driver.py +538 -0
- sqlspec/adapters/psqlpy/__init__.py +16 -0
- sqlspec/adapters/psqlpy/_types.py +11 -0
- sqlspec/adapters/psqlpy/config.py +214 -0
- sqlspec/adapters/psqlpy/driver.py +530 -0
- sqlspec/adapters/psycopg/__init__.py +32 -0
- sqlspec/adapters/psycopg/_types.py +17 -0
- sqlspec/adapters/psycopg/config.py +426 -0
- sqlspec/adapters/psycopg/driver.py +796 -0
- sqlspec/adapters/sqlite/__init__.py +15 -0
- sqlspec/adapters/sqlite/_types.py +11 -0
- sqlspec/adapters/sqlite/config.py +240 -0
- sqlspec/adapters/sqlite/driver.py +294 -0
- sqlspec/base.py +571 -0
- sqlspec/builder/__init__.py +62 -0
- sqlspec/builder/_base.py +473 -0
- sqlspec/builder/_column.py +320 -0
- sqlspec/builder/_ddl.py +1346 -0
- sqlspec/builder/_ddl_utils.py +103 -0
- sqlspec/builder/_delete.py +76 -0
- sqlspec/builder/_insert.py +256 -0
- sqlspec/builder/_merge.py +71 -0
- sqlspec/builder/_parsing_utils.py +140 -0
- sqlspec/builder/_select.py +170 -0
- sqlspec/builder/_update.py +188 -0
- sqlspec/builder/mixins/__init__.py +55 -0
- sqlspec/builder/mixins/_cte_and_set_ops.py +222 -0
- sqlspec/builder/mixins/_delete_operations.py +41 -0
- sqlspec/builder/mixins/_insert_operations.py +244 -0
- sqlspec/builder/mixins/_join_operations.py +122 -0
- sqlspec/builder/mixins/_merge_operations.py +476 -0
- sqlspec/builder/mixins/_order_limit_operations.py +135 -0
- sqlspec/builder/mixins/_pivot_operations.py +153 -0
- sqlspec/builder/mixins/_select_operations.py +603 -0
- sqlspec/builder/mixins/_update_operations.py +187 -0
- sqlspec/builder/mixins/_where_clause.py +621 -0
- sqlspec/cli.py +247 -0
- sqlspec/config.py +395 -0
- sqlspec/core/__init__.py +63 -0
- sqlspec/core/cache.cpython-39-aarch64-linux-gnu.so +0 -0
- sqlspec/core/cache.py +871 -0
- sqlspec/core/compiler.cpython-39-aarch64-linux-gnu.so +0 -0
- sqlspec/core/compiler.py +417 -0
- sqlspec/core/filters.cpython-39-aarch64-linux-gnu.so +0 -0
- sqlspec/core/filters.py +830 -0
- sqlspec/core/hashing.cpython-39-aarch64-linux-gnu.so +0 -0
- sqlspec/core/hashing.py +310 -0
- sqlspec/core/parameters.cpython-39-aarch64-linux-gnu.so +0 -0
- sqlspec/core/parameters.py +1237 -0
- sqlspec/core/result.cpython-39-aarch64-linux-gnu.so +0 -0
- sqlspec/core/result.py +677 -0
- sqlspec/core/splitter.cpython-39-aarch64-linux-gnu.so +0 -0
- sqlspec/core/splitter.py +819 -0
- sqlspec/core/statement.cpython-39-aarch64-linux-gnu.so +0 -0
- sqlspec/core/statement.py +676 -0
- sqlspec/driver/__init__.py +19 -0
- sqlspec/driver/_async.py +502 -0
- sqlspec/driver/_common.py +631 -0
- sqlspec/driver/_sync.py +503 -0
- sqlspec/driver/mixins/__init__.py +6 -0
- sqlspec/driver/mixins/_result_tools.py +193 -0
- sqlspec/driver/mixins/_sql_translator.py +86 -0
- sqlspec/exceptions.py +193 -0
- sqlspec/extensions/__init__.py +0 -0
- sqlspec/extensions/aiosql/__init__.py +10 -0
- sqlspec/extensions/aiosql/adapter.py +461 -0
- sqlspec/extensions/litestar/__init__.py +6 -0
- sqlspec/extensions/litestar/_utils.py +52 -0
- sqlspec/extensions/litestar/cli.py +48 -0
- sqlspec/extensions/litestar/config.py +92 -0
- sqlspec/extensions/litestar/handlers.py +260 -0
- sqlspec/extensions/litestar/plugin.py +145 -0
- sqlspec/extensions/litestar/providers.py +454 -0
- sqlspec/loader.cpython-39-aarch64-linux-gnu.so +0 -0
- sqlspec/loader.py +760 -0
- sqlspec/migrations/__init__.py +35 -0
- sqlspec/migrations/base.py +414 -0
- sqlspec/migrations/commands.py +443 -0
- sqlspec/migrations/loaders.py +402 -0
- sqlspec/migrations/runner.py +213 -0
- sqlspec/migrations/tracker.py +140 -0
- sqlspec/migrations/utils.py +129 -0
- sqlspec/protocols.py +407 -0
- sqlspec/py.typed +0 -0
- sqlspec/storage/__init__.py +23 -0
- sqlspec/storage/backends/__init__.py +0 -0
- sqlspec/storage/backends/base.py +163 -0
- sqlspec/storage/backends/fsspec.py +386 -0
- sqlspec/storage/backends/obstore.py +459 -0
- sqlspec/storage/capabilities.py +102 -0
- sqlspec/storage/registry.py +239 -0
- sqlspec/typing.py +299 -0
- sqlspec/utils/__init__.py +3 -0
- sqlspec/utils/correlation.py +150 -0
- sqlspec/utils/deprecation.py +106 -0
- sqlspec/utils/fixtures.cpython-39-aarch64-linux-gnu.so +0 -0
- sqlspec/utils/fixtures.py +58 -0
- sqlspec/utils/logging.py +127 -0
- sqlspec/utils/module_loader.py +89 -0
- sqlspec/utils/serializers.py +4 -0
- sqlspec/utils/singleton.py +32 -0
- sqlspec/utils/sync_tools.cpython-39-aarch64-linux-gnu.so +0 -0
- sqlspec/utils/sync_tools.py +237 -0
- sqlspec/utils/text.cpython-39-aarch64-linux-gnu.so +0 -0
- sqlspec/utils/text.py +96 -0
- sqlspec/utils/type_guards.cpython-39-aarch64-linux-gnu.so +0 -0
- sqlspec/utils/type_guards.py +1139 -0
- sqlspec-0.16.1.dist-info/METADATA +365 -0
- sqlspec-0.16.1.dist-info/RECORD +148 -0
- sqlspec-0.16.1.dist-info/WHEEL +7 -0
- sqlspec-0.16.1.dist-info/entry_points.txt +2 -0
- sqlspec-0.16.1.dist-info/licenses/LICENSE +21 -0
- sqlspec-0.16.1.dist-info/licenses/NOTICE +29 -0
|
@@ -0,0 +1,426 @@
|
|
|
1
|
+
"""Psycopg database configuration with direct field-based configuration."""
|
|
2
|
+
|
|
3
|
+
import contextlib
|
|
4
|
+
import logging
|
|
5
|
+
from contextlib import asynccontextmanager
|
|
6
|
+
from typing import TYPE_CHECKING, Any, ClassVar, Optional, TypedDict, Union, cast
|
|
7
|
+
|
|
8
|
+
from psycopg.rows import dict_row
|
|
9
|
+
from psycopg_pool import AsyncConnectionPool, ConnectionPool
|
|
10
|
+
from typing_extensions import NotRequired
|
|
11
|
+
|
|
12
|
+
from sqlspec.adapters.psycopg._types import PsycopgAsyncConnection, PsycopgSyncConnection
|
|
13
|
+
from sqlspec.adapters.psycopg.driver import (
|
|
14
|
+
PsycopgAsyncCursor,
|
|
15
|
+
PsycopgAsyncDriver,
|
|
16
|
+
PsycopgSyncCursor,
|
|
17
|
+
PsycopgSyncDriver,
|
|
18
|
+
psycopg_statement_config,
|
|
19
|
+
)
|
|
20
|
+
from sqlspec.config import AsyncDatabaseConfig, SyncDatabaseConfig
|
|
21
|
+
|
|
22
|
+
if TYPE_CHECKING:
|
|
23
|
+
from collections.abc import AsyncGenerator, Callable, Generator
|
|
24
|
+
|
|
25
|
+
from sqlspec.core.statement import StatementConfig
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
logger = logging.getLogger("sqlspec.adapters.psycopg")
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class PsycopgConnectionParams(TypedDict, total=False):
|
|
32
|
+
"""Psycopg connection parameters."""
|
|
33
|
+
|
|
34
|
+
conninfo: NotRequired[str]
|
|
35
|
+
host: NotRequired[str]
|
|
36
|
+
port: NotRequired[int]
|
|
37
|
+
user: NotRequired[str]
|
|
38
|
+
password: NotRequired[str]
|
|
39
|
+
dbname: NotRequired[str]
|
|
40
|
+
connect_timeout: NotRequired[int]
|
|
41
|
+
options: NotRequired[str]
|
|
42
|
+
application_name: NotRequired[str]
|
|
43
|
+
sslmode: NotRequired[str]
|
|
44
|
+
sslcert: NotRequired[str]
|
|
45
|
+
sslkey: NotRequired[str]
|
|
46
|
+
sslrootcert: NotRequired[str]
|
|
47
|
+
autocommit: NotRequired[bool]
|
|
48
|
+
extra: NotRequired[dict[str, Any]]
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
class PsycopgPoolParams(PsycopgConnectionParams, total=False):
|
|
52
|
+
"""Psycopg pool parameters."""
|
|
53
|
+
|
|
54
|
+
min_size: NotRequired[int]
|
|
55
|
+
max_size: NotRequired[int]
|
|
56
|
+
name: NotRequired[str]
|
|
57
|
+
timeout: NotRequired[float]
|
|
58
|
+
max_waiting: NotRequired[int]
|
|
59
|
+
max_lifetime: NotRequired[float]
|
|
60
|
+
max_idle: NotRequired[float]
|
|
61
|
+
reconnect_timeout: NotRequired[float]
|
|
62
|
+
num_workers: NotRequired[int]
|
|
63
|
+
configure: NotRequired["Callable[..., Any]"]
|
|
64
|
+
kwargs: NotRequired[dict[str, Any]]
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
__all__ = (
|
|
68
|
+
"PsycopgAsyncConfig",
|
|
69
|
+
"PsycopgAsyncCursor",
|
|
70
|
+
"PsycopgConnectionParams",
|
|
71
|
+
"PsycopgPoolParams",
|
|
72
|
+
"PsycopgSyncConfig",
|
|
73
|
+
"PsycopgSyncCursor",
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
class PsycopgSyncConfig(SyncDatabaseConfig[PsycopgSyncConnection, ConnectionPool, PsycopgSyncDriver]):
|
|
78
|
+
"""Configuration for Psycopg synchronous database connections with direct field-based configuration."""
|
|
79
|
+
|
|
80
|
+
driver_type: "ClassVar[type[PsycopgSyncDriver]]" = PsycopgSyncDriver
|
|
81
|
+
connection_type: "ClassVar[type[PsycopgSyncConnection]]" = PsycopgSyncConnection
|
|
82
|
+
|
|
83
|
+
def __init__(
|
|
84
|
+
self,
|
|
85
|
+
*,
|
|
86
|
+
pool_config: "Optional[Union[PsycopgPoolParams, dict[str, Any]]]" = None,
|
|
87
|
+
pool_instance: Optional["ConnectionPool"] = None,
|
|
88
|
+
statement_config: "Optional[StatementConfig]" = None,
|
|
89
|
+
migration_config: Optional[dict[str, Any]] = None,
|
|
90
|
+
) -> None:
|
|
91
|
+
"""Initialize Psycopg synchronous configuration.
|
|
92
|
+
|
|
93
|
+
Args:
|
|
94
|
+
pool_config: Pool configuration parameters (TypedDict or dict)
|
|
95
|
+
pool_instance: Existing pool instance to use
|
|
96
|
+
statement_config: Default SQL statement configuration
|
|
97
|
+
migration_config: Migration configuration
|
|
98
|
+
|
|
99
|
+
"""
|
|
100
|
+
processed_pool_config: dict[str, Any] = dict(pool_config) if pool_config else {}
|
|
101
|
+
if "extra" in processed_pool_config:
|
|
102
|
+
extras = processed_pool_config.pop("extra")
|
|
103
|
+
processed_pool_config.update(extras)
|
|
104
|
+
|
|
105
|
+
super().__init__(
|
|
106
|
+
pool_config=processed_pool_config,
|
|
107
|
+
pool_instance=pool_instance,
|
|
108
|
+
migration_config=migration_config,
|
|
109
|
+
statement_config=statement_config or psycopg_statement_config,
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
def _create_pool(self) -> "ConnectionPool":
|
|
113
|
+
"""Create the actual connection pool."""
|
|
114
|
+
logger.info("Creating Psycopg connection pool", extra={"adapter": "psycopg"})
|
|
115
|
+
|
|
116
|
+
try:
|
|
117
|
+
all_config = dict(self.pool_config)
|
|
118
|
+
|
|
119
|
+
pool_parameters = {
|
|
120
|
+
"min_size": all_config.pop("min_size", 4),
|
|
121
|
+
"max_size": all_config.pop("max_size", None),
|
|
122
|
+
"name": all_config.pop("name", None),
|
|
123
|
+
"timeout": all_config.pop("timeout", 30.0),
|
|
124
|
+
"max_waiting": all_config.pop("max_waiting", 0),
|
|
125
|
+
"max_lifetime": all_config.pop("max_lifetime", 3600.0),
|
|
126
|
+
"max_idle": all_config.pop("max_idle", 600.0),
|
|
127
|
+
"reconnect_timeout": all_config.pop("reconnect_timeout", 300.0),
|
|
128
|
+
"num_workers": all_config.pop("num_workers", 3),
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
autocommit_setting = all_config.get("autocommit")
|
|
132
|
+
|
|
133
|
+
def configure_connection(conn: "PsycopgSyncConnection") -> None:
|
|
134
|
+
conn.row_factory = dict_row
|
|
135
|
+
if autocommit_setting is not None:
|
|
136
|
+
conn.autocommit = autocommit_setting
|
|
137
|
+
|
|
138
|
+
try:
|
|
139
|
+
import pgvector.psycopg
|
|
140
|
+
|
|
141
|
+
pgvector.psycopg.register_vector(conn)
|
|
142
|
+
logger.debug("pgvector registered successfully for psycopg sync connection")
|
|
143
|
+
except ImportError:
|
|
144
|
+
pass
|
|
145
|
+
except Exception as e:
|
|
146
|
+
logger.debug("Failed to register pgvector for psycopg sync: %s", e)
|
|
147
|
+
|
|
148
|
+
pool_parameters["configure"] = all_config.pop("configure", configure_connection)
|
|
149
|
+
|
|
150
|
+
pool_parameters = {k: v for k, v in pool_parameters.items() if v is not None}
|
|
151
|
+
|
|
152
|
+
conninfo = all_config.pop("conninfo", None)
|
|
153
|
+
if conninfo:
|
|
154
|
+
pool = ConnectionPool(conninfo, open=True, **pool_parameters)
|
|
155
|
+
else:
|
|
156
|
+
kwargs = all_config.pop("kwargs", {})
|
|
157
|
+
all_config.update(kwargs)
|
|
158
|
+
pool = ConnectionPool("", kwargs=all_config, open=True, **pool_parameters)
|
|
159
|
+
|
|
160
|
+
logger.info("Psycopg connection pool created successfully", extra={"adapter": "psycopg"})
|
|
161
|
+
except Exception as e:
|
|
162
|
+
logger.exception("Failed to create Psycopg connection pool", extra={"adapter": "psycopg", "error": str(e)})
|
|
163
|
+
raise
|
|
164
|
+
return pool
|
|
165
|
+
|
|
166
|
+
def _close_pool(self) -> None:
|
|
167
|
+
"""Close the actual connection pool."""
|
|
168
|
+
if not self.pool_instance:
|
|
169
|
+
return
|
|
170
|
+
|
|
171
|
+
logger.info("Closing Psycopg connection pool", extra={"adapter": "psycopg"})
|
|
172
|
+
|
|
173
|
+
try:
|
|
174
|
+
if hasattr(self.pool_instance, "_closed"):
|
|
175
|
+
self.pool_instance._closed = True
|
|
176
|
+
|
|
177
|
+
self.pool_instance.close()
|
|
178
|
+
logger.info("Psycopg connection pool closed successfully", extra={"adapter": "psycopg"})
|
|
179
|
+
except Exception as e:
|
|
180
|
+
logger.exception("Failed to close Psycopg connection pool", extra={"adapter": "psycopg", "error": str(e)})
|
|
181
|
+
raise
|
|
182
|
+
finally:
|
|
183
|
+
self.pool_instance = None
|
|
184
|
+
|
|
185
|
+
def create_connection(self) -> "PsycopgSyncConnection":
|
|
186
|
+
"""Create a single connection (not from pool).
|
|
187
|
+
|
|
188
|
+
Returns:
|
|
189
|
+
A psycopg Connection instance configured with DictRow.
|
|
190
|
+
"""
|
|
191
|
+
if self.pool_instance is None:
|
|
192
|
+
self.pool_instance = self.create_pool()
|
|
193
|
+
return cast("PsycopgSyncConnection", self.pool_instance.getconn()) # pyright: ignore
|
|
194
|
+
|
|
195
|
+
@contextlib.contextmanager
|
|
196
|
+
def provide_connection(self, *args: Any, **kwargs: Any) -> "Generator[PsycopgSyncConnection, None, None]":
|
|
197
|
+
"""Provide a connection context manager.
|
|
198
|
+
|
|
199
|
+
Args:
|
|
200
|
+
*args: Additional arguments.
|
|
201
|
+
**kwargs: Additional keyword arguments.
|
|
202
|
+
|
|
203
|
+
Yields:
|
|
204
|
+
A psycopg Connection instance.
|
|
205
|
+
"""
|
|
206
|
+
if self.pool_instance:
|
|
207
|
+
with self.pool_instance.connection() as conn:
|
|
208
|
+
yield conn # type: ignore[misc]
|
|
209
|
+
else:
|
|
210
|
+
conn = self.create_connection() # type: ignore[assignment]
|
|
211
|
+
try:
|
|
212
|
+
yield conn # type: ignore[misc]
|
|
213
|
+
finally:
|
|
214
|
+
conn.close()
|
|
215
|
+
|
|
216
|
+
@contextlib.contextmanager
|
|
217
|
+
def provide_session(
|
|
218
|
+
self, *args: Any, statement_config: "Optional[StatementConfig]" = None, **kwargs: Any
|
|
219
|
+
) -> "Generator[PsycopgSyncDriver, None, None]":
|
|
220
|
+
"""Provide a driver session context manager.
|
|
221
|
+
|
|
222
|
+
Args:
|
|
223
|
+
*args: Additional arguments.
|
|
224
|
+
statement_config: Optional statement configuration override.
|
|
225
|
+
**kwargs: Additional keyword arguments.
|
|
226
|
+
|
|
227
|
+
Yields:
|
|
228
|
+
A PsycopgSyncDriver instance.
|
|
229
|
+
"""
|
|
230
|
+
with self.provide_connection(*args, **kwargs) as conn:
|
|
231
|
+
final_statement_config = statement_config or self.statement_config
|
|
232
|
+
yield self.driver_type(connection=conn, statement_config=final_statement_config)
|
|
233
|
+
|
|
234
|
+
def provide_pool(self, *args: Any, **kwargs: Any) -> "ConnectionPool":
|
|
235
|
+
"""Provide pool instance.
|
|
236
|
+
|
|
237
|
+
Returns:
|
|
238
|
+
The connection pool.
|
|
239
|
+
"""
|
|
240
|
+
if not self.pool_instance:
|
|
241
|
+
self.pool_instance = self.create_pool()
|
|
242
|
+
return self.pool_instance
|
|
243
|
+
|
|
244
|
+
def get_signature_namespace(self) -> "dict[str, type[Any]]":
|
|
245
|
+
"""Get the signature namespace for Psycopg types.
|
|
246
|
+
|
|
247
|
+
This provides all Psycopg-specific types that Litestar needs to recognize
|
|
248
|
+
to avoid serialization attempts.
|
|
249
|
+
|
|
250
|
+
Returns:
|
|
251
|
+
Dictionary mapping type names to types.
|
|
252
|
+
"""
|
|
253
|
+
namespace = super().get_signature_namespace()
|
|
254
|
+
namespace.update({"PsycopgSyncConnection": PsycopgSyncConnection, "PsycopgSyncCursor": PsycopgSyncCursor})
|
|
255
|
+
return namespace
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
class PsycopgAsyncConfig(AsyncDatabaseConfig[PsycopgAsyncConnection, AsyncConnectionPool, PsycopgAsyncDriver]):
|
|
259
|
+
"""Configuration for Psycopg asynchronous database connections with direct field-based configuration."""
|
|
260
|
+
|
|
261
|
+
driver_type: ClassVar[type[PsycopgAsyncDriver]] = PsycopgAsyncDriver
|
|
262
|
+
connection_type: "ClassVar[type[PsycopgAsyncConnection]]" = PsycopgAsyncConnection
|
|
263
|
+
|
|
264
|
+
def __init__(
|
|
265
|
+
self,
|
|
266
|
+
*,
|
|
267
|
+
pool_config: "Optional[Union[PsycopgPoolParams, dict[str, Any]]]" = None,
|
|
268
|
+
pool_instance: "Optional[AsyncConnectionPool]" = None,
|
|
269
|
+
migration_config: "Optional[dict[str, Any]]" = None,
|
|
270
|
+
statement_config: "Optional[StatementConfig]" = None,
|
|
271
|
+
) -> None:
|
|
272
|
+
"""Initialize Psycopg asynchronous configuration.
|
|
273
|
+
|
|
274
|
+
Args:
|
|
275
|
+
pool_config: Pool configuration parameters (TypedDict or dict)
|
|
276
|
+
pool_instance: Existing pool instance to use
|
|
277
|
+
statement_config: Default SQL statement configuration
|
|
278
|
+
migration_config: Migration configuration
|
|
279
|
+
"""
|
|
280
|
+
processed_pool_config: dict[str, Any] = dict(pool_config) if pool_config else {}
|
|
281
|
+
if "extra" in processed_pool_config:
|
|
282
|
+
extras = processed_pool_config.pop("extra")
|
|
283
|
+
processed_pool_config.update(extras)
|
|
284
|
+
|
|
285
|
+
super().__init__(
|
|
286
|
+
pool_config=processed_pool_config,
|
|
287
|
+
pool_instance=pool_instance,
|
|
288
|
+
migration_config=migration_config,
|
|
289
|
+
statement_config=statement_config or psycopg_statement_config,
|
|
290
|
+
)
|
|
291
|
+
|
|
292
|
+
async def _create_pool(self) -> "AsyncConnectionPool":
|
|
293
|
+
"""Create the actual async connection pool."""
|
|
294
|
+
|
|
295
|
+
all_config = dict(self.pool_config)
|
|
296
|
+
|
|
297
|
+
pool_parameters = {
|
|
298
|
+
"min_size": all_config.pop("min_size", 4),
|
|
299
|
+
"max_size": all_config.pop("max_size", None),
|
|
300
|
+
"name": all_config.pop("name", None),
|
|
301
|
+
"timeout": all_config.pop("timeout", 30.0),
|
|
302
|
+
"max_waiting": all_config.pop("max_waiting", 0),
|
|
303
|
+
"max_lifetime": all_config.pop("max_lifetime", 3600.0),
|
|
304
|
+
"max_idle": all_config.pop("max_idle", 600.0),
|
|
305
|
+
"reconnect_timeout": all_config.pop("reconnect_timeout", 300.0),
|
|
306
|
+
"num_workers": all_config.pop("num_workers", 3),
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
# Capture autocommit setting before configuring the pool
|
|
310
|
+
autocommit_setting = all_config.get("autocommit")
|
|
311
|
+
|
|
312
|
+
async def configure_connection(conn: "PsycopgAsyncConnection") -> None:
|
|
313
|
+
conn.row_factory = dict_row
|
|
314
|
+
if autocommit_setting is not None:
|
|
315
|
+
await conn.set_autocommit(autocommit_setting)
|
|
316
|
+
|
|
317
|
+
try:
|
|
318
|
+
from pgvector.psycopg import register_vector_async
|
|
319
|
+
|
|
320
|
+
await register_vector_async(conn)
|
|
321
|
+
logger.debug("pgvector registered successfully for psycopg async connection")
|
|
322
|
+
except ImportError:
|
|
323
|
+
pass
|
|
324
|
+
except Exception as e:
|
|
325
|
+
logger.debug("Failed to register pgvector for psycopg async: %s", e)
|
|
326
|
+
|
|
327
|
+
pool_parameters["configure"] = all_config.pop("configure", configure_connection)
|
|
328
|
+
|
|
329
|
+
pool_parameters = {k: v for k, v in pool_parameters.items() if v is not None}
|
|
330
|
+
|
|
331
|
+
conninfo = all_config.pop("conninfo", None)
|
|
332
|
+
if conninfo:
|
|
333
|
+
pool = AsyncConnectionPool(conninfo, open=False, **pool_parameters)
|
|
334
|
+
else:
|
|
335
|
+
kwargs = all_config.pop("kwargs", {})
|
|
336
|
+
all_config.update(kwargs)
|
|
337
|
+
pool = AsyncConnectionPool("", kwargs=all_config, open=False, **pool_parameters)
|
|
338
|
+
|
|
339
|
+
await pool.open()
|
|
340
|
+
|
|
341
|
+
return pool
|
|
342
|
+
|
|
343
|
+
async def _close_pool(self) -> None:
|
|
344
|
+
"""Close the actual async connection pool."""
|
|
345
|
+
if not self.pool_instance:
|
|
346
|
+
return
|
|
347
|
+
|
|
348
|
+
try:
|
|
349
|
+
if hasattr(self.pool_instance, "_closed"):
|
|
350
|
+
self.pool_instance._closed = True
|
|
351
|
+
|
|
352
|
+
await self.pool_instance.close()
|
|
353
|
+
finally:
|
|
354
|
+
self.pool_instance = None
|
|
355
|
+
|
|
356
|
+
async def create_connection(self) -> "PsycopgAsyncConnection": # pyright: ignore
|
|
357
|
+
"""Create a single async connection (not from pool).
|
|
358
|
+
|
|
359
|
+
Returns:
|
|
360
|
+
A psycopg AsyncConnection instance configured with DictRow.
|
|
361
|
+
"""
|
|
362
|
+
if self.pool_instance is None:
|
|
363
|
+
self.pool_instance = await self.create_pool()
|
|
364
|
+
return cast("PsycopgAsyncConnection", await self.pool_instance.getconn()) # pyright: ignore
|
|
365
|
+
|
|
366
|
+
@asynccontextmanager
|
|
367
|
+
async def provide_connection(self, *args: Any, **kwargs: Any) -> "AsyncGenerator[PsycopgAsyncConnection, None]": # pyright: ignore
|
|
368
|
+
"""Provide an async connection context manager.
|
|
369
|
+
|
|
370
|
+
Args:
|
|
371
|
+
*args: Additional arguments.
|
|
372
|
+
**kwargs: Additional keyword arguments.
|
|
373
|
+
|
|
374
|
+
Yields:
|
|
375
|
+
A psycopg AsyncConnection instance.
|
|
376
|
+
"""
|
|
377
|
+
if self.pool_instance:
|
|
378
|
+
async with self.pool_instance.connection() as conn:
|
|
379
|
+
yield conn # type: ignore[misc]
|
|
380
|
+
else:
|
|
381
|
+
conn = await self.create_connection() # type: ignore[assignment]
|
|
382
|
+
try:
|
|
383
|
+
yield conn # type: ignore[misc]
|
|
384
|
+
finally:
|
|
385
|
+
await conn.close()
|
|
386
|
+
|
|
387
|
+
@asynccontextmanager
|
|
388
|
+
async def provide_session(
|
|
389
|
+
self, *args: Any, statement_config: "Optional[StatementConfig]" = None, **kwargs: Any
|
|
390
|
+
) -> "AsyncGenerator[PsycopgAsyncDriver, None]":
|
|
391
|
+
"""Provide an async driver session context manager.
|
|
392
|
+
|
|
393
|
+
Args:
|
|
394
|
+
*args: Additional arguments.
|
|
395
|
+
statement_config: Optional statement configuration override.
|
|
396
|
+
**kwargs: Additional keyword arguments.
|
|
397
|
+
|
|
398
|
+
Yields:
|
|
399
|
+
A PsycopgAsyncDriver instance.
|
|
400
|
+
"""
|
|
401
|
+
async with self.provide_connection(*args, **kwargs) as conn:
|
|
402
|
+
final_statement_config = statement_config or psycopg_statement_config
|
|
403
|
+
yield self.driver_type(connection=conn, statement_config=final_statement_config)
|
|
404
|
+
|
|
405
|
+
async def provide_pool(self, *args: Any, **kwargs: Any) -> "AsyncConnectionPool":
|
|
406
|
+
"""Provide async pool instance.
|
|
407
|
+
|
|
408
|
+
Returns:
|
|
409
|
+
The async connection pool.
|
|
410
|
+
"""
|
|
411
|
+
if not self.pool_instance:
|
|
412
|
+
self.pool_instance = await self.create_pool()
|
|
413
|
+
return self.pool_instance
|
|
414
|
+
|
|
415
|
+
def get_signature_namespace(self) -> "dict[str, type[Any]]":
|
|
416
|
+
"""Get the signature namespace for Psycopg async types.
|
|
417
|
+
|
|
418
|
+
This provides all Psycopg async-specific types that Litestar needs to recognize
|
|
419
|
+
to avoid serialization attempts.
|
|
420
|
+
|
|
421
|
+
Returns:
|
|
422
|
+
Dictionary mapping type names to types.
|
|
423
|
+
"""
|
|
424
|
+
namespace = super().get_signature_namespace()
|
|
425
|
+
namespace.update({"PsycopgAsyncConnection": PsycopgAsyncConnection, "PsycopgAsyncCursor": PsycopgAsyncCursor})
|
|
426
|
+
return namespace
|