Skip to content

Commit 4022260

Browse files
committed
Support format
1 parent 6c73fd1 commit 4022260

27 files changed

Lines changed: 1415 additions & 231 deletions

File tree

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"changes":{"Cargo.toml":"Patch"},"note":"Support integer format, sea-orm default","date":"2026-02-18T12:19:24.863588800Z"}

Cargo.lock

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/vespera_macro/src/openapi_generator.rs

Lines changed: 71 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -274,7 +274,10 @@ fn build_path_items(
274274
}
275275

276276
/// Process default functions for struct fields
277-
/// This function extracts default values from functions specified in #[serde(default = "`function_name`")]
277+
/// This function extracts default values from:
278+
/// 1. `#[schema(default = "value")]` attributes (generated by `schema_type!` from `sea_orm(default_value)`)
279+
/// 2. `#[serde(default = "function_name")]` by finding the function in the file AST
280+
/// 3. `#[serde(default)]` by using type-specific defaults
278281
fn process_default_functions(
279282
struct_item: &syn::ItemStruct,
280283
file_ast: &syn::File,
@@ -294,21 +297,31 @@ fn process_default_functions(
294297
// Process each field in the struct
295298
if let Fields::Named(fields_named) = &struct_item.fields {
296299
for field in &fields_named.named {
297-
// Extract default function name
300+
let rust_field_name = field.ident.as_ref().map_or_else(
301+
|| "unknown".to_string(),
302+
|i| strip_raw_prefix(&i.to_string()).to_string(),
303+
);
304+
let field_name = extract_field_rename(&field.attrs).unwrap_or_else(|| {
305+
rename_field(&rust_field_name, struct_rename_all.as_deref())
306+
});
307+
308+
// Priority 1: #[schema(default = "value")] from schema_type! macro
309+
if let Some(default_str) = extract_schema_default_attr(&field.attrs) {
310+
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+
}
317+
continue;
318+
}
319+
320+
// Priority 2: #[serde(default)] / #[serde(default = "fn")]
298321
let default_info = match extract_default(&field.attrs) {
299322
Some(Some(func_name)) => func_name, // default = "function_name"
300323
Some(None) => {
301324
// Simple default (no function) - we can set type-specific defaults
302-
let rust_field_name = field.ident.as_ref().map_or_else(
303-
|| "unknown".to_string(),
304-
|i| strip_raw_prefix(&i.to_string()).to_string(),
305-
);
306-
307-
let field_name = extract_field_rename(&field.attrs).unwrap_or_else(|| {
308-
rename_field(&rust_field_name, struct_rename_all.as_deref())
309-
});
310-
311-
// Set type-specific default for simple default
312325
if let Some(prop_schema_ref) = properties.get_mut(&field_name)
313326
&& let SchemaRef::Inline(prop_schema) = prop_schema_ref
314327
&& prop_schema.default.is_none()
@@ -326,16 +339,6 @@ fn process_default_functions(
326339
if let Some(func_item) = func {
327340
// Extract default value from function body
328341
if let Some(default_value) = extract_default_value_from_function(func_item) {
329-
// Get the field name (with rename applied)
330-
let rust_field_name = field.ident.as_ref().map_or_else(
331-
|| "unknown".to_string(),
332-
|i| strip_raw_prefix(&i.to_string()).to_string(),
333-
);
334-
335-
let field_name = extract_field_rename(&field.attrs).unwrap_or_else(|| {
336-
rename_field(&rust_field_name, struct_rename_all.as_deref())
337-
});
338-
339342
// Set default value in schema
340343
if let Some(prop_schema_ref) = properties.get_mut(&field_name)
341344
&& let SchemaRef::Inline(prop_schema) = prop_schema_ref
@@ -348,6 +351,52 @@ fn process_default_functions(
348351
}
349352
}
350353

354+
/// Extract `default` value from `#[schema(default = "...")]` field attribute.
355+
///
356+
/// This attribute is generated by `schema_type!` when converting `sea_orm(default_value)`.
357+
/// It carries the raw default value string for OpenAPI schema generation.
358+
fn extract_schema_default_attr(attrs: &[syn::Attribute]) -> Option<String> {
359+
for attr in attrs {
360+
if attr.path().is_ident("schema") {
361+
let mut default_value = None;
362+
let _ = attr.parse_nested_meta(|meta| {
363+
if meta.path.is_ident("default") {
364+
let value = meta.value()?;
365+
let lit: syn::LitStr = value.parse()?;
366+
default_value = Some(lit.value());
367+
}
368+
Ok(())
369+
});
370+
if default_value.is_some() {
371+
return default_value;
372+
}
373+
}
374+
}
375+
None
376+
}
377+
378+
/// Parse a default value string into the appropriate `serde_json::Value`.
379+
///
380+
/// Tries to infer the JSON type: integer → number → bool → string (fallback).
381+
fn parse_default_string_to_json_value(value: &str) -> serde_json::Value {
382+
// Try integer first
383+
if let Ok(n) = value.parse::<i64>() {
384+
return serde_json::Value::Number(n.into());
385+
}
386+
// Try float
387+
if let Ok(f) = value.parse::<f64>()
388+
&& let Some(n) = serde_json::Number::from_f64(f)
389+
{
390+
return serde_json::Value::Number(n);
391+
}
392+
// Try bool
393+
if let Ok(b) = value.parse::<bool>() {
394+
return serde_json::Value::Bool(b);
395+
}
396+
// Fallback to string
397+
serde_json::Value::String(value.to_string())
398+
}
399+
351400
/// Find a function by name in the file AST
352401
fn find_function_in_file<'a>(
353402
file_ast: &'a syn::File,

crates/vespera_macro/src/parser/schema/snapshots/vespera_macro__parser__schema__enum_schema__tests__enum_repr_tests__adjacently_tagged_snapshot@adjacently_tagged.snap

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -339,7 +339,9 @@ Schema {
339339
schema_type: Some(
340340
Integer,
341341
),
342-
format: None,
342+
format: Some(
343+
"int32",
344+
),
343345
title: None,
344346
description: None,
345347
default: None,

crates/vespera_macro/src/parser/schema/snapshots/vespera_macro__parser__schema__enum_schema__tests__enum_repr_tests__externally_tagged_empty_struct_variant@externally_tagged_empty_struct.snap

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,9 @@ Schema {
193193
schema_type: Some(
194194
Integer,
195195
),
196-
format: None,
196+
format: Some(
197+
"int32",
198+
),
197199
title: None,
198200
description: None,
199201
default: None,

crates/vespera_macro/src/parser/schema/snapshots/vespera_macro__parser__schema__enum_schema__tests__enum_repr_tests__internally_tagged_snapshot@internally_tagged.snap

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,9 @@ Schema {
6767
schema_type: Some(
6868
Integer,
6969
),
70-
format: None,
70+
format: Some(
71+
"int32",
72+
),
7173
title: None,
7274
description: None,
7375
default: None,
@@ -260,7 +262,9 @@ Schema {
260262
schema_type: Some(
261263
Integer,
262264
),
263-
format: None,
265+
format: Some(
266+
"int32",
267+
),
264268
title: None,
265269
description: None,
266270
default: None,

crates/vespera_macro/src/parser/schema/snapshots/vespera_macro__parser__schema__enum_schema__tests__enum_repr_tests__untagged_multi_field_tuple_variant@untagged_multi_field_tuple.snap

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,9 @@ Schema {
108108
schema_type: Some(
109109
Integer,
110110
),
111-
format: None,
111+
format: Some(
112+
"int32",
113+
),
112114
title: None,
113115
description: None,
114116
default: None,
@@ -250,7 +252,9 @@ Schema {
250252
schema_type: Some(
251253
Integer,
252254
),
253-
format: None,
255+
format: Some(
256+
"int32",
257+
),
254258
title: None,
255259
description: None,
256260
default: None,

crates/vespera_macro/src/parser/schema/snapshots/vespera_macro__parser__schema__enum_schema__tests__enum_repr_tests__untagged_snapshot@untagged.snap

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,9 @@ Schema {
130130
schema_type: Some(
131131
Number,
132132
),
133-
format: None,
133+
format: Some(
134+
"double",
135+
),
134136
title: None,
135137
description: None,
136138
default: None,

crates/vespera_macro/src/parser/schema/snapshots/vespera_macro__parser__schema__enum_schema__tests__parse_enum_to_schema_tuple_and_named_variants@tuple_named_named_object.snap

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,9 @@ Schema {
9494
schema_type: Some(
9595
Integer,
9696
),
97-
format: None,
97+
format: Some(
98+
"int32",
99+
),
98100
title: None,
99101
description: None,
100102
default: None,

crates/vespera_macro/src/parser/schema/snapshots/vespera_macro__parser__schema__enum_schema__tests__parse_enum_to_schema_tuple_and_named_variants@tuple_named_tuple_multi.snap

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,9 @@ Schema {
9090
schema_type: Some(
9191
Integer,
9292
),
93-
format: None,
93+
format: Some(
94+
"int32",
95+
),
9496
title: None,
9597
description: None,
9698
default: None,

0 commit comments

Comments
 (0)