toasty_driver_integration_suite/tests/
embedded_enum_index.rs

1use crate::prelude::*;
2
3/// Tests that `#[unique]` and `#[index]` on embedded enum variant fields produce
4/// physical DB indices on the flattened columns.
5#[driver_test]
6pub async fn embedded_enum_index_schema(test: &mut Test) {
7    #[derive(Debug, toasty::Embed)]
8    enum ContactInfo {
9        #[column(variant = 1)]
10        Email {
11            #[unique]
12            address: String,
13        },
14        #[column(variant = 2)]
15        Phone {
16            #[index]
17            number: String,
18        },
19    }
20
21    #[derive(Debug, toasty::Model)]
22    struct User {
23        #[key]
24        id: String,
25        name: String,
26        #[allow(dead_code)]
27        contact: ContactInfo,
28    }
29
30    let db = test.setup_db(models!(User, ContactInfo)).await;
31    let schema = db.schema();
32
33    // The embedded enum should carry its indices in the app schema
34    assert_struct!(schema.app.models, #{
35        ContactInfo::id(): toasty::schema::app::Model::EmbeddedEnum(_ {
36            indices.len(): 2,
37            ..
38        }),
39        ..
40    });
41
42    // The DB table should have indices on the flattened variant field columns.
43    // Index 0: primary key (id)
44    // Index 1: unique on contact_address
45    // Index 2: non-unique on contact_number
46    let table = &schema.db.tables[0];
47    let address_col = columns(&db, "users", &["contact_address"])[0];
48    let number_col = columns(&db, "users", &["contact_number"])[0];
49
50    assert_struct!(table.indices, [
51        // PK
52        _ { primary_key: true, .. },
53        // Unique index on contact_address
54        _ { unique: true, primary_key: false, columns: [_ { column: == address_col }] },
55        // Non-unique index on contact_number
56        _ { unique: false, primary_key: false, columns: [_ { column: == number_col }] },
57    ]);
58}
59
60/// Tests that unique constraint on embedded enum variant field is enforced at
61/// the database level.
62#[driver_test]
63pub async fn embedded_enum_unique_index_enforced(test: &mut Test) -> Result<()> {
64    #[derive(Debug, toasty::Embed)]
65    enum ContactInfo {
66        #[column(variant = 1)]
67        Email {
68            #[unique]
69            address: String,
70        },
71        #[column(variant = 2)]
72        Phone { number: String },
73    }
74
75    #[derive(Debug, toasty::Model)]
76    struct User {
77        #[key]
78        id: String,
79        name: String,
80        contact: ContactInfo,
81    }
82
83    let mut db = test.setup_db(models!(User, ContactInfo)).await;
84
85    // Create a user with an email contact
86    User::create()
87        .id("1")
88        .name("Alice")
89        .contact(ContactInfo::Email {
90            address: "alice@example.com".to_string(),
91        })
92        .exec(&mut db)
93        .await?;
94
95    // Creating another user with the same email address should fail
96    assert_err!(
97        User::create()
98            .id("2")
99            .name("Bob")
100            .contact(ContactInfo::Email {
101                address: "alice@example.com".to_string(),
102            })
103            .exec(&mut db)
104            .await
105    );
106
107    // Creating a user with a different email works
108    User::create()
109        .id("3")
110        .name("Charlie")
111        .contact(ContactInfo::Email {
112            address: "charlie@example.com".to_string(),
113        })
114        .exec(&mut db)
115        .await?;
116
117    // Creating a user with a phone contact works (different variant, no unique on number)
118    User::create()
119        .id("4")
120        .name("Dave")
121        .contact(ContactInfo::Phone {
122            number: "555-1234".to_string(),
123        })
124        .exec(&mut db)
125        .await?;
126
127    // Filter by the indexed variant field
128    let users = User::filter(
129        User::fields()
130            .contact()
131            .email()
132            .matches(|e| e.address().eq("alice@example.com")),
133    )
134    .exec(&mut db)
135    .await?;
136
137    assert_struct!(users, [_ { name: "Alice", .. }]);
138
139    Ok(())
140}