From cd5d452e5ba84ce42d9acf601a0c6f842a4f4497 Mon Sep 17 00:00:00 2001 From: Tobie Morgan Hitchcock Date: Thu, 30 Mar 2023 19:30:46 +0100 Subject: [PATCH] Ensure internal edge record fields can not be modified Closes #1726 --- lib/src/doc/create.rs | 2 ++ lib/src/doc/insert.rs | 4 +++ lib/src/doc/mod.rs | 51 ++++++++++++++++++----------------- lib/src/doc/relate.rs | 2 ++ lib/src/doc/reset.rs | 33 +++++++++++++++++++++++ lib/src/doc/update.rs | 2 ++ lib/tests/relate.rs | 63 +++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 133 insertions(+), 24 deletions(-) create mode 100644 lib/src/doc/reset.rs diff --git a/lib/src/doc/create.rs b/lib/src/doc/create.rs index 2e90f5de..0b72fed7 100644 --- a/lib/src/doc/create.rs +++ b/lib/src/doc/create.rs @@ -20,6 +20,8 @@ impl<'a> Document<'a> { self.alter(ctx, opt, txn, stm).await?; // Merge fields data self.field(ctx, opt, txn, stm).await?; + // Reset fields data + self.reset(ctx, opt, txn, stm).await?; // Clean fields data self.clean(ctx, opt, txn, stm).await?; // Check if allowed diff --git a/lib/src/doc/insert.rs b/lib/src/doc/insert.rs index 8c164d1b..2cdfde3b 100644 --- a/lib/src/doc/insert.rs +++ b/lib/src/doc/insert.rs @@ -24,6 +24,8 @@ impl<'a> Document<'a> { self.merge(ctx, opt, txn, stm).await?; // Merge fields data self.field(ctx, opt, txn, stm).await?; + // Reset fields data + self.reset(ctx, opt, txn, stm).await?; // Clean fields data self.clean(ctx, opt, txn, stm).await?; // Check if allowed @@ -49,6 +51,8 @@ impl<'a> Document<'a> { self.alter(ctx, opt, txn, stm).await?; // Merge fields data self.field(ctx, opt, txn, stm).await?; + // Reset fields data + self.reset(ctx, opt, txn, stm).await?; // Clean fields data self.clean(ctx, opt, txn, stm).await?; // Check if allowed diff --git a/lib/src/doc/mod.rs b/lib/src/doc/mod.rs index 93d0a8c5..db71f947 100644 --- a/lib/src/doc/mod.rs +++ b/lib/src/doc/mod.rs @@ -3,27 +3,30 @@ pub(crate) use self::document::*; #[cfg(not(target_arch = "wasm32"))] mod compute; -mod allow; -mod alter; -mod check; -mod clean; -mod create; -mod delete; -mod document; -mod edges; -mod empty; -mod erase; -mod event; -mod exist; -mod field; -mod index; -mod insert; -mod lives; -mod merge; -mod pluck; -mod purge; -mod relate; -mod select; -mod store; -mod table; -mod update; +mod document; // The entry point for a document to be processed + +mod create; // Processes a CREATE statement for this document +mod delete; // Processes a DELETE statement for this document +mod insert; // Processes a INSERT statement for this document +mod relate; // Processes a RELATE statement for this document +mod select; // Processes a SELECT statement for this document +mod update; // Processes a UPDATE statement for this document + +mod allow; // Checks whether the query can access this document +mod alter; // Modifies and updates the fields in this document +mod check; // Checks whether the WHERE clauses matches this document +mod clean; // Ensures records adhere to the table schema +mod edges; // Attempts to store the edge data for this document +mod empty; // Checks whether the specified document actually exists +mod erase; // Removes all content and field data for this document +mod event; // Processes any table events relevant for this document +mod exist; // Checks whether the specified document actually exists +mod field; // Processes any schema-defined fields for this document +mod index; // Attempts to store the index data for this document +mod lives; // Processes any live queries relevant for this document +mod merge; // Merges any field changes for an INSERT statement +mod pluck; // Pulls the projected expressions from the document +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 diff --git a/lib/src/doc/relate.rs b/lib/src/doc/relate.rs index 6f36e665..085cf644 100644 --- a/lib/src/doc/relate.rs +++ b/lib/src/doc/relate.rs @@ -20,6 +20,8 @@ impl<'a> Document<'a> { self.alter(ctx, opt, txn, stm).await?; // Merge fields data self.field(ctx, opt, txn, stm).await?; + // Reset fields data + self.reset(ctx, opt, txn, stm).await?; // Clean fields data self.clean(ctx, opt, txn, stm).await?; // Check if allowed diff --git a/lib/src/doc/reset.rs b/lib/src/doc/reset.rs new file mode 100644 index 00000000..0d383e87 --- /dev/null +++ b/lib/src/doc/reset.rs @@ -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(()) + } +} diff --git a/lib/src/doc/update.rs b/lib/src/doc/update.rs index 553392e2..331ed608 100644 --- a/lib/src/doc/update.rs +++ b/lib/src/doc/update.rs @@ -22,6 +22,8 @@ impl<'a> Document<'a> { self.alter(ctx, opt, txn, stm).await?; // Merge fields data self.field(ctx, opt, txn, stm).await?; + // Reset fields data + self.reset(ctx, opt, txn, stm).await?; // Clean fields data self.clean(ctx, opt, txn, stm).await?; // Check if allowed diff --git a/lib/tests/relate.rs b/lib/tests/relate.rs index 144b9a4e..452e3ee0 100644 --- a/lib/tests/relate.rs +++ b/lib/tests/relate.rs @@ -39,3 +39,66 @@ async fn relate_with_parameters() -> Result<(), Error> { // 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(()) +}