use std::fmt::{Display, Formatter};
use async_graphql::async_trait::async_trait;
use async_graphql::{Context, CustomDirective, Directive, ResolveFut, ServerResult, Value};
use super::{MatcherError, Numeric, ValueTypeName};
#[Directive(location = "Field", name = "shouldBeLessThan")]
pub fn should_be_less_than(
i: Option<i64>,
f: Option<f64>,
bi: Option<String>,
) -> impl CustomDirective {
let num = if let Some(i) = i {
Numeric::Int(i)
} else if let Some(f) = f {
Numeric::Float(f)
} else if let Some(s) = bi {
Numeric::String(s)
} else {
panic!("@shouldBeLess missing an argument")
};
ShouldBeLessThan { num }
}
struct ShouldBeLessThan {
num: Numeric,
}
impl Display for ShouldBeLessThan {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
self.num.fmt(f)
}
}
#[async_trait]
impl CustomDirective for ShouldBeLessThan {
async fn resolve_field(
&self,
ctx: &Context<'_>,
resolve: ResolveFut<'_>,
) -> ServerResult<Option<Value>> {
match resolve.await {
Ok(None) => Ok(None),
Ok(Some(Value::Number(num))) => {
if self.num < num {
Ok(Some(Value::Number(num)))
} else {
Err(MatcherError::new(
ctx.item.pos,
format!("Expected: < {self}\nReceived: {num}"),
))
}
}
Ok(Some(value)) => {
let type_name = ValueTypeName(&value);
Err(MatcherError::new(
ctx.item.pos,
format!(
"@shouldBeLess error: value must be numeric.\nReceived has type: {type_name}\nReceived has value: {value}"
),
))
}
Err(err) => Err(MatcherError::unexpected_error(err)),
}
}
}