use std::fmt::{Debug, Display, Formatter};
use async_graphql::async_trait::async_trait;
use async_graphql::{Any, Context, CustomDirective, Directive, ResolveFut, ServerResult, Value};
use super::MatcherError;
#[Directive(location = "Field", name = "shouldBeOneOf")]
pub fn should_be_one_of(list: Vec<Option<Any>>) -> impl CustomDirective {
ShouldBeOneOf {
list: list
.into_iter()
.map(|any| any.map_or(Value::Null, |it| it.0))
.collect(),
}
}
struct ShouldBeOneOf {
list: Vec<Value>,
}
impl Display for ShouldBeOneOf {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
self.list.fmt(f)
}
}
#[async_trait]
impl CustomDirective for ShouldBeOneOf {
async fn resolve_field(
&self,
ctx: &Context<'_>,
resolve: ResolveFut<'_>,
) -> ServerResult<Option<Value>> {
match resolve.await {
Ok(None) => Ok(None),
Ok(Some(value)) => {
if self.list.contains(&value) {
Ok(Some(value))
} else {
Err(MatcherError::new(
ctx.item.pos,
format!("Expected: one of {self}\nReceived: {value}"),
))
}
}
Err(err) => Err(MatcherError::unexpected_error(err)),
}
}
}