11use std:: { env, time:: Duration } ;
2+ use std:: future:: Future ;
23
34use bb8:: { Pool , RunError } ;
45use bb8_postgres:: PostgresConnectionManager ;
@@ -11,16 +12,16 @@ use tokio::{task, time::timeout};
1112use tokio_postgres:: {
1213 binary_copy:: BinaryCopyInWriter ,
1314 config:: SslMode ,
14- types:: { ToSql , Type as PgType } ,
1515 Config , CopyInSink , Error as PgError , Row , Statement , ToStatement ,
1616 Transaction as PgTransaction ,
1717} ;
18+ pub use tokio_postgres:: types:: { ToSql , Type as PgType } ;
1819use tracing:: { debug, error} ;
19-
2020use crate :: database:: postgres:: {
2121 generate:: generate_event_table_columns_names_sql, sql_type_wrapper:: EthereumSqlTypeWrapper ,
2222} ;
2323
24+
2425pub fn connection_string ( ) -> Result < String , env:: VarError > {
2526 dotenv ( ) . ok ( ) ;
2627 let connection = env:: var ( "DATABASE_URL" ) ?;
@@ -57,8 +58,25 @@ pub enum PostgresError {
5758 ConnectionPoolError ( #[ from] RunError < tokio_postgres:: Error > ) ,
5859}
5960
60- pub struct PostgresTransaction {
61- pub transaction : PgTransaction < ' static > ,
61+ pub struct PostgresTransaction < ' a > {
62+ pub transaction : PgTransaction < ' a > ,
63+ }
64+ impl < ' a > PostgresTransaction < ' a > {
65+ pub async fn execute (
66+ & mut self ,
67+ query : & str ,
68+ params : & [ & ( dyn ToSql + Sync ) ] ,
69+ ) -> Result < u64 , PostgresError > {
70+ self . transaction . execute ( query, params) . await . map_err ( PostgresError :: PgError )
71+ }
72+
73+ pub async fn commit ( self ) -> Result < ( ) , PostgresError > {
74+ self . transaction . commit ( ) . await . map_err ( PostgresError :: PgError )
75+ }
76+
77+ pub async fn rollback ( self ) -> Result < ( ) , PostgresError > {
78+ self . transaction . rollback ( ) . await . map_err ( PostgresError :: PgError )
79+ }
6280}
6381
6482#[ derive( thiserror:: Error , Debug ) ]
@@ -167,14 +185,27 @@ impl PostgresClient {
167185 conn. prepare_typed ( query, parameter_types) . await . map_err ( PostgresError :: PgError )
168186 }
169187
170- pub async fn transaction ( & self ) -> Result < PostgresTransaction , PostgresError > {
171- let mut conn = self . pool . get ( ) . await ?;
188+ pub async fn with_transaction < F , Fut , T , Q > (
189+ & self ,
190+ query : & Q ,
191+ params : & [ & ( dyn ToSql + Sync ) ] ,
192+ f : F ,
193+ ) -> Result < T , PostgresError >
194+ where
195+ F : FnOnce ( u64 ) -> Fut + Send ,
196+ Fut : Future < Output = Result < T , PostgresError > > + Send ,
197+ Q : ?Sized + ToStatement ,
198+ {
199+ let mut conn = self . pool . get ( ) . await . map_err ( PostgresError :: ConnectionPoolError ) ?;
172200 let transaction = conn. transaction ( ) . await . map_err ( PostgresError :: PgError ) ?;
173201
174- // Wrap the transaction in a static lifetime
175- let boxed_transaction: Box < PgTransaction < ' static > > =
176- unsafe { std:: mem:: transmute ( Box :: new ( transaction) ) } ;
177- Ok ( PostgresTransaction { transaction : * boxed_transaction } )
202+ let count = transaction. execute ( query, params) . await . map_err ( PostgresError :: PgError ) ?;
203+
204+ let result = f ( count) . await ?;
205+
206+ transaction. commit ( ) . await . map_err ( PostgresError :: PgError ) ?;
207+
208+ Ok ( result)
178209 }
179210
180211 pub async fn query < T > (
@@ -343,4 +374,4 @@ impl PostgresClient {
343374 . map_err ( |e| e. to_string ( ) )
344375 }
345376 }
346- }
377+ }
0 commit comments