tbotd/vendor/src/github.com/asdine/storm/index/list.go

184 lines
3.7 KiB
Go

package index
import (
"bytes"
"github.com/boltdb/bolt"
)
// NewListIndex loads a ListIndex
func NewListIndex(parent *bolt.Bucket, indexName []byte) (*ListIndex, error) {
var err error
b := parent.Bucket(indexName)
if b == nil {
if !parent.Writable() {
return nil, ErrNotFound
}
b, err = parent.CreateBucket(indexName)
if err != nil {
return nil, err
}
}
ids, err := NewUniqueIndex(b, []byte("storm__ids"))
if err != nil {
return nil, err
}
return &ListIndex{
IndexBucket: b,
Parent: parent,
IDs: ids,
}, nil
}
// ListIndex is an index that references values and the corresponding IDs.
type ListIndex struct {
Parent *bolt.Bucket
IndexBucket *bolt.Bucket
IDs *UniqueIndex
}
// Add a value to the list index
func (idx *ListIndex) Add(value []byte, targetID []byte) error {
if value == nil || len(value) == 0 {
return ErrNilParam
}
if targetID == nil || len(targetID) == 0 {
return ErrNilParam
}
oldValue := idx.IDs.Get(targetID)
if oldValue != nil {
uni, err := NewUniqueIndex(idx.IndexBucket, oldValue)
if err != nil {
return err
}
err = uni.Remove(targetID)
if err != nil {
return err
}
err = idx.IDs.Remove(targetID)
if err != nil {
return err
}
}
uni, err := NewUniqueIndex(idx.IndexBucket, value)
if err != nil {
return err
}
err = uni.Add(targetID, targetID)
if err != nil {
return err
}
return idx.IDs.Add(targetID, value)
}
// Remove a value from the unique index
func (idx *ListIndex) Remove(value []byte) error {
err := idx.IDs.RemoveID(value)
if err != nil {
return err
}
return idx.IndexBucket.DeleteBucket(value)
}
// RemoveID removes an ID from the list index
func (idx *ListIndex) RemoveID(targetID []byte) error {
c := idx.IndexBucket.Cursor()
for bucketName, val := c.First(); bucketName != nil; bucketName, val = c.Next() {
if val != nil {
continue
}
uni, err := NewUniqueIndex(idx.IndexBucket, bucketName)
if err != nil {
return err
}
err = uni.Remove(targetID)
if err != nil {
return err
}
}
return idx.IDs.Remove(targetID)
}
// Get the first ID corresponding to the given value
func (idx *ListIndex) Get(value []byte) []byte {
uni, err := NewUniqueIndex(idx.IndexBucket, value)
if err != nil {
return nil
}
return uni.first()
}
// All the IDs corresponding to the given value
func (idx *ListIndex) All(value []byte, opts *Options) ([][]byte, error) {
uni, err := NewUniqueIndex(idx.IndexBucket, value)
if err != nil {
return nil, err
}
return uni.AllRecords(opts)
}
// AllRecords returns all the IDs of this index
func (idx *ListIndex) AllRecords(opts *Options) ([][]byte, error) {
var list [][]byte
c := idx.IndexBucket.Cursor()
for bucketName, val := c.First(); bucketName != nil; bucketName, val = c.Next() {
if val != nil || bytes.Equal(bucketName, []byte("storm__ids")) {
continue
}
uni, err := NewUniqueIndex(idx.IndexBucket, bucketName)
if err != nil {
return nil, err
}
all, err := uni.AllRecords(opts)
if err != nil {
return nil, err
}
list = append(list, all...)
}
return list, nil
}
// Range returns the ids corresponding to the given range of values
func (idx *ListIndex) Range(min []byte, max []byte, opts *Options) ([][]byte, error) {
var list [][]byte
c := idx.IndexBucket.Cursor()
for bucketName, val := c.Seek(min); bucketName != nil && bytes.Compare(bucketName, max) <= 0; bucketName, val = c.Next() {
if val != nil || bytes.Equal(bucketName, []byte("storm__ids")) {
continue
}
uni, err := NewUniqueIndex(idx.IndexBucket, bucketName)
if err != nil {
return nil, err
}
all, err := uni.AllRecords(opts)
if err != nil {
return nil, err
}
list = append(list, all...)
}
return list, nil
}