use crate::context::FeelContext;
use crate::errors::*;
use crate::values::Value;
use crate::{value_null, Name};
use dmntk_common::DmntkError;
use serde::{Deserialize, Serialize};
pub const XSD_STRING: &str = "xsd:string";
pub const XSD_INTEGER: &str = "xsd:integer";
pub const XSD_DECIMAL: &str = "xsd:decimal";
pub const XSD_DOUBLE: &str = "xsd:double";
pub const XSD_BOOLEAN: &str = "xsd:boolean";
pub const XSD_DATE: &str = "xsd:date";
pub const XSD_DATE_TIME: &str = "xsd:dateTime";
pub const XSD_TIME: &str = "xsd:time";
pub const XSD_DURATION: &str = "xsd:duration";
type ObjectDto = Vec<ComponentDto>;
#[derive(Default, Serialize, Deserialize)]
pub struct ValueDto {
#[serde(rename = "simple")]
simple: Option<SimpleDto>,
#[serde(rename = "components")]
object: Option<ObjectDto>,
#[serde(rename = "list")]
list: Option<ListDto>,
}
#[derive(Default, Serialize, Deserialize)]
pub struct SimpleDto {
#[serde(rename = "type")]
typ: Option<String>,
#[serde(rename = "text")]
text: Option<String>,
#[serde(rename = "isNil")]
nil: bool,
}
impl SimpleDto {
fn new(typ: &str, text: String) -> Option<Self> {
Some(Self {
typ: Some(typ.to_string()),
text: Some(text),
nil: false,
})
}
fn new_nil() -> Option<Self> {
Some(Self { typ: None, text: None, nil: true })
}
}
#[derive(Default, Serialize, Deserialize)]
pub struct ComponentDto {
#[serde(rename = "name")]
name: Option<String>,
#[serde(rename = "value")]
value: Option<ValueDto>,
#[serde(rename = "isNil")]
nil: bool,
}
#[derive(Default, Serialize, Deserialize)]
pub struct ListDto {
#[serde(rename = "items")]
items: Vec<ValueDto>,
#[serde(rename = "isNil")]
nil: bool,
}
impl ListDto {
fn new(items: Vec<ValueDto>) -> Option<Self> {
Some(Self { items, nil: false })
}
}
impl TryFrom<&Value> for ValueDto {
type Error = DmntkError;
fn try_from(value: &Value) -> Result<Self, Self::Error> {
match value {
Value::String(inner) => Ok(ValueDto {
simple: SimpleDto::new(XSD_STRING, inner.to_string()),
..Default::default()
}),
v @ Value::Number(_) => Ok(ValueDto {
simple: SimpleDto::new(XSD_DECIMAL, v.to_string()),
..Default::default()
}),
v @ Value::Boolean(_) => Ok(ValueDto {
simple: SimpleDto::new(XSD_BOOLEAN, v.to_string()),
..Default::default()
}),
v @ Value::Date(_) => Ok(ValueDto {
simple: SimpleDto::new(XSD_DATE, v.to_string()),
..Default::default()
}),
v @ Value::DateTime(_) => Ok(ValueDto {
simple: SimpleDto::new(XSD_DATE_TIME, v.to_string()),
..Default::default()
}),
v @ Value::Time(_) => Ok(ValueDto {
simple: SimpleDto::new(XSD_TIME, v.to_string()),
..Default::default()
}),
v @ Value::YearsAndMonthsDuration(_) => Ok(ValueDto {
simple: SimpleDto::new(XSD_DURATION, v.to_string()),
..Default::default()
}),
v @ Value::DaysAndTimeDuration(_) => Ok(ValueDto {
simple: SimpleDto::new(XSD_DURATION, v.to_string()),
..Default::default()
}),
Value::Null(_) => Ok(ValueDto {
simple: SimpleDto::new_nil(),
..Default::default()
}),
Value::Context(ctx) => {
let mut components = vec![];
for (name, value) in ctx.iter() {
components.push(ComponentDto {
name: Some(name.to_string()),
value: Some(value.try_into()?),
nil: false,
});
}
Ok(ValueDto {
object: Some(components),
..Default::default()
})
}
Value::List(list) => {
let mut items = vec![];
for value in list {
items.push(value.try_into()?);
}
Ok(ValueDto {
list: ListDto::new(items),
..Default::default()
})
}
_ => Ok(Default::default()),
}
}
}
impl TryFrom<&ValueDto> for Value {
type Error = DmntkError;
fn try_from(value: &ValueDto) -> Result<Self, Self::Error> {
if let Some(value_dto) = &value.simple {
return Value::try_from(value_dto);
}
if let Some(components) = &value.object {
return Value::try_from(components);
}
if let Some(list) = &value.list {
return Value::try_from(list);
}
Err(err_missing_attribute("no 'simple', 'components' or 'list' attribute"))
}
}
impl TryFrom<&SimpleDto> for Value {
type Error = DmntkError;
fn try_from(value: &SimpleDto) -> Result<Self, Self::Error> {
if value.nil {
return Ok(value_null!());
}
if let Some(typ) = &value.typ {
if let Some(text) = &value.text {
return match typ.as_str() {
XSD_STRING => Ok(Value::String(text.clone())),
XSD_INTEGER => Ok(Value::try_from_xsd_integer(text)?),
XSD_DECIMAL => Ok(Value::try_from_xsd_decimal(text)?),
XSD_DOUBLE => Ok(Value::try_from_xsd_double(text)?),
XSD_BOOLEAN => Ok(Value::try_from_xsd_boolean(text)?),
XSD_DATE => Ok(Value::try_from_xsd_date(text)?),
XSD_TIME => Ok(Value::try_from_xsd_time(text)?),
XSD_DATE_TIME => Ok(Value::try_from_xsd_date_time(text)?),
XSD_DURATION => Ok(Value::try_from_xsd_duration(text)?),
_ => Err(err_invalid_attribute(&format!("invalid type '{typ}'"))),
};
} else {
Err(err_missing_attribute("simple value must have 'text' attribute"))
}
} else {
Err(err_missing_attribute("simple value must have 'type' attribute"))
}
}
}
impl TryFrom<&ObjectDto> for Value {
type Error = DmntkError;
fn try_from(object: &ObjectDto) -> Result<Self, Self::Error> {
let mut ctx: FeelContext = Default::default();
for item in object {
let item_name = item.name.as_ref().ok_or_else(|| err_invalid_attribute("component must have a name"))?.to_string();
let value = Value::try_from(item)?;
let key: Name = item_name.into();
ctx.set_entry(&key, value);
}
Ok(ctx.into())
}
}
impl TryFrom<&ComponentDto> for Value {
type Error = DmntkError;
fn try_from(value: &ComponentDto) -> Result<Self, Self::Error> {
if value.nil {
return Ok(value_null!());
}
if let Some(v) = &value.value {
Value::try_from(v)
} else {
Err(err_invalid_attribute("component must have a value"))
}
}
}
impl TryFrom<&ListDto> for Value {
type Error = DmntkError;
fn try_from(value: &ListDto) -> Result<Self, Self::Error> {
if value.nil {
return Ok(value_null!());
}
let mut values = vec![];
for item in &value.items {
values.push(Value::try_from(item)?);
}
Ok(Value::List(values))
}
}