use std::future::ready;
use crate::async_test_matrix;
use ivo::{
constant_field, dependent_field, lax_field, virtual_field, IvoContext, IvoInputStruct,
IvoModel, IvoStruct,
};
mod ignore;
mod ignore_update;
mod post_validate;
mod required;
async fn should_respect_option_to_ignore_updates_with_empty_fields_array() {
#[derive(Debug, Clone, PartialEq, IvoStruct)]
struct Data {
lax: String,
}
#[derive(Debug, Clone, PartialEq, IvoInputStruct)]
struct DataInput {
lax: String,
}
let default_value = "default_lax_value";
const IGNORE_VALUE: &str = "ignore_value";
let model = IvoModel::<DataInput, Data>::new(
|f| f.field(lax_field("lax").default(default_value.to_string())),
|o| {
o.ignore_update([], |input: PartialDataInput, _, _| {
ready(input.lax.map(|v| v == IGNORE_VALUE).unwrap_or(false))
})
},
);
let lax = "lax_value".to_string();
let data = Data { lax };
let lax_update = IGNORE_VALUE.to_string();
let r = model
.update(
&data,
&PartialDataInput {
lax: Some(lax_update),
},
None,
)
.await;
match r {
Err((e, _, _)) => assert!(e.is_none()),
_ => unreachable!(),
}
let lax_update = "should_not_ignore".to_string();
let (updates, _, _) = model
.update(
&data,
&PartialDataInput {
lax: Some(lax_update.clone()),
},
None,
)
.await
.ok()
.unwrap();
assert_eq!(
updates,
PartialData {
lax: Some(lax_update)
}
);
}
async_test_matrix!(should_respect_option_to_ignore_updates_with_empty_fields_array);
async fn should_properly_trigger_on_delete_handlers() {
#[derive(Debug, Clone, PartialEq, IvoInputStruct)]
struct Data {
lax: i32,
lax_1: i32,
}
let model: IvoModel<Data> = IvoModel::new(
|f| {
f.field(lax_field("lax").default(1234))
.field(lax_field("lax_1").default(5678))
},
|o| {
o.on_delete(|_, _| {
if true {
panic!("[options.on_delete]: handler triggered");
}
ready(())
})
},
);
model.delete(&Data { lax: 2, lax_1: 3 }, None).await
}
async_test_matrix!(
"[options.on_delete]: handler triggered",
should_properly_trigger_on_delete_handlers
);
async fn should_properly_trigger_all_on_delete_handlers() {
#[derive(Debug, Clone, PartialEq, IvoInputStruct)]
struct Data {
lax: i32,
lax_1: i32,
}
let model: IvoModel<Data> = IvoModel::new(
|f| {
f.field(lax_field("lax").default(1234))
.field(lax_field("lax_1").default(5678))
},
|o| {
o.on_delete(|_, _| ready(())).on_delete(|_, _| {
if true {
panic!("[options.on_delete]: second handler triggered");
}
ready(())
})
},
);
model.delete(&Data { lax: 2, lax_1: 3 }, None).await
}
async_test_matrix!(
"[options.on_delete]: second handler triggered",
should_properly_trigger_all_on_delete_handlers
);
#[test]
#[should_panic(
expected = "[options.on_success]: remove duplicates of \"lax\" in grouped on_success config"
)]
fn should_reject_if_the_fields_array_contains_any_duplicates() {
#[derive(Debug, Clone, PartialEq, IvoStruct)]
struct Data {
lax: i32,
lax_1: i32,
}
#[derive(Debug, Clone, PartialEq, IvoInputStruct)]
struct DataInput {
lax: i32,
lax_1: i32,
}
let _: IvoModel<DataInput, Data, Option<()>, &'static str> = IvoModel::new(
|f| {
f.field(lax_field("lax").default(1234))
.field(lax_field("lax_1").default(5678))
},
|o| o.on_success(["lax", "lax"], |s| s.handle(|_, _| ready(()))),
);
}
#[test]
#[should_panic(expected = "[options.on_success]: \"invalid_field\" does not exist on your schema")]
fn should_reject_if_the_fields_array_contains_any_string_that_is_not_a_field_on_schema() {
#[derive(Debug, Clone, PartialEq, IvoStruct)]
struct Data {
lax: i32,
lax_1: i32,
}
#[derive(Debug, Clone, PartialEq, IvoInputStruct)]
struct DataInput {
lax: i32,
lax_1: i32,
}
let _: IvoModel<DataInput, Data, Option<()>, &'static str> = IvoModel::new(
|f| {
f.field(lax_field("lax").default(1234))
.field(lax_field("lax_1").default(5678))
},
|o| o.on_success(["lax", "invalid_field"], |s| s.handle(|_, _| ready(()))),
);
}
#[test]
#[should_panic(
expected = "[options.on_success]: \"alias\" is an alias; use \"virtual_field\" instead"
)]
fn should_reject_if_an_alias_with_foreign_name_is_provided_to_the_fields_array() {
#[derive(Debug, Clone, PartialEq, IvoStruct)]
struct Data {
lax: i32,
lax_1: i32,
dependent: i32,
}
#[derive(Debug, Clone, PartialEq, IvoInputStruct)]
struct DataInput {
lax: i32,
lax_1: i32,
alias: i32,
}
let _: IvoModel<DataInput, Data, Option<()>, &'static str> = IvoModel::new(
|f| {
f.field(
dependent_field("dependent", ["lax", "virtual_field"])
.default(1)
.resolve(|_, _| ready(2)),
)
.field(lax_field("lax").default(1234))
.field(lax_field("lax_1").default(5678))
.field(
virtual_field("virtual_field")
.alias("alias")
.validate(|_, _, _| ready(Ok(Some(1)))),
)
},
|o| o.on_success(["lax", "lax_1", "alias"], |s| s.handle(|_, _| ready(()))),
);
}
#[test]
#[should_panic(
expected = "[options.on_success]: timestamps are not allowed in on_success. remove \"created_at\""
)]
fn should_reject_if_created_at_timestamp_with_default_name_is_provided_to_the_fields_array() {
#[derive(Debug, Clone, PartialEq, IvoStruct)]
struct Data {
created_at: i32,
lax: i32,
lax_1: i32,
}
#[derive(Debug, Clone, PartialEq, IvoInputStruct)]
struct DataInput {
lax: i32,
lax_1: i32,
}
let _: IvoModel<DataInput, Data, Option<()>, i32> = IvoModel::new(
|f| {
f.field(lax_field("lax").default(1234))
.field(lax_field("lax_1").default(5678))
.timestamps(|t| t.resolve(|| 1234).created_at(None))
},
|o| {
o.on_success(["lax", "lax_1", "created_at"], |s| {
s.handle(|_, _| ready(()))
})
},
);
}
#[test]
#[should_panic(
expected = "[options.on_success]: timestamps are not allowed in on_success. remove \"custom_created_at\""
)]
fn should_reject_if_created_at_timestamp_with_custom_name_is_provided_to_the_fields_array() {
#[derive(Debug, Clone, PartialEq, IvoStruct)]
struct Data {
custom_created_at: i32,
lax: i32,
lax_1: i32,
}
#[derive(Debug, Clone, PartialEq, IvoInputStruct)]
struct DataInput {
lax: i32,
lax_1: i32,
}
let _: IvoModel<DataInput, Data, Option<()>, i32> = IvoModel::new(
|f| {
f.field(lax_field("lax").default(1234))
.field(lax_field("lax_1").default(5678))
.timestamps(|t| t.resolve(|| 1234).created_at(Some("custom_created_at")))
},
|o| {
o.on_success(["lax", "lax_1", "custom_created_at"], |s| {
s.handle(|_, _| ready(()))
})
},
);
}
#[test]
#[should_panic(
expected = "[options.on_success]: timestamps are not allowed in on_success. remove \"updated_at\""
)]
fn should_reject_if_updated_at_timestamp_with_default_name_is_provided_to_the_fields_array() {
#[derive(Debug, Clone, PartialEq, IvoStruct)]
struct Data {
updated_at: i32,
lax: i32,
lax_1: i32,
}
#[derive(Debug, Clone, PartialEq, IvoInputStruct)]
struct DataInput {
lax: i32,
lax_1: i32,
}
let _: IvoModel<DataInput, Data, Option<()>, i32> = IvoModel::new(
|f| {
f.field(lax_field("lax").default(1234))
.field(lax_field("lax_1").default(5678))
.timestamps(|t| t.resolve(|| 1234).updated_at(None))
},
|o| {
o.on_success(["lax", "lax_1", "updated_at"], |s| {
s.handle(|_, _| ready(()))
})
},
);
}
#[test]
#[should_panic(
expected = "[options.on_success]: timestamps are not allowed in on_success. remove \"custom_updated_at\""
)]
fn should_reject_if_updated_at_timestamp_with_custom_name_is_provided_to_the_fields_array() {
#[derive(Debug, Clone, PartialEq, IvoStruct)]
struct Data {
custom_updated_at: i32,
lax: i32,
lax_1: i32,
}
#[derive(Debug, Clone, PartialEq, IvoInputStruct)]
struct DataInput {
lax: i32,
lax_1: i32,
}
let _: IvoModel<DataInput, Data, Option<()>, i32> = IvoModel::new(
|f| {
f.field(lax_field("lax").default(1234))
.field(lax_field("lax_1").default(5678))
.timestamps(|t| t.resolve(|| 1234).updated_at(Some("custom_updated_at")))
},
|o| {
o.on_success(["lax", "lax_1", "custom_updated_at"], |s| {
s.handle(|_, _| ready(()))
})
},
);
}
#[test]
fn should_allow_constant_and_dependents_in_fields_array() {
#[derive(Debug, Clone, PartialEq, IvoStruct)]
struct Data {
id: i32,
dependent: i32,
lax: i32,
}
#[derive(Debug, Clone, PartialEq, IvoInputStruct)]
struct DataInput {
lax: i32,
}
let _: IvoModel<DataInput, Data, Option<()>, i32> = IvoModel::new(
|f| {
f.field(constant_field("id").value(1234))
.field(dependent_field("dependent", ["lax"]).default(1).resolve(
|ctx: IvoContext<DataInput, Data>, _| {
ready(ctx.values().dependent.unwrap() + 1)
},
))
.field(lax_field("lax").default(5678))
},
|o| o.on_success(["id", "dependent"], |s| s.handle(|_, _| ready(()))),
);
}