toasty_driver_integration_suite/tests/
default_and_update.rs

1use crate::prelude::*;
2
3#[driver_test(id(ID))]
4pub async fn default_expr_on_create(test: &mut Test) -> Result<()> {
5    #[derive(Debug, toasty::Model)]
6    struct Item {
7        #[key]
8        #[auto]
9        id: ID,
10
11        title: String,
12
13        #[default(5)]
14        view_count: i64,
15    }
16
17    let mut db = test.setup_db(models!(Item)).await;
18
19    // Create without setting view_count — should get the default
20    let created = Item::create().title("hello").exec(&mut db).await?;
21    assert_eq!(created.view_count, 5);
22
23    // Read back from DB
24    let read = Item::get_by_id(&mut db, &created.id).await?;
25    assert_eq!(read.view_count, 5);
26
27    Ok(())
28}
29
30#[driver_test(id(ID))]
31pub async fn default_expr_override(test: &mut Test) -> Result<()> {
32    #[derive(Debug, toasty::Model)]
33    struct Item {
34        #[key]
35        #[auto]
36        id: ID,
37
38        title: String,
39
40        #[default(5)]
41        view_count: i64,
42    }
43
44    let mut db = test.setup_db(models!(Item)).await;
45
46    // Override the default by explicitly setting view_count
47    let created = Item::create()
48        .title("hello")
49        .view_count(42)
50        .exec(&mut db)
51        .await?;
52    assert_eq!(created.view_count, 42);
53
54    let read = Item::get_by_id(&mut db, &created.id).await?;
55    assert_eq!(read.view_count, 42);
56
57    Ok(())
58}
59
60#[driver_test(id(ID))]
61pub async fn update_expr_on_create(test: &mut Test) -> Result<()> {
62    use jiff::Timestamp;
63
64    #[derive(Debug, toasty::Model)]
65    struct Item {
66        #[key]
67        #[auto]
68        id: ID,
69
70        title: String,
71
72        #[update(jiff::Timestamp::now())]
73        updated_at: Timestamp,
74    }
75
76    let mut db = test.setup_db(models!(Item)).await;
77
78    let before = Timestamp::now();
79    let created = Item::create().title("hello").exec(&mut db).await?;
80    let after = Timestamp::now();
81
82    // updated_at should be auto-populated on create
83    assert!(created.updated_at >= before);
84    assert!(created.updated_at <= after);
85
86    Ok(())
87}
88
89#[driver_test(id(ID))]
90pub async fn update_expr_on_update(test: &mut Test) -> Result<()> {
91    use jiff::Timestamp;
92
93    #[derive(Debug, toasty::Model)]
94    struct Item {
95        #[key]
96        #[auto]
97        id: ID,
98
99        title: String,
100
101        #[update(jiff::Timestamp::now())]
102        updated_at: Timestamp,
103    }
104
105    let mut db = test.setup_db(models!(Item)).await;
106
107    let mut item = Item::create().title("hello").exec(&mut db).await?;
108    let created_ts = item.updated_at;
109
110    // Small delay to ensure timestamp changes
111    tokio::time::sleep(std::time::Duration::from_millis(10)).await;
112
113    let before = Timestamp::now();
114    item.update().title("updated").exec(&mut db).await?;
115    let after = Timestamp::now();
116
117    // updated_at should have been refreshed
118    assert!(item.updated_at >= before);
119    assert!(item.updated_at <= after);
120    assert!(item.updated_at > created_ts);
121
122    Ok(())
123}
124
125#[driver_test(id(ID))]
126pub async fn update_expr_override_on_update(test: &mut Test) -> Result<()> {
127    use jiff::Timestamp;
128
129    #[derive(Debug, toasty::Model)]
130    struct Item {
131        #[key]
132        #[auto]
133        id: ID,
134
135        title: String,
136
137        #[update(jiff::Timestamp::now())]
138        updated_at: Timestamp,
139    }
140
141    let mut db = test.setup_db(models!(Item)).await;
142
143    let mut item = Item::create().title("hello").exec(&mut db).await?;
144
145    // Override the update expression with an explicit value
146    let explicit_ts = Timestamp::from_second(946684800).unwrap(); // 2000-01-01
147    item.update()
148        .title("updated")
149        .updated_at(explicit_ts)
150        .exec(&mut db)
151        .await?;
152
153    assert_eq!(item.updated_at, explicit_ts);
154
155    let read = Item::get_by_id(&mut db, &item.id).await?;
156    assert_eq!(read.updated_at, explicit_ts);
157
158    Ok(())
159}
160
161#[driver_test(id(ID))]
162pub async fn default_and_update_on_same_field(test: &mut Test) -> Result<()> {
163    #[derive(Debug, toasty::Model)]
164    struct Item {
165        #[key]
166        #[auto]
167        id: ID,
168
169        title: String,
170
171        // On create: defaults to "draft". On update: automatically set to "edited".
172        #[default("draft".to_string())]
173        #[update("edited".to_string())]
174        status: String,
175    }
176
177    let mut db = test.setup_db(models!(Item)).await;
178
179    // On create, #[default] takes priority
180    let mut item = Item::create().title("hello").exec(&mut db).await?;
181    assert_eq!(item.status, "draft");
182
183    // On update, #[update] applies
184    item.update().title("updated").exec(&mut db).await?;
185    assert_eq!(item.status, "edited");
186
187    // Explicit override on create
188    let mut item2 = Item::create()
189        .title("hello")
190        .status("published".to_string())
191        .exec(&mut db)
192        .await?;
193    assert_eq!(item2.status, "published");
194
195    // Explicit override on update
196    item2
197        .update()
198        .title("updated")
199        .status("archived".to_string())
200        .exec(&mut db)
201        .await?;
202    assert_eq!(item2.status, "archived");
203
204    Ok(())
205}
206
207#[driver_test(id(ID))]
208pub async fn auto_on_timestamp_fields(test: &mut Test) -> Result<()> {
209    use jiff::Timestamp;
210
211    #[derive(Debug, toasty::Model)]
212    struct Item {
213        #[key]
214        #[auto]
215        id: ID,
216
217        title: String,
218
219        #[auto]
220        created_at: Timestamp,
221
222        #[auto]
223        updated_at: Timestamp,
224    }
225
226    let mut db = test.setup_db(models!(Item)).await;
227
228    let before = Timestamp::now();
229    let mut item = Item::create().title("hello").exec(&mut db).await?;
230    let after = Timestamp::now();
231
232    assert!(item.created_at >= before);
233    assert!(item.created_at <= after);
234    assert!(item.updated_at >= before);
235    assert!(item.updated_at <= after);
236
237    tokio::time::sleep(std::time::Duration::from_millis(10)).await;
238
239    let before_update = Timestamp::now();
240    item.update().title("updated").exec(&mut db).await?;
241    let after_update = Timestamp::now();
242
243    // created_at stays the same, updated_at is refreshed
244    assert!(item.created_at <= after);
245    assert!(item.updated_at >= before_update);
246    assert!(item.updated_at <= after_update);
247
248    Ok(())
249}