Skip to content

Commit

Permalink
Add support for #[schema(pattern = "...")] on new type structs (#1241)
Browse files Browse the repository at this point in the history
Add support for `#[schema(pattern = "...")]` on new type structs
  • Loading branch information
wyatt-herkamp authored and juhaku committed Dec 18, 2024
1 parent 8ccef78 commit 4bc5ee8
Show file tree
Hide file tree
Showing 4 changed files with 49 additions and 2 deletions.
4 changes: 4 additions & 0 deletions utoipa-gen/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@

* `Info::from_env()` sets `License::identifier` (https://github.com/juhaku/utoipa/pull/1233)

### Added

* Add support for `#[schema(pattern = "...")]` on new type structs (https://github.com/juhaku/utoipa/pull/1241)

## 5.2.0 - Nov 2024

### Fixed
Expand Down
24 changes: 23 additions & 1 deletion utoipa-gen/src/component/schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@ use syn::{

use crate::{
as_tokens_or_diagnostics,
component::features::attributes::{Rename, Title, ValueType},
component::features::{
attributes::{Rename, Title, ValueType},
validation::Pattern,
},
doc_comment::CommentAttributes,
parse_utils::LitBoolOrExprPath,
Array, AttributesExt, Diagnostics, OptionExt, ToTokensDiagnostics,
Expand Down Expand Up @@ -741,6 +744,20 @@ impl UnnamedStructSchema {
));
}
}
let pattern = if let Some(pattern) =
pop_feature!(features => Feature::Pattern(_) as Option<Pattern>)
{
// Pattern Attribute is only allowed for unnamed structs with single field
if fields_len > 1 {
return Err(Diagnostics::with_span(
pattern.span(),
"Pattern attribute is not allowed for unnamed structs with multiple fields",
));
}
Some(pattern.to_token_stream())
} else {
None
};

let comments = CommentAttributes::from_attributes(root.attributes);
let description = description
Expand All @@ -763,6 +780,11 @@ impl UnnamedStructSchema {
})?;

tokens.extend(schema.to_token_stream());
if let Some(pattern) = pattern {
tokens.extend(quote! {
.pattern(Some(#pattern))
});
}
schema_references = std::mem::take(&mut schema.schema_references);
} else {
// Struct that has multiple unnamed fields is serialized to array by default with serde.
Expand Down
3 changes: 2 additions & 1 deletion utoipa-gen/src/component/schema/features.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,8 @@ impl Parse for UnnamedFieldStructFeatures {
ContentEncoding,
ContentMediaType,
Bound,
NoRecursion
NoRecursion,
Pattern
)))
}
}
Expand Down
20 changes: 20 additions & 0 deletions utoipa-gen/tests/schema_derive_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6127,3 +6127,23 @@ fn test_named_and_enum_container_recursion_compiles() {
.expect("OpenApi is JSON serializable");
println!("{json}")
}

#[test]
fn test_new_type_struct_pattern() {
#![allow(unused)]
#[derive(ToSchema)]
#[schema(pattern = r#"^([a-zA-Z0-9_\-]{3,32}$)"#)]
struct Username(String);

use utoipa::PartialSchema;
let schema = <Username as PartialSchema>::schema();
let value = serde_json::to_value(schema).expect("schema is JSON serializable");

assert_json_eq! {
value,
json!({
"pattern": r#"^([a-zA-Z0-9_\-]{3,32}$)"#,
"type": "string"
})
}
}

0 comments on commit 4bc5ee8

Please sign in to comment.