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

View file

@ -5,12 +5,14 @@ use crate::dbs::Transaction;
use crate::dbs::Workable; use crate::dbs::Workable;
use crate::doc::Document; use crate::doc::Document;
use crate::err::Error; use crate::err::Error;
use crate::sql::paths::IN;
use crate::sql::paths::OUT;
use crate::sql::Dir; use crate::sql::Dir;
impl<'a> Document<'a> { impl<'a> Document<'a> {
pub async fn edges( pub async fn edges(
&self, &mut self,
_ctx: &Context<'_>, ctx: &Context<'_>,
opt: &Options, opt: &Options,
txn: &Transaction, txn: &Transaction,
_stm: &Statement<'_>, _stm: &Statement<'_>,
@ -27,18 +29,23 @@ impl<'a> Document<'a> {
let rid = self.id.as_ref().unwrap(); let rid = self.id.as_ref().unwrap();
// Store the record edges // Store the record edges
if let Workable::Relate(l, r) = &self.extras { 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 // 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?; run.set(key, vec![]).await?;
// Store the left inner edge // 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?; run.set(key, vec![]).await?;
// Store the right inner edge // 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?; run.set(key, vec![]).await?;
// Store the right pointer edge // 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?; 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 // Carry on
Ok(()) Ok(())

View file

@ -4,11 +4,18 @@ use crate::dbs::Statement;
use crate::dbs::Transaction; use crate::dbs::Transaction;
use crate::doc::Document; use crate::doc::Document;
use crate::err::Error; 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> { impl<'a> Document<'a> {
pub async fn purge( pub async fn purge(
&self, &self,
_ctx: &Context<'_>, ctx: &Context<'_>,
opt: &Options, opt: &Options,
txn: &Transaction, txn: &Transaction,
_stm: &Statement<'_>, _stm: &Statement<'_>,
@ -30,10 +37,40 @@ impl<'a> Document<'a> {
// Purge the record data // Purge the record data
let key = crate::key::thing::new(opt.ns(), opt.db(), &rid.tb, &rid.id); let key = crate::key::thing::new(opt.ns(), opt.db(), &rid.tb, &rid.id);
run.del(key).await?; run.del(key).await?;
// Remove the graph data // Purge the record edges
let beg = crate::key::graph::prefix(opt.ns(), opt.db(), &rid.tb, &rid.id); match (self.initial.pick(&*IN), self.initial.pick(&*OUT)) {
let end = crate::key::graph::suffix(opt.ns(), opt.db(), &rid.tb, &rid.id); (Value::Thing(ref l), Value::Thing(ref r)) => {
run.delr(beg..end, u32::MAX).await?; // 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 // Carry on
Ok(()) Ok(())
} }

View file

@ -34,6 +34,7 @@ pub(crate) mod output;
pub(crate) mod param; pub(crate) mod param;
pub(crate) mod parser; pub(crate) mod parser;
pub(crate) mod part; pub(crate) mod part;
pub(crate) mod paths;
pub(crate) mod permission; pub(crate) mod permission;
pub(crate) mod query; pub(crate) mod query;
pub(crate) mod regex; 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::Options;
use crate::dbs::Transaction; use crate::dbs::Transaction;
use crate::err::Error; use crate::err::Error;
use crate::sql::part::Part; use crate::sql::paths::ID;
use crate::sql::thing::Thing; use crate::sql::thing::Thing;
use crate::sql::value::Value; use crate::sql::value::Value;
use once_cell::sync::Lazy;
static ID: Lazy<[Part; 1]> = Lazy::new(|| [Part::from("id")]);
impl Value { impl Value {
pub async fn def( pub async fn def(

View file

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

View file

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