Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix tuple params missing features #928

Merged
merged 1 commit into from
May 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions utoipa-gen/src/path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,12 +76,12 @@ impl<'p> PathAttr<'p> {
) {
let ext_params = ext_parameters.into_iter();

let (existing_params, new_params): (Vec<Parameter>, Vec<Parameter>) =
let (existing_incoming_params, new_params): (Vec<Parameter>, Vec<Parameter>) =
ext_params.partition(|param| self.params.iter().any(|p| p == param));

for existing in existing_params {
if let Some(param) = self.params.iter_mut().find(|p| **p == existing) {
param.merge(existing);
for existing_incoming in existing_incoming_params {
if let Some(param) = self.params.iter_mut().find(|p| **p == existing_incoming) {
param.merge(existing_incoming);
}
}

Expand Down
15 changes: 11 additions & 4 deletions utoipa-gen/src/path/parameter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,12 @@ impl<'p> Parameter<'p> {
pub fn merge(&mut self, other: Parameter<'p>) {
match (self, other) {
(Self::Value(value), Parameter::Value(other)) => {
let (schema_features, _) = &value.features;
value.parameter_schema = other.parameter_schema;

if let Some(parameter_schema) = &mut value.parameter_schema {
parameter_schema.features.clone_from(schema_features);
}
}
(Self::IntoParamsIdent(into_params), Parameter::IntoParamsIdent(other)) => {
*into_params = other;
Expand Down Expand Up @@ -157,7 +162,7 @@ impl ToTokensDiagnostics for ParameterSchema<'_> {
ParameterType::External(type_tree) => {
let required: Required = (!type_tree.is_option()).into();

Ok(to_tokens(
to_tokens(
ComponentSchema::new(component::ComponentSchemaProps {
type_tree,
features: Some(self.features.clone()),
Expand All @@ -166,7 +171,8 @@ impl ToTokensDiagnostics for ParameterSchema<'_> {
object_name: "",
}),
required,
))
);
Ok(())
}
ParameterType::Parsed(inline_type) => {
let type_tree = inline_type.as_type_tree()?;
Expand All @@ -175,7 +181,7 @@ impl ToTokensDiagnostics for ParameterSchema<'_> {
schema_features.clone_from(&self.features);
schema_features.push(Feature::Inline(inline_type.is_inline.into()));

Ok(to_tokens(
to_tokens(
ComponentSchema::new(component::ComponentSchemaProps {
type_tree: &type_tree,
features: Some(schema_features),
Expand All @@ -184,7 +190,8 @@ impl ToTokensDiagnostics for ParameterSchema<'_> {
object_name: "",
}),
required,
))
);
Ok(())
}
}
}
Expand Down
144 changes: 144 additions & 0 deletions utoipa-gen/tests/path_derive_axum_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,7 @@ fn get_todo_with_extension() {
fn derive_path_params_into_params_unnamed() {
#[derive(Deserialize, IntoParams)]
#[into_params(names("id", "name"))]
#[allow(dead_code)]
struct IdAndName(u64, String);

#[utoipa::path(
Expand Down Expand Up @@ -235,6 +236,7 @@ fn derive_path_params_with_ignored_parameter() {
struct Auth;
#[derive(Deserialize, IntoParams)]
#[into_params(names("id", "name"))]
#[allow(dead_code)]
struct IdAndName(u64, String);

#[utoipa::path(
Expand Down Expand Up @@ -537,6 +539,7 @@ fn path_param_single_arg_primitive_type() {
#[test]
fn path_param_single_arg_non_primitive_type() {
#[derive(utoipa::ToSchema)]
#[allow(dead_code)]
struct Id(String);

#[utoipa::path(
Expand Down Expand Up @@ -577,6 +580,7 @@ fn path_param_single_arg_non_primitive_type() {
fn path_param_single_arg_non_primitive_type_into_params() {
#[derive(utoipa::ToSchema, utoipa::IntoParams)]
#[into_params(names("id"))]
#[allow(dead_code)]
struct Id(String);

#[utoipa::path(
Expand Down Expand Up @@ -611,3 +615,143 @@ fn path_param_single_arg_non_primitive_type_into_params() {
])
)
}

#[test]
fn derive_path_with_validation_attributes_axum() {
#[derive(IntoParams)]
#[allow(dead_code)]
struct Params {
#[param(maximum = 10, minimum = 5, multiple_of = 2.5)]
id: i32,

#[param(max_length = 10, min_length = 5, pattern = "[a-z]*")]
value: String,

#[param(max_items = 5, min_items = 1)]
items: Vec<String>,
}

#[utoipa::path(
get,
path = "foo/{foo_id}",
responses(
(status = 200, description = "success response")
),
params(
("foo_id" = String, Path, min_length = 1, description = "Id of Foo to get"),
Params,
("name" = Option<String>, description = "Foo name", min_length = 3),
("nonnullable" = String, description = "Foo nonnullable", min_length = 3, max_length = 10),
("namequery" = Option<String>, Query, description = "Foo name", min_length = 3),
("nonnullablequery" = String, Query, description = "Foo nonnullable", min_length = 3, max_length = 10),
)
)]
#[allow(unused)]
fn get_foo(path: Path<String>, query: Query<Params>) {}

#[derive(OpenApi, Default)]
#[openapi(paths(get_foo))]
struct ApiDoc;

let doc = serde_json::to_value(ApiDoc::openapi()).unwrap();
let parameters = doc.pointer("/paths/foo~1{foo_id}/get/parameters").unwrap();

let config = Config::new(CompareMode::Strict).numeric_mode(NumericMode::AssumeFloat);

assert_json_matches!(
parameters,
json!([
{
"schema": {
"type": "string",
"minLength": 1,
},
"required": true,
"name": "foo_id",
"in": "path",
"description": "Id of Foo to get"
},
{
"schema": {
"format": "int32",
"type": "integer",
"maximum": 10.0,
"minimum": 5.0,
"multipleOf": 2.5,
},
"required": true,
"name": "id",
"in": "query"
},
{
"schema": {
"type": "string",
"maxLength": 10,
"minLength": 5,
"pattern": "[a-z]*"
},
"required": true,
"name": "value",
"in": "query"
},
{
"schema": {
"type": "array",
"items": {
"type": "string",
},
"maxItems": 5,
"minItems": 1,
},
"required": true,
"name": "items",
"in": "query"
},
{
"schema": {
"type": "string",
"nullable": true,
"minLength": 3,
},
"required": true,
"name": "name",
"in": "path",
"description": "Foo name"
},
{
"schema": {
"type": "string",
"minLength": 3,
"maxLength": 10,
},
"required": true,
"name": "nonnullable",
"in": "path",
"description": "Foo nonnullable"
},
{
"schema": {
"type": "string",
"nullable": true,
"minLength": 3,
},
"required": false,
"name": "namequery",
"in": "query",
"description": "Foo name"
},
{
"schema": {
"type": "string",
"minLength": 3,
"maxLength": 10,
},
"required": true,
"name": "nonnullablequery",
"in": "query",
"description": "Foo nonnullable"
}
]),
config
);
}
8 changes: 5 additions & 3 deletions utoipa-gen/tests/path_parameter_derive_actix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,8 @@ fn derive_params_from_method_args_actix_success() {
}

#[test]
fn derive_path_with_date_params_implicit() {
#[cfg(feature = "chrono")]
fn derive_path_with_date_params_chrono_implicit() {
mod mod_derive_path_with_date_params {
use actix_web::{get, web, HttpResponse, Responder};
use chrono::{DateTime, Utc};
Expand Down Expand Up @@ -221,7 +222,8 @@ fn derive_path_with_date_params_implicit() {
}

#[test]
fn derive_path_with_date_params_explicit_ignored() {
#[cfg(feature = "time")]
fn derive_path_with_date_params_explicit_ignored_time() {
mod mod_derive_path_with_date_params {
use actix_web::{get, web, HttpResponse, Responder};
use serde_json::json;
Expand Down Expand Up @@ -270,6 +272,6 @@ fn derive_path_with_date_params_explicit_ignored() {
"[1].required" = r#"true"#, "Parameter required"
"[1].deprecated" = r#"null"#, "Parameter deprecated"
"[1].schema.type" = r#""string""#, "Parameter schema type"
"[1].schema.format" = r#"null"#, "Parameter schema format"
"[1].schema.format" = r#""date-time""#, "Parameter schema format"
};
}
Loading