Implement DEFAULT
value clause on DEFINE FIELD
statements (#2468)
This commit is contained in:
parent
71adbe6f5a
commit
1fd6d991ae
2 changed files with 154 additions and 16 deletions
|
@ -31,24 +31,43 @@ impl<'a> Document<'a> {
|
||||||
let old = self.initial.doc.pick(&k);
|
let old = self.initial.doc.pick(&k);
|
||||||
// Get the input value
|
// Get the input value
|
||||||
let inp = inp.pick(&k);
|
let inp = inp.pick(&k);
|
||||||
|
// Get the default value
|
||||||
|
let def = match &fd.default {
|
||||||
|
Some(v) => Some(v),
|
||||||
|
_ => match &fd.value {
|
||||||
|
Some(v) if v.is_static() => Some(v),
|
||||||
|
_ => None,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
// Check for a DEFAULT clause
|
||||||
|
if let Some(expr) = def {
|
||||||
|
if self.is_new() && val.is_none() {
|
||||||
|
// 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 VALUE clause
|
||||||
|
val = expr.compute(&ctx, opt, txn, Some(&self.current)).await?;
|
||||||
|
}
|
||||||
|
}
|
||||||
// Check for a TYPE clause
|
// Check for a TYPE clause
|
||||||
if let Some(kind) = &fd.kind {
|
if let Some(kind) = &fd.kind {
|
||||||
if !val.is_none() {
|
val = val.coerce_to(kind).map_err(|e| match e {
|
||||||
val = val.coerce_to(kind).map_err(|e| match e {
|
// There was a conversion error
|
||||||
// There was a conversion error
|
Error::CoerceTo {
|
||||||
Error::CoerceTo {
|
from,
|
||||||
from,
|
..
|
||||||
..
|
} => Error::FieldCheck {
|
||||||
} => Error::FieldCheck {
|
thing: rid.to_string(),
|
||||||
thing: rid.to_string(),
|
field: fd.name.clone(),
|
||||||
field: fd.name.clone(),
|
value: from.to_string(),
|
||||||
value: from.to_string(),
|
check: kind.to_string(),
|
||||||
check: kind.to_string(),
|
},
|
||||||
},
|
// There was a different error
|
||||||
// There was a different error
|
e => e,
|
||||||
e => e,
|
})?;
|
||||||
})?;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// Check for a VALUE clause
|
// Check for a VALUE clause
|
||||||
if let Some(expr) = &fd.value {
|
if let Some(expr) = &fd.value {
|
||||||
|
|
|
@ -305,6 +305,125 @@ async fn field_definition_empty_nested_flexible() -> Result<(), Error> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn field_definition_default_value() -> Result<(), Error> {
|
||||||
|
let sql = "
|
||||||
|
DEFINE TABLE product SCHEMAFULL;
|
||||||
|
DEFINE FIELD primary ON product TYPE number VALUE 123.456;
|
||||||
|
DEFINE FIELD secondary ON product TYPE bool DEFAULT true VALUE $value;
|
||||||
|
DEFINE FIELD tertiary ON product TYPE string DEFAULT 'hello' VALUE 'tester';
|
||||||
|
--
|
||||||
|
CREATE product:test SET primary = NULL;
|
||||||
|
CREATE product:test SET secondary = 'oops';
|
||||||
|
CREATE product:test SET tertiary = 123;
|
||||||
|
CREATE product:test;
|
||||||
|
--
|
||||||
|
UPDATE product:test SET primary = 654.321;
|
||||||
|
UPDATE product:test SET secondary = false;
|
||||||
|
UPDATE product:test SET tertiary = 'something';
|
||||||
|
";
|
||||||
|
let dbs = Datastore::new("memory").await?;
|
||||||
|
let ses = Session::owner().with_ns("test").with_db("test");
|
||||||
|
let res = &mut dbs.execute(sql, &ses, None).await?;
|
||||||
|
assert_eq!(res.len(), 11);
|
||||||
|
//
|
||||||
|
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;
|
||||||
|
assert!(tmp.is_ok());
|
||||||
|
//
|
||||||
|
let tmp = res.remove(0).result;
|
||||||
|
assert!(tmp.is_ok());
|
||||||
|
//
|
||||||
|
let tmp = res.remove(0).result;
|
||||||
|
assert!(
|
||||||
|
matches!(
|
||||||
|
&tmp,
|
||||||
|
Err(e) if e.to_string() == "Found NULL for field `primary`, with record `product:test`, but expected a number"
|
||||||
|
),
|
||||||
|
"{}",
|
||||||
|
tmp.unwrap_err().to_string()
|
||||||
|
);
|
||||||
|
//
|
||||||
|
let tmp = res.remove(0).result;
|
||||||
|
assert!(
|
||||||
|
matches!(
|
||||||
|
&tmp,
|
||||||
|
Err(e) if e.to_string() == "Found 'oops' for field `secondary`, with record `product:test`, but expected a bool"
|
||||||
|
),
|
||||||
|
"{}",
|
||||||
|
tmp.unwrap_err().to_string()
|
||||||
|
);
|
||||||
|
//
|
||||||
|
let tmp = res.remove(0).result;
|
||||||
|
assert!(
|
||||||
|
matches!(
|
||||||
|
&tmp,
|
||||||
|
Err(e) if e.to_string() == "Found 123 for field `tertiary`, with record `product:test`, but expected a string"
|
||||||
|
),
|
||||||
|
"{}",
|
||||||
|
tmp.unwrap_err().to_string()
|
||||||
|
);
|
||||||
|
//
|
||||||
|
let tmp = res.remove(0).result?;
|
||||||
|
let val = Value::parse(
|
||||||
|
"[
|
||||||
|
{
|
||||||
|
id: product:test,
|
||||||
|
primary: 123.456,
|
||||||
|
secondary: true,
|
||||||
|
tertiary: 'tester',
|
||||||
|
}
|
||||||
|
]",
|
||||||
|
);
|
||||||
|
assert_eq!(tmp, val);
|
||||||
|
//
|
||||||
|
let tmp = res.remove(0).result?;
|
||||||
|
let val = Value::parse(
|
||||||
|
"[
|
||||||
|
{
|
||||||
|
id: product:test,
|
||||||
|
primary: 123.456,
|
||||||
|
secondary: true,
|
||||||
|
tertiary: 'tester',
|
||||||
|
}
|
||||||
|
]",
|
||||||
|
);
|
||||||
|
assert_eq!(tmp, val);
|
||||||
|
//
|
||||||
|
let tmp = res.remove(0).result?;
|
||||||
|
let val = Value::parse(
|
||||||
|
"[
|
||||||
|
{
|
||||||
|
id: product:test,
|
||||||
|
primary: 123.456,
|
||||||
|
secondary: false,
|
||||||
|
tertiary: 'tester',
|
||||||
|
}
|
||||||
|
]",
|
||||||
|
);
|
||||||
|
assert_eq!(tmp, val);
|
||||||
|
//
|
||||||
|
let tmp = res.remove(0).result?;
|
||||||
|
let val = Value::parse(
|
||||||
|
"[
|
||||||
|
{
|
||||||
|
id: product:test,
|
||||||
|
primary: 123.456,
|
||||||
|
secondary: false,
|
||||||
|
tertiary: 'tester',
|
||||||
|
}
|
||||||
|
]",
|
||||||
|
);
|
||||||
|
assert_eq!(tmp, val);
|
||||||
|
//
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn field_definition_value_reference() -> Result<(), Error> {
|
async fn field_definition_value_reference() -> Result<(), Error> {
|
||||||
let sql = "
|
let sql = "
|
||||||
|
|
Loading…
Reference in a new issue