diff --git a/Cargo.toml b/Cargo.toml index 3aac364..9cdf36d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,7 +20,7 @@ license = "MIT OR Apache-2.0" members = [".", "sqlb-macros"] [dependencies] -sqlx = { version = "0.7", features = [ "runtime-tokio-rustls", "postgres", "time", "uuid" ] } +sqlx = { version = "0.8.0", features = [ "runtime-tokio-rustls", "postgres", "time", "uuid" ] } sqlb-macros = { version="0.4.0", path = "sqlb-macros" } async-trait = "0.1" time = "0.3.20" @@ -33,9 +33,9 @@ rust_decimal = { version = "1.34", optional = true } default = [] chrono-support = ["chrono"] json = ["serde_json"] -decimal = ["rust_decimal", "sqlx:rust_decimal"] +decimal = ["rust_decimal"] [dev-dependencies] anyhow = "1" tokio = { version = "1", features = ["full"] } -serial_test = "2" +serial_test = "3.1.1" diff --git a/sqlb-macros/src/lib.rs b/sqlb-macros/src/lib.rs index 8b53d25..ee8c272 100644 --- a/sqlb-macros/src/lib.rs +++ b/sqlb-macros/src/lib.rs @@ -77,6 +77,12 @@ pub fn derives_fields(input: TokenStream) -> TokenStream { #props_all_names, )*] } + + fn field_names_prefixed(prefix: &str) -> Vec { + vec![#( + format!("{}{}", prefix, #props_all_names), + )*] + } } }; diff --git a/src/core.rs b/src/core.rs index 75baf86..2603d5d 100644 --- a/src/core.rs +++ b/src/core.rs @@ -1,18 +1,7 @@ use async_trait::async_trait; -pub use crate::delete::delete; -pub use crate::delete::delete_all; -pub use crate::delete::DeleteSqlBuilder; -pub use crate::insert::insert; -pub use crate::insert::InsertSqlBuilder; -pub use crate::select::select; -pub use crate::select::SelectSqlBuilder; -pub use crate::update::update; -pub use crate::update::update_all; -pub use crate::update::UpdateSqlBuilder; use crate::utils::x_column_name; pub use crate::val::SqlxBindable; -pub use sqlb_macros::Fields; use sqlx::Executor; use sqlx::FromRow; use sqlx::Postgres; @@ -53,6 +42,9 @@ pub trait HasFields { /// Return the array of all field names this struct has. fn field_names() -> &'static [&'static str]; + + /// Return the array of all field names this struct has. + fn field_names_prefixed(prefix: &str) -> Vec; } // region: Common Types diff --git a/src/sqlx_exec.rs b/src/sqlx_exec.rs index 87a403c..fc99073 100644 --- a/src/sqlx_exec.rs +++ b/src/sqlx_exec.rs @@ -1,6 +1,6 @@ //////////////////////////////////// // sqlx-exec - module for the sqlx query executor -//// +//////////////////////////////////// use crate::SqlBuilder; use sqlx::{postgres::PgArguments, Execute, Executor, FromRow, Postgres}; @@ -22,7 +22,13 @@ where } // create the QueryAs - let query = sqlx::query_as_with::(&sql, query.take_arguments().unwrap()); + let arguments = query.take_arguments().unwrap(); + let query; + if let Some(arguments) = arguments { + query = sqlx::query_as_with::(&sql, arguments); + } else { + query = sqlx::query_as::(&sql); + } // exec and return let r = query.fetch_one(db_pool).await?; @@ -46,7 +52,13 @@ where } // create the QueryAs - let query = sqlx::query_as_with::(&sql, query.take_arguments().unwrap()); + let arguments = query.take_arguments().unwrap(); + let query; + if let Some(arguments) = arguments { + query = sqlx::query_as_with::(&sql, arguments); + } else { + query = sqlx::query_as::(&sql); + } // exec and return let r = query.fetch_optional(db_pool).await?; @@ -70,7 +82,13 @@ where } // create the QueryAs - let query = sqlx::query_as_with::(&sql, query.take_arguments().unwrap()); + let arguments = query.take_arguments().unwrap(); + let query; + if let Some(arguments) = arguments { + query = sqlx::query_as_with::(&sql, arguments); + } else { + query = sqlx::query_as::(&sql); + } // exec and return let r = query.fetch_all(db_pool).await?; diff --git a/src/update.rs b/src/update.rs index 243a655..fcd3ef2 100644 --- a/src/update.rs +++ b/src/update.rs @@ -124,8 +124,7 @@ impl<'a> SqlBuilder<'a> for UpdateSqlBuilder<'a> { let fields = &self.data; let sql_set = fields .iter() - .enumerate() - .map(|(_, f)| { + .map(|f| { let mut part = format!("{} = ", x_column_name(&f.name)); match f.value.raw() { None => { diff --git a/src/val.rs b/src/val.rs index 4cb29af..c43f4c3 100644 --- a/src/val.rs +++ b/src/val.rs @@ -8,14 +8,14 @@ use time::OffsetDateTime; use uuid::Uuid; pub trait SqlxBindable: std::fmt::Debug { - fn bind_query<'q>( - &'q self, - query: sqlx::query::Query<'q, sqlx::Postgres, sqlx::postgres::PgArguments>, - ) -> sqlx::query::Query<'q, sqlx::Postgres, sqlx::postgres::PgArguments>; - - fn raw(&self) -> Option<&str> { - None - } + fn bind_query<'q>( + &'q self, + query: sqlx::query::Query<'q, sqlx::Postgres, sqlx::postgres::PgArguments>, + ) -> sqlx::query::Query<'q, sqlx::Postgres, sqlx::postgres::PgArguments>; + + fn raw(&self) -> Option<&str> { + None + } } #[macro_export] @@ -65,17 +65,17 @@ bindable_to_string!(String, str); impl SqlxBindable for Option where - T: SqlxBindable + Clone + Send, - T: for<'r> sqlx::Encode<'r, sqlx::Postgres>, - T: sqlx::Type, + T: SqlxBindable + Clone + Send, + T: for<'r> sqlx::Encode<'r, sqlx::Postgres>, + T: sqlx::Type, { - fn bind_query<'q>( - &'q self, - query: sqlx::query::Query<'q, sqlx::Postgres, sqlx::postgres::PgArguments>, - ) -> sqlx::query::Query<'q, sqlx::Postgres, sqlx::postgres::PgArguments> { - let query = query.bind(self.clone()); - query - } + fn bind_query<'q>( + &'q self, + query: sqlx::query::Query<'q, sqlx::Postgres, sqlx::postgres::PgArguments>, + ) -> sqlx::query::Query<'q, sqlx::Postgres, sqlx::postgres::PgArguments> { + let query = query.bind(self.clone()); + query + } } // Bind the boolean @@ -86,14 +86,16 @@ bindable!(i8, i16, i32, i64, f32, f64); bindable!(Uuid, OffsetDateTime); +bindable!(Vec, Vec); + // region: --- Raw Value // region: --- chrono support #[cfg(feature = "chrono-support")] mod chrono_support { - use chrono::{NaiveDateTime, NaiveDate, NaiveTime, DateTime, Utc}; + use chrono::{DateTime, NaiveDate, NaiveDateTime, NaiveTime, Utc}; - bindable!(NaiveDateTime, NaiveDate, NaiveTime, DateTime); + bindable!(NaiveDateTime, NaiveDate, NaiveTime, DateTime); } // endregion: --- chrono support @@ -102,7 +104,7 @@ mod chrono_support { mod json { use serde_json::Value; - bindable!(Value); + bindable!(Value); } // endregion: --- json support @@ -111,7 +113,7 @@ mod json { mod decimal { use rust_decimal::Decimal; - bindable!(Decimal); + bindable!(Decimal); } // endregion: --- decimal support @@ -119,40 +121,40 @@ mod decimal { pub struct Raw(pub &'static str); impl SqlxBindable for Raw { - // just return the query given, since no binding should be taken place - fn bind_query<'q>( - &self, - query: sqlx::query::Query<'q, sqlx::Postgres, sqlx::postgres::PgArguments>, - ) -> sqlx::query::Query<'q, sqlx::Postgres, sqlx::postgres::PgArguments> { - query - } - - fn raw(&self) -> Option<&str> { - Some(self.0) - } + // just return the query given, since no binding should be taken place + fn bind_query<'q>( + &self, + query: sqlx::query::Query<'q, sqlx::Postgres, sqlx::postgres::PgArguments>, + ) -> sqlx::query::Query<'q, sqlx::Postgres, sqlx::postgres::PgArguments> { + query + } + + fn raw(&self) -> Option<&str> { + Some(self.0) + } } // endregion: --- Raw Value #[cfg(test)] mod tests { - use crate::Field; - - #[test] - fn field_from_str() { - let field = Field::from(("name1", "v2")); - assert_eq!("name1", field.name); - - let field: Field = ("name1", "v2").into(); - assert_eq!("name1", field.name); - } - - #[test] - fn field_from_string() { - let field = Field::from(("name1", "v1")); - assert_eq!("name1", field.name); - - let v2 = &"v2".to_string(); - let field: Field = ("name2", v2).into(); - assert_eq!("name2", field.name); - } + use crate::Field; + + #[test] + fn field_from_str() { + let field = Field::from(("name1", "v2")); + assert_eq!("name1", field.name); + + let field: Field = ("name1", "v2").into(); + assert_eq!("name1", field.name); + } + + #[test] + fn field_from_string() { + let field = Field::from(("name1", "v1")); + assert_eq!("name1", field.name); + + let v2 = &"v2".to_string(); + let field: Field = ("name2", v2).into(); + assert_eq!("name2", field.name); + } } diff --git a/tests/test_sb_select.rs b/tests/test_sb_select.rs index c96c8e7..603dc4e 100644 --- a/tests/test_sb_select.rs +++ b/tests/test_sb_select.rs @@ -44,7 +44,7 @@ async fn sb_select_ok_limit_offset() -> Result<(), Box> { // -- Check assert_eq!(todos.len(), 3, "number of todos"); - let todo_02 = todos.get(0).unwrap(); + let todo_02 = todos.first().unwrap(); assert_eq!(todo_02.title, "sb_select_ok_limit_offset-02"); // -- Clean diff --git a/tests/utils/mod.rs b/tests/utils/mod.rs index e820f0f..7214e8e 100644 --- a/tests/utils/mod.rs +++ b/tests/utils/mod.rs @@ -1,5 +1,7 @@ #![allow(unused)] +use std::env; + use anyhow::Result; use sqlb::{Field, HasFields}; use sqlb_macros::Fields; @@ -105,9 +107,11 @@ pub async fn util_fetch_todo(db_pool: &Pool, id: i64) -> Result // region: Test Utils pub async fn init_db() -> Result, sqlx::Error> { + let database_url: String = env::var("DATABASE_URL").ok() + .unwrap_or("postgres://postgres:welcome@localhost/postgres".to_string()); let pool = PgPoolOptions::new() .max_connections(5) - .connect("postgres://postgres:welcome@localhost/postgres") + .connect(&database_url) .await?; sqlx::query("DROP TABLE IF EXISTS todo").execute(&pool).await?;