diff --git a/src/codegen/client.rs b/src/codegen/client.rs index 03de649d..00f92364 100644 --- a/src/codegen/client.rs +++ b/src/codegen/client.rs @@ -27,7 +27,7 @@ pub(crate) fn gen_lib( mod type_traits; mod utils; - pub(crate) use utils::slice_iter; + pub(crate) use utils::{slice_iter, slice_iter_typed}; pub use array_iterator::ArrayIterator; pub use domain::{Domain, DomainArray}; @@ -128,6 +128,12 @@ pub fn core_utils() -> proc_macro2::TokenStream { ) -> impl ExactSizeIterator + 'a { s.iter().map(|s| *s as _) } + + pub fn slice_iter_typed<'a>( + s: &'a [(&'a (dyn ToSql + Sync), Type)], + ) -> impl ExactSizeIterator + 'a { + s.iter().map(|(s, t)| (*s as _, t.clone())) + } } } @@ -506,6 +512,7 @@ pub fn sync() -> proc_macro2::TokenStream { client: &mut C, query: &str, params: &[&(dyn ToSql + Sync)], + typed_params: &[(&(dyn ToSql + Sync), postgres_types::Type)], cached: Option<&Statement>, ) -> Result { if let Some(cached) = cached { @@ -514,7 +521,7 @@ pub fn sync() -> proc_macro2::TokenStream { let cached = client.prepare(query)?; client.query_one(&cached, params) } else { - client.query_one(query, params) + client.query_typed_one(query, typed_params) } } @@ -522,6 +529,7 @@ pub fn sync() -> proc_macro2::TokenStream { client: &mut C, query: &str, params: &[&(dyn ToSql + Sync)], + typed_params: &[(&(dyn ToSql + Sync), postgres_types::Type)], cached: Option<&Statement>, ) -> Result, Error> { if let Some(cached) = cached { @@ -530,20 +538,23 @@ pub fn sync() -> proc_macro2::TokenStream { let cached = client.prepare(query)?; client.query_opt(&cached, params) } else { - client.query_opt(query, params) + client.query_typed_opt(query, typed_params) } } - pub fn raw<'a, C: GenericClient, P, I>( + pub fn raw<'a, C: GenericClient, P, I, Ty>( client: &'a mut C, query: &str, params: I, + typed_params: Ty, cached: Option<&Statement>, ) -> Result, Error> where P: BorrowToSql, I: IntoIterator, I::IntoIter: ExactSizeIterator, + Ty: IntoIterator, + Ty::IntoIter: ExactSizeIterator, { if let Some(cached) = cached { client.query_raw(cached, params) @@ -551,7 +562,7 @@ pub fn sync() -> proc_macro2::TokenStream { let cached = client.prepare(query)?; client.query_raw(&cached, params) } else { - client.query_raw(query, params) + client.query_typed_raw(query, typed_params) } } } @@ -580,6 +591,7 @@ pub fn async_() -> proc_macro2::TokenStream { client: &C, query: &str, params: &[&(dyn ToSql + Sync)], + typed_params: &[(&(dyn ToSql + Sync), postgres_types::Type)], cached: Option<&Statement>, ) -> Result { if let Some(cached) = cached { @@ -588,7 +600,7 @@ pub fn async_() -> proc_macro2::TokenStream { let cached = client.prepare(query).await?; client.query_one(&cached, params).await } else { - client.query_one(query, params).await + client.query_typed_one(query, typed_params).await } } @@ -596,6 +608,7 @@ pub fn async_() -> proc_macro2::TokenStream { client: &C, query: &str, params: &[&(dyn ToSql + Sync)], + typed_params: &[(&(dyn ToSql + Sync), postgres_types::Type)], cached: Option<&Statement>, ) -> Result, Error> { if let Some(cached) = cached { @@ -604,19 +617,18 @@ pub fn async_() -> proc_macro2::TokenStream { let cached = client.prepare(query).await?; client.query_opt(&cached, params).await } else { - client.query_opt(query, params).await + client.query_typed_opt(query, typed_params).await } } - pub async fn raw( + pub async fn raw + Sync + Send>( client: &C, query: &str, params: I, + typed_params: &[(&(dyn ToSql + Sync), postgres_types::Type)], cached: Option<&Statement>, ) -> Result where - P: BorrowToSql, - I: IntoIterator + Sync + Send, I::IntoIter: ExactSizeIterator, { if let Some(cached) = cached { @@ -625,7 +637,7 @@ pub fn async_() -> proc_macro2::TokenStream { let cached = client.prepare(query).await?; client.query_raw(&cached, params).await } else { - client.query_raw(query, params).await + client.query_typed_raw(query, typed_params).await } } } @@ -651,10 +663,18 @@ pub fn sync_generic_client() -> proc_macro2::TokenStream { where T: ?Sized + ToStatement; + fn execute_typed(&mut self, query: &str, typed_params: &[(&(dyn ToSql + Sync), postgres_types::Type)]) -> Result; + fn query_one(&mut self, statement: &T, params: &[&(dyn ToSql + Sync)]) -> Result where T: ?Sized + ToStatement; + fn query_typed_one( + &mut self, + query: &str, + typed_params: &[(&(dyn ToSql + Sync), postgres_types::Type)], + ) -> Result; + fn query_opt( &mut self, statement: &T, @@ -663,6 +683,12 @@ pub fn sync_generic_client() -> proc_macro2::TokenStream { where T: ?Sized + ToStatement; + fn query_typed_opt( + &mut self, + query: &str, + typed_params: &[(&(dyn ToSql + Sync), postgres_types::Type)], + ) -> Result, Error>; + fn query(&mut self, query: &T, params: &[&(dyn ToSql + Sync)]) -> Result, Error> where T: ?Sized + ToStatement; @@ -673,6 +699,12 @@ pub fn sync_generic_client() -> proc_macro2::TokenStream { P: BorrowToSql, I: IntoIterator, I::IntoIter: ExactSizeIterator; + + fn query_typed_raw( + &mut self, + query: &str, + typed_params: &[(&(dyn ToSql + Sync), postgres_types::Type)] + ) -> Result, Error>; } impl GenericClient for Transaction<'_> { @@ -687,6 +719,11 @@ pub fn sync_generic_client() -> proc_macro2::TokenStream { Transaction::execute(self, query, params) } + fn execute_typed(&mut self, query: &str, typed_params: &[(&(dyn ToSql + Sync), postgres_types::Type)]) -> Result + { + Transaction::execute_typed(self, query, typed_params) + } + fn query_one(&mut self, statement: &T, params: &[&(dyn ToSql + Sync)]) -> Result where T: ?Sized + ToStatement, @@ -694,6 +731,14 @@ pub fn sync_generic_client() -> proc_macro2::TokenStream { Transaction::query_one(self, statement, params) } + fn query_typed_one( + &mut self, + query: &str, + typed_params: &[(&(dyn ToSql + Sync), postgres_types::Type)], + ) -> Result { + Transaction::query_typed_one(self, query, typed_params) + } + fn query_opt( &mut self, statement: &T, @@ -705,6 +750,14 @@ pub fn sync_generic_client() -> proc_macro2::TokenStream { Transaction::query_opt(self, statement, params) } + fn query_typed_opt( + &mut self, + query: &str, + typed_params: &[(&(dyn ToSql + Sync), postgres_types::Type)], + ) -> Result, Error> { + Transaction::query_typed_opt(self, query, typed_params) + } + fn query(&mut self, query: &T, params: &[&(dyn ToSql + Sync)]) -> Result, Error> where T: ?Sized + ToStatement, @@ -721,6 +774,14 @@ pub fn sync_generic_client() -> proc_macro2::TokenStream { { Transaction::query_raw(self, statement, params) } + + fn query_typed_raw( + &mut self, + query: &str, + typed_params: &[(&(dyn ToSql + Sync), postgres_types::Type)] + ) -> Result, Error> { + Transaction::query_typed_raw(self, query, crate::slice_iter_typed(typed_params)) + } } impl GenericClient for Client { @@ -735,6 +796,11 @@ pub fn sync_generic_client() -> proc_macro2::TokenStream { Client::execute(self, query, params) } + fn execute_typed(&mut self, query: &str, typed_params: &[(&(dyn ToSql + Sync), postgres_types::Type)]) -> Result + { + Client::execute_typed(self, query, typed_params) + } + fn query_one(&mut self, statement: &T, params: &[&(dyn ToSql + Sync)]) -> Result where T: ?Sized + ToStatement, @@ -742,6 +808,14 @@ pub fn sync_generic_client() -> proc_macro2::TokenStream { Client::query_one(self, statement, params) } + fn query_typed_one( + &mut self, + query: &str, + typed_params: &[(&(dyn ToSql + Sync), postgres_types::Type)], + ) -> Result { + Client::query_typed_one(self, query, typed_params) + } + fn query_opt( &mut self, statement: &T, @@ -753,6 +827,14 @@ pub fn sync_generic_client() -> proc_macro2::TokenStream { Client::query_opt(self, statement, params) } + fn query_typed_opt( + &mut self, + query: &str, + typed_params: &[(&(dyn ToSql + Sync), postgres_types::Type)], + ) -> Result, Error> { + Client::query_typed_opt(self, query, typed_params) + } + fn query(&mut self, query: &T, params: &[&(dyn ToSql + Sync)]) -> Result, Error> where T: ?Sized + ToStatement, @@ -769,6 +851,14 @@ pub fn sync_generic_client() -> proc_macro2::TokenStream { { Client::query_raw(self, statement, params) } + + fn query_typed_raw( + &mut self, + query: &str, + typed_params: &[(&(dyn ToSql + Sync), postgres_types::Type)] + ) -> Result, Error> { + Client::query_typed_raw(self, query, crate::slice_iter_typed(typed_params)) + } } } } @@ -801,6 +891,12 @@ pub fn async_generic_client() -> proc_macro2::TokenStream { where T: ?Sized + ToStatement + Sync + Send; + fn execute_typed( + &self, + query: &str, + typed_params: &[(&(dyn ToSql + Sync), postgres_types::Type)], + ) -> impl Future> + Send; + fn query_one( &self, statement: &T, @@ -809,6 +905,12 @@ pub fn async_generic_client() -> proc_macro2::TokenStream { where T: ?Sized + ToStatement + Sync + Send; + fn query_typed_one( + &self, + query: &str, + typed_params: &[(&(dyn ToSql + Sync), postgres_types::Type)], + ) -> impl Future> + Send; + fn query_opt( &self, statement: &T, @@ -817,6 +919,12 @@ pub fn async_generic_client() -> proc_macro2::TokenStream { where T: ?Sized + ToStatement + Sync + Send; + fn query_typed_opt( + &self, + query: &str, + typed_params: &[(&(dyn ToSql + Sync), postgres_types::Type)], + ) -> impl Future, Error>> + Send; + fn query( &self, query: &T, @@ -835,6 +943,12 @@ pub fn async_generic_client() -> proc_macro2::TokenStream { I: IntoIterator + Sync + Send, I::IntoIter: ExactSizeIterator, I::Item: BorrowToSql; + + fn query_typed_raw( + &self, + query: &str, + typed_params: &[(&(dyn ToSql + Sync), postgres_types::Type)], + ) -> impl Future> + Send; } impl GenericClient for Transaction<'_> { @@ -853,6 +967,15 @@ pub fn async_generic_client() -> proc_macro2::TokenStream { Transaction::execute(self, query, params).await } + async fn execute_typed( + &self, + query: &str, + typed_params: &[(&(dyn ToSql + Sync), postgres_types::Type)], + ) -> Result + { + Transaction::execute_typed(self, query, typed_params).await + } + async fn query_one( &self, statement: &T, @@ -864,6 +987,14 @@ pub fn async_generic_client() -> proc_macro2::TokenStream { Transaction::query_one(self, statement, params).await } + async fn query_typed_one( + &self, + query: &str, + typed_params: &[(&(dyn ToSql + Sync), postgres_types::Type)], + ) -> Result { + Transaction::query_typed_one(self, query, typed_params).await + } + async fn query_opt( &self, statement: &T, @@ -875,6 +1006,14 @@ pub fn async_generic_client() -> proc_macro2::TokenStream { Transaction::query_opt(self, statement, params).await } + async fn query_typed_opt( + &self, + query: &str, + typed_params: &[(&(dyn ToSql + Sync), postgres_types::Type)], + ) -> Result, Error> { + Transaction::query_typed_opt(self, query, typed_params).await + } + async fn query( &self, query: &T, @@ -895,6 +1034,14 @@ pub fn async_generic_client() -> proc_macro2::TokenStream { { Transaction::query_raw(self, statement, params).await } + + async fn query_typed_raw( + &self, + query: &str, + typed_params: &[(&(dyn ToSql + Sync), postgres_types::Type)] + ) -> Result { + Transaction::query_typed_raw(self, query, crate::slice_iter_typed(typed_params)).await + } } impl GenericClient for Client { @@ -913,6 +1060,15 @@ pub fn async_generic_client() -> proc_macro2::TokenStream { Client::execute(self, query, params).await } + async fn execute_typed( + &self, + query: &str, + typed_params: &[(&(dyn ToSql + Sync), postgres_types::Type)], + ) -> Result + { + Client::execute_typed(self, query, typed_params).await + } + async fn query_one( &self, statement: &T, @@ -924,6 +1080,14 @@ pub fn async_generic_client() -> proc_macro2::TokenStream { Client::query_one(self, statement, params).await } + async fn query_typed_one( + &self, + query: &str, + typed_params: &[(&(dyn ToSql + Sync), postgres_types::Type)], + ) -> Result { + Client::query_typed_one(self, query, typed_params).await + } + async fn query_opt( &self, statement: &T, @@ -935,6 +1099,14 @@ pub fn async_generic_client() -> proc_macro2::TokenStream { Client::query_opt(self, statement, params).await } + async fn query_typed_opt( + &self, + query: &str, + typed_params: &[(&(dyn ToSql + Sync), postgres_types::Type)], + ) -> Result, Error> { + Client::query_typed_opt(self, query, typed_params).await + } + async fn query( &self, query: &T, @@ -955,6 +1127,14 @@ pub fn async_generic_client() -> proc_macro2::TokenStream { { Client::query_raw(self, statement, params).await } + + async fn query_typed_raw( + &self, + query: &str, + typed_params: &[(&(dyn ToSql + Sync), postgres_types::Type)] + ) -> Result { + Client::query_typed_raw(self, query, crate::slice_iter_typed(typed_params)).await + } } } } @@ -991,6 +1171,15 @@ pub fn async_deadpool() -> proc_macro2::TokenStream { PgClient::execute(self, query, params).await } + async fn execute_typed( + &self, + query: &str, + typed_params: &[(&(dyn tokio_postgres::types::ToSql + Sync), postgres_types::Type)], + ) -> Result + { + PgClient::execute_typed(self, query, typed_params).await + } + async fn query_one( &self, statement: &T, @@ -1002,6 +1191,14 @@ pub fn async_deadpool() -> proc_macro2::TokenStream { PgClient::query_one(self, statement, params).await } + async fn query_typed_one( + &self, + query: &str, + typed_params: &[(&(dyn tokio_postgres::types::ToSql + Sync), postgres_types::Type)], + ) -> Result { + PgClient::query_typed_one(self, query, typed_params).await + } + async fn query_opt( &self, statement: &T, @@ -1013,6 +1210,14 @@ pub fn async_deadpool() -> proc_macro2::TokenStream { PgClient::query_opt(self, statement, params).await } + async fn query_typed_opt( + &self, + query: &str, + typed_params: &[(&(dyn tokio_postgres::types::ToSql + Sync), postgres_types::Type)], + ) -> Result, Error> { + PgClient::query_typed_opt(self, query, typed_params).await + } + async fn query( &self, query: &T, @@ -1033,6 +1238,14 @@ pub fn async_deadpool() -> proc_macro2::TokenStream { { PgClient::query_raw(self, statement, params).await } + + async fn query_typed_raw( + &self, + query: &str, + typed_params: &[(&(dyn tokio_postgres::types::ToSql + Sync), postgres_types::Type)] + ) -> Result { + PgClient::query_typed_raw(self, query, crate::slice_iter_typed(typed_params)).await + } } impl GenericClient for DeadpoolTransaction<'_> { @@ -1055,6 +1268,15 @@ pub fn async_deadpool() -> proc_macro2::TokenStream { PgTransaction::execute(self, query, params).await } + async fn execute_typed( + &self, + query: &str, + typed_params: &[(&(dyn tokio_postgres::types::ToSql + Sync), postgres_types::Type)], + ) -> Result + { + PgTransaction::execute_typed(self, query, typed_params).await + } + async fn query_one( &self, statement: &T, @@ -1066,6 +1288,14 @@ pub fn async_deadpool() -> proc_macro2::TokenStream { PgTransaction::query_one(self, statement, params).await } + async fn query_typed_one( + &self, + query: &str, + typed_params: &[(&(dyn tokio_postgres::types::ToSql + Sync), postgres_types::Type)], + ) -> Result { + PgTransaction::query_typed_one(self, query, typed_params).await + } + async fn query_opt( &self, statement: &T, @@ -1077,6 +1307,14 @@ pub fn async_deadpool() -> proc_macro2::TokenStream { PgTransaction::query_opt(self, statement, params).await } + async fn query_typed_opt( + &self, + query: &str, + typed_params: &[(&(dyn tokio_postgres::types::ToSql + Sync), postgres_types::Type)], + ) -> Result, Error> { + PgTransaction::query_typed_opt(self, query, typed_params).await + } + async fn query( &self, query: &T, @@ -1097,6 +1335,14 @@ pub fn async_deadpool() -> proc_macro2::TokenStream { { PgTransaction::query_raw(self, statement, params).await } + + async fn query_typed_raw( + &self, + query: &str, + typed_params: &[(&(dyn tokio_postgres::types::ToSql + Sync), postgres_types::Type)] + ) -> Result { + PgTransaction::query_typed_raw(self, query, crate::slice_iter_typed(typed_params)).await + } } } } diff --git a/src/codegen/queries.rs b/src/codegen/queries.rs index f9ebb580..f706d45e 100644 --- a/src/codegen/queries.rs +++ b/src/codegen/queries.rs @@ -267,6 +267,7 @@ fn gen_row_query(row: &PreparedItem, ctx: &GenCtx) -> proc_macro2::TokenStream { pub struct #name_ident<'c, 'a, 's, C: GenericClient, T, const N: usize> { client: &'c #client_mut C, params: [&'a (dyn postgres_types::ToSql + Sync); N], + typed_params: [(&'a (dyn postgres_types::ToSql + Sync), postgres_types::Type); N], query: &'static str, cached: Option<&'s #backend::Statement>, extractor: fn(&#backend::Row) -> Result<#row_struct, #backend::Error>, @@ -281,6 +282,7 @@ fn gen_row_query(row: &PreparedItem, ctx: &GenCtx) -> proc_macro2::TokenStream { #name_ident { client: self.client, params: self.params, + typed_params: self.typed_params, query: self.query, cached: self.cached, extractor: self.extractor, @@ -289,7 +291,7 @@ fn gen_row_query(row: &PreparedItem, ctx: &GenCtx) -> proc_macro2::TokenStream { } pub #fn_async fn one(self) -> Result { - let row = #client::one(self.client, self.query, &self.params, self.cached)#fn_await?; + let row = #client::one(self.client, self.query, &self.params, &self.typed_params, self.cached)#fn_await?; Ok((self.mapper)((self.extractor)(&row)?)) } @@ -298,7 +300,7 @@ fn gen_row_query(row: &PreparedItem, ctx: &GenCtx) -> proc_macro2::TokenStream { } pub #fn_async fn opt(self) -> Result, #backend::Error> { - let opt_row = #client::opt(self.client, self.query, &self.params, self.cached)#fn_await?; + let opt_row = #client::opt(self.client, self.query, &self.params, &self.typed_params, self.cached)#fn_await?; Ok(opt_row .map(|row| { let extracted = (self.extractor)(&row)?; @@ -310,7 +312,7 @@ fn gen_row_query(row: &PreparedItem, ctx: &GenCtx) -> proc_macro2::TokenStream { pub #fn_async fn iter( self, ) -> Result> + 'c, #backend::Error> { - let stream = #client::raw(self.client, self.query, crate::slice_iter(&self.params), self.cached)#fn_await?; + let stream = #client::raw(self.client, self.query, crate::slice_iter(&self.params), &self.typed_params, self.cached)#fn_await?; let mapped = stream #raw_pre .map(move |res| @@ -373,6 +375,26 @@ fn gen_query_fn( }) .collect(); + let params_ty_val: Vec<_> = order + .iter() + .map(|idx| { + let pg_ty = param_field[*idx].ty.pg_ty(); + let ty_str = match pg_ty.clone() { + postgres_types::Type::UUID => "postgres_types::Type::UUID".to_string(), + postgres_types::Type::TEXT => "postgres_types::Type::TEXT".to_string(), + postgres_types::Type::VARCHAR => "postgres_types::Type::VARCHAR".to_string(), + postgres_types::Type::INT4 => "postgres_types::Type::INT4".to_string(), + postgres_types::Type::TIMESTAMPTZ => { + "postgres_types::Type::TIMESTAMPTZ".to_string() + } + pg_ty => unimplemented!("{}", pg_ty), + }; + syn::parse_str::(&ty_str).unwrap() + // param_field[*idx]. + // syn::parse_str::(¶m_field[*idx].param_ergo_ty(traits, ctx)).unwrap() + }) + .collect(); + let params_name: Vec<_> = order .iter() .map(|idx| format_ident!("{}", param_field[*idx].ident.rs)) @@ -446,6 +468,7 @@ fn gen_query_fn( #row_name_query_ident { client, params: [#(#params_name,)*], + typed_params: [#((#params_name, #params_ty_val),)*], query: self.0, cached: self.1.as_ref(), extractor: #extractor, @@ -467,6 +490,7 @@ fn gen_query_fn( #row_name_query_ident { client, params: [#(#params_name,)*], + typed_params: [#((#params_name, #params_ty_val),)*], query: self.0, cached: self.1.as_ref(), extractor: |row| Ok(row.try_get(0)?), @@ -490,7 +514,7 @@ fn gen_query_fn( client: &'c #client_mut C, #(#params_name: &'a #params_ty,)* ) -> Result { - client.execute(self.0, &[#(#params_wrap,)*])#fn_await + client.execute_typed(self.0, &[#((#params_wrap, #params_ty_val),)*])#fn_await } } };