feat(core): add Type, TypeEncode, and TypeDecode

This commit is contained in:
Ryan Leckey 2021-02-17 21:26:40 -08:00
parent f7516ea22d
commit 831df74b93
No known key found for this signature in database
GPG Key ID: F8AA68C235AB08C9
4 changed files with 78 additions and 9 deletions

View File

@ -6,12 +6,15 @@ use crate::database::HasRawValue;
use crate::Database;
/// A type that can be decoded from a SQL value.
pub trait Decode<'r, Db: Database>: Sized + Send + Sync {
fn decode(value: <Db as HasRawValue<'r>>::RawValue) -> Result<Self>;
pub trait Decode<'r, Db: Database>: Send + Sync {
fn decode(value: <Db as HasRawValue<'r>>::RawValue) -> Result<Self>
where
Self: Sized;
}
/// A type that can be decoded from a SQL value, without borrowing any data
/// from the row.
#[allow(clippy::module_name_repetitions)]
pub trait DecodeOwned<Db: Database>: for<'r> Decode<'r, Db> {}
impl<T, Db: Database> DecodeOwned<Db> for T where T: for<'r> Decode<'r, Db> {}
@ -33,6 +36,13 @@ pub enum Error {
Custom(Box<dyn StdError + Send + Sync>),
}
impl Error {
#[doc(hidden)]
pub fn msg<D: Display>(msg: D) -> Self {
Self::Custom(msg.to_string().into())
}
}
impl Display for Error {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self {

View File

@ -6,14 +6,8 @@ use crate::Database;
/// A type that can be encoded into a SQL value.
pub trait Encode<Db: Database>: Send + Sync {
/// Encode this value into a SQL value.
/// Encode this value into the specified SQL type.
fn encode(&self, ty: &Db::TypeInfo, out: &mut <Db as HasOutput<'_>>::Output) -> Result<()>;
#[doc(hidden)]
#[inline]
fn __type_name(&self) -> &'static str {
std::any::type_name::<Self>()
}
}
impl<T: Encode<Db>, Db: Database> Encode<Db> for &T {
@ -31,6 +25,13 @@ pub enum Error {
Custom(Box<dyn StdError + Send + Sync>),
}
impl Error {
#[doc(hidden)]
pub fn msg<D: Display>(msg: D) -> Self {
Self::Custom(msg.to_string().into())
}
}
impl Display for Error {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self {

View File

@ -19,6 +19,7 @@
#![allow(clippy::clippy::missing_errors_doc)]
mod acquire;
mod arguments;
mod close;
mod column;
mod connect;
@ -32,6 +33,8 @@ mod options;
mod query_result;
pub mod row;
mod runtime;
mod r#type;
mod type_info;
#[doc(hidden)]
pub mod io;
@ -47,6 +50,7 @@ pub mod mock;
pub mod blocking;
pub use acquire::Acquire;
pub use arguments::{Argument, Arguments};
#[cfg(feature = "blocking")]
pub use blocking::runtime::Blocking;
pub use close::Close;
@ -60,6 +64,7 @@ pub use error::{DatabaseError, Error, Result};
pub use executor::Executor;
pub use options::ConnectOptions;
pub use query_result::QueryResult;
pub use r#type::{Type, TypeEncode, TypeDecode};
pub use row::Row;
#[cfg(feature = "actix")]
pub use runtime::Actix;
@ -70,3 +75,4 @@ pub use runtime::AsyncStd;
pub use runtime::Runtime;
#[cfg(feature = "tokio")]
pub use runtime::Tokio;
pub use type_info::TypeInfo;

52
sqlx-core/src/type.rs Normal file
View File

@ -0,0 +1,52 @@
use crate::{Database, Decode, Encode, TypeInfo};
// NOTE: The interface here is not final. There are some special considerations
// for MSSQL and Postgres (Arrays and Ranges) that need careful handling
// to ensure we correctly cover them.
/// Indicates that a SQL type is supported for a database.
pub trait Type<Db: Database> {
/// Returns the canonical SQL type identifier for this Rust type.
///
/// When binding arguments, this is used to tell the database what is about to be sent; which,
/// the database then uses to guide query plans. This can be overridden by [`type_id_of`].
///
/// A map of SQL types to Rust types is populated with this and used
/// to determine the type that is returned from the anonymous struct type from [`query!`].
///
fn type_id() -> Db::TypeId
where
Self: Sized;
/// Determines if this Rust type is compatible with the specified SQL type.
///
/// To be compatible, the Rust type must support encoding _and_ decoding
/// from the specified SQL type.
///
fn compatible(ty: &Db::TypeInfo) -> bool
where
Self: Sized,
{
ty.id() == Self::type_id()
}
}
#[allow(clippy::module_name_repetitions)]
pub trait TypeEncode<Db: Database>: Type<Db> + Encode<Db> {
/// Returns the SQL type identifier that best hints to the database
/// at the incoming value for a bind parameter.
#[allow(unused_variables)]
fn type_id_of(&self, ty: &Db::TypeInfo) -> Db::TypeId;
/// Returns the Rust type name of this.
#[doc(hidden)]
#[inline]
fn __rust_type_name_of(&self) -> &'static str {
std::any::type_name::<Self>()
}
}
#[allow(clippy::module_name_repetitions)]
pub trait TypeDecode<'r, Db: Database>: Type<Db> + Decode<'r, Db> {}
impl<'r, T: Type<Db> + Decode<'r, Db>, Db: Database> TypeDecode<'r, Db> for T {}