use serde::{Deserialize, Serialize};
use std::fmt;
use std::marker::PhantomData;
use std::str::FromStr;
pub use chrono::{DateTime, NaiveDate, NaiveDateTime, NaiveTime, Utc};
pub use rust_decimal::Decimal;
pub use uuid::Uuid;
pub type Json = serde_json::Value;
pub type Jsonb = serde_json::Value;
pub type Text = String;
pub type IntArray = Vec<i32>;
pub type BigIntArray = Vec<i64>;
pub type TextArray = Vec<String>;
pub type BoolArray = Vec<bool>;
pub type FloatArray = Vec<f64>;
pub type JsonArray = Vec<serde_json::Value>;
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
#[serde(transparent)]
pub struct UnixTimestamp(pub i64);
impl UnixTimestamp {
pub fn new(seconds: i64) -> Self {
Self(seconds)
}
pub fn now() -> Self {
Self(chrono::Utc::now().timestamp())
}
pub fn from_datetime(dt: DateTime<Utc>) -> Self {
Self(dt.timestamp())
}
pub fn to_datetime(self) -> Option<DateTime<Utc>> {
chrono::DateTime::from_timestamp(self.0, 0)
}
pub fn as_seconds(&self) -> i64 {
self.0
}
pub fn is_past(&self) -> bool {
self.0 < chrono::Utc::now().timestamp()
}
pub fn is_future(&self) -> bool {
self.0 > chrono::Utc::now().timestamp()
}
}
impl Default for UnixTimestamp {
fn default() -> Self {
Self::now()
}
}
impl From<i64> for UnixTimestamp {
fn from(seconds: i64) -> Self {
Self(seconds)
}
}
impl From<UnixTimestamp> for i64 {
fn from(ts: UnixTimestamp) -> Self {
ts.0
}
}
impl From<DateTime<Utc>> for UnixTimestamp {
fn from(dt: DateTime<Utc>) -> Self {
Self::from_datetime(dt)
}
}
impl fmt::Display for UnixTimestamp {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if let Some(dt) = self.to_datetime() {
write!(f, "{}", dt.format("%Y-%m-%d %H:%M:%S UTC"))
} else {
write!(f, "{}", self.0)
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
#[serde(transparent)]
pub struct UnixTimestampMillis(pub i64);
impl UnixTimestampMillis {
pub fn new(millis: i64) -> Self {
Self(millis)
}
pub fn now() -> Self {
Self(chrono::Utc::now().timestamp_millis())
}
pub fn from_datetime(dt: DateTime<Utc>) -> Self {
Self(dt.timestamp_millis())
}
pub fn to_datetime(self) -> Option<DateTime<Utc>> {
chrono::DateTime::from_timestamp_millis(self.0)
}
pub fn as_millis(&self) -> i64 {
self.0
}
pub fn as_seconds(&self) -> i64 {
self.0 / 1000
}
pub fn to_unix_timestamp(self) -> UnixTimestamp {
UnixTimestamp(self.0 / 1000)
}
pub fn is_past(&self) -> bool {
self.0 < chrono::Utc::now().timestamp_millis()
}
pub fn is_future(&self) -> bool {
self.0 > chrono::Utc::now().timestamp_millis()
}
}
impl Default for UnixTimestampMillis {
fn default() -> Self {
Self::now()
}
}
impl From<i64> for UnixTimestampMillis {
fn from(millis: i64) -> Self {
Self(millis)
}
}
impl From<UnixTimestampMillis> for i64 {
fn from(ts: UnixTimestampMillis) -> Self {
ts.0
}
}
impl From<DateTime<Utc>> for UnixTimestampMillis {
fn from(dt: DateTime<Utc>) -> Self {
Self::from_datetime(dt)
}
}
impl From<UnixTimestamp> for UnixTimestampMillis {
fn from(ts: UnixTimestamp) -> Self {
Self(ts.0 * 1000)
}
}
impl fmt::Display for UnixTimestampMillis {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if let Some(dt) = self.to_datetime() {
write!(f, "{}", dt.format("%Y-%m-%d %H:%M:%S%.3f UTC"))
} else {
write!(f, "{}", self.0)
}
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct DbEnum<E>(pub E);
impl<E: Serialize> Serialize for DbEnum<E> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
self.0.serialize(serializer)
}
}
impl<'de, E: Deserialize<'de>> Deserialize<'de> for DbEnum<E> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
E::deserialize(deserializer).map(DbEnum)
}
}
impl<E: fmt::Display> fmt::Display for DbEnum<E> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0)
}
}
impl<E> From<E> for DbEnum<E> {
fn from(e: E) -> Self {
DbEnum(e)
}
}
impl<E> DbEnum<E> {
pub fn into_inner(self) -> E {
self.0
}
pub fn inner(&self) -> &E {
&self.0
}
}
pub trait Castable: Sized {
fn from_json(value: &serde_json::Value) -> Result<Self, String>;
fn to_json(&self) -> serde_json::Value;
}
impl Castable for String {
fn from_json(value: &serde_json::Value) -> Result<Self, String> {
value.as_str().map(|s| s.to_string()).ok_or_else(|| "Expected string".to_string())
}
fn to_json(&self) -> serde_json::Value {
serde_json::Value::String(self.clone())
}
}
impl Castable for i32 {
fn from_json(value: &serde_json::Value) -> Result<Self, String> {
value.as_i64().map(|n| n as i32).ok_or_else(|| "Expected integer".to_string())
}
fn to_json(&self) -> serde_json::Value {
serde_json::Value::Number((*self).into())
}
}
impl Castable for i64 {
fn from_json(value: &serde_json::Value) -> Result<Self, String> {
value.as_i64().ok_or_else(|| "Expected integer".to_string())
}
fn to_json(&self) -> serde_json::Value {
serde_json::Value::Number((*self).into())
}
}
impl Castable for f64 {
fn from_json(value: &serde_json::Value) -> Result<Self, String> {
value.as_f64().ok_or_else(|| "Expected float".to_string())
}
fn to_json(&self) -> serde_json::Value {
serde_json::json!(*self)
}
}
impl Castable for bool {
fn from_json(value: &serde_json::Value) -> Result<Self, String> {
value.as_bool().ok_or_else(|| "Expected boolean".to_string())
}
fn to_json(&self) -> serde_json::Value {
serde_json::Value::Bool(*self)
}
}
impl Castable for Uuid {
fn from_json(value: &serde_json::Value) -> Result<Self, String> {
value.as_str()
.ok_or_else(|| "Expected string".to_string())
.and_then(|s| Uuid::parse_str(s).map_err(|e| e.to_string()))
}
fn to_json(&self) -> serde_json::Value {
serde_json::Value::String(self.to_string())
}
}
impl<T: Castable> Castable for Option<T> {
fn from_json(value: &serde_json::Value) -> Result<Self, String> {
if value.is_null() {
Ok(None)
} else {
T::from_json(value).map(Some)
}
}
fn to_json(&self) -> serde_json::Value {
match self {
Some(v) => v.to_json(),
None => serde_json::Value::Null,
}
}
}
impl<T: Castable> Castable for Vec<T> {
fn from_json(value: &serde_json::Value) -> Result<Self, String> {
value.as_array()
.ok_or_else(|| "Expected array".to_string())
.and_then(|arr| {
arr.iter()
.map(|v| T::from_json(v))
.collect::<Result<Vec<_>, _>>()
})
}
fn to_json(&self) -> serde_json::Value {
serde_json::Value::Array(self.iter().map(|v| v.to_json()).collect())
}
}
pub trait AttributeCaster<T>: Sized {
fn get(value: serde_json::Value) -> Result<T, String>;
fn set(value: &T) -> serde_json::Value;
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Encrypted<T> {
value: T,
}
impl<T> Encrypted<T> {
pub fn new(value: T) -> Self {
Self { value }
}
pub fn into_inner(self) -> T {
self.value
}
pub fn inner(&self) -> &T {
&self.value
}
}
impl<T: Clone> Encrypted<T> {
pub fn get(&self) -> T {
self.value.clone()
}
}
impl<T: fmt::Display> fmt::Display for Encrypted<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "***ENCRYPTED***")
}
}
impl<T: Serialize> Serialize for Encrypted<T> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
self.value.serialize(serializer)
}
}
impl<'de, T: Deserialize<'de>> Deserialize<'de> for Encrypted<T> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
T::deserialize(deserializer).map(|v| Self { value: v })
}
}
impl<T> From<T> for Encrypted<T> {
fn from(value: T) -> Self {
Self::new(value)
}
}
impl<T: Default> Default for Encrypted<T> {
fn default() -> Self {
Self { value: T::default() }
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Hashed {
hash: String,
}
impl Hashed {
pub fn new(plain_text: &str) -> Self {
Self {
hash: Self::compute_hash(plain_text),
}
}
pub fn from_hash(hash: String) -> Self {
Self { hash }
}
pub fn hash(&self) -> &str {
&self.hash
}
pub fn verify(&self, plain_text: &str) -> bool {
Self::compute_hash(plain_text) == self.hash
}
fn compute_hash(input: &str) -> String {
use std::collections::hash_map::DefaultHasher;
use std::hash::{Hash, Hasher};
let mut hasher = DefaultHasher::new();
input.hash(&mut hasher);
format!("{:x}", hasher.finish())
}
}
impl From<&str> for Hashed {
fn from(s: &str) -> Self {
Self::new(s)
}
}
impl From<String> for Hashed {
fn from(s: String) -> Self {
Self::new(&s)
}
}
impl fmt::Display for Hashed {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "***HASHED***")
}
}
impl Serialize for Hashed {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
self.hash.serialize(serializer)
}
}
impl<'de> Deserialize<'de> for Hashed {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
String::deserialize(deserializer).map(|hash| Self { hash })
}
}
impl Default for Hashed {
fn default() -> Self {
Self { hash: String::new() }
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct CommaSeparated<T> {
values: Vec<T>,
}
impl<T> CommaSeparated<T> {
pub fn new(values: Vec<T>) -> Self {
Self { values }
}
pub fn values(&self) -> &[T] {
&self.values
}
pub fn values_mut(&mut self) -> &mut Vec<T> {
&mut self.values
}
pub fn into_inner(self) -> Vec<T> {
self.values
}
pub fn is_empty(&self) -> bool {
self.values.is_empty()
}
pub fn len(&self) -> usize {
self.values.len()
}
pub fn push(&mut self, value: T) {
self.values.push(value);
}
pub fn contains(&self, value: &T) -> bool
where
T: PartialEq,
{
self.values.contains(value)
}
}
impl<T: fmt::Display> CommaSeparated<T> {
pub fn to_string(&self) -> String {
self.values.iter()
.map(|v| v.to_string())
.collect::<Vec<_>>()
.join(",")
}
}
impl<T: FromStr> CommaSeparated<T>
where
T::Err: fmt::Debug,
{
pub fn from_string(s: &str) -> Self {
let values = s.split(',')
.filter(|s| !s.is_empty())
.filter_map(|s| s.trim().parse().ok())
.collect();
Self { values }
}
}
impl<T> From<Vec<T>> for CommaSeparated<T> {
fn from(values: Vec<T>) -> Self {
Self::new(values)
}
}
impl<T> FromIterator<T> for CommaSeparated<T> {
fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
Self { values: iter.into_iter().collect() }
}
}
impl<T> IntoIterator for CommaSeparated<T> {
type Item = T;
type IntoIter = std::vec::IntoIter<T>;
fn into_iter(self) -> Self::IntoIter {
self.values.into_iter()
}
}
impl<'a, T> IntoIterator for &'a CommaSeparated<T> {
type Item = &'a T;
type IntoIter = std::slice::Iter<'a, T>;
fn into_iter(self) -> Self::IntoIter {
self.values.iter()
}
}
impl<T: Serialize> Serialize for CommaSeparated<T> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
self.values.serialize(serializer)
}
}
impl<'de, T: Deserialize<'de>> Deserialize<'de> for CommaSeparated<T> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
Vec::<T>::deserialize(deserializer).map(|v| Self { values: v })
}
}
impl<T: Default> Default for CommaSeparated<T> {
fn default() -> Self {
Self { values: Vec::new() }
}
}
impl<T: fmt::Display> fmt::Display for CommaSeparated<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.to_string())
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Collection<T> {
items: Vec<T>,
}
impl<T> Collection<T> {
pub fn new() -> Self {
Self { items: Vec::new() }
}
pub fn from_vec(items: Vec<T>) -> Self {
Self { items }
}
pub fn all(&self) -> &[T] {
&self.items
}
pub fn first(&self) -> Option<&T> {
self.items.first()
}
pub fn last(&self) -> Option<&T> {
self.items.last()
}
pub fn is_empty(&self) -> bool {
self.items.is_empty()
}
pub fn count(&self) -> usize {
self.items.len()
}
pub fn add(&mut self, item: T) {
self.items.push(item);
}
pub fn remove(&mut self, index: usize) -> Option<T> {
if index < self.items.len() {
Some(self.items.remove(index))
} else {
None
}
}
pub fn filter<F: Fn(&T) -> bool>(&self, predicate: F) -> Self
where
T: Clone,
{
Self {
items: self.items.iter().filter(|i| predicate(i)).cloned().collect()
}
}
pub fn map<U, F: Fn(&T) -> U>(&self, mapper: F) -> Collection<U> {
Collection {
items: self.items.iter().map(mapper).collect()
}
}
pub fn find<F: Fn(&T) -> bool>(&self, predicate: F) -> Option<&T> {
self.items.iter().find(|i| predicate(i))
}
pub fn any<F: Fn(&T) -> bool>(&self, predicate: F) -> bool {
self.items.iter().any(predicate)
}
pub fn every<F: Fn(&T) -> bool>(&self, predicate: F) -> bool {
self.items.iter().all(predicate)
}
pub fn pluck<U, F: Fn(&T) -> U>(&self, extractor: F) -> Vec<U> {
self.items.iter().map(extractor).collect()
}
pub fn sorted<F: FnMut(&T, &T) -> std::cmp::Ordering>(&self, compare: F) -> Self
where
T: Clone,
{
let mut items = self.items.clone();
items.sort_by(compare);
Self { items }
}
pub fn take(&self, n: usize) -> Self
where
T: Clone,
{
Self {
items: self.items.iter().take(n).cloned().collect()
}
}
pub fn skip(&self, n: usize) -> Self
where
T: Clone,
{
Self {
items: self.items.iter().skip(n).cloned().collect()
}
}
pub fn to_vec(&self) -> Vec<T>
where
T: Clone,
{
self.items.clone()
}
pub fn into_inner(self) -> Vec<T> {
self.items
}
}
impl<T> From<Vec<T>> for Collection<T> {
fn from(items: Vec<T>) -> Self {
Self::from_vec(items)
}
}
impl<T> Default for Collection<T> {
fn default() -> Self {
Self::new()
}
}
impl<T> FromIterator<T> for Collection<T> {
fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
Self { items: iter.into_iter().collect() }
}
}
impl<T> IntoIterator for Collection<T> {
type Item = T;
type IntoIter = std::vec::IntoIter<T>;
fn into_iter(self) -> Self::IntoIter {
self.items.into_iter()
}
}
impl<'a, T> IntoIterator for &'a Collection<T> {
type Item = &'a T;
type IntoIter = std::slice::Iter<'a, T>;
fn into_iter(self) -> Self::IntoIter {
self.items.iter()
}
}
impl<T: Serialize> Serialize for Collection<T> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
self.items.serialize(serializer)
}
}
impl<'de, T: Deserialize<'de>> Deserialize<'de> for Collection<T> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
Vec::<T>::deserialize(deserializer).map(|v| Self { items: v })
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CastType {
String,
Integer,
Float,
Boolean,
Json,
Array,
DateTime,
Date,
Time,
Uuid,
Decimal,
Encrypted,
Hashed,
CommaSeparated,
Collection,
Custom,
}
impl CastType {
pub fn from_str(s: &str) -> Option<Self> {
match s.to_lowercase().as_str() {
"string" | "str" => Some(Self::String),
"integer" | "int" | "i64" | "i32" => Some(Self::Integer),
"float" | "f64" | "f32" | "double" => Some(Self::Float),
"boolean" | "bool" => Some(Self::Boolean),
"json" | "jsonb" => Some(Self::Json),
"array" => Some(Self::Array),
"datetime" | "timestamp" => Some(Self::DateTime),
"date" => Some(Self::Date),
"time" => Some(Self::Time),
"uuid" => Some(Self::Uuid),
"decimal" => Some(Self::Decimal),
"encrypted" => Some(Self::Encrypted),
"hashed" | "hash" => Some(Self::Hashed),
"comma_separated" | "csv" => Some(Self::CommaSeparated),
"collection" => Some(Self::Collection),
_ => None,
}
}
}
impl fmt::Display for CastType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::String => write!(f, "string"),
Self::Integer => write!(f, "integer"),
Self::Float => write!(f, "float"),
Self::Boolean => write!(f, "boolean"),
Self::Json => write!(f, "json"),
Self::Array => write!(f, "array"),
Self::DateTime => write!(f, "datetime"),
Self::Date => write!(f, "date"),
Self::Time => write!(f, "time"),
Self::Uuid => write!(f, "uuid"),
Self::Decimal => write!(f, "decimal"),
Self::Encrypted => write!(f, "encrypted"),
Self::Hashed => write!(f, "hashed"),
Self::CommaSeparated => write!(f, "comma_separated"),
Self::Collection => write!(f, "collection"),
Self::Custom => write!(f, "custom"),
}
}
}
pub struct CastValue;
impl CastValue {
pub fn cast(value: &serde_json::Value, cast_type: CastType) -> Result<serde_json::Value, String> {
match cast_type {
CastType::String => {
match value {
serde_json::Value::String(s) => Ok(serde_json::Value::String(s.clone())),
serde_json::Value::Number(n) => Ok(serde_json::Value::String(n.to_string())),
serde_json::Value::Bool(b) => Ok(serde_json::Value::String(b.to_string())),
serde_json::Value::Null => Ok(serde_json::Value::Null),
_ => Ok(serde_json::Value::String(value.to_string())),
}
}
CastType::Integer => {
match value {
serde_json::Value::Number(n) => {
if let Some(i) = n.as_i64() {
Ok(serde_json::json!(i))
} else if let Some(f) = n.as_f64() {
Ok(serde_json::json!(f as i64))
} else {
Err("Invalid number".to_string())
}
}
serde_json::Value::String(s) => {
s.parse::<i64>()
.map(|i| serde_json::json!(i))
.map_err(|_| "Failed to parse integer".to_string())
}
serde_json::Value::Bool(b) => Ok(serde_json::json!(if *b { 1 } else { 0 })),
serde_json::Value::Null => Ok(serde_json::Value::Null),
_ => Err("Cannot cast to integer".to_string()),
}
}
CastType::Float => {
match value {
serde_json::Value::Number(n) => {
if let Some(f) = n.as_f64() {
Ok(serde_json::json!(f))
} else {
Err("Invalid number".to_string())
}
}
serde_json::Value::String(s) => {
s.parse::<f64>()
.map(|f| serde_json::json!(f))
.map_err(|_| "Failed to parse float".to_string())
}
serde_json::Value::Bool(b) => Ok(serde_json::json!(if *b { 1.0 } else { 0.0 })),
serde_json::Value::Null => Ok(serde_json::Value::Null),
_ => Err("Cannot cast to float".to_string()),
}
}
CastType::Boolean => {
match value {
serde_json::Value::Bool(b) => Ok(serde_json::Value::Bool(*b)),
serde_json::Value::Number(n) => {
if let Some(i) = n.as_i64() {
Ok(serde_json::Value::Bool(i != 0))
} else {
Ok(serde_json::Value::Bool(true))
}
}
serde_json::Value::String(s) => {
let lower = s.to_lowercase();
Ok(serde_json::Value::Bool(
lower == "true" || lower == "1" || lower == "yes" || lower == "on"
))
}
serde_json::Value::Null => Ok(serde_json::Value::Bool(false)),
_ => Err("Cannot cast to boolean".to_string()),
}
}
CastType::Json => {
Ok(value.clone())
}
CastType::Array | CastType::Collection => {
match value {
serde_json::Value::Array(_) => Ok(value.clone()),
serde_json::Value::String(s) => {
serde_json::from_str(s)
.or_else(|_| {
Ok(serde_json::Value::Array(
s.split(',')
.map(|v| serde_json::Value::String(v.trim().to_string()))
.collect()
))
})
}
serde_json::Value::Null => Ok(serde_json::Value::Array(vec![])),
_ => Err("Cannot cast to array".to_string()),
}
}
CastType::DateTime => {
match value {
serde_json::Value::String(s) => {
if chrono::DateTime::parse_from_rfc3339(s).is_ok() {
Ok(value.clone())
} else {
Err("Invalid datetime format".to_string())
}
}
serde_json::Value::Null => Ok(serde_json::Value::Null),
_ => Err("Cannot cast to datetime".to_string()),
}
}
CastType::Date => {
match value {
serde_json::Value::String(s) => {
if chrono::NaiveDate::parse_from_str(s, "%Y-%m-%d").is_ok() {
Ok(value.clone())
} else {
Err("Invalid date format".to_string())
}
}
serde_json::Value::Null => Ok(serde_json::Value::Null),
_ => Err("Cannot cast to date".to_string()),
}
}
CastType::Time => {
match value {
serde_json::Value::String(s) => {
if chrono::NaiveTime::parse_from_str(s, "%H:%M:%S").is_ok() ||
chrono::NaiveTime::parse_from_str(s, "%H:%M").is_ok() {
Ok(value.clone())
} else {
Err("Invalid time format".to_string())
}
}
serde_json::Value::Null => Ok(serde_json::Value::Null),
_ => Err("Cannot cast to time".to_string()),
}
}
CastType::Uuid => {
match value {
serde_json::Value::String(s) => {
Uuid::parse_str(s)
.map(|_| value.clone())
.map_err(|e| format!("Invalid UUID: {}", e))
}
serde_json::Value::Null => Ok(serde_json::Value::Null),
_ => Err("Cannot cast to UUID".to_string()),
}
}
CastType::Decimal => {
match value {
serde_json::Value::Number(_) => Ok(value.clone()),
serde_json::Value::String(s) => {
s.parse::<f64>()
.map(|f| serde_json::json!(f))
.map_err(|_| "Failed to parse decimal".to_string())
}
serde_json::Value::Null => Ok(serde_json::Value::Null),
_ => Err("Cannot cast to decimal".to_string()),
}
}
CastType::Encrypted | CastType::Hashed => {
Ok(value.clone())
}
CastType::CommaSeparated => {
match value {
serde_json::Value::Array(arr) => {
let strings: Vec<String> = arr.iter()
.filter_map(|v| v.as_str().map(|s| s.to_string()))
.collect();
Ok(serde_json::Value::String(strings.join(",")))
}
serde_json::Value::String(_) => Ok(value.clone()),
serde_json::Value::Null => Ok(serde_json::Value::String(String::new())),
_ => Err("Cannot cast to comma-separated".to_string()),
}
}
CastType::Custom => {
Ok(value.clone())
}
}
}
pub fn parse_comma_separated(s: &str) -> Vec<String> {
s.split(',')
.map(|v| v.trim().to_string())
.filter(|v| !v.is_empty())
.collect()
}
pub fn format_comma_separated<T: fmt::Display>(values: &[T]) -> String {
values.iter()
.map(|v| v.to_string())
.collect::<Vec<_>>()
.join(",")
}
}
pub trait Accessor {
fn get_accessor(&self, key: &str) -> Option<serde_json::Value>;
fn accessor_keys() -> Vec<&'static str> {
vec![]
}
}
pub trait Mutator {
fn set_mutator(&mut self, key: &str, value: serde_json::Value) -> bool;
fn mutator_keys() -> Vec<&'static str> {
vec![]
}
}
#[derive(Clone, Debug)]
pub struct WithDefault<T> {
value: Option<T>,
_marker: PhantomData<T>,
}
impl<T: Clone> WithDefault<T> {
pub fn none() -> Self {
Self {
value: None,
_marker: PhantomData,
}
}
pub fn some(value: T) -> Self {
Self {
value: Some(value),
_marker: PhantomData,
}
}
pub fn unwrap_or(&self, default: T) -> T {
self.value.clone().unwrap_or(default)
}
pub fn unwrap_or_else<F: FnOnce() -> T>(&self, f: F) -> T {
self.value.clone().unwrap_or_else(f)
}
pub fn is_some(&self) -> bool {
self.value.is_some()
}
pub fn is_none(&self) -> bool {
self.value.is_none()
}
pub fn into_option(self) -> Option<T> {
self.value
}
}
impl<T: Default + Clone> Default for WithDefault<T> {
fn default() -> Self {
Self::some(T::default())
}
}
impl<T: Serialize + Clone> Serialize for WithDefault<T> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
self.value.serialize(serializer)
}
}
impl<'de, T: Deserialize<'de>> Deserialize<'de> for WithDefault<T> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
Option::<T>::deserialize(deserializer).map(|v| Self { value: v, _marker: PhantomData })
}
}