diff --git a/crates/db/src/kv/cursor.rs b/crates/db/src/kv/cursor.rs index 9a5b7dfd2e..33208bdfdd 100644 --- a/crates/db/src/kv/cursor.rs +++ b/crates/db/src/kv/cursor.rs @@ -128,6 +128,12 @@ impl<'tx, T: Table> DbCursorRW<'tx, T> for Cursor<'tx, RW, T> { .map_err(|e| Error::Write(e.into())) } + fn insert(&mut self, key: T::Key, value: T::Value) -> Result<(), Error> { + self.inner + .put(key.encode().as_ref(), value.compress().as_ref(), WriteFlags::NO_OVERWRITE) + .map_err(|e| Error::Write(e.into())) + } + /// Appends the data to the end of the table. Consequently, the append operation /// will fail if the inserted key is less than the last table key fn append(&mut self, key: T::Key, value: T::Value) -> Result<(), Error> { diff --git a/crates/db/src/kv/mod.rs b/crates/db/src/kv/mod.rs index 323eaf2ba2..f92ace32f3 100644 --- a/crates/db/src/kv/mod.rs +++ b/crates/db/src/kv/mod.rs @@ -237,6 +237,34 @@ mod tests { assert_eq!(cursor.prev(), Ok(Some((missing_key - 2, H256::zero())))); } + #[test] + fn db_cursor_insert() { + let db: Arc> = test_utils::create_test_db(EnvKind::RW); + + // PUT + let tx = db.tx_mut().expect(ERROR_INIT_TX); + vec![0, 1, 3, 4, 5] + .into_iter() + .try_for_each(|key| tx.put::(key, H256::zero())) + .expect(ERROR_PUT); + tx.commit().expect(ERROR_COMMIT); + + let db: Arc> = test_utils::create_test_db(EnvKind::RW); + + let key_to_insert = 2; + let tx = db.tx_mut().expect(ERROR_INIT_TX); + let mut cursor = tx.cursor_mut::().unwrap(); + + // INSERT + cursor.seek_exact(1).unwrap(); + assert_eq!(cursor.insert(key_to_insert, H256::zero()), Ok(())); + assert_eq!(cursor.current(), Ok(Some((key_to_insert, H256::zero())))); + + // INSERT (failure) + assert_eq!(cursor.insert(key_to_insert, H256::zero()), Err(db::Error::Write(4294936497))); + assert_eq!(cursor.current(), Ok(Some((key_to_insert, H256::zero())))); + } + #[test] fn db_cursor_append_failure() { let db: Arc> = test_utils::create_test_db(EnvKind::RW); @@ -250,11 +278,11 @@ mod tests { tx.commit().expect(ERROR_COMMIT); // APPEND - let key_to_insert = 2; + let key_to_append = 2; let tx = db.tx_mut().expect(ERROR_INIT_TX); let mut cursor = tx.cursor_mut::().unwrap(); cursor.seek_exact(1).unwrap(); - assert_eq!(cursor.append(key_to_insert, H256::zero()), Err(db::Error::Write(4294936878))); + assert_eq!(cursor.append(key_to_append, H256::zero()), Err(db::Error::Write(4294936878))); assert_eq!(cursor.current(), Ok(Some((5, H256::zero())))); // the end of table } diff --git a/crates/interfaces/src/db/mock.rs b/crates/interfaces/src/db/mock.rs index ab83786235..e25a3176b0 100644 --- a/crates/interfaces/src/db/mock.rs +++ b/crates/interfaces/src/db/mock.rs @@ -176,6 +176,14 @@ impl<'tx, T: Table> DbCursorRW<'tx, T> for CursorMock { todo!() } + fn insert( + &mut self, + _key: ::Key, + _value: ::Value, + ) -> Result<(), super::Error> { + todo!() + } + fn append( &mut self, _key: ::Key, diff --git a/crates/interfaces/src/db/mod.rs b/crates/interfaces/src/db/mod.rs index 4bc372d38b..2f24b56df4 100644 --- a/crates/interfaces/src/db/mod.rs +++ b/crates/interfaces/src/db/mod.rs @@ -190,6 +190,10 @@ pub trait DbCursorRW<'tx, T: Table> { /// exists in a table, and insert a new row if the specified value doesn't already exist fn upsert(&mut self, key: T::Key, value: T::Value) -> Result<(), Error>; + /// Database operation that will insert a row at a given key. If the key is already + /// present, the operation will result in an error. + fn insert(&mut self, key: T::Key, value: T::Value) -> Result<(), Error>; + /// Append value to next cursor item. /// /// This is efficient for pre-sorted data. If the data is not pre-sorted, use [`insert`].