aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cursor.go19
-rw-r--r--cursor_test.go40
2 files changed, 59 insertions, 0 deletions
diff --git a/cursor.go b/cursor.go
index dbc2833..90a1867 100644
--- a/cursor.go
+++ b/cursor.go
@@ -111,6 +111,25 @@ func (c *Cursor) Seek(seek []byte) (key []byte, value []byte) {
return k, v
}
+// Delete removes the current key/value under the cursor from the bucket.
+// Delete fails if current key/value is a bucket or if the transaction is not writable.
+func (c *Cursor) Delete() error {
+ if c.bucket.tx.db == nil {
+ return ErrTxClosed
+ } else if !c.bucket.Writable() {
+ return ErrTxNotWritable
+ }
+
+ key, _, flags := c.keyValue()
+ // Return an error if current value is a bucket.
+ if (flags & bucketLeafFlag) != 0 {
+ return ErrIncompatibleValue
+ }
+ c.node().del(key)
+
+ return nil
+}
+
// seek moves the cursor to a given key and returns it.
// If the key does not exist then the next key is used.
func (c *Cursor) seek(seek []byte) (key []byte, value []byte, flags uint32) {
diff --git a/cursor_test.go b/cursor_test.go
index b44bf53..470860d 100644
--- a/cursor_test.go
+++ b/cursor_test.go
@@ -1,6 +1,7 @@
package bolt
import (
+ "bytes"
"encoding/binary"
"sort"
"testing"
@@ -67,6 +68,45 @@ func TestCursor_Seek(t *testing.T) {
})
}
+func TestCursor_Delete(t *testing.T) {
+ withOpenDB(func(db *DB, path string) {
+ var count = 1000
+
+ // Insert every other key between 0 and $count.
+ db.Update(func(tx *Tx) error {
+ b, _ := tx.CreateBucket([]byte("widgets"))
+ for i := 0; i < count; i += 1 {
+ k := make([]byte, 8)
+ binary.BigEndian.PutUint64(k, uint64(i))
+ b.Put(k, make([]byte, 100))
+ }
+ b.CreateBucket([]byte("sub"))
+ return nil
+ })
+
+ db.Update(func(tx *Tx) error {
+ c := tx.Bucket([]byte("widgets")).Cursor()
+ bound := make([]byte, 8)
+ binary.BigEndian.PutUint64(bound, uint64(count/2))
+ for key, _ := c.First(); bytes.Compare(key, bound) < 0; key, _ = c.Next() {
+ if err := c.Delete(); err != nil {
+ return err
+ }
+ }
+ c.Seek([]byte("sub"))
+ err := c.Delete()
+ assert.Equal(t, err, ErrIncompatibleValue)
+ return nil
+ })
+
+ db.View(func(tx *Tx) error {
+ b := tx.Bucket([]byte("widgets"))
+ assert.Equal(t, b.Stats().KeyN, count/2+1)
+ return nil
+ })
+ })
+}
+
// Ensure that a Tx cursor can seek to the appropriate keys when there are a
// large number of keys. This test also checks that seek will always move
// forward to the next key.