mirror of https://github.com/etcd-io/bbolt.git
Add Transaction.ForEach().
parent
63e8e474d7
commit
b22480fd32
11
db.go
11
db.go
|
@ -359,6 +359,17 @@ func (db *DB) Do(fn func(*RWTransaction) error) error {
|
||||||
return t.Commit()
|
return t.Commit()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ForEach executes a function for each key/value pair in a bucket.
|
||||||
|
// An error is returned if the bucket cannot be found.
|
||||||
|
func (db *DB) ForEach(name string, fn func(k, v []byte) error) error {
|
||||||
|
t, err := db.Transaction()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer t.Close()
|
||||||
|
return t.ForEach(name, fn)
|
||||||
|
}
|
||||||
|
|
||||||
// Bucket retrieves a reference to a bucket.
|
// Bucket retrieves a reference to a bucket.
|
||||||
// This is typically useful for checking the existence of a bucket.
|
// This is typically useful for checking the existence of a bucket.
|
||||||
func (db *DB) Bucket(name string) (*Bucket, error) {
|
func (db *DB) Bucket(name string) (*Bucket, error) {
|
||||||
|
|
67
db_test.go
67
db_test.go
|
@ -1,6 +1,7 @@
|
||||||
package bolt
|
package bolt
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
|
@ -215,6 +216,72 @@ func TestDBTransactionBlockWhileClosed(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Ensure a database can loop over all key/value pairs in a bucket.
|
||||||
|
func TestDBForEach(t *testing.T) {
|
||||||
|
withOpenDB(func(db *DB, path string) {
|
||||||
|
db.CreateBucket("widgets")
|
||||||
|
db.Put("widgets", []byte("foo"), []byte("0000"))
|
||||||
|
db.Put("widgets", []byte("baz"), []byte("0001"))
|
||||||
|
db.Put("widgets", []byte("bar"), []byte("0002"))
|
||||||
|
|
||||||
|
var index int
|
||||||
|
err := db.ForEach("widgets", func(k, v []byte) error {
|
||||||
|
switch index {
|
||||||
|
case 0:
|
||||||
|
assert.Equal(t, k, []byte("bar"))
|
||||||
|
assert.Equal(t, v, []byte("0002"))
|
||||||
|
case 1:
|
||||||
|
assert.Equal(t, k, []byte("baz"))
|
||||||
|
assert.Equal(t, v, []byte("0001"))
|
||||||
|
case 2:
|
||||||
|
assert.Equal(t, k, []byte("foo"))
|
||||||
|
assert.Equal(t, v, []byte("0000"))
|
||||||
|
}
|
||||||
|
index++
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, index, 3)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure a database can stop iteration early.
|
||||||
|
func TestDBForEachShortCircuit(t *testing.T) {
|
||||||
|
withOpenDB(func(db *DB, path string) {
|
||||||
|
db.CreateBucket("widgets")
|
||||||
|
db.Put("widgets", []byte("bar"), []byte("0000"))
|
||||||
|
db.Put("widgets", []byte("baz"), []byte("0000"))
|
||||||
|
db.Put("widgets", []byte("foo"), []byte("0000"))
|
||||||
|
|
||||||
|
var index int
|
||||||
|
err := db.ForEach("widgets", func(k, v []byte) error {
|
||||||
|
index++
|
||||||
|
if bytes.Equal(k, []byte("baz")) {
|
||||||
|
return &Error{"marker", nil}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
assert.Equal(t, err, &Error{"marker", nil})
|
||||||
|
assert.Equal(t, index, 2)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure a database returns an error when trying to attempt a for each on a missing bucket.
|
||||||
|
func TestDBForEachBucketNotFound(t *testing.T) {
|
||||||
|
withOpenDB(func(db *DB, path string) {
|
||||||
|
err := db.ForEach("widgets", func(k, v []byte) error { return nil })
|
||||||
|
assert.Equal(t, err, ErrBucketNotFound)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure a closed database returns an error when executing a for each.
|
||||||
|
func TestDBForEachWhileClosed(t *testing.T) {
|
||||||
|
withDB(func(db *DB, path string) {
|
||||||
|
err := db.ForEach("widgets", func(k, v []byte) error { return nil })
|
||||||
|
assert.Equal(t, err, ErrDatabaseNotOpen)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// Ensure a closed database returns an error when finding a bucket.
|
// Ensure a closed database returns an error when finding a bucket.
|
||||||
func TestDBBucketWhileClosed(t *testing.T) {
|
func TestDBBucketWhileClosed(t *testing.T) {
|
||||||
withDB(func(db *DB, path string) {
|
withDB(func(db *DB, path string) {
|
||||||
|
|
|
@ -87,6 +87,30 @@ func ExampleDB_Do() {
|
||||||
// The value of 'foo' is: bar
|
// The value of 'foo' is: bar
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ExampleDB_ForEach() {
|
||||||
|
// Open the database.
|
||||||
|
var db DB
|
||||||
|
db.Open("/tmp/bolt/db_foreach.db", 0666)
|
||||||
|
defer db.Close()
|
||||||
|
|
||||||
|
// Insert data into a bucket.
|
||||||
|
db.CreateBucket("animals")
|
||||||
|
db.Put("animals", []byte("dog"), []byte("fun"))
|
||||||
|
db.Put("animals", []byte("cat"), []byte("lame"))
|
||||||
|
db.Put("animals", []byte("liger"), []byte("awesome"))
|
||||||
|
|
||||||
|
// Iterate over items in sorted key order.
|
||||||
|
db.ForEach("animals", func(k, v []byte) error {
|
||||||
|
fmt.Printf("A %s is %s.\n", string(k), string(v))
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// A cat is lame.
|
||||||
|
// A dog is fun.
|
||||||
|
// A liger is awesome.
|
||||||
|
}
|
||||||
|
|
||||||
func ExampleRWTransaction() {
|
func ExampleRWTransaction() {
|
||||||
// Open the database.
|
// Open the database.
|
||||||
var db DB
|
var db DB
|
||||||
|
|
|
@ -93,6 +93,25 @@ func (t *Transaction) Get(name string, key []byte) (value []byte, err error) {
|
||||||
return c.Get(key), nil
|
return c.Get(key), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ForEach executes a function for each key/value pair in a bucket.
|
||||||
|
// An error is returned if the bucket cannot be found.
|
||||||
|
func (t *Transaction) ForEach(name string, fn func(k, v []byte) error) error {
|
||||||
|
// Open a cursor on the bucket.
|
||||||
|
c, err := t.Cursor(name)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Iterate over each key/value pair in the bucket.
|
||||||
|
for k, v := c.First(); k != nil; k, v = c.Next() {
|
||||||
|
if err := fn(k, v); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// page returns a reference to the page with a given id.
|
// page returns a reference to the page with a given id.
|
||||||
// If page has been written to then a temporary bufferred page is returned.
|
// If page has been written to then a temporary bufferred page is returned.
|
||||||
func (t *Transaction) page(id pgid) *page {
|
func (t *Transaction) page(id pgid) *page {
|
||||||
|
|
Loading…
Reference in New Issue