Skip ASSERT
for type option<T>
and value NONE
(#4483)
Co-authored-by: Tobie Morgan Hitchcock <tobie@surrealdb.com>
This commit is contained in:
parent
c5a6e08225
commit
3f5ef43248
2 changed files with 79 additions and 14 deletions
|
@ -6,6 +6,7 @@ use crate::err::Error;
|
|||
use crate::iam::Action;
|
||||
use crate::sql::permission::Permission;
|
||||
use crate::sql::value::Value;
|
||||
use crate::sql::Kind;
|
||||
use reblessive::tree::Stk;
|
||||
|
||||
impl<'a> Document<'a> {
|
||||
|
@ -110,20 +111,30 @@ impl<'a> Document<'a> {
|
|||
}
|
||||
// Check for a ASSERT clause
|
||||
if let Some(expr) = &fd.assert {
|
||||
// Configure the context
|
||||
let mut ctx = Context::new(ctx);
|
||||
ctx.add_value("input", &inp);
|
||||
ctx.add_value("value", &val);
|
||||
ctx.add_value("after", &val);
|
||||
ctx.add_value("before", &old);
|
||||
// Process the ASSERT clause
|
||||
if !expr.compute(stk, &ctx, opt, Some(&self.current)).await?.is_truthy() {
|
||||
return Err(Error::FieldValue {
|
||||
thing: rid.to_string(),
|
||||
field: fd.name.clone(),
|
||||
value: val.to_string(),
|
||||
check: expr.to_string(),
|
||||
});
|
||||
match (&val, &fd.kind) {
|
||||
// The field TYPE is optional, and the field
|
||||
// value was not set or a NONE value was
|
||||
// specified, so let's ignore the ASSERT clause
|
||||
(Value::None, Some(Kind::Option(_))) => (),
|
||||
// Otherwise let's process the ASSERT clause
|
||||
_ => {
|
||||
// Configure the context
|
||||
let mut ctx = Context::new(ctx);
|
||||
ctx.add_value("input", &inp);
|
||||
ctx.add_value("value", &val);
|
||||
ctx.add_value("after", &val);
|
||||
ctx.add_value("before", &old);
|
||||
// Process the ASSERT clause
|
||||
if !expr.compute(stk, &ctx, opt, Some(&self.current)).await?.is_truthy()
|
||||
{
|
||||
return Err(Error::FieldValue {
|
||||
thing: rid.to_string(),
|
||||
field: fd.name.clone(),
|
||||
value: val.to_string(),
|
||||
check: expr.to_string(),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Check for a PERMISSIONS clause
|
||||
|
|
|
@ -138,6 +138,60 @@ async fn field_definition_value_assert_success() -> Result<(), Error> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn field_definition_option_kind_assert() -> Result<(), Error> {
|
||||
let sql = "
|
||||
DEFINE TABLE person SCHEMAFULL;
|
||||
DEFINE FIELD name ON TABLE person TYPE option<string> ASSERT string::len($value) > 3;
|
||||
CREATE person:test;
|
||||
CREATE person:mark SET name = 'mark';
|
||||
CREATE person:bob SET name = 'bob';
|
||||
";
|
||||
let dbs = new_ds().await?;
|
||||
let ses = Session::owner().with_ns("test").with_db("test");
|
||||
let res = &mut dbs.execute(sql, &ses, None).await?;
|
||||
assert_eq!(res.len(), 5);
|
||||
//
|
||||
let tmp = res.remove(0).result;
|
||||
assert!(tmp.is_ok());
|
||||
//
|
||||
let tmp = res.remove(0).result;
|
||||
assert!(tmp.is_ok());
|
||||
//
|
||||
let tmp = res.remove(0).result?;
|
||||
let val = Value::parse(
|
||||
"[
|
||||
{
|
||||
id: person:test
|
||||
}
|
||||
]",
|
||||
);
|
||||
assert_eq!(tmp, val);
|
||||
//
|
||||
let tmp = res.remove(0).result?;
|
||||
let val = Value::parse(
|
||||
"[
|
||||
{
|
||||
id: person:mark,
|
||||
name: 'mark'
|
||||
}
|
||||
]",
|
||||
);
|
||||
assert_eq!(tmp, val);
|
||||
//
|
||||
let tmp = res.remove(0).result;
|
||||
assert!(
|
||||
matches!(
|
||||
&tmp,
|
||||
Err(e) if e.to_string() == "Found 'bob' for field `name`, with record `person:bob`, but field must conform to: string::len($value) > 3"
|
||||
),
|
||||
"{}",
|
||||
tmp.unwrap_err().to_string()
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn field_definition_empty_nested_objects() -> Result<(), Error> {
|
||||
let sql = "
|
||||
|
|
Loading…
Reference in a new issue