Revert "refactor: remove several blanket impls to allow more customization"

This reverts commit eb26e9f557.
This commit is contained in:
Ryan Leckey
2020-06-27 18:54:50 -07:00
parent f9d961ae1d
commit 0b34545608
13 changed files with 62 additions and 104 deletions

View File

@@ -2,6 +2,7 @@
use crate::database::{Database, HasValueRef}; use crate::database::{Database, HasValueRef};
use crate::error::BoxDynError; use crate::error::BoxDynError;
use crate::value::ValueRef;
/// A type that can be decoded from the database. /// A type that can be decoded from the database.
/// ///
@@ -61,24 +62,17 @@ pub trait Decode<'r, DB: Database>: Sized {
fn decode(value: <DB as HasValueRef<'r>>::ValueRef) -> Result<Self, BoxDynError>; fn decode(value: <DB as HasValueRef<'r>>::ValueRef) -> Result<Self, BoxDynError>;
} }
#[allow(unused_macros)] // implement `Decode` for Option<T> for all SQL types
macro_rules! impl_decode_for_option { impl<'r, DB, T> Decode<'r, DB> for Option<T>
($DB:ident) => { where
impl<'r, T> crate::decode::Decode<'r, $DB> for Option<T> DB: Database,
where T: Decode<'r, DB>,
T: crate::decode::Decode<'r, $DB>, {
{ fn decode(value: <DB as HasValueRef<'r>>::ValueRef) -> Result<Self, BoxDynError> {
fn decode( if value.is_null() {
value: <$DB as crate::database::HasValueRef<'r>>::ValueRef, Ok(None)
) -> Result<Self, crate::error::BoxDynError> { } else {
use crate::value::ValueRef; Ok(Some(T::decode(value)?))
if value.is_null() {
Ok(None)
} else {
Ok(Some(T::decode(value)?))
}
}
} }
}; }
} }

View File

