|
5 | 5 | //! that are optional in rust but required in graphql - this is allowed, |
6 | 6 | //! but we need to do a bit of work for rust to be ok with it. |
7 | 7 |
|
| 8 | +use std::borrow::Cow; |
| 9 | + |
8 | 10 | use syn::parse_quote; |
9 | 11 |
|
10 | 12 | use crate::schema::types::{InputType, OutputType, TypeRef}; |
@@ -71,11 +73,38 @@ fn align_input_type_impl<'a>( |
71 | 73 | gql_field_has_default: bool, |
72 | 74 | ) -> RustType<'a> { |
73 | 75 | match (&ty, &gql_ty) { |
74 | | - (RustType::Ref { inner, .. }, _) => { |
75 | | - // Transform the inner types |
76 | | - let new_inner = align_input_type_impl(inner.as_ref(), gql_ty, gql_field_has_default); |
77 | | - ty.clone().replace_inner(new_inner) |
| 76 | + (RustType::Ref { inner, syn, span }, _) => { |
| 77 | + // We need to be careful with lifetimes - if we're doing any additional wrapping we need to |
| 78 | + // make sure that the reference goes _inside_ the wrapper, as otherwise we might end up |
| 79 | + // putting an unsized type inside an Option. e.g. `&'a Option<str>` which won't compile... |
| 80 | + match (inner.as_ref(), gql_ty) { |
| 81 | + (RustType::SimpleType { .. }, TypeRef::List(_)) => { |
| 82 | + let syn = Cow::Owned(parse_quote! { ::std::vec::Vec<#syn> }); |
| 83 | + let wrapped_rust_type = RustType::List { |
| 84 | + syn, |
| 85 | + inner: Box::new(ty.clone()), |
| 86 | + span: *span, |
| 87 | + }; |
| 88 | + align_input_type_impl(&wrapped_rust_type, gql_ty, false) |
| 89 | + } |
| 90 | + (RustType::SimpleType { .. }, TypeRef::Nullable(_)) => { |
| 91 | + let syn = Cow::Owned(parse_quote! { ::core::option::Option<#syn> }); |
| 92 | + let wrapped_rust_type = RustType::Optional { |
| 93 | + syn, |
| 94 | + inner: Box::new(ty.clone()), |
| 95 | + span: *span, |
| 96 | + }; |
| 97 | + align_input_type_impl(&wrapped_rust_type, gql_ty, false) |
| 98 | + } |
| 99 | + _ => { |
| 100 | + // Transform the inner types, preserving the reference. |
| 101 | + let new_inner = |
| 102 | + align_input_type_impl(inner.as_ref(), gql_ty, gql_field_has_default); |
| 103 | + ty.clone().replace_inner(new_inner) |
| 104 | + } |
| 105 | + } |
78 | 106 | } |
| 107 | + |
79 | 108 | (RustType::List { inner, .. }, TypeRef::List(inner_gql)) => { |
80 | 109 | // Transform the inner types |
81 | 110 | let new_inner = align_input_type_impl(inner.as_ref(), inner_gql, false); |
@@ -352,13 +381,41 @@ mod tests { |
352 | 381 | let input_quote = quote! { #input }; |
353 | 382 | let result_quote = quote! { #result }; |
354 | 383 |
|
355 | | - assert_eq!(input, result, "Expected {input_quote} got {result_quote}"); |
| 384 | + assert_eq!(input, result, "expected {input_quote} got {result_quote}"); |
| 385 | + } |
| 386 | + |
| 387 | + #[test] |
| 388 | + fn test_align_reference_types() { |
| 389 | + let input = parse2(quote! { &'a str }).unwrap(); |
| 390 | + |
| 391 | + let result = align_input_type(&input, &nullable(string()), true); |
| 392 | + |
| 393 | + let expected = quote! { ::core::option::Option<&'a str> }.to_string(); |
| 394 | + let result = quote! { #result }.to_string(); |
| 395 | + |
| 396 | + assert_eq!(expected, result, "expected {expected} got {result}"); |
| 397 | + } |
| 398 | + |
| 399 | + #[test] |
| 400 | + fn test_align_double_nested_reference_types() { |
| 401 | + let input = parse2(quote! { &'a str }).unwrap(); |
| 402 | + |
| 403 | + let result = align_input_type(&input, &list(nullable(string())), true); |
| 404 | + |
| 405 | + let result = quote! { #result }.to_string(); |
| 406 | + let expected = quote! { ::std::vec::Vec<::core::option::Option<&'a str> > }.to_string(); |
| 407 | + |
| 408 | + assert_eq!(expected, result, "expected {expected} got {result}"); |
356 | 409 | } |
357 | 410 |
|
358 | 411 | fn integer<'a, Kind>() -> TypeRef<'a, Kind> { |
359 | 412 | TypeRef::Named("Int".into(), PhantomData) |
360 | 413 | } |
361 | 414 |
|
| 415 | + fn string<'a, Kind>() -> TypeRef<'a, Kind> { |
| 416 | + TypeRef::Named("String".into(), PhantomData) |
| 417 | + } |
| 418 | + |
362 | 419 | fn list<Kind>(inner: TypeRef<'_, Kind>) -> TypeRef<'_, Kind> { |
363 | 420 | TypeRef::List(Box::new(inner)) |
364 | 421 | } |
|
0 commit comments