toasty_driver_integration_suite/tests/
has_one_crud_basic.rs

1use crate::prelude::*;
2
3#[driver_test(id(ID))]
4pub async fn crud_has_one_bi_direction_optional(test: &mut Test) -> Result<()> {
5    #[derive(Debug, toasty::Model)]
6    struct User {
7        #[key]
8        #[auto]
9        id: ID,
10
11        name: String,
12
13        #[has_one]
14        profile: toasty::HasOne<Option<Profile>>,
15    }
16
17    #[derive(Debug, toasty::Model)]
18    struct Profile {
19        #[key]
20        #[auto]
21        id: ID,
22
23        #[unique]
24        user_id: Option<ID>,
25
26        #[belongs_to(key = user_id, references = id)]
27        user: toasty::BelongsTo<Option<User>>,
28
29        bio: String,
30    }
31
32    let mut db = test.setup_db(models!(User, Profile)).await;
33
34    // Create a user without a profile
35    let user = User::create().name("Jane Doe").exec(&mut db).await?;
36
37    // No profile
38    assert_none!(user.profile().get(&mut db).await?);
39
40    // Create a profile for the user
41    let profile = user
42        .profile()
43        .create()
44        .bio("a person")
45        .exec(&mut db)
46        .await?;
47
48    // Load the profile
49    let profile_reload = user.profile().get(&mut db).await?.unwrap();
50    assert_eq!(profile.id, profile_reload.id);
51
52    // Load the user via the profile
53    let user_reload = profile.user().get(&mut db).await?.unwrap();
54    assert_eq!(user.id, user_reload.id);
55
56    // Create a new user with a profile
57    let mut user = User::create()
58        .name("Tim Apple")
59        .profile(Profile::create().bio("an apple a day"))
60        .exec(&mut db)
61        .await?;
62
63    let profile = user.profile().get(&mut db).await?.unwrap();
64    assert_eq!(profile.bio, "an apple a day");
65
66    // The new profile is associated with the user
67    assert_eq!(user.id, profile.user().get(&mut db).await?.unwrap().id);
68
69    // Update a user, creating a new profile.
70    user.update()
71        .profile(Profile::create().bio("keeps the doctor away"))
72        .exec(&mut db)
73        .await?;
74
75    // The user's profile is updated
76    let profile = user.profile().get(&mut db).await?.unwrap();
77    assert_eq!(profile.bio, "keeps the doctor away");
78    assert_eq!(user.id, profile.user().get(&mut db).await?.unwrap().id);
79
80    // Unset the profile via an update. This will nullify user on the profile.
81    user.update().profile(None).exec(&mut db).await?;
82
83    // The profile is none
84    assert!(user.profile().get(&mut db).await?.is_none());
85
86    let profile_reloaded = Profile::filter_by_id(profile.id).get(&mut db).await?;
87    assert_none!(profile_reloaded.user_id);
88
89    user.update()
90        .profile(&profile_reloaded)
91        .exec(&mut db)
92        .await?;
93
94    let profile_reloaded = Profile::get_by_id(&mut db, &profile.id).await?;
95    assert_eq!(&user.id, profile_reloaded.user_id.as_ref().unwrap());
96
97    // Deleting the profile will nullify the profile field for the user
98    profile_reloaded.delete().exec(&mut db).await?;
99
100    let mut user_reloaded = User::get_by_id(&mut db, &user.id).await?;
101    assert_none!(user_reloaded.profile().get(&mut db).await?);
102
103    // Create a new profile for the user
104    user_reloaded
105        .update()
106        .profile(Profile::create().bio("hello"))
107        .exec(&mut db)
108        .await?;
109
110    let profile_id = user_reloaded.profile().get(&mut db).await?.unwrap().id;
111
112    // Delete the user
113    user_reloaded.delete().exec(&mut db).await?;
114
115    let profile_reloaded = Profile::get_by_id(&mut db, &profile_id).await?;
116    assert_none!(profile_reloaded.user_id);
117    Ok(())
118}
119
120#[driver_test(id(ID))]
121#[should_panic]
122pub async fn crud_has_one_required_belongs_to_optional(test: &mut Test) -> Result<()> {
123    #[derive(Debug, toasty::Model)]
124    struct User {
125        #[key]
126        #[auto]
127        id: ID,
128
129        #[has_one]
130        profile: toasty::HasOne<Profile>,
131    }
132
133    #[derive(Debug, toasty::Model)]
134    struct Profile {
135        #[key]
136        #[auto]
137        id: ID,
138
139        #[unique]
140        user_id: Option<ID>,
141
142        #[belongs_to(key = user_id, references = id)]
143        user: toasty::BelongsTo<Option<User>>,
144
145        bio: String,
146    }
147
148    let mut db = test.setup_db(models!(User, Profile)).await;
149
150    // Create a new user with a profile
151    let user = User::create()
152        .profile(Profile::create().bio("an apple a day"))
153        .exec(&mut db)
154        .await?;
155
156    let profile = user.profile().get(&mut db).await?;
157    assert_eq!(profile.bio, "an apple a day");
158
159    // The new profile is associated with the user
160    assert_eq!(user.id, profile.user().get(&mut db).await?.unwrap().id);
161
162    // Deleting the user leaves the profile in place.
163    user.delete().exec(&mut db).await?;
164    let profile_reloaded = Profile::get_by_id(&mut db, &profile.id).await?;
165    assert_none!(profile_reloaded.user_id);
166
167    // Try creating a user **without** a user: error
168    assert_err!(User::create().exec(&mut db).await);
169    Ok(())
170}
171
172#[driver_test(id(ID))]
173pub async fn update_belongs_to_with_required_has_one_pair(test: &mut Test) -> Result<()> {
174    #[derive(Debug, toasty::Model)]
175    struct User {
176        #[key]
177        #[auto]
178        id: ID,
179
180        #[has_one]
181        profile: toasty::HasOne<Profile>,
182    }
183
184    #[derive(Debug, toasty::Model)]
185    struct Profile {
186        #[key]
187        #[auto]
188        id: ID,
189
190        #[unique]
191        user_id: Option<ID>,
192
193        #[belongs_to(key = user_id, references = id)]
194        user: toasty::BelongsTo<Option<User>>,
195
196        bio: String,
197    }
198
199    let mut db = test.setup_db(models!(User, Profile)).await;
200
201    // Create a user with a profile
202    let u1 = User::create()
203        .profile(Profile::create().bio("an apple a day"))
204        .exec(&mut db)
205        .await?;
206
207    let mut p1 = u1.profile().get(&mut db).await?;
208    assert_eq!(p1.bio, "an apple a day");
209
210    // Associate the profile with a new user by value
211    let u2 = User::create()
212        .profile(Profile::create().bio("I plant trees"))
213        .exec(&mut db)
214        .await?;
215
216    let p2 = u2.profile().get(&mut db).await?;
217    assert_eq!(p2.bio, "I plant trees");
218
219    // Associate the original profile w/ the new user by value
220    p1.update().user(&u2).exec(&mut db).await?;
221
222    // assert_eq!(u2.id, p1.user().find(&mut db).await.unwrap().unwrap().id);
223    // u1 is deleted
224    assert_err!(User::get_by_id(&mut db, &u1.id).await);
225    // p2 ID is null
226    let p2_reloaded = Profile::get_by_id(&mut db, &p2.id).await?;
227    assert_none!(p2_reloaded.user_id);
228
229    /*
230    // Associate the profile with a new user by statement
231    let u1 = db::User::create()
232        .name("Tim Apple")
233        .profile(db::Profile::create().bio("an apple a day"))
234        .exec(&mut db)
235        .await
236        .unwrap();
237
238    let mut p1 = u1.profile().get(&mut db).await.unwrap();
239    assert_eq!(p1.bio, "an apple a day");
240
241    /*
242    // Associate the profile with a new user by value
243    let u2 = db::User::create()
244        .name("Johnny Appleseed")
245        .profile(db::Profile::create().bio("I plant trees"))
246        .exec(&mut db)
247        .await
248        .unwrap();
249
250    let p2 = u2.profile().get(&mut db).await.unwrap();
251    assert_eq!(p2.bio, "I plant trees");
252    */
253
254    // Associate the original profile w/ the new user by value
255    p1.update()
256        .user(db::User::create().name("Johnny Appleseed"))
257        .exec(&mut db)
258        .await
259        .unwrap();
260
261    assert_eq!(
262        u2.id,
263        p1.user
264            .as_ref()
265            .unwrap()
266            .get(&mut db)
267            .await
268            .unwrap()
269            .unwrap()
270            .id
271    );
272    // u1 is deleted
273    assert_err!(db::User::find_by_id(&u1.id).get(&mut db).await);
274    */
275    Ok(())
276}
277
278#[driver_test(id(ID))]
279pub async fn crud_has_one_optional_belongs_to_required(test: &mut Test) -> Result<()> {
280    #[derive(Debug, toasty::Model)]
281    struct User {
282        #[key]
283        #[auto]
284        id: ID,
285
286        #[has_one]
287        profile: toasty::HasOne<Option<Profile>>,
288    }
289
290    #[derive(Debug, toasty::Model)]
291    struct Profile {
292        #[key]
293        #[auto]
294        id: ID,
295
296        #[unique]
297        user_id: ID,
298
299        #[belongs_to(key = user_id, references = id)]
300        user: toasty::BelongsTo<User>,
301
302        bio: String,
303    }
304
305    let mut db = test.setup_db(models!(User, Profile)).await;
306
307    // Create a new user with a profile
308    let user = User::create()
309        .profile(Profile::create().bio("an apple a day"))
310        .exec(&mut db)
311        .await?;
312
313    let profile = user.profile().get(&mut db).await?.unwrap();
314    assert_eq!(profile.bio, "an apple a day");
315
316    // The new profile is associated with the user
317    assert_eq!(user.id, profile.user().get(&mut db).await?.id);
318
319    // Deleting the user also deletes the profile
320    user.delete().exec(&mut db).await?;
321    assert_err!(Profile::get_by_id(&mut db, &profile.id).await);
322    Ok(())
323}
324
325#[driver_test(id(ID))]
326pub async fn set_has_one_by_value_in_update_query(test: &mut Test) -> Result<()> {
327    #[derive(Debug, toasty::Model)]
328    struct User {
329        #[key]
330        #[auto]
331        id: ID,
332
333        #[has_one]
334        profile: toasty::HasOne<Option<Profile>>,
335    }
336
337    #[derive(Debug, toasty::Model)]
338    struct Profile {
339        #[key]
340        #[auto]
341        id: ID,
342
343        #[unique]
344        user_id: Option<ID>,
345
346        #[belongs_to(key = user_id, references = id)]
347        user: toasty::BelongsTo<Option<User>>,
348    }
349
350    let mut db = test.setup_db(models!(User, Profile)).await;
351
352    let user = User::create().exec(&mut db).await?;
353    let profile = Profile::create().exec(&mut db).await?;
354
355    User::filter_by_id(user.id)
356        .update()
357        .profile(&profile)
358        .exec(&mut db)
359        .await?;
360
361    let profile_reload = user.profile().get(&mut db).await?.unwrap();
362    assert_eq!(profile_reload.id, profile.id);
363
364    assert_eq!(profile_reload.user_id.as_ref().unwrap(), &user.id);
365    Ok(())
366}
367
368#[driver_test(id(ID))]
369pub async fn unset_has_one_in_batch_update(test: &mut Test) -> Result<()> {
370    #[derive(Debug, toasty::Model)]
371    struct User {
372        #[key]
373        #[auto]
374        id: ID,
375
376        #[index]
377        name: String,
378
379        #[has_one]
380        profile: toasty::HasOne<Option<Profile>>,
381    }
382
383    #[derive(Debug, toasty::Model)]
384    struct Profile {
385        #[key]
386        #[auto]
387        id: ID,
388
389        #[unique]
390        user_id: ID,
391
392        #[belongs_to(key = user_id, references = id)]
393        user: toasty::BelongsTo<User>,
394    }
395
396    let mut db = test.setup_db(models!(User, Profile)).await;
397
398    // Create two users with the same name, each with a profile
399    let u1 = User::create()
400        .name("alice")
401        .profile(Profile::create())
402        .exec(&mut db)
403        .await?;
404    let p1 = u1.profile().get(&mut db).await?.unwrap();
405
406    let u2 = User::create()
407        .name("alice")
408        .profile(Profile::create())
409        .exec(&mut db)
410        .await?;
411    let p2 = u2.profile().get(&mut db).await?.unwrap();
412
413    // A third user with a different name (should not be affected)
414    let u3 = User::create()
415        .name("bob")
416        .profile(Profile::create())
417        .exec(&mut db)
418        .await?;
419
420    // Batch update: unset profiles for all users named "alice"
421    User::filter_by_name("alice")
422        .update()
423        .profile(None)
424        .exec(&mut db)
425        .await?;
426
427    // Both profiles should be deleted (required belongs_to)
428    assert_err!(Profile::get_by_id(&mut db, &p1.id).await);
429    assert_err!(Profile::get_by_id(&mut db, &p2.id).await);
430
431    // Bob's profile should still exist
432    let p3 = u3.profile().get(&mut db).await?.unwrap();
433    assert_eq!(p3.user_id, u3.id);
434
435    Ok(())
436}
437
438#[driver_test(id(ID))]
439pub async fn unset_has_one_with_required_pair_in_pk_query_update(test: &mut Test) -> Result<()> {
440    #[derive(Debug, toasty::Model)]
441    struct User {
442        #[key]
443        #[auto]
444        id: ID,
445
446        #[has_one]
447        profile: toasty::HasOne<Option<Profile>>,
448    }
449
450    #[derive(Debug, toasty::Model)]
451    struct Profile {
452        #[key]
453        #[auto]
454        id: ID,
455
456        #[unique]
457        user_id: ID,
458
459        #[belongs_to(key = user_id, references = id)]
460        user: toasty::BelongsTo<User>,
461    }
462
463    let mut db = test.setup_db(models!(User, Profile)).await;
464
465    let user = User::create()
466        .profile(Profile::create())
467        .exec(&mut db)
468        .await?;
469    let profile = user.profile().get(&mut db).await?.unwrap();
470
471    assert_eq!(user.id, profile.user_id);
472
473    User::filter_by_id(user.id)
474        .update()
475        .profile(None)
476        .exec(&mut db)
477        .await?;
478
479    // Profile is deleted
480    assert_err!(Profile::get_by_id(&mut db, &profile.id).await);
481    Ok(())
482}
483
484#[driver_test(id(ID))]
485pub async fn unset_has_one_with_required_pair_in_non_pk_query_update(
486    test: &mut Test,
487) -> Result<()> {
488    #[derive(Debug, toasty::Model)]
489    struct User {
490        #[key]
491        #[auto]
492        id: ID,
493
494        #[unique]
495        email: String,
496
497        #[has_one]
498        profile: toasty::HasOne<Option<Profile>>,
499    }
500
501    #[derive(Debug, toasty::Model)]
502    struct Profile {
503        #[key]
504        #[auto]
505        id: ID,
506
507        #[unique]
508        user_id: ID,
509
510        #[belongs_to(key = user_id, references = id)]
511        user: toasty::BelongsTo<User>,
512    }
513
514    let mut db = test.setup_db(models!(User, Profile)).await;
515
516    let user = User::create()
517        .email("foo@example.com")
518        .profile(Profile::create())
519        .exec(&mut db)
520        .await?;
521    let profile = user.profile().get(&mut db).await?.unwrap();
522    assert_eq!(profile.user_id, user.id);
523
524    User::filter_by_email(&user.email)
525        .update()
526        .profile(None)
527        .exec(&mut db)
528        .await?;
529
530    // Profile is deleted
531    assert_err!(Profile::get_by_id(&mut db, &profile.id).await);
532    Ok(())
533}
534
535#[driver_test(id(ID))]
536pub async fn associate_has_one_by_val_on_insert(test: &mut Test) -> Result<()> {
537    #[derive(Debug, toasty::Model)]
538    struct User {
539        #[key]
540        #[auto]
541        id: ID,
542
543        #[has_one]
544        profile: toasty::HasOne<Profile>,
545    }
546
547    #[derive(Debug, toasty::Model)]
548    struct Profile {
549        #[key]
550        #[auto]
551        id: ID,
552
553        #[unique]
554        user_id: Option<ID>,
555
556        #[belongs_to(key = user_id, references = id)]
557        user: toasty::BelongsTo<Option<User>>,
558
559        bio: String,
560    }
561
562    let mut db = test.setup_db(models!(User, Profile)).await;
563
564    // Create a profile
565    let profile = Profile::create().bio("hello world").exec(&mut db).await?;
566
567    // Create a user and associate the profile with it, by value
568    let u1 = User::create().profile(&profile).exec(&mut db).await?;
569
570    let profile_reloaded = u1.profile().get(&mut db).await?;
571    assert_eq!(profile.id, profile_reloaded.id);
572    assert_eq!(Some(&u1.id), profile_reloaded.user_id.as_ref());
573    assert_eq!(profile.bio, profile_reloaded.bio);
574    Ok(())
575}
576
577#[driver_test(id(ID))]
578#[ignore]
579pub async fn associate_has_one_by_val_on_update_query_with_filter(_test: &mut Test) {
580    /*
581    #[derive(Debug, toasty::Model)]
582    struct User {
583        #[key]
584        #[auto]
585        id: ID,
586
587        name: String,
588
589        #[has_one]
590        profile: toasty::HasOne<Option<Profile>>,
591    }
592
593    #[derive(Debug, toasty::Model)]
594    struct Profile {
595        #[key]
596        #[auto]
597        id: ID,
598
599        #[unique]
600        user_id: Option<ID>,
601
602        #[belongs_to(key = user_id, references = id)]
603        user: toasty::BelongsTo<Option<User>>,
604
605        bio: String,
606    }
607
608    let mut db = test.setup_db(models!(User, Profile)).await;
609
610    let u1 = User::create().name("user 1").exec(&mut db).await.unwrap();
611    let p1 = Profile::create()
612        .bio("hello world")
613        .exec(&mut db)
614        .await
615        .unwrap();
616
617    User::filter_by_id(&u1.id)
618        .update()
619        .profile(&p1)
620        .exec(&mut db)
621        .await
622        .unwrap();
623
624    let u1_reloaded = User::get_by_id(&mut db, &u1.id).await.unwrap();
625    let p1_reloaded = u1_reloaded.profile().get(&mut db).await.unwrap().unwrap();
626    assert_eq!(p1.id, p1_reloaded.id);
627    assert_eq!(p1.bio, p1_reloaded.bio);
628    assert_eq!(p1_reloaded.user_id.as_ref(), Some(&u1.id));
629
630    // Unset
631    User::filter_by_id(&u1.id)
632        .update()
633        .profile(None)
634        .exec(&mut db)
635        .await
636        .unwrap();
637
638    // Getting this to work will require a big chunk of work in the planner.
639    User::filter_by_id(&u1.id)
640        .filter(User::fields().name().eq("anon"))
641        .update()
642        .profile(&p1)
643        .exec(&mut db)
644        .await
645        .unwrap();
646    */
647}