use std::ops::{Deref, DerefMut};
#[derive(Debug, Clone, PartialEq, Eq, Hash, Default)]
pub struct Array<T>(pub Vec<T>);
impl<T> Array<T> {
#[must_use]
pub fn new(items: Vec<T>) -> Self {
Self(items)
}
#[must_use]
pub fn into_inner(self) -> Vec<T> {
self.0
}
}
impl<T> Deref for Array<T> {
type Target = Vec<T>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<T> DerefMut for Array<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl<T> From<Vec<T>> for Array<T> {
fn from(v: Vec<T>) -> Self {
Self(v)
}
}
impl<T> From<Array<T>> for Vec<T> {
fn from(a: Array<T>) -> Self {
a.0
}
}
impl<T> FromIterator<T> for Array<T> {
fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
Self(iter.into_iter().collect())
}
}
impl<T: serde::Serialize> serde::Serialize for Array<T> {
fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
self.0.serialize(serializer)
}
}
impl<'de, T> serde::Deserialize<'de> for Array<T>
where
T: serde::Deserialize<'de>,
{
fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
Vec::<T>::deserialize(deserializer).map(Self)
}
}
impl From<Array<String>> for crate::core::SqlValue {
fn from(a: Array<String>) -> Self {
crate::core::SqlValue::Array(a.0.into_iter().map(crate::core::SqlValue::String).collect())
}
}
impl From<Array<i32>> for crate::core::SqlValue {
fn from(a: Array<i32>) -> Self {
crate::core::SqlValue::Array(a.0.into_iter().map(crate::core::SqlValue::I32).collect())
}
}
impl From<Array<i64>> for crate::core::SqlValue {
fn from(a: Array<i64>) -> Self {
crate::core::SqlValue::Array(a.0.into_iter().map(crate::core::SqlValue::I64).collect())
}
}
#[cfg(feature = "postgres")]
impl<'r, T> sqlx::Decode<'r, sqlx::Postgres> for Array<T>
where
Vec<T>: sqlx::Decode<'r, sqlx::Postgres>,
{
fn decode(
value: <sqlx::Postgres as sqlx::Database>::ValueRef<'r>,
) -> Result<Self, sqlx::error::BoxDynError> {
Ok(Self(<Vec<T> as sqlx::Decode<'r, sqlx::Postgres>>::decode(
value,
)?))
}
}
#[cfg(feature = "postgres")]
impl<T> sqlx::Type<sqlx::Postgres> for Array<T>
where
Vec<T>: sqlx::Type<sqlx::Postgres>,
{
fn type_info() -> sqlx::postgres::PgTypeInfo {
<Vec<T> as sqlx::Type<sqlx::Postgres>>::type_info()
}
fn compatible(ty: &sqlx::postgres::PgTypeInfo) -> bool {
<Vec<T> as sqlx::Type<sqlx::Postgres>>::compatible(ty)
}
}
#[cfg(feature = "mysql")]
impl<'r, T> sqlx::Decode<'r, sqlx::MySql> for Array<T> {
fn decode(
_value: <sqlx::MySql as sqlx::Database>::ValueRef<'r>,
) -> Result<Self, sqlx::error::BoxDynError> {
Err("`Array<T>` columns are PostgreSQL-only; cannot decode on MySQL (issue #341)".into())
}
}
#[cfg(feature = "mysql")]
impl<T> sqlx::Type<sqlx::MySql> for Array<T> {
fn type_info() -> sqlx::mysql::MySqlTypeInfo {
<Vec<u8> as sqlx::Type<sqlx::MySql>>::type_info()
}
}
#[cfg(feature = "sqlite")]
impl<'r, T> sqlx::Decode<'r, sqlx::Sqlite> for Array<T> {
fn decode(
_value: <sqlx::Sqlite as sqlx::Database>::ValueRef<'r>,
) -> Result<Self, sqlx::error::BoxDynError> {
Err("`Array<T>` columns are PostgreSQL-only; cannot decode on SQLite (issue #341)".into())
}
}
#[cfg(feature = "sqlite")]
impl<T> sqlx::Type<sqlx::Sqlite> for Array<T> {
fn type_info() -> sqlx::sqlite::SqliteTypeInfo {
<Vec<u8> as sqlx::Type<sqlx::Sqlite>>::type_info()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn deref_and_from_vec() {
let a: Array<String> = vec!["x".to_owned(), "y".to_owned()].into();
assert_eq!(a.len(), 2);
assert_eq!(a[0], "x");
assert_eq!(a.into_inner(), vec!["x".to_owned(), "y".to_owned()]);
}
#[test]
fn serde_round_trips_as_plain_array() {
let a: Array<i32> = Array::new(vec![1, 2, 3]);
let json = serde_json::to_string(&a).unwrap();
assert_eq!(json, "[1,2,3]");
let back: Array<i32> = serde_json::from_str(&json).unwrap();
assert_eq!(back, a);
}
#[test]
fn into_sqlvalue_array_string() {
let v: crate::core::SqlValue = Array(vec!["a".to_owned(), "b".to_owned()]).into();
match v {
crate::core::SqlValue::Array(items) => {
assert_eq!(items.len(), 2);
assert!(matches!(items[0], crate::core::SqlValue::String(_)));
}
_ => panic!("expected SqlValue::Array"),
}
}
#[test]
fn into_sqlvalue_array_ints() {
let v: crate::core::SqlValue = Array(vec![1i32, 2, 3]).into();
match v {
crate::core::SqlValue::Array(items) => {
assert_eq!(items.len(), 3);
assert!(matches!(items[0], crate::core::SqlValue::I32(1)));
}
_ => panic!("expected SqlValue::Array"),
}
}
}