use serde::{Deserialize, Serialize, de::DeserializeOwned};
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum OneOrMany<T> {
One(T),
Many(Vec<T>),
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Expression {
#[serde(rename = "$jmespath")]
pub jmespath: String,
}
impl Expression {
pub fn compile_one_or_many<T>(
&self,
params: &super::Params,
) -> Result<OneOrMany<T>, super::ExpressionError>
where
T: DeserializeOwned,
{
let expr = super::JMESPATH_RUNTIME.compile(&self.jmespath)?;
let value = expr.search(params)?;
let value = serde_json::to_value(value).unwrap();
let value: Option<OneOrMany<Option<T>>> = serde_json::from_value(value)
.map_err(super::ExpressionError::DeserializationError)?;
Ok(match value {
Some(OneOrMany::One(Some(v))) => OneOrMany::One(v),
Some(OneOrMany::One(None)) => OneOrMany::Many(Vec::new()),
Some(OneOrMany::Many(mut vs)) => {
vs.retain(|v| v.is_some());
if vs.len() == 0 {
OneOrMany::Many(Vec::new())
} else if vs.len() == 1 {
OneOrMany::One(
vs.into_iter().filter_map(|v| v).next().unwrap(),
)
} else {
OneOrMany::Many(vs.into_iter().filter_map(|v| v).collect())
}
}
None => OneOrMany::Many(Vec::new()),
})
}
pub fn compile_one<T>(
&self,
params: &super::Params,
) -> Result<T, super::ExpressionError>
where
T: DeserializeOwned,
{
let result = self.compile_one_or_many(params)?;
match result {
OneOrMany::One(value) => Ok(value),
OneOrMany::Many(_) => {
Err(super::ExpressionError::ExpectedOneValueFoundMany)
}
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum WithExpression<T> {
Expression(Expression),
Value(T),
}
impl<T> std::default::Default for WithExpression<T>
where
T: Default,
{
fn default() -> Self {
WithExpression::Value(T::default())
}
}
impl<T> WithExpression<T>
where
T: DeserializeOwned,
{
pub fn compile_one_or_many(
self,
params: &super::Params,
) -> Result<OneOrMany<T>, super::ExpressionError> {
match self {
WithExpression::Expression(expr) => {
expr.compile_one_or_many(params)
}
WithExpression::Value(value) => Ok(OneOrMany::One(value)),
}
}
pub fn compile_one(
self,
params: &super::Params,
) -> Result<T, super::ExpressionError> {
match self {
WithExpression::Expression(expr) => expr.compile_one(params),
WithExpression::Value(value) => Ok(value),
}
}
}