From 819019ae758c77c5151cf2234d4de941c6e4105d Mon Sep 17 00:00:00 2001 From: Wisdom Ogwu Date: Mon, 20 Dec 2021 17:20:39 +0100 Subject: [PATCH 1/7] Written failing tests --- grovedb/src/lib.rs | 9 +++++++++ grovedb/src/tests.rs | 18 ++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/grovedb/src/lib.rs b/grovedb/src/lib.rs index 41d980832..77503b585 100644 --- a/grovedb/src/lib.rs +++ b/grovedb/src/lib.rs @@ -212,6 +212,15 @@ impl GroveDb { Ok(()) } + pub fn insert_if_not_exists( + &mut self, + path: &[&[u8]], + key: Vec, + mut element: subtree::Element, + ) -> Result<(), Error> { + Ok(()) + } + pub fn get(&self, path: &[&[u8]], key: &[u8]) -> Result { match self.get_raw(path, key)? { Element::Reference(reference_path) => self.follow_reference(reference_path), diff --git a/grovedb/src/tests.rs b/grovedb/src/tests.rs index 4b92ce4d8..5db0137e2 100644 --- a/grovedb/src/tests.rs +++ b/grovedb/src/tests.rs @@ -315,3 +315,21 @@ fn test_checkpoint() { Err(Error::InvalidPath(_)) )); } + +#[test] +fn test_insert_if_not_exists() { + let mut db = make_grovedb(); + + // First insertion + let result = db.insert_if_not_exists(&[TEST_LEAF], b"key1".to_vec(), Element::empty_tree()); + match result { + Ok(_) => (), + Err(_e) => panic!("First insertion should be a success") + } + + db.insert_if_not_exists(&[TEST_LEAF], b"key1".to_vec(), Element::empty_tree()); + match result { + Ok(_) => panic!("Second insertion for same key should not work"), + Err(_e) => (), + } +} From 5d7dff9cc76f1e9e3d3793fdbaf6e4e1f3e83930 Mon Sep 17 00:00:00 2001 From: Wisdom Ogwu Date: Mon, 20 Dec 2021 18:21:38 +0100 Subject: [PATCH 2/7] Implemented feature + test passing --- grovedb/src/lib.rs | 9 ++++++++- grovedb/src/tests.rs | 5 +++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/grovedb/src/lib.rs b/grovedb/src/lib.rs index 77503b585..716e4a54c 100644 --- a/grovedb/src/lib.rs +++ b/grovedb/src/lib.rs @@ -16,6 +16,8 @@ use storage::{ }; pub use subtree::Element; +use crate::Error::ElementAtPath; + /// Limit of possible indirections const MAX_REFERENCE_HOPS: usize = 10; /// A key to store serialized data about subtree prefixes to restore HADS @@ -38,6 +40,8 @@ pub enum Error { StorageError(#[from] PrefixedRocksDbStorageError), #[error("data corruption error: {0}")] CorruptedData(String), + #[error("element exists at path")] + ElementAtPath, } pub struct GroveDb { @@ -218,7 +222,10 @@ impl GroveDb { key: Vec, mut element: subtree::Element, ) -> Result<(), Error> { - Ok(()) + if self.get(path, &key).is_ok() { + return Err(ElementAtPath); + } + self.insert(path, key, element) } pub fn get(&self, path: &[&[u8]], key: &[u8]) -> Result { diff --git a/grovedb/src/tests.rs b/grovedb/src/tests.rs index 5db0137e2..87c3243f3 100644 --- a/grovedb/src/tests.rs +++ b/grovedb/src/tests.rs @@ -324,10 +324,11 @@ fn test_insert_if_not_exists() { let result = db.insert_if_not_exists(&[TEST_LEAF], b"key1".to_vec(), Element::empty_tree()); match result { Ok(_) => (), - Err(_e) => panic!("First insertion should be a success") + Err(_e) => panic!("First insertion should be a success"), } - db.insert_if_not_exists(&[TEST_LEAF], b"key1".to_vec(), Element::empty_tree()); + // Second insertion at same path + let result = db.insert_if_not_exists(&[TEST_LEAF], b"key1".to_vec(), Element::empty_tree()); match result { Ok(_) => panic!("Second insertion for same key should not work"), Err(_e) => (), From a31197e4dc5bacf66d160d95631d2a4380754378 Mon Sep 17 00:00:00 2001 From: Wisdom Ogwu Date: Mon, 20 Dec 2021 18:23:18 +0100 Subject: [PATCH 3/7] Removed unused import --- grovedb/src/lib.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/grovedb/src/lib.rs b/grovedb/src/lib.rs index 716e4a54c..3ab5df62b 100644 --- a/grovedb/src/lib.rs +++ b/grovedb/src/lib.rs @@ -16,8 +16,6 @@ use storage::{ }; pub use subtree::Element; -use crate::Error::ElementAtPath; - /// Limit of possible indirections const MAX_REFERENCE_HOPS: usize = 10; /// A key to store serialized data about subtree prefixes to restore HADS @@ -223,7 +221,7 @@ impl GroveDb { mut element: subtree::Element, ) -> Result<(), Error> { if self.get(path, &key).is_ok() { - return Err(ElementAtPath); + return Err(Error::ElementAtPath); } self.insert(path, key, element) } From 19424206634e8f1b06f01d47c128e5881c6de88a Mon Sep 17 00:00:00 2001 From: Wisdom Ogwu Date: Mon, 20 Dec 2021 19:23:46 +0100 Subject: [PATCH 4/7] Updated api --- grovedb/src/lib.rs | 11 +++++++---- grovedb/src/tests.rs | 27 +++++++++++++++++---------- 2 files changed, 24 insertions(+), 14 deletions(-) diff --git a/grovedb/src/lib.rs b/grovedb/src/lib.rs index 3ab5df62b..160c1489a 100644 --- a/grovedb/src/lib.rs +++ b/grovedb/src/lib.rs @@ -218,12 +218,15 @@ impl GroveDb { &mut self, path: &[&[u8]], key: Vec, - mut element: subtree::Element, - ) -> Result<(), Error> { + element: subtree::Element, + ) -> Result { if self.get(path, &key).is_ok() { - return Err(Error::ElementAtPath); + return Ok(false); + } + match self.insert(path, key, element) { + Ok(_) => Ok(true), + Err(e) => Err(e), } - self.insert(path, key, element) } pub fn get(&self, path: &[&[u8]], key: &[u8]) -> Result { diff --git a/grovedb/src/tests.rs b/grovedb/src/tests.rs index 87c3243f3..d7ff5a9c4 100644 --- a/grovedb/src/tests.rs +++ b/grovedb/src/tests.rs @@ -320,17 +320,24 @@ fn test_checkpoint() { fn test_insert_if_not_exists() { let mut db = make_grovedb(); - // First insertion - let result = db.insert_if_not_exists(&[TEST_LEAF], b"key1".to_vec(), Element::empty_tree()); - match result { - Ok(_) => (), - Err(_e) => panic!("First insertion should be a success"), - } + // Insert twice at the same path + assert_eq!( + db.insert_if_not_exists(&[TEST_LEAF], b"key1".to_vec(), Element::empty_tree()) + .expect("Provided valid path"), + true + ); + assert_eq!( + db.insert_if_not_exists(&[TEST_LEAF], b"key1".to_vec(), Element::empty_tree()) + .expect("Provided valid path"), + false + ); - // Second insertion at same path - let result = db.insert_if_not_exists(&[TEST_LEAF], b"key1".to_vec(), Element::empty_tree()); + // Should propagate errors from insertion + let result = db.insert_if_not_exists(&[TEST_LEAF, b"unknown"], b"key1".to_vec(), Element::empty_tree()); match result { - Ok(_) => panic!("Second insertion for same key should not work"), - Err(_e) => (), + Ok(_) => { + panic!("Should result in an error") + }, + Err(_e) => {}, } } From ed5bf949bbf7da15dbafd5c0658a1156b90773a5 Mon Sep 17 00:00:00 2001 From: Wisdom Ogwu Date: Mon, 20 Dec 2021 19:26:32 +0100 Subject: [PATCH 5/7] Removed unnecessary error definition --- grovedb/src/lib.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/grovedb/src/lib.rs b/grovedb/src/lib.rs index 160c1489a..afc677c68 100644 --- a/grovedb/src/lib.rs +++ b/grovedb/src/lib.rs @@ -38,8 +38,6 @@ pub enum Error { StorageError(#[from] PrefixedRocksDbStorageError), #[error("data corruption error: {0}")] CorruptedData(String), - #[error("element exists at path")] - ElementAtPath, } pub struct GroveDb { From a00667134d4bed9445b8b5a84abfa0b4b1236d3d Mon Sep 17 00:00:00 2001 From: Wisdom Ogwu <40731160+iammadab@users.noreply.github.com> Date: Mon, 20 Dec 2021 19:38:44 +0100 Subject: [PATCH 6/7] Update grovedb/src/tests.rs Co-authored-by: Evgeny Fomin --- grovedb/src/tests.rs | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/grovedb/src/tests.rs b/grovedb/src/tests.rs index d7ff5a9c4..2591adc95 100644 --- a/grovedb/src/tests.rs +++ b/grovedb/src/tests.rs @@ -334,10 +334,4 @@ fn test_insert_if_not_exists() { // Should propagate errors from insertion let result = db.insert_if_not_exists(&[TEST_LEAF, b"unknown"], b"key1".to_vec(), Element::empty_tree()); - match result { - Ok(_) => { - panic!("Should result in an error") - }, - Err(_e) => {}, - } -} + assert!(matches!(result, Err(Error::InvalidPath(_)))); From 729d67ebec41350e5591fd8c41342b683aa1d26f Mon Sep 17 00:00:00 2001 From: Wisdom Ogwu Date: Mon, 20 Dec 2021 19:39:46 +0100 Subject: [PATCH 7/7] fmt --- grovedb/src/tests.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/grovedb/src/tests.rs b/grovedb/src/tests.rs index 2591adc95..795b2b20f 100644 --- a/grovedb/src/tests.rs +++ b/grovedb/src/tests.rs @@ -333,5 +333,10 @@ fn test_insert_if_not_exists() { ); // Should propagate errors from insertion - let result = db.insert_if_not_exists(&[TEST_LEAF, b"unknown"], b"key1".to_vec(), Element::empty_tree()); + let result = db.insert_if_not_exists( + &[TEST_LEAF, b"unknown"], + b"key1".to_vec(), + Element::empty_tree(), + ); assert!(matches!(result, Err(Error::InvalidPath(_)))); +}