Ensure internal edge record fields can not be modified

Closes #1726
This commit is contained in:
Tobie Morgan Hitchcock 2023-03-30 19:30:46 +01:00
parent 494203d358
commit cd5d452e5b
7 changed files with 133 additions and 24 deletions

View file

@ -20,6 +20,8 @@ impl<'a> Document<'a> {
self.alter(ctx, opt, txn, stm).await?; self.alter(ctx, opt, txn, stm).await?;
// Merge fields data // Merge fields data
self.field(ctx, opt, txn, stm).await?; self.field(ctx, opt, txn, stm).await?;
// Reset fields data
self.reset(ctx, opt, txn, stm).await?;
// Clean fields data // Clean fields data
self.clean(ctx, opt, txn, stm).await?; self.clean(ctx, opt, txn, stm).await?;
// Check if allowed // Check if allowed

View file

@ -24,6 +24,8 @@ impl<'a> Document<'a> {
self.merge(ctx, opt, txn, stm).await?; self.merge(ctx, opt, txn, stm).await?;
// Merge fields data // Merge fields data
self.field(ctx, opt, txn, stm).await?; self.field(ctx, opt, txn, stm).await?;
// Reset fields data
self.reset(ctx, opt, txn, stm).await?;
// Clean fields data // Clean fields data
self.clean(ctx, opt, txn, stm).await?; self.clean(ctx, opt, txn, stm).await?;
// Check if allowed // Check if allowed
@ -49,6 +51,8 @@ impl<'a> Document<'a> {
self.alter(ctx, opt, txn, stm).await?; self.alter(ctx, opt, txn, stm).await?;
// Merge fields data // Merge fields data
self.field(ctx, opt, txn, stm).await?; self.field(ctx, opt, txn, stm).await?;
// Reset fields data
self.reset(ctx, opt, txn, stm).await?;
// Clean fields data // Clean fields data
self.clean(ctx, opt, txn, stm).await?; self.clean(ctx, opt, txn, stm).await?;
// Check if allowed // Check if allowed

View file

@ -3,27 +3,30 @@ pub(crate) use self::document::*;
#[cfg(not(target_arch = "wasm32"))] #[cfg(not(target_arch = "wasm32"))]
mod compute; mod compute;
mod allow; mod document; // The entry point for a document to be processed
mod alter;
mod check; mod create; // Processes a CREATE statement for this document
mod clean; mod delete; // Processes a DELETE statement for this document
mod create; mod insert; // Processes a INSERT statement for this document
mod delete; mod relate; // Processes a RELATE statement for this document
mod document; mod select; // Processes a SELECT statement for this document
mod edges; mod update; // Processes a UPDATE statement for this document
mod empty;
mod erase; mod allow; // Checks whether the query can access this document
mod event; mod alter; // Modifies and updates the fields in this document
mod exist; mod check; // Checks whether the WHERE clauses matches this document
mod field; mod clean; // Ensures records adhere to the table schema
mod index; mod edges; // Attempts to store the edge data for this document
mod insert; mod empty; // Checks whether the specified document actually exists
mod lives; mod erase; // Removes all content and field data for this document
mod merge; mod event; // Processes any table events relevant for this document
mod pluck; mod exist; // Checks whether the specified document actually exists
mod purge; mod field; // Processes any schema-defined fields for this document
mod relate; mod index; // Attempts to store the index data for this document
mod select; mod lives; // Processes any live queries relevant for this document
mod store; mod merge; // Merges any field changes for an INSERT statement
mod table; mod pluck; // Pulls the projected expressions from the document
mod update; mod purge; // Deletes this document, and any edges or indexes
mod reset; // Resets internal fields which were set for this document
mod store; // Writes the document content to the storage engine
mod table; // Processes any foreign tables relevant for this document

View file

@ -20,6 +20,8 @@ impl<'a> Document<'a> {
self.alter(ctx, opt, txn, stm).await?; self.alter(ctx, opt, txn, stm).await?;
// Merge fields data // Merge fields data
self.field(ctx, opt, txn, stm).await?; self.field(ctx, opt, txn, stm).await?;
// Reset fields data
self.reset(ctx, opt, txn, stm).await?;
// Clean fields data // Clean fields data
self.clean(ctx, opt, txn, stm).await?; self.clean(ctx, opt, txn, stm).await?;
// Check if allowed // Check if allowed

33
lib/src/doc/reset.rs Normal file
View file

@ -0,0 +1,33 @@
use crate::ctx::Context;
use crate::dbs::Options;
use crate::dbs::Statement;
use crate::dbs::Transaction;
use crate::doc::Document;
use crate::err::Error;
use crate::sql::paths::EDGE;
use crate::sql::paths::IN;
use crate::sql::paths::OUT;
use crate::sql::value::Value;
impl<'a> Document<'a> {
pub async fn reset(
&mut self,
ctx: &Context<'_>,
opt: &Options,
txn: &Transaction,
_stm: &Statement<'_>,
) -> Result<(), Error> {
// Get the record id
let rid = self.id.as_ref().unwrap();
// Set default field values
self.current.to_mut().def(ctx, opt, txn, rid).await?;
// Ensure edge fields are reset
if self.initial.pick(&*EDGE).is_true() {
self.current.to_mut().put(&*EDGE, Value::True);
self.current.to_mut().put(&*IN, self.initial.pick(&*IN));
self.current.to_mut().put(&*OUT, self.initial.pick(&*OUT));
}
// Carry on
Ok(())
}
}

View file

@ -22,6 +22,8 @@ impl<'a> Document<'a> {
self.alter(ctx, opt, txn, stm).await?; self.alter(ctx, opt, txn, stm).await?;
// Merge fields data // Merge fields data
self.field(ctx, opt, txn, stm).await?; self.field(ctx, opt, txn, stm).await?;
// Reset fields data
self.reset(ctx, opt, txn, stm).await?;
// Clean fields data // Clean fields data
self.clean(ctx, opt, txn, stm).await?; self.clean(ctx, opt, txn, stm).await?;
// Check if allowed // Check if allowed

View file

@ -39,3 +39,66 @@ async fn relate_with_parameters() -> Result<(), Error> {
// //
Ok(()) Ok(())
} }
#[tokio::test]
async fn relate_and_overwrite() -> Result<(), Error> {
let sql = "
LET $tobie = person:tobie;
LET $jaime = person:jaime;
RELATE $tobie->knows->$jaime SET id = knows:test;
UPDATE knows:test CONTENT { test: true };
SELECT * FROM knows:test;
";
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(), 5);
//
let tmp = res.remove(0).result?;
let val = Value::None;
assert_eq!(tmp, val);
//
let tmp = res.remove(0).result?;
let val = Value::None;
assert_eq!(tmp, val);
//
let tmp = res.remove(0).result?;
let val = Value::parse(
"[
{
id: knows:test,
in: person:tobie,
out: person:jaime,
}
]",
);
assert_eq!(tmp, val);
//
let tmp = res.remove(0).result?;
let val = Value::parse(
"[
{
id: knows:test,
in: person:tobie,
out: person:jaime,
test: true,
}
]",
);
assert_eq!(tmp, val);
//
let tmp = res.remove(0).result?;
let val = Value::parse(
"[
{
id: knows:test,
in: person:tobie,
out: person:jaime,
test: true,
}
]",
);
assert_eq!(tmp, val);
//
Ok(())
}