use async_graphql::async_trait::async_trait;
use async_graphql::{Context, CustomDirective, Directive, ResolveFut, ServerResult, Value};
use super::{MatcherError, ValueTypeName};
#[Directive(location = "Field", name = "shouldHaveLength")]
pub fn should_have_length(n: usize) -> impl CustomDirective {
ShouldHaveLength { len: n }
}
struct ShouldHaveLength {
len: usize,
}
#[async_trait]
impl CustomDirective for ShouldHaveLength {
async fn resolve_field(
&self,
ctx: &Context<'_>,
resolve: ResolveFut<'_>,
) -> ServerResult<Option<Value>> {
match resolve.await {
Ok(None) => Ok(None),
Ok(Some(Value::List(list))) => {
if list.len() == self.len {
Ok(Some(Value::List(list)))
} else {
Err(MatcherError::new(
ctx.item.pos,
format!(
"Expected length: {}\nReceived length: {}\nReceived array: {}",
self.len,
list.len(),
Value::List(list)
),
))
}
}
Ok(Some(Value::String(string))) => {
if string.len() == self.len {
Ok(Some(Value::String(string)))
} else {
Err(MatcherError::new(
ctx.item.pos,
format!(
"Expected length: {}\nReceived length: {}\nReceived string: {}",
self.len,
string.len(),
Value::String(string)
),
))
}
}
Ok(Some(value)) => {
let type_name = ValueTypeName(&value);
Err(MatcherError::new(
ctx.item.pos,
format!(
"@shouldHaveLength error: value must have a length property.\nReceived has type: {type_name}\nReceived has value: {value}"
),
))
}
Err(err) => Err(MatcherError::unexpected_error(err)),
}
}
}