@@ -11,6 +11,27 @@ use super::schema::{
1111 parse_type_to_schema_ref_with_schemas, rename_field,
1212} ;
1313
14+ /// Convert SchemaRef to inline schema for query parameters
15+ /// Query parameters should always use inline schemas, not refs
16+ /// Adds nullable flag if the field is optional
17+ fn convert_to_inline_schema ( field_schema : SchemaRef , is_optional : bool ) -> SchemaRef {
18+ match field_schema {
19+ SchemaRef :: Inline ( mut schema) => {
20+ if is_optional {
21+ schema. nullable = Some ( true ) ;
22+ }
23+ SchemaRef :: Inline ( schema)
24+ }
25+ SchemaRef :: Ref ( _) => {
26+ let mut schema = Schema :: new ( SchemaType :: Object ) ;
27+ if is_optional {
28+ schema. nullable = Some ( true ) ;
29+ }
30+ SchemaRef :: Inline ( Box :: new ( schema) )
31+ }
32+ }
33+ }
34+
1435/// Analyze function parameter and convert to OpenAPI Parameter(s)
1536/// Returns None if parameter should be ignored (e.g., Query<HashMap<...>>)
1637/// Returns Some(Vec<Parameter>) with one or more parameters
@@ -393,46 +414,23 @@ fn parse_query_struct_to_parameters(
393414
394415 // Convert ref to inline if needed (Query parameters should not use refs)
395416 // If it's a ref to a known struct, get the struct definition and inline it
396- if let SchemaRef :: Ref ( ref_ref) = & field_schema {
397- // Try to extract type name from ref path (e.g., "#/components/schemas/User" -> "User")
398- if let Some ( type_name) =
417+ if let SchemaRef :: Ref ( ref_ref) = & field_schema
418+ && let Some ( type_name) =
399419 ref_ref. ref_path . strip_prefix ( "#/components/schemas/" )
400- && let Some ( struct_def) = struct_definitions. get ( type_name)
401- && let Ok ( nested_struct_item) =
402- syn:: parse_str :: < syn:: ItemStruct > ( struct_def)
403- {
404- // Parse the nested struct to schema (inline)
405- let nested_schema = parse_struct_to_schema (
406- & nested_struct_item,
407- known_schemas,
408- struct_definitions,
409- ) ;
410- field_schema = SchemaRef :: Inline ( Box :: new ( nested_schema) ) ;
411- }
420+ && let Some ( struct_def) = struct_definitions. get ( type_name)
421+ && let Ok ( nested_struct_item) =
422+ syn:: parse_str :: < syn:: ItemStruct > ( struct_def)
423+ {
424+ // Parse the nested struct to schema (inline)
425+ let nested_schema = parse_struct_to_schema (
426+ & nested_struct_item,
427+ known_schemas,
428+ struct_definitions,
429+ ) ;
430+ field_schema = SchemaRef :: Inline ( Box :: new ( nested_schema) ) ;
412431 }
413432
414- // If it's Option<T>, make it nullable
415- let final_schema = if is_optional {
416- if let SchemaRef :: Inline ( mut schema) = field_schema {
417- schema. nullable = Some ( true ) ;
418- SchemaRef :: Inline ( schema)
419- } else {
420- // If still a ref, convert to inline object with nullable
421- SchemaRef :: Inline ( Box :: new ( Schema {
422- schema_type : Some ( SchemaType :: Object ) ,
423- nullable : Some ( true ) ,
424- ..Schema :: object ( )
425- } ) )
426- }
427- } else {
428- // If it's still a ref, convert to inline object
429- match field_schema {
430- SchemaRef :: Ref ( _) => {
431- SchemaRef :: Inline ( Box :: new ( Schema :: new ( SchemaType :: Object ) ) )
432- }
433- SchemaRef :: Inline ( schema) => SchemaRef :: Inline ( schema) ,
434- }
435- } ;
433+ let final_schema = convert_to_inline_schema ( field_schema, is_optional) ;
436434
437435 let required = !is_optional;
438436
@@ -1011,23 +1009,6 @@ mod tests {
10111009 }
10121010 }
10131011
1014- // NOTE: Line 313 is defensive/unreachable code.
1015- //
1016- // Analysis: Line 313 requires:
1017- // 1. is_optional == true (field type starts with "Option")
1018- // 2. field_schema is still SchemaRef::Ref after the conversion at lines 294-304
1019- //
1020- // However, parse_type_to_schema_ref_with_schemas("Option<T>") ALWAYS returns
1021- // SchemaRef::Inline because:
1022- // - schema.rs lines 650-668 handle Option specially
1023- // - If inner type is Inline → returns Inline (line 660)
1024- // - If inner type is Ref → wraps in Inline (line 664)
1025- //
1026- // Therefore, for any field whose type starts with "Option", field_schema at line 290
1027- // will always be SchemaRef::Inline, making the else branch at line 312-313 unreachable.
1028- //
1029- // This is defensive code guarding against future changes to Option handling in schema.rs.
1030-
10311012 #[ test]
10321013 fn test_schema_ref_to_inline_conversion_required ( ) {
10331014 // Test line 318: SchemaRef::Ref converted to inline for required fields
@@ -1117,4 +1098,59 @@ mod tests {
11171098 _ => panic ! ( "Expected inline schema (converted from Ref via struct_def)" ) ,
11181099 }
11191100 }
1101+
1102+ // Tests for convert_to_inline_schema helper function
1103+ #[ test]
1104+ fn test_convert_to_inline_schema_inline_required ( ) {
1105+ let schema = SchemaRef :: Inline ( Box :: new ( Schema :: string ( ) ) ) ;
1106+ let result = convert_to_inline_schema ( schema, false ) ;
1107+ match result {
1108+ SchemaRef :: Inline ( s) => {
1109+ assert_eq ! ( s. schema_type, Some ( SchemaType :: String ) ) ;
1110+ assert ! ( s. nullable. is_none( ) ) ;
1111+ }
1112+ _ => panic ! ( "Expected Inline" ) ,
1113+ }
1114+ }
1115+
1116+ #[ test]
1117+ fn test_convert_to_inline_schema_inline_optional ( ) {
1118+ let schema = SchemaRef :: Inline ( Box :: new ( Schema :: string ( ) ) ) ;
1119+ let result = convert_to_inline_schema ( schema, true ) ;
1120+ match result {
1121+ SchemaRef :: Inline ( s) => {
1122+ assert_eq ! ( s. schema_type, Some ( SchemaType :: String ) ) ;
1123+ assert_eq ! ( s. nullable, Some ( true ) ) ;
1124+ }
1125+ _ => panic ! ( "Expected Inline" ) ,
1126+ }
1127+ }
1128+
1129+ #[ test]
1130+ fn test_convert_to_inline_schema_ref_required ( ) {
1131+ use vespera_core:: schema:: Reference ;
1132+ let schema = SchemaRef :: Ref ( Reference :: schema ( "SomeType" ) ) ;
1133+ let result = convert_to_inline_schema ( schema, false ) ;
1134+ match result {
1135+ SchemaRef :: Inline ( s) => {
1136+ assert_eq ! ( s. schema_type, Some ( SchemaType :: Object ) ) ;
1137+ assert ! ( s. nullable. is_none( ) ) ;
1138+ }
1139+ _ => panic ! ( "Expected Inline" ) ,
1140+ }
1141+ }
1142+
1143+ #[ test]
1144+ fn test_convert_to_inline_schema_ref_optional ( ) {
1145+ use vespera_core:: schema:: Reference ;
1146+ let schema = SchemaRef :: Ref ( Reference :: schema ( "SomeType" ) ) ;
1147+ let result = convert_to_inline_schema ( schema, true ) ;
1148+ match result {
1149+ SchemaRef :: Inline ( s) => {
1150+ assert_eq ! ( s. schema_type, Some ( SchemaType :: Object ) ) ;
1151+ assert_eq ! ( s. nullable, Some ( true ) ) ;
1152+ }
1153+ _ => panic ! ( "Expected Inline" ) ,
1154+ }
1155+ }
11201156}
0 commit comments