diff --git a/benches/value.rs b/benches/value.rs index 4b42c7b60..10c64913e 100644 --- a/benches/value.rs +++ b/benches/value.rs @@ -1,3 +1,4 @@ +use core::fmt; use std::hint::black_box; use criterion::{Criterion, criterion_group, criterion_main}; @@ -10,59 +11,147 @@ pub enum Char { Character, } -fn vanilla() -> String { - format!( - "SELECT `{}` from `{}` where `character` = {}", - "character", - "character".to_owned(), - "foobar" - ) +fn small_raw(value: i32) -> Result { + let mut str = String::new(); + str.write_str("SELECT ")?; + str.write_str(&Char::Id.quoted())?; + str.write_str(" FROM ")?; + str.write_str(&Char::Table.quoted())?; + str.write_str(" WHERE ")?; + for _ in black_box(0..9) { + str.write_str(&Char::Id.quoted())?; + str.write_str(" = ")?; + write!(str, "{value}")?; + str.write_str(" AND ")?; + } + str.write_str("1=1")?; + + Ok(str) +} + +fn small_select(value: i32) -> SelectStatement { + Query::select() + .column(Char::Character) + .from(Char::Table) + .and_where(Expr::col(Char::Character).eq(value)) + .and_where(Expr::col(Char::Character).eq(value)) + .and_where(Expr::col(Char::Character).eq(value)) + .and_where(Expr::col(Char::Character).eq(value)) + .and_where(Expr::col(Char::Character).eq(value)) + .and_where(Expr::col(Char::Character).eq(value)) + .and_where(Expr::col(Char::Character).eq(value)) + .and_where(Expr::col(Char::Character).eq(value)) + .and_where(Expr::col(Char::Character).eq(value)) + .and_where(Expr::col(Char::Character).eq(value)) + .to_owned() } -fn select() -> SelectStatement { +fn large_raw(value: &jiff::Zoned) -> Result { + let mut str = String::new(); + str.write_str("SELECT ")?; + str.write_str(&Char::Character.quoted())?; + str.write_str(" FROM ")?; + str.write_str(&Char::Table.quoted())?; + str.write_str(" WHERE ")?; + + for _ in 0..9 { + str.write_str(&Char::Character.quoted())?; + str.write_str(" = '")?; + write!(str, "{value}")?; + str.write_str("' AND ")?; + } + + str.write_str("1=1")?; + + Ok(str) +} + +fn large_select(value: jiff::Zoned) -> SelectStatement { Query::select() .column(Char::Character) .from(Char::Table) - .and_where(Expr::col(Char::Character).eq("foobar")) - .and_where(Expr::col(Char::Character).eq("foobar")) - .and_where(Expr::col(Char::Character).eq("foobar")) - .and_where(Expr::col(Char::Character).eq("foobar")) - .and_where(Expr::col(Char::Character).eq("foobar")) - .and_where(Expr::col(Char::Character).eq("foobar")) - .and_where(Expr::col(Char::Character).eq("foobar")) - .and_where(Expr::col(Char::Character).eq("foobar")) - .and_where(Expr::col(Char::Character).eq("foobar")) - .and_where(Expr::col(Char::Character).eq("foobar")) + .and_where(Expr::col(Char::Character).eq(value.clone())) + .and_where(Expr::col(Char::Character).eq(value.clone())) + .and_where(Expr::col(Char::Character).eq(value.clone())) + .and_where(Expr::col(Char::Character).eq(value.clone())) + .and_where(Expr::col(Char::Character).eq(value.clone())) + .and_where(Expr::col(Char::Character).eq(value.clone())) + .and_where(Expr::col(Char::Character).eq(value.clone())) + .and_where(Expr::col(Char::Character).eq(value.clone())) + .and_where(Expr::col(Char::Character).eq(value.clone())) + .and_where(Expr::col(Char::Character).eq(value)) .to_owned() } fn criterion_benchmark(c: &mut Criterion) { let mut group = c.benchmark_group("value"); - group.bench_function("vanilla", |b| b.iter(vanilla)); - group.bench_function("select", |b| b.iter(select)); + let value = black_box(jiff::Zoned::now()); + + group.bench_function("select_construction/small", |b| { + b.iter(|| small_select(black_box(123))) + }); + group.bench_function("select_construction/small/raw", |b| { + b.iter(|| small_raw(black_box(123)).unwrap()) + }); + + group.bench_function("select_construction/large", |b| { + b.iter(|| large_select(value.clone())) + }); + + group.bench_function("select_construction/large/raw", |b| { + b.iter(|| large_raw(&value).unwrap()) + }); + + let select_small = black_box(small_select(black_box(123))); + group.bench_function("select_and_build/small/mysql", |b| { + b.iter(|| select_small.build(MysqlQueryBuilder)) + }); + group.bench_function("select_and_build/small/pg", |b| { + b.iter(|| select_small.build(PostgresQueryBuilder)) + }); + group.bench_function("select_and_build/small/sqlite", |b| { + b.iter(|| select_small.build(SqliteQueryBuilder)) + }); + group.bench_function("select_and_to_string/small/mysql", |b| { + b.iter(|| select_small.to_string(MysqlQueryBuilder)) + }); + group.bench_function("select_and_to_string/small/pg", |b| { + b.iter(|| select_small.to_string(PostgresQueryBuilder)) + }); + group.bench_function("select_and_to_string/small/sqlite", |b| { + b.iter(|| select_small.to_string(SqliteQueryBuilder)) + }); - let select = black_box(select()); - group.bench_function("select_and_build::mysql", |b| { - b.iter(|| select.build(MysqlQueryBuilder)) + let select_large = black_box(large_select(value)); + group.bench_function("select_and_build/large/mysql", |b| { + b.iter(|| select_large.build(MysqlQueryBuilder)) }); - group.bench_function("select_and_build::pg", |b| { - b.iter(|| select.build(PostgresQueryBuilder)) + group.bench_function("select_and_build/large/pg", |b| { + b.iter(|| select_large.build(PostgresQueryBuilder)) }); - group.bench_function("select_and_build::sqlite", |b| { - b.iter(|| select.build(SqliteQueryBuilder)) + group.bench_function("select_and_build/large/sqlite", |b| { + b.iter(|| select_large.build(SqliteQueryBuilder)) }); - group.bench_function("select_and_to_string::mysql", |b| { - b.iter(|| select.to_string(MysqlQueryBuilder)) + group.bench_function("select_and_to_string/large/mysql", |b| { + b.iter(|| select_large.to_string(MysqlQueryBuilder)) }); - group.bench_function("select_and_to_string::pg", |b| { - b.iter(|| select.to_string(PostgresQueryBuilder)) + group.bench_function("select_and_to_string/large/pg", |b| { + b.iter(|| select_large.to_string(PostgresQueryBuilder)) }); - group.bench_function("select_and_to_string::sqlite", |b| { - b.iter(|| select.to_string(SqliteQueryBuilder)) + group.bench_function("select_and_to_string/large/sqlite", |b| { + b.iter(|| select_large.to_string(SqliteQueryBuilder)) }); group.finish(); } -criterion_group!(benches, criterion_benchmark); +fn config() -> Criterion { + Criterion::default().measurement_time(std::time::Duration::new(10, 0)) +} + +criterion_group!( + name = benches; + config = config(); + targets = criterion_benchmark +); criterion_main!(benches); diff --git a/sea-query-diesel/src/backend/mysql.rs b/sea-query-diesel/src/backend/mysql.rs index a69913093..87d5e27eb 100644 --- a/sea-query-diesel/src/backend/mysql.rs +++ b/sea-query-diesel/src/backend/mysql.rs @@ -64,7 +64,7 @@ impl TransformValue for Mysql { ))] Value::Decimal(_) => bail!("Enable feature with-rust_decimal-mysql"), #[cfg(feature = "with-bigdecimal")] - Value::BigDecimal(v) => build!(Numeric, v.map(|v| *v)), + Value::BigDecimal(v) => build!(Numeric, v), #[cfg(feature = "with-json")] Value::Json(v) => build!(Json, v), #[cfg(feature = "with-ipnetwork")] diff --git a/sea-query-diesel/src/backend/postgres.rs b/sea-query-diesel/src/backend/postgres.rs index ae40ca137..e94cfd7ce 100644 --- a/sea-query-diesel/src/backend/postgres.rs +++ b/sea-query-diesel/src/backend/postgres.rs @@ -74,7 +74,7 @@ impl TransformValue for Pg { ))] Value::Decimal(_) => bail!("Enable feature with-rust_decimal-postgres"), #[cfg(feature = "with-bigdecimal")] - Value::BigDecimal(v) => build!(Numeric, v.map(|v| *v)), + Value::BigDecimal(v) => build!(Numeric, v), #[cfg(feature = "with-json")] Value::Json(v) => build!(Json, v), #[cfg(feature = "with-ipnetwork")] diff --git a/sea-query-postgres/src/lib.rs b/sea-query-postgres/src/lib.rs index a98660c6a..795c6101b 100644 --- a/sea-query-postgres/src/lib.rs +++ b/sea-query-postgres/src/lib.rs @@ -104,7 +104,7 @@ impl ToSql for PostgresValue { #[cfg(feature = "with-bigdecimal")] Value::BigDecimal(v) => { use bigdecimal::ToPrimitive; - v.as_deref() + v.as_ref() .map(|v| v.to_f64().expect("Fail to convert bigdecimal as f64")) .to_sql(ty, out) } diff --git a/sea-query-sqlx/src/sqlx_mysql.rs b/sea-query-sqlx/src/sqlx_mysql.rs index 5275f65f2..4fa2718fe 100644 --- a/sea-query-sqlx/src/sqlx_mysql.rs +++ b/sea-query-sqlx/src/sqlx_mysql.rs @@ -100,7 +100,7 @@ impl sqlx::IntoArguments<'_, sqlx::mysql::MySql> for SqlxValues { } #[cfg(feature = "with-bigdecimal")] Value::BigDecimal(d) => { - let _ = args.add(d.as_deref()); + let _ = args.add(d.as_ref()); } #[cfg(feature = "with-json")] Value::Json(j) => { diff --git a/sea-query-sqlx/src/sqlx_postgres.rs b/sea-query-sqlx/src/sqlx_postgres.rs index 6402de556..6c7cd5c92 100644 --- a/sea-query-sqlx/src/sqlx_postgres.rs +++ b/sea-query-sqlx/src/sqlx_postgres.rs @@ -115,7 +115,7 @@ impl sqlx::IntoArguments<'_, sqlx::postgres::Postgres> for SqlxValues { } #[cfg(feature = "with-bigdecimal")] Value::BigDecimal(d) => { - let _ = args.add(d.as_deref()); + let _ = args.add(d.as_ref()); } #[cfg(feature = "with-json")] Value::Json(j) => { diff --git a/src/value.rs b/src/value.rs index ac47b9837..6ddf0f685 100644 --- a/src/value.rs +++ b/src/value.rs @@ -280,15 +280,15 @@ pub enum Value { #[cfg(feature = "with-jiff")] #[cfg_attr(docsrs, doc(cfg(feature = "with-jiff")))] - JiffDateTime(Option>), + JiffDateTime(Option), #[cfg(feature = "with-jiff")] #[cfg_attr(docsrs, doc(cfg(feature = "with-jiff")))] - JiffTimestamp(Option>), + JiffTimestamp(Option), #[cfg(feature = "with-jiff")] #[cfg_attr(docsrs, doc(cfg(feature = "with-jiff")))] - JiffZoned(Option>), + JiffZoned(Option), #[cfg(feature = "with-uuid")] #[cfg_attr(docsrs, doc(cfg(feature = "with-uuid")))] @@ -300,11 +300,11 @@ pub enum Value { #[cfg(feature = "with-bigdecimal")] #[cfg_attr(docsrs, doc(cfg(feature = "with-bigdecimal")))] - BigDecimal(Option>), + BigDecimal(Option), #[cfg(feature = "postgres-array")] #[cfg_attr(docsrs, doc(cfg(feature = "postgres-array")))] - Array(ArrayType, Option>>), + Array(ArrayType, Option>), #[cfg(feature = "postgres-vector")] #[cfg_attr(docsrs, doc(cfg(feature = "postgres-vector")))] @@ -327,8 +327,8 @@ pub enum Value { pub const VALUE_SIZE: usize = check_value_size(); const fn check_value_size() -> usize { - if std::mem::size_of::() > 32 { - panic!("the size of Value shouldn't be greater than 32 bytes") + if std::mem::size_of::() > 104 { + panic!("the size of Value shouldn't be greater than 104 bytes") } std::mem::size_of::() } @@ -557,19 +557,17 @@ impl Value { #[cfg(feature = "with-jiff")] #[cfg_attr(docsrs, doc(cfg(feature = "with-jiff")))] Self::JiffDateTime(_) => { - Self::JiffDateTime(Some(jiff::civil::date(1970, 1, 1).at(0, 0, 0, 0).into())) + Self::JiffDateTime(Some(jiff::civil::date(1970, 1, 1).at(0, 0, 0, 0))) } #[cfg(feature = "with-jiff")] #[cfg_attr(docsrs, doc(cfg(feature = "with-jiff")))] - Self::JiffTimestamp(_) => Self::JiffTimestamp(Some(Timestamp::UNIX_EPOCH.into())), + Self::JiffTimestamp(_) => Self::JiffTimestamp(Some(Timestamp::UNIX_EPOCH)), #[cfg(feature = "with-jiff")] #[cfg_attr(docsrs, doc(cfg(feature = "with-jiff")))] Self::JiffZoned(_) => Self::JiffZoned(Some( - Timestamp::UNIX_EPOCH - .to_zoned(jiff::tz::TimeZone::UTC) - .into(), + Timestamp::UNIX_EPOCH.to_zoned(jiff::tz::TimeZone::UTC), )), #[cfg(feature = "with-uuid")] @@ -815,6 +813,7 @@ type_to_value!(Vec, Bytes, VarBinary(StringLen::None)); type_to_value!(String, String, String(StringLen::None)); #[cfg(any(feature = "with-bigdecimal", feature = "with-jiff"))] +#[allow(unused)] macro_rules! type_to_box_value { ( $type: ty, $name: ident, $col_type: expr ) => { impl From<$type> for Value { @@ -854,4 +853,5 @@ macro_rules! type_to_box_value { } #[cfg(any(feature = "with-bigdecimal", feature = "with-jiff"))] +#[allow(unused)] use type_to_box_value; diff --git a/src/value/hashable_value.rs b/src/value/hashable_value.rs index e51a9234d..b946a0018 100644 --- a/src/value/hashable_value.rs +++ b/src/value/hashable_value.rs @@ -328,11 +328,11 @@ mod tests { Into::::into(vec![0i32, 1, 2]), Value::Array( ArrayType::Int, - Some(Box::new(vec![ + Some(vec![ Value::Int(Some(0)), Value::Int(Some(1)), Value::Int(Some(2)) - ])) + ]) ) ); @@ -340,11 +340,11 @@ mod tests { Into::::into(vec![0f32, 1.0, 2.0]), Value::Array( ArrayType::Float, - Some(Box::new(vec![ + Some(vec![ Value::Float(Some(0f32)), Value::Float(Some(1.0)), Value::Float(Some(2.0)) - ])) + ]) ) ); diff --git a/src/value/with_array.rs b/src/value/with_array.rs index ef198974f..764c575cf 100644 --- a/src/value/with_array.rs +++ b/src/value/with_array.rs @@ -83,7 +83,7 @@ where fn from(x: Vec) -> Value { Value::Array( T::array_type(), - Some(Box::new(x.into_iter().map(|e| e.into()).collect())), + Some(x.into_iter().map(|e| e.into()).collect()), ) } } @@ -131,7 +131,7 @@ impl Value { pub fn as_ref_array(&self) -> Option<&Vec> { match self { - Self::Array(_, v) => v.as_ref().map(|v| v.as_ref()), + Self::Array(_, v) => v.as_ref(), _ => panic!("not Value::Array"), } } diff --git a/src/value/with_bigdecimal.rs b/src/value/with_bigdecimal.rs index 9a7ee4264..e3570fe5a 100644 --- a/src/value/with_bigdecimal.rs +++ b/src/value/with_bigdecimal.rs @@ -1,6 +1,6 @@ use super::*; -type_to_box_value!(BigDecimal, BigDecimal, Decimal(None)); +type_to_value!(BigDecimal, BigDecimal, Decimal(None)); impl Value { pub fn is_big_decimal(&self) -> bool { @@ -9,7 +9,7 @@ impl Value { pub fn as_ref_big_decimal(&self) -> Option<&BigDecimal> { match self { - Self::BigDecimal(v) => v.as_ref().map(|x| x.as_ref()), + Self::BigDecimal(v) => v.as_ref(), _ => panic!("not Value::BigDecimal"), } } diff --git a/src/value/with_jiff.rs b/src/value/with_jiff.rs index c072f8f07..cdf0cad36 100644 --- a/src/value/with_jiff.rs +++ b/src/value/with_jiff.rs @@ -3,9 +3,9 @@ use jiff::{Timestamp, Zoned, civil}; type_to_value!(civil::Date, JiffDate, Date); type_to_value!(civil::Time, JiffTime, Time); -type_to_box_value!(civil::DateTime, JiffDateTime, DateTime); -type_to_box_value!(Timestamp, JiffTimestamp, Timestamp); -type_to_box_value!(Zoned, JiffZoned, TimestampWithTimeZone); +type_to_value!(civil::DateTime, JiffDateTime, DateTime); +type_to_value!(Timestamp, JiffTimestamp, Timestamp); +type_to_value!(Zoned, JiffZoned, TimestampWithTimeZone); impl Value { #[inline] @@ -20,17 +20,17 @@ impl Value { #[inline] pub fn jiff_date_time>>(v: T) -> Value { - Value::JiffDateTime(v.into().map(Into::into)) + Value::JiffDateTime(v.into()) } #[inline] pub fn jiff_timestamp>>(v: T) -> Value { - Value::JiffTimestamp(v.into().map(Into::into)) + Value::JiffTimestamp(v.into()) } #[inline] pub fn jiff_zoned>>(v: T) -> Value { - Value::JiffZoned(v.into().map(Into::into)) + Value::JiffZoned(v.into()) } } @@ -71,21 +71,21 @@ impl Value { pub fn as_ref_jiff_date_time(&self) -> Option<&civil::DateTime> { match self { - Self::JiffDateTime(v) => v.as_deref(), + Self::JiffDateTime(v) => v.as_ref(), _ => panic!("not Value::JiffDateTime"), } } pub fn as_ref_jiff_timestamp(&self) -> Option<&Timestamp> { match self { - Self::JiffTimestamp(v) => v.as_deref(), + Self::JiffTimestamp(v) => v.as_ref(), _ => panic!("not Value::JiffTimestamp"), } } pub fn as_ref_jiff_zoned(&self) -> Option<&Zoned> { match self { - Self::JiffZoned(v) => v.as_deref(), + Self::JiffZoned(v) => v.as_ref(), _ => panic!("not Value::JiffZoned"), } }