toasty_driver_integration_suite/tests/
crud_create_macro.rs

1use crate::prelude::*;
2
3#[driver_test(id(ID), scenario(crate::scenarios::two_models))]
4pub async fn create_macro_simple(test: &mut Test) -> Result<()> {
5    let mut db = setup(test).await;
6
7    // Create using the macro — translates to: User::create().name("Carl")
8    let user = toasty::create!(User { name: "Carl" }).exec(&mut db).await?;
9
10    assert_eq!(user.name, "Carl");
11
12    // Verify it persisted
13    let reloaded = User::get_by_id(&mut db, &user.id).await?;
14    assert_eq!(reloaded.name, "Carl");
15
16    Ok(())
17}
18
19#[driver_test(id(ID))]
20pub async fn create_macro_multiple_fields(test: &mut Test) -> Result<()> {
21    #[derive(Debug, toasty::Model)]
22    struct User {
23        #[key]
24        #[auto]
25        id: ID,
26
27        name: String,
28        email: String,
29    }
30
31    let mut db = test.setup_db(models!(User)).await;
32
33    // Create with multiple fields
34    let user = toasty::create!(User {
35        name: "Carl",
36        email: "carl@example.com"
37    })
38    .exec(&mut db)
39    .await?;
40
41    assert_eq!(user.name, "Carl");
42    assert_eq!(user.email, "carl@example.com");
43
44    Ok(())
45}
46
47#[driver_test(id(ID), scenario(crate::scenarios::two_models))]
48pub async fn create_macro_with_variable(test: &mut Test) -> Result<()> {
49    let mut db = setup(test).await;
50
51    let name = "Carl";
52
53    // Explicit `name: name` — field and variable have the same identifier
54    let user = toasty::create!(User { name: name }).exec(&mut db).await?;
55
56    assert_eq!(user.name, "Carl");
57
58    Ok(())
59}
60
61#[driver_test(id(ID), scenario(crate::scenarios::two_models))]
62pub async fn create_macro_with_different_variable(test: &mut Test) -> Result<()> {
63    let mut db = setup(test).await;
64
65    let user_name = "Carl";
66
67    // Explicit `name: expr` where the expression differs from the field name
68    let user = toasty::create!(User { name: user_name })
69        .exec(&mut db)
70        .await?;
71
72    assert_eq!(user.name, "Carl");
73
74    Ok(())
75}
76
77#[driver_test(id(ID), scenario(crate::scenarios::has_many_belongs_to))]
78pub async fn create_macro_scoped(test: &mut Test) -> Result<()> {
79    let mut db = setup(test).await;
80
81    let user = User::create().name("Alice").exec(&mut db).await?;
82
83    // Scoped create — translates to: user.todos().create().title("get something done")
84    let todo = toasty::create!(in user.todos() { title: "get something done" })
85        .exec(&mut db)
86        .await?;
87
88    assert_eq!(todo.title, "get something done");
89    assert_eq!(todo.user_id, user.id);
90
91    Ok(())
92}
93
94#[driver_test(id(ID), scenario(crate::scenarios::two_models))]
95pub async fn create_macro_batch(test: &mut Test) -> Result<()> {
96    let mut db = setup(test).await;
97
98    // Same-type batch — expands to toasty::batch([...]), returns Vec<User>
99    let users = toasty::create!(User::[
100        { name: "Carl" },
101        { name: "Bob" },
102    ])
103    .exec(&mut db)
104    .await?;
105
106    assert_struct!(users, [{ name: "Carl" }, { name: "Bob" }]);
107
108    Ok(())
109}
110
111#[driver_test(id(ID), requires(sql), scenario(crate::scenarios::two_models))]
112pub async fn create_macro_tuple(test: &mut Test) -> Result<()> {
113    let mut db = setup(test).await;
114
115    // Tuple syntax — returns (User, Post)
116    let (user, post) = toasty::create!((User { name: "Carl" }, Post { title: "Hello" },))
117        .exec(&mut db)
118        .await?;
119
120    assert_struct!(user, { name: "Carl" });
121    assert_struct!(post, { title: "Hello" });
122
123    Ok(())
124}
125
126#[driver_test(id(ID), requires(sql), scenario(crate::scenarios::two_models))]
127pub async fn create_macro_tuple_mixed(test: &mut Test) -> Result<()> {
128    let mut db = setup(test).await;
129
130    // Mixed tuple: typed batch + single create — returns (Vec<User>, Post)
131    let (users, post) = toasty::create!((
132        User::[ { name: "Carl" }, { name: "Bob" } ],
133        Post { title: "Hello" },
134    ))
135    .exec(&mut db)
136    .await?;
137
138    assert_struct!(users, [{ name: "Carl" }, { name: "Bob" }]);
139    assert_struct!(post, { title: "Hello" });
140
141    Ok(())
142}
143
144#[driver_test(id(ID), scenario(crate::scenarios::has_many_belongs_to))]
145pub async fn create_macro_nested_association(test: &mut Test) -> Result<()> {
146    let mut db = setup(test).await;
147
148    // Nested association — no type prefix needed; type inferred from field.
149    let user = toasty::create!(User {
150        name: "Carl",
151        todos: [{ title: "get something done" }]
152    })
153    .exec(&mut db)
154    .await?;
155
156    assert_eq!(user.name, "Carl");
157
158    let todos: Vec<_> = user.todos().exec(&mut db).await?;
159    assert_eq!(todos.len(), 1);
160    assert_eq!(todos[0].title, "get something done");
161
162    Ok(())
163}
164
165#[driver_test(id(ID), scenario(crate::scenarios::has_many_belongs_to))]
166pub async fn create_macro_nested_multiple(test: &mut Test) -> Result<()> {
167    let mut db = setup(test).await;
168
169    // Multiple nested associations
170    let user = toasty::create!(User {
171        name: "Carl",
172        todos: [{ title: "first" }, { title: "second" }]
173    })
174    .exec(&mut db)
175    .await?;
176
177    assert_eq!(user.name, "Carl");
178
179    let mut todos: Vec<_> = user.todos().exec(&mut db).await?;
180    assert_eq!(todos.len(), 2);
181
182    todos.sort_by(|a, b| a.title.cmp(&b.title));
183    assert_eq!(todos[0].title, "first");
184    assert_eq!(todos[1].title, "second");
185
186    Ok(())
187}
188
189#[driver_test(id(ID), scenario(crate::scenarios::has_many_belongs_to))]
190pub async fn create_macro_with_belongs_to(test: &mut Test) -> Result<()> {
191    let mut db = setup(test).await;
192
193    // Create a todo with an inline belongs_to user
194    let todo = toasty::create!(Todo {
195        title: "buy milk",
196        user: { name: "Carl" }
197    })
198    .exec(&mut db)
199    .await?;
200
201    assert_eq!(todo.title, "buy milk");
202
203    // The user should have been created inline
204    let user = User::get_by_id(&mut db, &todo.user_id).await?;
205    assert_eq!(user.name, "Carl");
206
207    Ok(())
208}
209
210#[driver_test(id(ID))]
211pub async fn create_macro_deeply_nested(test: &mut Test) -> Result<()> {
212    #[derive(Debug, toasty::Model)]
213    struct User {
214        #[key]
215        #[auto]
216        id: ID,
217
218        name: String,
219
220        #[has_many]
221        todos: toasty::HasMany<Todo>,
222    }
223
224    #[derive(Debug, toasty::Model)]
225    struct Todo {
226        #[key]
227        #[auto]
228        id: ID,
229
230        #[index]
231        user_id: ID,
232
233        #[belongs_to(key = user_id, references = id)]
234        user: toasty::BelongsTo<User>,
235
236        title: String,
237
238        #[has_many]
239        tags: toasty::HasMany<Tag>,
240    }
241
242    #[derive(Debug, toasty::Model)]
243    struct Tag {
244        #[key]
245        #[auto]
246        id: ID,
247
248        #[index]
249        todo_id: ID,
250
251        #[belongs_to(key = todo_id, references = id)]
252        todo: toasty::BelongsTo<Todo>,
253
254        name: String,
255    }
256
257    let mut db = test.setup_db(models!(User, Todo, Tag)).await;
258
259    // Three levels deep: User → Todo → Tag
260    let user = toasty::create!(User {
261        name: "Carl",
262        todos: [{
263            title: "get something done",
264            tags: [{ name: "urgent" }, { name: "work" }]
265        }]
266    })
267    .exec(&mut db)
268    .await?;
269
270    assert_eq!(user.name, "Carl");
271
272    let todos: Vec<_> = user.todos().exec(&mut db).await?;
273    assert_eq!(todos.len(), 1);
274    assert_eq!(todos[0].title, "get something done");
275
276    let mut tags: Vec<_> = todos[0].tags().exec(&mut db).await?;
277    tags.sort_by(|a, b| a.name.cmp(&b.name));
278    assert_eq!(tags.len(), 2);
279    assert_eq!(tags[0].name, "urgent");
280    assert_eq!(tags[1].name, "work");
281
282    Ok(())
283}
284
285#[driver_test(id(ID), scenario(crate::scenarios::two_models))]
286pub async fn create_macro_field_shorthand(test: &mut Test) -> Result<()> {
287    let mut db = setup(test).await;
288
289    let name = "Carl".to_string();
290
291    // Field shorthand — `name` is equivalent to `name: name`
292    let user = toasty::create!(User { name }).exec(&mut db).await?;
293
294    assert_eq!(user.name, "Carl");
295
296    Ok(())
297}
298
299#[driver_test(id(ID))]
300pub async fn create_macro_field_shorthand_multiple(test: &mut Test) -> Result<()> {
301    #[derive(Debug, toasty::Model)]
302    struct User {
303        #[key]
304        #[auto]
305        id: ID,
306
307        name: String,
308        email: String,
309    }
310
311    let mut db = test.setup_db(models!(User)).await;
312
313    let name = "Carl".to_string();
314    let email = "carl@example.com".to_string();
315
316    // Multiple shorthand fields
317    let user = toasty::create!(User { name, email }).exec(&mut db).await?;
318
319    assert_eq!(user.name, "Carl");
320    assert_eq!(user.email, "carl@example.com");
321
322    Ok(())
323}
324
325#[driver_test(id(ID))]
326pub async fn create_macro_field_shorthand_mixed(test: &mut Test) -> Result<()> {
327    #[derive(Debug, toasty::Model)]
328    struct User {
329        #[key]
330        #[auto]
331        id: ID,
332
333        name: String,
334        email: String,
335    }
336
337    let mut db = test.setup_db(models!(User)).await;
338
339    let name = "Carl".to_string();
340
341    // Mix shorthand and explicit fields
342    let user = toasty::create!(User {
343        name,
344        email: "carl@example.com"
345    })
346    .exec(&mut db)
347    .await?;
348
349    assert_eq!(user.name, "Carl");
350    assert_eq!(user.email, "carl@example.com");
351
352    Ok(())
353}
354
355#[driver_test(id(ID), scenario(crate::scenarios::has_many_belongs_to))]
356pub async fn create_macro_field_shorthand_scoped(test: &mut Test) -> Result<()> {
357    let mut db = setup(test).await;
358
359    let user = User::create().name("Alice").exec(&mut db).await?;
360
361    let title = "get something done".to_string();
362
363    // Shorthand in scoped create
364    let todo = toasty::create!(in user.todos() { title })
365        .exec(&mut db)
366        .await?;
367
368    assert_eq!(todo.title, "get something done");
369    assert_eq!(todo.user_id, user.id);
370
371    Ok(())
372}
373
374#[driver_test(id(ID), scenario(crate::scenarios::two_models))]
375pub async fn create_macro_field_shorthand_batch(test: &mut Test) -> Result<()> {
376    let mut db = setup(test).await;
377
378    let name = "Carl".to_string();
379
380    // Shorthand in batch create
381    let users = toasty::create!(User::[
382        { name },
383        { name: "Bob" },
384    ])
385    .exec(&mut db)
386    .await?;
387
388    assert_struct!(users, [{ name: "Carl" }, { name: "Bob" }]);
389
390    Ok(())
391}