use std::collections::HashMap;
use serde_json::Value as JsonValue;
use thiserror::Error;
use crate::graphql::{
DirectiveError, DirectiveEvaluator, FragmentError, FragmentResolver,
types::{FieldSelection, FragmentDefinition},
};
#[derive(Debug, Error)]
#[non_exhaustive]
pub enum SelectionError {
#[error(transparent)]
Fragment(#[from] FragmentError),
#[error(transparent)]
Directive(#[from] DirectiveError),
}
impl From<SelectionError> for crate::error::FraiseQLError {
fn from(err: SelectionError) -> Self {
let path = match &err {
SelectionError::Fragment(_) => "fragments",
SelectionError::Directive(_) => "directives",
};
Self::Validation {
message: err.to_string(),
path: Some(path.to_string()),
}
}
}
pub fn resolve(
selections: &[FieldSelection],
fragments: &[FragmentDefinition],
max_depth: u32,
) -> Result<Vec<FieldSelection>, SelectionError> {
Ok(FragmentResolver::new(fragments)
.with_max_depth(max_depth)
.resolve_spreads(selections)?)
}
#[allow(clippy::implicit_hasher)]
pub fn filter(
selections: &[FieldSelection],
variables: &HashMap<String, JsonValue>,
) -> Result<Vec<FieldSelection>, SelectionError> {
Ok(DirectiveEvaluator::filter_selections(selections, variables)?)
}
#[allow(clippy::implicit_hasher)]
pub fn resolve_and_filter(
selections: &[FieldSelection],
fragments: &[FragmentDefinition],
variables: &HashMap<String, JsonValue>,
max_depth: u32,
) -> Result<Vec<FieldSelection>, SelectionError> {
filter(&resolve(selections, fragments, max_depth)?, variables)
}
#[must_use]
pub fn variables_map(variables: Option<&JsonValue>) -> HashMap<String, JsonValue> {
match variables {
Some(JsonValue::Object(map)) => map.iter().map(|(k, v)| (k.clone(), v.clone())).collect(),
_ => HashMap::new(),
}
}
#[cfg(test)]
#[path = "selection_set_tests.rs"]
mod selection_set_tests;