Implement `InputType` and `OutputType` for `Box<[T]>` and `Arc<[T]>`. [#805](https://github.com/async-graphql/async-graphql/issues/805)
This commit is contained in:
parent
5563aafacd
commit
bf05607e84
|
@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file.
|
|||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
# [3.0.28] 2022-1-30
|
||||
|
||||
- Implement `InputType` and `OutputType` for `Box<[T]>` and `Arc<[T]>`. [#805](https://github.com/async-graphql/async-graphql/issues/805)
|
||||
|
||||
# [3.0.27] 2022-1-28
|
||||
|
||||
- Fix possible stack overflow in validator, thanks @quapka.
|
||||
|
|
|
@ -1,8 +1,12 @@
|
|||
use std::borrow::Cow;
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::parser::types::Field;
|
||||
use crate::resolver_utils::resolve_list;
|
||||
use crate::{registry, ContextSelectionSet, OutputType, Positioned, ServerResult, Value};
|
||||
use crate::{
|
||||
registry, ContextSelectionSet, InputType, InputValueError, InputValueResult, OutputType,
|
||||
Positioned, ServerResult, Value,
|
||||
};
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl<'a, T: OutputType + 'a> OutputType for &'a [T] {
|
||||
|
@ -27,3 +31,83 @@ impl<'a, T: OutputType + 'a> OutputType for &'a [T] {
|
|||
resolve_list(ctx, field, self.iter(), Some(self.len())).await
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_output_slice_for_smart_ptr {
|
||||
($ty:ty) => {
|
||||
#[async_trait::async_trait]
|
||||
impl<T: OutputType> OutputType for $ty {
|
||||
fn type_name() -> Cow<'static, str> {
|
||||
Cow::Owned(format!("[{}]", T::qualified_type_name()))
|
||||
}
|
||||
|
||||
fn qualified_type_name() -> String {
|
||||
format!("[{}]!", T::qualified_type_name())
|
||||
}
|
||||
|
||||
fn create_type_info(registry: &mut registry::Registry) -> String {
|
||||
T::create_type_info(registry);
|
||||
Self::qualified_type_name()
|
||||
}
|
||||
|
||||
async fn resolve(
|
||||
&self,
|
||||
ctx: &ContextSelectionSet<'_>,
|
||||
field: &Positioned<Field>,
|
||||
) -> ServerResult<Value> {
|
||||
resolve_list(ctx, field, self.iter(), Some(self.len())).await
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl_output_slice_for_smart_ptr!(Box<[T]>);
|
||||
impl_output_slice_for_smart_ptr!(Arc<[T]>);
|
||||
|
||||
macro_rules! impl_input_slice_for_smart_ptr {
|
||||
($ty:ty) => {
|
||||
impl<T: InputType> InputType for $ty {
|
||||
type RawValueType = Self;
|
||||
|
||||
fn type_name() -> Cow<'static, str> {
|
||||
Cow::Owned(format!("[{}]", T::qualified_type_name()))
|
||||
}
|
||||
|
||||
fn qualified_type_name() -> String {
|
||||
format!("[{}]!", T::qualified_type_name())
|
||||
}
|
||||
|
||||
fn create_type_info(registry: &mut registry::Registry) -> String {
|
||||
T::create_type_info(registry);
|
||||
Self::qualified_type_name()
|
||||
}
|
||||
|
||||
fn parse(value: Option<Value>) -> InputValueResult<Self> {
|
||||
match value.unwrap_or_default() {
|
||||
Value::List(values) => values
|
||||
.into_iter()
|
||||
.map(|value| InputType::parse(Some(value)))
|
||||
.collect::<Result<_, _>>()
|
||||
.map_err(InputValueError::propagate),
|
||||
value => {
|
||||
Ok(
|
||||
vec![InputType::parse(Some(value))
|
||||
.map_err(InputValueError::propagate)?]
|
||||
.into(),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn to_value(&self) -> Value {
|
||||
Value::List(self.iter().map(InputType::to_value).collect())
|
||||
}
|
||||
|
||||
fn as_raw_value(&self) -> Option<&Self::RawValueType> {
|
||||
Some(self)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl_input_slice_for_smart_ptr!(Box<[T]>);
|
||||
impl_input_slice_for_smart_ptr!(Arc<[T]>);
|
||||
|
|
|
@ -55,3 +55,29 @@ pub async fn test_input_box_str() {
|
|||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
pub async fn test_input_box_slice() {
|
||||
struct Query;
|
||||
|
||||
#[Object]
|
||||
impl Query {
|
||||
async fn box_slice(&self, s: Box<[i32]>) -> Box<[i32]> {
|
||||
s
|
||||
}
|
||||
|
||||
async fn arc_slice(&self, s: Arc<[i32]>) -> Arc<[i32]> {
|
||||
s
|
||||
}
|
||||
}
|
||||
|
||||
let schema = Schema::new(Query, EmptyMutation, EmptySubscription);
|
||||
let query = r#"{ boxSlice(s: [1, 2, 3]) arcSlice(s: [4, 5, 6]) }"#;
|
||||
assert_eq!(
|
||||
schema.execute(query).await.into_result().unwrap().data,
|
||||
value!({
|
||||
"boxSlice": [1, 2, 3],
|
||||
"arcSlice": [4, 5, 6],
|
||||
})
|
||||
);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue