mirror of
https://github.com/launchbadge/sqlx.git
synced 2025-11-01 14:02:46 +00:00
refactor: remove several blanket impls to allow more customization
This commit is contained in:
parent
34859af1d3
commit
eb26e9f557
@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
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.
|
||||||
///
|
///
|
||||||
@ -62,17 +61,24 @@ 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>;
|
||||||
}
|
}
|
||||||
|
|
||||||
// implement `Decode` for Option<T> for all SQL types
|
#[allow(unused_macros)]
|
||||||
impl<'r, DB, T> Decode<'r, DB> for Option<T>
|
macro_rules! impl_decode_for_option {
|
||||||
where
|
($DB:ident) => {
|
||||||
DB: Database,
|
impl<'r, T> crate::decode::Decode<'r, $DB> for Option<T>
|
||||||
T: Decode<'r, DB>,
|
where
|
||||||
{
|
T: crate::decode::Decode<'r, $DB>,
|
||||||
fn decode(value: <DB as HasValueRef<'r>>::ValueRef) -> Result<Self, BoxDynError> {
|
{
|
||||||
|
fn decode(
|
||||||
|
value: <$DB as crate::database::HasValueRef<'r>>::ValueRef,
|
||||||
|
) -> Result<Self, crate::error::BoxDynError> {
|
||||||
|
use crate::value::ValueRef;
|
||||||
|
|
||||||
if value.is_null() {
|
if value.is_null() {
|
||||||
Ok(None)
|
Ok(None)
|
||||||
} else {
|
} else {
|
||||||
Ok(Some(T::decode(value)?))
|
Ok(Some(T::decode(value)?))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -45,22 +45,32 @@ pub trait Encode<'q, DB: Database> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'q, T, DB: Database> Encode<'q, DB> for &'_ T
|
// de-generified using macros because Any doesn't want this
|
||||||
where
|
#[allow(unused_macros)]
|
||||||
T: Encode<'q, DB>,
|
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]
|
#[inline]
|
||||||
fn encode(self, buf: &mut <DB as HasArguments<'q>>::ArgumentBuffer) -> IsNull {
|
fn encode(
|
||||||
<T as Encode<DB>>::encode_by_ref(self, buf)
|
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(&self, buf: &mut <DB as HasArguments<'q>>::ArgumentBuffer) -> IsNull {
|
fn encode_by_ref(
|
||||||
<&T as Encode<DB>>::encode(self, buf)
|
&self,
|
||||||
|
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::TypeInfo> {
|
fn produces(&self) -> Option<<$DB as crate::database::Database>::TypeInfo> {
|
||||||
(**self).produces()
|
(**self).produces()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -68,8 +78,11 @@ where
|
|||||||
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) => {
|
||||||
|
|||||||
@ -31,5 +31,10 @@ 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
|
||||||
|
|||||||
@ -31,6 +31,11 @@ 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);
|
||||||
|
|||||||
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -34,6 +34,11 @@ 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);
|
||||||
|
|||||||
@ -37,7 +37,6 @@ 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 {
|
||||||
@ -48,7 +47,6 @@ 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
|
||||||
@ -77,7 +75,6 @@ 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();
|
||||||
|
|||||||
@ -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: Type<Postgres>>(ty: &PgTypeInfo) -> bool {
|
fn array_compatible<E: ?Sized + 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() {
|
||||||
|
|||||||
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -35,6 +35,11 @@ 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);
|
||||||
|
|||||||
@ -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()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -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()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -69,24 +69,30 @@ pub trait Type<DB: Database> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// for references, the underlying SQL type is identical
|
// de-generified using macros because Any doesn't want this
|
||||||
impl<T: ?Sized + Type<DB>, DB: Database> Type<DB> for &'_ T {
|
#[allow(unused_macros)]
|
||||||
fn type_info() -> DB::TypeInfo {
|
macro_rules! impl_type_for_ref_and_option {
|
||||||
<T as Type<DB>>::type_info()
|
($DB:ident) => {
|
||||||
|
// 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::TypeInfo) -> bool {
|
fn compatible(ty: &<$DB as crate::database::Database>::TypeInfo) -> bool {
|
||||||
<T as Type<DB>>::compatible(ty)
|
<T as crate::types::Type<$DB>>::compatible(ty)
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// for optionals, the underlying SQL type is identical
|
|
||||||
impl<T: Type<DB>, DB: Database> Type<DB> for Option<T> {
|
|
||||||
fn type_info() -> DB::TypeInfo {
|
|
||||||
<T as Type<DB>>::type_info()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn compatible(ty: &DB::TypeInfo) -> bool {
|
|
||||||
<T as Type<DB>>::compatible(ty)
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// for optionals, the underlying SQL type is identical
|
||||||
|
impl<T: crate::types::Type<$DB>> crate::types::Type<$DB> for Option<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 {
|
||||||
|
<T as crate::types::Type<$DB>>::compatible(ty)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user