Skip to content

Commit

Permalink
The attribute now accepts an optional bool value
Browse files Browse the repository at this point in the history
  • Loading branch information
Jean-Marc Le Roux committed Nov 1, 2024
1 parent 9e85e0e commit cdfb909
Show file tree
Hide file tree
Showing 10 changed files with 182 additions and 17 deletions.
6 changes: 6 additions & 0 deletions utoipa-gen/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Changelog - utoipa-gen

## Unreleased

### Changed

* The `#[schema(ignore)]` attribute now accepts an optional bool value

## 5.1.3 - Oct 27 2024

### Fixed
Expand Down
2 changes: 1 addition & 1 deletion utoipa-gen/src/component/features.rs
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,7 @@ impl ToTokensDiagnostics for Feature {
let name = <attributes::Required as FeatureLike>::get_name();
quote! { .#name(#required) }
}
Feature::Ignore(_) => return Err(Diagnostics::new("Feature::Ignore does not support ToTokens")),
Feature::Ignore(ignore) => quote! { .ignore(Some(#ignore)) },
};

tokens.extend(feature);
Expand Down
22 changes: 17 additions & 5 deletions utoipa-gen/src/component/features/attributes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use syn::{Error, LitStr, Token, TypePath, WherePredicate};

use crate::component::serde::RenameRule;
use crate::component::{schema, GenericType, TypeTree};
use crate::parse_utils::LitStrOrExpr;
use crate::parse_utils::{LitBoolOrExpr, LitStrOrExpr};
use crate::path::parameter::{self, ParameterStyle};
use crate::schema_type::KnownFormat;
use crate::{parse_utils, AnyValue, Array, Diagnostics};
Expand Down Expand Up @@ -983,19 +983,25 @@ impl From<Bound> for Feature {
}
}

// Nothing to parse, it will be parsed true via `parse_features!` when defined as `ignore`
impl_feature! {
/// Ignore feature parsed from macro attributes.
#[derive(Clone)]
#[cfg_attr(feature = "debug", derive(Debug))]
pub struct Ignore;
pub struct Ignore(pub LitBoolOrExpr);
}

impl Parse for Ignore {
fn parse(_: ParseStream, _: Ident) -> syn::Result<Self>
fn parse(input: syn::parse::ParseStream, _: Ident) -> syn::Result<Self>
where
Self: std::marker::Sized,
{
Ok(Self)
parse_utils::parse_next_literal_bool_or_expr(input).map(Self)
}
}

impl ToTokens for Ignore {
fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
tokens.extend(self.0.to_token_stream())
}
}

Expand All @@ -1005,6 +1011,12 @@ impl From<Ignore> for Feature {
}
}

impl From<bool> for Ignore {
fn from(value: bool) -> Self {
Self(value.into())
}
}

