1313load_dotenv ()
1414
1515
16+ class _ResultProxy :
17+ """Lightweight wrapper that eagerly fetches results from a
18+ SQLAlchemy CursorResult so they survive connection closure.
19+ Provides fetchone()/fetchall() with dict-like row access."""
20+
21+ def __init__ (self , cursor_result ):
22+ try :
23+ # Use .mappings() so rows behave like dicts
24+ self ._rows = list (cursor_result .mappings ())
25+ except Exception :
26+ # For non-SELECT statements (INSERT/UPDATE/DELETE)
27+ # there are no rows to fetch
28+ self ._rows = []
29+ self ._index = 0
30+
31+ def fetchone (self ):
32+ if self ._index < len (self ._rows ):
33+ row = self ._rows [self ._index ]
34+ self ._index += 1
35+ return row
36+ return None
37+
38+ def fetchall (self ):
39+ remaining = self ._rows [self ._index :]
40+ self ._index = len (self ._rows )
41+ return remaining
42+
43+
1644class PolicyEngineDatabase :
1745 """
1846 A wrapper around the database connection.
@@ -70,6 +98,22 @@ def _close_pool(self):
7098 except :
7199 pass
72100
101+ def _execute_remote (self , query_args ):
102+ """Execute a query against the remote database using
103+ SQLAlchemy v2 connection-based execution."""
104+ main_query = query_args [0 ]
105+ params = query_args [1 ] if len (query_args ) > 1 else None
106+ with self .pool .connect () as conn :
107+ if params is not None :
108+ result = conn .exec_driver_sql (main_query , params )
109+ else :
110+ result = conn .exec_driver_sql (main_query )
111+ conn .commit ()
112+ # Return a lightweight wrapper that holds
113+ # the fetched results so they survive the
114+ # connection context closing
115+ return _ResultProxy (result )
116+
73117 def query (self , * query ):
74118 if self .local :
75119 with sqlite3 .connect (self .db_url ) as conn :
@@ -89,7 +133,7 @@ def dict_factory(cursor, row):
89133 main_query = main_query .replace ("?" , "%s" )
90134 query [0 ] = main_query
91135 try :
92- return self .pool . execute ( * query )
136+ return self ._execute_remote ( query )
93137 # Except InterfaceError and OperationalError, which are thrown when the connection is lost.
94138 except (
95139 sqlalchemy .exc .InterfaceError ,
@@ -98,7 +142,7 @@ def dict_factory(cursor, row):
98142 try :
99143 self ._close_pool ()
100144 self ._create_pool ()
101- return self .pool . execute ( * query )
145+ return self ._execute_remote ( query )
102146 except Exception as e :
103147 raise e
104148
0 commit comments