@@ -1006,45 +1006,45 @@ async def create_uta_connection_pool(
10061006 try :
10071007 async with pool .connection () as conn :
10081008 await UtaRepository (conn ).create_genomic_table ()
1009- # catch all exceptions, this is probably a critical error, it's important to
1009+ # catch all exceptions -- this is probably a critical error, it's good to
10101010 # close the pool first
10111011 except :
10121012 await pool .close ()
10131013 raise
10141014 return pool
10151015
10161016
1017+ class ClosedUtaConnectionError (Exception ):
1018+ """Raise for attempts to access a UTA connection when it's been closed/deleted"""
1019+
1020+
10171021class UtaDatabase :
10181022 """Provide pooled access to connection-scoped UTA repositories.
10191023
10201024 This class owns or borrows an async psycopg connection pool and yields
10211025 ``UtaRepository`` instances bound to checked-out connections.
10221026 """
10231027
1024- def __init__ (self , pool : AsyncConnectionPool | None = None ) -> None :
1028+ def __init__ (self , pool : AsyncConnectionPool ) -> None :
10251029 """Initialize access wrapper.
10261030
10271031 :param pool: Existing async connection pool to use. If omitted, a default
10281032 pool is created lazily on first use.
10291033 """
10301034 self ._connection_pool = pool
10311035
1032- async def open (self ) -> None :
1033- """Initialize connection"""
1034- if self ._connection_pool is None :
1035- # TODO not sure i like this here
1036- self ._connection_pool = await create_uta_connection_pool ()
1037-
10381036 @asynccontextmanager
10391037 async def repository (self ) -> AsyncIterator [UtaRepository ]:
10401038 """Yield a ``UtaRepository`` backed by a pooled connection.
10411039
10421040 If no pool has been provided yet, a default one is created on first use.
10431041
10441042 :yield: Repository bound to an active pooled connection
1043+ :raise ClosedUtaConnectionError: if connection associated w/ this instance is closed
1044+ or nullified
10451045 """
1046- await self .open ()
1047-
1046+ if self ._connection_pool is None :
1047+ raise ClosedUtaConnectionError
10481048 async with self ._connection_pool .connection () as conn :
10491049 yield UtaRepository (conn )
10501050
@@ -1056,3 +1056,53 @@ async def close(self) -> None:
10561056
10571057 await self ._connection_pool .close ()
10581058 self ._connection_pool = None
1059+
1060+
1061+ class LazyUtaDatabase (UtaDatabase ):
1062+ """UTA access wrapper with lazy connection pool initialization.
1063+
1064+ This variant defers creation of the underlying connection pool until first use.
1065+ It exists primarily for backward compatibility with earlier APIs that did not
1066+ require explicit pool construction.
1067+
1068+ Because configuration is resolved at runtime (via environment variables or
1069+ defaults), this class can introduce implicit behavior and is not recommended
1070+ for applications that require explicit control over database connections.
1071+ """
1072+
1073+ def __init__ (self , pool : AsyncConnectionPool | None = None ) -> None :
1074+ """Initialize the lazy access wrapper.
1075+
1076+ :param pool: Optional existing async connection pool. If not provided,
1077+ a pool will be created on first use using environment variables
1078+ or default configuration.
1079+ """
1080+ if pool is None :
1081+ _logger .info (
1082+ "LazyUtaDatabase initialized without a connection pool; "
1083+ "a pool will be created on first use from environment/default settings."
1084+ )
1085+ self ._connection_pool = pool
1086+
1087+ async def open (self ) -> None :
1088+ """Ensure that a connection pool has been initialized.
1089+
1090+ If no pool is currently set, one is created using default configuration.
1091+ """
1092+ if self ._connection_pool is None :
1093+ _logger .debug ("Creating UTA connection pool lazily on first use" )
1094+ self ._connection_pool = await create_uta_connection_pool ()
1095+
1096+ @asynccontextmanager
1097+ async def repository (self ) -> AsyncIterator [UtaRepository ]:
1098+ """Yield a repository backed by a pooled UTA connection.
1099+
1100+ This method ensures that a connection pool exists, creating one if
1101+ necessary, and then yields a ``UtaRepository`` bound to a checked-out
1102+ connection.
1103+
1104+ :yield: Repository bound to an active pooled connection
1105+ """
1106+ await self .open ()
1107+ async with self ._connection_pool .connection () as conn :
1108+ yield UtaRepository (conn )
0 commit comments