181 lines
3.8 KiB
Go
181 lines
3.8 KiB
Go
package storm
|
|
|
|
import (
|
|
"fmt"
|
|
"reflect"
|
|
|
|
"github.com/asdine/storm/index"
|
|
"github.com/boltdb/bolt"
|
|
)
|
|
|
|
// AllByIndex gets all the records of a bucket that are indexed in the specified index
|
|
func (n *Node) AllByIndex(fieldName string, to interface{}, options ...func(*index.Options)) error {
|
|
if fieldName == "" {
|
|
return n.All(to, options...)
|
|
}
|
|
|
|
ref := reflect.ValueOf(to)
|
|
|
|
if ref.Kind() != reflect.Ptr || reflect.Indirect(ref).Kind() != reflect.Slice {
|
|
return ErrSlicePtrNeeded
|
|
}
|
|
|
|
typ := reflect.Indirect(ref).Type().Elem()
|
|
|
|
if typ.Kind() == reflect.Ptr {
|
|
typ = typ.Elem()
|
|
}
|
|
|
|
newElem := reflect.New(typ)
|
|
|
|
info, err := extract(newElem.Interface())
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if info.ID.Field.Name() == fieldName {
|
|
return n.All(to, options...)
|
|
}
|
|
|
|
opts := index.NewOptions()
|
|
for _, fn := range options {
|
|
fn(opts)
|
|
}
|
|
|
|
if n.tx != nil {
|
|
return n.allByIndex(n.tx, fieldName, info, &ref, opts)
|
|
}
|
|
|
|
return n.s.Bolt.View(func(tx *bolt.Tx) error {
|
|
return n.allByIndex(tx, fieldName, info, &ref, opts)
|
|
})
|
|
}
|
|
|
|
func (n *Node) allByIndex(tx *bolt.Tx, fieldName string, info *modelInfo, ref *reflect.Value, opts *index.Options) error {
|
|
bucket := n.GetBucket(tx, info.Name)
|
|
if bucket == nil {
|
|
return fmt.Errorf("bucket %s not found", info.Name)
|
|
}
|
|
|
|
idxInfo, ok := info.Indexes[fieldName]
|
|
if !ok {
|
|
return ErrNotFound
|
|
}
|
|
|
|
idx, err := getIndex(bucket, idxInfo.Type, fieldName)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
list, err := idx.AllRecords(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
|
|
}
|
|
|
|
// All gets all the records of a bucket
|
|
func (n *Node) All(to interface{}, options ...func(*index.Options)) error {
|
|
ref := reflect.ValueOf(to)
|
|
|
|
if ref.Kind() != reflect.Ptr || reflect.Indirect(ref).Kind() != reflect.Slice {
|
|
return ErrSlicePtrNeeded
|
|
}
|
|
|
|
rtyp := reflect.Indirect(ref).Type().Elem()
|
|
typ := rtyp
|
|
|
|
if rtyp.Kind() == reflect.Ptr {
|
|
typ = typ.Elem()
|
|
}
|
|
|
|
newElem := reflect.New(typ)
|
|
|
|
info, err := extract(newElem.Interface())
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
opts := index.NewOptions()
|
|
for _, fn := range options {
|
|
fn(opts)
|
|
}
|
|
|
|
if n.tx != nil {
|
|
return n.all(n.tx, info, &ref, rtyp, typ, opts)
|
|
}
|
|
|
|
return n.s.Bolt.View(func(tx *bolt.Tx) error {
|
|
return n.all(tx, info, &ref, rtyp, typ, opts)
|
|
})
|
|
}
|
|
|
|
func (n *Node) all(tx *bolt.Tx, info *modelInfo, ref *reflect.Value, rtyp, typ reflect.Type, opts *index.Options) error {
|
|
bucket := n.GetBucket(tx, info.Name)
|
|
if bucket == nil {
|
|
return fmt.Errorf("bucket %s not found", info.Name)
|
|
}
|
|
|
|
results := reflect.MakeSlice(reflect.Indirect(*ref).Type(), 0, 0)
|
|
c := bucket.Cursor()
|
|
for k, v := c.First(); k != nil; k, v = c.Next() {
|
|
if v == nil {
|
|
continue
|
|
}
|
|
|
|
if opts != nil && opts.Skip > 0 {
|
|
opts.Skip--
|
|
continue
|
|
}
|
|
|
|
if opts != nil && opts.Limit == 0 {
|
|
break
|
|
}
|
|
|
|
if opts != nil && opts.Limit > 0 {
|
|
opts.Limit--
|
|
}
|
|
|
|
newElem := reflect.New(typ)
|
|
err := n.s.Codec.Decode(v, newElem.Interface())
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if rtyp.Kind() == reflect.Ptr {
|
|
results = reflect.Append(results, newElem)
|
|
} else {
|
|
results = reflect.Append(results, reflect.Indirect(newElem))
|
|
}
|
|
}
|
|
|
|
reflect.Indirect(*ref).Set(results)
|
|
return nil
|
|
}
|
|
|
|
// AllByIndex gets all the records of a bucket that are indexed in the specified index
|
|
func (s *DB) AllByIndex(fieldName string, to interface{}, options ...func(*index.Options)) error {
|
|
return s.root.AllByIndex(fieldName, to, options...)
|
|
}
|
|
|
|
// All get all the records of a bucket
|
|
func (s *DB) All(to interface{}, options ...func(*index.Options)) error {
|
|
return s.root.All(to, options...)
|
|
}
|