Skip to main content

toasty_driver_integration_suite/tests/
crud_basic.rs

1use crate::prelude::*;
2
3use toasty_core::{
4    driver::{Operation, Rows},
5    stmt::{Assignment, Expr, 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]: Assignment::Set(Expr::Arg({ position: 0 }))},
137            }),
138            params: [{ value: == "updated!" }, ..],
139            ret: None,
140        }));
141    } else {
142        assert_struct!(op, Operation::UpdateByKey({
143            table: == item_table_id,
144            keys.len(): 1,
145            assignments: #{ [1]: Assignment::Set(== "updated!")},
146            filter: None,
147            returning: false,
148        }));
149    }
150    assert_struct!(resp, { values: Rows::Count(1) });
151    assert!(test.log().is_empty());
152
153    test.log().clear();
154    let reload = Item::get_by_id(&mut db, &created.id).await?;
155    assert_eq!(reload.val, created.val);
156
157    // Update by ID
158    Item::filter_by_id(created.id)
159        .update()
160        .val("updated again!")
161        .exec(&mut db)
162        .await?;
163    let reload = Item::get_by_id(&mut db, &created.id).await?;
164    assert_eq!(reload.val, "updated again!");
165
166    // Delete the record (instance method — generates full-key filter).
167    test.log().clear();
168    reload.delete().exec(&mut db).await?;
169
170    let (op, resp) = test.log().pop();
171    if is_sql {
172        assert_struct!(op, Operation::QuerySql({
173            stmt: Statement::Delete({
174                from: Source::Table({
175                    tables: [== item_table_id, ..],
176                }),
177            }),
178        }));
179    } else {
180        assert_struct!(op, Operation::DeleteByKey({
181            table: == item_table_id,
182            keys.len(): 1,
183            filter: None,
184        }));
185    }
186    assert_struct!(resp, { values: Rows::Count(1) });
187    assert!(test.log().is_empty());
188
189    // It is gone
190    assert_err!(Item::get_by_id(&mut db, &created.id).await);
191
192    // Delete by ID
193    Item::filter_by_id(ids[0]).delete().exec(&mut db).await?;
194
195    // It is gone
196    assert_err!(Item::get_by_id(&mut db, &ids[0]).await);
197    Ok(())
198}
199
200#[driver_test(id(ID))]
201pub async fn required_field_create_without_setting(test: &mut Test) {
202    #[derive(Debug, toasty::Model)]
203    struct User {
204        #[key]
205        #[auto]
206        id: ID,
207
208        #[allow(dead_code)]
209        name: String,
210    }
211
212    let mut db = test.setup_db(models!(User)).await;
213
214    // Try creating a user without setting the name field results in an error
215    assert_err!(User::create().exec(&mut db).await);
216}
217
218#[driver_test(id(ID), scenario(crate::scenarios::user_unique_email))]
219pub async fn unique_index_required_field_update(test: &mut Test) -> Result<()> {
220    let mut db = setup(test).await;
221
222    let email = "user1@example.com";
223
224    let user = User::create().email(email).exec(&mut db).await?;
225
226    assert_eq!("user1@example.com", user.email);
227
228    // Trying to create a user with the same email address fails
229    assert_err!(User::create().email(email).exec(&mut db).await);
230
231    // Loading the user by email
232    let user_reloaded = User::get_by_email(&mut db, email).await?;
233    assert_eq!(user.id, user_reloaded.id);
234    assert_eq!(user_reloaded.email, email);
235
236    // Creating a user with a different email works
237    let user_alt_email = User::create()
238        .email("alt-email@example.com")
239        .exec(&mut db)
240        .await?;
241
242    assert_ne!(user.id, user_alt_email.id);
243
244    // Deleting the user then reuse the email address
245    user.delete().exec(&mut db).await?;
246
247    // Finding by the email returns None
248    assert_none!(User::filter_by_email(email).first().exec(&mut db).await?);
249
250    let mut user2 = User::create().email(email).exec(&mut db).await?;
251    assert_ne!(user2.id, user_reloaded.id);
252
253    // Trying to create a third user with that email address fails.
254    assert_err!(User::create().email(email).exec(&mut db).await);
255
256    // Updating the email address by object
257    user2
258        .update()
259        .email("user2@example.com")
260        .exec(&mut db)
261        .await?;
262
263    // Reload the user by ID
264    let user_reloaded = User::filter_by_id(user2.id).get(&mut db).await?;
265    assert_eq!(user2.id, user_reloaded.id);
266    assert_eq!(user_reloaded.email, "user2@example.com");
267
268    // Finding by the email returns None
269    assert_none!(User::filter_by_email(email).first().exec(&mut db).await?);
270
271    // Trying to create a user with the updated email address fails
272    assert_err!(
273        User::create()
274            .email("user2@example.com")
275            .exec(&mut db)
276            .await
277    );
278
279    // Creating a user with the **old** email address succeeds
280    let user3 = User::create().email(email).exec(&mut db).await?;
281    assert_eq!(user3.email, email);
282    assert_ne!(user3.id, user2.id);
283
284    // Updating the email address by ID
285    User::filter_by_id(user2.id)
286        .update()
287        .email("user3@example.com")
288        .exec(&mut db)
289        .await?;
290
291    // Finding by the email returns None
292    assert_none!(
293        User::filter_by_email(&user2.email)
294            .first()
295            .exec(&mut db)
296            .await?
297    );
298
299    // Find the user by the new address.
300    let u = User::filter_by_email("user3@example.com")
301        .get(&mut db)
302        .await?;
303
304    assert_eq!(u.id, user2.id);
305
306    assert_err!(
307        User::create()
308            .email("user3@example.com")
309            .exec(&mut db)
310            .await
311    );
312
313    // But we *can* create a user w/ the old email
314    assert_ok!(
315        User::create()
316            .email("user2@example.com")
317            .exec(&mut db)
318            .await
319    );
320    Ok(())
321}
322
323#[driver_test(id(ID))]
324pub async fn unique_index_nullable_field_update(test: &mut Test) -> Result<()> {
325    #[derive(Debug, toasty::Model)]
326    struct User {
327        #[key]
328        #[auto]
329        id: ID,
330
331        #[unique]
332        email: Option<String>,
333    }
334
335    let mut db = test.setup_db(models!(User)).await;
336
337    // Create a user without an email address
338    let mut u1 = User::create().exec(&mut db).await?;
339    assert!(u1.email.is_none());
340
341    // Create a second user without an email address
342    let mut u2 = User::create().exec(&mut db).await?;
343    assert!(u2.email.is_none());
344
345    // Reload u1 and make sure email is still set.
346    let u1_reload = User::get_by_id(&mut db, &u1.id).await?;
347    assert!(u1_reload.email.is_none());
348
349    // Finding by a bogus email finds nothing
350    assert_none!(
351        User::filter_by_email("nobody@example.com")
352            .first()
353            .exec(&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 unique_index_set_same_value(test: &mut Test) -> Result<()> {
446    #[derive(Debug, toasty::Model)]
447    struct User {
448        #[key]
449        #[auto]
450        id: ID,
451
452        #[unique]
453        email: String,
454
455        name: String,
456    }
457
458    let mut db = test.setup_db(models!(User)).await;
459
460    let mut user = toasty::create!(User {
461        email: "user@example.com",
462        name: "John Doe",
463    })
464    .exec(&mut db)
465    .await?;
466
467    // Update both fields, but set email to the same value it already has.
468    // This exercises the path where the unique column appears in op.assignments
469    // but its new value equals the current stored value.
470    user.update()
471        .email("user@example.com")
472        .name("Jane Doe")
473        .exec(&mut db)
474        .await?;
475
476    assert_eq!("user@example.com", user.email);
477    assert_eq!("Jane Doe", user.name);
478
479    let u = User::get_by_id(&mut db, &user.id).await?;
480    assert_eq!(user.email, u.email);
481    assert_eq!(user.name, u.name);
482
483    // Lookup by email still works
484    let u = User::get_by_email(&mut db, &user.email).await?;
485    assert_eq!(user.name, u.name);
486
487    Ok(())
488}
489
490#[driver_test(id(ID))]
491pub async fn update_multiple_fields(test: &mut Test) -> Result<()> {
492    #[derive(Debug, toasty::Model)]
493    struct User {
494        #[key]
495        #[auto]
496        id: ID,
497
498        name: String,
499        email: String,
500    }
501
502    let mut db = test.setup_db(models!(User)).await;
503
504    let mut user = User::create()
505        .name("John Doe")
506        .email("john@example.com")
507        .exec(&mut db)
508        .await?;
509
510    // Update by object
511    user.update()
512        .name("Jane Doe")
513        .email("jane@example.com")
514        .exec(&mut db)
515        .await?;
516
517    assert_eq!("Jane Doe", user.name);
518    assert_eq!("jane@example.com", user.email);
519
520    let user = User::get_by_id(&mut db, &user.id).await?;
521    assert_eq!("Jane Doe", user.name);
522    assert_eq!("jane@example.com", user.email);
523
524    // Update by query
525    User::filter_by_id(user.id)
526        .update()
527        .name("John2 Doe")
528        .email("john2@example.com")
529        .exec(&mut db)
530        .await?;
531
532    let user = User::get_by_id(&mut db, &user.id).await?;
533    assert_eq!("John2 Doe", user.name);
534    assert_eq!("john2@example.com", user.email);
535    Ok(())
536}
537
538#[driver_test(id(ID))]
539pub async fn update_and_delete_snippets(test: &mut Test) -> Result<()> {
540    #[derive(Debug, toasty::Model)]
541    struct User {
542        #[key]
543        #[auto]
544        id: ID,
545
546        #[allow(dead_code)]
547        name: String,
548    }
549
550    let mut db = test.setup_db(models!(User)).await;
551
552    let user = User::create().name("John Doe").exec(&mut db).await?;
553
554    User::update_by_id(user.id)
555        .name("John Doe2")
556        .exec(&mut db)
557        .await?;
558
559    let new_user = User::get_by_id(&mut db, user.id).await?;
560    assert!(new_user.name == "John Doe2");
561
562    User::delete_by_id(&mut db, user.id).await?;
563
564    assert_err!(User::get_by_id(&mut db, user.id).await);
565    Ok(())
566}