diff --git a/sqlx-core/src/decode.rs b/sqlx-core/src/decode.rs index 82e14d0d..90b75534 100644 --- a/sqlx-core/src/decode.rs +++ b/sqlx-core/src/decode.rs @@ -2,7 +2,6 @@ use crate::database::{Database, HasValueRef}; use crate::error::BoxDynError; -use crate::value::ValueRef; /// A type that can be decoded from the database. /// @@ -62,17 +61,24 @@ pub trait Decode<'r, DB: Database>: Sized { fn decode(value: >::ValueRef) -> Result; } -// implement `Decode` for Option for all SQL types -impl<'r, DB, T> Decode<'r, DB> for Option -where - DB: Database, - T: Decode<'r, DB>, -{ - fn decode(value: >::ValueRef) -> Result { - if value.is_null() { - Ok(None) - } else { - Ok(Some(T::decode(value)?)) +#[allow(unused_macros)] +macro_rules! impl_decode_for_option { + ($DB:ident) => { + impl<'r, T> crate::decode::Decode<'r, $DB> for Option + where + T: crate::decode::Decode<'r, $DB>, + { + fn decode( + value: <$DB as crate::database::HasValueRef<'r>>::ValueRef, + ) -> Result { + use crate::value::ValueRef; + + if value.is_null() { + Ok(None) + } else { + Ok(Some(T::decode(value)?)) + } + } } - } + }; } diff --git a/sqlx-core/src/encode.rs b/sqlx-core/src/encode.rs index ba439263..1608a4bf 100644 --- a/sqlx-core/src/encode.rs +++ b/sqlx-core/src/encode.rs @@ -45,31 +45,44 @@ pub trait Encode<'q, DB: Database> { } } -impl<'q, T, DB: Database> Encode<'q, DB> for &'_ T -where - T: Encode<'q, DB>, -{ - #[inline] - fn encode(self, buf: &mut >::ArgumentBuffer) -> IsNull { - >::encode_by_ref(self, buf) - } +// de-generified using macros because Any doesn't want this +#[allow(unused_macros)] +macro_rules! impl_encode_for_ref { + ($DB:ident) => { + impl<'q, T> crate::encode::Encode<'q, $DB> for &'_ T + where + T: crate::encode::Encode<'q, $DB>, + { + #[inline] + fn encode( + self, + buf: &mut <$DB as crate::database::HasArguments<'q>>::ArgumentBuffer, + ) -> crate::encode::IsNull { + >::encode_by_ref(self, buf) + } - #[inline] - fn encode_by_ref(&self, buf: &mut >::ArgumentBuffer) -> IsNull { - <&T as Encode>::encode(self, buf) - } + #[inline] + fn encode_by_ref( + &self, + buf: &mut <$DB as crate::database::HasArguments<'q>>::ArgumentBuffer, + ) -> crate::encode::IsNull { + <&T as crate::encode::Encode<$DB>>::encode(self, buf) + } - #[inline] - fn produces(&self) -> Option { - (**self).produces() - } + #[inline] + fn produces(&self) -> Option<<$DB as crate::database::Database>::TypeInfo> { + (**self).produces() + } - #[inline] - fn size_hint(&self) -> usize { - (**self).size_hint() - } + #[inline] + fn size_hint(&self) -> usize { + (**self).size_hint() + } + } + }; } +// de-generified using macros because MSSQL has a different concept of how nullable encoding works #[allow(unused_macros)] macro_rules! impl_encode_for_option { ($DB:ident) => { diff --git a/sqlx-core/src/mssql/mod.rs b/sqlx-core/src/mssql/mod.rs index 9708f229..1c2acbe0 100644 --- a/sqlx-core/src/mssql/mod.rs +++ b/sqlx-core/src/mssql/mod.rs @@ -31,5 +31,10 @@ impl_into_arguments_for_arguments!(MssqlArguments); impl_executor_for_pool_connection!(Mssql, MssqlConnection, MssqlRow); impl_executor_for_transaction!(Mssql, MssqlRow); +// required because of `Any` +impl_type_for_ref_and_option!(Mssql); +impl_encode_for_ref!(Mssql); +impl_decode_for_option!(Mssql); + // FIXME: RPC NULL parameter values / results // FIXME: RPC Empty String parameter values diff --git a/sqlx-core/src/mysql/mod.rs b/sqlx-core/src/mysql/mod.rs index 64a5bbba..9d5ae5b4 100644 --- a/sqlx-core/src/mysql/mod.rs +++ b/sqlx-core/src/mysql/mod.rs @@ -31,6 +31,11 @@ impl_into_arguments_for_arguments!(MySqlArguments); impl_executor_for_pool_connection!(MySql, MySqlConnection, MySqlRow); impl_executor_for_transaction!(MySql, MySqlRow); +// required because of `Any` +impl_type_for_ref_and_option!(MySql); +impl_encode_for_ref!(MySql); +impl_decode_for_option!(MySql); + // required because some databases have a different handling // of NULL impl_encode_for_option!(MySql); diff --git a/sqlx-core/src/mysql/types/bytes.rs b/sqlx-core/src/mysql/types/bytes.rs index 1426425a..2758eb56 100644 --- a/sqlx-core/src/mysql/types/bytes.rs +++ b/sqlx-core/src/mysql/types/bytes.rs @@ -46,7 +46,7 @@ impl Type for Vec { } fn compatible(ty: &MySqlTypeInfo) -> bool { - <&[u8] as Type>::compatible(ty) + <[u8] as Type>::compatible(ty) } } diff --git a/sqlx-core/src/postgres/mod.rs b/sqlx-core/src/postgres/mod.rs index c49cc7a6..02435311 100644 --- a/sqlx-core/src/postgres/mod.rs +++ b/sqlx-core/src/postgres/mod.rs @@ -34,6 +34,11 @@ impl_into_arguments_for_arguments!(PgArguments); impl_executor_for_pool_connection!(Postgres, PgConnection, PgRow); impl_executor_for_transaction!(Postgres, PgRow); +// required because of `Any` +impl_type_for_ref_and_option!(Postgres); +impl_encode_for_ref!(Postgres); +impl_decode_for_option!(Postgres); + // required because some databases have a different handling // of NULL impl_encode_for_option!(Postgres); diff --git a/sqlx-core/src/postgres/types/array.rs b/sqlx-core/src/postgres/types/array.rs index 9dedfa03..91574edb 100644 --- a/sqlx-core/src/postgres/types/array.rs +++ b/sqlx-core/src/postgres/types/array.rs @@ -37,7 +37,6 @@ impl<'q, T> Encode<'q, Postgres> for Vec where for<'a> &'a [T]: Encode<'q, Postgres>, T: Encode<'q, Postgres>, - Self: Type, { #[inline] fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> IsNull { @@ -48,7 +47,6 @@ where impl<'q, T> Encode<'q, Postgres> for &'_ [T] where T: Encode<'q, Postgres> + Type, - Self: Type, { fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> IsNull { buf.extend(&1_i32.to_be_bytes()); // number of dimensions @@ -77,7 +75,6 @@ where impl<'r, T> Decode<'r, Postgres> for Vec where T: for<'a> Decode<'a, Postgres> + Type, - Self: Type, { fn decode(value: PgValueRef<'r>) -> Result { let element_type_info = T::type_info(); diff --git a/sqlx-core/src/postgres/types/mod.rs b/sqlx-core/src/postgres/types/mod.rs index b65c29d4..490da6f4 100644 --- a/sqlx-core/src/postgres/types/mod.rs +++ b/sqlx-core/src/postgres/types/mod.rs @@ -171,7 +171,7 @@ pub use range::PgRange; pub use record::{PgRecordDecoder, PgRecordEncoder}; // Type::compatible impl appropriate for arrays -fn array_compatible>(ty: &PgTypeInfo) -> bool { +fn array_compatible>(ty: &PgTypeInfo) -> bool { // we require the declared type to be an _array_ with an // element type that is acceptable if let PgTypeKind::Array(element) = &ty.kind() { diff --git a/sqlx-core/src/postgres/types/str.rs b/sqlx-core/src/postgres/types/str.rs index 3607a4b8..4d56730b 100644 --- a/sqlx-core/src/postgres/types/str.rs +++ b/sqlx-core/src/postgres/types/str.rs @@ -28,7 +28,7 @@ impl Type for [&'_ str] { } fn compatible(ty: &PgTypeInfo) -> bool { - array_compatible::<&str>(ty) + array_compatible::(ty) } } @@ -64,11 +64,11 @@ impl<'r> Decode<'r, Postgres> for &'r str { impl Type for String { fn type_info() -> PgTypeInfo { - <&str as Type>::type_info() + >::type_info() } fn compatible(ty: &PgTypeInfo) -> bool { - <&str as Type>::compatible(ty) + >::compatible(ty) } } diff --git a/sqlx-core/src/sqlite/mod.rs b/sqlx-core/src/sqlite/mod.rs index bb25f45f..e029337c 100644 --- a/sqlx-core/src/sqlite/mod.rs +++ b/sqlx-core/src/sqlite/mod.rs @@ -35,6 +35,11 @@ impl_into_arguments_for_arguments!(SqliteArguments<'q>); impl_executor_for_pool_connection!(Sqlite, SqliteConnection, SqliteRow); impl_executor_for_transaction!(Sqlite, SqliteRow); +// required because of `Any` +impl_type_for_ref_and_option!(Sqlite); +impl_encode_for_ref!(Sqlite); +impl_decode_for_option!(Sqlite); + // required because some databases have a different handling // of NULL impl_encode_for_option!(Sqlite); diff --git a/sqlx-core/src/sqlite/types/bytes.rs b/sqlx-core/src/sqlite/types/bytes.rs index f3c97296..949aa0ee 100644 --- a/sqlx-core/src/sqlite/types/bytes.rs +++ b/sqlx-core/src/sqlite/types/bytes.rs @@ -29,7 +29,7 @@ impl<'r> Decode<'r, Sqlite> for &'r [u8] { impl Type for Vec { fn type_info() -> SqliteTypeInfo { - <&[u8] as Type>::type_info() + <[u8] as Type>::type_info() } } diff --git a/sqlx-core/src/sqlite/types/str.rs b/sqlx-core/src/sqlite/types/str.rs index 6a3ed533..f9de2eb2 100644 --- a/sqlx-core/src/sqlite/types/str.rs +++ b/sqlx-core/src/sqlite/types/str.rs @@ -29,7 +29,7 @@ impl<'r> Decode<'r, Sqlite> for &'r str { impl Type for String { fn type_info() -> SqliteTypeInfo { - <&str as Type>::type_info() + >::type_info() } } diff --git a/sqlx-core/src/types/mod.rs b/sqlx-core/src/types/mod.rs index 18e18423..0d6ddb13 100644 --- a/sqlx-core/src/types/mod.rs +++ b/sqlx-core/src/types/mod.rs @@ -69,24 +69,30 @@ pub trait Type { } } -// for references, the underlying SQL type is identical -impl, DB: Database> Type for &'_ T { - fn type_info() -> DB::TypeInfo { - >::type_info() - } +// de-generified using macros because Any doesn't want this +#[allow(unused_macros)] +macro_rules! impl_type_for_ref_and_option { + ($DB:ident) => { + // for references, the underlying SQL type is identical + impl> crate::types::Type<$DB> for &'_ T { + fn type_info() -> <$DB as crate::database::Database>::TypeInfo { + >::type_info() + } - fn compatible(ty: &DB::TypeInfo) -> bool { - >::compatible(ty) - } -} - -// for optionals, the underlying SQL type is identical -impl, DB: Database> Type for Option { - fn type_info() -> DB::TypeInfo { - >::type_info() - } - - fn compatible(ty: &DB::TypeInfo) -> bool { - >::compatible(ty) - } + fn compatible(ty: &<$DB as crate::database::Database>::TypeInfo) -> bool { + >::compatible(ty) + } + } + + // for optionals, the underlying SQL type is identical + impl> crate::types::Type<$DB> for Option { + fn type_info() -> <$DB as crate::database::Database>::TypeInfo { + >::type_info() + } + + fn compatible(ty: &<$DB as crate::database::Database>::TypeInfo) -> bool { + >::compatible(ty) + } + } + }; }