sqlalchemy-foundation-kit 0.2.1__tar.gz → 0.3.0__tar.gz

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.
Files changed (52) hide show
  1. {sqlalchemy_foundation_kit-0.2.1 → sqlalchemy_foundation_kit-0.3.0}/CHANGELOG.md +7 -0
  2. {sqlalchemy_foundation_kit-0.2.1 → sqlalchemy_foundation_kit-0.3.0}/PKG-INFO +3 -3
  3. {sqlalchemy_foundation_kit-0.2.1 → sqlalchemy_foundation_kit-0.3.0}/README.md +2 -2
  4. {sqlalchemy_foundation_kit-0.2.1 → sqlalchemy_foundation_kit-0.3.0}/sqlalchemy_foundation_kit/__init__.py +1 -1
  5. sqlalchemy_foundation_kit-0.3.0/sqlalchemy_foundation_kit/__version__.py +1 -0
  6. {sqlalchemy_foundation_kit-0.2.1 → sqlalchemy_foundation_kit-0.3.0}/sqlalchemy_foundation_kit/config/postgres.py +3 -3
  7. {sqlalchemy_foundation_kit-0.2.1 → sqlalchemy_foundation_kit-0.3.0}/sqlalchemy_foundation_kit/contrib/settings/postgres.py +13 -4
  8. {sqlalchemy_foundation_kit-0.2.1 → sqlalchemy_foundation_kit-0.3.0}/sqlalchemy_foundation_kit/session/builder.py +18 -0
  9. {sqlalchemy_foundation_kit-0.2.1 → sqlalchemy_foundation_kit-0.3.0}/sqlalchemy_foundation_kit/session/factories.py +12 -3
  10. {sqlalchemy_foundation_kit-0.2.1 → sqlalchemy_foundation_kit-0.3.0}/sqlalchemy_foundation_kit/session/manager.py +40 -1
  11. sqlalchemy_foundation_kit-0.2.1/sqlalchemy_foundation_kit/__version__.py +0 -1
  12. {sqlalchemy_foundation_kit-0.2.1 → sqlalchemy_foundation_kit-0.3.0}/.gitignore +0 -0
  13. {sqlalchemy_foundation_kit-0.2.1 → sqlalchemy_foundation_kit-0.3.0}/LICENSE +0 -0
  14. {sqlalchemy_foundation_kit-0.2.1 → sqlalchemy_foundation_kit-0.3.0}/pyproject.toml +0 -0
  15. {sqlalchemy_foundation_kit-0.2.1 → sqlalchemy_foundation_kit-0.3.0}/sqlalchemy_foundation_kit/_typing.py +0 -0
  16. {sqlalchemy_foundation_kit-0.2.1 → sqlalchemy_foundation_kit-0.3.0}/sqlalchemy_foundation_kit/base/__init__.py +0 -0
  17. {sqlalchemy_foundation_kit-0.2.1 → sqlalchemy_foundation_kit-0.3.0}/sqlalchemy_foundation_kit/base/_optional.py +0 -0
  18. {sqlalchemy_foundation_kit-0.2.1 → sqlalchemy_foundation_kit-0.3.0}/sqlalchemy_foundation_kit/base/engine.py +0 -0
  19. {sqlalchemy_foundation_kit-0.2.1 → sqlalchemy_foundation_kit-0.3.0}/sqlalchemy_foundation_kit/base/metadata.py +0 -0
  20. {sqlalchemy_foundation_kit-0.2.1 → sqlalchemy_foundation_kit-0.3.0}/sqlalchemy_foundation_kit/base/models.py +0 -0
  21. {sqlalchemy_foundation_kit-0.2.1 → sqlalchemy_foundation_kit-0.3.0}/sqlalchemy_foundation_kit/base/serialization.py +0 -0
  22. {sqlalchemy_foundation_kit-0.2.1 → sqlalchemy_foundation_kit-0.3.0}/sqlalchemy_foundation_kit/base/types.py +0 -0
  23. {sqlalchemy_foundation_kit-0.2.1 → sqlalchemy_foundation_kit-0.3.0}/sqlalchemy_foundation_kit/config/__init__.py +0 -0
  24. {sqlalchemy_foundation_kit-0.2.1 → sqlalchemy_foundation_kit-0.3.0}/sqlalchemy_foundation_kit/contrib/__init__.py +0 -0
  25. {sqlalchemy_foundation_kit-0.2.1 → sqlalchemy_foundation_kit-0.3.0}/sqlalchemy_foundation_kit/contrib/_metrics_utils.py +0 -0
  26. {sqlalchemy_foundation_kit-0.2.1 → sqlalchemy_foundation_kit-0.3.0}/sqlalchemy_foundation_kit/contrib/dependency_injector/__init__.py +0 -0
  27. {sqlalchemy_foundation_kit-0.2.1 → sqlalchemy_foundation_kit-0.3.0}/sqlalchemy_foundation_kit/contrib/dependency_injector/_base.py +0 -0
  28. {sqlalchemy_foundation_kit-0.2.1 → sqlalchemy_foundation_kit-0.3.0}/sqlalchemy_foundation_kit/contrib/dependency_injector/_deps.py +0 -0
  29. {sqlalchemy_foundation_kit-0.2.1 → sqlalchemy_foundation_kit-0.3.0}/sqlalchemy_foundation_kit/contrib/dependency_injector/database.py +0 -0
  30. {sqlalchemy_foundation_kit-0.2.1 → sqlalchemy_foundation_kit-0.3.0}/sqlalchemy_foundation_kit/contrib/dependency_injector/metrics.py +0 -0
  31. {sqlalchemy_foundation_kit-0.2.1 → sqlalchemy_foundation_kit-0.3.0}/sqlalchemy_foundation_kit/contrib/di/__init__.py +0 -0
  32. {sqlalchemy_foundation_kit-0.2.1 → sqlalchemy_foundation_kit-0.3.0}/sqlalchemy_foundation_kit/contrib/di/_base.py +0 -0
  33. {sqlalchemy_foundation_kit-0.2.1 → sqlalchemy_foundation_kit-0.3.0}/sqlalchemy_foundation_kit/contrib/di/_deps.py +0 -0
  34. {sqlalchemy_foundation_kit-0.2.1 → sqlalchemy_foundation_kit-0.3.0}/sqlalchemy_foundation_kit/contrib/di/database.py +0 -0
  35. {sqlalchemy_foundation_kit-0.2.1 → sqlalchemy_foundation_kit-0.3.0}/sqlalchemy_foundation_kit/contrib/di/metrics.py +0 -0
  36. {sqlalchemy_foundation_kit-0.2.1 → sqlalchemy_foundation_kit-0.3.0}/sqlalchemy_foundation_kit/contrib/metrics/__init__.py +0 -0
  37. {sqlalchemy_foundation_kit-0.2.1 → sqlalchemy_foundation_kit-0.3.0}/sqlalchemy_foundation_kit/contrib/metrics/postgres.py +0 -0
  38. {sqlalchemy_foundation_kit-0.2.1 → sqlalchemy_foundation_kit-0.3.0}/sqlalchemy_foundation_kit/contrib/settings/__init__.py +0 -0
  39. {sqlalchemy_foundation_kit-0.2.1 → sqlalchemy_foundation_kit-0.3.0}/sqlalchemy_foundation_kit/contrib/telemetry/__init__.py +0 -0
  40. {sqlalchemy_foundation_kit-0.2.1 → sqlalchemy_foundation_kit-0.3.0}/sqlalchemy_foundation_kit/contrib/telemetry/instrumentations.py +0 -0
  41. {sqlalchemy_foundation_kit-0.2.1 → sqlalchemy_foundation_kit-0.3.0}/sqlalchemy_foundation_kit/contrib/telemetry/uow.py +0 -0
  42. {sqlalchemy_foundation_kit-0.2.1 → sqlalchemy_foundation_kit-0.3.0}/sqlalchemy_foundation_kit/protocols/__init__.py +0 -0
  43. {sqlalchemy_foundation_kit-0.2.1 → sqlalchemy_foundation_kit-0.3.0}/sqlalchemy_foundation_kit/protocols/metrics.py +0 -0
  44. {sqlalchemy_foundation_kit-0.2.1 → sqlalchemy_foundation_kit-0.3.0}/sqlalchemy_foundation_kit/py.typed +0 -0
  45. {sqlalchemy_foundation_kit-0.2.1 → sqlalchemy_foundation_kit-0.3.0}/sqlalchemy_foundation_kit/session/__init__.py +0 -0
  46. {sqlalchemy_foundation_kit-0.2.1 → sqlalchemy_foundation_kit-0.3.0}/sqlalchemy_foundation_kit/session/connection.py +0 -0
  47. {sqlalchemy_foundation_kit-0.2.1 → sqlalchemy_foundation_kit-0.3.0}/sqlalchemy_foundation_kit/session/locks.py +0 -0
  48. {sqlalchemy_foundation_kit-0.2.1 → sqlalchemy_foundation_kit-0.3.0}/sqlalchemy_foundation_kit/session/retry.py +0 -0
  49. {sqlalchemy_foundation_kit-0.2.1 → sqlalchemy_foundation_kit-0.3.0}/sqlalchemy_foundation_kit/uow/__init__.py +0 -0
  50. {sqlalchemy_foundation_kit-0.2.1 → sqlalchemy_foundation_kit-0.3.0}/sqlalchemy_foundation_kit/uow/enums.py +0 -0
  51. {sqlalchemy_foundation_kit-0.2.1 → sqlalchemy_foundation_kit-0.3.0}/sqlalchemy_foundation_kit/uow/protocols.py +0 -0
  52. {sqlalchemy_foundation_kit-0.2.1 → sqlalchemy_foundation_kit-0.3.0}/sqlalchemy_foundation_kit/uow/sqlalchemy.py +0 -0
