Coverage for src/lumen/db/pool.py: 63%
35 statements
« prev ^ index » next coverage.py v7.16.0, created at 2026-08-31 18:46 +0000
« prev ^ index » next coverage.py v7.16.0, created at 2026-08-31 18:46 +0000
1"""
2This file manages the PostgreSQL connection pool using asyncpg.
3It handles pool initialization, lifecycle management, and registers JSONB serialization helpers.
4"""
6from __future__ import annotations
8import asyncio
9import json
11import asyncpg
13from lumen.config import DatabaseSettings
15_pool: asyncpg.Pool[asyncpg.Record] | None = None
18async def _init_connection(conn: asyncpg.Connection[asyncpg.Record]) -> None:
19 """
20 handle jsonb decoder/encoder for asyncpg connection
21 """
22 await conn.set_type_codec(
23 "jsonb",
24 encoder=json.dumps,
25 decoder=json.loads,
26 schema="pg_catalog",
27 )
30async def init_pool(settings: DatabaseSettings | None = None) -> asyncpg.Pool[asyncpg.Record]:
31 global _pool
32 try:
33 current_loop = asyncio.get_running_loop()
34 except RuntimeError:
35 current_loop = None
37 if _pool is not None:
38 try:
39 pool_loop = getattr(_pool, "_loop", None)
40 if not getattr(_pool, "_closed", True) and pool_loop == current_loop:
41 return _pool
42 await _pool.close()
43 except Exception:
44 pass
45 _pool = None
47 if settings is None:
48 from lumen.config import get_settings
50 settings = get_settings().db
52 _pool = await asyncpg.create_pool(
53 dsn=settings.url,
54 min_size=settings.min_connections,
55 max_size=settings.max_connections,
56 init=_init_connection,
57 )
58 return _pool
61async def close_pool() -> None:
62 global _pool
63 if _pool is not None:
64 await _pool.close()
65 _pool = None
68def get_pool() -> asyncpg.Pool[asyncpg.Record]:
69 if _pool is None:
70 raise RuntimeError("Database pool has not been initialised")
71 return _pool