toasty_driver_integration_suite/tests/
deferred_embed.rs1use crate::prelude::*;
2
3#[driver_test(scenario(crate::scenarios::document_deferred_metadata))]
6pub async fn deferred_embed_struct(t: &mut Test) -> Result<()> {
7 let mut db = setup(t).await;
8
9 let created = toasty::create!(Document {
10 title: "Hello".to_string(),
11 metadata: Metadata {
12 author: "Alice".to_string(),
13 notes: "Important".to_string(),
14 },
15 })
16 .exec(&mut db)
17 .await?;
18
19 assert_eq!("Hello", created.title);
22 assert_eq!("Alice", created.metadata.get().author);
23 assert_eq!("Important", created.metadata.get().notes);
24
25 let read = Document::filter_by_id(created.id).get(&mut db).await?;
27 assert_eq!("Hello", read.title);
28 assert!(read.metadata.is_unloaded());
29
30 let read_with = Document::filter_by_id(created.id)
32 .include(Document::fields().metadata())
33 .get(&mut db)
34 .await?;
35 assert!(!read_with.metadata.is_unloaded());
36 assert_eq!("Alice", read_with.metadata.get().author);
37 assert_eq!("Important", read_with.metadata.get().notes);
38
39 Ok(())
40}
41
42#[driver_test(scenario(crate::scenarios::person_contact_deferred_metadata))]
55pub async fn deferred_inside_embed_in_enum_variant(t: &mut Test) -> Result<()> {
56 let mut db = setup(t).await;
57
58 let created = toasty::create!(Person {
61 name: "Alice".to_string(),
62 contact: ContactInfo::Email {
63 address: "alice@example.com".to_string(),
64 metadata: Metadata {
65 author: "Alice".to_string(),
66 notes: "Important".to_string().into(),
67 },
68 },
69 })
70 .exec(&mut db)
71 .await?;
72
73 let ContactInfo::Email {
74 address, metadata, ..
75 } = &created.contact
76 else {
77 panic!("expected Email variant");
78 };
79 assert_eq!("alice@example.com", address);
80 assert_eq!("Alice", metadata.author);
81 assert_eq!("Important", metadata.notes.get());
82
83 let read = Person::filter_by_id(created.id).get(&mut db).await?;
86 let ContactInfo::Email { metadata, .. } = &read.contact else {
87 panic!("expected Email variant");
88 };
89 assert_eq!("Alice", metadata.author);
90 assert!(metadata.notes.is_unloaded());
91
92 Ok(())
93}
94
95#[driver_test(scenario(crate::scenarios::person_contact_deferred_metadata))]
102pub async fn include_deferred_inside_embed_in_enum_variant(t: &mut Test) -> Result<()> {
103 let mut db = setup(t).await;
104
105 let alice = toasty::create!(Person {
106 name: "Alice".to_string(),
107 contact: ContactInfo::Email {
108 address: "alice@example.com".to_string(),
109 metadata: Metadata {
110 author: "Alice".to_string(),
111 notes: "Important".to_string().into(),
112 },
113 },
114 })
115 .exec(&mut db)
116 .await?;
117
118 let bob = toasty::create!(Person {
121 name: "Bob".to_string(),
122 contact: ContactInfo::Phone {
123 number: "555-0100".to_string(),
124 },
125 })
126 .exec(&mut db)
127 .await?;
128
129 let alice_read = Person::filter_by_id(alice.id)
131 .include(Person::fields().contact().email().metadata().notes())
132 .get(&mut db)
133 .await?;
134 let ContactInfo::Email { metadata, .. } = &alice_read.contact else {
135 panic!("expected Email variant");
136 };
137 assert_eq!("Alice", metadata.author);
138 assert!(!metadata.notes.is_unloaded());
139 assert_eq!("Important", metadata.notes.get());
140
141 let bob_read = Person::filter_by_id(bob.id)
144 .include(Person::fields().contact().email().metadata().notes())
145 .get(&mut db)
146 .await?;
147 let ContactInfo::Phone { number } = &bob_read.contact else {
148 panic!("expected Phone variant");
149 };
150 assert_eq!("555-0100", number);
151
152 Ok(())
153}
154
155#[driver_test(scenario(crate::scenarios::person_contact_deferred_metadata))]
156pub async fn update_with_variant_rooted_include(t: &mut Test) -> Result<()> {
157 let mut db = setup(t).await;
158
159 for contact in [
160 ContactInfo::Email {
161 address: "alice@example.com".to_string(),
162 metadata: Metadata {
163 author: "Alice".to_string(),
164 notes: "Important".to_string().into(),
165 },
166 },
167 ContactInfo::Phone {
168 number: "555-0100".to_string(),
169 },
170 ] {
171 let person = toasty::create!(Person {
172 name: "before",
173 contact,
174 })
175 .exec(&mut db)
176 .await?;
177
178 Person::filter_by_id(person.id)
179 .include(Person::fields().contact().email().metadata().notes())
180 .update()
181 .name("updated")
182 .exec(&mut db)
183 .await?;
184
185 let read = Person::get_by_id(&mut db, person.id).await?;
186 assert_eq!(read.name, "updated");
187 }
188
189 Person::filter_by_id(uuid::Uuid::new_v4())
190 .include(Person::fields().contact().email().metadata().notes())
191 .update()
192 .name("updated")
193 .exec(&mut db)
194 .await?;
195
196 Ok(())
197}
198
199#[driver_test(
200 requires(not(native_ilike)),
201 scenario(crate::scenarios::person_contact_deferred_metadata)
202)]
203pub async fn update_with_variant_rooted_include_verifies_filter(t: &mut Test) -> Result<()> {
204 let mut db = setup(t).await;
205 t.log().clear();
206
207 let err = assert_err!(
208 Person::filter(Person::fields().name().ilike("alice"))
209 .include(Person::fields().contact().email().metadata().notes())
210 .update()
211 .name("updated")
212 .exec(&mut db)
213 .await
214 );
215 assert!(err.is_unsupported_feature());
216 assert!(t.log().is_empty());
217
218 Ok(())
219}
220
221#[driver_test]
224pub async fn deferred_embed_unit_enum(t: &mut Test) -> Result<()> {
225 #[derive(Debug, PartialEq, toasty::Embed)]
226 enum Status {
227 Draft,
228 Published,
229 Archived,
230 }
231
232 #[derive(Debug, toasty::Model)]
233 struct Document {
234 #[key]
235 #[auto]
236 id: uuid::Uuid,
237
238 title: String,
239 status: toasty::Deferred<Status>,
240 }
241
242 let mut db = t.setup_db(models!(Document)).await;
243
244 let created = toasty::create!(Document {
245 title: "Hello".to_string(),
246 status: Status::Published,
247 })
248 .exec(&mut db)
249 .await?;
250
251 assert_eq!(&Status::Published, created.status.get());
252
253 let read = Document::filter_by_id(created.id).get(&mut db).await?;
254 assert!(read.status.is_unloaded());
255
256 let inc = Document::filter_by_id(created.id)
257 .include(Document::fields().status())
258 .get(&mut db)
259 .await?;
260 assert!(!inc.status.is_unloaded());
261 assert_eq!(&Status::Published, inc.status.get());
262
263 Ok(())
264}
265
266#[driver_test]
269pub async fn deferred_embed_data_enum(t: &mut Test) -> Result<()> {
270 #[derive(Debug, PartialEq, toasty::Embed)]
271 enum ContactInfo {
272 Email { address: String },
273 Phone { number: String },
274 Mail,
275 }
276
277 #[derive(Debug, toasty::Model)]
278 struct Person {
279 #[key]
280 #[auto]
281 id: uuid::Uuid,
282
283 name: String,
284 contact: toasty::Deferred<ContactInfo>,
285 }
286
287 let mut db = t.setup_db(models!(Person)).await;
288
289 let alice = toasty::create!(Person {
290 name: "Alice".to_string(),
291 contact: ContactInfo::Email {
292 address: "alice@example.com".to_string(),
293 },
294 })
295 .exec(&mut db)
296 .await?;
297
298 let bob = toasty::create!(Person {
299 name: "Bob".to_string(),
300 contact: ContactInfo::Mail,
301 })
302 .exec(&mut db)
303 .await?;
304
305 assert_eq!(
306 &ContactInfo::Email {
307 address: "alice@example.com".to_string()
308 },
309 alice.contact.get()
310 );
311
312 let read = Person::filter_by_id(alice.id).get(&mut db).await?;
313 assert!(read.contact.is_unloaded());
314
315 let inc = Person::filter_by_id(alice.id)
316 .include(Person::fields().contact())
317 .get(&mut db)
318 .await?;
319 assert!(!inc.contact.is_unloaded());
320 assert_eq!(
321 &ContactInfo::Email {
322 address: "alice@example.com".to_string()
323 },
324 inc.contact.get()
325 );
326
327 let inc_bob = Person::filter_by_id(bob.id)
328 .include(Person::fields().contact())
329 .get(&mut db)
330 .await?;
331 assert_eq!(&ContactInfo::Mail, inc_bob.contact.get());
332
333 Ok(())
334}
335
336#[driver_test(scenario(crate::scenarios::document_deferred_metadata))]
339pub async fn deferred_embed_update_reloads(t: &mut Test) -> Result<()> {
340 let mut db = setup(t).await;
341
342 let created = toasty::create!(Document {
343 title: "Hello".to_string(),
344 metadata: Metadata {
345 author: "Alice".to_string(),
346 notes: "old".to_string(),
347 },
348 })
349 .exec(&mut db)
350 .await?;
351
352 let mut doc = Document::filter_by_id(created.id).get(&mut db).await?;
353 assert!(doc.metadata.is_unloaded());
354
355 doc.update()
356 .metadata(Metadata {
357 author: "Bob".to_string(),
358 notes: "new".to_string(),
359 })
360 .exec(&mut db)
361 .await?;
362
363 assert!(!doc.metadata.is_unloaded());
365 assert_eq!("Bob", doc.metadata.get().author);
366 assert_eq!("new", doc.metadata.get().notes);
367
368 Ok(())
369}
370
371#[driver_test]
379pub async fn deferred_embed_with_deferred_sub_field(t: &mut Test) -> Result<()> {
380 #[derive(Debug, toasty::Embed)]
381 struct Metadata {
382 author: String,
383 notes: toasty::Deferred<String>,
384 }
385
386 #[derive(Debug, toasty::Model)]
387 struct Document {
388 #[key]
389 #[auto]
390 id: uuid::Uuid,
391
392 title: String,
393 metadata: toasty::Deferred<Metadata>,
394 }
395
396 let mut db = t.setup_db(models!(Document)).await;
397
398 let created = toasty::create!(Document {
399 title: "Hello".to_string(),
400 metadata: Metadata {
401 author: "Alice".to_string(),
402 notes: "Important".to_string().into(),
403 },
404 })
405 .exec(&mut db)
406 .await?;
407
408 assert_eq!("Alice", created.metadata.get().author);
410 assert_eq!("Important", created.metadata.get().notes.get());
411
412 let read = Document::filter_by_id(created.id).get(&mut db).await?;
414 assert!(read.metadata.is_unloaded());
415
416 let inc_outer = Document::filter_by_id(created.id)
419 .include(Document::fields().metadata())
420 .get(&mut db)
421 .await?;
422 assert!(!inc_outer.metadata.is_unloaded());
423 assert_eq!("Alice", inc_outer.metadata.get().author);
424 assert!(inc_outer.metadata.get().notes.is_unloaded());
425
426 let inc_inner = Document::filter_by_id(created.id)
429 .include(Document::fields().metadata().notes())
430 .get(&mut db)
431 .await?;
432 assert!(!inc_inner.metadata.is_unloaded());
433 assert_eq!("Alice", inc_inner.metadata.get().author);
434 assert!(!inc_inner.metadata.get().notes.is_unloaded());
435 assert_eq!("Important", inc_inner.metadata.get().notes.get());
436
437 Ok(())
438}
439
440#[driver_test(scenario(crate::scenarios::document_metadata_deferred_notes))]
443pub async fn deferred_field_inside_embed(t: &mut Test) -> Result<()> {
444 let mut db = setup(t).await;
445
446 let created = toasty::create!(Document {
447 title: "Hello".to_string(),
448 metadata: Metadata {
449 author: "Alice".to_string(),
450 notes: "Important".to_string().into(),
451 },
452 })
453 .exec(&mut db)
454 .await?;
455
456 assert_eq!("Alice", created.metadata.author);
458 assert_eq!("Important", created.metadata.notes.get());
459
460 let read = Document::filter_by_id(created.id).get(&mut db).await?;
462 assert_eq!("Alice", read.metadata.author);
463 assert!(read.metadata.notes.is_unloaded());
464
465 let inc = Document::filter_by_id(created.id)
467 .include(Document::fields().metadata().notes())
468 .get(&mut db)
469 .await?;
470 assert!(!inc.metadata.notes.is_unloaded());
471 assert_eq!("Important", inc.metadata.notes.get());
472
473 Ok(())
474}
475
476#[driver_test(scenario(crate::scenarios::document_metadata_deferred_notes))]
482pub async fn update_embed_by_value_with_deferred_sub_field(t: &mut Test) -> Result<()> {
483 let mut db = setup(t).await;
484
485 let mut doc = toasty::create!(Document {
486 title: "Hello".to_string(),
487 metadata: Metadata {
488 author: "Alice".to_string(),
489 notes: "old".to_string().into(),
490 },
491 })
492 .exec(&mut db)
493 .await?;
494
495 doc.update()
496 .metadata(Metadata {
497 author: "Bob".to_string(),
498 notes: "new".to_string().into(),
499 })
500 .exec(&mut db)
501 .await?;
502
503 assert_eq!("Bob", doc.metadata.author);
505 assert_eq!("new", doc.metadata.notes.get());
506
507 let reread = Document::filter_by_id(doc.id)
510 .include(Document::fields().metadata().notes())
511 .get(&mut db)
512 .await?;
513 assert_eq!("Bob", reread.metadata.author);
514 assert_eq!("new", reread.metadata.notes.get());
515
516 Ok(())
517}
518
519#[driver_test(scenario(crate::scenarios::document_optional_metadata_deferred_notes))]
526pub async fn deferred_field_inside_option_embed(t: &mut Test) -> Result<()> {
527 let mut db = setup(t).await;
528
529 let created = toasty::create!(Document {
530 title: "Hello".to_string(),
531 metadata: Some(Metadata {
532 author: "Alice".to_string(),
533 notes: "Important".to_string().into(),
534 }),
535 })
536 .exec(&mut db)
537 .await?;
538
539 let md = created.metadata.as_ref().expect("Some");
541 assert_eq!("Alice", md.author);
542 assert_eq!("Important", md.notes.get());
543
544 let read = Document::filter_by_id(created.id).get(&mut db).await?;
546 let md = read.metadata.as_ref().expect("Some");
547 assert_eq!("Alice", md.author);
548 assert!(md.notes.is_unloaded());
549
550 let empty = toasty::create!(Document {
552 title: "Empty".to_string(),
553 metadata: None,
554 })
555 .exec(&mut db)
556 .await?;
557 assert!(empty.metadata.is_none());
558
559 Ok(())
560}
561
562#[driver_test(scenario(crate::scenarios::document_optional_body_deferred))]
569pub async fn deferred_newtype_inside_option_embed(t: &mut Test) -> Result<()> {
570 let mut db = setup(t).await;
571
572 let created = toasty::create!(Document {
573 title: "Hello".to_string(),
574 body: Some(Body("Important".to_string().into())),
575 })
576 .exec(&mut db)
577 .await?;
578
579 let body = created.body.as_ref().expect("Some");
581 assert_eq!("Important", body.0.get());
582
583 let read = Document::filter_by_id(created.id).get(&mut db).await?;
585 let body = read.body.as_ref().expect("Some");
586 assert!(body.0.is_unloaded());
587
588 let empty = toasty::create!(Document {
590 title: "Empty".to_string(),
591 body: None,
592 })
593 .exec(&mut db)
594 .await?;
595 assert!(empty.body.is_none());
596
597 Ok(())
598}