Skip to content

Commit ec8f60c

Browse files
committed
Enum upper
1 parent e184b0a commit ec8f60c

6 files changed

Lines changed: 106 additions & 21 deletions

File tree

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"changes":{"crates/vespertide/Cargo.toml":"Patch","crates/vespertide-core/Cargo.toml":"Patch","crates/vespertide-exporter/Cargo.toml":"Patch","crates/vespertide-loader/Cargo.toml":"Patch","crates/vespertide-macro/Cargo.toml":"Patch","crates/vespertide-config/Cargo.toml":"Patch","crates/vespertide-naming/Cargo.toml":"Patch","crates/vespertide-query/Cargo.toml":"Patch","crates/vespertide-cli/Cargo.toml":"Patch","crates/vespertide-planner/Cargo.toml":"Patch"},"note":"Fix enum SCREAMING_SNAKE_CASE","date":"2026-04-17T07:02:13.191508900Z"}

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@ settings.local.json
44
coverage
55
lcov.info
66
.sisyphus
7+
.omc

Cargo.lock

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

Cargo.toml

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,14 @@ documentation = "https://docs.rs/vespertide"
1313
unexpected_cfgs = { level = "warn", check-cfg = ['cfg(tarpaulin_include)'] }
1414

1515
[workspace.dependencies]
16-
vespertide-core = { path = "crates/vespertide-core", version = "0.1.57", default-features = false }
17-
vespertide-config = { path = "crates/vespertide-config", version = "0.1.57", default-features = false }
18-
vespertide-loader = { path = "crates/vespertide-loader", version = "0.1.57", default-features = false }
19-
vespertide-macro = { path = "crates/vespertide-macro", version = "0.1.57" }
20-
vespertide-naming = { path = "crates/vespertide-naming", version = "0.1.57" }
21-
vespertide-planner = { path = "crates/vespertide-planner", version = "0.1.57" }
22-
vespertide-query = { path = "crates/vespertide-query", version = "0.1.57" }
23-
vespertide-exporter = { path = "crates/vespertide-exporter", version = "0.1.57" }
16+
vespertide-core = { path = "crates/vespertide-core", version = "0.1.58", default-features = false }
17+
vespertide-config = { path = "crates/vespertide-config", version = "0.1.58", default-features = false }
18+
vespertide-loader = { path = "crates/vespertide-loader", version = "0.1.58", default-features = false }
19+
vespertide-macro = { path = "crates/vespertide-macro", version = "0.1.58" }
20+
vespertide-naming = { path = "crates/vespertide-naming", version = "0.1.58" }
21+
vespertide-planner = { path = "crates/vespertide-planner", version = "0.1.58" }
22+
vespertide-query = { path = "crates/vespertide-query", version = "0.1.58" }
23+
vespertide-exporter = { path = "crates/vespertide-exporter", version = "0.1.58" }
2424

2525
[profile.dev]
2626
debug = 1 # Line tables only — faster DWARF generation for large codegen output

crates/vespertide-exporter/src/seaorm/mod.rs

