use toasty::schema::{
app::FieldTy,
mapping::{self, FieldEnum, FieldPrimitive},
};
use crate::{helpers::column, prelude::*};
use toasty_core::{
driver::Operation,
stmt::{Assignment, BinaryOp, Expr, ExprSet, Statement},
};
#[driver_test(id(ID))]
pub async fn create_and_query_enum(t: &mut Test) -> Result<()> {
#[derive(Debug, PartialEq, toasty::Embed)]
enum Status {
#[column(variant = 1)]
Pending,
#[column(variant = 2)]
Active,
#[column(variant = 3)]
Done,
}
#[derive(Debug, toasty::Model)]
struct User {
#[key]
#[auto]
id: ID,
name: String,
status: Status,
}
let mut db = t.setup_db(models!(User, Status)).await;
let user_table = table_id(&db, "users");
t.log().clear();
let mut user = User::create()
.name("Alice")
.status(Status::Pending)
.exec(&mut db)
.await?;
let sql = t.capability().sql;
let status_pos = if driver_test_cfg!(id_u64) { 1 } else { 2 };
let status_pat = if sql {
ArgOr::Arg(status_pos)
} else {
ArgOr::Value(1i64)
};
let op = t.log().pop_op();
assert_struct!(op, Operation::QuerySql({
stmt: Statement::Insert({
source.body: ExprSet::Values({
rows: [=~ (Any, Any, status_pat)],
}),
target: toasty_core::stmt::InsertTarget::Table({
table: == user_table,
columns: == columns(&db, "users", &["id", "name", "status"]),
}),
}),
}));
if sql {
assert_struct!(op, Operation::QuerySql({
params[status_pos].value: == 1i64,
}));
}
let found = User::get_by_id(&mut db, &user.id).await?;
assert_eq!(found.status, Status::Pending);
t.log().clear();
user.update().status(Status::Active).exec(&mut db).await?;
if t.capability().sql {
assert_struct!(t.log().pop_op(), Operation::QuerySql({
stmt: Statement::Update({
target: toasty_core::stmt::UpdateTarget::Table(== user_table),
assignments: #{ [2]: Assignment::Set(Expr::Arg({ position: 0 }))},
}),
params: [{ value: == 2i64 }, ..],
}));
} else {
assert_struct!(t.log().pop_op(), Operation::UpdateByKey({
table: == user_table,
filter: None,
keys: _,
assignments: #{ [2]: Assignment::Set(== 2i64)},
returning: false,
}));
}
let found = User::get_by_id(&mut db, &user.id).await?;
assert_eq!(found.status, Status::Active);
User::filter_by_id(user.id)
.update()
.status(Status::Done)
.exec(&mut db)
.await?;
let found = User::get_by_id(&mut db, &user.id).await?;
assert_eq!(found.status, Status::Done);
let id = user.id;
user.delete().exec(&mut db).await?;
assert_err!(User::get_by_id(&mut db, &id).await);
Ok(())
}
#[driver_test(requires(sql))]
pub async fn filter_by_enum_variant(t: &mut Test) -> Result<()> {
#[derive(Debug, PartialEq, toasty::Embed)]
enum Status {
#[column(variant = 1)]
Pending,
#[column(variant = 2)]
Active,
#[column(variant = 3)]
Done,
}
#[derive(Debug, toasty::Model)]
#[allow(dead_code)]
struct Task {
#[key]
#[auto]
id: uuid::Uuid,
name: String,
status: Status,
}
let mut db = t.setup_db(models!(Task, Status)).await;
for (name, status) in [
("Task A", Status::Pending),
("Task B", Status::Active),
("Task C", Status::Active),
("Task D", Status::Done),
] {
Task::create()
.name(name)
.status(status)
.exec(&mut db)
.await?;
}
let status_col = column(&db, "tasks", "status");
t.log().clear();
let active = Task::filter(Task::fields().status().eq(Status::Active))
.exec(&mut db)
.await?;
assert_eq!(active.len(), 2);
{
let (op, _) = t.log().pop();
assert_struct!(op, Operation::QuerySql({
stmt: Statement::Query({
body: ExprSet::Select({
filter.expr: Some(Expr::BinaryOp({
lhs.as_expr_column_unwrap().column: == status_col.index,
op: BinaryOp::Eq,
*rhs: Expr::Arg({ position: 0 }),
})),
}),
}),
params: [{ value: == 2i64 }],
}));
}
let pending = Task::filter(Task::fields().status().eq(Status::Pending))
.exec(&mut db)
.await?;
assert_eq!(pending.len(), 1);
assert_eq!(pending[0].name, "Task A");
{
let (op, _) = t.log().pop();
assert_struct!(op, Operation::QuerySql({
stmt: Statement::Query({
body: ExprSet::Select({
filter.expr: Some(Expr::BinaryOp({
lhs.as_expr_column_unwrap().column: == status_col.index,
op: BinaryOp::Eq,
*rhs: Expr::Arg({ position: 0 }),
})),
}),
}),
params: [{ value: == 1i64 }],
}));
}
let done = Task::filter(Task::fields().status().eq(Status::Done))
.exec(&mut db)
.await?;
assert_eq!(done.len(), 1);
assert_eq!(done[0].name, "Task D");
{
let (op, _) = t.log().pop();
assert_struct!(op, Operation::QuerySql({
stmt: Statement::Query({
body: ExprSet::Select({
filter.expr: Some(Expr::BinaryOp({
lhs.as_expr_column_unwrap().column: == status_col.index,
op: BinaryOp::Eq,
*rhs: Expr::Arg({ position: 0 }),
})),
}),
}),
params: [{ value: == 3i64 }],
}));
}
Ok(())
}
#[driver_test]
pub async fn basic_embedded_enum(test: &mut Test) {
#[derive(toasty::Embed)]
enum Status {
#[column(variant = 1)]
Pending,
#[column(variant = 2)]
Active,
#[column(variant = 3)]
Done,
}
let db = test.setup_db(models!(Status)).await;
let schema = db.schema();
assert_struct!(schema.app.models, #{
Status::id(): toasty::schema::app::Model::EmbeddedEnum({
name.upper_camel_case(): "Status",
variants: [
_ { name.upper_camel_case(): "Pending", discriminant: toasty_core::stmt::Value::I64(1), .. },
_ { name.upper_camel_case(): "Active", discriminant: toasty_core::stmt::Value::I64(2), .. },
_ { name.upper_camel_case(): "Done", discriminant: toasty_core::stmt::Value::I64(3), .. },
],
}),
});
assert!(schema.db.tables.is_empty());
}
#[driver_test]
pub async fn root_model_with_embedded_enum_field(test: &mut Test) {
#[derive(toasty::Embed)]
enum Status {
#[column(variant = 1)]
Pending,
#[column(variant = 2)]
Active,
#[column(variant = 3)]
Done,
}
#[derive(toasty::Model)]
struct User {
#[key]
id: String,
#[allow(dead_code)]
status: Status,
}
let db = test.setup_db(models!(User, Status)).await;
let schema = db.schema();
assert_struct!(schema.app.models, #{
Status::id(): toasty::schema::app::Model::EmbeddedEnum({
name.upper_camel_case(): "Status",
variants.len(): 3,
}),
User::id(): toasty::schema::app::Model::Root({
name.upper_camel_case(): "User",
fields: [
{ name.app: Some("id") },
{
name.app: Some("status"),
ty: FieldTy::Embedded({
target: == Status::id(),
}),
},
],
}),
});
assert_struct!(schema.db.tables, [
{
name: =~ r"users$",
columns: [
{ name: "id" },
{ name: "status" },
],
},
]);
let user = &schema.app.models[&User::id()];
let user_table = schema.table_for(user);
let user_mapping = &schema.mapping.models[&User::id()];
assert_struct!(user_mapping, {
columns.len(): 2,
fields: [
mapping::Field::Primitive(FieldPrimitive {
column: == user_table.columns[0].id,
lowering: 0,
..
}),
mapping::Field::Enum(FieldEnum {
discriminant: FieldPrimitive {
column: == user_table.columns[1].id,
lowering: 1,
..
},
variants.len(): 3,
..
}),
],
});
}