use crate::pgs_error::PgsError;
use regex::Regex;
use serde::Serialize;
use std::fmt::Display;
use time::{Date, macros::format_description};
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize)]
pub enum Value {
String(String),
Integer(i32),
Date(Date), Bool(bool),
}
impl Value {
pub fn str(s: &str) -> Self {
Value::String(s.to_string())
}
pub fn int(i: i32) -> Self {
Value::Integer(i)
}
pub fn date(repr: &str) -> Result<Self, PgsError> {
let format = format_description!("[year]-[month]-[day]");
let date = Date::parse(repr, &format).map_err(|e| PgsError::InvalidDate {
date: repr.to_string(),
error: e.to_string(),
})?;
Ok(Value::Date(date))
}
pub fn is_string(&self) -> bool {
matches!(self, Value::String(_))
}
pub fn true_() -> Self {
Value::Bool(true)
}
pub fn false_() -> Self {
Value::Bool(false)
}
pub fn is_integer(&self) -> bool {
matches!(self, Value::Integer(_))
}
pub fn is_date(&self) -> bool {
matches!(self, Value::Date(_))
}
pub fn is_bool(&self) -> bool {
matches!(self, Value::Bool(_))
}
pub fn greater_than(&self, other: &Value) -> Result<bool, PgsError> {
match (self, other) {
(Value::Integer(i), Value::Integer(v)) => Ok(i > v),
(Value::Date(i), Value::Date(v)) => Ok(i > v),
_ => Err(PgsError::TypeMismatch {
operation: ">".into(),
expected: "Integer".into(),
found: format!("{:?}", other),
}),
}
}
pub fn less_than(&self, other: &Value) -> Result<bool, PgsError> {
match (self, other) {
(Value::Integer(i), Value::Integer(v)) => Ok(i < v),
(Value::Date(i), Value::Date(v)) => Ok(i < v),
_ => Err(PgsError::TypeMismatch {
operation: "<".into(),
expected: "Integer".into(),
found: format!("{:?}", other),
}),
}
}
pub fn less_than_or_equal(&self, other: &Value) -> Result<bool, PgsError> {
match (self, other) {
(Value::Integer(i), Value::Integer(v)) => Ok(i <= v),
(Value::Date(i), Value::Date(v)) => Ok(i <= v),
_ => Err(PgsError::TypeMismatch {
operation: "<=".into(),
expected: "Integer".into(),
found: format!("{:?}", other),
}),
}
}
pub fn greater_than_or_equal(&self, other: &Value) -> Result<bool, PgsError> {
match (self, other) {
(Value::Integer(i), Value::Integer(v)) => Ok(i >= v),
(Value::Date(i), Value::Date(v)) => Ok(i >= v),
_ => Err(PgsError::TypeMismatch {
operation: ">=".into(),
expected: "Integer".into(),
found: format!("{:?}", other),
}),
}
}
pub fn regex_match(&self, pattern: &str) -> Result<bool, PgsError> {
match self {
Value::String(s) => {
let regex = Regex::new(pattern).map_err(|e| PgsError::InvalidRegex {
pattern: pattern.to_string(),
error: e.to_string(),
})?;
let matches = regex.is_match(s);
Ok(matches)
},
_ => Err(PgsError::TypeMismatch {
operation: "regex_match".into(),
expected: "String".into(),
found: format!("{:?}", self),
}),
}
}
}
impl Display for Value {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Value::String(s) => write!(f, "{}", s),
Value::Integer(i) => write!(f, "{}", i),
Value::Date(d) => write!(f, "{}", d),
Value::Bool(b) => write!(f, "{}", b),
}
}
}
impl PartialOrd for Value {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl Ord for Value {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
match (self, other) {
(Value::Integer(i1), Value::Integer(i2)) => i1.cmp(i2),
(Value::String(s1), Value::String(s2)) => s1.cmp(s2),
(Value::Date(d1), Value::Date(d2)) => d1.cmp(d2),
_ => std::cmp::Ordering::Equal, }
}
}