toasty_driver_integration_suite/tests/
create_macro.rs

1use crate::prelude::*;
2
3#[driver_test(id(ID))]
4pub async fn create_macro_simple(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
14    let mut db = test.setup_db(models!(User)).await;
15
16    // Create using the macro — translates to: User::create().name("Carl")
17    let user = toasty::create!(User { name: "Carl" }).exec(&mut db).await?;
18
19    assert_eq!(user.name, "Carl");
20
21    // Verify it persisted
22    let reloaded = User::get_by_id(&mut db, &user.id).await?;
23    assert_eq!(reloaded.name, "Carl");
24
25    Ok(())
26}
27
28#[driver_test(id(ID))]
29pub async fn create_macro_multiple_fields(test: &mut Test) -> Result<()> {
30    #[derive(Debug, toasty::Model)]
31    struct User {
32        #[key]
33        #[auto]
34        id: ID,
35
36        name: String,
37        email: String,
38    }
39
40    let mut db = test.setup_db(models!(User)).await;
41
42    // Create with multiple fields
43    let user = toasty::create!(User {
44        name: "Carl",
45        email: "carl@example.com"
46    })
47    .exec(&mut db)
48    .await?;
49
50    assert_eq!(user.name, "Carl");
51    assert_eq!(user.email, "carl@example.com");
52
53    Ok(())
54}
55
56#[driver_test(id(ID))]
57pub async fn create_macro_with_variable(test: &mut Test) -> Result<()> {
58    #[derive(Debug, toasty::Model)]
59    struct User {
60        #[key]
61        #[auto]
62        id: ID,
63
64        name: String,
65    }
66
67    let mut db = test.setup_db(models!(User)).await;
68
69    let name = "Carl";
70
71    // Value can be a variable expression
72    let user = toasty::create!(User { name: name }).exec(&mut db).await?;
73
74    assert_eq!(user.name, "Carl");
75
76    Ok(())
77}
78
79#[driver_test(id(ID), scenario(crate::scenarios::has_many_belongs_to))]
80pub async fn create_macro_scoped(test: &mut Test) -> Result<()> {
81    let mut db = setup(test).await;
82
83    let user = User::create().name("Alice").exec(&mut db).await?;
84
85    // Scoped create — translates to: user.todos().create().title("get something done")
86    let todo = toasty::create!(in user.todos() { title: "get something done" })
87        .exec(&mut db)
88        .await?;
89
90    assert_eq!(todo.title, "get something done");
91    assert_eq!(todo.user_id, user.id);
92
93    Ok(())
94}
95
96#[driver_test(id(ID))]
97pub async fn create_macro_batch(test: &mut Test) -> Result<()> {
98    #[derive(Debug, toasty::Model)]
99    struct User {
100        #[key]
101        #[auto]
102        id: ID,
103
104        name: String,
105    }
106
107    let mut db = test.setup_db(models!(User)).await;
108
109    // Same-type batch — produces a tuple of builders, composed via toasty::batch()
110    let (carl, bob) = toasty::batch(toasty::create!(User::[
111        { name: "Carl" },
112        { name: "Bob" },
113    ]))
114    .exec(&mut db)
115    .await?;
116
117    assert_eq!(carl.name, "Carl");
118    assert_eq!(bob.name, "Bob");
119
120    Ok(())
121}
122
123#[driver_test(id(ID), scenario(crate::scenarios::has_many_belongs_to))]
124pub async fn create_macro_nested_association(test: &mut Test) -> Result<()> {
125    let mut db = setup(test).await;
126
127    // Nested association — no type prefix needed; type inferred from field.
128    let user = toasty::create!(User {
129        name: "Carl",
130        todos: [{ title: "get something done" }]
131    })
132    .exec(&mut db)
133    .await?;
134
135    assert_eq!(user.name, "Carl");
136
137    let todos: Vec<_> = user.todos().exec(&mut db).await?;
138    assert_eq!(todos.len(), 1);
139    assert_eq!(todos[0].title, "get something done");
140
141    Ok(())
142}
143
144#[driver_test(id(ID), scenario(crate::scenarios::has_many_belongs_to))]
145pub async fn create_macro_nested_multiple(test: &mut Test) -> Result<()> {
146    let mut db = setup(test).await;
147
148    // Multiple nested associations
149    let user = toasty::create!(User {
150        name: "Carl",
151        todos: [{ title: "first" }, { title: "second" }]
152    })
153    .exec(&mut db)
154    .await?;
155
156    assert_eq!(user.name, "Carl");
157
158    let mut todos: Vec<_> = user.todos().exec(&mut db).await?;
159    assert_eq!(todos.len(), 2);
160
161    todos.sort_by(|a, b| a.title.cmp(&b.title));
162    assert_eq!(todos[0].title, "first");
163    assert_eq!(todos[1].title, "second");
164
165    Ok(())
166}
167
168#[driver_test(id(ID), scenario(crate::scenarios::has_many_belongs_to))]
169pub async fn create_macro_with_belongs_to(test: &mut Test) -> Result<()> {
170    let mut db = setup(test).await;
171
172    // Create a todo with an inline belongs_to user
173    let todo = toasty::create!(Todo {
174        title: "buy milk",
175        user: { name: "Carl" }
176    })
177    .exec(&mut db)
178    .await?;
179
180    assert_eq!(todo.title, "buy milk");
181
182    // The user should have been created inline
183    let user = User::get_by_id(&mut db, &todo.user_id).await?;
184    assert_eq!(user.name, "Carl");
185
186    Ok(())
187}
188
189#[driver_test(id(ID))]
190pub async fn create_macro_deeply_nested(test: &mut Test) -> Result<()> {
191    #[derive(Debug, toasty::Model)]
192    struct User {
193        #[key]
194        #[auto]
195        id: ID,
196
197        name: String,
198
199        #[has_many]
200        todos: toasty::HasMany<Todo>,
201    }
202
203    #[derive(Debug, toasty::Model)]
204    struct Todo {
205        #[key]
206        #[auto]
207        id: ID,
208
209        #[index]
210        user_id: ID,
211
212        #[belongs_to(key = user_id, references = id)]
213        user: toasty::BelongsTo<User>,
214
215        title: String,
216
217        #[has_many]
218        tags: toasty::HasMany<Tag>,
219    }
220
221    #[derive(Debug, toasty::Model)]
222    struct Tag {
223        #[key]
224        #[auto]
225        id: ID,
226
227        #[index]
228        todo_id: ID,
229
230        #[belongs_to(key = todo_id, references = id)]
231        todo: toasty::BelongsTo<Todo>,
232
233        name: String,
234    }
235
236    let mut db = test.setup_db(models!(User, Todo, Tag)).await;
237
238    // Three levels deep: User → Todo → Tag
239    let user = toasty::create!(User {
240        name: "Carl",
241        todos: [{
242            title: "get something done",
243            tags: [{ name: "urgent" }, { name: "work" }]
244        }]
245    })
246    .exec(&mut db)
247    .await?;
248
249    assert_eq!(user.name, "Carl");
250
251    let todos: Vec<_> = user.todos().exec(&mut db).await?;
252    assert_eq!(todos.len(), 1);
253    assert_eq!(todos[0].title, "get something done");
254
255    let mut tags: Vec<_> = todos[0].tags().exec(&mut db).await?;
256    tags.sort_by(|a, b| a.name.cmp(&b.name));
257    assert_eq!(tags.len(), 2);
258    assert_eq!(tags[0].name, "urgent");
259    assert_eq!(tags[1].name, "work");
260
261    Ok(())
262}