[Feat] aligns DEFINE resource creation (already exists) ()

This commit is contained in:
Emmanuel Keller 2024-06-07 17:24:55 +01:00 committed by GitHub
parent 2201b6d26d
commit 2913917284
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
26 changed files with 1572 additions and 2069 deletions

View file

@ -899,7 +899,7 @@ pub enum Error {
},
/// The requested user already exists
#[error("The user '{value}' already exists")]
#[error("The root user '{value}' already exists")]
UserRootAlreadyExists {
value: String,
},

View file

@ -66,10 +66,14 @@ impl DefineAccessStatement {
// Clear the cache
run.clear_cache();
// Check if access method already exists
if self.if_not_exists && run.get_ns_access(opt.ns(), &self.name).await.is_ok() {
return Err(Error::AccessNsAlreadyExists {
value: self.name.to_string(),
});
if run.get_ns_access(opt.ns(), &self.name).await.is_ok() {
if self.if_not_exists {
return Ok(Value::None);
} else {
return Err(Error::AccessNsAlreadyExists {
value: self.name.to_string(),
});
}
}
// Process the statement
let key = crate::key::namespace::ac::new(opt.ns(), &self.name);
@ -91,12 +95,14 @@ impl DefineAccessStatement {
// Clear the cache
run.clear_cache();
// Check if access method already exists
if self.if_not_exists
&& run.get_db_access(opt.ns(), opt.db(), &self.name).await.is_ok()
{
return Err(Error::AccessDbAlreadyExists {
value: self.name.to_string(),
});
if run.get_db_access(opt.ns(), opt.db(), &self.name).await.is_ok() {
if self.if_not_exists {
return Ok(Value::None);
} else {
return Err(Error::AccessDbAlreadyExists {
value: self.name.to_string(),
});
}
}
// Process the statement
let key = crate::key::database::ac::new(opt.ns(), opt.db(), &self.name);

View file

@ -39,10 +39,14 @@ impl DefineAnalyzerStatement {
// Clear the cache
run.clear_cache();
// Check if analyzer already exists
if self.if_not_exists && run.get_db_analyzer(opt.ns(), opt.db(), &self.name).await.is_ok() {
return Err(Error::AzAlreadyExists {
value: self.name.to_string(),
});
if run.get_db_analyzer(opt.ns(), opt.db(), &self.name).await.is_ok() {
if self.if_not_exists {
return Ok(Value::None);
} else {
return Err(Error::AzAlreadyExists {
value: self.name.to_string(),
});
}
}
// Process the statement
let key = crate::key::database::az::new(opt.ns(), opt.db(), &self.name);

View file

@ -38,10 +38,14 @@ impl DefineDatabaseStatement {
// Clear the cache
run.clear_cache();
// Check if database already exists
if self.if_not_exists && run.get_db(opt.ns(), &self.name).await.is_ok() {
return Err(Error::DbAlreadyExists {
value: self.name.to_string(),
});
if run.get_db(opt.ns(), &self.name).await.is_ok() {
if self.if_not_exists {
return Ok(Value::None);
} else {
return Err(Error::DbAlreadyExists {
value: self.name.to_string(),
});
}
}
// Process the statement
let key = crate::key::namespace::db::new(opt.ns(), &self.name);

View file

@ -39,12 +39,14 @@ impl DefineEventStatement {
// Clear the cache
run.clear_cache();
// Check if event already exists
if self.if_not_exists
&& run.get_tb_event(opt.ns(), opt.db(), &self.what, &self.name).await.is_ok()
{
return Err(Error::EvAlreadyExists {
value: self.name.to_string(),
});
if run.get_tb_event(opt.ns(), opt.db(), &self.what, &self.name).await.is_ok() {
if self.if_not_exists {
return Ok(Value::None);
} else {
return Err(Error::EvAlreadyExists {
value: self.name.to_string(),
});
}
}
// Process the statement
let key = crate::key::table::ev::new(opt.ns(), opt.db(), &self.what, &self.name);

View file

@ -51,11 +51,14 @@ impl DefineFieldStatement {
run.clear_cache();
// Check if field already exists
let fd = self.name.to_string();
if self.if_not_exists && run.get_tb_field(opt.ns(), opt.db(), &self.what, &fd).await.is_ok()
{
return Err(Error::FdAlreadyExists {
value: fd,
});
if run.get_tb_field(opt.ns(), opt.db(), &self.what, &fd).await.is_ok() {
if self.if_not_exists {
return Ok(Value::None);
} else {
return Err(Error::FdAlreadyExists {
value: fd,
});
}
}
// Process the statement
run.add_ns(opt.ns(), opt.strict).await?;

View file

@ -42,10 +42,14 @@ impl DefineFunctionStatement {
// Clear the cache
run.clear_cache();
// Check if function already exists
if self.if_not_exists && run.get_db_function(opt.ns(), opt.db(), &self.name).await.is_ok() {
return Err(Error::FcAlreadyExists {
value: self.name.to_string(),
});
if run.get_db_function(opt.ns(), opt.db(), &self.name).await.is_ok() {
if self.if_not_exists {
return Ok(Value::None);
} else {
return Err(Error::FcAlreadyExists {
value: self.name.to_string(),
});
}
}
// Process the statement
let key = crate::key::database::fc::new(opt.ns(), opt.db(), &self.name);

View file

@ -44,12 +44,14 @@ impl DefineIndexStatement {
// Clear the cache
run.clear_cache();
// Check if index already exists
let index_exists =
run.get_tb_index(opt.ns(), opt.db(), &self.what, &self.name).await.is_ok();
if self.if_not_exists && index_exists {
return Err(Error::IxAlreadyExists {
value: self.name.to_string(),
});
if run.get_tb_index(opt.ns(), opt.db(), &self.what, &self.name).await.is_ok() {
if self.if_not_exists {
return Ok(Value::None);
} else {
return Err(Error::IxAlreadyExists {
value: self.name.to_string(),
});
}
}
// If we are strict, check that the table exists
run.check_ns_db_tb(opt.ns(), opt.db(), &self.what, opt.strict).await?;
@ -74,11 +76,6 @@ impl DefineIndexStatement {
Err(e) => return Err(e),
}
// Clear the index store cache
if index_exists {
ctx.get_index_stores().index_removed(opt, &mut run, &self.what, &self.name).await?;
}
// Process the statement
let key = crate::key::table::ix::new(opt.ns(), opt.db(), &self.what, &self.name);
run.add_ns(opt.ns(), opt.strict).await?;

View file

@ -63,12 +63,14 @@ impl DefineModelStatement {
// Clear the cache
run.clear_cache();
// Check if model already exists
if self.if_not_exists
&& run.get_db_model(opt.ns(), opt.db(), &self.name, &self.version).await.is_ok()
{
return Err(Error::MlAlreadyExists {
value: self.name.to_string(),
});
if run.get_db_model(opt.ns(), opt.db(), &self.name, &self.version).await.is_ok() {
if self.if_not_exists {
return Ok(Value::None);
} else {
return Err(Error::MlAlreadyExists {
value: self.name.to_string(),
});
}
}
// Process the statement
let key = crate::key::database::ml::new(opt.ns(), opt.db(), &self.name, &self.version);

View file

@ -39,10 +39,14 @@ impl DefineNamespaceStatement {
// Clear the cache
run.clear_cache();
// Check if namespace already exists
if self.if_not_exists && run.get_ns(&self.name).await.is_ok() {
return Err(Error::NsAlreadyExists {
value: self.name.to_string(),
});
if run.get_ns(&self.name).await.is_ok() {
if self.if_not_exists {
return Ok(Value::None);
} else {
return Err(Error::NsAlreadyExists {
value: self.name.to_string(),
});
}
}
if self.id.is_none() {
// Set the id

View file

@ -41,10 +41,14 @@ impl DefineParamStatement {
// Clear the cache
run.clear_cache();
// Check if param already exists
if self.if_not_exists && run.get_db_param(opt.ns(), opt.db(), &self.name).await.is_ok() {
return Err(Error::PaAlreadyExists {
value: self.name.to_string(),
});
if run.get_db_param(opt.ns(), opt.db(), &self.name).await.is_ok() {
if self.if_not_exists {
return Ok(Value::None);
} else {
return Err(Error::PaAlreadyExists {
value: self.name.to_string(),
});
}
}
// Process the statement
let key = crate::key::database::pa::new(opt.ns(), opt.db(), &self.name);

View file

@ -55,10 +55,14 @@ impl DefineTableStatement {
// Clear the cache
run.clear_cache();
// Check if table already exists
if self.if_not_exists && run.get_tb(opt.ns(), opt.db(), &self.name).await.is_ok() {
return Err(Error::TbAlreadyExists {
value: self.name.to_string(),
});
if run.get_tb(opt.ns(), opt.db(), &self.name).await.is_ok() {
if self.if_not_exists {
return Ok(Value::None);
} else {
return Err(Error::TbAlreadyExists {
value: self.name.to_string(),
});
}
}
// Process the statement
let key = crate::key::database::tb::new(opt.ns(), opt.db(), &self.name);

View file

@ -113,10 +113,14 @@ impl DefineUserStatement {
// Clear the cache
run.clear_cache();
// Check if user already exists
if self.if_not_exists && run.get_root_user(&self.name).await.is_ok() {
return Err(Error::UserRootAlreadyExists {
value: self.name.to_string(),
});
if run.get_root_user(&self.name).await.is_ok() {
if self.if_not_exists {
return Ok(Value::None);
} else {
return Err(Error::UserRootAlreadyExists {
value: self.name.to_string(),
});
}
}
// Process the statement
let key = crate::key::root::us::new(&self.name);
@ -138,11 +142,15 @@ impl DefineUserStatement {
// Clear the cache
run.clear_cache();
// Check if user already exists
if self.if_not_exists && run.get_ns_user(opt.ns(), &self.name).await.is_ok() {
return Err(Error::UserNsAlreadyExists {
value: self.name.to_string(),
ns: opt.ns().into(),
});
if run.get_ns_user(opt.ns(), &self.name).await.is_ok() {
if self.if_not_exists {
return Ok(Value::None);
} else {
return Err(Error::UserNsAlreadyExists {
value: self.name.to_string(),
ns: opt.ns().into(),
});
}
}
// Process the statement
let key = crate::key::namespace::us::new(opt.ns(), &self.name);
@ -165,14 +173,16 @@ impl DefineUserStatement {
// Clear the cache
run.clear_cache();
// Check if user already exists
if self.if_not_exists
&& run.get_db_user(opt.ns(), opt.db(), &self.name).await.is_ok()
{
return Err(Error::UserDbAlreadyExists {
value: self.name.to_string(),
ns: opt.ns().into(),
db: opt.db().into(),
});
if run.get_db_user(opt.ns(), opt.db(), &self.name).await.is_ok() {
if self.if_not_exists {
return Ok(Value::None);
} else {
return Err(Error::UserDbAlreadyExists {
value: self.name.to_string(),
ns: opt.ns().into(),
db: opt.db().into(),
});
}
}
// Process the statement
let key = crate::key::database::us::new(opt.ns(), opt.db(), &self.name);

View file

@ -1,6 +1,7 @@
// Tests for exporting and importing data
// Supported by the storage engines and the HTTP protocol
use surrealdb_core::sql::Table;
use tokio::fs::remove_file;
#[test_log::test(tokio::test)]
@ -22,6 +23,7 @@ async fn export_import() {
let res = async {
db.export(&file).await?;
db.query("REMOVE TABLE user").await?;
db.import(&file).await?;
Result::<(), Error>::Ok(())
}

View file

@ -210,8 +210,8 @@ async fn create_with_custom_function() -> Result<(), Error> {
#[tokio::test]
async fn create_or_insert_with_permissions() -> Result<(), Error> {
let sql = "
CREATE user:test;
DEFINE TABLE user SCHEMAFULL PERMISSIONS FULL;
CREATE user:test;
DEFINE TABLE demo SCHEMAFULL PERMISSIONS FOR select, create, update WHERE user = $auth.id;
DEFINE FIELD user ON TABLE demo VALUE $auth.id;
";

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,7 @@
mod parse;
use parse::Parse;
mod helpers;
use crate::helpers::Test;
use helpers::new_ds;
use helpers::with_enough_stack;
use surrealdb::dbs::Session;
@ -926,27 +927,15 @@ async fn field_definition_flexible_array_any() -> Result<(), Error> {
let sql = "
DEFINE TABLE user SCHEMAFULL;
DEFINE FIELD custom ON user TYPE option<array>;
REMOVE FIELD custom.* ON user;
DEFINE FIELD custom.* ON user FLEXIBLE TYPE any;
CREATE user:one CONTENT { custom: ['sometext'] };
CREATE user:two CONTENT { custom: [ ['sometext'] ] };
CREATE user:three CONTENT { custom: [ { key: 'sometext' } ] };
";
let dbs = new_ds().await?.with_auth_enabled(true);
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;
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?;
let val = Value::parse(
let mut t = Test::new(sql).await?;
t.skip_ok(4)?;
t.expect_val(
"[
{
custom: [
@ -955,11 +944,8 @@ async fn field_definition_flexible_array_any() -> Result<(), Error> {
id: user:one
},
]",
);
assert_eq!(tmp, val);
//
let tmp = res.remove(0).result?;
let val = Value::parse(
)?;
t.expect_val(
"[
{
custom: [
@ -970,11 +956,8 @@ async fn field_definition_flexible_array_any() -> Result<(), Error> {
id: user:two
},
]",
);
assert_eq!(tmp, val);
//
let tmp = res.remove(0).result?;
let val = Value::parse(
)?;
t.expect_val(
"[
{
custom: [
@ -985,8 +968,6 @@ async fn field_definition_flexible_array_any() -> Result<(), Error> {
id: user:three
}
]",
);
assert_eq!(tmp, val);
//
)?;
Ok(())
}

File diff suppressed because it is too large Load diff

View file

@ -598,7 +598,7 @@ async fn select_array_group_group_by() -> Result<(), Error> {
let mut res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 5);
//
skip_ok(&mut res, 4);
skip_ok(&mut res, 4)?;
//
let tmp = res.remove(0).result?;
let val = Value::parse(
@ -636,7 +636,7 @@ async fn select_array_count_subquery_group_by() -> Result<(), Error> {
let mut res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 5);
//
skip_ok(&mut res, 3);
skip_ok(&mut res, 3)?;
//
let tmp = res.remove(0).result?;
let val = Value::parse(

View file

@ -197,19 +197,24 @@ pub fn with_enough_stack(
.unwrap()
}
#[allow(dead_code)]
fn skip_ok_pos(res: &mut Vec<Response>, pos: usize) -> Result<(), Error> {
assert!(!res.is_empty(), "At position {pos} - No more result!");
let r = res.remove(0).result;
let _ = r.is_err_and(|e| {
panic!("At position {pos} - Statement fails with: {e}");
});
Ok(())
}
/// Skip the specified number of successful results from a vector of responses.
/// This function will panic if there are not enough results in the vector or if an error occurs.
#[allow(dead_code)]
pub fn skip_ok(res: &mut Vec<Response>, skip: usize) {
pub fn skip_ok(res: &mut Vec<Response>, skip: usize) -> Result<(), Error> {
for i in 0..skip {
if res.is_empty() {
panic!("No more result #{i}");
}
let r = res.remove(0).result;
let _ = r.is_err_and(|e| {
panic!("Statement #{i} fails with: {e}");
});
skip_ok_pos(res, i)?;
}
Ok(())
}
/// Struct representing a test scenario.
@ -238,14 +243,7 @@ impl Test {
/// Arguments `sql` - A string slice representing the SQL query.
/// Panics if an error occurs.
#[allow(dead_code)]
pub async fn new(sql: &str) -> Self {
Self::try_new(sql).await.unwrap_or_else(|e| panic!("{e}"))
}
/// Create a new instance of the Test struct and execute the given SQL statement.
///
#[allow(dead_code)]
pub async fn try_new(sql: &str) -> Result<Self, Error> {
pub async fn new(sql: &str) -> Result<Self, Error> {
let ds = new_ds().await?;
let session = Session::owner().with_ns("test").with_db("test");
let responses = ds.execute(sql, &session, None).await?;
@ -260,52 +258,50 @@ impl Test {
/// Checks if the number of responses matches the expected size.
/// Panics if the number of responses does not match the expected size
#[allow(dead_code)]
pub fn expect_size(&mut self, expected: usize) -> &mut Self {
pub fn expect_size(&mut self, expected: usize) -> Result<&mut Self, Error> {
assert_eq!(
self.responses.len(),
expected,
"Unexpected number of results: {} - Expected: {expected}",
self.responses.len()
);
self
Ok(self)
}
/// Retrieves the next response from the responses list.
/// This method will panic if the responses list is empty, indicating that there are no more responses to retrieve.
/// The panic message will include the last position in the responses list before it was emptied.
#[allow(dead_code)]
pub fn next(&mut self) -> Response {
if self.responses.is_empty() {
panic!("No response left - last position: {}", self.pos);
}
pub fn next(&mut self) -> Result<Response, Error> {
assert!(!self.responses.is_empty(), "No response left - last position: {}", self.pos);
self.pos += 1;
self.responses.remove(0)
Ok(self.responses.remove(0))
}
/// Retrieves the next value from the responses list.
/// This method will panic if the responses list is empty, indicating that there are no more responses to retrieve.
/// The panic message will include the last position in the responses list before it was emptied.
pub fn next_value(&mut self) -> Value {
self.next()
.result
.unwrap_or_else(|e| panic!("Unexpected error: {e} - last position: {}", self.pos))
pub fn next_value(&mut self) -> Result<Value, Error> {
self.next()?.result
}
/// Skips a specified number of elements from the beginning of the `responses` vector
/// and updates the position.
#[allow(dead_code)]
pub fn skip_ok(&mut self, skip: usize) -> &mut Self {
skip_ok(&mut self.responses, skip);
self.pos += skip;
self
pub fn skip_ok(&mut self, skip: usize) -> Result<&mut Self, Error> {
for _ in 0..skip {
skip_ok_pos(&mut self.responses, self.pos)?;
self.pos += 1;
}
Ok(self)
}
/// Expects the next value to be equal to the provided value.
/// Panics if the expected value is not equal to the actual value.
/// Compliant with NaN and Constants.
#[allow(dead_code)]
pub fn expect_value(&mut self, val: Value) -> &mut Self {
let tmp = self.next_value();
pub fn expect_value(&mut self, val: Value) -> Result<&mut Self, Error> {
let tmp = self.next_value()?;
// Then check they are indeed the same values
//
// If it is a constant we need to transform it as a number
@ -320,55 +316,65 @@ impl Test {
assert_eq!(tmp, val, "{tmp:#}");
}
//
self
Ok(self)
}
/// Expect values in the given slice to be present in the responses, following the same order.
#[allow(dead_code)]
pub fn expect_values(&mut self, values: &[Value]) -> &mut Self {
pub fn expect_values(&mut self, values: &[Value]) -> Result<&mut Self, Error> {
for value in values {
self.expect_value(value.clone());
self.expect_value(value.clone())?;
}
self
Ok(self)
}
/// Expect the given value to be equals to the next response.
#[allow(dead_code)]
pub fn expect_val(&mut self, val: &str) -> &mut Self {
pub fn expect_val(&mut self, val: &str) -> Result<&mut Self, Error> {
self.expect_value(value(val).unwrap())
}
#[allow(dead_code)]
/// Expect values in the given slice to be present in the responses, following the same order.
pub fn expect_vals(&mut self, vals: &[&str]) -> &mut Self {
pub fn expect_vals(&mut self, vals: &[&str]) -> Result<&mut Self, Error> {
for val in vals {
self.expect_val(val);
self.expect_val(val)?;
}
self
Ok(self)
}
/// Expects the next result to be an error with the specified error message.
/// Expects the next result to be an error with the given check function returning true.
/// This function will panic if the next result is not an error or if the error
/// message does not match the specified error.
/// message does not pass the check.
#[allow(dead_code)]
pub fn expect_error(&mut self, error: &str) -> &mut Self {
let tmp = self.next().result;
assert!(
matches!(
&tmp,
Err(e) if e.to_string() == error
),
"{tmp:?} didn't match {error}"
);
self
pub fn expect_error_func<F: Fn(&Error) -> bool>(
&mut self,
check: F,
) -> Result<&mut Self, Error> {
let tmp = self.next()?.result;
match &tmp {
Ok(val) => {
panic!("At position {} - Expect error, but got OK: {val}", self.pos);
}
Err(e) => {
assert!(check(e), "At position {} - Err didn't match: {e}", self.pos)
}
}
Ok(self)
}
#[allow(dead_code)]
pub fn expect_errors(&mut self, errors: &[&str]) -> &mut Self {
/// Expects the next result to be an error with the specified error message.
pub fn expect_error(&mut self, error: &str) -> Result<&mut Self, Error> {
self.expect_error_func(|e| e.to_string() == error)
}
#[allow(dead_code)]
pub fn expect_errors(&mut self, errors: &[&str]) -> Result<&mut Self, Error> {
for error in errors {
self.expect_error(error);
self.expect_error(error)?;
}
self
Ok(self)
}
/// Expects the next value to be a floating-point number and compares it with the given value.
@ -383,8 +389,8 @@ impl Test {
/// Panics if the next value is not a number or if the difference
/// between the expected and actual value exceeds the precision.
#[allow(dead_code)]
pub fn expect_float(&mut self, val: f64, precision: f64) -> &mut Self {
let tmp = self.next_value();
pub fn expect_float(&mut self, val: f64, precision: f64) -> Result<&mut Self, Error> {
let tmp = self.next_value()?;
if let Value::Number(Number::Float(n)) = tmp {
let diff = (n - val).abs();
assert!(
@ -394,15 +400,15 @@ impl Test {
} else {
panic!("At position {}: Value {tmp} is not a number", self.pos);
}
self
Ok(self)
}
#[allow(dead_code)]
pub fn expect_floats(&mut self, vals: &[f64], precision: f64) -> &mut Self {
pub fn expect_floats(&mut self, vals: &[f64], precision: f64) -> Result<&mut Self, Error> {
for val in vals {
self.expect_float(*val, precision);
self.expect_float(*val, precision)?;
}
self
Ok(self)
}
}

View file

@ -21,7 +21,7 @@ async fn select_where_matches_using_index() -> Result<(), Error> {
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 5);
//
skip_ok(res, 3);
skip_ok(res, 3)?;
//
let tmp = res.remove(0).result?;
let val = Value::parse(
@ -74,7 +74,7 @@ async fn select_where_matches_without_using_index_iterator() -> Result<(), Error
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 6);
//
skip_ok(res, 4);
skip_ok(res, 4)?;
//
let tmp = res.remove(0).result?;
let val = Value::parse(
@ -133,7 +133,7 @@ async fn select_where_matches_using_index_and_arrays(parallel: bool) -> Result<(
let res = &mut dbs.execute(&sql, &ses, None).await?;
assert_eq!(res.len(), 5);
//
skip_ok(res, 3);
skip_ok(res, 3)?;
//
let tmp = res.remove(0).result?;
let val = Value::parse(
@ -204,7 +204,7 @@ async fn select_where_matches_partial_highlight() -> Result<(), Error> {
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 9);
//
skip_ok(res, 3);
skip_ok(res, 3)?;
//
for i in 0..2 {
let tmp = res.remove(0).result?;
@ -289,7 +289,7 @@ async fn select_where_matches_partial_highlight_ngram() -> Result<(), Error> {
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 10);
//
skip_ok(res, 3);
skip_ok(res, 3)?;
//
for i in 0..3 {
let tmp = res.remove(0).result?;
@ -375,7 +375,7 @@ async fn select_where_matches_using_index_and_objects(parallel: bool) -> Result<
let res = &mut dbs.execute(&sql, &ses, None).await?;
assert_eq!(res.len(), 5);
//
skip_ok(res, 3);
skip_ok(res, 3)?;
//
let tmp = res.remove(0).result?;
let val = Value::parse(
@ -443,7 +443,7 @@ async fn select_where_matches_using_index_offsets() -> Result<(), Error> {
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 5);
//
skip_ok(res, 4);
skip_ok(res, 4)?;
//
let tmp = res.remove(0).result?;
let val = Value::parse(
@ -480,7 +480,7 @@ async fn select_where_matches_using_index_and_score() -> Result<(), Error> {
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 7);
//
skip_ok(res, 6);
skip_ok(res, 6)?;
//
let tmp = res.remove(0).result?;
let val = Value::parse(
@ -517,7 +517,7 @@ async fn select_where_matches_without_using_index_and_score() -> Result<(), Erro
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 9);
//
skip_ok(res, 7);
skip_ok(res, 7)?;
//
let tmp = res.remove(0).result?;
let val = Value::parse(
@ -565,7 +565,7 @@ async fn select_where_matches_without_complex_query() -> Result<(), Error> {
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 10);
//
skip_ok(res, 6);
skip_ok(res, 6)?;
//
let tmp = res.remove(0).result?;
let val_docs = Value::parse(
@ -654,7 +654,7 @@ async fn select_where_matches_mixing_indexes() -> Result<(), Error> {
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 7);
//
skip_ok(res, 5);
skip_ok(res, 5)?;
//
let tmp = res.remove(0).result?;
let val = Value::parse(

View file

@ -12,7 +12,7 @@ use surrealdb::sql::Value;
async fn select_where_iterate_three_multi_index() -> Result<(), Error> {
let dbs = new_ds().await?;
let mut res = execute_test(&dbs, &three_multi_index_query("", ""), 12).await?;
skip_ok(&mut res, 8);
skip_ok(&mut res, 8)?;
check_result(&mut res, "[{ name: 'Jaime' }, { name: 'Tobie' }, { name: 'Lizzie' }]")?;
// OR results
check_result(&mut res, THREE_MULTI_INDEX_EXPLAIN)?;
@ -26,7 +26,7 @@ async fn select_where_iterate_three_multi_index() -> Result<(), Error> {
async fn select_where_iterate_three_multi_index_parallel() -> Result<(), Error> {
let dbs = new_ds().await?;
let mut res = execute_test(&dbs, &three_multi_index_query("", "PARALLEL"), 12).await?;
skip_ok(&mut res, 8);
skip_ok(&mut res, 8)?;
// OR results
check_result(&mut res, "[{ name: 'Jaime' }, { name: 'Tobie' }, { name: 'Lizzie' }]")?;
check_result(&mut res, THREE_MULTI_INDEX_EXPLAIN)?;
@ -45,7 +45,7 @@ async fn select_where_iterate_three_multi_index_with_all_index() -> Result<(), E
12,
)
.await?;
skip_ok(&mut res, 8);
skip_ok(&mut res, 8)?;
// OR results
check_result(&mut res, "[{ name: 'Jaime' }, { name: 'Tobie' }, { name: 'Lizzie' }]")?;
check_result(&mut res, THREE_MULTI_INDEX_EXPLAIN)?;
@ -60,7 +60,7 @@ async fn select_where_iterate_three_multi_index_with_one_ft_index() -> Result<()
let dbs = new_ds().await?;
let mut res =
execute_test(&dbs, &three_multi_index_query("WITH INDEX ft_company", ""), 12).await?;
skip_ok(&mut res, 8);
skip_ok(&mut res, 8)?;
// OR results
check_result(&mut res, "[{ name: 'Jaime' }, { name: 'Lizzie' }, { name: 'Tobie' } ]")?;
@ -76,7 +76,7 @@ async fn select_where_iterate_three_multi_index_with_one_index() -> Result<(), E
let dbs = new_ds().await?;
let mut res =
execute_test(&dbs, &three_multi_index_query("WITH INDEX uniq_name", ""), 12).await?;
skip_ok(&mut res, 8);
skip_ok(&mut res, 8)?;
// OR results
check_result(&mut res, "[{ name: 'Jaime' }, { name: 'Lizzie' }, { name: 'Tobie' } ]")?;
@ -91,7 +91,7 @@ async fn select_where_iterate_three_multi_index_with_one_index() -> Result<(), E
async fn select_where_iterate_two_multi_index() -> Result<(), Error> {
let dbs = new_ds().await?;
let mut res = execute_test(&dbs, &two_multi_index_query("", ""), 9).await?;
skip_ok(&mut res, 5);
skip_ok(&mut res, 5)?;
// OR results
check_result(&mut res, "[{ name: 'Jaime' }, { name: 'Tobie' }]")?;
check_result(&mut res, TWO_MULTI_INDEX_EXPLAIN)?;
@ -105,7 +105,7 @@ async fn select_where_iterate_two_multi_index() -> Result<(), Error> {
async fn select_where_iterate_two_multi_index_with_one_index() -> Result<(), Error> {
let dbs = new_ds().await?;
let mut res = execute_test(&dbs, &two_multi_index_query("WITH INDEX idx_genre", ""), 9).await?;
skip_ok(&mut res, 5);
skip_ok(&mut res, 5)?;
// OR results
check_result(&mut res, "[{ name: 'Jaime' }, { name: 'Tobie' }]")?;
check_result(&mut res, &table_explain(2))?;
@ -120,7 +120,7 @@ async fn select_where_iterate_two_multi_index_with_two_index() -> Result<(), Err
let dbs = new_ds().await?;
let mut res =
execute_test(&dbs, &two_multi_index_query("WITH INDEX idx_genre,uniq_name", ""), 9).await?;
skip_ok(&mut res, 5);
skip_ok(&mut res, 5)?;
// OR results
check_result(&mut res, "[{ name: 'Jaime' }, { name: 'Tobie' }]")?;
check_result(&mut res, TWO_MULTI_INDEX_EXPLAIN)?;
@ -134,7 +134,7 @@ async fn select_where_iterate_two_multi_index_with_two_index() -> Result<(), Err
async fn select_where_iterate_two_no_index() -> Result<(), Error> {
let dbs = new_ds().await?;
let mut res = execute_test(&dbs, &two_multi_index_query("WITH NOINDEX", ""), 9).await?;
skip_ok(&mut res, 5);
skip_ok(&mut res, 5)?;
// OR results
check_result(&mut res, "[{ name: 'Jaime' }, { name: 'Tobie' }]")?;
check_result(&mut res, &table_explain_no_index(2))?;
@ -547,7 +547,7 @@ async fn select_range(
) -> Result<(), Error> {
let dbs = new_ds().await?;
let mut res = execute_test(&dbs, &range_test(unique, from_incl, to_incl), 8).await?;
skip_ok(&mut res, 6);
skip_ok(&mut res, 6)?;
{
let tmp = res.remove(0).result?;
let val = Value::parse(explain);
@ -790,7 +790,7 @@ async fn select_single_range_operator(
) -> Result<(), Error> {
let dbs = new_ds().await?;
let mut res = execute_test(&dbs, &single_range_operator_test(unique, op), 6).await?;
skip_ok(&mut res, 4);
skip_ok(&mut res, 4)?;
{
let tmp = res.remove(0).result?;
let val = Value::parse(explain);
@ -990,7 +990,7 @@ async fn select_with_idiom_param_value() -> Result<(), Error> {
.to_owned();
let mut res = dbs.execute(&sql, &ses, None).await?;
assert_eq!(res.len(), 6);
skip_ok(&mut res, 5);
skip_ok(&mut res, 5)?;
let tmp = res.remove(0).result?;
let val = Value::parse(
r#"[
@ -1079,7 +1079,7 @@ async fn test_contains(
let val = Value::parse(result);
assert_eq!(format!("{:#}", tmp), format!("{:#}", val));
}
skip_ok(&mut res, 1);
skip_ok(&mut res, 1)?;
{
let tmp = res.remove(0).result?;
let val = Value::parse(index_explain);
@ -1097,7 +1097,7 @@ async fn test_contains(
async fn select_contains() -> Result<(), Error> {
let dbs = new_ds().await?;
let mut res = execute_test(&dbs, CONTAINS_CONTENT, 3).await?;
skip_ok(&mut res, 3);
skip_ok(&mut res, 3)?;
const SQL: &str = r#"
SELECT id FROM student WHERE marks.*.subject CONTAINS "english" EXPLAIN;
@ -1142,7 +1142,7 @@ async fn select_contains() -> Result<(), Error> {
async fn select_contains_all() -> Result<(), Error> {
let dbs = new_ds().await?;
let mut res = execute_test(&dbs, CONTAINS_CONTENT, 3).await?;
skip_ok(&mut res, 3);
skip_ok(&mut res, 3)?;
const SQL: &str = r#"
SELECT id FROM student WHERE marks.*.subject CONTAINSALL ["hindi", "maths"] EXPLAIN;
SELECT id FROM student WHERE marks.*.subject CONTAINSALL ["hindi", "maths"];
@ -1185,7 +1185,7 @@ async fn select_contains_all() -> Result<(), Error> {
async fn select_contains_any() -> Result<(), Error> {
let dbs = new_ds().await?;
let mut res = execute_test(&dbs, CONTAINS_CONTENT, 3).await?;
skip_ok(&mut res, 3);
skip_ok(&mut res, 3)?;
const SQL: &str = r#"
SELECT id FROM student WHERE marks.*.subject CONTAINSANY ["tamil", "french"] EXPLAIN;
SELECT id FROM student WHERE marks.*.subject CONTAINSANY ["tamil", "french"];
@ -1233,7 +1233,7 @@ const CONTAINS_UNIQUE_CONTENT: &str = r#"
async fn select_unique_contains() -> Result<(), Error> {
let dbs = new_ds().await?;
let mut res = execute_test(&dbs, CONTAINS_UNIQUE_CONTENT, 3).await?;
skip_ok(&mut res, 3);
skip_ok(&mut res, 3)?;
const SQL: &str = r#"
SELECT id FROM student WHERE subject CONTAINS "english" EXPLAIN;
@ -1291,7 +1291,7 @@ async fn select_with_datetime_value() -> Result<(), Error> {
let mut res = dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 8);
skip_ok(&mut res, 4);
skip_ok(&mut res, 4)?;
for _ in 0..2 {
let tmp = res.remove(0).result?;
@ -1354,7 +1354,7 @@ async fn select_with_uuid_value() -> Result<(), Error> {
let mut res = dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 7);
skip_ok(&mut res, 3);
skip_ok(&mut res, 3)?;
for _ in 0..2 {
let tmp = res.remove(0).result?;
@ -1415,7 +1415,7 @@ async fn select_with_in_operator() -> Result<(), Error> {
let mut res = dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 7);
skip_ok(&mut res, 3);
skip_ok(&mut res, 3)?;
for _ in 0..2 {
let tmp = res.remove(0).result?;
@ -1476,7 +1476,7 @@ async fn select_with_in_operator_uniq_index() -> Result<(), Error> {
let mut res = dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 8);
skip_ok(&mut res, 2);
skip_ok(&mut res, 2)?;
let tmp = res.remove(0).result?;
let val = Value::parse(r#"[]"#);
@ -1549,7 +1549,7 @@ async fn select_with_in_operator_multiple_indexes() -> Result<(), Error> {
let mut res = dbs.execute(sql, &ses, None).await?;
//
assert_eq!(res.len(), 17);
skip_ok(&mut res, 9);
skip_ok(&mut res, 9)?;
//
let tmp = res.remove(0).result?;
let val = Value::parse(
@ -1933,7 +1933,7 @@ async fn select_with_record_id_link_no_index() -> Result<(), Error> {
let mut res = dbs.execute(&sql, &ses, None).await?;
//
assert_eq!(res.len(), 8);
skip_ok(&mut res, 6);
skip_ok(&mut res, 6)?;
//
let tmp = res.remove(0).result?;
let val = Value::parse(
@ -1992,7 +1992,7 @@ async fn select_with_record_id_link_index() -> Result<(), Error> {
let mut res = dbs.execute(&sql, &ses, None).await?;
//
assert_eq!(res.len(), 10);
skip_ok(&mut res, 8);
skip_ok(&mut res, 8)?;
//
let expected = Value::parse(
r#"[
@ -2057,7 +2057,7 @@ async fn select_with_record_id_link_unique_index() -> Result<(), Error> {
let mut res = dbs.execute(&sql, &ses, None).await?;
//
assert_eq!(res.len(), 10);
skip_ok(&mut res, 8);
skip_ok(&mut res, 8)?;
//
let expected = Value::parse(
r#"[
@ -2121,7 +2121,7 @@ async fn select_with_record_id_link_unique_remote_index() -> Result<(), Error> {
let mut res = dbs.execute(&sql, &ses, None).await?;
//
assert_eq!(res.len(), 10);
skip_ok(&mut res, 8);
skip_ok(&mut res, 8)?;
//
let expected = Value::parse(
r#"[
@ -2188,7 +2188,7 @@ async fn select_with_record_id_link_full_text_index() -> Result<(), Error> {
let mut res = dbs.execute(&sql, &ses, None).await?;
assert_eq!(res.len(), 9);
skip_ok(&mut res, 7);
skip_ok(&mut res, 7)?;
//
let tmp = res.remove(0).result?;
let val = Value::parse(
@ -2245,7 +2245,7 @@ async fn select_with_record_id_link_full_text_no_record_index() -> Result<(), Er
let mut res = dbs.execute(&sql, &ses, None).await?;
assert_eq!(res.len(), 8);
skip_ok(&mut res, 6);
skip_ok(&mut res, 6)?;
//
let tmp = res.remove(0).result?;
let val = Value::parse(
@ -2313,7 +2313,7 @@ async fn select_with_record_id_index() -> Result<(), Error> {
);
//
assert_eq!(res.len(), 15);
skip_ok(&mut res, 2);
skip_ok(&mut res, 2)?;
//
for t in ["CONTAINS", "CONTAINSANY", "IN"] {
let tmp = res.remove(0).result?;
@ -2345,7 +2345,7 @@ async fn select_with_record_id_index() -> Result<(), Error> {
assert_eq!(format!("{:#}", tmp), format!("{:#}", val));
}
//
skip_ok(&mut res, 1);
skip_ok(&mut res, 1)?;
// CONTAINS
let tmp = res.remove(0).result?;
assert_eq!(format!("{:#}", tmp), format!("{:#}", expected));
@ -2450,7 +2450,7 @@ async fn select_with_exact_operator() -> Result<(), Error> {
let mut res = dbs.execute(&sql, &ses, None).await?;
//
assert_eq!(res.len(), 8);
skip_ok(&mut res, 4);
skip_ok(&mut res, 4)?;
//
let tmp = res.remove(0).result?;
let val = Value::parse(
@ -2553,7 +2553,7 @@ async fn select_with_non_boolean_expression() -> Result<(), Error> {
let mut res = dbs.execute(&sql, &ses, None).await?;
//
assert_eq!(res.len(), 15);
skip_ok(&mut res, 5);
skip_ok(&mut res, 5)?;
//
for i in 0..5 {
let tmp = res.remove(0).result?;

View file

@ -133,7 +133,7 @@ async fn define_foreign_table_no_doubles() -> Result<(), Error> {
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 7);
//
skip_ok(res, 5);
skip_ok(res, 5)?;
//
let tmp = res.remove(0).result?;
let val = Value::parse(
@ -218,11 +218,11 @@ async fn define_foreign_table_group(cond: bool, agr: &str) -> Result<(), Error>
let res = &mut dbs.execute(&sql, &ses, None).await?;
assert_eq!(res.len(), 29);
//
skip_ok(res, 2);
skip_ok(res, 2)?;
//
for i in 0..9 {
// Skip the UPDATE or DELETE statement
skip_ok(res, 1);
skip_ok(res, 1)?;
// Get the computed result
let comp = res.remove(0).result?;
// Get the projected result

View file

@ -1,6 +1,7 @@
mod parse;
use parse::Parse;
mod helpers;
use crate::helpers::Test;
use helpers::new_ds;
use surrealdb::dbs::Session;
use surrealdb::err::Error;
@ -196,127 +197,87 @@ async fn strict_typing_none_null() -> Result<(), Error> {
UPDATE person:test SET name = NULL;
UPDATE person:test SET name = NONE;
--
REMOVE TABLE person;
DEFINE TABLE person SCHEMAFULL;
DEFINE FIELD name ON TABLE person TYPE option<string | null>;
UPDATE person:test SET name = 'Tobie';
UPDATE person:test SET name = NULL;
UPDATE person:test SET name = NONE;
--
REMOVE TABLE person;
DEFINE TABLE person SCHEMAFULL;
DEFINE FIELD name ON TABLE person TYPE string | null;
UPDATE person:test SET name = 'Tobie';
UPDATE person:test SET name = NULL;
UPDATE person:test SET name = NONE;
";
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(), 15);
let mut t = Test::new(sql).await?;
//
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(
t.skip_ok(2)?;
t.expect_val(
"[
{
id: person:test,
name: 'Tobie',
}
]",
);
assert_eq!(tmp, val);
//
let tmp = res.remove(0).result;
assert!(matches!(
tmp.err(),
Some(e) if e.to_string() == "Found NULL for field `name`, with record `person:test`, but expected a option<string>"
));
//
let tmp = res.remove(0).result?;
let val = Value::parse(
)?;
t.expect_error(
"Found NULL for field `name`, with record `person:test`, but expected a option<string>",
)?;
t.expect_val(
"[
{
id: person:test,
}
]",
);
assert_eq!(tmp, val);
)?;
//
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(
t.skip_ok(3)?;
t.expect_val(
"[
{
id: person:test,
name: 'Tobie',
}
]",
);
assert_eq!(tmp, val);
//
let tmp = res.remove(0).result?;
let val = Value::parse(
)?;
t.expect_val(
"[
{
id: person:test,
name: NULL,
}
]",
);
assert_eq!(tmp, val);
//
let tmp = res.remove(0).result?;
let val = Value::parse(
)?;
t.expect_val(
"[
{
id: person:test,
}
]",
);
assert_eq!(tmp, val);
)?;
//
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(
t.skip_ok(3)?;
t.expect_val(
"[
{
id: person:test,
name: 'Tobie',
}
]",
);
assert_eq!(tmp, val);
//
let tmp = res.remove(0).result?;
let val = Value::parse(
)?;
t.expect_val(
"[
{
id: person:test,
name: NULL,
}
]",
);
assert_eq!(tmp, val);
//
let tmp = res.remove(0).result;
assert!(matches!(
tmp.err(),
Some(e) if e.to_string() == "Found NONE for field `name`, with record `person:test`, but expected a string | null"
));
)?;
t.expect_error(
"Found NONE for field `name`, with record `person:test`, but expected a string | null",
)?;
//
Ok(())
}

View file

@ -1,6 +1,7 @@
mod parse;
use parse::Parse;
mod helpers;
use crate::helpers::Test;
use helpers::new_ds;
use surrealdb::dbs::Session;
use surrealdb::err::Error;
@ -175,34 +176,23 @@ async fn update_complex_with_input() -> Result<(), Error> {
TYPE array
ASSERT array::len($value) > 0
;
REMOVE FIELD images.* ON product;
DEFINE FIELD images.* ON product TYPE string
VALUE string::trim($input)
ASSERT $input AND string::len($value) > 0
;
CREATE product:test SET images = [' test.png '];
";
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(), 3);
//
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(
let mut t = Test::new(sql).await?;
t.skip_ok(3)?;
t.expect_val(
"[
{
id: product:test,
images: ['test.png'],
}
]",
);
assert_eq!(tmp, val);
//
)?;
Ok(())
}

View file

@ -170,7 +170,7 @@ async fn select_where_brute_force_knn() -> Result<(), Error> {
let res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 7);
//
skip_ok(res, 4);
skip_ok(res, 4)?;
//
let tmp = res.remove(0).result?;
let val = Value::parse(
@ -229,8 +229,8 @@ async fn select_where_hnsw_knn() -> Result<(), Error> {
SELECT id, vector::distance::knn() AS dist FROM pts WHERE point <|2,EUCLIDEAN|> $pt;
SELECT id, vector::distance::knn() AS dist FROM pts WHERE point <|2,EUCLIDEAN|> $pt EXPLAIN;
";
let mut t = Test::try_new(sql).await?;
t.skip_ok(5);
let mut t = Test::new(sql).await?;
t.skip_ok(5)?;
// KNN result with HNSW index
t.expect_val(
"[
@ -243,7 +243,7 @@ async fn select_where_hnsw_knn() -> Result<(), Error> {
dist: 4f
}
]",
);
)?;
// Explains KNN with HNSW index
t.expect_val(
"[
@ -265,7 +265,7 @@ async fn select_where_hnsw_knn() -> Result<(), Error> {
operation: 'Collector'
}
]",
);
)?;
// KNN result with brute force
t.expect_val(
"[
@ -278,7 +278,7 @@ async fn select_where_hnsw_knn() -> Result<(), Error> {
dist: 4f
}
]",
);
)?;
// Explain KNN with brute force
t.expect_val(
"[
@ -301,7 +301,7 @@ async fn select_where_hnsw_knn() -> Result<(), Error> {
operation: 'Collector'
}
]",
);
)?;
Ok(())
}
@ -331,7 +331,7 @@ async fn select_mtree_knn_with_condition() -> Result<(), Error> {
let mut res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 5);
//
skip_ok(&mut res, 3);
skip_ok(&mut res, 3)?;
//
let tmp = res.remove(0).result?;
let val = Value::parse(
@ -403,7 +403,7 @@ async fn select_hnsw_knn_with_condition() -> Result<(), Error> {
let mut res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 5);
//
skip_ok(&mut res, 3);
skip_ok(&mut res, 3)?;
//
let tmp = res.remove(0).result?;
let val = Value::parse(
@ -474,7 +474,7 @@ async fn select_bruteforce_knn_with_condition() -> Result<(), Error> {
let mut res = &mut dbs.execute(sql, &ses, None).await?;
assert_eq!(res.len(), 4);
//
skip_ok(&mut res, 2);
skip_ok(&mut res, 2)?;
//
let tmp = res.remove(0).result?;
let val = Value::parse(