#![cfg(feature = "openapi")]
use gotcha::Schematic;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize, Schematic)]
pub struct Pagination {
page: u32,
per_page: u32,
}
#[derive(Debug, Clone, Serialize, Deserialize, Schematic)]
pub struct Sorting {
sort_by: String,
sort_order: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize, Schematic)]
pub struct ListRequest {
query: String,
#[serde(flatten)]
pagination: Pagination,
}
#[derive(Debug, Clone, Serialize, Deserialize, Schematic)]
pub struct AdvancedListRequest {
query: String,
#[serde(flatten)]
pagination: Pagination,
#[serde(flatten)]
sorting: Sorting,
}
#[derive(Debug, Clone, Serialize, Deserialize, Schematic)]
#[serde(rename_all = "camelCase")]
pub struct CamelCaseRequest {
user_name: String,
#[serde(flatten)]
pagination: Pagination,
}
#[derive(Debug, Clone, Serialize, Deserialize, Schematic)]
pub struct PaginatedSorting {
#[serde(flatten)]
pagination: Pagination,
#[serde(flatten)]
sorting: Sorting,
}
#[derive(Debug, Clone, Serialize, Deserialize, Schematic)]
pub struct NestedFlattenRequest {
query: String,
#[serde(flatten)]
paginated_sorting: PaginatedSorting,
}
#[derive(Debug, Clone, Serialize, Deserialize, Schematic)]
pub struct MixedRenameRequest {
#[serde(rename = "searchQuery")]
query: String,
#[serde(flatten)]
pagination: Pagination,
}
#[derive(Debug, Clone, Serialize, Deserialize, Schematic)]
pub struct OptionalFields {
name: String,
#[serde(flatten)]
pagination: Pagination,
extra: Option<String>,
}
#[test]
fn test_single_flatten_field() {
let schema = ListRequest::generate_schema();
let properties = schema.schema.extras.get("properties").unwrap().as_object().unwrap();
assert!(properties.contains_key("query"), "should have 'query' field");
assert!(properties.contains_key("page"), "should have flattened 'page' field");
assert!(properties.contains_key("per_page"), "should have flattened 'per_page' field");
assert!(!properties.contains_key("pagination"), "should not have 'pagination' as nested object");
}
#[test]
fn test_multiple_flatten_fields() {
let schema = AdvancedListRequest::generate_schema();
let properties = schema.schema.extras.get("properties").unwrap().as_object().unwrap();
assert!(properties.contains_key("query"));
assert!(properties.contains_key("page"));
assert!(properties.contains_key("per_page"));
assert!(properties.contains_key("sort_by"));
assert!(properties.contains_key("sort_order"));
assert!(!properties.contains_key("pagination"));
assert!(!properties.contains_key("sorting"));
}
#[test]
fn test_flatten_with_rename_all() {
let schema = CamelCaseRequest::generate_schema();
let properties = schema.schema.extras.get("properties").unwrap().as_object().unwrap();
assert!(properties.contains_key("userName"), "should have camelCase 'userName'");
assert!(!properties.contains_key("user_name"));
assert!(properties.contains_key("page"));
assert!(properties.contains_key("per_page"));
}
#[test]
fn test_nested_flatten() {
let schema = NestedFlattenRequest::generate_schema();
let properties = schema.schema.extras.get("properties").unwrap().as_object().unwrap();
assert!(properties.contains_key("query"));
assert!(properties.contains_key("page"));
assert!(properties.contains_key("per_page"));
assert!(properties.contains_key("sort_by"));
assert!(properties.contains_key("sort_order"));
assert!(!properties.contains_key("paginated_sorting"));
assert!(!properties.contains_key("pagination"));
assert!(!properties.contains_key("sorting"));
}
#[test]
fn test_flatten_with_field_rename() {
let schema = MixedRenameRequest::generate_schema();
let properties = schema.schema.extras.get("properties").unwrap().as_object().unwrap();
assert!(properties.contains_key("searchQuery"), "should have renamed 'searchQuery'");
assert!(!properties.contains_key("query"));
assert!(properties.contains_key("page"));
assert!(properties.contains_key("per_page"));
}
#[test]
fn test_required_fields_tracking() {
let schema = OptionalFields::generate_schema();
let required = schema.schema.extras.get("required").unwrap().as_array().unwrap();
let required_names: Vec<&str> = required.iter().map(|v| v.as_str().unwrap()).collect();
assert!(required_names.contains(&"name"), "name should be required");
assert!(required_names.contains(&"page"), "page should be required");
assert!(required_names.contains(&"per_page"), "per_page should be required");
assert!(!required_names.contains(&"extra"), "extra should not be required");
}
#[test]
fn test_fields_method() {
let fields = ListRequest::fields();
let field_names: Vec<&str> = fields.iter().map(|(name, _)| *name).collect();
assert!(field_names.contains(&"query"));
assert!(field_names.contains(&"page"));
assert!(field_names.contains(&"per_page"));
assert_eq!(fields.len(), 3);
}
#[test]
fn test_documentation_preserved() {
let fields = ListRequest::fields();
let page_field = fields.iter().find(|(name, _)| *name == "page").unwrap();
assert!(
page_field.1.schema.description.as_ref().map(|s| s.contains("Page number")).unwrap_or(false),
"page field should preserve documentation"
);
}