Ensure graph edges are purged correctly when deleted

This commit is contained in:
Tobie Morgan Hitchcock 2022-06-17 23:55:09 +01:00
parent 27f011d13c
commit 20c4e03446
8 changed files with 70 additions and 22 deletions

View file

@ -12,6 +12,7 @@ use crate::sql::part::Part;
use crate::sql::table::Table;
use crate::sql::thing::Thing;
use crate::sql::value::Value;
use async_recursion::async_recursion;
use std::cmp::Ordering;
use std::collections::BTreeMap;
use std::mem;
@ -329,6 +330,7 @@ impl Iterator {
}
#[cfg(not(feature = "parallel"))]
#[cfg_attr(not(feature = "parallel"), async_recursion(?Send))]
async fn iterate(
&mut self,
ctx: &Context<'_>,
@ -345,6 +347,7 @@ impl Iterator {
}
#[cfg(feature = "parallel")]
#[cfg_attr(feature = "parallel", async_recursion)]
async fn iterate(
&mut self,
ctx: &Context<'_>,

View file

@ -5,12 +5,14 @@ use crate::dbs::Transaction;
use crate::dbs::Workable;
use crate::doc::Document;
use crate::err::Error;
use crate::sql::paths::IN;
use crate::sql::paths::OUT;
use crate::sql::Dir;
impl<'a> Document<'a> {
pub async fn edges(
&self,
_ctx: &Context<'_>,
&mut self,
ctx: &Context<'_>,
opt: &Options,
txn: &Transaction,
_stm: &Statement<'_>,
@ -27,18 +29,23 @@ impl<'a> Document<'a> {
let rid = self.id.as_ref().unwrap();
// Store the record edges
if let Workable::Relate(l, r) = &self.extras {
// Get temporary edge references
let (ref o, ref i) = (Dir::Out, Dir::In);
// Store the left pointer edge
let key = crate::key::graph::new(opt.ns(), opt.db(), &l.tb, &l.id, &Dir::Out, rid);
let key = crate::key::graph::new(opt.ns(), opt.db(), &l.tb, &l.id, o, rid);
run.set(key, vec![]).await?;
// Store the left inner edge
let key = crate::key::graph::new(opt.ns(), opt.db(), &rid.tb, &rid.id, &Dir::In, l);
let key = crate::key::graph::new(opt.ns(), opt.db(), &rid.tb, &rid.id, i, l);
run.set(key, vec![]).await?;
// Store the right inner edge
let key = crate::key::graph::new(opt.ns(), opt.db(), &rid.tb, &rid.id, &Dir::Out, r);
let key = crate::key::graph::new(opt.ns(), opt.db(), &rid.tb, &rid.id, o, r);
run.set(key, vec![]).await?;
// Store the right pointer edge
let key = crate::key::graph::new(opt.ns(), opt.db(), &r.tb, &r.id, &Dir::In, rid);
let key = crate::key::graph::new(opt.ns(), opt.db(), &r.tb, &r.id, i, rid);
run.set(key, vec![]).await?;
// Store the edges on the record
self.current.to_mut().set(ctx, opt, txn, &*IN, l.clone().into()).await?;
self.current.to_mut().set(ctx, opt, txn, &*OUT, r.clone().into()).await?;
}
// Carry on
Ok(())

View file

@ -4,11 +4,18 @@ use crate::dbs::Statement;
use crate::dbs::Transaction;
use crate::doc::Document;
use crate::err::Error;
use crate::sql::dir::Dir;
use crate::sql::edges::Edges;
use crate::sql::paths::IN;
use crate::sql::paths::OUT;
use crate::sql::statements::DeleteStatement;
use crate::sql::table::Tables;
use crate::sql::value::{Value, Values};
impl<'a> Document<'a> {
pub async fn purge(
&self,
_ctx: &Context<'_>,
ctx: &Context<'_>,
opt: &Options,
txn: &Transaction,
_stm: &Statement<'_>,
@ -30,10 +37,40 @@ impl<'a> Document<'a> {
// Purge the record data
let key = crate::key::thing::new(opt.ns(), opt.db(), &rid.tb, &rid.id);
run.del(key).await?;
// Remove the graph data
let beg = crate::key::graph::prefix(opt.ns(), opt.db(), &rid.tb, &rid.id);
let end = crate::key::graph::suffix(opt.ns(), opt.db(), &rid.tb, &rid.id);
run.delr(beg..end, u32::MAX).await?;
// Purge the record edges
match (self.initial.pick(&*IN), self.initial.pick(&*OUT)) {
(Value::Thing(ref l), Value::Thing(ref r)) => {
// Get temporary edge references
let (ref o, ref i) = (Dir::Out, Dir::In);
// Purge the left pointer edge
let key = crate::key::graph::new(opt.ns(), opt.db(), &l.tb, &l.id, o, rid);
run.del(key).await?;
// Purge the left inner edge
let key = crate::key::graph::new(opt.ns(), opt.db(), &rid.tb, &rid.id, i, l);
run.del(key).await?;
// Purge the right inner edge
let key = crate::key::graph::new(opt.ns(), opt.db(), &rid.tb, &rid.id, o, r);
run.del(key).await?;
// Purge the right pointer edge
let key = crate::key::graph::new(opt.ns(), opt.db(), &r.tb, &r.id, i, rid);
run.del(key).await?;
}
_ => {
// Release the transaction
drop(run);
// Setup the delete statement
let stm = DeleteStatement {
what: Values(vec![Value::from(Edges {
dir: Dir::Both,
from: rid.clone(),
what: Tables::default(),
})]),
..DeleteStatement::default()
};
// Execute the delete statement
stm.compute(ctx, opt, txn, None).await?;
}
}
// Carry on
Ok(())
}

View file

@ -34,6 +34,7 @@ pub(crate) mod output;
pub(crate) mod param;
pub(crate) mod parser;
pub(crate) mod part;
pub(crate) mod paths;
pub(crate) mod permission;
pub(crate) mod query;
pub(crate) mod regex;

8
lib/src/sql/paths.rs Normal file
View file

@ -0,0 +1,8 @@
use crate::sql::part::Part;
use once_cell::sync::Lazy;
pub static ID: Lazy<[Part; 1]> = Lazy::new(|| [Part::from("id")]);
pub static IN: Lazy<[Part; 1]> = Lazy::new(|| [Part::from("in")]);
pub static OUT: Lazy<[Part; 1]> = Lazy::new(|| [Part::from("out")]);

View file

@ -2,12 +2,9 @@ use crate::ctx::Context;
use crate::dbs::Options;
use crate::dbs::Transaction;
use crate::err::Error;
use crate::sql::part::Part;
use crate::sql::paths::ID;
use crate::sql::thing::Thing;
use crate::sql::value::Value;
use once_cell::sync::Lazy;
static ID: Lazy<[Part; 1]> = Lazy::new(|| [Part::from("id")]);
impl Value {
pub async fn def(

View file

@ -6,13 +6,11 @@ use crate::sql::edges::Edges;
use crate::sql::field::{Field, Fields};
use crate::sql::part::Next;
use crate::sql::part::Part;
use crate::sql::paths::ID;
use crate::sql::statements::select::SelectStatement;
use crate::sql::value::{Value, Values};
use async_recursion::async_recursion;
use futures::future::try_join_all;
use once_cell::sync::Lazy;
static ID: Lazy<[Part; 1]> = Lazy::new(|| [Part::from("id")]);
impl Value {
#[cfg_attr(feature = "parallel", async_recursion)]

View file

@ -1,12 +1,9 @@
use crate::err::Error;
use crate::sql::id::Id;
use crate::sql::part::Part;
use crate::sql::paths::ID;
use crate::sql::table::Table;
use crate::sql::thing::Thing;
use crate::sql::value::Value;
use once_cell::sync::Lazy;
static ID: Lazy<[Part; 1]> = Lazy::new(|| [Part::from("id")]);
impl Value {
pub fn retable(&self, val: &Table) -> Result<Thing, Error> {