use crate::prelude::*;
use crate::{
sql::{ColumnRef, SQL, TableRef, Token},
traits::SQLParam,
};
#[cfg(feature = "uuid")]
use uuid::Uuid;
#[diagnostic::on_unimplemented(
message = "`{Self}` cannot be converted to SQL",
label = "this type does not implement ToSQL for the current dialect"
)]
pub trait ToSQL<'a, V: SQLParam> {
fn to_sql(&self) -> SQL<'a, V>;
fn into_sql(self) -> SQL<'a, V>
where
Self: Sized,
{
self.to_sql()
}
}
#[derive(Debug, Clone)]
pub struct SQLBytes<'a>(pub Cow<'a, [u8]>);
#[derive(Debug, Clone, Copy, Default)]
pub struct SQLNull;
impl<'a> SQLBytes<'a> {
#[inline]
pub fn new(bytes: impl Into<Cow<'a, [u8]>>) -> Self {
Self(bytes.into())
}
}
impl<'a, V: SQLParam + 'a> ToSQL<'a, V> for SQLNull {
fn to_sql(&self) -> SQL<'a, V> {
SQL::raw("NULL")
}
}
impl<'a, T, V> From<&T> for SQL<'a, V>
where
T: ToSQL<'a, V>,
V: SQLParam,
{
fn from(value: &T) -> Self {
value.to_sql()
}
}
impl<'a, V: SQLParam, T> ToSQL<'a, V> for &T
where
T: ToSQL<'a, V>,
{
fn to_sql(&self) -> SQL<'a, V> {
(**self).to_sql()
}
}
impl<'a, V: SQLParam + 'a> ToSQL<'a, V> for () {
fn to_sql(&self) -> SQL<'a, V> {
SQL::empty()
}
}
impl<'a, V, T> ToSQL<'a, V> for Vec<T>
where
V: SQLParam + 'a,
T: ToSQL<'a, V>,
{
fn to_sql(&self) -> SQL<'a, V> {
SQL::join(self.iter().map(ToSQL::to_sql), Token::COMMA)
}
}
impl<'a, V, T> ToSQL<'a, V> for &'a [T]
where
V: SQLParam + 'a,
T: ToSQL<'a, V>,
{
fn to_sql(&self) -> SQL<'a, V> {
SQL::join(self.iter().map(ToSQL::to_sql), Token::COMMA)
}
}
impl<'a, V, T, const N: usize> ToSQL<'a, V> for [T; N]
where
V: SQLParam + 'a,
T: ToSQL<'a, V>,
{
fn to_sql(&self) -> SQL<'a, V> {
SQL::join(self.iter().map(ToSQL::to_sql), Token::COMMA)
}
}
impl<'a, V: SQLParam + 'a> ToSQL<'a, V> for TableRef {
fn to_sql(&self) -> SQL<'a, V> {
SQL::table(*self)
}
}
impl<'a, V: SQLParam + 'a> ToSQL<'a, V> for ColumnRef {
fn to_sql(&self) -> SQL<'a, V> {
SQL::column(*self)
}
}
impl<'a, V> ToSQL<'a, V> for &'a str
where
V: SQLParam + 'a + From<&'a str> + Into<Cow<'a, V>>,
{
fn to_sql(&self) -> SQL<'a, V> {
SQL::param(V::from(self))
}
}
impl<'a, V> ToSQL<'a, V> for Box<str>
where
V: SQLParam + 'a + From<String> + Into<Cow<'a, V>>,
{
fn to_sql(&self) -> SQL<'a, V> {
SQL::param(V::from(self.to_string()))
}
fn into_sql(self) -> SQL<'a, V> {
SQL::param(V::from(self.into_string()))
}
}
#[cfg(any(feature = "std", feature = "alloc"))]
impl<'a, V> ToSQL<'a, V> for Rc<str>
where
V: SQLParam + 'a + From<String> + Into<Cow<'a, V>>,
{
fn to_sql(&self) -> SQL<'a, V> {
SQL::param(V::from(self.as_ref().to_string()))
}
}
#[cfg(any(feature = "std", feature = "alloc"))]
impl<'a, V> ToSQL<'a, V> for Arc<str>
where
V: SQLParam + 'a + From<String> + Into<Cow<'a, V>>,
{
fn to_sql(&self) -> SQL<'a, V> {
SQL::param(V::from(self.as_ref().to_string()))
}
}
impl<'a, V, T> ToSQL<'a, V> for Box<T>
where
V: SQLParam + 'a,
T: ToSQL<'a, V>,
{
fn to_sql(&self) -> SQL<'a, V> {
(**self).to_sql()
}
}
#[cfg(any(feature = "std", feature = "alloc"))]
impl<'a, V, T> ToSQL<'a, V> for Rc<T>
where
V: SQLParam + 'a,
T: ToSQL<'a, V>,
{
fn to_sql(&self) -> SQL<'a, V> {
(**self).to_sql()
}
}
#[cfg(any(feature = "std", feature = "alloc"))]
impl<'a, V, T> ToSQL<'a, V> for Arc<T>
where
V: SQLParam + 'a,
T: ToSQL<'a, V>,
{
fn to_sql(&self) -> SQL<'a, V> {
(**self).to_sql()
}
}
impl<'a, V> ToSQL<'a, V> for String
where
V: SQLParam + 'a + From<Self> + Into<Cow<'a, V>>,
{
fn to_sql(&self) -> SQL<'a, V> {
SQL::param(V::from(self.clone()))
}
fn into_sql(self) -> SQL<'a, V> {
SQL::param(V::from(self))
}
}
impl<'a, V> ToSQL<'a, V> for Cow<'a, str>
where
V: SQLParam + 'a + From<&'a str> + From<String> + Into<Cow<'a, V>>,
{
fn to_sql(&self) -> SQL<'a, V> {
match self {
Cow::Borrowed(value) => SQL::param(V::from(*value)),
Cow::Owned(value) => SQL::param(V::from(value.clone())),
}
}
fn into_sql(self) -> SQL<'a, V> {
match self {
Cow::Borrowed(value) => SQL::param(V::from(value)),
Cow::Owned(value) => SQL::param(V::from(value)),
}
}
}
impl<'a, V> ToSQL<'a, V> for Cow<'a, [u8]>
where
V: SQLParam + 'a + From<&'a [u8]> + From<Vec<u8>> + Into<Cow<'a, V>>,
{
fn to_sql(&self) -> SQL<'a, V> {
match self {
Cow::Borrowed(value) => SQL::param(V::from(*value)),
Cow::Owned(value) => SQL::param(V::from(value.clone())),
}
}
fn into_sql(self) -> SQL<'a, V> {
match self {
Cow::Borrowed(value) => SQL::param(V::from(value)),
Cow::Owned(value) => SQL::param(V::from(value)),
}
}
}
impl<'a, V> ToSQL<'a, V> for SQLBytes<'a>
where
V: SQLParam + 'a + From<&'a [u8]> + From<Vec<u8>> + Into<Cow<'a, V>>,
{
fn to_sql(&self) -> SQL<'a, V> {
match &self.0 {
Cow::Borrowed(value) => SQL::param(V::from(*value)),
Cow::Owned(value) => SQL::param(V::from(value.clone())),
}
}
fn into_sql(self) -> SQL<'a, V> {
match self.0 {
Cow::Borrowed(value) => SQL::param(V::from(value)),
Cow::Owned(value) => SQL::param(V::from(value)),
}
}
}
macro_rules! impl_tosql_param_copy {
($($ty:ty),+ $(,)?) => {
$(
impl<'a, V> ToSQL<'a, V> for $ty
where
V: SQLParam + 'a + From<$ty>,
V: Into<Cow<'a, V>>,
{
fn to_sql(&self) -> SQL<'a, V> {
SQL::param(V::from(*self))
}
}
)+
};
}
impl_tosql_param_copy!(
i8, i16, i32, i64, f32, f64, bool, u8, u16, u32, u64, isize, usize
);
impl<'a, V, T> ToSQL<'a, V> for Option<T>
where
V: SQLParam + 'a,
T: ToSQL<'a, V>,
{
fn to_sql(&self) -> SQL<'a, V> {
self.as_ref()
.map_or_else(|| SQLNull.to_sql(), ToSQL::to_sql)
}
}
#[cfg(feature = "uuid")]
impl<'a, V> ToSQL<'a, V> for Uuid
where
V: SQLParam + 'a + From<Self> + Into<Cow<'a, V>>,
{
fn to_sql(&self) -> SQL<'a, V> {
SQL::param(V::from(*self))
}
}