toasty_driver_integration_suite/tests/
embed_enum_unit.rs1use toasty::schema::{
2 app::FieldTy,
3 mapping::{self, FieldEnum, FieldPrimitive},
4};
5
6use crate::{helpers::column, prelude::*};
7
8use toasty_core::{
9 driver::Operation,
10 stmt::{Assignment, BinaryOp, Expr, ExprSet, Statement},
11};
12
13#[driver_test(id(ID))]
19pub async fn create_and_query_enum(t: &mut Test) -> Result<()> {
20 #[derive(Debug, PartialEq, toasty::Embed)]
21 enum Status {
22 #[column(variant = 1)]
23 Pending,
24 #[column(variant = 2)]
25 Active,
26 #[column(variant = 3)]
27 Done,
28 }
29
30 #[derive(Debug, toasty::Model)]
31 struct User {
32 #[key]
33 #[auto]
34 id: ID,
35 name: String,
36 status: Status,
37 }
38
39 let mut db = t.setup_db(models!(User, Status)).await;
40 let user_table = table_id(&db, "users");
41
42 t.log().clear();
44
45 let mut user = User::create()
46 .name("Alice")
47 .status(Status::Pending)
48 .exec(&mut db)
49 .await?;
50
51 assert_struct!(t.log().pop_op(), Operation::QuerySql({
53 stmt: Statement::Insert({
54 source.body: ExprSet::Values({
55 rows: [== (Any, Any, 1i64)],
56 }),
57 target: toasty_core::stmt::InsertTarget::Table({
58 table: == user_table,
59 columns: == columns(&db, "users", &["id", "name", "status"]),
60 }),
61 }),
62 }));
63
64 let found = User::get_by_id(&mut db, &user.id).await?;
66 assert_eq!(found.status, Status::Pending);
67
68 t.log().clear();
70 user.update().status(Status::Active).exec(&mut db).await?;
71
72 if t.capability().sql {
75 assert_struct!(t.log().pop_op(), Operation::QuerySql({
76 stmt: Statement::Update({
77 target: toasty_core::stmt::UpdateTarget::Table(== user_table),
78 assignments: #{ [2]: Assignment::Set(== 2i64)},
79 }),
80 }));
81 } else {
82 assert_struct!(t.log().pop_op(), Operation::UpdateByKey({
83 table: == user_table,
84 filter: None,
85 keys: _,
86 assignments: #{ [2]: Assignment::Set(== 2i64)},
87 returning: false,
88 }));
89 }
90
91 let found = User::get_by_id(&mut db, &user.id).await?;
92 assert_eq!(found.status, Status::Active);
93
94 User::filter_by_id(user.id)
96 .update()
97 .status(Status::Done)
98 .exec(&mut db)
99 .await?;
100
101 let found = User::get_by_id(&mut db, &user.id).await?;
102 assert_eq!(found.status, Status::Done);
103
104 let id = user.id;
106 user.delete().exec(&mut db).await?;
107 assert_err!(User::get_by_id(&mut db, &id).await);
108 Ok(())
109}
110
111#[driver_test(requires(sql))]
117pub async fn filter_by_enum_variant(t: &mut Test) -> Result<()> {
118 #[derive(Debug, PartialEq, toasty::Embed)]
119 enum Status {
120 #[column(variant = 1)]
121 Pending,
122 #[column(variant = 2)]
123 Active,
124 #[column(variant = 3)]
125 Done,
126 }
127
128 #[derive(Debug, toasty::Model)]
129 #[allow(dead_code)]
130 struct Task {
131 #[key]
132 #[auto]
133 id: uuid::Uuid,
134 name: String,
135 status: Status,
136 }
137
138 let mut db = t.setup_db(models!(Task, Status)).await;
139
140 for (name, status) in [
142 ("Task A", Status::Pending),
143 ("Task B", Status::Active),
144 ("Task C", Status::Active),
145 ("Task D", Status::Done),
146 ] {
147 Task::create()
148 .name(name)
149 .status(status)
150 .exec(&mut db)
151 .await?;
152 }
153
154 let status_col = column(&db, "tasks", "status");
155 t.log().clear();
156
157 let active = Task::filter(Task::fields().status().eq(Status::Active))
159 .exec(&mut db)
160 .await?;
161 assert_eq!(active.len(), 2);
162 {
163 let (op, _) = t.log().pop();
164 assert_struct!(op, Operation::QuerySql({
165 stmt: Statement::Query({
166 body: ExprSet::Select({
167 filter.expr: Some(Expr::BinaryOp({
168 lhs.as_expr_column_unwrap().column: == status_col.index,
169 op: BinaryOp::Eq,
170 *rhs: == 2i64,
171 })),
172 }),
173 }),
174 }));
175 }
176
177 let pending = Task::filter(Task::fields().status().eq(Status::Pending))
179 .exec(&mut db)
180 .await?;
181 assert_eq!(pending.len(), 1);
182 assert_eq!(pending[0].name, "Task A");
183 {
184 let (op, _) = t.log().pop();
185 assert_struct!(op, Operation::QuerySql({
186 stmt: Statement::Query({
187 body: ExprSet::Select({
188 filter.expr: Some(Expr::BinaryOp({
189 lhs.as_expr_column_unwrap().column: == status_col.index,
190 op: BinaryOp::Eq,
191 *rhs: == 1i64,
192 })),
193 }),
194 }),
195 }));
196 }
197
198 let done = Task::filter(Task::fields().status().eq(Status::Done))
200 .exec(&mut db)
201 .await?;
202 assert_eq!(done.len(), 1);
203 assert_eq!(done[0].name, "Task D");
204 {
205 let (op, _) = t.log().pop();
206 assert_struct!(op, Operation::QuerySql({
207 stmt: Statement::Query({
208 body: ExprSet::Select({
209 filter.expr: Some(Expr::BinaryOp({
210 lhs.as_expr_column_unwrap().column: == status_col.index,
211 op: BinaryOp::Eq,
212 *rhs: == 3i64,
213 })),
214 }),
215 }),
216 }));
217 }
218
219 Ok(())
220}
221
222#[driver_test]
225pub async fn basic_embedded_enum(test: &mut Test) {
226 #[derive(toasty::Embed)]
227 enum Status {
228 #[column(variant = 1)]
229 Pending,
230 #[column(variant = 2)]
231 Active,
232 #[column(variant = 3)]
233 Done,
234 }
235
236 let db = test.setup_db(models!(Status)).await;
237 let schema = db.schema();
238
239 assert_struct!(schema.app.models, #{
241 Status::id(): toasty::schema::app::Model::EmbeddedEnum({
242 name.upper_camel_case(): "Status",
243 variants: [
244 _ { name.upper_camel_case(): "Pending", discriminant: toasty_core::stmt::Value::I64(1), .. },
245 _ { name.upper_camel_case(): "Active", discriminant: toasty_core::stmt::Value::I64(2), .. },
246 _ { name.upper_camel_case(): "Done", discriminant: toasty_core::stmt::Value::I64(3), .. },
247 ],
248 }),
249 });
250
251 assert!(schema.db.tables.is_empty());
253}
254
255#[driver_test]
260pub async fn root_model_with_embedded_enum_field(test: &mut Test) {
261 #[derive(toasty::Embed)]
262 enum Status {
263 #[column(variant = 1)]
264 Pending,
265 #[column(variant = 2)]
266 Active,
267 #[column(variant = 3)]
268 Done,
269 }
270
271 #[derive(toasty::Model)]
272 struct User {
273 #[key]
274 id: String,
275 #[allow(dead_code)]
276 status: Status,
277 }
278
279 let db = test.setup_db(models!(User, Status)).await;
280 let schema = db.schema();
281
282 assert_struct!(schema.app.models, #{
284 Status::id(): toasty::schema::app::Model::EmbeddedEnum({
285 name.upper_camel_case(): "Status",
286 variants.len(): 3,
287 }),
288 User::id(): toasty::schema::app::Model::Root({
289 name.upper_camel_case(): "User",
290 fields: [
291 { name.app: Some("id") },
292 {
293 name.app: Some("status"),
294 ty: FieldTy::Embedded({
295 target: == Status::id(),
296 }),
297 },
298 ],
299 }),
300 });
301
302 assert_struct!(schema.db.tables, [
304 {
305 name: =~ r"users$",
306 columns: [
307 { name: "id" },
308 { name: "status" },
309 ],
310 },
311 ]);
312
313 let user = &schema.app.models[&User::id()];
314 let user_table = schema.table_for(user);
315 let user_mapping = &schema.mapping.models[&User::id()];
316
317 assert_struct!(user_mapping, {
318 columns.len(): 2,
319 fields: [
320 mapping::Field::Primitive(FieldPrimitive {
321 column: == user_table.columns[0].id,
322 lowering: 0,
323 ..
324 }),
325 mapping::Field::Enum(FieldEnum {
326 discriminant: FieldPrimitive {
327 column: == user_table.columns[1].id,
328 lowering: 1,
329 ..
330 },
331 variants.len(): 3,
332 ..
333 }),
334 ],
335 });
336}