Ensure incorrect data causes error (#2559)

This commit is contained in:
Tobie Morgan Hitchcock 2023-09-04 18:54:17 +01:00 committed by GitHub
parent c64ccf7cf2
commit abb5ce00db
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 127 additions and 24 deletions

View file

@ -47,7 +47,11 @@ macro_rules! into_future {
None => resource?.into(),
};
let mut conn = Client::new(method);
conn.$method(router?, Param::new(vec![param, content?])).await
let params = match content? {
Value::None | Value::Null => vec![param],
content => vec![param, content],
};
conn.$method(router?, Param::new(params)).await
})
}
};

View file

@ -124,6 +124,18 @@ pub enum Error {
sql: String,
},
/// There was an error with the SQL query
#[error("Can not use {value} in a CONTENT clause")]
InvalidContent {
value: Value,
},
/// There was an error with the SQL query
#[error("Can not use {value} in a MERGE clause")]
InvalidMerge {
value: Value,
},
/// There was an error with the provided JSON Patch
#[error("The JSON Patch contains invalid operations. {message}")]
InvalidPatch {

View file

@ -3,12 +3,17 @@ use crate::sql::value::Value;
impl Value {
pub(crate) fn merge(&mut self, val: Value) -> Result<(), Error> {
if val.is_object() {
for k in val.every(None, false, false).iter() {
match val.pick(k) {
Value::None => self.cut(k),
v => self.put(k, v),
}
// If this value is not an object, then error
if !val.is_object() {
return Err(Error::InvalidMerge {
value: val,
});
}
// Otherwise loop through every object field
for k in val.every(None, false, false).iter() {
match val.pick(k) {
Value::None => self.cut(k),
v => self.put(k, v),
}
}
Ok(())
@ -32,18 +37,13 @@ mod tests {
},
}",
);
let mrg = Value::None;
let val = Value::parse(
"{
name: {
first: 'Tobie',
last: 'Morgan Hitchcock',
initials: 'TMH',
},
}",
);
res.merge(mrg).unwrap();
assert_eq!(res, val);
let none = Value::None;
match res.merge(none.clone()).unwrap_err() {
Error::InvalidMerge {
value,
} => assert_eq!(value, none),
error => panic!("unexpected error: {error:?}"),
}
}
#[tokio::test]

View file

@ -3,9 +3,14 @@ use crate::sql::value::Value;
impl Value {
pub(crate) fn replace(&mut self, val: Value) -> Result<(), Error> {
if val.is_object() {
*self = val;
// If this value is not an object, then error
if !val.is_object() {
return Err(Error::InvalidContent {
value: val,
});
}
// Otherwise replace the current value
*self = val;
Ok(())
}
}

View file

@ -7,6 +7,76 @@ use surrealdb::err::Error;
use surrealdb::iam::Role;
use surrealdb::sql::Value;
#[tokio::test]
async fn update_merge_and_content() -> Result<(), Error> {
let sql = "
CREATE person:test CONTENT { name: 'Tobie' };
UPDATE person:test CONTENT { name: 'Jaime' };
UPDATE person:test CONTENT 'some content';
UPDATE person:test REPLACE 'some content';
UPDATE person:test MERGE { age: 50 };
UPDATE person:test MERGE 'some content';
";
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(), 6);
//
let tmp = res.remove(0).result?;
let val = Value::parse(
"[
{
id: person:test,
name: 'Tobie',
}
]",
);
assert_eq!(tmp, val);
//
let tmp = res.remove(0).result?;
let val = Value::parse(
"[
{
id: person:test,
name: 'Jaime',
}
]",
);
assert_eq!(tmp, val);
//
let tmp = res.remove(0).result;
assert!(matches!(
tmp.err(),
Some(e) if e.to_string() == r#"Can not use 'some content' in a CONTENT clause"#
));
//
let tmp = res.remove(0).result;
assert!(matches!(
tmp.err(),
Some(e) if e.to_string() == r#"Can not use 'some content' in a CONTENT clause"#
));
//
let tmp = res.remove(0).result?;
let val = Value::parse(
"[
{
id: person:test,
name: 'Jaime',
age: 50,
}
]",
);
assert_eq!(tmp, val);
//
let tmp = res.remove(0).result;
assert!(matches!(
tmp.err(),
Some(e) if e.to_string() == r#"Can not use 'some content' in a MERGE clause"#
));
//
Ok(())
}
#[tokio::test]
async fn update_simple_with_input() -> Result<(), Error> {
let sql = "

View file

@ -357,7 +357,11 @@ impl Processor {
// Get a database reference
let kvs = DB.get().unwrap();
// Specify the SQL query string
let sql = "CREATE $what CONTENT $data RETURN AFTER";
let sql = if data.is_none_or_null() {
"CREATE $what RETURN AFTER"
} else {
"CREATE $what CONTENT $data RETURN AFTER"
};
// Specify the query parameters
let var = Some(map! {
String::from("what") => what.could_be_table(),
@ -385,7 +389,11 @@ impl Processor {
// Get a database reference
let kvs = DB.get().unwrap();
// Specify the SQL query string
let sql = "UPDATE $what CONTENT $data RETURN AFTER";
let sql = if data.is_none_or_null() {
"UPDATE $what RETURN AFTER"
} else {
"UPDATE $what CONTENT $data RETURN AFTER"
};
// Specify the query parameters
let var = Some(map! {
String::from("what") => what.could_be_table(),
@ -413,7 +421,11 @@ impl Processor {
// Get a database reference
let kvs = DB.get().unwrap();
// Specify the SQL query string
let sql = "UPDATE $what MERGE $data RETURN AFTER";
let sql = if data.is_none_or_null() {
"UPDATE $what RETURN AFTER"
} else {
"UPDATE $what MERGE $data RETURN AFTER"
};
// Specify the query parameters
let var = Some(map! {
String::from("what") => what.could_be_table(),