// Nothing to parse, it is considered to be set when attribute itself is parsed via
// `parse_features!`.
impl_feature! {
Expand Down
20 changes: 17 additions & 3 deletions utoipa-gen/src/component/into_params.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ use crate::{

use super::{
features::{
impl_into_inner, impl_merge, parse_features, pop_feature, Feature, FeaturesExt, IntoInner,
Merge, ToTokensExt,
attributes, impl_into_inner, impl_merge, parse_features, pop_feature, Feature, FeaturesExt,
IntoInner, Merge, ToTokensExt,
},
serde::{self, SerdeContainer, SerdeValue},
ComponentSchema, Container, TypeTree,
Expand Down Expand Up @@ -122,7 +122,7 @@ impl ToTokensDiagnostics for IntoParams {
.collect::<Result<Vec<_>, Diagnostics>>()?
.into_iter()
.filter_map(|(index, field, field_serde_params, field_features)| {
if field_serde_params.skip || field_features.iter().any(|feature| matches!(feature, Feature::Ignore(_))) {
if field_serde_params.skip {
None
} else {
Some((index, field, field_serde_params, field_features))
Expand Down Expand Up @@ -366,6 +366,20 @@ impl Param {
},
);

// tokens.extend(
// if let Some(ignore) = pop_feature!(param_features => Feature::Ignore(_)) {
// let ignore = ignore.to_token_stream();

// quote! {
// //.ignore(Some(#ignore))
// }
// } else {
// quote! {
// //.ignore(Some(false))
// }
// },
// );

if let Some(deprecated) = super::get_deprecated(&field.attrs) {
tokens.extend(quote! { .deprecated(Some(#deprecated)) });
}
Expand Down
8 changes: 0 additions & 8 deletions utoipa-gen/src/component/schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -549,14 +549,6 @@ impl NamedStructSchema {
.into_inner()
.unwrap_or_default();

if field_features
.iter()
.any(|feature| matches!(feature, Feature::Ignore(_)))
{
// skip ignored field
return Ok(None);
};

if features
.iter()
.any(|feature| matches!(feature, Feature::NoRecursion(_)))
Expand Down
51 changes: 51 additions & 0 deletions utoipa-gen/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3793,4 +3793,55 @@ mod parse_utils {
))
}
}

#[cfg_attr(feature = "debug", derive(Debug))]
#[derive(Clone)]
pub enum LitBoolOrExpr {
LitBool(LitBool),
Expr(Expr),
}

impl From<bool> for LitBoolOrExpr {
fn from(value: bool) -> Self {
Self::LitBool(LitBool::new(value, proc_macro2::Span::call_site()))
}
}

impl Default for LitBoolOrExpr {
fn default() -> Self {
Self::LitBool(LitBool::new(false, proc_macro2::Span::call_site()))
}
}

impl Parse for LitBoolOrExpr {
fn parse(input: ParseStream) -> syn::Result<Self> {
if input.peek(LitBool) {
Ok(LitBoolOrExpr::LitBool(input.parse::<LitBool>()?))
} else {
Ok(LitBoolOrExpr::Expr(input.parse::<Expr>()?))
}
}
}

impl ToTokens for LitBoolOrExpr {
fn to_tokens(&self, tokens: &mut TokenStream) {
match self {
Self::LitBool(bool) => bool.to_tokens(tokens),
Self::Expr(expr) => expr.to_tokens(tokens),
}
}
}

pub fn parse_next_literal_bool_or_expr(input: ParseStream) -> syn::Result<LitBoolOrExpr> {
if input.peek(Token![=]) {
parse_next(input, || LitBoolOrExpr::parse(input)).map_err(|error| {
syn::Error::new(
error.span(),
format!("expected literal bool or expression argument: {error}"),
)
})
} else {
Ok(LitBoolOrExpr::from(true))
}
}
}
46 changes: 46 additions & 0 deletions utoipa-gen/tests/path_derive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2898,6 +2898,52 @@ fn derive_into_params_with_ignored_field() {
)
}

#[test]
fn derive_into_params_with_ignored_eq_alse_field() {
#![allow(unused)]

#[derive(IntoParams)]
#[into_params(parameter_in = Query)]
struct Params {
name: String,
#[param(ignore = false)]
__this_is_private: String,
}

#[utoipa::path(get, path = "/params", params(Params))]
#[allow(unused)]
fn get_params() {}
let operation = test_api_fn_doc! {
get_params,
operation: get,
path: "/params"
};

let value = operation.pointer("/parameters");

assert_json_eq!(
value,
json!([
{
"in": "query",
"name": "name",
"required": true,
"schema": {
"type": "string"
}
},
{
"in": "query",
"name": "__this_is_private",
"required": true,
"schema": {
"type": "string"
}
}
])
)
}

#[test]
fn derive_octet_stream_request_body() {
#![allow(dead_code)]
Expand Down
26 changes: 26 additions & 0 deletions utoipa-gen/tests/schema_derive_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5713,6 +5713,32 @@ fn derive_schema_with_ignored_field() {
)
}

#[test]
fn derive_schema_with_ignored_eq_false_field() {
#![allow(unused)]

let value = api_doc! {
struct SchemaIgnoredField {
value: String,
#[schema(ignore = false)]
__this_is_private: String,
}
};

assert_json_eq!(
value,
json!({
"properties": {
"value": {
"type": "string"
}
},
"required": [ "value" ],
"type": "object"
})
)
}

#[test]
fn derive_schema_unnamed_title() {
#![allow(unused)]
Expand Down
11 changes: 11 additions & 0 deletions utoipa/src/openapi/path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -739,6 +739,10 @@ builder! {
/// Optional extensions "x-something".
#[serde(skip_serializing_if = "Option::is_none", flatten)]
pub extensions: Option<Extensions>,

/// Describes if [`Parameter`] is ignored.
#[serde(skip)]
pub ignore: Option<bool>,
}
}

Expand Down Expand Up @@ -815,6 +819,13 @@ impl ParameterBuilder {
pub fn extensions(mut self, extensions: Option<Extensions>) -> Self {
set_value!(self extensions extensions)
}

/// Define whether [`Parameter`]s are ignored or not.
pub fn ignore(mut self, ignore: Option<bool>) -> Self {
self.ignore = ignore;

self
}
}

/// In definition of [`Parameter`].
Expand Down
7 changes: 7 additions & 0 deletions utoipa/src/openapi/schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1067,6 +1067,9 @@ builder! {
/// See more details at <https://json-schema.org/understanding-json-schema/reference/non_json_data#contentmediatype>
#[serde(skip_serializing_if = "String::is_empty", default)]
pub content_media_type: String,

#[serde(skip)]
pub ignore: Option<bool>,
}
}

Expand Down Expand Up @@ -1289,6 +1292,10 @@ impl ObjectBuilder {
set_value!(self content_media_type content_media_type.into())
}

pub fn ignore(mut self, ignore: Option<bool>) -> Self {
set_value!(self ignore ignore)
}

to_array_builder!();
}

Expand Down

0 comments on commit cdfb909

Please sign in to comment.