184 lines
3.7 KiB
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
|
|
}
|