Lines changed: 85 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1584,7 +1584,7 @@ fn render_enum(
15841584
lines.push(format!("#[derive({})]", derives.join(", ")));
15851585
lines.push(format!(
15861586
"#[serde(rename_all = \"{}\")]",
1587-
config.enum_naming_case().serde_rename_all()
1587+
enum_serde_rename_all(values, config)
15881588
));
15891589

15901590
match values {
@@ -1605,8 +1605,9 @@ fn render_enum(
16051605

16061606
match values {
16071607
EnumValues::String(string_values) => {
1608+
let use_screaming_snake_variants = uses_screaming_snake_variants(string_values);
16081609
for s in string_values {
1609-
let variant_name = enum_variant_name(s);
1610+
let variant_name = enum_string_variant_name(s, use_screaming_snake_variants);
16101611
lines.push(format!(" #[sea_orm(string_value = \"{}\")]", s));
16111612
lines.push(format!(" {},", variant_name));
16121613
}
@@ -1631,6 +1632,20 @@ fn render_enum(
16311632
fn enum_variant_name(s: &str) -> String {
16321633
let pascal = to_pascal_case(s);
16331634

1635+
finalize_enum_variant_name(pascal)
1636+
}
1637+
1638+
fn enum_string_variant_name(s: &str, use_screaming_snake_variants: bool) -> String {
1639+
let pascal = if use_screaming_snake_variants {
1640+
screaming_snake_to_pascal_case(s)
1641+
} else {
1642+
to_pascal_case(s)
1643+
};
1644+
1645+
finalize_enum_variant_name(pascal)
1646+
}
1647+
1648+
fn finalize_enum_variant_name(pascal: String) -> String {
16341649
// Handle empty string
16351650
if pascal.is_empty() {
16361651
return "Value".to_string();
@@ -1649,6 +1664,58 @@ fn enum_variant_name(s: &str) -> String {
16491664
pascal
16501665
}
16511666

1667+
fn enum_serde_rename_all(values: &EnumValues, config: &SeaOrmConfig) -> &'static str {
1668+
match values {
1669+
EnumValues::String(string_values) if uses_screaming_snake_variants(string_values) => {
1670+
"SCREAMING_SNAKE_CASE"
1671+
}
1672+
_ => config.enum_naming_case().serde_rename_all(),
1673+
}
1674+
}
1675+
1676+
fn uses_screaming_snake_variants(values: &[String]) -> bool {
1677+
!values.is_empty() && values.iter().all(|value| is_screaming_snake_value(value))
1678+
}
1679+
1680+
fn is_screaming_snake_value(value: &str) -> bool {
1681+
let mut has_ascii_upper = false;
1682+
1683+
for ch in value.chars() {
1684+
if ch.is_ascii_lowercase() {
1685+
return false;
1686+
}
1687+
if ch.is_ascii_uppercase() {
1688+
has_ascii_upper = true;
1689+
continue;
1690+
}
1691+
if ch.is_ascii_digit() || ch == '_' {
1692+
continue;
1693+
}
1694+
return false;
1695+
}
1696+
1697+
has_ascii_upper
1698+
}
1699+
1700+
fn screaming_snake_to_pascal_case(value: &str) -> String {
1701+
value
1702+
.split('_')
1703+
.filter(|segment| !segment.is_empty())
1704+
.map(|segment| {
1705+
let mut chars = segment.chars();
1706+
match chars.next() {
1707+
Some(first) => {
1708+
let mut out = String::new();
1709+
out.push(first.to_ascii_uppercase());
1710+
out.extend(chars.map(|ch| ch.to_ascii_lowercase()));
1711+
out
1712+
}
1713+
None => String::new(),
1714+
}
1715+
})
1716+
.collect()
1717+
}
1718+
16521719
fn to_pascal_case(s: &str) -> String {
16531720
let mut result = String::new();
16541721
let mut capitalize = true;
@@ -2182,6 +2249,8 @@ mod helper_tests {
21822249
#[case("pending", "Pending")]
21832250
#[case("in_stock", "InStock")]
21842251
#[case("info-level", "InfoLevel")]
2252+
#[case("ACTIVE", "ACTIVE")]
2253+
#[case("ERROR_LEVEL", "ERRORLEVEL")]
21852254
#[case("1critical", "N1critical")]
21862255
#[case("123abc", "N123abc")]
21872256
#[case("1_critical", "N1Critical")]
@@ -2190,6 +2259,20 @@ mod helper_tests {
21902259
assert_eq!(enum_variant_name(input), expected);
21912260
}
21922261

2262+
#[test]
2263+
fn test_render_enum_uses_screaming_snake_serde_for_uppercase_values() {
2264+
let mut lines = Vec::new();
2265+
let config = SeaOrmConfig::default();
2266+
let values = EnumValues::String(vec!["PENDING".into(), "IN_PROGRESS".into()]);
2267+
2268+
render_enum(&mut lines, "orders", "order_status", &values, &config);
2269+
2270+
let result = lines.join("\n");
2271+
assert!(result.contains("#[serde(rename_all = \"SCREAMING_SNAKE_CASE\")]"));
2272+
assert!(result.contains(" #[sea_orm(string_value = \"PENDING\")]\n Pending,"));
2273+
assert!(result.contains(" #[sea_orm(string_value = \"IN_PROGRESS\")]\n InProgress,"));
2274+
}
2275+
21932276
fn string_enum_order_status() -> (&'static str, EnumValues) {
21942277
(
21952278
"order_status",

examples/app/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,4 @@ tokio = { version = "1", features = ["full"] }
1010
sea-orm = { version = "2.0.0-rc.37", features = ["sqlx-sqlite", "sqlx-postgres", "runtime-tokio-native-tls", "macros"] }
1111
anyhow = "1"
1212
serde = { version = "1", features = ["derive"] }
13-
vespera = "0.1.48"
13+
vespera = "0.1.50"

0 commit comments

Comments
 (0)