Skip to content

Commit

Permalink
Do not inline non-primitive type parameters by default
Browse files Browse the repository at this point in the history
  • Loading branch information
Jean-Marc Le Roux committed Nov 4, 2024
1 parent a792520 commit dce8e51
Show file tree
Hide file tree
Showing 7 changed files with 112 additions and 7 deletions.
14 changes: 12 additions & 2 deletions utoipa-gen/src/component.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1255,8 +1255,18 @@ impl ComponentSchema {

schema.to_tokens(tokens);
} else {
let index = container.generics.get_generic_type_param_index(type_tree);
// only set schema references tokens for concrete non generic types
let schema_type = SchemaType {
path: Cow::Borrowed(&rewritten_path),
nullable,
};
let index =
if schema_type.is_primitive() || type_tree.generic_type.is_none() {
container.generics.get_generic_type_param_index(type_tree)
} else {
None
};

// forcibly inline primitive type parameters, otherwise use references
if index.is_none() {
let reference_tokens = if let Some(children) = &type_tree.children {
let composed_generics = Self::compose_generics(
Expand Down
58 changes: 58 additions & 0 deletions utoipa-gen/tests/openapi_derive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -553,6 +553,64 @@ fn derive_nest_openapi_with_tags() {
)
}

#[test]
fn openapi_schemas_resolve_generic_enum_schema() {
#![allow(dead_code)]
use utoipa::ToSchema;

#[derive(ToSchema)]
enum Element<T> {
One(T),
Many(Vec<T>),
}

#[derive(OpenApi)]
#[openapi(components(schemas(Element<String>)))]
struct ApiDoc;

let doc = ApiDoc::openapi();

let value = serde_json::to_value(&doc).expect("OpenAPI is JSON serializable");
let schemas = value.pointer("/components/schemas").unwrap();
let json = serde_json::to_string_pretty(&schemas).expect("OpenAPI is json serializable");
println!("{json}");

assert_json_eq!(
schemas,
json!({
"Element_String": {
"oneOf": [
{
"properties": {
"One": {
"type": "string"
}
},
"required": [
"One"
],
"type": "object"
},
{
"properties": {
"Many": {
"items": {
"type": "string"
},
"type": "array"
}
},
"required": [
"Many"
],
"type": "object"
}
]
}
})
)
}

#[test]
fn openapi_schemas_resolve_schema_references() {
#![allow(dead_code)]
Expand Down
2 changes: 2 additions & 0 deletions utoipa-gen/tests/path_derive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2655,6 +2655,7 @@ fn derive_path_test_collect_generic_array_request_body() {

#[derive(ToSchema)]
struct CreateRequest<T> {
#[schema(inline)]
value: T,
}

Expand Down Expand Up @@ -2744,6 +2745,7 @@ fn derive_path_test_collect_generic_request_body() {

#[derive(ToSchema)]
struct CreateRequest<T> {
#[schema(inline)]
value: T,
}

Expand Down
13 changes: 11 additions & 2 deletions utoipa-gen/tests/schema_generics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,17 @@ fn generic_schema_full_api() {
#[derive(ToSchema)]
#[schema(as = path::MyType<T>)]
struct Type<T> {
#[schema(inline)]
t: T,
}

#[derive(ToSchema)]
struct Person<'p, T: Sized, P> {
id: usize,
name: Option<Cow<'p, str>>,
#[schema(inline)]
field: T,
#[schema(inline)]
t: P,
}

Expand All @@ -47,14 +50,15 @@ fn generic_schema_full_api() {
total: usize,
page: usize,
pages: usize,
#[schema(inline)]
items: Vec<T>,
}

#[derive(ToSchema)]
#[schema(as = path::to::Element<T>)]
enum E<T> {
One(T),
Many(Vec<T>),
One(#[schema(inline)] T),
Many(#[schema(inline)] Vec<T>),
}

struct NoToSchema;
Expand Down Expand Up @@ -107,6 +111,7 @@ fn schema_with_non_generic_root() {

#[derive(ToSchema)]
struct Bar<T> {
#[schema(inline)]
value: T,
}

Expand Down Expand Up @@ -172,6 +177,7 @@ fn derive_generic_schema_collect_recursive_schema_not_inlined() {

#[derive(ToSchema)]
pub struct FooStruct<B> {
#[schema(inline)]
pub foo: B,
}

Expand All @@ -182,6 +188,7 @@ fn derive_generic_schema_collect_recursive_schema_not_inlined() {
pub struct Person<T> {
name: String,
account: Account,
#[schema(inline)]
t: T,
}

Expand All @@ -192,6 +199,7 @@ fn derive_generic_schema_collect_recursive_schema_not_inlined() {

#[derive(ToSchema, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Ty<T> {
#[schema(inline)]
t: T,
}

Expand Down Expand Up @@ -231,6 +239,7 @@ fn high_order_types() {

#[derive(ToSchema)]
pub struct High<T> {
#[schema(inline)]
high: T,
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
"properties": {
"Many": {
"items": {
"type": "object"
"type": "string"
},
"type": "array"
}
Expand Down Expand Up @@ -95,6 +95,32 @@
"properties": {
"Many": {
"items": {
"properties": {
"accounts": {
"items": {
"oneOf": [
{
"type": "null"
},
{
"$ref": "#/components/schemas/Account"
}
]
},
"type": "array"
},
"foo_bar": {
"$ref": "#/components/schemas/Foobar"
},
"name": {
"type": "string"
}
},
"required": [
"name",
"foo_bar",
"accounts"
],
"type": "object"
},
"type": "array"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@
},
"t": {
"type": "integer",
"format": "int32"
"format": "int64"
}
}
},
Expand Down
2 changes: 1 addition & 1 deletion utoipa-gen/tests/testdata/schema_generics_openapi
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@
"Many": {
"type": "array",
"items": {
"type": "object"
"type": "string"
}
}
}
Expand Down

0 comments on commit dce8e51

Please sign in to comment.