@@ -1,5 +1,12 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.3.0](https://github.com/bedrock-python/sqlalchemy-foundation-kit/compare/sqlalchemy-foundation-kit-v0.2.1...sqlalchemy-foundation-kit-v0.3.0) (2026-09-07)
4
+
5
+
6
+ ### Features
7
+
8
+ * stop sending jit and search_path as startup parameters ([#24](https://github.com/bedrock-python/sqlalchemy-foundation-kit/issues/24)) ([704c343](https://github.com/bedrock-python/sqlalchemy-foundation-kit/commit/704c343b932b15f0c6ee434f2fc80ab4732b0f80))
9
+
3
10
  ## [0.2.1](https://github.com/bedrock-python/sqlalchemy-foundation-kit/compare/sqlalchemy-foundation-kit-v0.2.0...sqlalchemy-foundation-kit-v0.2.1) (2026-09-06)
4
11
 
5
12
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: sqlalchemy-foundation-kit
3
- Version: 0.2.1
3
+ Version: 0.3.0
4
4
  Summary: Foundation layer for SQLAlchemy-based services with UoW, session management, and observability
5
5
  Project-URL: Repository, https://github.com/bedrock-python/sqlalchemy-foundation-kit
6
6
  Project-URL: Documentation, https://bedrock-python.github.io/sqlalchemy-foundation-kit/
@@ -295,7 +295,7 @@ Only `sqlalchemy[asyncio]`, `pydantic` and `asyncpg` are required by default —
295
295
  ✅ **Single dependency** — All foundation pieces in one place
296
296
  ✅ **Unit of Work pattern** — Transactional consistency with automatic commit/rollback
297
297
  ✅ **Connection pool management** — `AsyncSessionManager` with metrics and health checks
298
- ✅ **pgbouncer compatible** — Custom connection class for transaction mode
298
+ ✅ **PgBouncer compatible** — A startup packet PgBouncer accepts, `search_path` per transaction, unique statement names
299
299
  ✅ **Observability built-in** — Prometheus metrics + OpenTelemetry tracing
300
300
  ✅ **Type-safe configuration** — Pydantic settings with validation
301
301
  ✅ **Base ORM models** — Pre-configured `Base` with naming conventions and mixins
@@ -398,7 +398,7 @@ class PostgresConfig:
398
398
  application_name: str = "my-service"
399
399
  db_schema: str | None = None
400
400
  use_orjson_serialization: bool = True
401
- jit: str | None = "off"
401
+ jit: str | None = None
402
402
 
403
403
  def to_dsn(self) -> str:
404
404
  return f"postgresql+asyncpg://{self.connection.user}@{self.connection.host}:{self.connection.port}/{self.connection.database}"
@@ -44,7 +44,7 @@ Only `sqlalchemy[asyncio]`, `pydantic` and `asyncpg` are required by default —
44
44
  ✅ **Single dependency** — All foundation pieces in one place
45
45
  ✅ **Unit of Work pattern** — Transactional consistency with automatic commit/rollback
46
46
  ✅ **Connection pool management** — `AsyncSessionManager` with metrics and health checks
47
- ✅ **pgbouncer compatible** — Custom connection class for transaction mode
47
+ ✅ **PgBouncer compatible** — A startup packet PgBouncer accepts, `search_path` per transaction, unique statement names
48
48
  ✅ **Observability built-in** — Prometheus metrics + OpenTelemetry tracing
49
49
  ✅ **Type-safe configuration** — Pydantic settings with validation
50
50
  ✅ **Base ORM models** — Pre-configured `Base` with naming conventions and mixins
@@ -147,7 +147,7 @@ class PostgresConfig:
147
147
  application_name: str = "my-service"
148
148
  db_schema: str | None = None
149
149
  use_orjson_serialization: bool = True
150
- jit: str | None = "off"
150
+ jit: str | None = None
151
151
 
152
152
  def to_dsn(self) -> str:
153
153
  return f"postgresql+asyncpg://{self.connection.user}@{self.connection.host}:{self.connection.port}/{self.connection.database}"
@@ -64,7 +64,7 @@ from .uow import (
64
64
  try:
65
65
  __version__ = version("sqlalchemy-foundation-kit")
66
66
  except PackageNotFoundError: # pragma: no cover
67
- __version__ = "0.2.1"
67
+ __version__ = "0.3.0"
68
68
 
69
69
  __all__ = [ # noqa: RUF022
70
70
  # Base ORM
@@ -0,0 +1 @@
1
+ __version__ = "0.3.0"
@@ -131,9 +131,9 @@ class PostgresSettingsProtocol(Protocol):
131
131
  pool: Connection pool settings.
132
132
  query: Query execution and transaction settings.
133
133
  application_name: Application identifier for connections.
134
- db_schema: Optional PostgreSQL schema name.
134
+ db_schema: Optional PostgreSQL ``search_path``, applied to every transaction.
135
135
  use_orjson_serialization: Enable orjson for JSON operations.
136
- jit: JIT compilation setting (PgBouncer compatibility).
136
+ jit: JIT compilation setting, sent as a startup parameter only when not ``None``.
137
137
 
138
138
  Examples:
139
139
  Implementing the protocol:
@@ -144,7 +144,7 @@ class PostgresSettingsProtocol(Protocol):
144
144
  ... application_name: str = "my-app"
145
145
  ... db_schema: str | None = None
146
146
  ... use_orjson_serialization: bool = True
147
- ... jit: str | None = "off"
147
+ ... jit: str | None = None
148
148
  ...
149
149
  ... def to_dsn(self) -> str:
150
150
  ... return f"postgresql://{self.connection.user}@{self.connection.host}..."
@@ -98,9 +98,12 @@ class BasePostgresConfig(BaseSettings):
98
98
  pool: Connection pool configuration (size, overflow, timeouts).
99
99
  query: Query execution settings (echo, caching, isolation level).
100
100
  application_name: Application name for connection identification.
101
- db_schema: Optional PostgreSQL schema name.
101
+ db_schema: Optional PostgreSQL ``search_path`` — a schema, or a comma-separated
102
+ list — applied to every transaction with ``SET LOCAL`` semantics.
102
103
  use_orjson_serialization: Use orjson for JSON serialization (requires orjson).
103
- jit: JIT compilation setting (off/on) for PgBouncer compatibility.
104
+ jit: JIT compilation setting (off/on), sent as a startup parameter only when set.
105
+ ``None`` (the default) sends nothing and leaves the server's own setting; a
106
+ transaction-mode PgBouncer rejects the parameter unless it tracks it.
104
107
  metrics_enabled: Enable connection pool metrics collection.
105
108
 
106
109
  Examples:
@@ -125,12 +128,18 @@ class BasePostgresConfig(BaseSettings):
125
128
 
126
129
  # Top-level settings
127
130
  application_name: str = Field(description="Application name for PostgreSQL")
128
- db_schema: str | None = Field(default=None, description="PostgreSQL schema name")
131
+ db_schema: str | None = Field(
132
+ default=None,
133
+ description="PostgreSQL search_path (a schema or a comma-separated list), applied to every transaction",
134
+ )
129
135
  use_orjson_serialization: bool = Field(
130
136
  default=True,
131
137
  description="Use orjson for JSON serialization (requires orjson installed)",
132
138
  )
133
- jit: PostgresJit | None = Field(default="off", description="JIT setting (off/on)")
139
+ jit: PostgresJit | None = Field(
140
+ default=None,
141
+ description="JIT setting (off/on), sent as a startup parameter only when set",
142
+ )
134
143
  metrics_enabled: bool = Field(default=False, description="Enable PostgreSQL metrics")
135
144
 
136
145
  def __repr__(self) -> str:
@@ -77,6 +77,7 @@ class AsyncSessionManagerBuilder(Generic[SessionT]):
77
77
  self._metrics: PostgresMetricsProtocol | None = None
78
78
  self._on_engine_created: Callable[[AsyncEngine], None] | None = None
79
79
  self._dispose_timeout: float | None = None
80
+ self._search_path: str | None = None
80
81
  self._extra_kwargs: dict[str, object] = {}
81
82
 
82
83
  def with_echo(self, echo: bool = True) -> AsyncSessionManagerBuilder[SessionT]:
@@ -258,6 +259,22 @@ class AsyncSessionManagerBuilder(Generic[SessionT]):
258
259
  self._dispose_timeout = timeout
259
260
  return self
260
261
 
262
+ def with_search_path(self, search_path: str) -> AsyncSessionManagerBuilder[SessionT]:
263
+ """Apply a PostgreSQL ``search_path`` to every transaction.
264
+
265
+ Issued with ``SET LOCAL`` semantics at the start of each transaction — the one
266
+ scope a transaction-mode pooler such as PgBouncer honours. See
267
+ :func:`~sqlalchemy_foundation_kit.session.manager.attach_search_path`.
268
+
269
+ Args:
270
+ search_path: A schema, or a comma-separated list such as ``"tenant_7, public"``.
271
+
272
+ Returns:
273
+ Self for method chaining.
274
+ """
275
+ self._search_path = search_path
276
+ return self
277
+
261
278
  def build(self) -> AsyncSessionManager[SessionT]:
262
279
  """Build AsyncSessionManager instance with configured parameters.
263
280
 
@@ -284,6 +301,7 @@ class AsyncSessionManagerBuilder(Generic[SessionT]):
284
301
  "use_orjson": self._use_orjson,
285
302
  "metrics": self._metrics,
286
303
  "on_engine_created": self._on_engine_created,
304
+ "search_path": self._search_path,
287
305
  }
288
306
  if self._dispose_timeout is not None:
289
307
  kwargs["dispose_timeout"] = self._dispose_timeout
@@ -31,6 +31,13 @@ def create_async_session_manager(
31
31
  ) -> AsyncSessionManager[AsyncSession]:
32
32
  """Create async session manager with PostgreSQL-specific configuration.
33
33
 
34
+ The startup packet carries ``application_name`` and, only when the config sets it,
35
+ ``jit``; nothing else, because a transaction-mode pooler such as PgBouncer rejects
36
+ startup parameters it does not track (``unsupported startup parameter: jit``) or,
37
+ with ``ignore_startup_parameters``, silently drops them. ``db_schema`` therefore
38
+ travels as the manager's ``search_path`` and is applied with ``SET LOCAL`` semantics
39
+ at the start of every transaction, which is the one scope such a pooler honours.
40
+
34
41
  Args:
35
42
  postgres_config: PostgreSQL configuration implementing PostgresSettingsProtocol.
36
43
  application_name: Optional custom application name. If None, uses postgres_config.application_name.
@@ -41,7 +48,8 @@ def create_async_session_manager(
41
48
  which provides pgbouncer transaction-mode compatibility.
42
49
  extra_server_settings: Additional PostgreSQL ``server_settings`` to merge with defaults
43
50
  (e.g., ``{"statement_timeout": "30000", "timezone": "UTC"}``). User-provided keys
44
- override library defaults.
51
+ override library defaults. These are startup parameters: through PgBouncer only
52
+ the ones it tracks arrive (``track_extra_parameters``).
45
53
  extra_connect_args: Additional asyncpg ``connect_args`` to merge with defaults
46
54
  (e.g., ``{"command_timeout": 60}``). User-provided keys override library defaults.
47
55
  **kwargs: Additional keyword arguments passed to AsyncSessionManager.
@@ -73,11 +81,11 @@ def create_async_session_manager(
73
81
  """
74
82
  app_name = application_name or postgres_config.application_name
75
83
 
76
- # Build server settings with optional overrides
84
+ # Build server settings with optional overrides. These are startup parameters, so
85
+ # search_path is deliberately not among them -- see the docstring.
77
86
  server_settings: dict[str, str] = {
78
87
  "application_name": app_name,
79
88
  **({"jit": postgres_config.jit} if postgres_config.jit is not None else {}),
80
- **({"search_path": postgres_config.db_schema} if postgres_config.db_schema is not None else {}),
81
89
  **(extra_server_settings or {}),
82
90
  }
83
91
 
@@ -100,5 +108,6 @@ def create_async_session_manager(
100
108
  use_orjson=postgres_config.use_orjson_serialization,
101
109
  metrics=metrics,
102
110
  on_engine_created=on_engine_created,
111
+ search_path=postgres_config.db_schema,
103
112
  **kwargs,
104
113
  )
@@ -10,7 +10,7 @@ from contextlib import asynccontextmanager
10
10
  from types import TracebackType
11
11
  from typing import TYPE_CHECKING, Any, Generic, cast
12
12
 
13
- from sqlalchemy import event
13
+ from sqlalchemy import event, text
14
14
  from sqlalchemy.exc import TimeoutError as SATimeoutError
15
15
  from sqlalchemy.ext.asyncio import (
16
16
  AsyncEngine,
@@ -23,6 +23,8 @@ from .._typing import SessionT
23
23
  from ..base import build_engine_kwargs, resolve_pool_class
24
24
 
25
25
  if TYPE_CHECKING:
26
+ from sqlalchemy.engine import Connection
27
+
26
28
  from ..config import PoolSettingsProtocol
27
29
  from ..protocols import PostgresMetricsProtocol
28
30
 
@@ -100,6 +102,35 @@ def attach_metrics(engine: AsyncEngine, metrics: PostgresMetricsProtocol) -> Non
100
102
  event.listen(engine.sync_engine, "handle_error", on_error)
101
103
 
102
104
 
105
+ def attach_search_path(engine: AsyncEngine, search_path: str) -> None:
106
+ """Apply ``search_path`` to every transaction the engine begins.
107
+
108
+ Registers a ``begin`` listener that issues ``set_config('search_path', …, true)`` —
109
+ the function form of ``SET LOCAL``, with the value as a bind parameter — as the first
110
+ statement of each transaction, so the setting lives exactly as long as the transaction
111
+ does. That is the one scope a transaction-mode pooler such as PgBouncer honours: a
112
+ startup parameter is rejected or dropped before it reaches PostgreSQL, and a plain
113
+ ``SET`` on a server connection leaks to whichever client is handed it next.
114
+
115
+ Under the asyncpg adapter ``BEGIN`` is sent lazily with the first statement, so the
116
+ ``set_config`` call lands inside the transaction rather than ahead of it. Every
117
+ transaction is covered — a session's autobegin, ``session.begin()``, a raw
118
+ ``engine.connect()``, the one that follows a ``commit()`` — but a statement run with
119
+ ``isolation_level="AUTOCOMMIT"`` begins none and runs with the server's default.
120
+
121
+ Args:
122
+ engine: SQLAlchemy ``AsyncEngine`` to attach the listener to.
123
+ search_path: Value for ``search_path`` — a schema, or a comma-separated list such
124
+ as ``"tenant_7, public"``.
125
+ """
126
+ statement = text("SELECT set_config('search_path', :search_path, true)")
127
+
128
+ def on_begin(conn: Connection) -> None:
129
+ conn.execute(statement, {"search_path": search_path})
130
+
131
+ event.listen(engine.sync_engine, "begin", on_begin)
132
+
133
+
103
134
  class AsyncSessionManager(Generic[SessionT]):
104
135
  """Manages async database sessions with configurable connection pooling.
105
136
 
@@ -124,6 +155,7 @@ class AsyncSessionManager(Generic[SessionT]):
124
155
  metrics: PostgresMetricsProtocol | None = None,
125
156
  on_engine_created: Callable[[AsyncEngine], None] | None = None,
126
157
  dispose_timeout: float = DEFAULT_DISPOSE_TIMEOUT_SECONDS,
158
+ search_path: str | None = None,
127
159
  **kwargs: object,
128
160
  ) -> None:
129
161
  """Initialize session manager with direct configuration.
@@ -145,6 +177,10 @@ class AsyncSessionManager(Generic[SessionT]):
145
177
  dispose_timeout: Maximum seconds to wait for engine disposal in :meth:`aclose`
146
178
  (default: 30.0). Lower this in tests or short-lived environments; raise it
147
179
  if you have long-running transactions that need more time to settle.
180
+ search_path: PostgreSQL ``search_path`` applied to every transaction with
181
+ ``SET LOCAL`` semantics, which is what survives a transaction-mode pooler
182
+ (default: None — nothing is sent, the server default applies). See
183
+ :func:`attach_search_path`.
148
184
  **kwargs: Additional keyword arguments for ``create_async_engine``.
149
185
  """
150
186
  self._closed = False
@@ -174,6 +210,9 @@ class AsyncSessionManager(Generic[SessionT]):
174
210
  if metrics:
175
211
  attach_metrics(self._engine, metrics)
176
212
 
213
+ if search_path is not None:
214
+ attach_search_path(self._engine, search_path)
215
+
177
216
  if on_engine_created is not None:
178
217
  on_engine_created(self._engine)
179
218
 
@@ -1 +0,0 @@
1
- __version__ = "0.2.1"