toasty_driver_integration_suite/tests/
one_model_crud.rs

1use crate::prelude::*;
2
3use toasty_core::{
4    driver::{Operation, Rows},
5    stmt::{Source, Statement, UpdateTarget},
6};
7
8#[driver_test(id(ID))]
9pub async fn crud_no_fields(t: &mut Test) -> Result<()> {
10    const MORE: i32 = 10;
11
12    #[derive(Debug, toasty::Model)]
13    struct Item {
14        #[key]
15        #[auto]
16        id: ID,
17    }
18
19    let mut db = t.setup_db(models!(Item)).await;
20
21    let created = Item::create().exec(&mut db).await?;
22
23    // Find Item
24    let read = Item::filter_by_id(created.id).exec(&mut db).await?;
25
26    assert_eq!(1, read.len());
27    assert_eq!(created.id, read[0].id);
28
29    // Generate a few instances, IDs should be different
30
31    let mut ids = vec![];
32
33    for _ in 0..MORE {
34        let item = Item::create().exec(&mut db).await?;
35        assert_ne!(item.id, created.id);
36        ids.push(item.id);
37    }
38
39    assert_unique!(ids);
40
41    for id in &ids {
42        let read = Item::filter_by_id(id).exec(&mut db).await?;
43
44        assert_eq!(1, read.len());
45        assert_eq!(*id, read[0].id);
46    }
47
48    // Randomize the IDs
49    ids.shuffle();
50
51    // Delete the IDs
52    for i in 0..MORE {
53        let id = ids.pop().unwrap();
54
55        if i.is_even() {
56            // Delete by object
57            let val = Item::get_by_id(&mut db, &id).await?;
58            val.delete().exec(&mut db).await?;
59        } else {
60            // Delete by ID
61            Item::filter_by_id(id).delete().exec(&mut db).await?;
62        }
63
64        // Assert deleted
65        assert_err!(Item::get_by_id(&mut db, id).await);
66
67        // Assert other items remain
68        for id in &ids {
69            let item = Item::get_by_id(&mut db, id).await?;
70            assert_eq!(*id, item.id);
71        }
72    }
73    Ok(())
74}
75
76#[driver_test(id(ID))]
77pub async fn crud_one_string(test: &mut Test) -> Result<()> {
78    #[derive(Debug, toasty::Model)]
79    struct Item {
80        #[key]
81        #[auto]
82        id: ID,
83
84        val: String,
85    }
86
87    let mut db = test.setup_db(models!(Item)).await;
88
89    let item_table_id = table_id(&db, "items");
90    let is_sql = test.capability().sql;
91
92    let mut created = Item::create().val("hello world").exec(&mut db).await?;
93
94    assert_eq!(created.val, "hello world");
95
96    // Find Item
97    let read = Item::filter_by_id(created.id).exec(&mut db).await?;
98
99    assert_eq!(1, read.len());
100    assert_eq!(created.id, read[0].id);
101    assert_eq!(created.val, "hello world");
102
103    let mut ids = vec![];
104
105    for i in 0..10 {
106        let item = Item::create()
107            .val(format!("hello {i}"))
108            .exec(&mut db)
109            .await?;
110
111        assert_ne!(item.id, created.id);
112        ids.push(item.id);
113    }
114
115    assert_unique!(ids);
116
117    for (i, id) in ids.iter().enumerate() {
118        let read = Item::filter_by_id(id).exec(&mut db).await?;
119
120        assert_eq!(1, read.len());
121        assert_eq!(*id, read[0].id);
122        assert_eq!(format!("hello {i}"), read[0].val);
123    }
124
125    // Update by val (instance method — generates full-key filter).
126    test.log().clear();
127    created.update().val("updated!").exec(&mut db).await?;
128    assert_eq!(created.val, "updated!");
129
130    let (op, resp) = test.log().pop();
131    // Column index 1 = val (id=0, val=1).
132    if is_sql {
133        assert_struct!(op, Operation::QuerySql(_ {
134            stmt: Statement::Update(_ {
135                target: UpdateTarget::Table(== item_table_id),
136                assignments: #{ 1: _ { expr: == "updated!", .. }},
137                ..
138            }),
139            ret: None,
140            ..
141        }));
142    } else {
143        assert_struct!(op, Operation::UpdateByKey(_ {
144            table: == item_table_id,
145            keys.len(): 1,
146            assignments: #{ 1: _ { expr: == "updated!", .. }},
147            filter: None,
148            returning: false,
149            ..
150        }));
151    }
152    assert_struct!(resp, _ { rows: Rows::Count(1), .. });
153    assert!(test.log().is_empty());
154
155    test.log().clear();
156    let reload = Item::get_by_id(&mut db, &created.id).await?;
157    assert_eq!(reload.val, created.val);
158
159    // Update by ID
160    Item::filter_by_id(created.id)
161        .update()
162        .val("updated again!")
163        .exec(&mut db)
164        .await?;
165    let reload = Item::get_by_id(&mut db, &created.id).await?;
166    assert_eq!(reload.val, "updated again!");
167
168    // Delete the record (instance method — generates full-key filter).
169    test.log().clear();
170    reload.delete().exec(&mut db).await?;
171
172    let (op, resp) = test.log().pop();
173    if is_sql {
174        assert_struct!(op, Operation::QuerySql(_ {
175            stmt: Statement::Delete(_ {
176                from: Source::Table(_ {
177                    tables: [== item_table_id, ..],
178                    ..
179                }),
180                ..
181            }),
182            ..
183        }));
184    } else {
185        assert_struct!(op, Operation::DeleteByKey(_ {
186            table: == item_table_id,
187            keys.len(): 1,
188            filter: None,
189            ..
190        }));
191    }
192    assert_struct!(resp, _ { rows: Rows::Count(1), .. });
193    assert!(test.log().is_empty());
194
195    // It is gone
196    assert_err!(Item::get_by_id(&mut db, &created.id).await);
197
198    // Delete by ID
199    Item::filter_by_id(ids[0]).delete().exec(&mut db).await?;
200
201    // It is gone
202    assert_err!(Item::get_by_id(&mut db, &ids[0]).await);
203    Ok(())
204}
205
206#[driver_test(id(ID))]
207pub async fn required_field_create_without_setting(test: &mut Test) {
208    #[derive(Debug, toasty::Model)]
209    struct User {
210        #[key]
211        #[auto]
212        id: ID,
213
214        #[allow(dead_code)]
215        name: String,
216    }
217
218    let mut db = test.setup_db(models!(User)).await;
219
220    // Try creating a user without setting the name field results in an error
221    assert_err!(User::create().exec(&mut db).await);
222}
223
224#[driver_test(id(ID), scenario(crate::scenarios::user_unique_email))]
225pub async fn unique_index_required_field_update(test: &mut Test) -> Result<()> {
226    let mut db = setup(test).await;
227
228    let email = "user1@example.com";
229
230    let user = User::create().email(email).exec(&mut db).await?;
231
232    assert_eq!("user1@example.com", user.email);
233
234    // Trying to create a user with the same email address fails
235    assert_err!(User::create().email(email).exec(&mut db).await);
236
237    // Loading the user by email
238    let user_reloaded = User::get_by_email(&mut db, email).await?;
239    assert_eq!(user.id, user_reloaded.id);
240    assert_eq!(user_reloaded.email, email);
241
242    // Creating a user with a different email works
243    let user_alt_email = User::create()
244        .email("alt-email@example.com")
245        .exec(&mut db)
246        .await?;
247
248    assert_ne!(user.id, user_alt_email.id);
249
250    // Deleting the user then reuse the email address
251    user.delete().exec(&mut db).await?;
252
253    // Finding by the email returns None
254    assert_none!(User::filter_by_email(email).first(&mut db).await?);
255
256    let mut user2 = User::create().email(email).exec(&mut db).await?;
257    assert_ne!(user2.id, user_reloaded.id);
258
259    // Trying to create a third user with that email address fails.
260    assert_err!(User::create().email(email).exec(&mut db).await);
261
262    // Updating the email address by object
263    user2
264        .update()
265        .email("user2@example.com")
266        .exec(&mut db)
267        .await?;
268
269    // Reload the user by ID
270    let user_reloaded = User::filter_by_id(user2.id).get(&mut db).await?;
271    assert_eq!(user2.id, user_reloaded.id);
272    assert_eq!(user_reloaded.email, "user2@example.com");
273
274    // Finding by the email returns None
275    assert_none!(User::filter_by_email(email).first(&mut db).await?);
276
277    // Trying to create a user with the updated email address fails
278    assert_err!(
279        User::create()
280            .email("user2@example.com")
281            .exec(&mut db)
282            .await
283    );
284
285    // Creating a user with the **old** email address succeeds
286    let user3 = User::create().email(email).exec(&mut db).await?;
287    assert_eq!(user3.email, email);
288    assert_ne!(user3.id, user2.id);
289
290    // Updating the email address by ID
291    User::filter_by_id(user2.id)
292        .update()
293        .email("user3@example.com")
294        .exec(&mut db)
295        .await?;
296
297    // Finding by the email returns None
298    assert_none!(User::filter_by_email(&user2.email).first(&mut db).await?);
299
300    // Find the user by the new address.
301    let u = User::filter_by_email("user3@example.com")
302        .get(&mut db)
303        .await?;
304
305    assert_eq!(u.id, user2.id);
306
307    assert_err!(
308        User::create()
309            .email("user3@example.com")
310            .exec(&mut db)
311            .await
312    );
313
314    // But we *can* create a user w/ the old email
315    assert_ok!(
316        User::create()
317            .email("user2@example.com")
318            .exec(&mut db)
319            .await
320    );
321    Ok(())
322}
323
324#[driver_test(id(ID))]
325pub async fn unique_index_nullable_field_update(test: &mut Test) -> Result<()> {
326    #[derive(Debug, toasty::Model)]
327    struct User {
328        #[key]
329        #[auto]
330        id: ID,
331
332        #[unique]
333        email: Option<String>,
334    }
335
336    let mut db = test.setup_db(models!(User)).await;
337
338    // Create a user without an email address
339    let mut u1 = User::create().exec(&mut db).await?;
340    assert!(u1.email.is_none());
341
342    // Create a second user without an email address
343    let mut u2 = User::create().exec(&mut db).await?;
344    assert!(u2.email.is_none());
345
346    // Reload u1 and make sure email is still set.
347    let u1_reload = User::get_by_id(&mut db, &u1.id).await?;
348    assert!(u1_reload.email.is_none());
349
350    // Finding by a bogus email finds nothing
351    assert_none!(
352        User::filter_by_email("nobody@example.com")
353            .first(&mut db)
354            .await?
355    );
356
357    // Create a user **with** an email
358    let mut u3 = User::create()
359        .email("three@example.com")
360        .exec(&mut db)
361        .await?;
362    assert_eq!(u3.email, Some("three@example.com".to_string()));
363
364    let u3_reload = User::get_by_email(&mut db, "three@example.com").await?;
365    assert_eq!(u3_reload.id, u3.id);
366
367    // Now, set u1's email to something
368    u1.update().email("one@example.com").exec(&mut db).await?;
369    assert_eq!(u1.email, Some("one@example.com".to_string()));
370
371    // Find it
372    let u1_reload = User::get_by_email(&mut db, "one@example.com").await?;
373    assert_eq!(u1.id, u1_reload.id);
374
375    // Try updating user 2 to an already taken email address
376    assert_err!(u2.update().email("three@example.com").exec(&mut db).await);
377
378    // Can still fetch user 3
379    let u3_reload = User::get_by_email(&mut db, "three@example.com").await?;
380    assert_eq!(u3_reload.id, u3.id);
381
382    // Update user 2 to set an actual email now.
383    u2.update().email("two@example.com").exec(&mut db).await?;
384    let u2_reload = User::get_by_email(&mut db, "two@example.com").await?;
385    assert_eq!(u2_reload.id, u2.id);
386
387    // Update a user to **remove** the email attribute
388    let mut update = u3.update();
389    update.set_email(None);
390    update.exec(&mut db).await?;
391    assert!(u3.email.is_none());
392
393    // We can create a new user using the freed email
394    let u4 = User::create()
395        .email("three@example.com")
396        .exec(&mut db)
397        .await?;
398    let u4_reload = User::filter_by_email("three@example.com")
399        .get(&mut db)
400        .await?;
401    assert_eq!(u4_reload.id, u4.id);
402    Ok(())
403}
404
405#[driver_test(id(ID))]
406pub async fn unique_index_no_update(test: &mut Test) -> Result<()> {
407    #[derive(Debug, toasty::Model)]
408    struct User {
409        #[key]
410        #[auto]
411        id: ID,
412
413        #[unique]
414        email: String,
415
416        name: String,
417    }
418
419    let mut db = test.setup_db(models!(User)).await;
420
421    let mut user = User::create()
422        .email("user@example.com")
423        .name("John Doe")
424        .exec(&mut db)
425        .await?;
426
427    let u = User::filter_by_id(user.id).get(&mut db).await?;
428    assert_eq!(user.name, u.name);
429
430    // Update the name by value
431    user.update().name("Jane Doe").exec(&mut db).await?;
432
433    assert_eq!("Jane Doe", user.name);
434
435    let u = User::get_by_id(&mut db, &user.id).await?;
436    assert_eq!(user.name, u.name);
437
438    // Find by email still works
439    let u = User::get_by_email(&mut db, &user.email).await?;
440    assert_eq!(user.name, u.name);
441    Ok(())
442}
443
444#[driver_test(id(ID))]
445pub async fn batch_get_by_id(test: &mut Test) -> Result<()> {
446    #[derive(Debug, toasty::Model)]
447    struct Item {
448        #[key]
449        #[auto]
450        id: ID,
451    }
452
453    let mut db = test.setup_db(models!(Item)).await;
454    let mut keys = vec![];
455
456    for _ in 0..5 {
457        let item = Item::create().exec(&mut db).await?;
458        keys.push(item.id);
459    }
460
461    let items: Vec<_> = Item::filter_by_id_batch([&keys[0], &keys[1], &keys[2]])
462        .exec(&mut db)
463        .await?;
464
465    assert_eq!(3, items.len());
466
467    for item in items {
468        assert!(keys.contains(&item.id));
469    }
470    Ok(())
471}
472
473#[driver_test(id(ID))]
474pub async fn empty_batch_get_by_id(test: &mut Test) -> Result<()> {
475    #[derive(Debug, toasty::Model)]
476    struct Item {
477        #[key]
478        #[auto]
479        id: ID,
480    }
481
482    let mut db = test.setup_db(models!(Item)).await;
483    let mut ids = vec![];
484
485    for _ in 0..5 {
486        let item = Item::create().exec(&mut db).await?;
487        ids.push(item.id);
488    }
489
490    let items: Vec<_> = Item::filter_by_id_batch(&[] as &[ID]).exec(&mut db).await?;
491
492    assert_eq!(0, items.len());
493    Ok(())
494}
495
496#[driver_test(id(ID))]
497pub async fn update_multiple_fields(test: &mut Test) -> Result<()> {
498    #[derive(Debug, toasty::Model)]
499    struct User {
500        #[key]
501        #[auto]
502        id: ID,
503
504        name: String,
505        email: String,
506    }
507
508    let mut db = test.setup_db(models!(User)).await;
509
510    let mut user = User::create()
511        .name("John Doe")
512        .email("john@example.com")
513        .exec(&mut db)
514        .await?;
515
516    // Update by object
517    user.update()
518        .name("Jane Doe")
519        .email("jane@example.com")
520        .exec(&mut db)
521        .await?;
522
523    assert_eq!("Jane Doe", user.name);
524    assert_eq!("jane@example.com", user.email);
525
526    let user = User::get_by_id(&mut db, &user.id).await?;
527    assert_eq!("Jane Doe", user.name);
528    assert_eq!("jane@example.com", user.email);
529
530    // Update by query
531    User::filter_by_id(user.id)
532        .update()
533        .name("John2 Doe")
534        .email("john2@example.com")
535        .exec(&mut db)
536        .await?;
537
538    let user = User::get_by_id(&mut db, &user.id).await?;
539    assert_eq!("John2 Doe", user.name);
540    assert_eq!("john2@example.com", user.email);
541    Ok(())
542}
543
544#[driver_test(id(ID))]
545pub async fn update_and_delete_snippets(test: &mut Test) -> Result<()> {
546    #[derive(Debug, toasty::Model)]
547    struct User {
548        #[key]
549        #[auto]
550        id: ID,
551
552        #[allow(dead_code)]
553        name: String,
554    }
555
556    let mut db = test.setup_db(models!(User)).await;
557
558    let user = User::create().name("John Doe").exec(&mut db).await?;
559
560    User::update_by_id(user.id)
561        .name("John Doe2")
562        .exec(&mut db)
563        .await?;
564
565    let new_user = User::get_by_id(&mut db, user.id).await?;
566    assert!(new_user.name == "John Doe2");
567
568    User::delete_by_id(&mut db, user.id).await?;
569
570    assert_err!(User::get_by_id(&mut db, user.id).await);
571    Ok(())
572}