diff --git a/Cargo.toml b/Cargo.toml index ee2551d8a..567c46ec6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,16 +30,30 @@ path = "src/lib.rs" [dependencies] inherent = "1.0" sea-query-derive = { version = "1.0.0-rc", path = "sea-query-derive", optional = true } -serde = { version = "1", default-features = false, optional = true, features = ["std", "derive"] } -serde_json = { version = "1", default-features = false, optional = true, features = ["std"] } -chrono = { version = "0.4.27", default-features = false, optional = true, features = ["clock"] } +sea-query-postgres-types = { version = "0.8.0-rc.9", path = "sea-query-postgres-types", optional = true } +serde = { version = "1", default-features = false, optional = true, features = [ + "std", + "derive", +] } +serde_json = { version = "1", default-features = false, optional = true, features = [ + "std", +] } +chrono = { version = "0.4.27", default-features = false, optional = true, features = [ + "clock", +] } postgres-types = { version = "0", default-features = false, optional = true } pgvector = { version = "~0.4", default-features = false, optional = true } rust_decimal = { version = "1", default-features = false, optional = true } bigdecimal = { version = "0.4", default-features = false, optional = true } uuid = { version = "1", default-features = false, optional = true } -time = { version = "0.3.36", default-features = false, optional = true, features = ["macros", "formatting"] } -jiff = { version = "0.2.15", default-features = false, optional = true, features = ["std", "perf-inline"] } +time = { version = "0.3.36", default-features = false, optional = true, features = [ + "macros", + "formatting", +] } +jiff = { version = "0.2.15", default-features = false, optional = true, features = [ + "std", + "perf-inline", +] } ipnetwork = { version = "0.20", default-features = false, optional = true } mac_address = { version = "1.1", default-features = false, optional = true } ordered-float = { version = "4.6", default-features = false, optional = true } @@ -56,13 +70,21 @@ audit = [] backend-mysql = [] backend-postgres = [] backend-sqlite = [] -default = ["derive", "audit", "backend-mysql", "backend-postgres", "backend-sqlite", "itoa"] +default = [ + "derive", + "audit", + "backend-mysql", + "backend-postgres", + "backend-sqlite", + "itoa", +] derive = ["sea-query-derive"] attr = ["sea-query-derive"] hashable-value = ["ordered-float"] postgres-array = [] postgres-vector = ["pgvector"] postgres-interval = [] +postgres-range = ["sea-query-postgres-types"] serde = [ "dep:serde", "chrono?/serde", diff --git a/build-tools/rustclippy.sh b/build-tools/rustclippy.sh old mode 100644 new mode 100755 diff --git a/build-tools/rustfmt.sh b/build-tools/rustfmt.sh old mode 100644 new mode 100755 diff --git a/sea-query-postgres-types/Cargo.toml b/sea-query-postgres-types/Cargo.toml new file mode 100644 index 000000000..8b9459935 --- /dev/null +++ b/sea-query-postgres-types/Cargo.toml @@ -0,0 +1,41 @@ +[package] +name = "sea-query-postgres-types" +version = "0.8.0-rc.9" +authors = ["Richard Jonas "] +edition = "2024" +description = "Postgres types for using SeaQuery with SQLx" +license = "MIT OR Apache-2.0" +documentation = "https://docs.rs/sea-query" +repository = "https://github.com/SeaQL/sea-query" +categories = ["database"] +keywords = ["database", "sql", "mysql", "postgres", "sqlite"] +rust-version = "1.85.0" + +[lib] + +[dependencies] +bytes = { version = "1", default-features = false } +chrono = { version = "0.4", default-features = false, optional = true, features = [ + "clock", +] } +ordered-float = { version = "4.6", default-features = false, optional = false } +postgres-protocol = { version = "0.6", default-features = false } +postgres-types = { version = "0.2", default-features = false } +serde = { version = "1", default-features = false, optional = false, features = [ + "std", + "derive", +] } +serde_json = { version = "1", default-features = false, optional = false, features = [ + "std", +] } +time = { version = "0.3.36", default-features = false, optional = true, features = [ + "macros", + "formatting", +] } + +[features] +hashable-value = [] +postgres-range = [] +serde = ["chrono?/serde", "time?/serde"] +with-chrono = ["chrono"] +with-time = ["time"] diff --git a/sea-query-postgres-types/src/lib.rs b/sea-query-postgres-types/src/lib.rs new file mode 100644 index 000000000..dee801b6e --- /dev/null +++ b/sea-query-postgres-types/src/lib.rs @@ -0,0 +1 @@ +pub mod range; diff --git a/sea-query-postgres-types/src/range.rs b/sea-query-postgres-types/src/range.rs new file mode 100644 index 000000000..7e51c3485 --- /dev/null +++ b/sea-query-postgres-types/src/range.rs @@ -0,0 +1,190 @@ +//#[cfg(feature = "hashable-value")] +use std::hash::{Hash, Hasher}; +use std::{ + error::Error, + fmt::{Debug, Display}, +}; + +use bytes::BytesMut; +use postgres_protocol::types; +use postgres_types::{IsNull, Kind, ToSql, Type, to_sql_checked}; + +#[derive(Clone, Debug, Eq, PartialEq, Hash, serde::Serialize, serde::Deserialize)] +//#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub enum RangeBound { + Exclusive(T), + Inclusive(T), + Unbounded, +} + +#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] +//#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub enum RangeType { + Int4Range(RangeBound, RangeBound), + Int8Range(RangeBound, RangeBound), + NumRange(RangeBound, RangeBound), +} + +impl RangeType { + pub fn empty(&self) -> bool { + matches!( + self, + &RangeType::Int4Range(RangeBound::Unbounded, RangeBound::Unbounded) + | &RangeType::Int8Range(RangeBound::Unbounded, RangeBound::Unbounded) + | &RangeType::NumRange(RangeBound::Unbounded, RangeBound::Unbounded) + ) + } +} + +impl Default for RangeType { + fn default() -> Self { + Self::Int4Range(RangeBound::Unbounded, RangeBound::Unbounded) + } +} + +impl Display for RangeType { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + RangeType::Int4Range(a, b) => display_range(a, b, f), + RangeType::Int8Range(a, b) => display_range(a, b, f), + RangeType::NumRange(a, b) => display_range(a, b, f), + } + } +} + +fn display_range( + a: &RangeBound, + b: &RangeBound, + f: &mut std::fmt::Formatter<'_>, +) -> std::fmt::Result { + match a { + RangeBound::Exclusive(v) => { + f.write_fmt(format_args!("[{v},"))?; + } + RangeBound::Inclusive(v) => { + f.write_fmt(format_args!("({v},"))?; + } + RangeBound::Unbounded => { + f.write_str("(,")?; + } + } + + match b { + RangeBound::Exclusive(v) => { + f.write_fmt(format_args!("{v}]"))?; + } + RangeBound::Inclusive(v) => { + f.write_fmt(format_args!("{v})"))?; + } + RangeBound::Unbounded => { + f.write_str(")")?; + } + } + + Ok(()) +} + +// TODO even if I put Hash impl behind feature gate, compilation fails +//#[cfg(feature = "hashable-value")] +impl Hash for RangeType { + fn hash(&self, state: &mut H) { + core::mem::discriminant(self).hash(state); + match self { + RangeType::Int4Range(a, b) => { + a.hash(state); + b.hash(state); + } + RangeType::Int8Range(a, b) => { + a.hash(state); + b.hash(state); + } + RangeType::NumRange(a, b) => { + hash_range_bound(a, state); + hash_range_bound(b, state); + } + } + } +} + +//#[cfg(feature = "hashable-value")] +fn hash_range_bound(rb: &RangeBound, state: &mut H) { + match rb { + RangeBound::Exclusive(v) => ordered_float::OrderedFloat(*v).hash(state), + RangeBound::Inclusive(v) => ordered_float::OrderedFloat(*v).hash(state), + RangeBound::Unbounded => (), + } +} + +impl ToSql for RangeType { + fn to_sql( + &self, + ty: &postgres_types::Type, + buf: &mut BytesMut, + ) -> Result> + where + Self: Sized, + { + let element_type = match *ty.kind() { + Kind::Range(ref ty) => ty, + _ => return Err(format!("unexpected type {:?}", ty).into()), + }; + + if self.empty() { + types::empty_range_to_sql(buf); + } else { + types::range_to_sql( + |buf| match self { + RangeType::Int4Range(lower, _) => bound_to_sql(lower, element_type, buf), + RangeType::Int8Range(lower, _) => bound_to_sql(lower, element_type, buf), + RangeType::NumRange(lower, _) => bound_to_sql(lower, element_type, buf), + }, + |buf| match self { + RangeType::Int4Range(_, upper) => bound_to_sql(upper, element_type, buf), + RangeType::Int8Range(_, upper) => bound_to_sql(upper, element_type, buf), + RangeType::NumRange(_, upper) => bound_to_sql(upper, element_type, buf), + }, + buf, + )?; + } + + Ok(postgres_types::IsNull::No) + } + + fn accepts(ty: &postgres_types::Type) -> bool + where + Self: Sized, + { + matches!(ty.kind(), &Kind::Range(_)) + } + + to_sql_checked!(); +} + +fn bound_to_sql( + bound: &RangeBound, + ty: &Type, + buf: &mut BytesMut, +) -> Result, Box> +where + T: Clone + Display + ToSql, +{ + match bound { + RangeBound::Exclusive(v) => { + let is_null = match v.to_sql(ty, buf)? { + IsNull::Yes => postgres_protocol::IsNull::Yes, + IsNull::No => postgres_protocol::IsNull::No, + }; + + Ok(types::RangeBound::Exclusive(is_null)) + } + RangeBound::Inclusive(v) => { + let is_null = match v.to_sql(ty, buf)? { + IsNull::Yes => postgres_protocol::IsNull::Yes, + IsNull::No => postgres_protocol::IsNull::No, + }; + + Ok(types::RangeBound::Inclusive(is_null)) + } + RangeBound::Unbounded => Ok(types::RangeBound::Unbounded), + } +} diff --git a/sea-query-postgres/Cargo.toml b/sea-query-postgres/Cargo.toml index 4618b25d4..19f0254e1 100644 --- a/sea-query-postgres/Cargo.toml +++ b/sea-query-postgres/Cargo.toml @@ -4,20 +4,21 @@ [package] name = "sea-query-postgres" version = "0.6.0-rc.1" -authors = [ "Ivan Krivosheev " ] +authors = ["Ivan Krivosheev "] edition = "2024" description = "Binder traits for connecting sea-query with postgres driver" license = "MIT OR Apache-2.0" documentation = "https://docs.rs/sea-query" repository = "https://github.com/SeaQL/sea-query" -categories = [ "database" ] -keywords = [ "database", "sql", "postgres" ] +categories = ["database"] +keywords = ["database", "sql", "postgres"] rust-version = "1.85.0" [lib] [dependencies] sea-query = { version = "1.0.0-rc.1", path = "..", default-features = false } +sea-query-postgres-types = { version = "0.8.0-rc.9", path = "../sea-query-postgres-types", default-features = false } postgres-types = { version = "0.2", default-features = false } pgvector = { version = "~0.4", default-features = false, optional = true } bytes = { version = "1", default-features = false } @@ -36,6 +37,17 @@ with-bigdecimal = ["sea-query/with-bigdecimal", "bigdecimal"] with-uuid = ["postgres-types/with-uuid-1", "sea-query/with-uuid"] with-time = ["postgres-types/with-time-0_3", "sea-query/with-time"] postgres-array = ["postgres-types/array-impls", "sea-query/postgres-array"] +postgres-range = ["sea-query/postgres-range"] postgres-vector = ["sea-query/postgres-vector", "pgvector/postgres"] -with-ipnetwork = ["postgres-types/with-cidr-0_2", "sea-query/with-ipnetwork", "ipnetwork", "cidr"] -with-mac_address = ["postgres-types/with-eui48-1", "sea-query/with-mac_address", "mac_address", "eui48"] +with-ipnetwork = [ + "postgres-types/with-cidr-0_2", + "sea-query/with-ipnetwork", + "ipnetwork", + "cidr", +] +with-mac_address = [ + "postgres-types/with-eui48-1", + "sea-query/with-mac_address", + "mac_address", + "eui48", +] diff --git a/sea-query-postgres/src/lib.rs b/sea-query-postgres/src/lib.rs index a98660c6a..bd39e54c8 100644 --- a/sea-query-postgres/src/lib.rs +++ b/sea-query-postgres/src/lib.rs @@ -136,6 +136,10 @@ impl ToSql for PostgresValue { use eui48::MacAddress; v.map(|v| MacAddress::new(v.bytes())).to_sql(ty, out) } + #[cfg(feature = "postgres-range")] + Value::Range(None) => Ok(IsNull::Yes), + #[cfg(feature = "postgres-range")] + Value::Range(Some(v)) => v.to_sql(ty, out), } } diff --git a/sea-query-sqlx/Cargo.toml b/sea-query-sqlx/Cargo.toml index ae0c50f2b..f62eccc14 100644 --- a/sea-query-sqlx/Cargo.toml +++ b/sea-query-sqlx/Cargo.toml @@ -4,27 +4,39 @@ [package] name = "sea-query-sqlx" version = "0.8.0-rc.9" -authors = [ "Valentin Tolmer ", "Ivan Krivosheev " ] +authors = [ + "Valentin Tolmer ", + "Ivan Krivosheev ", +] edition = "2024" description = "Driver library for using SeaQuery with SQLx" license = "MIT OR Apache-2.0" documentation = "https://docs.rs/sea-query" repository = "https://github.com/SeaQL/sea-query" -categories = [ "database" ] -keywords = [ "database", "sql", "mysql", "postgres", "sqlite" ] +categories = ["database"] +keywords = ["database", "sql", "mysql", "postgres", "sqlite"] rust-version = "1.85.0" [lib] [dependencies] -sea-query = { version = "1.0.0-rc.10", path = "..", default-features = false, features = ["thread-safe"] } +sea-query = { version = "1.0.0-rc.10", path = "..", default-features = false, features = [ + "thread-safe", +] } sqlx = { version = "0.8", default-features = false, optional = true } -serde_json = { version = "1", default-features = false, optional = true, features = ["std"] } -chrono = { version = "0.4", default-features = false, optional = true, features = ["clock"] } +serde_json = { version = "1", default-features = false, optional = true, features = [ + "std", +] } +chrono = { version = "0.4", default-features = false, optional = true, features = [ + "clock", +] } rust_decimal = { version = "1", default-features = false, optional = true } bigdecimal = { version = "0.4", default-features = false, optional = true } uuid = { version = "1", default-features = false, optional = true } -time = { version = "0.3.36", default-features = false, optional = true, features = ["macros", "formatting"] } +time = { version = "0.3.36", default-features = false, optional = true, features = [ + "macros", + "formatting", +] } ipnetwork = { version = "0.20", default-features = false, optional = true } mac_address = { version = "1.1", default-features = false, optional = true } pgvector = { version = "~0.4", default-features = false, optional = true } @@ -36,17 +48,30 @@ sqlx-sqlite = ["sqlx/sqlite"] sqlx-any = ["sqlx/any"] with-chrono = ["sqlx?/chrono", "sea-query/with-chrono", "chrono"] with-json = ["sqlx?/json", "sea-query/with-json", "serde_json"] -with-rust_decimal = ["sqlx?/rust_decimal", "sea-query/with-rust_decimal", "rust_decimal"] -with-bigdecimal = ["sqlx?/bigdecimal", "sea-query/with-bigdecimal", "bigdecimal"] +with-rust_decimal = [ + "sqlx?/rust_decimal", + "sea-query/with-rust_decimal", + "rust_decimal", +] +with-bigdecimal = [ + "sqlx?/bigdecimal", + "sea-query/with-bigdecimal", + "bigdecimal", +] with-uuid = ["sqlx?/uuid", "sea-query/with-uuid", "uuid"] with-time = ["sqlx?/time", "sea-query/with-time", "time"] with-ipnetwork = ["sqlx?/ipnetwork", "sea-query/with-ipnetwork", "ipnetwork"] -with-mac_address = ["sqlx?/mac_address", "sea-query/with-mac_address", "mac_address"] +with-mac_address = [ + "sqlx?/mac_address", + "sea-query/with-mac_address", + "mac_address", +] postgres-array = ["sea-query/postgres-array"] +postgres-range = ["sea-query/postgres-range"] postgres-vector = ["sea-query/postgres-vector", "pgvector/sqlx"] runtime-async-std = ["sqlx?/runtime-async-std"] runtime-async-std-native-tls = ["sqlx?/runtime-async-std-native-tls"] -runtime-async-std-rustls = ["sqlx?/runtime-async-std-rustls", ] +runtime-async-std-rustls = ["sqlx?/runtime-async-std-rustls"] runtime-actix = ["sqlx?/runtime-tokio"] runtime-actix-native-tls = ["sqlx?/runtime-tokio-native-tls"] runtime-actix-rustls = ["sqlx?/runtime-tokio-rustls"] diff --git a/sea-query-sqlx/src/sqlx_any.rs b/sea-query-sqlx/src/sqlx_any.rs index 466f7b187..5a7081a31 100644 --- a/sea-query-sqlx/src/sqlx_any.rs +++ b/sea-query-sqlx/src/sqlx_any.rs @@ -124,6 +124,10 @@ impl<'q> sqlx::IntoArguments<'q, sqlx::any::Any> for SqlxValues { Value::Vector(_) => { panic!("SQLx doesn't support vector arguments for Any"); } + #[cfg(feature = "postgres-range")] + Value::Range(_) => { + panic!("SQLx doesn't support PgRange arguments for Any"); + } } } args diff --git a/sea-query-sqlx/src/sqlx_mysql.rs b/sea-query-sqlx/src/sqlx_mysql.rs index 5275f65f2..339e56dad 100644 --- a/sea-query-sqlx/src/sqlx_mysql.rs +++ b/sea-query-sqlx/src/sqlx_mysql.rs @@ -122,6 +122,10 @@ impl sqlx::IntoArguments<'_, sqlx::mysql::MySql> for SqlxValues { Value::MacAddress(_) => { panic!("Mysql doesn't support MacAddress arguments"); } + #[cfg(feature = "postgres-range")] + Value::Range(_) => { + panic!("Mysql doesn't support PgRange arguments"); + } } } args diff --git a/sea-query-sqlx/src/sqlx_postgres.rs b/sea-query-sqlx/src/sqlx_postgres.rs index 6402de556..47eaa7f93 100644 --- a/sea-query-sqlx/src/sqlx_postgres.rs +++ b/sea-query-sqlx/src/sqlx_postgres.rs @@ -318,6 +318,10 @@ impl sqlx::IntoArguments<'_, sqlx::postgres::Postgres> for SqlxValues { Value::Vector(v) => { let _ = args.add(v); } + #[cfg(feature = "postgres-range")] + Value::Range(v) => { + let _ = args.add(v); + } } } args diff --git a/sea-query-sqlx/src/sqlx_sqlite.rs b/sea-query-sqlx/src/sqlx_sqlite.rs index 888e55778..300929e3d 100644 --- a/sea-query-sqlx/src/sqlx_sqlite.rs +++ b/sea-query-sqlx/src/sqlx_sqlite.rs @@ -124,6 +124,10 @@ impl<'q> sqlx::IntoArguments<'q, sqlx::sqlite::Sqlite> for SqlxValues { Value::Vector(_) => { panic!("Sqlite doesn't support vector arguments"); } + #[cfg(feature = "postgres-range")] + Value::Range(_) => { + panic!("Sqlite doesn't support PgRange arguments"); + } } } args diff --git a/src/backend/query_builder.rs b/src/backend/query_builder.rs index 43fe575df..b6764c67d 100644 --- a/src/backend/query_builder.rs +++ b/src/backend/query_builder.rs @@ -1172,6 +1172,8 @@ pub trait QueryBuilder: Value::Array(_, None) => buf.write_str("NULL")?, #[cfg(feature = "postgres-vector")] Value::Vector(None) => buf.write_str("NULL")?, + #[cfg(feature = "postgres-range")] + Value::Range(None) => buf.write_str("NULL")?, Value::Bool(Some(b)) => buf.write_str(if *b { "TRUE" } else { "FALSE" })?, Value::TinyInt(Some(v)) => { write_int(buf, *v); @@ -1360,6 +1362,12 @@ pub trait QueryBuilder: write!(buf, "{v}")?; buf.write_str("'")?; } + #[cfg(feature = "postgres-range")] + Value::Range(Some(v)) => { + buf.write_str("'")?; + write!(buf, "{v}")?; + buf.write_str("'")?; + } }; Ok(()) @@ -1907,7 +1915,7 @@ mod tests { use chrono::{DateTime, FixedOffset, NaiveDate, NaiveDateTime, NaiveTime, Utc}; #[cfg(feature = "with-chrono")] - use crate::{MysqlQueryBuilder, PostgresQueryBuilder, QueryBuilder, SqliteQueryBuilder}; + use crate::QueryBuilder; /// [Postgresql reference](https://www.postgresql.org/docs/current/datatype-datetime.html#DATATYPE-DATETIME-INPUT-TIMES) /// diff --git a/src/raw_sql.rs b/src/raw_sql.rs index b1af01187..7ed9527ef 100644 --- a/src/raw_sql.rs +++ b/src/raw_sql.rs @@ -81,7 +81,7 @@ mod test { #[test] fn test_raw_sql_1() { let a = 1; - let b = vec![2i32, 3]; + let b = [2i32, 3]; let c = [4i32, 5, 6]; let mut builder = RawSqlQueryBuilder::new(PostgresQueryBuilder); @@ -90,18 +90,18 @@ mod test { .push_fragment(" ") .push_parameters(1) .push_fragment(", ") - .push_parameters((&b).len()) + .push_parameters(b.len()) .push_fragment(", ") - .push_parameters((&c).len()); + .push_parameters(c.len()); assert_eq!(builder.finish(), "SELECT $1, $2, $3, $4, $5, $6"); let mut values = Values::default(); values.bind(a); - for v in (&b).iter() { + for v in b.iter() { values.bind(v); } - for v in (&c).iter() { + for v in c.iter() { values.bind(v); } diff --git a/src/value.rs b/src/value.rs index 148c9664c..313da9acf 100644 --- a/src/value.rs +++ b/src/value.rs @@ -34,6 +34,9 @@ use std::net::IpAddr; #[cfg(feature = "with-mac_address")] use mac_address::MacAddress; +#[cfg(feature = "postgres-range")] +use sea_query_postgres_types::range::RangeType; + use crate::{ColumnType, CommonSqlQueryBuilder, QueryBuilder, StringLen}; #[cfg(test)] @@ -325,6 +328,10 @@ pub enum Value { #[cfg(feature = "with-mac_address")] #[cfg_attr(docsrs, doc(cfg(feature = "with-mac_address")))] MacAddress(Option), + + #[cfg(feature = "postgres-range")] + #[cfg_attr(docsrs, doc(cfg(feature = "postgres-range")))] + Range(Option>), } /// This test is to check if the size of [`Value`] exceeds the limit. @@ -495,6 +502,10 @@ impl Value { #[cfg(feature = "with-mac_address")] #[cfg_attr(docsrs, doc(cfg(feature = "with-mac_address")))] Self::MacAddress(_) => Self::MacAddress(None), + + #[cfg(feature = "postgres-range")] + #[cfg_attr(docsrs, doc(cfg(feature = "postgres-range")))] + Self::Range(_) => Self::Range(None), } } @@ -625,6 +636,10 @@ impl Value { #[cfg(feature = "with-mac_address")] #[cfg_attr(docsrs, doc(cfg(feature = "with-mac_address")))] Self::MacAddress(_) => Self::MacAddress(Some(Default::default())), + + #[cfg(feature = "postgres-range")] + #[cfg_attr(docsrs, doc(cfg(feature = "postgres-range")))] + Self::Range(_) => Self::Range(Some(Default::default())), } } } diff --git a/src/value/hashable_value.rs b/src/value/hashable_value.rs index e51a9234d..e53a3d729 100644 --- a/src/value/hashable_value.rs +++ b/src/value/hashable_value.rs @@ -167,6 +167,9 @@ impl Hash for Value { #[cfg(feature = "with-mac_address")] Value::MacAddress(mac_address) => mac_address.hash(state), + + #[cfg(feature = "postgres-range")] + Value::Range(range) => hash_range(range, state), } } } @@ -220,6 +223,19 @@ fn cmp_json(l: &Option, r: &Option) -> bool { } } +#[cfg(feature = "postgres-range")] +fn hash_range( + v: &Option>, + state: &mut H, +) { + match v { + Some(v) => { + v.hash(state); + } + None => "null".hash(state), + } +} + #[cfg(feature = "postgres-vector")] fn hash_vector(v: &Option, state: &mut H) { match v { diff --git a/src/value/with_json.rs b/src/value/with_json.rs index 7b4cf4ba6..aecec00df 100644 --- a/src/value/with_json.rs +++ b/src/value/with_json.rs @@ -48,6 +48,8 @@ pub fn sea_value_to_json_value(value: &Value) -> Json { Value::IpNetwork(None) => Json::Null, #[cfg(feature = "with-mac_address")] Value::MacAddress(None) => Json::Null, + #[cfg(feature = "postgres-range")] + Value::Range(None) => Json::Null, Value::Bool(Some(b)) => Json::Bool(*b), Value::TinyInt(Some(v)) => (*v).into(), Value::SmallInt(Some(v)) => (*v).into(), @@ -113,5 +115,7 @@ pub fn sea_value_to_json_value(value: &Value) -> Json { Value::IpNetwork(Some(_)) => CommonSqlQueryBuilder.value_to_string(value).into(), #[cfg(feature = "with-mac_address")] Value::MacAddress(Some(_)) => CommonSqlQueryBuilder.value_to_string(value).into(), + #[cfg(feature = "postgres-range")] + Value::Range(Some(_)) => CommonSqlQueryBuilder.value_to_string(value).into(), } } diff --git a/tests/common.rs b/tests/common.rs index eb7fc7003..d64e4dd20 100644 --- a/tests/common.rs +++ b/tests/common.rs @@ -1,6 +1,3 @@ -#[cfg(feature = "with-json")] -pub use serde_json::json; - use sea_query::Iden; /// Representation of a database table named `BloB`. diff --git a/tests/mysql/query.rs b/tests/mysql/query.rs index 255a00837..b1415a7c9 100644 --- a/tests/mysql/query.rs +++ b/tests/mysql/query.rs @@ -736,7 +736,7 @@ fn select_48() { .from(Glyph::Table) .cond_where( Cond::all().add_option(Some( - Expr::tuple([Expr::col(Glyph::Aspect).into(), Expr::value(100)]) + Expr::tuple([Expr::col(Glyph::Aspect), Expr::value(100)]) .lt(Expr::tuple([Expr::value(8), Expr::value(100)])), )), ) @@ -755,11 +755,8 @@ fn select_48a() { .from(Glyph::Table) .cond_where( Cond::all().add_option(Some( - Expr::tuple([ - Expr::col(Glyph::Aspect).into(), - Expr::value(String::from("100")), - ]) - .in_tuples([(8, String::from("100"))]), + Expr::tuple([Expr::col(Glyph::Aspect), Expr::value(String::from("100"))]) + .in_tuples([(8, String::from("100"))]), )), ) .to_string(MysqlQueryBuilder); diff --git a/tests/postgres/query.rs b/tests/postgres/query.rs index 575530154..a8fa6778b 100644 --- a/tests/postgres/query.rs +++ b/tests/postgres/query.rs @@ -822,7 +822,7 @@ fn select_48() { .from(Glyph::Table) .cond_where( Cond::all().add_option(Some( - Expr::tuple([Expr::col(Glyph::Aspect).into(), Expr::value(100)]) + Expr::tuple([Expr::col(Glyph::Aspect), Expr::value(100)]) .lt(Expr::tuple([Expr::value(8), Expr::value(100)])), )), ) @@ -841,11 +841,8 @@ fn select_48a() { .from(Glyph::Table) .cond_where( Cond::all().add_option(Some( - Expr::tuple([ - Expr::col(Glyph::Aspect).into(), - Expr::value(String::from("100")), - ]) - .in_tuples([(8, String::from("100"))]), + Expr::tuple([Expr::col(Glyph::Aspect), Expr::value(String::from("100"))]) + .in_tuples([(8, String::from("100"))]), )), ) .to_string(PostgresQueryBuilder); diff --git a/tests/sqlite/query.rs b/tests/sqlite/query.rs index 6bb781920..a82c2d4e6 100644 --- a/tests/sqlite/query.rs +++ b/tests/sqlite/query.rs @@ -737,7 +737,7 @@ fn select_48() { .from(Glyph::Table) .cond_where( Cond::all().add_option(Some( - Expr::tuple([Expr::col(Glyph::Aspect).into(), Expr::value(100)]) + Expr::tuple([Expr::col(Glyph::Aspect), Expr::value(100)]) .lt(Expr::tuple([Expr::value(8), Expr::value(100)])), )), ) @@ -756,11 +756,8 @@ fn select_48a() { .from(Glyph::Table) .cond_where( Cond::all().add_option(Some( - Expr::tuple([ - Expr::col(Glyph::Aspect).into(), - Expr::value(String::from("100")), - ]) - .in_tuples([(8, String::from("100"))]), + Expr::tuple([Expr::col(Glyph::Aspect), Expr::value(String::from("100"))]) + .in_tuples([(8, String::from("100"))]), )), ) .to_string(SqliteQueryBuilder);