#[cfg(feature = "sqlx")]
use sqlx::database::Database;
#[cfg(feature = "sqlx")]
use crate::value::Value;
#[cfg(feature = "sqlx")]
#[cfg_attr(docsrs, doc(cfg(feature = "sqlx")))]
pub trait Query<'q, DB>: Sized
where
DB: sqlx::Database,
{
fn bind_fn<T>() -> fn(Self, T) -> Self
where
T: 'q + Send + sqlx::Encode<'q, DB> + sqlx::Type<DB>;
fn bind<T>(self, value: T) -> Self
where
T: 'q + Send + sqlx::Encode<'q, DB> + sqlx::Type<DB>,
{
Self::bind_fn()(self, value)
}
}
macro_rules! gen_query_common {
($feature:expr, $database:ident) => {
#[cfg(feature = $feature)]
#[cfg_attr(docsrs, doc(cfg(feature = $feature)))]
impl<'q> $crate::exec::bind::Query<'q, ::sqlx::$database>
for ::sqlx::query::Query<
'q,
::sqlx::$database,
<::sqlx::$database as ::sqlx::database::HasArguments<'q>>::Arguments,
>
{
fn bind_fn<T>() -> fn(Self, T) -> Self
where
T: 'q
+ ::std::marker::Send
+ ::sqlx::Encode<'q, sqlx::$database>
+ ::sqlx::Type<sqlx::$database>,
{
::sqlx::query::Query::bind
}
}
#[cfg(feature = $feature)]
#[cfg_attr(docsrs, doc(cfg(feature = $feature)))]
impl<'q, O> $crate::exec::bind::Query<'q, ::sqlx::$database>
for ::sqlx::query::QueryAs<
'q,
::sqlx::$database,
O,
<::sqlx::$database as ::sqlx::database::HasArguments<'q>>::Arguments,
>
{
fn bind_fn<T>() -> fn(Self, T) -> Self
where
T: 'q
+ ::std::marker::Send
+ ::sqlx::Encode<'q, ::sqlx::$database>
+ ::sqlx::Type<sqlx::$database>,
{
::sqlx::query::QueryAs::bind
}
}
#[cfg(feature = $feature)]
#[cfg_attr(docsrs, doc(cfg(feature = $feature)))]
impl<'q, O> $crate::exec::bind::Query<'q, ::sqlx::$database>
for ::sqlx::query::QueryScalar<
'q,
::sqlx::$database,
O,
<::sqlx::$database as ::sqlx::database::HasArguments<'q>>::Arguments,
>
{
fn bind_fn<T>() -> fn(Self, T) -> Self
where
T: 'q
+ ::std::marker::Send
+ ::sqlx::Encode<'q, ::sqlx::$database>
+ ::sqlx::Type<sqlx::$database>,
{
::sqlx::query::QueryScalar::bind
}
}
};
}
gen_query_common!("postgres", Postgres);
gen_query_common!("mysql", MySql);
gen_query_common!("sqlite", Sqlite);
#[cfg(feature = "sqlx")]
#[cfg_attr(docsrs, doc(cfg(feature = "sqlx")))]
pub trait Bind: Database {
fn bind<'q, Q>(query: Q, value: Value<'q>) -> Result<Q, sqlx::Error>
where
Q: Query<'q, Self>;
}
#[cfg(any(feature = "postgres", feature = "sqlite"))]
fn unsupported<DB, T>() -> sqlx::Error {
sqlx::Error::Io(std::io::Error::new(
std::io::ErrorKind::Other,
format!(
"sqlx::encode::Encode<'_, {}> is not implemented for {}",
std::any::type_name::<T>(),
std::any::type_name::<DB>(),
),
))
}
#[cfg(feature = "postgres")]
#[cfg_attr(docsrs, doc(cfg(feature = "postgres")))]
impl Bind for sqlx::Postgres {
fn bind<'q, Q>(query: Q, value: Value<'q>) -> Result<Q, sqlx::Error>
where
Q: Query<'q, Self>,
{
match value {
Value::Bool(val) => Ok(query.bind(val)),
Value::TinyInt(val) => Ok(query.bind(val)),
Value::SmallInt(val) => Ok(query.bind(val)),
Value::Int(val) => Ok(query.bind(val)),
Value::BigInt(val) => Ok(query.bind(val)),
Value::TinyUInt(..) => Err(unsupported::<sqlx::Postgres, u8>()),
Value::SmallUInt(..) => Err(unsupported::<sqlx::Postgres, u16>()),
Value::UInt(..) => Err(unsupported::<sqlx::Postgres, u32>()),
Value::BigUInt(..) => Err(unsupported::<sqlx::Postgres, u64>()),
Value::Text(val) => Ok(query.bind(val)),
Value::Bytes(val) => Ok(query.bind(val)),
Value::Null(crate::value::Null::Bool(..)) => Ok(query.bind(None::<bool>)),
Value::Null(crate::value::Null::TinyInt(..)) => Ok(query.bind(None::<i8>)),
Value::Null(crate::value::Null::SmallInt(..)) => Ok(query.bind(None::<i16>)),
Value::Null(crate::value::Null::Int(..)) => Ok(query.bind(None::<i32>)),
Value::Null(crate::value::Null::BigInt(..)) => Ok(query.bind(None::<i64>)),
Value::Null(crate::value::Null::TinyUInt(..)) => {
Err(unsupported::<sqlx::Postgres, u8>())
}
Value::Null(crate::value::Null::SmallUInt(..)) => {
Err(unsupported::<sqlx::Postgres, u16>())
}
Value::Null(crate::value::Null::UInt(..)) => Err(unsupported::<sqlx::Postgres, u32>()),
Value::Null(crate::value::Null::BigUInt(..)) => {
Err(unsupported::<sqlx::Postgres, u64>())
}
Value::Null(crate::value::Null::Text(..)) => Ok(query.bind(None::<&'q str>)),
Value::Null(crate::value::Null::Bytes(..)) => Ok(query.bind(None::<&'q str>)),
#[cfg(feature = "use-chrono")]
Value::DateTime(val) => Ok(query.bind(val)),
#[cfg(feature = "use-chrono")]
Value::Null(crate::value::Null::DateTime(..)) => {
Ok(query.bind(None::<chrono::DateTime<chrono::Utc>>))
}
#[cfg(feature = "use-decimal")]
Value::Numeric(val) => Ok(query.bind(val)),
#[cfg(feature = "use-decimal")]
Value::Null(crate::value::Null::Numeric(..)) => {
Ok(query.bind(None::<rust_decimal::Decimal>))
}
}
}
}
#[cfg(feature = "mysql")]
#[cfg_attr(docsrs, doc(cfg(feature = "mysql")))]
impl Bind for sqlx::MySql {
fn bind<'q, Q>(query: Q, value: Value<'q>) -> Result<Q, sqlx::Error>
where
Q: Query<'q, Self>,
{
match value {
Value::Bool(val) => Ok(query.bind(val)),
Value::TinyInt(val) => Ok(query.bind(val)),
Value::SmallInt(val) => Ok(query.bind(val)),
Value::Int(val) => Ok(query.bind(val)),
Value::BigInt(val) => Ok(query.bind(val)),
Value::TinyUInt(val) => Ok(query.bind(val)),
Value::SmallUInt(val) => Ok(query.bind(val)),
Value::UInt(val) => Ok(query.bind(val)),
Value::BigUInt(val) => Ok(query.bind(val)),
Value::Text(val) => Ok(query.bind(val)),
Value::Bytes(val) => Ok(query.bind(val)),
Value::Null(crate::value::Null::Bool(..)) => Ok(query.bind(None::<bool>)),
Value::Null(crate::value::Null::TinyInt(..)) => Ok(query.bind(None::<i8>)),
Value::Null(crate::value::Null::SmallInt(..)) => Ok(query.bind(None::<i16>)),
Value::Null(crate::value::Null::Int(..)) => Ok(query.bind(None::<i32>)),
Value::Null(crate::value::Null::BigInt(..)) => Ok(query.bind(None::<i64>)),
Value::Null(crate::value::Null::TinyUInt(..)) => Ok(query.bind(None::<u8>)),
Value::Null(crate::value::Null::SmallUInt(..)) => Ok(query.bind(None::<u16>)),
Value::Null(crate::value::Null::UInt(..)) => Ok(query.bind(None::<u32>)),
Value::Null(crate::value::Null::BigUInt(..)) => Ok(query.bind(None::<u64>)),
Value::Null(crate::value::Null::Text(..)) => Ok(query.bind(None::<&'q str>)),
Value::Null(crate::value::Null::Bytes(..)) => Ok(query.bind(None::<&'q str>)),
#[cfg(feature = "use-chrono")]
Value::DateTime(val) => Ok(query.bind(val)),
#[cfg(feature = "use-chrono")]
Value::Null(crate::value::Null::DateTime(..)) => {
Ok(query.bind(None::<chrono::DateTime<chrono::Utc>>))
}
#[cfg(feature = "use-decimal")]
Value::Numeric(val) => Ok(query.bind(val)),
#[cfg(feature = "use-decimal")]
Value::Null(crate::value::Null::Numeric(..)) => {
Ok(query.bind(None::<rust_decimal::Decimal>))
}
}
}
}
#[cfg(feature = "sqlite")]
#[cfg_attr(docsrs, doc(cfg(feature = "sqlite")))]
impl Bind for sqlx::Sqlite {
fn bind<'q, Q>(query: Q, value: Value<'q>) -> Result<Q, sqlx::Error>
where
Q: Query<'q, Self>,
{
match value {
Value::Bool(val) => Ok(query.bind(val)),
Value::TinyInt(val) => Ok(query.bind(val)),
Value::SmallInt(val) => Ok(query.bind(val)),
Value::Int(val) => Ok(query.bind(val)),
Value::BigInt(val) => Ok(query.bind(val)),
Value::TinyUInt(val) => Ok(query.bind(val)),
Value::SmallUInt(val) => Ok(query.bind(val)),
Value::UInt(val) => Ok(query.bind(val)),
Value::BigUInt(..) => Err(unsupported::<sqlx::Sqlite, u64>()),
Value::Text(val) => Ok(query.bind(val)),
Value::Bytes(val) => Ok(query.bind(val)),
Value::Null(crate::value::Null::Bool(..)) => Ok(query.bind(None::<bool>)),
Value::Null(crate::value::Null::TinyInt(..)) => Ok(query.bind(None::<i8>)),
Value::Null(crate::value::Null::SmallInt(..)) => Ok(query.bind(None::<i16>)),
Value::Null(crate::value::Null::Int(..)) => Ok(query.bind(None::<i32>)),
Value::Null(crate::value::Null::BigInt(..)) => Ok(query.bind(None::<i64>)),
Value::Null(crate::value::Null::TinyUInt(..)) => Ok(query.bind(None::<u8>)),
Value::Null(crate::value::Null::SmallUInt(..)) => Ok(query.bind(None::<u16>)),
Value::Null(crate::value::Null::UInt(..)) => Ok(query.bind(None::<u32>)),
Value::Null(crate::value::Null::BigUInt(..)) => Err(unsupported::<sqlx::Sqlite, u64>()),
Value::Null(crate::value::Null::Text(..)) => Ok(query.bind(None::<&'q str>)),
Value::Null(crate::value::Null::Bytes(..)) => Ok(query.bind(None::<&'q str>)),
#[cfg(feature = "use-chrono")]
Value::DateTime(val) => Ok(query.bind(val)),
#[cfg(feature = "use-chrono")]
Value::Null(crate::value::Null::DateTime(..)) => {
Ok(query.bind(None::<chrono::DateTime<chrono::Utc>>))
}
#[cfg(feature = "use-decimal")]
Value::Numeric(..) => Err(unsupported::<sqlx::Sqlite, u64>()),
#[cfg(feature = "use-decimal")]
Value::Null(crate::value::Null::Numeric(..)) => Err(unsupported::<sqlx::Sqlite, u64>()),
}
}
}