Handle required flattened Option fields

This commit is contained in:
Graham Esau 2021-04-15 18:11:28 +01:00
parent b68132f17d
commit 1a2dafc1a5
5 changed files with 37 additions and 18 deletions

View file

@ -4,9 +4,14 @@ use crate::schema::{Metadata, Schema, SchemaObject};
use crate::JsonSchema; use crate::JsonSchema;
// Helper for generating schemas for flattened `Option` fields. // Helper for generating schemas for flattened `Option` fields.
pub fn json_schema_for_flatten<T: ?Sized + JsonSchema>(gen: &mut SchemaGenerator) -> Schema { pub fn json_schema_for_flatten<T: ?Sized + JsonSchema>(
gen: &mut SchemaGenerator,
required: Option<bool>,
) -> Schema {
let mut schema = T::_schemars_private_non_optional_json_schema(gen); let mut schema = T::_schemars_private_non_optional_json_schema(gen);
if T::_schemars_private_is_option() {
let required = required.unwrap_or_else(|| !T::_schemars_private_is_option());
if !required {
if let Schema::Object(SchemaObject { if let Schema::Object(SchemaObject {
object: Some(ref mut object_validation), object: Some(ref mut object_validation),
.. ..
@ -15,6 +20,7 @@ pub fn json_schema_for_flatten<T: ?Sized + JsonSchema>(gen: &mut SchemaGenerator
object_validation.required.clear(); object_validation.required.clear();
} }
} }
schema schema
} }
@ -28,11 +34,13 @@ pub fn add_schema_as_property<T: ?Sized + JsonSchema>(
) { ) {
let is_type_option = T::_schemars_private_is_option(); let is_type_option = T::_schemars_private_is_option();
let required = required.unwrap_or(!is_type_option); let required = required.unwrap_or(!is_type_option);
let mut schema = if required && is_type_option { let mut schema = if required && is_type_option {
T::_schemars_private_non_optional_json_schema(gen) T::_schemars_private_non_optional_json_schema(gen)
} else { } else {
gen.subschema_for::<T>() gen.subschema_for::<T>()
}; };
schema = apply_metadata(schema, metadata); schema = apply_metadata(schema, metadata);
let object = parent.object(); let object = parent.object();

View file

@ -14,7 +14,8 @@
"regex_str1", "regex_str1",
"regex_str2", "regex_str2",
"required_option", "required_option",
"tel" "tel",
"x"
], ],
"properties": { "properties": {
"min_max": { "min_max": {
@ -76,6 +77,10 @@
}, },
"required_option": { "required_option": {
"type": "boolean" "type": "boolean"
},
"x": {
"type": "integer",
"format": "int32"
} }
} }
} }

View file

@ -32,6 +32,14 @@ pub struct Struct {
map_contains: HashMap<String, ()>, map_contains: HashMap<String, ()>,
#[validate(required)] #[validate(required)]
required_option: Option<bool>, required_option: Option<bool>,
#[validate(required)]
#[serde(flatten)]
required_flattened: Option<Inner>,
}
#[derive(Debug, JsonSchema)]
pub struct Inner {
x: i32,
} }
#[test] #[test]

View file

@ -120,17 +120,9 @@ impl ValidationAttrs {
self self
} }
pub fn validation_statements(&self, field_name: &str) -> TokenStream { pub fn validation_statements(&self, field_name: &str) -> Option<TokenStream> {
// Assume that the result will be interpolated in a context with the local variable // Assume that the result will be interpolated in a context with the local variable
// `schema_object` - the SchemaObject for the struct that contains this field. // `schema_object` - the SchemaObject for the struct that contains this field.
let mut statements = Vec::new();
// if self.required {
// statements.push(quote! {
// schema_object.object().required.insert(#field_name.to_owned());
// });
// }
let mut array_validation = Vec::new(); let mut array_validation = Vec::new();
let mut number_validation = Vec::new(); let mut number_validation = Vec::new();
let mut object_validation = Vec::new(); let mut object_validation = Vec::new();
@ -210,7 +202,7 @@ impl ValidationAttrs {
|| string_validation.is_some() || string_validation.is_some()
|| format.is_some() || format.is_some()
{ {
statements.push(quote! { Some(quote! {
if let Some(schemars::schema::Schema::Object(prop_schema_object)) = schema_object if let Some(schemars::schema::Schema::Object(prop_schema_object)) = schema_object
.object .object
.as_mut() .as_mut()
@ -222,10 +214,10 @@ impl ValidationAttrs {
#string_validation #string_validation
#format #format
} }
}); })
} else {
None
} }
statements.into_iter().collect()
} }
} }

View file

@ -449,9 +449,15 @@ fn expr_for_struct(
type_defs.push(type_def); type_defs.push(type_def);
} }
let gen = quote!(gen); let required = if field.validation_attrs.required {
quote!(Some(true))
} else {
quote!(None)
};
let args = quote!(gen, #required);
quote_spanned! {ty.span()=> quote_spanned! {ty.span()=>
.flatten(schemars::_private::json_schema_for_flatten::<#ty>(#gen)) .flatten(schemars::_private::json_schema_for_flatten::<#ty>(#args))
} }
}) })
.collect(); .collect();