tbotd/vendor/src/github.com/asdine/storm/range.go

101 lines
2.2 KiB
Go

package storm
import (
"fmt"
"reflect"
"github.com/asdine/storm/index"
"github.com/boltdb/bolt"
"github.com/fatih/structs"
)
// Range returns one or more records by the specified index within the specified range
func (n *Node) Range(fieldName string, min, max, to interface{}, options ...func(*index.Options)) error {
ref := reflect.ValueOf(to)
if ref.Kind() != reflect.Ptr || reflect.Indirect(ref).Kind() != reflect.Slice {
return ErrSlicePtrNeeded
}
typ := reflect.Indirect(ref).Type().Elem()
newElem := reflect.New(typ)
d := structs.New(newElem.Interface())
bucketName := d.Name()
if bucketName == "" {
return ErrNoName
}
field, ok := d.FieldOk(fieldName)
if !ok {
return fmt.Errorf("field %s not found", fieldName)
}
tag := field.Tag("storm")
if tag == "" {
return fmt.Errorf("index %s not found", fieldName)
}
mn, err := toBytes(min, n.s.Codec)
if err != nil {
return err
}
mx, err := toBytes(max, n.s.Codec)
if err != nil {
return err
}
opts := index.NewOptions()
for _, fn := range options {
fn(opts)
}
if n.tx != nil {
return n.rnge(n.tx, bucketName, fieldName, tag, &ref, mn, mx, opts)
}
return n.s.Bolt.View(func(tx *bolt.Tx) error {
return n.rnge(tx, bucketName, fieldName, tag, &ref, mn, mx, opts)
})
}
func (n *Node) rnge(tx *bolt.Tx, bucketName, fieldName, tag string, ref *reflect.Value, min, max []byte, opts *index.Options) error {
bucket := n.GetBucket(tx, bucketName)
if bucket == nil {
return fmt.Errorf("bucket %s not found", bucketName)
}
idx, err := getIndex(bucket, tag, fieldName)
if err != nil {
return err
}
list, err := idx.Range(min, max, opts)
if err != nil {
return err
}
results := reflect.MakeSlice(reflect.Indirect(*ref).Type(), len(list), len(list))
for i := range list {
raw := bucket.Get(list[i])
if raw == nil {
return ErrNotFound
}
err = n.s.Codec.Decode(raw, results.Index(i).Addr().Interface())
if err != nil {
return err
}
}
reflect.Indirect(*ref).Set(results)
return nil
}
// Range returns one or more records by the specified index within the specified range
func (s *DB) Range(fieldName string, min, max, to interface{}, options ...func(*index.Options)) error {
return s.root.Range(fieldName, min, max, to, options...)
}