Skip to main content

toasty_driver_integration_suite/tests/
crud_driver_ops.rs

1use crate::helpers::column;
2use crate::prelude::*;
3
4use toasty_core::{
5    driver::{Operation, Rows},
6    stmt::{Assignment, BinaryOp, Expr, ExprColumn, ExprSet, Source, Statement, Type},
7};
8
9#[driver_test(id(ID))]
10pub async fn basic_crud(test: &mut Test) -> Result<()> {
11    #[derive(Debug, toasty::Model)]
12    struct User {
13        #[key]
14        #[auto]
15        id: ID,
16
17        name: String,
18        age: i32,
19    }
20
21    let mut db = test.setup_db(models!(User)).await;
22
23    // Helper to get the table ID (handles database-specific prefixes automatically)
24    let user_table_id = table_id(&db, "users");
25    let user_id_column = column(&db, "users", "id");
26
27    // Clear any setup operations (from reset_db, etc.)
28    test.log().clear();
29
30    let is_sql = test.capability().sql();
31
32    // ========== CREATE ==========
33    let user = User::create().name("Alice").age(30).exec(&mut db).await?;
34
35    // Check the CREATE operation
36    let (op, resp) = test.log().pop();
37
38    assert_struct!(op, Operation::Insert({
39        stmt: Statement::Insert({
40            target: toasty_core::stmt::InsertTarget::Table({
41                table: == user_table_id,
42                columns.len(): 3,
43                columns: == columns(&db, "users", &["id", "name", "age"]),
44            }),
45            source: {
46                body: _,
47            },
48        }),
49        // ret: None,
50    }));
51
52    if driver_test_cfg!(id_u64) {
53        assert_struct!(op, Operation::Insert({
54            ret: Some([Type::U64]),
55        }));
56
57        let rows = resp.values.collect_as_value().await?;
58
59        // Check response
60        assert_struct!(rows, == [(1u64,)]);
61    } else {
62        assert_struct!(op, Operation::Insert({
63            ret: None,
64        }));
65
66        // Check response
67        assert_struct!(resp, {
68            values: Rows::Count(1),
69        });
70    }
71
72    let user_id = user.id;
73
74    // ========== READ ==========
75    let fetched = User::get_by_id(&mut db, &user_id).await?;
76    assert_eq!(fetched.name, "Alice");
77    assert_eq!(fetched.age, 30);
78
79    // Check the READ operation
80    let (op, resp) = test.log().pop();
81
82    if is_sql {
83        assert_struct!(op, Operation::QuerySql({
84            stmt: Statement::Query({
85                body: ExprSet::Select({
86                    source: Source::Table({
87                        tables: [== user_table_id, ..],
88                    }),
89                    filter.expr: Some(Expr::BinaryOp({
90                        lhs.as_expr_column_unwrap(): ExprColumn {
91                            nesting: 0,
92                            table: 0,
93                            column: == user_id_column.index,
94                        },
95                        op: BinaryOp::Eq,
96                        rhs: _,
97                    })),
98                }),
99            }),
100            ret: Some(_),
101        }));
102    } else {
103        assert_struct!(op, Operation::GetByKey({
104            table: == user_table_id,
105            keys: _,
106            select.len(): 3,
107        }));
108    }
109
110    assert_struct!(resp.values, Rows::Stream(_));
111
112    // ========== UPDATE ==========
113    User::filter_by_id(user_id)
114        .update()
115        .age(31)
116        .exec(&mut db)
117        .await?;
118
119    // Check the UPDATE operation
120    let (op, resp) = test.log().pop();
121
122    if is_sql {
123        assert_struct!(op, Operation::QuerySql({
124            stmt: Statement::Update({
125                target: toasty_core::stmt::UpdateTarget::Table(== user_table_id),
126                assignments: #{ [2]: Assignment::Set(Expr::Arg({ position: 0 }))},
127                filter.expr: Some(Expr::BinaryOp({
128                    lhs.as_expr_column_unwrap(): ExprColumn {
129                        nesting: 0,
130                        table: 0,
131                        column: == user_id_column.index,
132                    },
133                    op: BinaryOp::Eq,
134                    rhs: _,
135                })),
136            }),
137            params: [{ value: == 31i32 }, ..],
138            ret: None,
139        }));
140    } else {
141        assert_struct!(op, Operation::UpdateByKey({
142            table: == user_table_id,
143            filter: None,
144            keys: _,
145            assignments: #{ [2]: Assignment::Set(== 31i32)},
146            returning: None,
147        }));
148    }
149
150    assert_struct!(resp, {
151        values: Rows::Count(1),
152    });
153
154    // ========== DELETE ==========
155    User::filter_by_id(user_id).delete().exec(&mut db).await?;
156
157    // Check the DELETE operation
158    let (op, resp) = test.log().pop();
159
160    if is_sql {
161        assert_struct!(op, Operation::QuerySql({
162            stmt: Statement::Delete({
163                from: Source::Table({
164                    tables: [== user_table_id, ..],
165                }),
166                filter.expr: Some(Expr::BinaryOp({
167                    lhs.as_expr_column_unwrap(): ExprColumn {
168                        nesting: 0,
169                        table: 0,
170                        column: == user_id_column.index,
171                    },
172                    op: BinaryOp::Eq,
173                    rhs: _,
174                })),
175            }),
176        }));
177    } else {
178        assert_struct!(op, Operation::DeleteByKey({
179            table: == user_table_id,
180            filter: None,
181            keys: _,
182        }));
183    }
184
185    // Check response
186    assert_struct!(resp, {
187        values: Rows::Count(1),
188    });
189
190    // ========== VERIFY LOG IS EMPTY ==========
191    assert!(test.log().is_empty(), "Log should be empty");
192    Ok(())
193}