use std::{borrow::Cow, rc::Rc, sync::Arc};
#[cfg(feature = "chrono")]
use chrono::{DateTime, FixedOffset, NaiveDate, NaiveDateTime, NaiveTime, Utc};
use quex::{
Date as QuexDate, DateTime as QuexDateTime, DateTimeTz as QuexDateTimeTz, Encode,
Time as QuexTime,
};
#[cfg(feature = "serde_json")]
use serde_json::Value as JsonValue;
#[cfg(feature = "uuid")]
use uuid::Uuid;
use crate::{
BigInt, Blob, Bool, Date, Double, Float, Int, Nullable, Text, Time, Timestamp, UBigInt, UInt,
expression::{AsExpression, Expression},
lower::LowerCtx,
param::encode_param,
ty::TypeMeta,
};
pub trait DefaultMeta {
type Meta: TypeMeta;
}
pub trait Compatible<T: TypeMeta>: Encode {}
#[doc(hidden)]
pub trait LowerCompatible<T: TypeMeta> {
fn lower_compatible(&self, ctx: &mut LowerCtx) -> usize;
}
impl<T> DefaultMeta for Option<T>
where
T: DefaultMeta,
{
type Meta = Nullable<T::Meta>;
}
impl<T> DefaultMeta for &T
where
T: DefaultMeta + ?Sized,
{
type Meta = T::Meta;
}
impl<T, U> Compatible<T> for &U
where
T: TypeMeta,
U: Compatible<T> + ?Sized,
{
}
impl<T, V> LowerCompatible<T> for V
where
T: TypeMeta,
V: Compatible<T> + ?Sized,
{
fn lower_compatible(&self, ctx: &mut LowerCtx) -> usize {
let param = encode_param(self, ctx.data);
ctx.lower_param(param)
}
}
macro_rules! impl_text_lower_compatible {
($($ty:ty),+ $(,)?) => {
$(
impl LowerCompatible<Text> for $ty {
fn lower_compatible(&self, ctx: &mut LowerCtx) -> usize {
let param = encode_param(self.as_ref(), ctx.data);
ctx.lower_param(param)
}
}
impl LowerCompatible<Nullable<Text>> for $ty {
fn lower_compatible(&self, ctx: &mut LowerCtx) -> usize {
let param = encode_param(self.as_ref(), ctx.data);
ctx.lower_param(param)
}
}
)+
};
}
impl_text_lower_compatible!(Box<str>, Arc<str>, Rc<str>, Cow<'_, str>);
macro_rules! impl_blob_lower_compatible {
($($ty:ty),+ $(,)?) => {
$(
impl LowerCompatible<Blob> for $ty {
fn lower_compatible(&self, ctx: &mut LowerCtx) -> usize {
let param = encode_param(self.as_ref(), ctx.data);
ctx.lower_param(param)
}
}
impl LowerCompatible<Nullable<Blob>> for $ty {
fn lower_compatible(&self, ctx: &mut LowerCtx) -> usize {
let param = encode_param(self.as_ref(), ctx.data);
ctx.lower_param(param)
}
}
)+
};
}
impl_blob_lower_compatible!(Box<[u8]>, Arc<[u8]>, Rc<[u8]>, Cow<'_, [u8]>);
impl<T, U> AsExpression<T> for &U
where
T: TypeMeta,
U: AsExpression<T> + ?Sized,
{
type Expression<'e>
= U::Expression<'e>
where
Self: 'e;
fn as_expression<'e>(&'e self) -> Self::Expression<'e> {
U::as_expression(*self)
}
}
macro_rules! impl_default_meta {
($meta:ty => $($ty:ty),+ $(,)?) => {
$(impl DefaultMeta for $ty {
type Meta = $meta;
})+
};
}
impl_default_meta!(Text => String, str, Box<str>, Arc<str>, Rc<str>, Cow<'_, str>);
impl_default_meta!(Blob => Vec<u8>, [u8], Box<[u8]>, Arc<[u8]>, Rc<[u8]>, Cow<'_, [u8]>);
impl_default_meta!(Bool => bool);
impl_default_meta!(Int => i8, i16, i32);
impl_default_meta!(BigInt => i64);
impl_default_meta!(UInt => u8, u16, u32);
impl_default_meta!(UBigInt => u64);
impl_default_meta!(Float => f32);
impl_default_meta!(Double => f64);
impl_default_meta!(Date => QuexDate);
impl_default_meta!(Time => QuexTime);
impl_default_meta!(Timestamp => QuexDateTime, QuexDateTimeTz);
#[cfg(feature = "chrono")]
impl_default_meta!(Date => NaiveDate);
#[cfg(feature = "chrono")]
impl_default_meta!(Time => NaiveTime);
#[cfg(feature = "chrono")]
impl_default_meta!(Timestamp => NaiveDateTime, DateTime<Utc>, DateTime<FixedOffset>);
#[cfg(feature = "uuid")]
impl_default_meta!(Text => Uuid);
#[cfg(feature = "serde_json")]
impl_default_meta!(Text => JsonValue);
macro_rules! impl_compatible_exact {
($sql:ty => $($ty:ty),+ $(,)?) => {
$(
impl Compatible<$sql> for $ty {}
impl Compatible<Nullable<$sql>> for $ty {}
)+
};
}
impl_compatible_exact!(Int => i8, i16, i32);
impl_compatible_exact!(BigInt => i64);
impl_compatible_exact!(UInt => u8, u16, u32);
impl_compatible_exact!(UBigInt => u64);
impl_compatible_exact!(Bool => bool);
impl_compatible_exact!(Float => f32);
impl_compatible_exact!(Double => f64);
impl_compatible_exact!(Date => QuexDate);
impl_compatible_exact!(Time => QuexTime);
impl_compatible_exact!(Timestamp => QuexDateTime, QuexDateTimeTz);
macro_rules! impl_compatible_bigint_widen {
($($ty:ty),+ $(,)?) => {
$(
impl Compatible<BigInt> for $ty {}
impl Compatible<Nullable<BigInt>> for $ty {}
)+
};
}
impl_compatible_bigint_widen!(i8, i16, i32);
impl Compatible<Double> for f32 {}
impl Compatible<Nullable<Double>> for f32 {}
macro_rules! impl_text_compatible {
($($ty:ty),+ $(,)?) => {
$(
impl Compatible<Text> for $ty {}
impl Compatible<Nullable<Text>> for $ty {}
)+
};
}
impl_text_compatible!(str, String);
macro_rules! impl_blob_compatible {
($($ty:ty),+ $(,)?) => {
$(
impl Compatible<Blob> for $ty {}
impl Compatible<Nullable<Blob>> for $ty {}
)+
};
}
impl_blob_compatible!([u8], Vec<u8>);
#[cfg(feature = "chrono")]
impl Compatible<Date> for NaiveDate {}
#[cfg(feature = "chrono")]
impl Compatible<Nullable<Date>> for NaiveDate {}
#[cfg(feature = "chrono")]
impl Compatible<Time> for NaiveTime {}
#[cfg(feature = "chrono")]
impl Compatible<Nullable<Time>> for NaiveTime {}
#[cfg(feature = "chrono")]
impl Compatible<Timestamp> for NaiveDateTime {}
#[cfg(feature = "chrono")]
impl Compatible<Nullable<Timestamp>> for NaiveDateTime {}
#[cfg(feature = "chrono")]
impl Compatible<Timestamp> for DateTime<FixedOffset> {}
#[cfg(feature = "chrono")]
impl Compatible<Nullable<Timestamp>> for DateTime<FixedOffset> {}
#[cfg(feature = "chrono")]
impl Compatible<Timestamp> for DateTime<Utc> {}
#[cfg(feature = "chrono")]
impl Compatible<Nullable<Timestamp>> for DateTime<Utc> {}
#[cfg(feature = "uuid")]
impl Compatible<Text> for Uuid {}
#[cfg(feature = "uuid")]
impl Compatible<Nullable<Text>> for Uuid {}
#[cfg(feature = "serde_json")]
impl Compatible<Text> for JsonValue {}
#[cfg(feature = "serde_json")]
impl Compatible<Nullable<Text>> for JsonValue {}
impl<T, V> Compatible<Nullable<T>> for Option<V>
where
T: TypeMeta,
V: Compatible<T>,
{
}
pub struct TypedParam<'e, T: TypeMeta, V: ?Sized> {
value: &'e V,
marker: std::marker::PhantomData<T>,
}
impl<'e, T: TypeMeta, V: ?Sized> TypedParam<'e, T, V> {
pub fn new(value: &'e V) -> Self {
Self {
value,
marker: std::marker::PhantomData,
}
}
}
impl<T, V> Expression for TypedParam<'_, T, V>
where
T: TypeMeta,
V: Compatible<T> + ?Sized,
{
type Type = T;
fn lower(&self, ctx: &mut LowerCtx) -> usize {
self.value.lower_compatible(ctx)
}
}
macro_rules! impl_as_expression {
($sql:ty => $($ty:ty),+ $(,)?) => {
$(
impl AsExpression<$sql> for $ty {
type Expression<'e>
= TypedParam<'e, $sql, $ty>
where
Self: 'e;
fn as_expression<'e>(&'e self) -> Self::Expression<'e> {
TypedParam::new(self)
}
}
impl AsExpression<Nullable<$sql>> for $ty {
type Expression<'e>
= TypedParam<'e, Nullable<$sql>, $ty>
where
Self: 'e;
fn as_expression<'e>(&'e self) -> Self::Expression<'e> {
TypedParam::new(self)
}
}
)+
};
}
impl_as_expression!(Bool => bool);
impl_as_expression!(Int => i8, i16, i32);
impl_as_expression!(BigInt => i8, i16, i32, i64);
impl_as_expression!(UInt => u8, u16, u32);
impl_as_expression!(UBigInt => u64);
impl_as_expression!(Float => f32);
impl_as_expression!(Double => f32, f64);
impl_as_expression!(Text => str, String);
impl_as_expression!(Blob => [u8], Vec<u8>);
impl_as_expression!(Date => QuexDate);
impl_as_expression!(Time => QuexTime);
impl_as_expression!(Timestamp => QuexDateTime, QuexDateTimeTz);
#[cfg(feature = "chrono")]
impl_as_expression!(Date => NaiveDate);
#[cfg(feature = "chrono")]
impl_as_expression!(Time => NaiveTime);
#[cfg(feature = "chrono")]
impl_as_expression!(Timestamp => NaiveDateTime, DateTime<Utc>, DateTime<FixedOffset>);
#[cfg(feature = "uuid")]
impl_as_expression!(Text => Uuid);
#[cfg(feature = "serde_json")]
impl_as_expression!(Text => JsonValue);
impl<T, V> AsExpression<Nullable<T>> for Option<V>
where
T: TypeMeta,
V: Compatible<T>,
{
type Expression<'e>
= TypedParam<'e, Nullable<T>, Option<V>>
where
Self: 'e;
fn as_expression<'e>(&'e self) -> Self::Expression<'e> {
TypedParam::new(self)
}
}