Skip to main content

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