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,9 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
"""Psqlpy adapter for SQLSpec."""
|
|
2
|
+
|
|
3
|
+
from sqlspec.adapters.psqlpy.config import CONNECTION_FIELDS, POOL_FIELDS, PsqlpyConfig
|
|
2
4
|
from sqlspec.adapters.psqlpy.driver import PsqlpyConnection, PsqlpyDriver
|
|
3
5
|
|
|
4
|
-
__all__ = (
|
|
5
|
-
"PsqlpyConfig",
|
|
6
|
-
"PsqlpyConnection",
|
|
7
|
-
"PsqlpyDriver",
|
|
8
|
-
"PsqlpyPoolConfig",
|
|
9
|
-
)
|
|
6
|
+
__all__ = ("CONNECTION_FIELDS", "POOL_FIELDS", "PsqlpyConfig", "PsqlpyConnection", "PsqlpyDriver")
|
|
@@ -1,250 +1,419 @@
|
|
|
1
|
-
"""
|
|
1
|
+
"""Psqlpy database configuration with direct field-based configuration."""
|
|
2
2
|
|
|
3
|
+
import logging
|
|
4
|
+
from collections.abc import AsyncGenerator
|
|
3
5
|
from contextlib import asynccontextmanager
|
|
4
|
-
from dataclasses import
|
|
5
|
-
from typing import TYPE_CHECKING, Any,
|
|
6
|
+
from dataclasses import replace
|
|
7
|
+
from typing import TYPE_CHECKING, Any, ClassVar, Optional
|
|
6
8
|
|
|
7
|
-
from psqlpy import
|
|
9
|
+
from psqlpy import ConnectionPool
|
|
8
10
|
|
|
9
11
|
from sqlspec.adapters.psqlpy.driver import PsqlpyConnection, PsqlpyDriver
|
|
10
|
-
from sqlspec.
|
|
11
|
-
from sqlspec.
|
|
12
|
-
from sqlspec.typing import
|
|
12
|
+
from sqlspec.config import AsyncDatabaseConfig
|
|
13
|
+
from sqlspec.statement.sql import SQLConfig
|
|
14
|
+
from sqlspec.typing import DictRow, Empty
|
|
13
15
|
|
|
14
16
|
if TYPE_CHECKING:
|
|
15
|
-
from collections.abc import
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
17
|
+
from collections.abc import Callable
|
|
18
|
+
|
|
19
|
+
from sqlglot.dialects.dialect import DialectType
|
|
20
|
+
|
|
21
|
+
logger = logging.getLogger("sqlspec.adapters.psqlpy")
|
|
22
|
+
|
|
23
|
+
CONNECTION_FIELDS = frozenset(
|
|
24
|
+
{
|
|
25
|
+
"dsn",
|
|
26
|
+
"username",
|
|
27
|
+
"password",
|
|
28
|
+
"db_name",
|
|
29
|
+
"host",
|
|
30
|
+
"port",
|
|
31
|
+
"connect_timeout_sec",
|
|
32
|
+
"connect_timeout_nanosec",
|
|
33
|
+
"tcp_user_timeout_sec",
|
|
34
|
+
"tcp_user_timeout_nanosec",
|
|
35
|
+
"keepalives",
|
|
36
|
+
"keepalives_idle_sec",
|
|
37
|
+
"keepalives_idle_nanosec",
|
|
38
|
+
"keepalives_interval_sec",
|
|
39
|
+
"keepalives_interval_nanosec",
|
|
40
|
+
"keepalives_retries",
|
|
41
|
+
"ssl_mode",
|
|
42
|
+
"ca_file",
|
|
43
|
+
"target_session_attrs",
|
|
44
|
+
"options",
|
|
45
|
+
"application_name",
|
|
46
|
+
"client_encoding",
|
|
47
|
+
"gssencmode",
|
|
48
|
+
"sslnegotiation",
|
|
49
|
+
"sslcompression",
|
|
50
|
+
"sslcert",
|
|
51
|
+
"sslkey",
|
|
52
|
+
"sslpassword",
|
|
53
|
+
"sslrootcert",
|
|
54
|
+
"sslcrl",
|
|
55
|
+
"require_auth",
|
|
56
|
+
"channel_binding",
|
|
57
|
+
"krbsrvname",
|
|
58
|
+
"gsslib",
|
|
59
|
+
"gssdelegation",
|
|
60
|
+
"service",
|
|
61
|
+
"load_balance_hosts",
|
|
62
|
+
}
|
|
21
63
|
)
|
|
22
64
|
|
|
65
|
+
POOL_FIELDS = CONNECTION_FIELDS.union({"hosts", "ports", "conn_recycling_method", "max_db_pool_size", "configure"})
|
|
23
66
|
|
|
24
|
-
|
|
25
|
-
class PsqlpyPoolConfig(GenericPoolConfig):
|
|
26
|
-
"""Configuration for psqlpy connection pool.
|
|
27
|
-
|
|
28
|
-
Ref: https://psqlpy-python.github.io/components/connection_pool.html#all-available-connectionpool-parameters
|
|
29
|
-
"""
|
|
30
|
-
|
|
31
|
-
dsn: Optional[Union[str, EmptyType]] = Empty
|
|
32
|
-
"""DSN of the PostgreSQL."""
|
|
33
|
-
# Required connection parameters
|
|
34
|
-
username: Optional[Union[str, EmptyType]] = Empty
|
|
35
|
-
"""Username of the user in the PostgreSQL."""
|
|
36
|
-
password: Optional[Union[str, EmptyType]] = Empty
|
|
37
|
-
"""Password of the user in the PostgreSQL."""
|
|
38
|
-
db_name: Optional[Union[str, EmptyType]] = Empty
|
|
39
|
-
"""Name of the database in PostgreSQL."""
|
|
40
|
-
|
|
41
|
-
# Single or Multi-host parameters (mutually exclusive)
|
|
42
|
-
host: Optional[Union[str, EmptyType]] = Empty
|
|
43
|
-
"""Host of the PostgreSQL (use for single host)."""
|
|
44
|
-
port: Optional[Union[int, EmptyType]] = Empty
|
|
45
|
-
"""Port of the PostgreSQL (use for single host)."""
|
|
46
|
-
hosts: Optional[Union[list[str], EmptyType]] = Empty
|
|
47
|
-
"""List of hosts of the PostgreSQL (use for multiple hosts)."""
|
|
48
|
-
ports: Optional[Union[list[int], EmptyType]] = Empty
|
|
49
|
-
"""List of ports of the PostgreSQL (use for multiple hosts)."""
|
|
50
|
-
|
|
51
|
-
# Pool size
|
|
52
|
-
max_db_pool_size: int = 10
|
|
53
|
-
"""Maximum size of the connection pool. Defaults to 10."""
|
|
54
|
-
|
|
55
|
-
# Optional timeouts
|
|
56
|
-
connect_timeout_sec: Optional[Union[int, EmptyType]] = Empty
|
|
57
|
-
"""The time limit in seconds applied to each socket-level connection attempt."""
|
|
58
|
-
connect_timeout_nanosec: Optional[Union[int, EmptyType]] = Empty
|
|
59
|
-
"""Nanoseconds for connection timeout, can be used only with `connect_timeout_sec`."""
|
|
60
|
-
tcp_user_timeout_sec: Optional[Union[int, EmptyType]] = Empty
|
|
61
|
-
"""The time limit that transmitted data may remain unacknowledged before a connection is forcibly closed."""
|
|
62
|
-
tcp_user_timeout_nanosec: Optional[Union[int, EmptyType]] = Empty
|
|
63
|
-
"""Nanoseconds for tcp_user_timeout, can be used only with `tcp_user_timeout_sec`."""
|
|
64
|
-
|
|
65
|
-
# Optional keepalives
|
|
66
|
-
keepalives: bool = True
|
|
67
|
-
"""Controls the use of TCP keepalive. Defaults to True (on)."""
|
|
68
|
-
keepalives_idle_sec: Optional[Union[int, EmptyType]] = Empty
|
|
69
|
-
"""The number of seconds of inactivity after which a keepalive message is sent to the server."""
|
|
70
|
-
keepalives_idle_nanosec: Optional[Union[int, EmptyType]] = Empty
|
|
71
|
-
"""Nanoseconds for keepalives_idle_sec."""
|
|
72
|
-
keepalives_interval_sec: Optional[Union[int, EmptyType]] = Empty
|
|
73
|
-
"""The time interval between TCP keepalive probes."""
|
|
74
|
-
keepalives_interval_nanosec: Optional[Union[int, EmptyType]] = Empty
|
|
75
|
-
"""Nanoseconds for keepalives_interval_sec."""
|
|
76
|
-
keepalives_retries: Optional[Union[int, EmptyType]] = Empty
|
|
77
|
-
"""The maximum number of TCP keepalive probes that will be sent before dropping a connection."""
|
|
78
|
-
|
|
79
|
-
# Other optional parameters
|
|
80
|
-
load_balance_hosts: Optional[Union[str, EmptyType]] = Empty
|
|
81
|
-
"""Controls the order in which the client tries to connect to the available hosts and addresses ('disable' or 'random')."""
|
|
82
|
-
conn_recycling_method: Optional[Union[str, EmptyType]] = Empty
|
|
83
|
-
"""How a connection is recycled."""
|
|
84
|
-
ssl_mode: Optional[Union[str, EmptyType]] = Empty
|
|
85
|
-
"""SSL mode."""
|
|
86
|
-
ca_file: Optional[Union[str, EmptyType]] = Empty
|
|
87
|
-
"""Path to ca_file for SSL."""
|
|
88
|
-
target_session_attrs: Optional[Union[str, EmptyType]] = Empty
|
|
89
|
-
"""Specifies requirements of the session (e.g., 'read-write')."""
|
|
90
|
-
options: Optional[Union[str, EmptyType]] = Empty
|
|
91
|
-
"""Command line options used to configure the server."""
|
|
92
|
-
application_name: Optional[Union[str, EmptyType]] = Empty
|
|
93
|
-
"""Sets the application_name parameter on the server."""
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
@dataclass
|
|
97
|
-
class PsqlpyConfig(AsyncDatabaseConfig[PsqlpyConnection, ConnectionPool, PsqlpyDriver]):
|
|
98
|
-
"""Configuration for psqlpy database connections, managing a connection pool.
|
|
67
|
+
__all__ = ("CONNECTION_FIELDS", "POOL_FIELDS", "PsqlpyConfig")
|
|
99
68
|
|
|
100
|
-
This configuration class wraps `PsqlpyPoolConfig` and manages the lifecycle
|
|
101
|
-
of a `psqlpy.ConnectionPool`.
|
|
102
|
-
"""
|
|
103
69
|
|
|
104
|
-
|
|
105
|
-
"""Psqlpy
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
70
|
+
class PsqlpyConfig(AsyncDatabaseConfig[PsqlpyConnection, ConnectionPool, PsqlpyDriver]):
|
|
71
|
+
"""Configuration for Psqlpy asynchronous database connections with direct field-based configuration."""
|
|
72
|
+
|
|
73
|
+
__slots__ = (
|
|
74
|
+
"_dialect",
|
|
75
|
+
"application_name",
|
|
76
|
+
"ca_file",
|
|
77
|
+
"channel_binding",
|
|
78
|
+
"client_encoding",
|
|
79
|
+
"configure",
|
|
80
|
+
"conn_recycling_method",
|
|
81
|
+
"connect_timeout_nanosec",
|
|
82
|
+
"connect_timeout_sec",
|
|
83
|
+
"db_name",
|
|
84
|
+
"default_row_type",
|
|
85
|
+
"dsn",
|
|
86
|
+
"extras",
|
|
87
|
+
"gssdelegation",
|
|
88
|
+
"gssencmode",
|
|
89
|
+
"gsslib",
|
|
90
|
+
"host",
|
|
91
|
+
"hosts",
|
|
92
|
+
"keepalives",
|
|
93
|
+
"keepalives_idle_nanosec",
|
|
94
|
+
"keepalives_idle_sec",
|
|
95
|
+
"keepalives_interval_nanosec",
|
|
96
|
+
"keepalives_interval_sec",
|
|
97
|
+
"keepalives_retries",
|
|
98
|
+
"krbsrvname",
|
|
99
|
+
"load_balance_hosts",
|
|
100
|
+
"max_db_pool_size",
|
|
101
|
+
"options",
|
|
102
|
+
"password",
|
|
103
|
+
"pool_instance",
|
|
104
|
+
"port",
|
|
105
|
+
"ports",
|
|
106
|
+
"require_auth",
|
|
107
|
+
"service",
|
|
108
|
+
"ssl_mode",
|
|
109
|
+
"sslcert",
|
|
110
|
+
"sslcompression",
|
|
111
|
+
"sslcrl",
|
|
112
|
+
"sslkey",
|
|
113
|
+
"sslnegotiation",
|
|
114
|
+
"sslpassword",
|
|
115
|
+
"sslrootcert",
|
|
116
|
+
"statement_config",
|
|
117
|
+
"target_session_attrs",
|
|
118
|
+
"tcp_user_timeout_nanosec",
|
|
119
|
+
"tcp_user_timeout_sec",
|
|
120
|
+
"username",
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
is_async: ClassVar[bool] = True
|
|
124
|
+
supports_connection_pooling: ClassVar[bool] = True
|
|
125
|
+
|
|
126
|
+
driver_type: type[PsqlpyDriver] = PsqlpyDriver
|
|
127
|
+
connection_type: type[PsqlpyConnection] = PsqlpyConnection
|
|
128
|
+
# Parameter style support information
|
|
129
|
+
supported_parameter_styles: ClassVar[tuple[str, ...]] = ("numeric",)
|
|
130
|
+
"""Psqlpy only supports $1, $2, ... (numeric) parameter style."""
|
|
131
|
+
|
|
132
|
+
preferred_parameter_style: ClassVar[str] = "numeric"
|
|
133
|
+
"""Psqlpy's native parameter style is $1, $2, ... (numeric)."""
|
|
134
|
+
|
|
135
|
+
def __init__(
|
|
136
|
+
self,
|
|
137
|
+
statement_config: Optional[SQLConfig] = None,
|
|
138
|
+
default_row_type: type[DictRow] = DictRow,
|
|
139
|
+
# Connection parameters
|
|
140
|
+
dsn: Optional[str] = None,
|
|
141
|
+
username: Optional[str] = None,
|
|
142
|
+
password: Optional[str] = None,
|
|
143
|
+
db_name: Optional[str] = None,
|
|
144
|
+
host: Optional[str] = None,
|
|
145
|
+
port: Optional[int] = None,
|
|
146
|
+
hosts: Optional[list[str]] = None,
|
|
147
|
+
ports: Optional[list[int]] = None,
|
|
148
|
+
connect_timeout_sec: Optional[int] = None,
|
|
149
|
+
connect_timeout_nanosec: Optional[int] = None,
|
|
150
|
+
tcp_user_timeout_sec: Optional[int] = None,
|
|
151
|
+
tcp_user_timeout_nanosec: Optional[int] = None,
|
|
152
|
+
keepalives: Optional[bool] = None,
|
|
153
|
+
keepalives_idle_sec: Optional[int] = None,
|
|
154
|
+
keepalives_idle_nanosec: Optional[int] = None,
|
|
155
|
+
keepalives_interval_sec: Optional[int] = None,
|
|
156
|
+
keepalives_interval_nanosec: Optional[int] = None,
|
|
157
|
+
keepalives_retries: Optional[int] = None,
|
|
158
|
+
ssl_mode: Optional[str] = None,
|
|
159
|
+
ca_file: Optional[str] = None,
|
|
160
|
+
target_session_attrs: Optional[str] = None,
|
|
161
|
+
options: Optional[str] = None,
|
|
162
|
+
application_name: Optional[str] = None,
|
|
163
|
+
client_encoding: Optional[str] = None,
|
|
164
|
+
gssencmode: Optional[str] = None,
|
|
165
|
+
sslnegotiation: Optional[str] = None,
|
|
166
|
+
sslcompression: Optional[bool] = None,
|
|
167
|
+
sslcert: Optional[str] = None,
|
|
168
|
+
sslkey: Optional[str] = None,
|
|
169
|
+
sslpassword: Optional[str] = None,
|
|
170
|
+
sslrootcert: Optional[str] = None,
|
|
171
|
+
sslcrl: Optional[str] = None,
|
|
172
|
+
require_auth: Optional[str] = None,
|
|
173
|
+
channel_binding: Optional[str] = None,
|
|
174
|
+
krbsrvname: Optional[str] = None,
|
|
175
|
+
gsslib: Optional[str] = None,
|
|
176
|
+
gssdelegation: Optional[bool] = None,
|
|
177
|
+
service: Optional[str] = None,
|
|
178
|
+
load_balance_hosts: Optional[str] = None,
|
|
179
|
+
# Pool parameters
|
|
180
|
+
conn_recycling_method: Optional[str] = None,
|
|
181
|
+
max_db_pool_size: Optional[int] = None,
|
|
182
|
+
configure: Optional["Callable[[ConnectionPool], None]"] = None,
|
|
183
|
+
pool_instance: Optional[ConnectionPool] = None,
|
|
184
|
+
**kwargs: Any,
|
|
185
|
+
) -> None:
|
|
186
|
+
"""Initialize Psqlpy asynchronous configuration.
|
|
187
|
+
|
|
188
|
+
Args:
|
|
189
|
+
statement_config: Default SQL statement configuration
|
|
190
|
+
default_row_type: Default row type for results
|
|
191
|
+
dsn: DSN of the PostgreSQL database
|
|
192
|
+
username: Username of the user in the PostgreSQL
|
|
193
|
+
password: Password of the user in the PostgreSQL
|
|
194
|
+
db_name: Name of the database in PostgreSQL
|
|
195
|
+
host: Host of the PostgreSQL (use for single host)
|
|
196
|
+
port: Port of the PostgreSQL (use for single host)
|
|
197
|
+
hosts: List of hosts of the PostgreSQL (use for multiple hosts)
|
|
198
|
+
ports: List of ports of the PostgreSQL (use for multiple hosts)
|
|
199
|
+
connect_timeout_sec: The time limit in seconds applied to each socket-level connection attempt
|
|
200
|
+
connect_timeout_nanosec: Nanoseconds for connection timeout, can be used only with connect_timeout_sec
|
|
201
|
+
tcp_user_timeout_sec: The time limit that transmitted data may remain unacknowledged before a connection is forcibly closed
|
|
202
|
+
tcp_user_timeout_nanosec: Nanoseconds for tcp_user_timeout, can be used only with tcp_user_timeout_sec
|
|
203
|
+
keepalives: Controls the use of TCP keepalive. Defaults to True (on)
|
|
204
|
+
keepalives_idle_sec: The number of seconds of inactivity after which a keepalive message is sent to the server
|
|
205
|
+
keepalives_idle_nanosec: Nanoseconds for keepalives_idle_sec
|
|
206
|
+
keepalives_interval_sec: The time interval between TCP keepalive probes
|
|
207
|
+
keepalives_interval_nanosec: Nanoseconds for keepalives_interval_sec
|
|
208
|
+
keepalives_retries: The maximum number of TCP keepalive probes that will be sent before dropping a connection
|
|
209
|
+
ssl_mode: SSL mode (disable, prefer, require, verify-ca, verify-full)
|
|
210
|
+
ca_file: Path to ca_file for SSL
|
|
211
|
+
target_session_attrs: Specifies requirements of the session (e.g., 'read-write', 'read-only', 'primary', 'standby')
|
|
212
|
+
options: Command line options used to configure the server
|
|
213
|
+
application_name: Sets the application_name parameter on the server
|
|
214
|
+
client_encoding: Sets the client_encoding parameter
|
|
215
|
+
gssencmode: GSS encryption mode (disable, prefer, require)
|
|
216
|
+
sslnegotiation: SSL negotiation mode (postgres, direct)
|
|
217
|
+
sslcompression: Whether to use SSL compression
|
|
218
|
+
sslcert: Client SSL certificate file
|
|
219
|
+
sslkey: Client SSL private key file
|
|
220
|
+
sslpassword: Password for the SSL private key
|
|
221
|
+
sslrootcert: SSL root certificate file
|
|
222
|
+
sslcrl: SSL certificate revocation list file
|
|
223
|
+
require_auth: Authentication method requirements
|
|
224
|
+
channel_binding: Channel binding preference (disable, prefer, require)
|
|
225
|
+
krbsrvname: Kerberos service name
|
|
226
|
+
gsslib: GSS library to use
|
|
227
|
+
gssdelegation: Forward GSS credentials to server
|
|
228
|
+
service: Service name for additional parameters
|
|
229
|
+
load_balance_hosts: Controls the order in which the client tries to connect to the available hosts and addresses ('disable' or 'random')
|
|
230
|
+
conn_recycling_method: How a connection is recycled
|
|
231
|
+
max_db_pool_size: Maximum size of the connection pool. Defaults to 10
|
|
232
|
+
configure: Callback to configure new connections
|
|
233
|
+
pool_instance: Existing connection pool instance to use
|
|
234
|
+
**kwargs: Additional parameters (stored in extras)
|
|
235
|
+
"""
|
|
236
|
+
# Store connection parameters as instance attributes
|
|
237
|
+
self.dsn = dsn
|
|
238
|
+
self.username = username
|
|
239
|
+
self.password = password
|
|
240
|
+
self.db_name = db_name
|
|
241
|
+
self.host = host
|
|
242
|
+
self.port = port
|
|
243
|
+
self.hosts = hosts
|
|
244
|
+
self.ports = ports
|
|
245
|
+
self.connect_timeout_sec = connect_timeout_sec
|
|
246
|
+
self.connect_timeout_nanosec = connect_timeout_nanosec
|
|
247
|
+
self.tcp_user_timeout_sec = tcp_user_timeout_sec
|
|
248
|
+
self.tcp_user_timeout_nanosec = tcp_user_timeout_nanosec
|
|
249
|
+
self.keepalives = keepalives
|
|
250
|
+
self.keepalives_idle_sec = keepalives_idle_sec
|
|
251
|
+
self.keepalives_idle_nanosec = keepalives_idle_nanosec
|
|
252
|
+
self.keepalives_interval_sec = keepalives_interval_sec
|
|
253
|
+
self.keepalives_interval_nanosec = keepalives_interval_nanosec
|
|
254
|
+
self.keepalives_retries = keepalives_retries
|
|
255
|
+
self.ssl_mode = ssl_mode
|
|
256
|
+
self.ca_file = ca_file
|
|
257
|
+
self.target_session_attrs = target_session_attrs
|
|
258
|
+
self.options = options
|
|
259
|
+
self.application_name = application_name
|
|
260
|
+
self.client_encoding = client_encoding
|
|
261
|
+
self.gssencmode = gssencmode
|
|
262
|
+
self.sslnegotiation = sslnegotiation
|
|
263
|
+
self.sslcompression = sslcompression
|
|
264
|
+
self.sslcert = sslcert
|
|
265
|
+
self.sslkey = sslkey
|
|
266
|
+
self.sslpassword = sslpassword
|
|
267
|
+
self.sslrootcert = sslrootcert
|
|
268
|
+
self.sslcrl = sslcrl
|
|
269
|
+
self.require_auth = require_auth
|
|
270
|
+
self.channel_binding = channel_binding
|
|
271
|
+
self.krbsrvname = krbsrvname
|
|
272
|
+
self.gsslib = gsslib
|
|
273
|
+
self.gssdelegation = gssdelegation
|
|
274
|
+
self.service = service
|
|
275
|
+
self.load_balance_hosts = load_balance_hosts
|
|
276
|
+
|
|
277
|
+
# Store pool parameters as instance attributes
|
|
278
|
+
self.conn_recycling_method = conn_recycling_method
|
|
279
|
+
self.max_db_pool_size = max_db_pool_size
|
|
280
|
+
self.configure = configure
|
|
281
|
+
|
|
282
|
+
self.extras = kwargs or {}
|
|
283
|
+
|
|
284
|
+
# Store other config
|
|
285
|
+
self.statement_config = statement_config or SQLConfig()
|
|
286
|
+
self.default_row_type = default_row_type
|
|
287
|
+
self.pool_instance: Optional[ConnectionPool] = pool_instance
|
|
288
|
+
self._dialect: DialectType = None
|
|
289
|
+
|
|
290
|
+
super().__init__()
|
|
112
291
|
|
|
113
292
|
@property
|
|
114
|
-
def connection_config_dict(self) ->
|
|
115
|
-
"""Return the
|
|
116
|
-
|
|
117
|
-
Returns:
|
|
118
|
-
A string keyed dict of config kwargs for a psqlpy.Connection.
|
|
293
|
+
def connection_config_dict(self) -> dict[str, Any]:
|
|
294
|
+
"""Return the connection configuration as a dict for psqlpy.Connection.
|
|
119
295
|
|
|
120
|
-
|
|
121
|
-
ImproperConfigurationError: If essential connection parameters are missing.
|
|
296
|
+
This method filters out pool-specific parameters that are not valid for psqlpy.Connection.
|
|
122
297
|
"""
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
"pool_instance",
|
|
130
|
-
"connection_type",
|
|
131
|
-
"driver_type",
|
|
132
|
-
}
|
|
133
|
-
return dataclass_to_dict(
|
|
134
|
-
self.pool_config,
|
|
135
|
-
exclude_empty=True,
|
|
136
|
-
convert_nested=False,
|
|
137
|
-
exclude_none=True,
|
|
138
|
-
exclude=pool_specific_keys,
|
|
139
|
-
)
|
|
140
|
-
msg = "You must provide a 'pool_config' for this adapter."
|
|
141
|
-
raise ImproperConfigurationError(msg)
|
|
298
|
+
# Gather non-None connection parameters
|
|
299
|
+
config = {
|
|
300
|
+
field: getattr(self, field)
|
|
301
|
+
for field in CONNECTION_FIELDS
|
|
302
|
+
if getattr(self, field, None) is not None and getattr(self, field) is not Empty
|
|
303
|
+
}
|
|
142
304
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
"""Return the pool configuration as a dict.
|
|
305
|
+
# Add connection-specific extras (not pool-specific ones)
|
|
306
|
+
config.update(self.extras)
|
|
146
307
|
|
|
147
|
-
|
|
148
|
-
|
|
308
|
+
return config
|
|
309
|
+
|
|
310
|
+
@property
|
|
311
|
+
def pool_config_dict(self) -> dict[str, Any]:
|
|
312
|
+
"""Return the full pool configuration as a dict for psqlpy.ConnectionPool.
|
|
149
313
|
|
|
150
314
|
Returns:
|
|
151
|
-
A
|
|
315
|
+
A dictionary containing all pool configuration parameters.
|
|
152
316
|
"""
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
exclude_none=True,
|
|
160
|
-
exclude={"pool_instance", "connection_type", "driver_type"},
|
|
161
|
-
)
|
|
317
|
+
# Gather non-None parameters from all fields (connection + pool)
|
|
318
|
+
config = {
|
|
319
|
+
field: getattr(self, field)
|
|
320
|
+
for field in POOL_FIELDS
|
|
321
|
+
if getattr(self, field, None) is not None and getattr(self, field) is not Empty
|
|
322
|
+
}
|
|
162
323
|
|
|
163
|
-
|
|
164
|
-
|
|
324
|
+
# Merge extras parameters
|
|
325
|
+
config.update(self.extras)
|
|
165
326
|
|
|
166
|
-
|
|
167
|
-
"""Return a pool. If none exists yet, create one.
|
|
327
|
+
return config
|
|
168
328
|
|
|
169
|
-
|
|
329
|
+
async def _create_pool(self) -> ConnectionPool:
|
|
330
|
+
"""Create the actual async connection pool."""
|
|
331
|
+
logger.info("Creating psqlpy connection pool", extra={"adapter": "psqlpy"})
|
|
170
332
|
|
|
171
|
-
|
|
172
|
-
|
|
333
|
+
try:
|
|
334
|
+
config = self.pool_config_dict
|
|
335
|
+
pool = ConnectionPool(**config) # pyright: ignore
|
|
336
|
+
logger.info("Psqlpy connection pool created successfully", extra={"adapter": "psqlpy"})
|
|
337
|
+
except Exception as e:
|
|
338
|
+
logger.exception("Failed to create psqlpy connection pool", extra={"adapter": "psqlpy", "error": str(e)})
|
|
339
|
+
raise
|
|
340
|
+
return pool
|
|
173
341
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
return self.pool_instance
|
|
342
|
+
async def _close_pool(self) -> None:
|
|
343
|
+
"""Close the actual async connection pool."""
|
|
344
|
+
if not self.pool_instance:
|
|
345
|
+
return
|
|
179
346
|
|
|
180
|
-
|
|
181
|
-
msg = "One of 'pool_config' or 'pool_instance' must be provided."
|
|
182
|
-
raise ImproperConfigurationError(msg)
|
|
347
|
+
logger.info("Closing psqlpy connection pool", extra={"adapter": "psqlpy"})
|
|
183
348
|
|
|
184
|
-
# pool_config is guaranteed to exist due to __post_init__
|
|
185
349
|
try:
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
self.pool_instance = ConnectionPool(**self.pool_config_dict)
|
|
350
|
+
self.pool_instance.close()
|
|
351
|
+
logger.info("Psqlpy connection pool closed successfully", extra={"adapter": "psqlpy"})
|
|
189
352
|
except Exception as e:
|
|
190
|
-
|
|
191
|
-
raise
|
|
353
|
+
logger.exception("Failed to close psqlpy connection pool", extra={"adapter": "psqlpy", "error": str(e)})
|
|
354
|
+
raise
|
|
192
355
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
def provide_pool(self, *args: "Any", **kwargs: "Any") -> "Awaitable[ConnectionPool]":
|
|
196
|
-
"""Create or return the pool instance.
|
|
356
|
+
async def create_connection(self) -> PsqlpyConnection:
|
|
357
|
+
"""Create a single async connection (not from pool).
|
|
197
358
|
|
|
198
359
|
Returns:
|
|
199
|
-
|
|
360
|
+
A psqlpy Connection instance.
|
|
200
361
|
"""
|
|
362
|
+
# Ensure pool exists
|
|
363
|
+
if not self.pool_instance:
|
|
364
|
+
self.pool_instance = await self._create_pool()
|
|
201
365
|
|
|
202
|
-
|
|
203
|
-
|
|
366
|
+
# Get connection from pool
|
|
367
|
+
return await self.pool_instance.connection()
|
|
204
368
|
|
|
205
|
-
|
|
369
|
+
@asynccontextmanager
|
|
370
|
+
async def provide_connection(self, *args: Any, **kwargs: Any) -> AsyncGenerator[PsqlpyConnection, None]:
|
|
371
|
+
"""Provide an async connection context manager.
|
|
206
372
|
|
|
207
|
-
|
|
208
|
-
|
|
373
|
+
Args:
|
|
374
|
+
*args: Additional arguments.
|
|
375
|
+
**kwargs: Additional keyword arguments.
|
|
209
376
|
|
|
210
|
-
|
|
211
|
-
|
|
377
|
+
Yields:
|
|
378
|
+
A psqlpy Connection instance.
|
|
212
379
|
"""
|
|
380
|
+
# Ensure pool exists
|
|
381
|
+
if not self.pool_instance:
|
|
382
|
+
self.pool_instance = await self._create_pool()
|
|
213
383
|
|
|
214
|
-
async
|
|
215
|
-
|
|
216
|
-
async with self.provide_connection() as conn:
|
|
217
|
-
return conn
|
|
218
|
-
except Exception as e:
|
|
219
|
-
msg = f"Could not configure the psqlpy connection. Error: {e!s}"
|
|
220
|
-
raise ImproperConfigurationError(msg) from e
|
|
221
|
-
|
|
222
|
-
return _create()
|
|
384
|
+
async with self.pool_instance.acquire() as conn:
|
|
385
|
+
yield conn
|
|
223
386
|
|
|
224
387
|
@asynccontextmanager
|
|
225
|
-
async def
|
|
226
|
-
"""
|
|
388
|
+
async def provide_session(self, *args: Any, **kwargs: Any) -> AsyncGenerator[PsqlpyDriver, None]:
|
|
389
|
+
"""Provide an async driver session context manager.
|
|
390
|
+
|
|
391
|
+
Args:
|
|
392
|
+
*args: Additional arguments.
|
|
393
|
+
**kwargs: Additional keyword arguments.
|
|
227
394
|
|
|
228
395
|
Yields:
|
|
229
|
-
A
|
|
396
|
+
A PsqlpyDriver instance.
|
|
230
397
|
"""
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
398
|
+
async with self.provide_connection(*args, **kwargs) as conn:
|
|
399
|
+
# Create statement config with parameter style info if not already set
|
|
400
|
+
statement_config = self.statement_config
|
|
401
|
+
if statement_config.allowed_parameter_styles is None:
|
|
402
|
+
statement_config = replace(
|
|
403
|
+
statement_config,
|
|
404
|
+
allowed_parameter_styles=self.supported_parameter_styles,
|
|
405
|
+
target_parameter_style=self.preferred_parameter_style,
|
|
406
|
+
)
|
|
407
|
+
|
|
408
|
+
driver = self.driver_type(connection=conn, config=statement_config)
|
|
409
|
+
yield driver
|
|
410
|
+
|
|
411
|
+
async def provide_pool(self, *args: Any, **kwargs: Any) -> ConnectionPool:
|
|
412
|
+
"""Provide async pool instance.
|
|
234
413
|
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
if self.pool_instance is not None:
|
|
238
|
-
# psqlpy pool close is synchronous
|
|
239
|
-
self.pool_instance.close()
|
|
240
|
-
self.pool_instance = None
|
|
241
|
-
|
|
242
|
-
@asynccontextmanager
|
|
243
|
-
async def provide_session(self, *args: Any, **kwargs: Any) -> "AsyncGenerator[PsqlpyDriver, None]":
|
|
244
|
-
"""Create and provide a database session using a pooled connection.
|
|
245
|
-
|
|
246
|
-
Yields:
|
|
247
|
-
A Psqlpy driver instance wrapping a pooled connection.
|
|
414
|
+
Returns:
|
|
415
|
+
The async connection pool.
|
|
248
416
|
"""
|
|
249
|
-
|
|
250
|
-
|
|
417
|
+
if not self.pool_instance:
|
|
418
|
+
self.pool_instance = await self.create_pool()
|
|
419
|
+
return self.pool_instance
|