mirror of https://github.com/tidwall/buntdb.git
Added AscendEqual and DescendEqual
AscendEqual and DescendEqual return only the items that equal a specified value. Closes #26
This commit is contained in:
parent
83418750ee
commit
b67b1b8c16
|
@ -148,7 +148,9 @@ err := tx.Ascend("", func(key, value string) bool{
|
||||||
})
|
})
|
||||||
```
|
```
|
||||||
|
|
||||||
There is also `AscendGreaterOrEqual`, `AscendLessThan`, `AscendRange`, `Descend`, `DescendLessOrEqual`, `DescendGreaterThan`, and `DescendRange`. Please see the [documentation](https://godoc.org/github.com/tidwall/buntdb) for more information on these functions.
|
There is also `AscendGreaterOrEqual`, `AscendLessThan`, `AscendRange`, `AscendEqual`, `Descend`, `DescendLessOrEqual`, `DescendGreaterThan`, `DescendRange`, and `DescendEqual`. Please see the [documentation](https://godoc.org/github.com/tidwall/buntdb) for more information on these functions.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Custom Indexes
|
## Custom Indexes
|
||||||
|
|
66
buntdb.go
66
buntdb.go
|
@ -1185,6 +1185,7 @@ type dbItemOpts struct {
|
||||||
type dbItem struct {
|
type dbItem struct {
|
||||||
key, val string // the binary key and value
|
key, val string // the binary key and value
|
||||||
opts *dbItemOpts // optional meta information
|
opts *dbItemOpts // optional meta information
|
||||||
|
keyless bool // keyless item for scanning
|
||||||
}
|
}
|
||||||
|
|
||||||
func appendArray(buf []byte, count int) []byte {
|
func appendArray(buf []byte, count int) []byte {
|
||||||
|
@ -1278,6 +1279,11 @@ func (dbi *dbItem) Less(item btree.Item, ctx interface{}) bool {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Always fall back to the key comparison. This creates absolute uniqueness.
|
// Always fall back to the key comparison. This creates absolute uniqueness.
|
||||||
|
if dbi.keyless {
|
||||||
|
return false
|
||||||
|
} else if dbi2.keyless {
|
||||||
|
return true
|
||||||
|
}
|
||||||
return dbi.key < dbi2.key
|
return dbi.key < dbi2.key
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1507,6 +1513,10 @@ func (tx *Tx) scan(desc, gt, lt bool, index, start, stop string,
|
||||||
} else {
|
} else {
|
||||||
itemA = &dbItem{val: start}
|
itemA = &dbItem{val: start}
|
||||||
itemB = &dbItem{val: stop}
|
itemB = &dbItem{val: stop}
|
||||||
|
if desc {
|
||||||
|
itemA.keyless = true
|
||||||
|
itemB.keyless = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// execute the scan on the underlying tree.
|
// execute the scan on the underlying tree.
|
||||||
|
@ -1709,6 +1719,62 @@ func (tx *Tx) DescendRange(index, lessOrEqual, greaterThan string,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AscendEqual calls the iterator for every item in the database that equals
|
||||||
|
// pivot, until iterator returns false.
|
||||||
|
// When an index is provided, the results will be ordered by the item values
|
||||||
|
// as specified by the less() function of the defined index.
|
||||||
|
// When an index is not provided, the results will be ordered by the item key.
|
||||||
|
// An invalid index will return an error.
|
||||||
|
func (tx *Tx) AscendEqual(index, pivot string,
|
||||||
|
iterator func(key, value string) bool) error {
|
||||||
|
var err error
|
||||||
|
var less func(a, b string) bool
|
||||||
|
if index != "" {
|
||||||
|
less, err = tx.GetLess(index)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return tx.AscendGreaterOrEqual(index, pivot, func(key, value string) bool {
|
||||||
|
if less == nil {
|
||||||
|
if key != pivot {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
} else if less(pivot, value) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return iterator(key, value)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// DescendEqual calls the iterator for every item in the database that equals
|
||||||
|
// pivot, until iterator returns false.
|
||||||
|
// When an index is provided, the results will be ordered by the item values
|
||||||
|
// as specified by the less() function of the defined index.
|
||||||
|
// When an index is not provided, the results will be ordered by the item key.
|
||||||
|
// An invalid index will return an error.
|
||||||
|
func (tx *Tx) DescendEqual(index, pivot string,
|
||||||
|
iterator func(key, value string) bool) error {
|
||||||
|
var err error
|
||||||
|
var less func(a, b string) bool
|
||||||
|
if index != "" {
|
||||||
|
less, err = tx.GetLess(index)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return tx.DescendLessOrEqual(index, pivot, func(key, value string) bool {
|
||||||
|
if less == nil {
|
||||||
|
if key != pivot {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
} else if less(value, pivot) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return iterator(key, value)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// rect is used by Intersects
|
// rect is used by Intersects
|
||||||
type rect struct {
|
type rect struct {
|
||||||
min, max []float64
|
min, max []float64
|
||||||
|
|
104
buntdb_test.go
104
buntdb_test.go
|
@ -495,6 +495,110 @@ func TestDeleteAll(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestAscendEqual(t *testing.T) {
|
||||||
|
db := testOpen(t)
|
||||||
|
defer testClose(db)
|
||||||
|
if err := db.Update(func(tx *Tx) error {
|
||||||
|
for i := 0; i < 300; i++ {
|
||||||
|
_, _, err := tx.Set(fmt.Sprintf("key:%05dA", i), fmt.Sprintf("%d", i+1000), nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_, _, err = tx.Set(fmt.Sprintf("key:%05dB", i), fmt.Sprintf("%d", i+1000), nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return tx.CreateIndex("num", "*", IndexInt)
|
||||||
|
}); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
var res []string
|
||||||
|
if err := db.View(func(tx *Tx) error {
|
||||||
|
return tx.AscendEqual("", "key:00055A", func(key, value string) bool {
|
||||||
|
res = append(res, key)
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
}); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(res) != 1 {
|
||||||
|
t.Fatalf("expected %v, got %v", 1, len(res))
|
||||||
|
}
|
||||||
|
if res[0] != "key:00055A" {
|
||||||
|
t.Fatalf("expected %v, got %v", "key:00055A", res[0])
|
||||||
|
}
|
||||||
|
res = nil
|
||||||
|
if err := db.View(func(tx *Tx) error {
|
||||||
|
return tx.AscendEqual("num", "1125", func(key, value string) bool {
|
||||||
|
res = append(res, key)
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
}); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(res) != 2 {
|
||||||
|
t.Fatalf("expected %v, got %v", 2, len(res))
|
||||||
|
}
|
||||||
|
if res[0] != "key:00125A" {
|
||||||
|
t.Fatalf("expected %v, got %v", "key:00125A", res[0])
|
||||||
|
}
|
||||||
|
if res[1] != "key:00125B" {
|
||||||
|
t.Fatalf("expected %v, got %v", "key:00125B", res[1])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func TestDescendEqual(t *testing.T) {
|
||||||
|
db := testOpen(t)
|
||||||
|
defer testClose(db)
|
||||||
|
if err := db.Update(func(tx *Tx) error {
|
||||||
|
for i := 0; i < 300; i++ {
|
||||||
|
_, _, err := tx.Set(fmt.Sprintf("key:%05dA", i), fmt.Sprintf("%d", i+1000), nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_, _, err = tx.Set(fmt.Sprintf("key:%05dB", i), fmt.Sprintf("%d", i+1000), nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return tx.CreateIndex("num", "*", IndexInt)
|
||||||
|
}); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
var res []string
|
||||||
|
if err := db.View(func(tx *Tx) error {
|
||||||
|
return tx.DescendEqual("", "key:00055A", func(key, value string) bool {
|
||||||
|
res = append(res, key)
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
}); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(res) != 1 {
|
||||||
|
t.Fatalf("expected %v, got %v", 1, len(res))
|
||||||
|
}
|
||||||
|
if res[0] != "key:00055A" {
|
||||||
|
t.Fatalf("expected %v, got %v", "key:00055A", res[0])
|
||||||
|
}
|
||||||
|
res = nil
|
||||||
|
if err := db.View(func(tx *Tx) error {
|
||||||
|
return tx.DescendEqual("num", "1125", func(key, value string) bool {
|
||||||
|
res = append(res, key)
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
}); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(res) != 2 {
|
||||||
|
t.Fatalf("expected %v, got %v", 2, len(res))
|
||||||
|
}
|
||||||
|
if res[0] != "key:00125B" {
|
||||||
|
t.Fatalf("expected %v, got %v", "key:00125B", res[0])
|
||||||
|
}
|
||||||
|
if res[1] != "key:00125A" {
|
||||||
|
t.Fatalf("expected %v, got %v", "key:00125A", res[1])
|
||||||
|
}
|
||||||
|
}
|
||||||
func TestVariousTx(t *testing.T) {
|
func TestVariousTx(t *testing.T) {
|
||||||
db := testOpen(t)
|
db := testOpen(t)
|
||||||
defer testClose(db)
|
defer testClose(db)
|
||||||
|
|
Loading…
Reference in New Issue