Skip to main content

toasty_driver_integration_suite/tests/
embed_enum_rename_all.rs

1use crate::prelude::*;
2
3use toasty::Db;
4use toasty_core::schema::db;
5
6/// The (type name, variant labels) of a native enum column, in declaration
7/// order. Panics if the column is not a native enum type.
8fn native_enum(db: &Db, table: &str, column: &str) -> (String, Vec<String>) {
9    match column_storage_ty(db, table, column) {
10        db::Type::Enum(e) => (
11            e.name.expect("a native enum type has a name"),
12            e.variants.into_iter().map(|v| v.name).collect(),
13        ),
14        other => panic!("expected a native enum column, got {other:?}"),
15    }
16}
17
18/// `#[column(rename_all = ...)]` derives each variant's default label; an
19/// explicit per-variant `#[column(variant = ...)]` still wins.
20#[driver_test]
21pub async fn rename_all_derives_labels(t: &mut Test) {
22    #[derive(Debug, toasty::Embed)]
23    #[column(rename_all = "PascalCase")]
24    enum Pascal {
25        Customer,
26        PreferredSupplier,
27    }
28
29    #[derive(Debug, toasty::Embed)]
30    #[column(rename_all = "SCREAMING_SNAKE_CASE")]
31    enum Screaming {
32        Customer,
33        PreferredSupplier,
34    }
35
36    #[derive(Debug, toasty::Embed)]
37    #[column(rename_all = "PascalCase")]
38    enum Overridden {
39        #[column(variant = "vip")]
40        PreferredSupplier,
41        Customer,
42    }
43
44    #[derive(Debug, toasty::Model)]
45    #[allow(dead_code)]
46    struct Contact {
47        #[key]
48        #[auto]
49        id: uuid::Uuid,
50        pascal: Pascal,
51        screaming: Screaming,
52        overridden: Overridden,
53    }
54
55    let db = t.setup_db(models!(Contact)).await;
56
57    assert_eq!(
58        native_enum(&db, "contacts", "pascal").1,
59        ["Customer", "PreferredSupplier"]
60    );
61    assert_eq!(
62        native_enum(&db, "contacts", "screaming").1,
63        ["CUSTOMER", "PREFERRED_SUPPLIER"]
64    );
65    assert_eq!(
66        native_enum(&db, "contacts", "overridden").1,
67        ["vip", "Customer"]
68    );
69}
70
71/// The renamed labels flow into every string storage mapping: native enum
72/// (default, explicit `type = enum`, and named `type = enum("...")`) and the
73/// plain `type = text` column. `rename_all` never affects the enum type name.
74#[driver_test]
75pub async fn rename_all_across_storage_mappings(t: &mut Test) {
76    #[derive(Debug, toasty::Embed)]
77    #[column(rename_all = "PascalCase")]
78    enum NativeDefault {
79        Customer,
80        Supplier,
81    }
82
83    #[derive(Debug, toasty::Embed)]
84    #[column(rename_all = "PascalCase", type = enum)]
85    enum NativeExplicit {
86        Customer,
87        Supplier,
88    }
89
90    #[derive(Debug, toasty::Embed)]
91    #[column(rename_all = "PascalCase", type = enum("party_kind"))]
92    enum NativeNamed {
93        Customer,
94        Supplier,
95    }
96
97    #[derive(Debug, toasty::Embed)]
98    #[column(rename_all = "PascalCase", type = text)]
99    enum TextMapped {
100        Customer,
101        Supplier,
102    }
103
104    #[derive(Debug, toasty::Model)]
105    #[allow(dead_code)]
106    struct Contact {
107        #[key]
108        #[auto]
109        id: uuid::Uuid,
110        native_default: NativeDefault,
111        native_explicit: NativeExplicit,
112        native_named: NativeNamed,
113        text_mapped: TextMapped,
114    }
115
116    let db = t.setup_db(models!(Contact)).await;
117    let renamed = ["Customer".to_string(), "Supplier".to_string()];
118
119    // Default native enum: type name derived from the ident in snake_case.
120    let (name, labels) = native_enum(&db, "contacts", "native_default");
121    assert!(name.ends_with("native_default"), "unexpected name: {name}");
122    assert_eq!(labels, renamed);
123
124    // Explicit `type = enum`: identical native representation.
125    assert_eq!(native_enum(&db, "contacts", "native_explicit").1, renamed);
126
127    // Named `type = enum("party_kind")`: custom type name, renamed labels.
128    let (name, labels) = native_enum(&db, "contacts", "native_named");
129    assert!(name.ends_with("party_kind"), "unexpected name: {name}");
130    assert_eq!(labels, renamed);
131
132    // Plain text mapping: a TEXT column, not a native enum type.
133    assert_eq!(
134        column_storage_ty(&db, "contacts", "text_mapped"),
135        db::Type::Text
136    );
137}
138
139/// End-to-end: a renamed enum round-trips through the database (create + read).
140#[driver_test]
141pub async fn rename_all_round_trip(t: &mut Test) -> Result<()> {
142    #[derive(Debug, PartialEq, toasty::Embed)]
143    #[column(rename_all = "PascalCase")]
144    enum PartyKind {
145        Customer,
146        Supplier,
147    }
148
149    #[derive(Debug, toasty::Model)]
150    struct Contact {
151        #[key]
152        #[auto]
153        id: uuid::Uuid,
154        kind: PartyKind,
155    }
156
157    let mut db = t.setup_db(models!(Contact)).await;
158
159    let contact = toasty::create!(Contact {
160        kind: PartyKind::Supplier,
161    })
162    .exec(&mut db)
163    .await?;
164    let found = Contact::get_by_id(&mut db, &contact.id).await?;
165    assert_eq!(found.kind, PartyKind::Supplier);
166
167    Ok(())
168}