1use std::borrow::Cow;
2use std::fmt::Debug;
3
4use serde::Serialize;
5use utoipa::openapi::path::ParameterStyle;
6use utoipa::openapi::{RefOr, Schema};
7use utoipa::{PartialSchema, ToSchema};
8
9use super::ApiClientError;
10
11pub trait ParameterValue: Serialize + ToSchema + Debug + Send + Sync + Clone + 'static {}
16
17impl<T> ParameterValue for T where T: Serialize + ToSchema + Debug + Send + Sync + Clone + 'static {}
19
20#[derive(Debug, Clone, Copy, PartialEq, Eq)]
48pub enum ParamStyle {
49 Default,
51 Form,
53 Simple,
55 SpaceDelimited,
57 PipeDelimited,
59 Label,
61 Matrix,
63 DeepObject,
65}
66
67impl From<ParamStyle> for Option<ParameterStyle> {
68 fn from(value: ParamStyle) -> Self {
69 let result = match value {
70 ParamStyle::Default => return None,
71 ParamStyle::Form => ParameterStyle::Form,
72 ParamStyle::Simple => ParameterStyle::Simple,
73 ParamStyle::SpaceDelimited => ParameterStyle::SpaceDelimited,
74 ParamStyle::PipeDelimited => ParameterStyle::PipeDelimited,
75 ParamStyle::Label => ParameterStyle::Label,
76 ParamStyle::Matrix => ParameterStyle::Matrix,
77 ParamStyle::DeepObject => ParameterStyle::DeepObject,
78 };
79 Some(result)
80 }
81}
82
83#[derive(Debug, Clone)]
85pub struct ParamValue<T>
86where
87 T: Serialize + ToSchema + Debug + Send + Sync + Clone,
88{
89 pub value: T,
91 pub style: ParamStyle,
93}
94
95#[derive(Debug, Clone)]
100pub(super) struct ResolvedParamValue {
101 pub value: serde_json::Value,
103 pub schema: RefOr<Schema>,
105 pub style: ParamStyle,
107}
108
109impl<T> ParamValue<T>
110where
111 T: Serialize + ToSchema + Debug + Send + Sync + Clone,
112{
113 pub fn new(value: T) -> Self {
115 Self {
116 value,
117 style: ParamStyle::Default,
118 }
119 }
120
121 pub fn with_style(value: T, style: ParamStyle) -> Self {
123 Self { value, style }
124 }
125
126 pub fn query_style(&self) -> ParamStyle {
128 match self.style {
129 ParamStyle::Default => ParamStyle::Form,
130 style => style,
131 }
132 }
133
134 pub fn path_style(&self) -> ParamStyle {
136 match self.style {
137 ParamStyle::Default => ParamStyle::Simple,
138 style => style,
139 }
140 }
141
142 pub fn header_style(&self) -> ParamStyle {
144 match self.style {
145 ParamStyle::Default => ParamStyle::Simple,
146 style => style,
147 }
148 }
149
150 pub fn as_query_value(&self) -> Option<serde_json::Value> {
154 serde_json::to_value(&self.value).ok()
155 }
156
157 pub fn as_header_value(&self) -> Result<serde_json::Value, ApiClientError> {
159 serde_json::to_value(&self.value).map_err(|e| ApiClientError::SerializationError {
160 message: format!("Failed to serialize header value: {e}"),
161 })
162 }
163
164 pub(super) fn resolve<F>(&self, add_schema_fn: F) -> Option<ResolvedParamValue>
169 where
170 F: FnOnce(serde_json::Value) -> RefOr<Schema>,
171 {
172 self.as_query_value().map(|value| {
173 let schema = add_schema_fn(value.clone());
174 ResolvedParamValue {
175 value,
176 schema,
177 style: self.style,
178 }
179 })
180 }
181}
182
183impl ResolvedParamValue {
184 fn json_value_to_string(value: &serde_json::Value) -> Result<String, ApiClientError> {
189 match value {
190 serde_json::Value::String(s) => Ok(s.clone()),
191 serde_json::Value::Number(n) => Ok(n.to_string()),
192 serde_json::Value::Bool(b) => Ok(b.to_string()),
193 serde_json::Value::Null => Ok(String::new()),
194 serde_json::Value::Array(_) | serde_json::Value::Object(_) => {
195 Err(ApiClientError::UnsupportedParameterValue {
196 message: "nested complex values not supported in parameters".to_string(),
197 value: value.clone(),
198 })
199 }
200 }
201 }
202
203 fn array_to_string_values(arr: &[serde_json::Value]) -> Result<Vec<String>, ApiClientError> {
208 let mut result = Vec::with_capacity(arr.len());
209 for value in arr {
210 result.push(Self::json_value_to_string(value)?);
211 }
212 Ok(result)
213 }
214
215 pub(super) fn to_string_value(&self) -> Result<String, ApiClientError> {
225 match &self.value {
226 serde_json::Value::Array(arr) => {
227 let string_values = Self::array_to_string_values(arr)?;
228 let delimiter = match self.style {
229 ParamStyle::Default | ParamStyle::Simple => ",",
230 ParamStyle::Form => ",", ParamStyle::SpaceDelimited => " ",
232 ParamStyle::PipeDelimited => "|",
233 ParamStyle::Label => ",", ParamStyle::Matrix => ",", ParamStyle::DeepObject => {
236 return Err(ApiClientError::UnsupportedParameterValue {
237 message:
238 "DeepObject style not supported for arrays, use objects instead"
239 .to_string(),
240 value: self.value.clone(),
241 });
242 }
243 };
244 Ok(string_values.join(delimiter))
245 }
246 serde_json::Value::Object(_) => {
247 match self.style {
248 ParamStyle::DeepObject => {
249 Err(ApiClientError::UnsupportedParameterValue {
251 message: "DeepObject style objects require special handling in query parameters".to_string(),
252 value: self.value.clone(),
253 })
254 }
255 _ => Err(ApiClientError::UnsupportedParameterValue {
256 message: "object values not supported in parameters".to_string(),
257 value: self.value.clone(),
258 }),
259 }
260 }
261 _ => Self::json_value_to_string(&self.value),
262 }
263 }
264
265 pub(super) fn to_query_values(&self) -> Result<Vec<String>, ApiClientError> {
275 match &self.value {
276 serde_json::Value::Array(arr) => {
277 match self.style {
278 ParamStyle::Default | ParamStyle::Form => {
279 Self::array_to_string_values(arr)
281 }
282 _ => {
283 self.to_string_value().map(|s| vec![s])
285 }
286 }
287 }
288 serde_json::Value::Object(_) => {
289 match self.style {
290 ParamStyle::DeepObject => {
291 Err(ApiClientError::UnsupportedParameterValue {
293 message: "DeepObject style objects require special handling in query parameters".to_string(),
294 value: self.value.clone(),
295 })
296 }
297 _ => Err(ApiClientError::UnsupportedParameterValue {
298 message: "object values not supported in parameters".to_string(),
299 value: self.value.clone(),
300 }),
301 }
302 }
303 _ => Self::json_value_to_string(&self.value).map(|s| vec![s]),
304 }
305 }
306}
307
308impl<T> From<T> for ParamValue<T>
309where
310 T: Serialize + ToSchema + Debug + Send + Sync + Clone,
311{
312 fn from(value: T) -> Self {
313 Self::new(value)
314 }
315}
316
317impl<T: ToSchema> ToSchema for ParamValue<T>
319where
320 T: Serialize + ToSchema + Debug + Send + Sync + Clone,
321{
322 fn name() -> Cow<'static, str> {
323 T::name()
324 }
325}
326
327impl<T: ToSchema> PartialSchema for ParamValue<T>
328where
329 T: Serialize + ToSchema + Debug + Send + Sync + Clone,
330{
331 fn schema() -> RefOr<Schema> {
332 T::schema()
333 }
334}
335
336#[cfg(test)]
337mod tests {
338 use super::*;
339 use serde::{Deserialize, Serialize};
340 use utoipa::ToSchema;
341 use utoipa::openapi::path::ParameterStyle;
342
343 #[derive(Debug, Clone, Serialize, Deserialize, ToSchema, PartialEq)]
344 struct TestStruct {
345 id: u32,
346 name: String,
347 }
348
349 #[test]
351 fn test_param_style_from_conversion() {
352 assert_eq!(Option::<ParameterStyle>::from(ParamStyle::Default), None);
353 assert_eq!(
354 Option::<ParameterStyle>::from(ParamStyle::Form),
355 Some(ParameterStyle::Form)
356 );
357 assert_eq!(
358 Option::<ParameterStyle>::from(ParamStyle::Simple),
359 Some(ParameterStyle::Simple)
360 );
361 assert_eq!(
362 Option::<ParameterStyle>::from(ParamStyle::SpaceDelimited),
363 Some(ParameterStyle::SpaceDelimited)
364 );
365 assert_eq!(
366 Option::<ParameterStyle>::from(ParamStyle::PipeDelimited),
367 Some(ParameterStyle::PipeDelimited)
368 );
369 assert_eq!(
370 Option::<ParameterStyle>::from(ParamStyle::Label),
371 Some(ParameterStyle::Label)
372 );
373 assert_eq!(
374 Option::<ParameterStyle>::from(ParamStyle::Matrix),
375 Some(ParameterStyle::Matrix)
376 );
377 assert_eq!(
378 Option::<ParameterStyle>::from(ParamStyle::DeepObject),
379 Some(ParameterStyle::DeepObject)
380 );
381 }
382
383 #[test]
384 fn test_param_style_eq() {
385 assert_eq!(ParamStyle::Default, ParamStyle::Default);
386 assert_eq!(ParamStyle::Form, ParamStyle::Form);
387 assert_ne!(ParamStyle::Form, ParamStyle::Simple);
388 }
389
390 #[test]
392 fn test_param_value_new() {
393 let param = ParamValue::new(42);
394 assert_eq!(param.value, 42);
395 assert_eq!(param.style, ParamStyle::Default);
396 }
397
398 #[test]
399 fn test_param_value_with_style() {
400 let param = ParamValue::with_style("test", ParamStyle::Form);
401 assert_eq!(param.value, "test");
402 assert_eq!(param.style, ParamStyle::Form);
403 }
404
405 #[test]
406 fn test_param_value_from_conversion() {
407 let param: ParamValue<i32> = 42.into();
408 assert_eq!(param.value, 42);
409 assert_eq!(param.style, ParamStyle::Default);
410 }
411
412 #[test]
414 fn test_param_value_query_style() {
415 let default_param = ParamValue::new(42);
416 assert_eq!(default_param.query_style(), ParamStyle::Form);
417
418 let form_param = ParamValue::with_style(42, ParamStyle::Form);
419 assert_eq!(form_param.query_style(), ParamStyle::Form);
420
421 let simple_param = ParamValue::with_style(42, ParamStyle::Simple);
422 assert_eq!(simple_param.query_style(), ParamStyle::Simple);
423
424 let space_param = ParamValue::with_style(42, ParamStyle::SpaceDelimited);
425 assert_eq!(space_param.query_style(), ParamStyle::SpaceDelimited);
426
427 let pipe_param = ParamValue::with_style(42, ParamStyle::PipeDelimited);
428 assert_eq!(pipe_param.query_style(), ParamStyle::PipeDelimited);
429 }
430
431 #[test]
432 fn test_param_value_path_style() {
433 let default_param = ParamValue::new(42);
434 assert_eq!(default_param.path_style(), ParamStyle::Simple);
435
436 let form_param = ParamValue::with_style(42, ParamStyle::Form);
437 assert_eq!(form_param.path_style(), ParamStyle::Form);
438
439 let simple_param = ParamValue::with_style(42, ParamStyle::Simple);
440 assert_eq!(simple_param.path_style(), ParamStyle::Simple);
441 }
442
443 #[test]
444 fn test_param_value_header_style() {
445 let default_param = ParamValue::new(42);
446 assert_eq!(default_param.header_style(), ParamStyle::Simple);
447
448 let form_param = ParamValue::with_style(42, ParamStyle::Form);
449 assert_eq!(form_param.header_style(), ParamStyle::Form);
450
451 let simple_param = ParamValue::with_style(42, ParamStyle::Simple);
452 assert_eq!(simple_param.header_style(), ParamStyle::Simple);
453 }
454
455 #[test]
457 fn test_param_value_as_query_value() {
458 let string_param = ParamValue::new("test");
459 let query_value = string_param.as_query_value().unwrap();
460 assert_eq!(query_value, serde_json::Value::String("test".to_string()));
461
462 let number_param = ParamValue::new(42);
463 let query_value = number_param.as_query_value().unwrap();
464 assert_eq!(query_value, serde_json::Value::Number(42.into()));
465
466 let bool_param = ParamValue::new(true);
467 let query_value = bool_param.as_query_value().unwrap();
468 assert_eq!(query_value, serde_json::Value::Bool(true));
469
470 let array_param = ParamValue::new(vec!["a", "b", "c"]);
471 let query_value = array_param.as_query_value().unwrap();
472 let expected = serde_json::json!(["a", "b", "c"]);
473 assert_eq!(query_value, expected);
474 }
475
476 #[test]
477 fn test_param_value_as_header_value() {
478 let string_param = ParamValue::new("test");
479 let header_value = string_param.as_header_value().unwrap();
480 assert_eq!(header_value, serde_json::Value::String("test".to_string()));
481
482 let number_param = ParamValue::new(42);
483 let header_value = number_param.as_header_value().unwrap();
484 assert_eq!(header_value, serde_json::Value::Number(42.into()));
485 }
486
487 #[test]
488 fn test_param_value_resolve() {
489 let param = ParamValue::new(42);
490 let resolved = param.resolve(|value| {
491 assert_eq!(value, serde_json::Value::Number(42.into()));
493 utoipa::openapi::RefOr::T(utoipa::openapi::Schema::Object(Default::default()))
494 });
495
496 assert!(resolved.is_some());
497 let resolved = resolved.unwrap();
498 assert_eq!(resolved.value, serde_json::Value::Number(42.into()));
499 assert_eq!(resolved.style, ParamStyle::Default);
500 }
501
502 #[test]
503 fn test_param_value_resolve_none_on_serialization_error() {
504 let param = ParamValue::new(42); let resolved = param.resolve(|_| {
508 utoipa::openapi::RefOr::T(utoipa::openapi::Schema::Object(Default::default()))
509 });
510 assert!(resolved.is_some());
511 }
512
513 #[test]
515 fn test_resolved_param_value_json_value_to_string() {
516 assert_eq!(
517 ResolvedParamValue::json_value_to_string(&serde_json::Value::String(
518 "test".to_string()
519 ))
520 .unwrap(),
521 "test"
522 );
523 assert_eq!(
524 ResolvedParamValue::json_value_to_string(&serde_json::Value::Number(42.into()))
525 .unwrap(),
526 "42"
527 );
528 assert_eq!(
529 ResolvedParamValue::json_value_to_string(&serde_json::Value::Bool(true)).unwrap(),
530 "true"
531 );
532 assert_eq!(
533 ResolvedParamValue::json_value_to_string(&serde_json::Value::Bool(false)).unwrap(),
534 "false"
535 );
536 assert_eq!(
537 ResolvedParamValue::json_value_to_string(&serde_json::Value::Null).unwrap(),
538 ""
539 );
540
541 let array_result = ResolvedParamValue::json_value_to_string(&serde_json::json!(["a", "b"]));
543 assert!(array_result.is_err());
544
545 let object_result =
546 ResolvedParamValue::json_value_to_string(&serde_json::json!({"key": "value"}));
547 assert!(object_result.is_err());
548 }
549
550 #[test]
551 fn test_resolved_param_value_array_to_string_values() {
552 let arr = vec![
553 serde_json::Value::String("a".to_string()),
554 serde_json::Value::Number(42.into()),
555 serde_json::Value::Bool(true),
556 ];
557 let result = ResolvedParamValue::array_to_string_values(&arr).unwrap();
558 assert_eq!(result, vec!["a", "42", "true"]);
559
560 let nested_arr = vec![
562 serde_json::Value::String("a".to_string()),
563 serde_json::json!(["nested"]),
564 ];
565 let result = ResolvedParamValue::array_to_string_values(&nested_arr);
566 assert!(result.is_err());
567 }
568
569 #[test]
571 fn test_resolved_param_value_to_string_value_simple_values() {
572 let resolved = ResolvedParamValue {
573 value: serde_json::Value::String("test".to_string()),
574 schema: utoipa::openapi::RefOr::T(utoipa::openapi::Schema::Object(Default::default())),
575 style: ParamStyle::Default,
576 };
577 assert_eq!(resolved.to_string_value().unwrap(), "test");
578
579 let resolved = ResolvedParamValue {
580 value: serde_json::Value::Number(42.into()),
581 schema: utoipa::openapi::RefOr::T(utoipa::openapi::Schema::Object(Default::default())),
582 style: ParamStyle::Default,
583 };
584 assert_eq!(resolved.to_string_value().unwrap(), "42");
585 }
586
587 #[test]
588 fn test_resolved_param_value_to_string_value_arrays() {
589 let resolved = ResolvedParamValue {
591 value: serde_json::json!(["a", "b", "c"]),
592 schema: utoipa::openapi::RefOr::T(utoipa::openapi::Schema::Object(Default::default())),
593 style: ParamStyle::Simple,
594 };
595 assert_eq!(resolved.to_string_value().unwrap(), "a,b,c");
596
597 let resolved = ResolvedParamValue {
599 value: serde_json::json!(["a", "b", "c"]),
600 schema: utoipa::openapi::RefOr::T(utoipa::openapi::Schema::Object(Default::default())),
601 style: ParamStyle::SpaceDelimited,
602 };
603 assert_eq!(resolved.to_string_value().unwrap(), "a b c");
604
605 let resolved = ResolvedParamValue {
607 value: serde_json::json!(["a", "b", "c"]),
608 schema: utoipa::openapi::RefOr::T(utoipa::openapi::Schema::Object(Default::default())),
609 style: ParamStyle::PipeDelimited,
610 };
611 assert_eq!(resolved.to_string_value().unwrap(), "a|b|c");
612
613 let resolved = ResolvedParamValue {
615 value: serde_json::json!(["a", "b", "c"]),
616 schema: utoipa::openapi::RefOr::T(utoipa::openapi::Schema::Object(Default::default())),
617 style: ParamStyle::Label,
618 };
619 assert_eq!(resolved.to_string_value().unwrap(), "a,b,c");
620
621 let resolved = ResolvedParamValue {
623 value: serde_json::json!(["a", "b", "c"]),
624 schema: utoipa::openapi::RefOr::T(utoipa::openapi::Schema::Object(Default::default())),
625 style: ParamStyle::Matrix,
626 };
627 assert_eq!(resolved.to_string_value().unwrap(), "a,b,c");
628
629 let resolved = ResolvedParamValue {
631 value: serde_json::json!(["a", "b", "c"]),
632 schema: utoipa::openapi::RefOr::T(utoipa::openapi::Schema::Object(Default::default())),
633 style: ParamStyle::Form,
634 };
635 assert_eq!(resolved.to_string_value().unwrap(), "a,b,c");
636
637 let resolved = ResolvedParamValue {
639 value: serde_json::json!(["a", "b", "c"]),
640 schema: utoipa::openapi::RefOr::T(utoipa::openapi::Schema::Object(Default::default())),
641 style: ParamStyle::Default,
642 };
643 assert_eq!(resolved.to_string_value().unwrap(), "a,b,c");
644 }
645
646 #[test]
647 fn test_resolved_param_value_to_string_value_object_error() {
648 let resolved = ResolvedParamValue {
649 value: serde_json::json!({"key": "value"}),
650 schema: utoipa::openapi::RefOr::T(utoipa::openapi::Schema::Object(Default::default())),
651 style: ParamStyle::Default,
652 };
653 let result = resolved.to_string_value();
654 assert!(result.is_err());
655 assert!(matches!(
656 result.unwrap_err(),
657 ApiClientError::UnsupportedParameterValue { .. }
658 ));
659 }
660
661 #[test]
662 fn test_resolved_param_value_deep_object_style_errors() {
663 let resolved = ResolvedParamValue {
665 value: serde_json::json!(["a", "b", "c"]),
666 schema: utoipa::openapi::RefOr::T(utoipa::openapi::Schema::Object(Default::default())),
667 style: ParamStyle::DeepObject,
668 };
669 let result = resolved.to_string_value();
670 assert!(result.is_err());
671 assert!(matches!(
672 result.unwrap_err(),
673 ApiClientError::UnsupportedParameterValue { .. }
674 ));
675
676 let resolved = ResolvedParamValue {
678 value: serde_json::json!({"key": "value"}),
679 schema: utoipa::openapi::RefOr::T(utoipa::openapi::Schema::Object(Default::default())),
680 style: ParamStyle::DeepObject,
681 };
682 let result = resolved.to_string_value();
683 assert!(result.is_err());
684 assert!(matches!(
685 result.unwrap_err(),
686 ApiClientError::UnsupportedParameterValue { .. }
687 ));
688 }
689
690 #[test]
691 fn test_resolved_param_value_to_query_values_simple_values() {
692 let resolved = ResolvedParamValue {
693 value: serde_json::Value::String("test".to_string()),
694 schema: utoipa::openapi::RefOr::T(utoipa::openapi::Schema::Object(Default::default())),
695 style: ParamStyle::Default,
696 };
697 assert_eq!(resolved.to_query_values().unwrap(), vec!["test"]);
698
699 let resolved = ResolvedParamValue {
700 value: serde_json::Value::Number(42.into()),
701 schema: utoipa::openapi::RefOr::T(utoipa::openapi::Schema::Object(Default::default())),
702 style: ParamStyle::Default,
703 };
704 assert_eq!(resolved.to_query_values().unwrap(), vec!["42"]);
705 }
706
707 #[test]
708 fn test_resolved_param_value_to_query_values_arrays() {
709 let resolved = ResolvedParamValue {
711 value: serde_json::json!(["a", "b", "c"]),
712 schema: utoipa::openapi::RefOr::T(utoipa::openapi::Schema::Object(Default::default())),
713 style: ParamStyle::Form,
714 };
715 assert_eq!(resolved.to_query_values().unwrap(), vec!["a", "b", "c"]);
716
717 let resolved = ResolvedParamValue {
719 value: serde_json::json!(["a", "b", "c"]),
720 schema: utoipa::openapi::RefOr::T(utoipa::openapi::Schema::Object(Default::default())),
721 style: ParamStyle::Default,
722 };
723 assert_eq!(resolved.to_query_values().unwrap(), vec!["a", "b", "c"]);
724
725 let resolved = ResolvedParamValue {
727 value: serde_json::json!(["a", "b", "c"]),
728 schema: utoipa::openapi::RefOr::T(utoipa::openapi::Schema::Object(Default::default())),
729 style: ParamStyle::Simple,
730 };
731 assert_eq!(resolved.to_query_values().unwrap(), vec!["a,b,c"]);
732
733 let resolved = ResolvedParamValue {
735 value: serde_json::json!(["a", "b", "c"]),
736 schema: utoipa::openapi::RefOr::T(utoipa::openapi::Schema::Object(Default::default())),
737 style: ParamStyle::SpaceDelimited,
738 };
739 assert_eq!(resolved.to_query_values().unwrap(), vec!["a b c"]);
740
741 let resolved = ResolvedParamValue {
743 value: serde_json::json!(["a", "b", "c"]),
744 schema: utoipa::openapi::RefOr::T(utoipa::openapi::Schema::Object(Default::default())),
745 style: ParamStyle::PipeDelimited,
746 };
747 assert_eq!(resolved.to_query_values().unwrap(), vec!["a|b|c"]);
748 }
749
750 #[test]
751 fn test_resolved_param_value_to_query_values_object_error() {
752 let resolved = ResolvedParamValue {
753 value: serde_json::json!({"key": "value"}),
754 schema: utoipa::openapi::RefOr::T(utoipa::openapi::Schema::Object(Default::default())),
755 style: ParamStyle::Default,
756 };
757 let result = resolved.to_query_values();
758 assert!(result.is_err());
759 assert!(matches!(
760 result.unwrap_err(),
761 ApiClientError::UnsupportedParameterValue { .. }
762 ));
763 }
764
765 #[test]
767 fn test_param_value_to_schema_name() {
768 assert_eq!(ParamValue::<String>::name(), String::name());
769 assert_eq!(ParamValue::<i32>::name(), i32::name());
770 assert_eq!(ParamValue::<TestStruct>::name(), TestStruct::name());
771 }
772
773 #[test]
774 fn test_param_value_partial_schema() {
775 let string_schema = ParamValue::<String>::schema();
777 let expected_schema = String::schema();
778 match (string_schema, expected_schema) {
781 (utoipa::openapi::RefOr::T(_), utoipa::openapi::RefOr::T(_)) => {}
782 (utoipa::openapi::RefOr::Ref(_), utoipa::openapi::RefOr::Ref(_)) => {}
783 _ => panic!("Schema types don't match"),
784 }
785 }
786
787 #[test]
789 fn test_param_value_with_complex_types() {
790 let struct_param = ParamValue::new(TestStruct {
791 id: 123,
792 name: "test".to_string(),
793 });
794
795 let json_value = struct_param.as_query_value().unwrap();
797 let expected = serde_json::json!({"id": 123, "name": "test"});
798 assert_eq!(json_value, expected);
799
800 let resolved = struct_param.resolve(|value| {
802 assert_eq!(value, expected);
803 utoipa::openapi::RefOr::T(utoipa::openapi::Schema::Object(Default::default()))
804 });
805 assert!(resolved.is_some());
806 }
807
808 #[test]
809 fn test_param_value_with_option_types() {
810 let some_param = ParamValue::new(Some(42));
811 let json_value = some_param.as_query_value().unwrap();
812 assert_eq!(json_value, serde_json::Value::Number(42.into()));
813
814 let none_param: ParamValue<Option<i32>> = ParamValue::new(None);
815 let json_value = none_param.as_query_value().unwrap();
816 assert_eq!(json_value, serde_json::Value::Null);
817 }
818
819 #[test]
820 fn test_param_value_with_mixed_array_types() {
821 let mixed_numbers = vec![1, 2, 3];
823 let param = ParamValue::with_style(mixed_numbers, ParamStyle::SpaceDelimited);
824 let json_value = param.as_query_value().unwrap();
825 assert_eq!(json_value, serde_json::json!([1, 2, 3]));
826
827 let resolved = param
828 .resolve(|_| {
829 utoipa::openapi::RefOr::T(utoipa::openapi::Schema::Object(Default::default()))
830 })
831 .unwrap();
832
833 assert_eq!(resolved.to_string_value().unwrap(), "1 2 3");
834 assert_eq!(resolved.to_query_values().unwrap(), vec!["1 2 3"]);
835 }
836
837 #[test]
839 fn test_param_value_empty_array() {
840 let empty_array: Vec<String> = vec![];
841 let param = ParamValue::new(empty_array);
842 let json_value = param.as_query_value().unwrap();
843 assert_eq!(json_value, serde_json::json!([]));
844
845 let resolved = param
846 .resolve(|_| {
847 utoipa::openapi::RefOr::T(utoipa::openapi::Schema::Object(Default::default()))
848 })
849 .unwrap();
850
851 assert_eq!(resolved.to_string_value().unwrap(), "");
852 assert_eq!(resolved.to_query_values().unwrap(), Vec::<String>::new());
853 }
854
855 #[test]
856 fn test_param_value_single_item_array() {
857 let single_item = vec!["only"];
858 let param = ParamValue::new(single_item);
859 let resolved = param
860 .resolve(|_| {
861 utoipa::openapi::RefOr::T(utoipa::openapi::Schema::Object(Default::default()))
862 })
863 .unwrap();
864
865 assert_eq!(resolved.to_string_value().unwrap(), "only");
866 assert_eq!(resolved.to_query_values().unwrap(), vec!["only"]);
867 }
868
869 #[test]
871 fn test_parameter_value_trait_implementation() {
872 fn accepts_parameter_value<T: ParameterValue>(_value: T) {}
873
874 accepts_parameter_value("string");
876 accepts_parameter_value(42i32);
877 accepts_parameter_value(true);
878 accepts_parameter_value(vec!["a", "b"]);
879 accepts_parameter_value(TestStruct {
880 id: 1,
881 name: "test".to_string(),
882 });
883 }
884}