From a00a88baef376804b9980a4854250d08da2908e5 Mon Sep 17 00:00:00 2001 From: Martin Kobetic Date: Wed, 11 Jun 2014 21:46:19 +0000 Subject: [PATCH] add Cursor.Delete() --- cursor.go | 19 +++++++++++++++++++ cursor_test.go | 40 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+) 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.