use sqlx_core::decode::Decode;
use sqlx_core::encode::{Encode, IsNull};
use sqlx_core::error::BoxDynError;
use sqlx_core::types::Type;
use spg_embedded::Value as EngineValue;
use crate::arguments::SpgArgumentValue;
use crate::database::Spg;
use crate::type_info::{Kind, SpgTypeInfo};
use crate::value::SpgValueRef;
impl Type<Spg> for [i32] {
fn type_info() -> SpgTypeInfo {
SpgTypeInfo::of(Kind::Text)
}
fn compatible(_ty: &SpgTypeInfo) -> bool {
true
}
}
impl Type<Spg> for Vec<i32> {
fn type_info() -> SpgTypeInfo {
<[i32] as Type<Spg>>::type_info()
}
fn compatible(_ty: &SpgTypeInfo) -> bool {
true
}
}
impl<'q> Encode<'q, Spg> for [i32] {
fn encode_by_ref(&self, buf: &mut Vec<SpgArgumentValue<'q>>) -> Result<IsNull, BoxDynError> {
buf.push(SpgArgumentValue {
value: EngineValue::IntArray(self.iter().map(|v| Some(*v)).collect()),
type_info: Some(<[i32] as Type<Spg>>::type_info()),
_phantom: core::marker::PhantomData,
});
Ok(IsNull::No)
}
}
impl<'q> Encode<'q, Spg> for Vec<i32> {
fn encode_by_ref(&self, buf: &mut Vec<SpgArgumentValue<'q>>) -> Result<IsNull, BoxDynError> {
self.as_slice().encode_by_ref(buf)
}
}
impl<'q> Encode<'q, Spg> for &'q [i32] {
fn encode_by_ref(&self, buf: &mut Vec<SpgArgumentValue<'q>>) -> Result<IsNull, BoxDynError> {
(**self).encode_by_ref(buf)
}
}
impl<'r> Decode<'r, Spg> for Vec<i32> {
fn decode(value: SpgValueRef<'r>) -> Result<Self, BoxDynError> {
match value.engine() {
EngineValue::IntArray(items) => Ok(items.iter().filter_map(|o| *o).collect()),
EngineValue::BigIntArray(items) => Ok(items
.iter()
.filter_map(|o| (*o).and_then(|n| i32::try_from(n).ok()))
.collect()),
other => Err(format!("cannot decode {other:?} as Vec<i32>").into()),
}
}
}
impl Type<Spg> for [i64] {
fn type_info() -> SpgTypeInfo {
SpgTypeInfo::of(Kind::Text)
}
fn compatible(_ty: &SpgTypeInfo) -> bool {
true
}
}
impl Type<Spg> for Vec<i64> {
fn type_info() -> SpgTypeInfo {
<[i64] as Type<Spg>>::type_info()
}
fn compatible(_ty: &SpgTypeInfo) -> bool {
true
}
}
impl<'q> Encode<'q, Spg> for [i64] {
fn encode_by_ref(&self, buf: &mut Vec<SpgArgumentValue<'q>>) -> Result<IsNull, BoxDynError> {
buf.push(SpgArgumentValue {
value: EngineValue::BigIntArray(self.iter().map(|v| Some(*v)).collect()),
type_info: Some(<[i64] as Type<Spg>>::type_info()),
_phantom: core::marker::PhantomData,
});
Ok(IsNull::No)
}
}
impl<'q> Encode<'q, Spg> for Vec<i64> {
fn encode_by_ref(&self, buf: &mut Vec<SpgArgumentValue<'q>>) -> Result<IsNull, BoxDynError> {
self.as_slice().encode_by_ref(buf)
}
}
impl<'q> Encode<'q, Spg> for &'q [i64] {
fn encode_by_ref(&self, buf: &mut Vec<SpgArgumentValue<'q>>) -> Result<IsNull, BoxDynError> {
(**self).encode_by_ref(buf)
}
}
impl<'r> Decode<'r, Spg> for Vec<i64> {
fn decode(value: SpgValueRef<'r>) -> Result<Self, BoxDynError> {
match value.engine() {
EngineValue::BigIntArray(items) => Ok(items.iter().filter_map(|o| *o).collect()),
EngineValue::IntArray(items) => {
Ok(items.iter().filter_map(|o| (*o).map(i64::from)).collect())
}
other => Err(format!("cannot decode {other:?} as Vec<i64>").into()),
}
}
}
impl Type<Spg> for [String] {
fn type_info() -> SpgTypeInfo {
SpgTypeInfo::of(Kind::Text)
}
fn compatible(_ty: &SpgTypeInfo) -> bool {
true
}
}
impl Type<Spg> for Vec<String> {
fn type_info() -> SpgTypeInfo {
<[String] as Type<Spg>>::type_info()
}
fn compatible(_ty: &SpgTypeInfo) -> bool {
true
}
}
fn encode_text_array<'q, S: AsRef<str>>(
items: impl Iterator<Item = S>,
buf: &mut Vec<SpgArgumentValue<'q>>,
) -> Result<IsNull, BoxDynError> {
buf.push(SpgArgumentValue {
value: EngineValue::TextArray(items.map(|v| Some(v.as_ref().to_string())).collect()),
type_info: Some(<[String] as Type<Spg>>::type_info()),
_phantom: core::marker::PhantomData,
});
Ok(IsNull::No)
}
impl<'q> Encode<'q, Spg> for [String] {
fn encode_by_ref(&self, buf: &mut Vec<SpgArgumentValue<'q>>) -> Result<IsNull, BoxDynError> {
encode_text_array(self.iter(), buf)
}
}
impl<'q> Encode<'q, Spg> for Vec<String> {
fn encode_by_ref(&self, buf: &mut Vec<SpgArgumentValue<'q>>) -> Result<IsNull, BoxDynError> {
self.as_slice().encode_by_ref(buf)
}
}
impl<'q> Encode<'q, Spg> for &'q [String] {
fn encode_by_ref(&self, buf: &mut Vec<SpgArgumentValue<'q>>) -> Result<IsNull, BoxDynError> {
(**self).encode_by_ref(buf)
}
}
impl Type<Spg> for [&str] {
fn type_info() -> SpgTypeInfo {
SpgTypeInfo::of(Kind::Text)
}
fn compatible(_ty: &SpgTypeInfo) -> bool {
true
}
}
impl Type<Spg> for Vec<&str> {
fn type_info() -> SpgTypeInfo {
<[&str] as Type<Spg>>::type_info()
}
fn compatible(_ty: &SpgTypeInfo) -> bool {
true
}
}
impl<'q> Encode<'q, Spg> for [&str] {
fn encode_by_ref(&self, buf: &mut Vec<SpgArgumentValue<'q>>) -> Result<IsNull, BoxDynError> {
encode_text_array(self.iter(), buf)
}
}
impl<'q> Encode<'q, Spg> for Vec<&str> {
fn encode_by_ref(&self, buf: &mut Vec<SpgArgumentValue<'q>>) -> Result<IsNull, BoxDynError> {
self.as_slice().encode_by_ref(buf)
}
}
impl<'q> Encode<'q, Spg> for &'q [&str] {
fn encode_by_ref(&self, buf: &mut Vec<SpgArgumentValue<'q>>) -> Result<IsNull, BoxDynError> {
(**self).encode_by_ref(buf)
}
}
impl<'r> Decode<'r, Spg> for Vec<String> {
fn decode(value: SpgValueRef<'r>) -> Result<Self, BoxDynError> {
match value.engine() {
EngineValue::TextArray(items) => Ok(items.iter().filter_map(|o| o.clone()).collect()),
other => Err(format!("cannot decode {other:?} as Vec<String>").into()),
}
}
}