diff --git a/sqlx-core/src/decode.rs b/sqlx-core/src/decode.rs index 3249c349cc..081228e958 100644 --- a/sqlx-core/src/decode.rs +++ b/sqlx-core/src/decode.rs @@ -1,5 +1,9 @@ //! Provides [`Decode`] for decoding values from the database. +use std::borrow::Cow; +use std::rc::Rc; +use std::sync::Arc; + use crate::database::Database; use crate::error::BoxDynError; @@ -77,3 +81,78 @@ where } } } + +macro_rules! impl_decode_for_smartpointer { + ($smart_pointer:tt) => { + impl<'r, DB, T> Decode<'r, DB> for $smart_pointer + where + DB: Database, + T: Decode<'r, DB>, + { + fn decode(value: ::ValueRef<'r>) -> Result { + Ok(Self::new(T::decode(value)?)) + } + } + + impl<'r, DB> Decode<'r, DB> for $smart_pointer + where + DB: Database, + &'r str: Decode<'r, DB>, + { + fn decode(value: ::ValueRef<'r>) -> Result { + let ref_str = <&str as Decode>::decode(value)?; + Ok(ref_str.into()) + } + } + + impl<'r, DB> Decode<'r, DB> for $smart_pointer<[u8]> + where + DB: Database, + &'r [u8]: Decode<'r, DB>, + { + fn decode(value: ::ValueRef<'r>) -> Result { + let ref_str = <&[u8] as Decode>::decode(value)?; + Ok(ref_str.into()) + } + } + }; +} + +impl_decode_for_smartpointer!(Arc); +impl_decode_for_smartpointer!(Box); +impl_decode_for_smartpointer!(Rc); + +// implement `Decode` for Cow for all SQL types +impl<'r, DB, T> Decode<'r, DB> for Cow<'_, T> +where + DB: Database, + T: ToOwned, + ::Owned: Decode<'r, DB>, +{ + fn decode(value: ::ValueRef<'r>) -> Result { + let owned = <::Owned as Decode>::decode(value)?; + Ok(Cow::Owned(owned)) + } +} + +impl<'r, DB> Decode<'r, DB> for Cow<'r, str> +where + DB: Database, + &'r str: Decode<'r, DB>, +{ + fn decode(value: ::ValueRef<'r>) -> Result { + let borrowed = <&str as Decode>::decode(value)?; + Ok(Cow::Borrowed(borrowed)) + } +} + +impl<'r, DB> Decode<'r, DB> for Cow<'r, [u8]> +where + DB: Database, + &'r [u8]: Decode<'r, DB>, +{ + fn decode(value: ::ValueRef<'r>) -> Result { + let borrowed = <&[u8] as Decode>::decode(value)?; + Ok(Cow::Borrowed(borrowed)) + } +} diff --git a/sqlx-core/src/encode.rs b/sqlx-core/src/encode.rs index 2d28641f94..d2111de114 100644 --- a/sqlx-core/src/encode.rs +++ b/sqlx-core/src/encode.rs @@ -1,6 +1,9 @@ //! Provides [`Encode`] for encoding values for the database. +use std::borrow::Cow; use std::mem; +use std::rc::Rc; +use std::sync::Arc; use crate::database::Database; use crate::error::BoxDynError; @@ -129,3 +132,96 @@ macro_rules! impl_encode_for_option { } }; } + +macro_rules! impl_encode_for_smartpointer { + ($smart_pointer:ty) => { + impl<'q, T, DB: Database> Encode<'q, DB> for $smart_pointer + where + T: Encode<'q, DB>, + { + #[inline] + fn encode( + self, + buf: &mut ::ArgumentBuffer<'q>, + ) -> Result { + >::encode_by_ref(self.as_ref(), buf) + } + + #[inline] + fn encode_by_ref( + &self, + buf: &mut ::ArgumentBuffer<'q>, + ) -> Result { + <&T as Encode>::encode(self, buf) + } + + #[inline] + fn produces(&self) -> Option { + (**self).produces() + } + + #[inline] + fn size_hint(&self) -> usize { + (**self).size_hint() + } + } + }; +} + +impl_encode_for_smartpointer!(Arc); +impl_encode_for_smartpointer!(Box); +impl_encode_for_smartpointer!(Rc); + +impl<'q, T, DB: Database> Encode<'q, DB> for Cow<'_, T> +where + T: Encode<'q, DB>, + T: ToOwned, +{ + #[inline] + fn encode(self, buf: &mut ::ArgumentBuffer<'q>) -> Result { + <&T as Encode>::encode_by_ref(&self.as_ref(), buf) + } + + #[inline] + fn encode_by_ref( + &self, + buf: &mut ::ArgumentBuffer<'q>, + ) -> Result { + <&T as Encode>::encode_by_ref(&self.as_ref(), buf) + } + + #[inline] + fn produces(&self) -> Option { + <&T as Encode>::produces(&self.as_ref()) + } + + #[inline] + fn size_hint(&self) -> usize { + <&T as Encode>::size_hint(&self.as_ref()) + } +} + +#[macro_export] +macro_rules! forward_encode_impl { + ($for_type:ty, $forward_to:ty, $db:ident) => { + impl<'q> Encode<'q, $db> for $for_type { + fn encode_by_ref( + &self, + buf: &mut <$db as Database>::ArgumentBuffer<'q>, + ) -> Result { + <$forward_to as Encode<$db>>::encode(&**self, buf) + } + } + }; + ($for_type:ty, $forward_to:ty, $db:ident, $before:expr) => { + impl<'q> Encode<'q, $db> for $for_type { + fn encode_by_ref( + &self, + buf: &mut <$db as Database>::ArgumentBuffer<'q>, + ) -> Result { + let value = $before(self); + <$forward_to as Encode<$db>>::encode(value, buf) + } + } + }; +} diff --git a/sqlx-core/src/types/mod.rs b/sqlx-core/src/types/mod.rs index 909dd4927b..1ca6610e23 100644 --- a/sqlx-core/src/types/mod.rs +++ b/sqlx-core/src/types/mod.rs @@ -17,6 +17,8 @@ //! To represent nullable SQL types, `Option` is supported where `T` implements `Type`. //! An `Option` represents a potentially `NULL` value from SQL. +use std::{borrow::Cow, rc::Rc, sync::Arc}; + use crate::database::Database; use crate::type_info::TypeInfo; @@ -241,3 +243,40 @@ impl, DB: Database> Type for Option { ty.is_null() || >::compatible(ty) } } + +macro_rules! impl_type_for_smartpointer { + ($smart_pointer:ty) => { + impl Type for $smart_pointer + where + T: Type, + T: ?Sized, + { + fn type_info() -> DB::TypeInfo { + >::type_info() + } + + fn compatible(ty: &DB::TypeInfo) -> bool { + >::compatible(ty) + } + } + }; +} + +impl_type_for_smartpointer!(Arc); +impl_type_for_smartpointer!(Box); +impl_type_for_smartpointer!(Rc); + +impl Type for Cow<'_, T> +where + T: Type, + T: ToOwned, + T: ?Sized, +{ + fn type_info() -> DB::TypeInfo { + >::type_info() + } + + fn compatible(ty: &DB::TypeInfo) -> bool { + >::compatible(ty) + } +} diff --git a/sqlx-mysql/src/types/bytes.rs b/sqlx-mysql/src/types/bytes.rs index ade079ad4e..943e58ed99 100644 --- a/sqlx-mysql/src/types/bytes.rs +++ b/sqlx-mysql/src/types/bytes.rs @@ -1,3 +1,9 @@ +use std::borrow::Cow; +use std::rc::Rc; +use std::sync::Arc; + +use sqlx_core::database::Database; + use crate::decode::Decode; use crate::encode::{Encode, IsNull}; use crate::error::BoxDynError; @@ -40,28 +46,6 @@ impl<'r> Decode<'r, MySql> for &'r [u8] { } } -impl Type for Box<[u8]> { - fn type_info() -> MySqlTypeInfo { - <&[u8] as Type>::type_info() - } - - fn compatible(ty: &MySqlTypeInfo) -> bool { - <&[u8] as Type>::compatible(ty) - } -} - -impl Encode<'_, MySql> for Box<[u8]> { - fn encode_by_ref(&self, buf: &mut Vec) -> Result { - <&[u8] as Encode>::encode(self.as_ref(), buf) - } -} - -impl<'r> Decode<'r, MySql> for Box<[u8]> { - fn decode(value: MySqlValueRef<'r>) -> Result { - <&[u8] as Decode>::decode(value).map(Box::from) - } -} - impl Type for Vec { fn type_info() -> MySqlTypeInfo { <[u8] as Type>::type_info() @@ -83,3 +67,8 @@ impl Decode<'_, MySql> for Vec { <&[u8] as Decode>::decode(value).map(ToOwned::to_owned) } } + +forward_encode_impl!(Arc<[u8]>, &[u8], MySql); +forward_encode_impl!(Rc<[u8]>, &[u8], MySql); +forward_encode_impl!(Box<[u8]>, &[u8], MySql); +forward_encode_impl!(Cow<'_, [u8]>, &[u8], MySql); diff --git a/sqlx-mysql/src/types/str.rs b/sqlx-mysql/src/types/str.rs index 8233e90893..ffe1ec1afe 100644 --- a/sqlx-mysql/src/types/str.rs +++ b/sqlx-mysql/src/types/str.rs @@ -1,3 +1,9 @@ +use std::borrow::Cow; +use std::rc::Rc; +use std::sync::Arc; + +use sqlx_core::database::Database; + use crate::decode::Decode; use crate::encode::{Encode, IsNull}; use crate::error::BoxDynError; @@ -5,7 +11,6 @@ use crate::io::MySqlBufMutExt; use crate::protocol::text::{ColumnFlags, ColumnType}; use crate::types::Type; use crate::{MySql, MySqlTypeInfo, MySqlValueRef}; -use std::borrow::Cow; impl Type for str { fn type_info() -> MySqlTypeInfo { @@ -46,28 +51,6 @@ impl<'r> Decode<'r, MySql> for &'r str { } } -impl Type for Box { - fn type_info() -> MySqlTypeInfo { - <&str as Type>::type_info() - } - - fn compatible(ty: &MySqlTypeInfo) -> bool { - <&str as Type>::compatible(ty) - } -} - -impl Encode<'_, MySql> for Box { - fn encode_by_ref(&self, buf: &mut Vec) -> Result { - <&str as Encode>::encode(&**self, buf) - } -} - -impl<'r> Decode<'r, MySql> for Box { - fn decode(value: MySqlValueRef<'r>) -> Result { - <&str as Decode>::decode(value).map(Box::from) - } -} - impl Type for String { fn type_info() -> MySqlTypeInfo { >::type_info() @@ -78,39 +61,14 @@ impl Type for String { } } -impl Encode<'_, MySql> for String { - fn encode_by_ref(&self, buf: &mut Vec) -> Result { - <&str as Encode>::encode(&**self, buf) - } -} - impl Decode<'_, MySql> for String { fn decode(value: MySqlValueRef<'_>) -> Result { <&str as Decode>::decode(value).map(ToOwned::to_owned) } } -impl Type for Cow<'_, str> { - fn type_info() -> MySqlTypeInfo { - <&str as Type>::type_info() - } - - fn compatible(ty: &MySqlTypeInfo) -> bool { - <&str as Type>::compatible(ty) - } -} - -impl Encode<'_, MySql> for Cow<'_, str> { - fn encode_by_ref(&self, buf: &mut Vec) -> Result { - match self { - Cow::Borrowed(str) => <&str as Encode>::encode(*str, buf), - Cow::Owned(str) => <&str as Encode>::encode(&**str, buf), - } - } -} - -impl<'r> Decode<'r, MySql> for Cow<'r, str> { - fn decode(value: MySqlValueRef<'r>) -> Result { - value.as_str().map(Cow::Borrowed) - } -} +forward_encode_impl!(Arc, &str, MySql); +forward_encode_impl!(Rc, &str, MySql); +forward_encode_impl!(Cow<'_, str>, &str, MySql); +forward_encode_impl!(Box, &str, MySql); +forward_encode_impl!(String, &str, MySql); diff --git a/sqlx-postgres/src/types/bytes.rs b/sqlx-postgres/src/types/bytes.rs index 45968837af..a5c88e3fae 100644 --- a/sqlx-postgres/src/types/bytes.rs +++ b/sqlx-postgres/src/types/bytes.rs @@ -1,3 +1,9 @@ +use std::borrow::Cow; +use std::rc::Rc; +use std::sync::Arc; + +use sqlx_core::database::Database; + use crate::decode::Decode; use crate::encode::{Encode, IsNull}; use crate::error::BoxDynError; @@ -42,12 +48,6 @@ impl Encode<'_, Postgres> for &'_ [u8] { } } -impl Encode<'_, Postgres> for Box<[u8]> { - fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result { - <&[u8] as Encode>::encode(self.as_ref(), buf) - } -} - impl Encode<'_, Postgres> for Vec { fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result { <&[u8] as Encode>::encode(self, buf) @@ -80,15 +80,6 @@ fn text_hex_decode_input(value: PgValueRef<'_>) -> Result<&[u8], BoxDynError> { .map_err(Into::into) } -impl Decode<'_, Postgres> for Box<[u8]> { - fn decode(value: PgValueRef<'_>) -> Result { - Ok(match value.format() { - PgValueFormat::Binary => Box::from(value.as_bytes()?), - PgValueFormat::Text => Box::from(hex::decode(text_hex_decode_input(value)?)?), - }) - } -} - impl Decode<'_, Postgres> for Vec { fn decode(value: PgValueRef<'_>) -> Result { Ok(match value.format() { @@ -110,3 +101,8 @@ impl Decode<'_, Postgres> for [u8; N] { Ok(bytes) } } + +forward_encode_impl!(Arc<[u8]>, &[u8], Postgres); +forward_encode_impl!(Rc<[u8]>, &[u8], Postgres); +forward_encode_impl!(Box<[u8]>, &[u8], Postgres); +forward_encode_impl!(Cow<'_, [u8]>, &[u8], Postgres); diff --git a/sqlx-postgres/src/types/str.rs b/sqlx-postgres/src/types/str.rs index ca7e20a558..a50b142aa7 100644 --- a/sqlx-postgres/src/types/str.rs +++ b/sqlx-postgres/src/types/str.rs @@ -1,3 +1,5 @@ +use sqlx_core::database::Database; + use crate::decode::Decode; use crate::encode::{Encode, IsNull}; use crate::error::BoxDynError; @@ -5,6 +7,8 @@ use crate::types::array_compatible; use crate::types::Type; use crate::{PgArgumentBuffer, PgHasArrayType, PgTypeInfo, PgValueRef, Postgres}; use std::borrow::Cow; +use std::rc::Rc; +use std::sync::Arc; impl Type for str { fn type_info() -> PgTypeInfo { @@ -24,26 +28,6 @@ impl Type for str { } } -impl Type for Cow<'_, str> { - fn type_info() -> PgTypeInfo { - <&str as Type>::type_info() - } - - fn compatible(ty: &PgTypeInfo) -> bool { - <&str as Type>::compatible(ty) - } -} - -impl Type for Box { - fn type_info() -> PgTypeInfo { - <&str as Type>::type_info() - } - - fn compatible(ty: &PgTypeInfo) -> bool { - <&str as Type>::compatible(ty) - } -} - impl Type for String { fn type_info() -> PgTypeInfo { <&str as Type>::type_info() @@ -102,47 +86,20 @@ impl Encode<'_, Postgres> for &'_ str { } } -impl Encode<'_, Postgres> for Cow<'_, str> { - fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result { - match self { - Cow::Borrowed(str) => <&str as Encode>::encode(*str, buf), - Cow::Owned(str) => <&str as Encode>::encode(&**str, buf), - } - } -} - -impl Encode<'_, Postgres> for Box { - fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result { - <&str as Encode>::encode(&**self, buf) - } -} - -impl Encode<'_, Postgres> for String { - fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result { - <&str as Encode>::encode(&**self, buf) - } -} - impl<'r> Decode<'r, Postgres> for &'r str { fn decode(value: PgValueRef<'r>) -> Result { value.as_str() } } -impl<'r> Decode<'r, Postgres> for Cow<'r, str> { - fn decode(value: PgValueRef<'r>) -> Result { - Ok(Cow::Borrowed(value.as_str()?)) - } -} - -impl<'r> Decode<'r, Postgres> for Box { - fn decode(value: PgValueRef<'r>) -> Result { - Ok(Box::from(value.as_str()?)) - } -} - impl Decode<'_, Postgres> for String { fn decode(value: PgValueRef<'_>) -> Result { Ok(value.as_str()?.to_owned()) } } + +forward_encode_impl!(Arc, &str, Postgres); +forward_encode_impl!(Rc, &str, Postgres); +forward_encode_impl!(Cow<'_, str>, &str, Postgres); +forward_encode_impl!(Box, &str, Postgres); +forward_encode_impl!(String, &str, Postgres); diff --git a/sqlx-sqlite/src/types/bytes.rs b/sqlx-sqlite/src/types/bytes.rs index f854b911c5..07ef89c4bb 100644 --- a/sqlx-sqlite/src/types/bytes.rs +++ b/sqlx-sqlite/src/types/bytes.rs @@ -1,4 +1,8 @@ use std::borrow::Cow; +use std::rc::Rc; +use std::sync::Arc; + +use sqlx_core::database::Database; use crate::decode::Decode; use crate::encode::{Encode, IsNull}; @@ -34,41 +38,6 @@ impl<'r> Decode<'r, Sqlite> for &'r [u8] { } } -impl Type for Box<[u8]> { - fn type_info() -> SqliteTypeInfo { - <&[u8] as Type>::type_info() - } - - fn compatible(ty: &SqliteTypeInfo) -> bool { - <&[u8] as Type>::compatible(ty) - } -} - -impl Encode<'_, Sqlite> for Box<[u8]> { - fn encode(self, args: &mut Vec>) -> Result { - args.push(SqliteArgumentValue::Blob(Cow::Owned(self.into_vec()))); - - Ok(IsNull::No) - } - - fn encode_by_ref( - &self, - args: &mut Vec>, - ) -> Result { - args.push(SqliteArgumentValue::Blob(Cow::Owned( - self.clone().into_vec(), - ))); - - Ok(IsNull::No) - } -} - -impl Decode<'_, Sqlite> for Box<[u8]> { - fn decode(value: SqliteValueRef<'_>) -> Result { - Ok(Box::from(value.blob())) - } -} - impl Type for Vec { fn type_info() -> SqliteTypeInfo { <&[u8] as Type>::type_info() @@ -101,3 +70,8 @@ impl<'r> Decode<'r, Sqlite> for Vec { Ok(value.blob().to_owned()) } } + +forward_encode_impl!(Arc<[u8]>, Vec, Sqlite, |v: &[u8]| v.to_vec()); +forward_encode_impl!(Rc<[u8]>, Vec, Sqlite, |v: &[u8]| v.to_vec()); +forward_encode_impl!(Box<[u8]>, Vec, Sqlite, |v: &[u8]| v.to_vec()); +forward_encode_impl!(Cow<'_, [u8]>, Vec, Sqlite, |v: &[u8]| v.to_vec()); diff --git a/sqlx-sqlite/src/types/str.rs b/sqlx-sqlite/src/types/str.rs index bfaffae78e..b627d27fdc 100644 --- a/sqlx-sqlite/src/types/str.rs +++ b/sqlx-sqlite/src/types/str.rs @@ -1,4 +1,8 @@ use std::borrow::Cow; +use std::rc::Rc; +use std::sync::Arc; + +use sqlx_core::database::Database; use crate::decode::Decode; use crate::encode::{Encode, IsNull}; @@ -30,50 +34,19 @@ impl<'r> Decode<'r, Sqlite> for &'r str { } } -impl Type for Box { +impl Type for String { fn type_info() -> SqliteTypeInfo { <&str as Type>::type_info() } } -impl Encode<'_, Sqlite> for Box { - fn encode(self, args: &mut Vec>) -> Result { - args.push(SqliteArgumentValue::Text(Cow::Owned(self.into_string()))); - - Ok(IsNull::No) - } - - fn encode_by_ref( - &self, - args: &mut Vec>, - ) -> Result { - args.push(SqliteArgumentValue::Text(Cow::Owned( - self.clone().into_string(), - ))); - - Ok(IsNull::No) - } -} - -impl Decode<'_, Sqlite> for Box { - fn decode(value: SqliteValueRef<'_>) -> Result { - value.text().map(Box::from) - } -} - -impl Type for String { - fn type_info() -> SqliteTypeInfo { - <&str as Type>::type_info() +impl<'r> Decode<'r, Sqlite> for String { + fn decode(value: SqliteValueRef<'r>) -> Result { + value.text().map(ToOwned::to_owned) } } impl<'q> Encode<'q, Sqlite> for String { - fn encode(self, args: &mut Vec>) -> Result { - args.push(SqliteArgumentValue::Text(Cow::Owned(self))); - - Ok(IsNull::No) - } - fn encode_by_ref( &self, args: &mut Vec>, @@ -82,43 +55,21 @@ impl<'q> Encode<'q, Sqlite> for String { Ok(IsNull::No) } -} - -impl<'r> Decode<'r, Sqlite> for String { - fn decode(value: SqliteValueRef<'r>) -> Result { - value.text().map(ToOwned::to_owned) - } -} - -impl Type for Cow<'_, str> { - fn type_info() -> SqliteTypeInfo { - <&str as Type>::type_info() - } - - fn compatible(ty: &SqliteTypeInfo) -> bool { - <&str as Type>::compatible(ty) - } -} - -impl<'q> Encode<'q, Sqlite> for Cow<'q, str> { - fn encode(self, args: &mut Vec>) -> Result { - args.push(SqliteArgumentValue::Text(self)); - - Ok(IsNull::No) - } - fn encode_by_ref( - &self, - args: &mut Vec>, - ) -> Result { - args.push(SqliteArgumentValue::Text(self.clone())); + fn encode( + self, + buf: &mut ::ArgumentBuffer<'q>, + ) -> Result + where + Self: Sized, + { + buf.push(SqliteArgumentValue::Text(Cow::Owned(self))); Ok(IsNull::No) } } -impl<'r> Decode<'r, Sqlite> for Cow<'r, str> { - fn decode(value: SqliteValueRef<'r>) -> Result { - value.text().map(Cow::Borrowed) - } -} +forward_encode_impl!(Arc, String, Sqlite, |s: &str| s.to_string()); +forward_encode_impl!(Rc, String, Sqlite, |s: &str| s.to_string()); +forward_encode_impl!(Cow<'_, str>, String, Sqlite, |s: &str| s.to_string()); +forward_encode_impl!(Box, String, Sqlite, |s: &str| s.to_string()); diff --git a/tests/mysql/types.rs b/tests/mysql/types.rs index e837a53f75..acb761b352 100644 --- a/tests/mysql/types.rs +++ b/tests/mysql/types.rs @@ -1,8 +1,11 @@ extern crate time_ as time; +use std::borrow::Cow; use std::net::SocketAddr; +use std::rc::Rc; #[cfg(feature = "rust_decimal")] use std::str::FromStr; +use std::sync::Arc; use sqlx::mysql::MySql; use sqlx::{Executor, Row}; @@ -12,7 +15,7 @@ use sqlx::types::Text; use sqlx::mysql::types::MySqlTime; use sqlx_mysql::types::MySqlTimeSign; -use sqlx_test::{new, test_type}; +use sqlx_test::{new, test_prepared_type, test_type}; test_type!(bool(MySql, "false" == false, "true" == true)); @@ -300,6 +303,21 @@ mod json_tests { )); } +test_type!(test_arc>(MySql, "1" == Arc::new(1i32))); +test_type!(test_cow>(MySql, "1" == Cow::::Owned(1i32))); +test_type!(test_box>(MySql, "1" == Box::new(1i32))); +test_type!(test_rc>(MySql, "1" == Rc::new(1i32))); + +test_type!(test_box_str>(MySql, "'John'" == Box::::from("John"))); +test_type!(test_cow_str>(MySql, "'Phil'" == Cow::<'static, str>::from("Phil"))); +test_type!(test_arc_str>(MySql, "'John'" == Arc::::from("John"))); +test_type!(test_rc_str>(MySql, "'Phil'" == Rc::::from("Phil"))); + +test_prepared_type!(test_box_slice>(MySql, "X'01020304'" == Box::<[u8]>::from([1,2,3,4]))); +test_prepared_type!(test_cow_slice>(MySql, "X'01020304'" == Cow::<'static, [u8]>::from(&[1,2,3,4]))); +test_prepared_type!(test_arc_slice>(MySql, "X'01020304'" == Arc::<[u8]>::from([1,2,3,4]))); +test_prepared_type!(test_rc_slice>(MySql, "X'01020304'" == Rc::<[u8]>::from([1,2,3,4]))); + #[sqlx_macros::test] async fn test_bits() -> anyhow::Result<()> { let mut conn = new::().await?; diff --git a/tests/postgres/types.rs b/tests/postgres/types.rs index da20467ea3..b66f322e7b 100644 --- a/tests/postgres/types.rs +++ b/tests/postgres/types.rs @@ -1,7 +1,10 @@ extern crate time_ as time; +use std::borrow::Cow; use std::net::SocketAddr; use std::ops::Bound; +use std::rc::Rc; +use std::sync::Arc; use sqlx::postgres::types::{Oid, PgCiText, PgInterval, PgMoney, PgRange}; use sqlx::postgres::Postgres; @@ -653,6 +656,21 @@ test_type!(ltree_vec>(Postgres, ] )); +test_type!(test_arc>(Postgres, "1::INT4" == Arc::new(1i32))); +test_type!(test_cow>(Postgres, "1::INT4" == Cow::::Owned(1i32))); +test_type!(test_box>(Postgres, "1::INT4" == Box::new(1i32))); +test_type!(test_rc>(Postgres, "1::INT4" == Rc::new(1i32))); + +test_type!(test_box_str>(Postgres, "'John'::TEXT" == Box::::from("John"))); +test_type!(test_cow_str>(Postgres, "'Phil'::TEXT" == Cow::<'static, str>::from("Phil"))); +test_type!(test_arc_str>(Postgres, "'John'::TEXT" == Arc::::from("John"))); +test_type!(test_rc_str>(Postgres, "'John'::TEXT" == Rc::::from("John"))); + +test_prepared_type!(test_box_slice>(Postgres, "'\\x01020304'::BYTEA" == Box::<[u8]>::from([1,2,3,4]))); +test_prepared_type!(test_cow_slice>(Postgres, "'\\x01020304'::BYTEA" == Cow::<'static, [u8]>::from(&[1,2,3,4]))); +test_prepared_type!(test_arc_slice>(Postgres, "'\\x01020304'::BYTEA" == Arc::<[u8]>::from([1,2,3,4]))); +test_prepared_type!(test_rc_slice>(Postgres, "'\\x01020304'::BYTEA" == Rc::<[u8]>::from([1,2,3,4]))); + #[sqlx_macros::test] async fn test_text_adapter() -> anyhow::Result<()> { #[derive(sqlx::FromRow, Debug, PartialEq, Eq)] diff --git a/tests/sqlite/types.rs b/tests/sqlite/types.rs index 2497e406cc..a42ec07bd5 100644 --- a/tests/sqlite/types.rs +++ b/tests/sqlite/types.rs @@ -6,7 +6,10 @@ use sqlx_core::row::Row; use sqlx_core::types::Text; use sqlx_test::new; use sqlx_test::test_type; +use std::borrow::Cow; use std::net::SocketAddr; +use std::rc::Rc; +use std::sync::Arc; test_type!(null>(Sqlite, "NULL" == None:: @@ -208,6 +211,21 @@ test_type!(uuid_simple(Sqlite, == sqlx::types::Uuid::parse_str("00000000000000000000000000000000").unwrap().simple() )); +test_type!(test_arc>(Sqlite, "1" == Arc::new(1i32))); +test_type!(test_cow>(Sqlite, "1" == Cow::::Owned(1i32))); +test_type!(test_box>(Sqlite, "1" == Box::new(1i32))); +test_type!(test_rc>(Sqlite, "1" == Rc::new(1i32))); + +test_type!(test_box_str>(Sqlite, "'John'" == Box::::from("John"))); +test_type!(test_cow_str>(Sqlite, "'Phil'" == Cow::<'static, str>::from("Phil"))); +test_type!(test_arc_str>(Sqlite, "'John'" == Arc::::from("John"))); +test_type!(test_rc_str>(Sqlite, "'John'" == Rc::::from("John"))); + +test_type!(test_box_slice>(Sqlite, "X'01020304'" == Box::<[u8]>::from([1,2,3,4]))); +test_type!(test_cow_slice>(Sqlite, "X'01020304'" == Cow::<'static, [u8]>::from(&[1,2,3,4]))); +test_type!(test_arc_slice>(Sqlite, "X'01020304'" == Arc::<[u8]>::from([1,2,3,4]))); +test_type!(test_rc_slice>(Sqlite, "X'01020304'" == Rc::<[u8]>::from([1,2,3,4]))); + #[sqlx_macros::test] async fn test_text_adapter() -> anyhow::Result<()> { #[derive(sqlx::FromRow, Debug, PartialEq, Eq)]