@@ -48,11 +48,7 @@ pub fn generate_openapi_doc_with_metadata(
4848 info : Info {
4949 title : title. unwrap_or_else ( || "API" . to_string ( ) ) ,
5050 version : version. unwrap_or_else ( || "1.0.0" . to_string ( ) ) ,
51- description : None ,
52- terms_of_service : None ,
53- contact : None ,
54- license : None ,
55- summary : None ,
51+ ..Default :: default ( )
5652 } ,
5753 servers : servers. or_else ( || {
5854 Some ( vec ! [ Server {
@@ -250,19 +246,7 @@ fn build_path_items(
250246
251247 let path_item = paths
252248 . entry ( route_meta. path . clone ( ) )
253- . or_insert_with ( || PathItem {
254- get : None ,
255- post : None ,
256- put : None ,
257- patch : None ,
258- delete : None ,
259- head : None ,
260- options : None ,
261- trace : None ,
262- parameters : None ,
263- summary : None ,
264- description : None ,
265- } ) ;
249+ . or_insert_with ( PathItem :: default) ;
266250
267251 path_item. set_operation ( method, operation) ;
268252 break ;
@@ -273,6 +257,24 @@ fn build_path_items(
273257 ( paths, all_tags)
274258}
275259
260+ /// Set the default value on an inline property schema, if not already set.
261+ ///
262+ /// Looks up `field_name` in the properties map. If found as an inline schema
263+ /// and the schema has no existing default, sets `value` as the default.
264+ fn set_property_default (
265+ properties : & mut BTreeMap < String , vespera_core:: schema:: SchemaRef > ,
266+ field_name : & str ,
267+ value : serde_json:: Value ,
268+ ) {
269+ use vespera_core:: schema:: SchemaRef ;
270+
271+ if let Some ( SchemaRef :: Inline ( prop_schema) ) = properties. get_mut ( field_name)
272+ && prop_schema. default . is_none ( )
273+ {
274+ prop_schema. default = Some ( value) ;
275+ }
276+ }
277+
276278/// Process default functions for struct fields
277279/// This function extracts default values from:
278280/// 1. `#[schema(default = "value")]` attributes (generated by `schema_type!` from `sea_orm(default_value)`)
@@ -284,7 +286,6 @@ fn process_default_functions(
284286 schema : & mut vespera_core:: schema:: Schema ,
285287) {
286288 use syn:: Fields ;
287- use vespera_core:: schema:: SchemaRef ;
288289
289290 // Extract rename_all from struct level
290291 let struct_rename_all = extract_rename_all ( & struct_item. attrs ) ;
@@ -308,12 +309,7 @@ fn process_default_functions(
308309 // Priority 1: #[schema(default = "value")] from schema_type! macro
309310 if let Some ( default_str) = extract_schema_default_attr ( & field. attrs ) {
310311 let value = parse_default_string_to_json_value ( & default_str) ;
311- if let Some ( prop_schema_ref) = properties. get_mut ( & field_name)
312- && let SchemaRef :: Inline ( prop_schema) = prop_schema_ref
313- && prop_schema. default . is_none ( )
314- {
315- prop_schema. default = Some ( value) ;
316- }
312+ set_property_default ( properties, & field_name, value) ;
317313 continue ;
318314 }
319315
@@ -322,30 +318,19 @@ fn process_default_functions(
322318 Some ( Some ( func_name) ) => func_name, // default = "function_name"
323319 Some ( None ) => {
324320 // Simple default (no function) - we can set type-specific defaults
325- if let Some ( prop_schema_ref) = properties. get_mut ( & field_name)
326- && let SchemaRef :: Inline ( prop_schema) = prop_schema_ref
327- && prop_schema. default . is_none ( )
328- && let Some ( default_value) = utils_get_type_default ( & field. ty )
329- {
330- prop_schema. default = Some ( default_value) ;
321+ if let Some ( default_value) = utils_get_type_default ( & field. ty ) {
322+ set_property_default ( properties, & field_name, default_value) ;
331323 }
332324 continue ;
333325 }
334326 None => continue , // No default attribute
335327 } ;
336328
337- // Find the function in the file AST
338- let func = find_function_in_file ( file_ast, & default_info) ;
339- if let Some ( func_item) = func {
340- // Extract default value from function body
341- if let Some ( default_value) = extract_default_value_from_function ( func_item) {
342- // Set default value in schema
343- if let Some ( prop_schema_ref) = properties. get_mut ( & field_name)
344- && let SchemaRef :: Inline ( prop_schema) = prop_schema_ref
345- {
346- prop_schema. default = Some ( default_value) ;
347- }
348- }
329+ // Find the function in the file AST and extract default value
330+ if let Some ( func_item) = find_function_in_file ( file_ast, & default_info)
331+ && let Some ( default_value) = extract_default_value_from_function ( func_item)
332+ {
333+ set_property_default ( properties, & field_name, default_value) ;
349334 }
350335 }
351336 }
@@ -356,8 +341,10 @@ fn process_default_functions(
356341/// This attribute is generated by `schema_type!` when converting `sea_orm(default_value)`.
357342/// It carries the raw default value string for OpenAPI schema generation.
358343fn extract_schema_default_attr ( attrs : & [ syn:: Attribute ] ) -> Option < String > {
359- for attr in attrs {
360- if attr. path ( ) . is_ident ( "schema" ) {
344+ attrs
345+ . iter ( )
346+ . filter ( |attr| attr. path ( ) . is_ident ( "schema" ) )
347+ . find_map ( |attr| {
361348 let mut default_value = None ;
362349 let _ = attr. parse_nested_meta ( |meta| {
363350 if meta. path . is_ident ( "default" ) {
@@ -367,12 +354,8 @@ fn extract_schema_default_attr(attrs: &[syn::Attribute]) -> Option<String> {
367354 }
368355 Ok ( ( ) )
369356 } ) ;
370- if default_value. is_some ( ) {
371- return default_value;
372- }
373- }
374- }
375- None
357+ default_value
358+ } )
376359}
377360
378361/// Parse a default value string into the appropriate `serde_json::Value`.
@@ -402,14 +385,10 @@ fn find_function_in_file<'a>(
402385 file_ast : & ' a syn:: File ,
403386 function_name : & str ,
404387) -> Option < & ' a syn:: ItemFn > {
405- for item in & file_ast. items {
406- if let syn:: Item :: Fn ( fn_item) = item
407- && fn_item. sig . ident == function_name
408- {
409- return Some ( fn_item) ;
410- }
411- }
412- None
388+ file_ast. items . iter ( ) . find_map ( |item| match item {
389+ syn:: Item :: Fn ( fn_item) if fn_item. sig . ident == function_name => Some ( fn_item) ,
390+ _ => None ,
391+ } )
413392}
414393
415394/// Extract default value from function body
@@ -1504,4 +1483,94 @@ pub fn create_users() -> String {
15041483 // The unparseable definition should be skipped
15051484 assert ! ( doc. components. is_none( ) || doc. components. as_ref( ) . unwrap( ) . schemas. is_none( ) ) ;
15061485 }
1486+
1487+ // ======== Tests for set_property_default helper ========
1488+
1489+ #[ test]
1490+ fn test_set_property_default_on_inline_schema ( ) {
1491+ use vespera_core:: schema:: { Schema , SchemaRef } ;
1492+
1493+ let mut properties = BTreeMap :: new ( ) ;
1494+ let mut schema = Schema :: object ( ) ;
1495+ schema. default = None ;
1496+ properties. insert ( "name" . to_string ( ) , SchemaRef :: Inline ( Box :: new ( schema) ) ) ;
1497+
1498+ set_property_default (
1499+ & mut properties,
1500+ "name" ,
1501+ serde_json:: Value :: String ( "Alice" . to_string ( ) ) ,
1502+ ) ;
1503+
1504+ if let Some ( SchemaRef :: Inline ( prop) ) = properties. get ( "name" ) {
1505+ assert_eq ! (
1506+ prop. default ,
1507+ Some ( serde_json:: Value :: String ( "Alice" . to_string( ) ) )
1508+ ) ;
1509+ } else {
1510+ panic ! ( "Expected Inline schema" ) ;
1511+ }
1512+ }
1513+
1514+ #[ test]
1515+ fn test_set_property_default_does_not_overwrite_existing ( ) {
1516+ use vespera_core:: schema:: { Schema , SchemaRef } ;
1517+
1518+ let mut properties = BTreeMap :: new ( ) ;
1519+ let mut schema = Schema :: object ( ) ;
1520+ schema. default = Some ( serde_json:: Value :: String ( "existing" . to_string ( ) ) ) ;
1521+ properties. insert ( "name" . to_string ( ) , SchemaRef :: Inline ( Box :: new ( schema) ) ) ;
1522+
1523+ set_property_default (
1524+ & mut properties,
1525+ "name" ,
1526+ serde_json:: Value :: String ( "new" . to_string ( ) ) ,
1527+ ) ;
1528+
1529+ if let Some ( SchemaRef :: Inline ( prop) ) = properties. get ( "name" ) {
1530+ assert_eq ! (
1531+ prop. default ,
1532+ Some ( serde_json:: Value :: String ( "existing" . to_string( ) ) ) ,
1533+ "Should NOT overwrite existing default"
1534+ ) ;
1535+ } else {
1536+ panic ! ( "Expected Inline schema" ) ;
1537+ }
1538+ }
1539+
1540+ #[ test]
1541+ fn test_set_property_default_skips_ref_schema ( ) {
1542+ use vespera_core:: schema:: { Reference , SchemaRef } ;
1543+
1544+ let mut properties = BTreeMap :: new ( ) ;
1545+ properties. insert (
1546+ "user" . to_string ( ) ,
1547+ SchemaRef :: Ref ( Reference :: schema ( "User" ) ) ,
1548+ ) ;
1549+
1550+ // Should silently no-op (Ref variants have no default field)
1551+ set_property_default (
1552+ & mut properties,
1553+ "user" ,
1554+ serde_json:: Value :: String ( "ignored" . to_string ( ) ) ,
1555+ ) ;
1556+
1557+ assert ! (
1558+ matches!( properties. get( "user" ) , Some ( SchemaRef :: Ref ( _) ) ) ,
1559+ "Should remain a Ref variant"
1560+ ) ;
1561+ }
1562+
1563+ #[ test]
1564+ fn test_set_property_default_skips_missing_property ( ) {
1565+ let mut properties = BTreeMap :: new ( ) ;
1566+
1567+ // Should silently no-op (property doesn't exist)
1568+ set_property_default (
1569+ & mut properties,
1570+ "nonexistent" ,
1571+ serde_json:: Value :: Number ( 42 . into ( ) ) ,
1572+ ) ;
1573+
1574+ assert ! ( properties. is_empty( ) , "Should not insert new properties" ) ;
1575+ }
15071576}
0 commit comments