use anyhow::anyhow;
use anyhow::Result;
use serde::Deserialize;
use serde::Serialize;
use serde_json::Value;
use std::collections::HashMap;
use crate::expression::Expression;
pub type Query = HashMap<String, Fragment>;
pub type Selection = HashMap<String, SelectionField>;
#[derive(Deserialize, Serialize, Debug)]
#[serde(try_from = "Value")]
pub struct SelectionField {
pub field_arguments: Option<HashMap<String, Expression>>,
pub field_query: Option<Query>,
}
#[derive(Deserialize, Serialize, Debug)]
#[serde(rename_all = "camelCase")]
pub struct Fragment {
pub object_type_name: String,
pub selection: Selection,
}
impl TryFrom<Value> for SelectionField {
type Error = anyhow::Error;
fn try_from(value: Value) -> Result<Self> {
match value {
Value::Object(object) => {
let field_arguments: Option<HashMap<String, Expression>> = object
.get("fieldArguments")
.map(|field_arguments| match field_arguments {
Value::Object(field_arguments) => field_arguments
.clone()
.into_iter()
.map(|(key, value)| match value.try_into() {
Ok(value) => Ok((key, value)),
Err(error) => Err(error),
})
.collect::<Result<_>>(),
_ => Err(anyhow!("Field arguments must be a JSON object")),
})
.transpose()?;
let field_query: Option<Query> = match object.get("fieldQuery") {
Some(field_query) => serde_json::from_value(field_query.clone())?,
None => None,
};
Ok(Self {
field_arguments,
field_query,
})
}
_ => Err(anyhow!(
"Can only construct a selection field from an object query"
)),
}
}
}