From 010dbaa4974ded93fc8087b9abe4e732e4507ebe Mon Sep 17 00:00:00 2001 From: Kurt Wolf Date: Sat, 11 Jan 2025 09:39:19 -0500 Subject: [PATCH] use required instead of changing option<$ref> into allOf --- core/src/schema.rs | 22 ++----- macro/src/util.rs | 85 ++++++++++++++++--------- oasgen/tests/test-none/02-required.yaml | 3 +- oasgen/tests/test-none/03-newtype.yaml | 7 +- 4 files changed, 64 insertions(+), 53 deletions(-) diff --git a/core/src/schema.rs b/core/src/schema.rs index f2dfcd1..c3cc7ed 100644 --- a/core/src/schema.rs +++ b/core/src/schema.rs @@ -1,6 +1,6 @@ use std::collections::HashMap; -use openapiv3::{RefOr, ReferenceOr, Schema, SchemaData, SchemaKind}; +use openapiv3::{ReferenceOr, Schema}; #[cfg(feature = "actix")] mod actix; @@ -124,21 +124,11 @@ where fn schema_ref() -> ReferenceOr { let mut schema = T::schema_ref(); - match schema.as_mut() { - Some(s) => { - s.nullable = true; - schema - } - None => RefOr::Item(Schema { - data: SchemaData { - nullable: true, - ..Default::default() - }, - kind: SchemaKind::AllOf { - all_of: vec![schema], - }, - }), - } + let Some(s) = schema.as_mut() else { + return schema; + }; + s.nullable = true; + schema } } diff --git a/macro/src/util.rs b/macro/src/util.rs index 904583d..c272880 100644 --- a/macro/src/util.rs +++ b/macro/src/util.rs @@ -7,6 +7,16 @@ use serde_derive_internals::{ attr::TagType, }; +fn is_option(ty: &syn::Type) -> bool { + let syn::Type::Path(p) = ty else { + return false; + }; + let Some(segment) = p.path.segments.first() else { + return false; + }; + segment.ident == "Option" +} + pub fn impl_OaSchema_schema(fields: &[Field], docstring: Option) -> TokenStream2 { if fields.len() == 1 { let field = fields.first().unwrap(); @@ -17,11 +27,13 @@ pub fn impl_OaSchema_schema(fields: &[Field], docstring: Option) -> Toke }; } } - let description = docstring.map(|s| { - quote! { - o.description = Some(#s.into()); - } - }).unwrap_or_default(); + let description = docstring + .map(|s| { + quote! { + o.description = Some(#s.into()); + } + }) + .unwrap_or_default(); let properties = fields .into_iter() .map(|f| { @@ -48,7 +60,7 @@ pub fn impl_OaSchema_schema(fields: &[Field], docstring: Option) -> Toke } } } else { - let required = !(attr.skip || attr.skip_serializing_if.is_some()); + let required = !(attr.skip || attr.skip_serializing_if.is_some() || is_option(ty)); let required = required.then(|| { quote! { o.required_mut().push(#name.to_string()); } }).unwrap_or_default(); @@ -79,7 +91,11 @@ pub fn impl_OaSchema_schema(fields: &[Field], docstring: Option) -> Toke } /// Create OaSchema derive token stream for a struct from ident and fields -pub fn derive_oaschema_struct(ident: &Ident, fields: &[Field], docstring: Option) -> TokenStream { +pub fn derive_oaschema_struct( + ident: &Ident, + fields: &[Field], + docstring: Option, +) -> TokenStream { let schema = impl_OaSchema_schema(fields, docstring); let name = ident.to_string(); let submit = quote! { @@ -97,17 +113,21 @@ pub fn derive_oaschema_struct(ident: &Ident, fields: &[Field], docstring: Option } } #submit - }.into() + } + .into() } /// Create OaSchema derive token stream for an enum from ident and variants -pub fn derive_oaschema_enum(ident: &Ident, variants: &[Variant], tag: &TagType, _docstring: Option) -> TokenStream { - let variants = variants - .into_iter() - .filter(|v| { - let openapi_attrs = FieldAttributes::try_from(&v.original.attrs).unwrap(); - !openapi_attrs.skip - }); +pub fn derive_oaschema_enum( + ident: &Ident, + variants: &[Variant], + tag: &TagType, + _docstring: Option, +) -> TokenStream { + let variants = variants.into_iter().filter(|v| { + let openapi_attrs = FieldAttributes::try_from(&v.original.attrs).unwrap(); + !openapi_attrs.skip + }); let mut complex_variants = vec![]; let mut str_variants = vec![]; for v in variants { @@ -172,19 +192,22 @@ pub fn derive_oaschema_enum(ident: &Ident, variants: &[Variant], tag: &TagType, if str_variants.len() > 0 { match tag { - TagType::External => complex_variants.push(quote! { ::oasgen::Schema::new_str_enum(vec![#(#str_variants)*]) }), - TagType::Internal { tag } | TagType::Adjacent { tag, .. } => complex_variants.push(quote! {{ - let mut o = ::oasgen::Schema::new_object(); - let values = vec![#(#str_variants)*]; - o.properties_mut().insert(#tag, ::oasgen::Schema::new_str_enum(values)); - o.required_mut().push(#tag.to_string()); - o - }}), - _ => () // a null case should be handled, which will deserialize to the first unit - // variant, but unsure how to handle this case. I tried an enum with - // type: 'null', which is supported in glademiller:openapiv3, but not in - // kurtbuilds:openapiv3 - // kurt: I believe null enum is handled by setting nullable: true. + TagType::External => complex_variants + .push(quote! { ::oasgen::Schema::new_str_enum(vec![#(#str_variants)*]) }), + TagType::Internal { tag } | TagType::Adjacent { tag, .. } => { + complex_variants.push(quote! {{ + let mut o = ::oasgen::Schema::new_object(); + let values = vec![#(#str_variants)*]; + o.properties_mut().insert(#tag, ::oasgen::Schema::new_str_enum(values)); + o.required_mut().push(#tag.to_string()); + o + }}) + } + _ => (), // a null case should be handled, which will deserialize to the first unit + // variant, but unsure how to handle this case. I tried an enum with + // type: 'null', which is supported in glademiller:openapiv3, but not in + // kurtbuilds:openapiv3 + // kurt: I believe null enum is handled by setting nullable: true. } } @@ -211,7 +234,8 @@ pub fn derive_oaschema_enum(ident: &Ident, variants: &[Variant], tag: &TagType, } } #submit - }.into() + } + .into() } pub fn derive_oaschema_newtype(ident: &Ident, field: &Field) -> TokenStream { @@ -226,5 +250,6 @@ pub fn derive_oaschema_newtype(ident: &Ident, field: &Field) -> TokenStream { <#ty as OaSchema>::schema() } } - }.into() + } + .into() } diff --git a/oasgen/tests/test-none/02-required.yaml b/oasgen/tests/test-none/02-required.yaml index c35aebc..0a2afa6 100644 --- a/oasgen/tests/test-none/02-required.yaml +++ b/oasgen/tests/test-none/02-required.yaml @@ -9,5 +9,4 @@ properties: nullable: true type: string required: -- is_required -- is_nullable \ No newline at end of file +- is_required \ No newline at end of file diff --git a/oasgen/tests/test-none/03-newtype.yaml b/oasgen/tests/test-none/03-newtype.yaml index 84558c0..fbf7292 100644 --- a/oasgen/tests/test-none/03-newtype.yaml +++ b/oasgen/tests/test-none/03-newtype.yaml @@ -17,11 +17,8 @@ properties: required: - test prop_d: - nullable: true - allOf: - - $ref: '#/components/schemas/Struct' + $ref: '#/components/schemas/Struct' required: - id - prop_a -- prop_b -- prop_d \ No newline at end of file +- prop_b \ No newline at end of file