toasty_driver_integration_suite/tests/
embed_relation.rs1use crate::prelude::*;
2
3#[driver_test]
11pub async fn belongs_to_in_enum_variants(test: &mut Test) -> Result<()> {
12 #[derive(Debug, toasty::Model)]
13 struct Human {
14 #[key]
15 #[auto]
16 id: uuid::Uuid,
17 name: String,
18 }
19
20 #[derive(Debug, toasty::Model)]
21 struct Bot {
22 #[key]
23 #[auto]
24 id: uuid::Uuid,
25 #[unique]
26 serial: String,
27 name: String,
28 }
29
30 #[derive(Debug, toasty::Embed)]
31 enum Owner {
32 Human {
33 #[index]
34 id: uuid::Uuid,
35 #[belongs_to(key = id)]
36 human: toasty::Deferred<Human>,
37 },
38 Bot {
39 #[index]
40 serial: String,
41 #[belongs_to(key = serial, references = serial)]
42 bot: toasty::Deferred<Bot>,
43 },
44 }
45
46 #[derive(Debug, toasty::Model)]
47 struct Object {
48 #[key]
49 #[auto]
50 id: uuid::Uuid,
51 owner: Owner,
52 }
53
54 let mut db = test.setup_db(models!(Object, Human, Bot)).await;
55
56 let table = &db.schema().db.tables[0];
59 let names: Vec<_> = table.columns.iter().map(|c| c.name.as_str()).collect();
60 assert_eq!(names, ["id", "owner", "owner_id", "owner_serial"]);
61
62 let alice = toasty::create!(Human { name: "Alice" })
63 .exec(&mut db)
64 .await?;
65 let bot = toasty::create!(Bot {
66 serial: "B-1000",
67 name: "Marvin"
68 })
69 .exec(&mut db)
70 .await?;
71
72 let obj_a = toasty::create!(Object {
74 owner: Owner::Human {
75 id: alice.id,
76 human: toasty::Deferred::default(),
77 }
78 })
79 .exec(&mut db)
80 .await?;
81 let obj_b = toasty::create!(Object {
82 owner: Owner::Bot {
83 serial: bot.serial.clone(),
84 bot: toasty::Deferred::default(),
85 }
86 })
87 .exec(&mut db)
88 .await?;
89
90 let mut obj_a = Object::get_by_id(&mut db, obj_a.id).await?;
93 match &obj_a.owner {
94 Owner::Human { id, human } => {
95 assert!(human.is_unloaded());
96 let human = Human::get_by_id(&mut db, id).await?;
97 assert_eq!(human.name, "Alice");
98 }
99 other => panic!("expected Owner::Human, got {other:?}"),
100 }
101
102 let obj_b = Object::get_by_id(&mut db, obj_b.id).await?;
103 match &obj_b.owner {
104 Owner::Bot { serial, bot } => {
105 assert!(bot.is_unloaded());
106 let bot = Bot::get_by_serial(&mut db, serial).await?;
107 assert_eq!(bot.name, "Marvin");
108 }
109 other => panic!("expected Owner::Bot, got {other:?}"),
110 }
111
112 obj_a
115 .update()
116 .owner(Owner::Bot {
117 serial: bot.serial.clone(),
118 bot: toasty::Deferred::default(),
119 })
120 .exec(&mut db)
121 .await?;
122 let reloaded = Object::get_by_id(&mut db, obj_a.id).await?;
123 assert_struct!(
124 reloaded.owner,
125 Owner::Bot {
126 serial: "B-1000",
127 ..
128 }
129 );
130
131 let obj_a_id = obj_a.id;
132 obj_a.delete().exec(&mut db).await?;
133 assert_err!(Object::get_by_id(&mut db, obj_a_id).await);
134 assert!(matches!(
135 Object::get_by_id(&mut db, obj_b.id).await?.owner,
136 Owner::Bot { .. }
137 ));
138
139 Ok(())
140}
141
142#[driver_test]
147pub async fn filter_by_relation_key_through_variant_path(test: &mut Test) -> Result<()> {
148 #[derive(Debug, toasty::Model)]
149 struct Human {
150 #[key]
151 #[auto]
152 id: uuid::Uuid,
153 name: String,
154 }
155
156 #[derive(Debug, toasty::Model)]
157 struct Animal {
158 #[key]
159 #[auto]
160 id: uuid::Uuid,
161 name: String,
162 }
163
164 #[derive(Debug, toasty::Embed)]
167 #[index(id)]
168 enum Owner {
169 Human {
170 #[shared(id)]
171 id: uuid::Uuid,
172 #[belongs_to(key = id)]
173 human: toasty::Deferred<Human>,
174 },
175 Animal {
176 #[shared(id)]
177 id: uuid::Uuid,
178 #[belongs_to(key = id)]
179 animal: toasty::Deferred<Animal>,
180 },
181 }
182
183 #[derive(Debug, toasty::Model)]
184 struct Object {
185 #[key]
186 #[auto]
187 id: uuid::Uuid,
188 owner: Owner,
189 }
190
191 let mut db = test.setup_db(models!(Object, Human, Animal)).await;
192
193 let table = &db.schema().db.tables[0];
195 let names: Vec<_> = table.columns.iter().map(|c| c.name.as_str()).collect();
196 assert_eq!(names, ["id", "owner", "owner_id"]);
197 let key_col = columns(&db, "objects", &["owner_id"])[0];
198 assert_struct!(table.indices, [
199 { primary_key: true },
200 { unique: false, primary_key: false, columns: [{ column: == key_col }] },
201 ]);
202
203 let alice = toasty::create!(Human { name: "Alice" })
204 .exec(&mut db)
205 .await?;
206 let rex = toasty::create!(Animal { name: "Rex" })
208 .exec(&mut db)
209 .await?;
210
211 let mut human_obj = toasty::create!(Object {
212 owner: Owner::Human {
213 id: alice.id,
214 human: toasty::Deferred::default(),
215 }
216 })
217 .exec(&mut db)
218 .await?;
219 toasty::create!(Object {
220 owner: Owner::Animal {
221 id: rex.id,
222 animal: toasty::Deferred::default(),
223 }
224 })
225 .exec(&mut db)
226 .await?;
227
228 let by_key = |id: uuid::Uuid| {
231 Object::fields()
232 .owner()
233 .human()
234 .matches(move |h| h.id().eq(id))
235 };
236 let found: Vec<Object> = Object::filter(by_key(alice.id)).exec(&mut db).await?;
237 assert_eq!(found.len(), 1);
238 assert_eq!(found[0].id, human_obj.id);
239
240 let humans: Vec<Object> = Object::filter(Object::fields().owner().is_human())
242 .exec(&mut db)
243 .await?;
244 assert_eq!(humans.len(), 1);
245 assert_eq!(humans[0].id, human_obj.id);
246
247 let bea = toasty::create!(Human { name: "Bea" }).exec(&mut db).await?;
250 human_obj
251 .update()
252 .owner(Owner::Human {
253 id: bea.id,
254 human: toasty::Deferred::default(),
255 })
256 .exec(&mut db)
257 .await?;
258 assert!(
259 Object::filter(by_key(alice.id))
260 .exec(&mut db)
261 .await?
262 .is_empty()
263 );
264 let found: Vec<Object> = Object::filter(by_key(bea.id)).exec(&mut db).await?;
265 assert_eq!(found.len(), 1);
266 assert_eq!(found[0].id, human_obj.id);
267
268 human_obj.delete().exec(&mut db).await?;
270 assert!(
271 Object::filter(by_key(bea.id))
272 .exec(&mut db)
273 .await?
274 .is_empty()
275 );
276 let animals: Vec<Object> = Object::filter(Object::fields().owner().is_animal())
277 .exec(&mut db)
278 .await?;
279 assert_eq!(animals.len(), 1);
280
281 Ok(())
282}
283
284#[driver_test]
288pub async fn belongs_to_in_embedded_struct(test: &mut Test) -> Result<()> {
289 #[derive(Debug, toasty::Model)]
290 struct Author {
291 #[key]
292 #[auto]
293 id: uuid::Uuid,
294 name: String,
295 }
296
297 #[derive(Debug, toasty::Embed)]
298 struct Attribution {
299 #[index]
300 author_id: uuid::Uuid,
301 #[belongs_to(key = author_id)]
302 author: toasty::Deferred<Author>,
303 note: String,
304 }
305
306 #[derive(Debug, toasty::Model)]
307 struct Post {
308 #[key]
309 #[auto]
310 id: uuid::Uuid,
311 attribution: Attribution,
312 }
313
314 let mut db = test.setup_db(models!(Post, Author)).await;
315
316 let table = &db.schema().db.tables[0];
317 let names: Vec<_> = table.columns.iter().map(|c| c.name.as_str()).collect();
318 assert_eq!(names, ["id", "attribution_author_id", "attribution_note"]);
319
320 let author = toasty::create!(Author { name: "Ann" })
321 .exec(&mut db)
322 .await?;
323
324 let post = toasty::create!(Post {
325 attribution: Attribution {
326 author_id: author.id,
327 author: toasty::Deferred::default(),
328 note: "first draft".to_string(),
329 }
330 })
331 .exec(&mut db)
332 .await?;
333
334 let mut post = Post::get_by_id(&mut db, post.id).await?;
335 assert!(post.attribution.author.is_unloaded());
336 assert_eq!(post.attribution.note, "first draft");
337 let author = Author::get_by_id(&mut db, &post.attribution.author_id).await?;
338 assert_eq!(author.name, "Ann");
339
340 let found: Vec<Post> = Post::filter(
342 Post::fields()
343 .attribution()
344 .author_id()
345 .eq(post.attribution.author_id),
346 )
347 .exec(&mut db)
348 .await?;
349 assert_eq!(found.len(), 1);
350
351 let other = toasty::create!(Author { name: "Bea" })
353 .exec(&mut db)
354 .await?;
355 post.update()
356 .attribution(toasty::stmt::patch(
357 Attribution::fields().author_id(),
358 other.id,
359 ))
360 .exec(&mut db)
361 .await?;
362 assert_eq!(post.attribution.author_id, other.id);
363 assert_eq!(
364 Post::get_by_id(&mut db, post.id)
365 .await?
366 .attribution
367 .author_id,
368 other.id
369 );
370
371 let post_id = post.id;
372 post.delete().exec(&mut db).await?;
373 assert_err!(Post::get_by_id(&mut db, post_id).await);
374
375 Ok(())
376}
377
378#[driver_test]
382pub async fn optional_relation_carrying_embed(test: &mut Test) -> Result<()> {
383 #[derive(Debug, toasty::Model)]
384 struct Human {
385 #[key]
386 #[auto]
387 id: uuid::Uuid,
388 }
389
390 #[derive(Debug, toasty::Embed)]
391 enum Owner {
392 Human {
393 #[index]
394 id: uuid::Uuid,
395 #[belongs_to(key = id)]
396 human: toasty::Deferred<Human>,
397 },
398 }
399
400 #[derive(Debug, toasty::Model)]
401 struct Object {
402 #[key]
403 #[auto]
404 id: uuid::Uuid,
405 owner: Option<Owner>,
406 }
407
408 let mut db = test.setup_db(models!(Object, Human)).await;
409
410 let orphan = toasty::create!(Object { owner: None })
411 .exec(&mut db)
412 .await?;
413
414 let human = toasty::create!(Human {}).exec(&mut db).await?;
415 let owned = toasty::create!(Object {
416 owner: Some(Owner::Human {
417 id: human.id,
418 human: toasty::Deferred::default(),
419 })
420 })
421 .exec(&mut db)
422 .await?;
423
424 let mut orphan = Object::get_by_id(&mut db, orphan.id).await?;
425 assert!(orphan.owner.is_none());
426
427 let mut owned = Object::get_by_id(&mut db, owned.id).await?;
428 match &owned.owner {
429 Some(Owner::Human { id, human: rel }) => {
430 assert_eq!(*id, human.id);
431 assert!(rel.is_unloaded());
432 }
433 other => panic!("expected Some(Owner::Human), got {other:?}"),
434 }
435
436 orphan
438 .update()
439 .owner(Some(Owner::Human {
440 id: human.id,
441 human: toasty::Deferred::default(),
442 }))
443 .exec(&mut db)
444 .await?;
445 assert!(matches!(
446 Object::get_by_id(&mut db, orphan.id).await?.owner,
447 Some(Owner::Human { .. })
448 ));
449
450 owned.update().owner(None).exec(&mut db).await?;
451 assert!(Object::get_by_id(&mut db, owned.id).await?.owner.is_none());
452
453 Ok(())
454}