@@ -45,44 +45,31 @@ pub trait Encode<'q, DB: Database> {
} }
} }
// de-generified using macros because Any doesn't want this impl<'q, T, DB: Database> Encode<'q, DB> for &'_ T
#[allow(unused_macros)] where
macro_rules! impl_encode_for_ref { T: Encode<'q, DB>,
($DB:ident) => { {
impl<'q, T> crate::encode::Encode<'q, $DB> for &'_ T #[inline]
where fn encode(self, buf: &mut <DB as HasArguments<'q>>::ArgumentBuffer) -> IsNull {
T: crate::encode::Encode<'q, $DB>, <T as Encode<DB>>::encode_by_ref(self, buf)
{ }
#[inline]
fn encode(
self,
buf: &mut <$DB as crate::database::HasArguments<'q>>::ArgumentBuffer,
) -> crate::encode::IsNull {
<T as crate::encode::Encode<$DB>>::encode_by_ref(self, buf)
}
#[inline] #[inline]
fn encode_by_ref( fn encode_by_ref(&self, buf: &mut <DB as HasArguments<'q>>::ArgumentBuffer) -> IsNull {
&self, <&T as Encode<DB>>::encode(self, buf)
buf: &mut <$DB as crate::database::HasArguments<'q>>::ArgumentBuffer, }
) -> crate::encode::IsNull {
<&T as crate::encode::Encode<$DB>>::encode(self, buf)
}
#[inline] #[inline]
fn produces(&self) -> Option<<$DB as crate::database::Database>::TypeInfo> { fn produces(&self) -> Option<DB::TypeInfo> {
(**self).produces() (**self).produces()
} }
#[inline] #[inline]
fn size_hint(&self) -> usize { fn size_hint(&self) -> usize {
(**self).size_hint() (**self).size_hint()
} }
}
};
} }
// de-generified using macros because MSSQL has a different concept of how nullable encoding works
#[allow(unused_macros)] #[allow(unused_macros)]
macro_rules! impl_encode_for_option { macro_rules! impl_encode_for_option {
($DB:ident) => { ($DB:ident) => {

View File

@@ -31,10 +31,5 @@ impl_into_arguments_for_arguments!(MssqlArguments);
impl_executor_for_pool_connection!(Mssql, MssqlConnection, MssqlRow); impl_executor_for_pool_connection!(Mssql, MssqlConnection, MssqlRow);
impl_executor_for_transaction!(Mssql, 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 NULL parameter values / results
// FIXME: RPC Empty String parameter values // FIXME: RPC Empty String parameter values

View File

@@ -31,11 +31,6 @@ impl_into_arguments_for_arguments!(MySqlArguments);
impl_executor_for_pool_connection!(MySql, MySqlConnection, MySqlRow); impl_executor_for_pool_connection!(MySql, MySqlConnection, MySqlRow);
impl_executor_for_transaction!(MySql, 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 // required because some databases have a different handling
// of NULL // of NULL
impl_encode_for_option!(MySql); impl_encode_for_option!(MySql);

View File

@@ -46,7 +46,7 @@ impl Type<MySql> for Vec<u8> {
} }
fn compatible(ty: &MySqlTypeInfo) -> bool { fn compatible(ty: &MySqlTypeInfo) -> bool {
<[u8] as Type<MySql>>::compatible(ty) <&[u8] as Type<MySql>>::compatible(ty)
} }
} }

View File

@@ -34,11 +34,6 @@ impl_into_arguments_for_arguments!(PgArguments);
impl_executor_for_pool_connection!(Postgres, PgConnection, PgRow); impl_executor_for_pool_connection!(Postgres, PgConnection, PgRow);
impl_executor_for_transaction!(Postgres, 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 // required because some databases have a different handling
// of NULL // of NULL
impl_encode_for_option!(Postgres); impl_encode_for_option!(Postgres);

View File

@@ -37,6 +37,7 @@ impl<'q, T> Encode<'q, Postgres> for Vec<T>
where where
for<'a> &'a [T]: Encode<'q, Postgres>, for<'a> &'a [T]: Encode<'q, Postgres>,
T: Encode<'q, Postgres>, T: Encode<'q, Postgres>,
Self: Type<Postgres>,
{ {
#[inline] #[inline]
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> IsNull { fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> IsNull {
@@ -47,6 +48,7 @@ where
impl<'q, T> Encode<'q, Postgres> for &'_ [T] impl<'q, T> Encode<'q, Postgres> for &'_ [T]
where where
T: Encode<'q, Postgres> + Type<Postgres>, T: Encode<'q, Postgres> + Type<Postgres>,
Self: Type<Postgres>,
{ {
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> IsNull { fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> IsNull {
buf.extend(&1_i32.to_be_bytes()); // number of dimensions buf.extend(&1_i32.to_be_bytes()); // number of dimensions
@@ -75,6 +77,7 @@ where
impl<'r, T> Decode<'r, Postgres> for Vec<T> impl<'r, T> Decode<'r, Postgres> for Vec<T>
where where
T: for<'a> Decode<'a, Postgres> + Type<Postgres>, T: for<'a> Decode<'a, Postgres> + Type<Postgres>,
Self: Type<Postgres>,
{ {
fn decode(value: PgValueRef<'r>) -> Result<Self, BoxDynError> { fn decode(value: PgValueRef<'r>) -> Result<Self, BoxDynError> {
let element_type_info = T::type_info(); let element_type_info = T::type_info();

View File

@@ -171,7 +171,7 @@ pub use range::PgRange;
pub use record::{PgRecordDecoder, PgRecordEncoder}; pub use record::{PgRecordDecoder, PgRecordEncoder};
// Type::compatible impl appropriate for arrays // Type::compatible impl appropriate for arrays
fn array_compatible<E: ?Sized + Type<Postgres>>(ty: &PgTypeInfo) -> bool { fn array_compatible<E: Type<Postgres>>(ty: &PgTypeInfo) -> bool {
// we require the declared type to be an _array_ with an // we require the declared type to be an _array_ with an
// element type that is acceptable // element type that is acceptable
if let PgTypeKind::Array(element) = &ty.kind() { if let PgTypeKind::Array(element) = &ty.kind() {

View File

@@ -28,7 +28,7 @@ impl Type<Postgres> for [&'_ str] {
} }
fn compatible(ty: &PgTypeInfo) -> bool { fn compatible(ty: &PgTypeInfo) -> bool {
array_compatible::<str>(ty) array_compatible::<&str>(ty)
} }
} }
@@ -64,11 +64,11 @@ impl<'r> Decode<'r, Postgres> for &'r str {
impl Type<Postgres> for String { impl Type<Postgres> for String {
fn type_info() -> PgTypeInfo { fn type_info() -> PgTypeInfo {
<str as Type<Postgres>>::type_info() <&str as Type<Postgres>>::type_info()
} }
fn compatible(ty: &PgTypeInfo) -> bool { fn compatible(ty: &PgTypeInfo) -> bool {
<str as Type<Postgres>>::compatible(ty) <&str as Type<Postgres>>::compatible(ty)
} }
} }

View File

@@ -35,11 +35,6 @@ impl_into_arguments_for_arguments!(SqliteArguments<'q>);
impl_executor_for_pool_connection!(Sqlite, SqliteConnection, SqliteRow); impl_executor_for_pool_connection!(Sqlite, SqliteConnection, SqliteRow);
impl_executor_for_transaction!(Sqlite, 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 // required because some databases have a different handling
// of NULL // of NULL
impl_encode_for_option!(Sqlite); impl_encode_for_option!(Sqlite);

View File

@@ -29,7 +29,7 @@ impl<'r> Decode<'r, Sqlite> for &'r [u8] {
impl Type<Sqlite> for Vec<u8> { impl Type<Sqlite> for Vec<u8> {
fn type_info() -> SqliteTypeInfo { fn type_info() -> SqliteTypeInfo {
<[u8] as Type<Sqlite>>::type_info() <&[u8] as Type<Sqlite>>::type_info()
} }
} }

View File

@@ -29,7 +29,7 @@ impl<'r> Decode<'r, Sqlite> for &'r str {
impl Type<Sqlite> for String { impl Type<Sqlite> for String {
fn type_info() -> SqliteTypeInfo { fn type_info() -> SqliteTypeInfo {
<str as Type<Sqlite>>::type_info() <&str as Type<Sqlite>>::type_info()
} }
} }

View File

@@ -69,30 +69,24 @@ pub trait Type<DB: Database> {
} }
} }
// de-generified using macros because Any doesn't want this // for references, the underlying SQL type is identical
#[allow(unused_macros)] impl<T: ?Sized + Type<DB>, DB: Database> Type<DB> for &'_ T {
macro_rules! impl_type_for_ref_and_option { fn type_info() -> DB::TypeInfo {
($DB:ident) => { <T as Type<DB>>::type_info()
// for references, the underlying SQL type is identical }
impl<T: ?Sized + crate::types::Type<$DB>> crate::types::Type<$DB> for &'_ T {
fn type_info() -> <$DB as crate::database::Database>::TypeInfo {
<T as crate::types::Type<$DB>>::type_info()
}
fn compatible(ty: &<$DB as crate::database::Database>::TypeInfo) -> bool { fn compatible(ty: &DB::TypeInfo) -> bool {
<T as crate::types::Type<$DB>>::compatible(ty) <T as Type<DB>>::compatible(ty)
} }
} }
// for optionals, the underlying SQL type is identical // for optionals, the underlying SQL type is identical
impl<T: crate::types::Type<$DB>> crate::types::Type<$DB> for Option<T> { impl<T: Type<DB>, DB: Database> Type<DB> for Option<T> {
fn type_info() -> <$DB as crate::database::Database>::TypeInfo { fn type_info() -> DB::TypeInfo {
<T as crate::types::Type<$DB>>::type_info() <T as Type<DB>>::type_info()
} }
fn compatible(ty: &<$DB as crate::database::Database>::TypeInfo) -> bool { fn compatible(ty: &DB::TypeInfo) -> bool {
<T as crate::types::Type<$DB>>::compatible(ty) <T as Type<DB>>::compatible(ty)
} }
}
};
} }