use core::marker::PhantomData;
use crate::prelude::*;
use drizzle_core::{Placeholder, SQL, SQLParam, TypedPlaceholder};
use super::{OwnedSQLiteValue, SQLiteValue};
#[doc(hidden)]
#[derive(Debug, Clone)]
pub struct ValueWrapper<'a, V: SQLParam, T> {
pub value: SQL<'a, V>,
pub _phantom: PhantomData<T>,
}
impl<'a, V: SQLParam, T> ValueWrapper<'a, V, T> {
pub const fn new<U>(value: SQL<'a, V>) -> ValueWrapper<'a, V, U> {
ValueWrapper {
value,
_phantom: PhantomData,
}
}
}
#[derive(Debug, Clone, Default)]
#[allow(clippy::large_enum_variant)]
pub enum SQLiteInsertValue<'a, V: SQLParam, T> {
#[default]
Omit,
Null,
Value(ValueWrapper<'a, V, T>),
}
impl<'a, T> SQLiteInsertValue<'a, SQLiteValue<'a>, T> {
#[must_use]
pub fn into_owned(self) -> SQLiteInsertValue<'static, SQLiteValue<'static>, T> {
match self {
SQLiteInsertValue::Omit => SQLiteInsertValue::Omit,
SQLiteInsertValue::Null => SQLiteInsertValue::Null,
SQLiteInsertValue::Value(wrapper) => {
let static_sql = wrapper
.value
.into_owned_with(|value| SQLiteValue::from(OwnedSQLiteValue::from(value)));
SQLiteInsertValue::Value(ValueWrapper::<SQLiteValue<'static>, T>::new(static_sql))
}
}
}
}
impl<'a, T, U> From<T> for SQLiteInsertValue<'a, SQLiteValue<'a>, U>
where
T: TryInto<SQLiteValue<'a>> + TryInto<U>,
U: TryInto<SQLiteValue<'a>>,
{
fn from(value: T) -> Self {
let column_value = TryInto::<U>::try_into(value).unwrap_or_else(|_| {
panic!(
"a `{}` does not fit a `{}` column",
core::any::type_name::<T>(),
core::any::type_name::<U>()
)
});
let sql = SQL::from(
TryInto::<SQLiteValue<'a>>::try_into(column_value).unwrap_or_else(|_| {
panic!(
"could not convert a `{}` to a SQLite value",
core::any::type_name::<U>()
)
}),
);
SQLiteInsertValue::Value(ValueWrapper::<SQLiteValue<'a>, T>::new(sql))
}
}
impl<'a, T> From<Placeholder> for SQLiteInsertValue<'a, SQLiteValue<'a>, T> {
fn from(placeholder: Placeholder) -> Self {
use drizzle_core::{Param, SQLChunk};
let chunk = SQLChunk::Param(Param {
placeholder,
value: None,
});
SQLiteInsertValue::Value(ValueWrapper::<SQLiteValue<'a>, T>::new(
core::iter::once(chunk).collect(),
))
}
}
impl<'a, M: drizzle_core::types::DataType, N: drizzle_core::expr::Nullability, T>
From<TypedPlaceholder<M, N>> for SQLiteInsertValue<'a, SQLiteValue<'a>, T>
{
fn from(typed: TypedPlaceholder<M, N>) -> Self {
Placeholder::from(typed).into()
}
}
impl<'a, const N: usize> From<[u8; N]> for SQLiteInsertValue<'a, SQLiteValue<'a>, Vec<u8>> {
fn from(value: [u8; N]) -> Self {
let sqlite_value = SQLiteValue::Blob(Cow::Owned(value.to_vec()));
let sql = SQL::param(sqlite_value);
SQLiteInsertValue::Value(ValueWrapper::<SQLiteValue<'a>, Vec<u8>>::new(sql))
}
}