Fix bug where records couldn’t be updated after defining an index

Closes #57
This commit is contained in:
Tobie Morgan Hitchcock 2022-08-25 14:49:33 +01:00
parent 9c6f178536
commit 56d3b0e861
5 changed files with 196 additions and 6 deletions

View file

@ -29,14 +29,16 @@ pub struct Options {
pub force: bool,
// Should we run permissions checks?
pub perms: bool,
// Should we error if tables don't exist?
pub strict: bool,
// Should we process field queries?
pub fields: bool,
// Should we process event queries?
pub events: bool,
// Should we process table queries?
pub tables: bool,
// Should we error if tables don't exist?
pub strict: bool,
// Should we process index queries?
pub indexes: bool,
// Should we process function futures?
pub futures: bool,
}
@ -58,10 +60,11 @@ impl Options {
perms: true,
debug: false,
force: false,
strict: false,
fields: true,
events: true,
tables: true,
strict: false,
indexes: true,
futures: false,
auth: Arc::new(auth),
}
@ -158,6 +161,17 @@ impl Options {
}
}
// Create a new Options object for a subquery
pub fn indexes(&self, v: bool) -> Options {
Options {
auth: self.auth.clone(),
ns: self.ns.clone(),
db: self.db.clone(),
indexes: v,
..*self
}
}
// Create a new Options object for a subquery
pub fn import(&self, v: bool) -> Options {
Options {

View file

@ -15,6 +15,10 @@ impl<'a> Document<'a> {
txn: &Transaction,
stm: &Statement<'_>,
) -> Result<(), Error> {
// Check fields
if !opt.fields {
return Ok(());
}
// Loop through all field statements
for fd in self.fd(opt, txn).await?.iter() {
// Loop over each field in document

View file

@ -14,6 +14,10 @@ impl<'a> Document<'a> {
txn: &Transaction,
_stm: &Statement<'_>,
) -> Result<(), Error> {
// Check events
if !opt.indexes {
return Ok(());
}
// Check if forced
if !opt.force && !self.changed() {
return Ok(());
@ -50,7 +54,7 @@ impl<'a> Document<'a> {
if self.initial.is_some() {
#[rustfmt::skip]
let key = crate::key::index::new(opt.ns(), opt.db(), &ix.what, &ix.name, o, None);
run.delc(key, Some(rid)).await?;
let _ = run.delc(key, Some(rid)).await; // Ignore this error
}
// Create the new index data
if self.current.is_some() {
@ -69,7 +73,7 @@ impl<'a> Document<'a> {
if self.initial.is_some() {
#[rustfmt::skip]
let key = crate::key::index::new(opt.ns(), opt.db(), &ix.what, &ix.name, o, Some(&rid.id));
run.delc(key, Some(rid)).await?;
let _ = run.delc(key, Some(rid)).await; // Ignore this error
}
// Create the new index data
if self.current.is_some() {

View file

@ -599,8 +599,14 @@ impl DefineTableStatement {
}
// Release the transaction
drop(run);
// Force tables to reprocess
// Force queries to run
let opt = &opt.force(true);
// Don't process field queries
let opt = &opt.fields(false);
// Don't process event queries
let opt = &opt.events(false);
// Don't process index queries
let opt = &opt.indexes(false);
// Process each foreign table
for v in view.what.0.iter() {
// Process the view data
@ -983,6 +989,14 @@ impl DefineIndexStatement {
run.delr(beg..end, u32::MAX).await?;
// Release the transaction
drop(run);
// Force queries to run
let opt = &opt.force(true);
// Don't process field queries
let opt = &opt.fields(false);
// Don't process event queries
let opt = &opt.events(false);
// Don't process table queries
let opt = &opt.tables(false);
// Update the index data
let stm = UpdateStatement {
what: Values(vec![Value::Table(self.what.clone().into())]),

View file

@ -472,6 +472,56 @@ async fn define_statement_field_type_value_assert() -> Result<(), Error> {
Ok(())
}
#[tokio::test]
async fn define_statement_index_single_simple() -> Result<(), Error> {
let sql = "
CREATE user:1 SET age = 23;
CREATE user:2 SET age = 10;
DEFINE INDEX test ON user FIELDS age;
DEFINE INDEX test ON user COLUMNS age;
INFO FOR TABLE user;
UPDATE user:1 SET age = 24;
UPDATE user:2 SET age = 11;
";
let dbs = Datastore::new("memory").await?;
let ses = Session::for_kv().with_ns("test").with_db("test");
let res = &mut dbs.execute(&sql, &ses, None, false).await?;
assert_eq!(res.len(), 7);
//
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?;
let val = Value::parse(
"{
ev: {},
fd: {},
ft: {},
ix: { test: 'DEFINE INDEX test ON user FIELDS age' },
}",
);
assert_eq!(tmp, val);
//
let tmp = res.remove(0).result?;
let val = Value::parse("[{ id: user:1, age: 24 }]");
assert_eq!(tmp, val);
//
let tmp = res.remove(0).result?;
let val = Value::parse("[{ id: user:2, age: 11 }]");
assert_eq!(tmp, val);
//
Ok(())
}
#[tokio::test]
async fn define_statement_index_single() -> Result<(), Error> {
let sql = "
@ -665,3 +715,107 @@ async fn define_statement_index_multiple_unique() -> Result<(), Error> {
//
Ok(())
}
#[tokio::test]
async fn define_statement_index_single_unique_existing() -> Result<(), Error> {
let sql = "
CREATE user:1 SET email = 'info@surrealdb.com';
CREATE user:2 SET email = 'test@surrealdb.com';
CREATE user:3 SET email = 'test@surrealdb.com';
DEFINE INDEX test ON user FIELDS email UNIQUE;
DEFINE INDEX test ON user COLUMNS email UNIQUE;
INFO FOR TABLE user;
";
let dbs = Datastore::new("memory").await?;
let ses = Session::for_kv().with_ns("test").with_db("test");
let res = &mut dbs.execute(&sql, &ses, None, false).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;
assert!(matches!(
tmp.err(),
Some(e) if e.to_string() == "Database index `test` already contains `user:3`"
));
//
let tmp = res.remove(0).result;
assert!(matches!(
tmp.err(),
Some(e) if e.to_string() == "Database index `test` already contains `user:3`"
));
//
let tmp = res.remove(0).result?;
let val = Value::parse(
"{
ev: {},
fd: {},
ft: {},
ix: {},
}",
);
assert_eq!(tmp, val);
//
Ok(())
}
#[tokio::test]
async fn define_statement_index_multiple_unique_existing() -> Result<(), Error> {
let sql = "
CREATE user:1 SET account = 'apple', email = 'test@surrealdb.com';
CREATE user:2 SET account = 'tesla', email = 'test@surrealdb.com';
CREATE user:3 SET account = 'apple', email = 'test@surrealdb.com';
CREATE user:4 SET account = 'tesla', email = 'test@surrealdb.com';
DEFINE INDEX test ON user FIELDS account, email UNIQUE;
DEFINE INDEX test ON user COLUMNS account, email UNIQUE;
INFO FOR TABLE user;
";
let dbs = Datastore::new("memory").await?;
let ses = Session::for_kv().with_ns("test").with_db("test");
let res = &mut dbs.execute(&sql, &ses, None, false).await?;
assert_eq!(res.len(), 7);
//
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(),
Some(e) if e.to_string() == "Database index `test` already contains `user:3`"
));
//
let tmp = res.remove(0).result;
assert!(matches!(
tmp.err(),
Some(e) if e.to_string() == "Database index `test` already contains `user:3`"
));
//
let tmp = res.remove(0).result?;
let val = Value::parse(
"{
ev: {},
fd: {},
ft: {},
ix: {},
}",
);
assert_eq!(tmp, val);
//
Ok(())
}