Skip to content

Commit

Permalink
fix: default to None when Option missing (#1092)
Browse files Browse the repository at this point in the history
Brings the behaviour of `ValueDeserialize` when working with `Option`s
in line with serde.
  • Loading branch information
obmarg authored Nov 12, 2024
1 parent 6a01e8d commit 2479a51
Show file tree
Hide file tree
Showing 3 changed files with 33 additions and 7 deletions.
11 changes: 7 additions & 4 deletions cynic-parser-deser-macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,11 +109,14 @@ fn value_deser_impl(ast: syn::DeriveInput) -> Result<TokenStream, ()> {
quote! { let #field_name = #field_name.unwrap_or_else(|| #expr); }
}
None => {
let ty = &field.ty;
quote! {
let #field_name = #field_name.ok_or_else(|| cynic_parser_deser::Error::MissingField {
name: #field_name_string.to_string(),
object_span: input.span()
})?;
let #field_name = #field_name
.or(<#ty as ValueDeserialize<#deser_lifetime>>::default_when_missing())
.ok_or_else(|| cynic_parser_deser::Error::MissingField {
name: #field_name_string.to_string(),
object_span: input.span()
})?;
}
}
}
Expand Down
9 changes: 9 additions & 0 deletions cynic-parser-deser/src/deserialize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@ use crate::{value::ValueType, ConstDeserializer, DeserValue, Error};
// ValueDeserialize vs DeserializeValue
pub trait ValueDeserialize<'a>: Sized {
fn deserialize(input: DeserValue<'a>) -> Result<Self, Error>;

/// Provides a default in the case where a field of this type is missing
fn default_when_missing() -> Option<Self> {
None
}
}

pub trait ValueDeserializeOwned: for<'a> ValueDeserialize<'a> {}
Expand Down Expand Up @@ -134,6 +139,10 @@ where
other => T::deserialize(other).map(Some),
}
}

fn default_when_missing() -> Option<Self> {
Some(None)
}
}

impl<'a, T> ValueDeserialize<'a> for Vec<T>
Expand Down
20 changes: 17 additions & 3 deletions cynic-parser-deser/tests/deser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,13 @@ fn test_struct_default() {
#[derive(ValueDeserialize)]
struct FieldDefault {
#[deser(default)]
foo: Option<usize>,
foo: usize,
}

#[test]
fn test_field_default() {
assert_eq!(deser::<FieldDefault>("@id").unwrap().foo, None);
assert_eq!(deser::<FieldDefault>("@id(foo: 10)").unwrap().foo, Some(10));
assert_eq!(deser::<FieldDefault>("@id").unwrap().foo, 0);
assert_eq!(deser::<FieldDefault>("@id(foo: 10)").unwrap().foo, 10);
}

#[derive(ValueDeserialize)]
Expand Down Expand Up @@ -57,6 +57,20 @@ fn test_with() {
assert_eq!(deser::<WithTest>("@id(foo: 25)").unwrap().foo, 100);
}

#[derive(ValueDeserialize)]
struct OptionDefaults {
foo: Option<usize>,
}

#[test]
fn test_option_defaults() {
assert_eq!(deser::<OptionDefaults>("@id").unwrap().foo, None);
assert_eq!(
deser::<OptionDefaults>("@id(foo: 100)").unwrap().foo,
Some(100)
);
}

fn deser<T>(input: &str) -> Result<T, cynic_parser_deser::Error>
where
T: ValueDeserializeOwned,
Expand Down

0 comments on commit 2479a51

Please sign in to comment.