mirror of
https://github.com/timshannon/bolthold.git
synced 2026-04-23 00:27:06 +08:00
Removed global encode/decode func; added to store
This commit is contained in:
+3
-2
@@ -179,8 +179,9 @@ func (s *Store) FindAggregate(dataType interface{}, query *Query, groupBy ...str
|
||||
|
||||
// TxFindAggregate is the same as FindAggregate, but you specify your own transaction
|
||||
// groupBy is optional
|
||||
func (s *Store) TxFindAggregate(tx *bolt.Tx, dataType interface{}, query *Query, groupBy ...string) ([]*AggregateResult, error) {
|
||||
return aggregateQuery(tx, dataType, query, groupBy...)
|
||||
func (s *Store) TxFindAggregate(tx *bolt.Tx, dataType interface{}, query *Query,
|
||||
groupBy ...string) ([]*AggregateResult, error) {
|
||||
return s.aggregateQuery(tx, dataType, query, groupBy...)
|
||||
}
|
||||
|
||||
func tryFloat(val reflect.Value) float64 {
|
||||
|
||||
+13
-10
@@ -222,7 +222,7 @@ func (q *Query) Or(query *Query) *Query {
|
||||
return q
|
||||
}
|
||||
|
||||
func (q *Query) matchesAllFields(key []byte, value reflect.Value, currentRow interface{}) (bool, error) {
|
||||
func (q *Query) matchesAllFields(s *Store, key []byte, value reflect.Value, currentRow interface{}) (bool, error) {
|
||||
if q.IsEmpty() {
|
||||
return true, nil
|
||||
}
|
||||
@@ -234,7 +234,7 @@ func (q *Query) matchesAllFields(key []byte, value reflect.Value, currentRow int
|
||||
}
|
||||
|
||||
if field == Key {
|
||||
ok, err := matchesAllCriteria(criteria, key, true, currentRow)
|
||||
ok, err := matchesAllCriteria(s, criteria, key, true, currentRow)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
@@ -250,7 +250,7 @@ func (q *Query) matchesAllFields(key []byte, value reflect.Value, currentRow int
|
||||
return false, err
|
||||
}
|
||||
|
||||
ok, err := matchesAllCriteria(criteria, fVal.Interface(), false, currentRow)
|
||||
ok, err := matchesAllCriteria(s, criteria, fVal.Interface(), false, currentRow)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
@@ -383,6 +383,7 @@ type MatchFunc func(ra interface{}) (bool, error)
|
||||
// MatchFunc
|
||||
type RecordAccess struct {
|
||||
tx *bolt.Tx
|
||||
s *Store
|
||||
record interface{}
|
||||
field interface{}
|
||||
}
|
||||
@@ -400,13 +401,13 @@ func (r *RecordAccess) Record() interface{} {
|
||||
// SubQuery allows you to run another query in the same transaction for each
|
||||
// record in a parent query
|
||||
func (r *RecordAccess) SubQuery(result interface{}, query *Query) error {
|
||||
return findQuery(r.tx, result, query)
|
||||
return r.s.findQuery(r.tx, result, query)
|
||||
}
|
||||
|
||||
// SubAggregateQuery allows you to run another aggregate query in the same transaction for each
|
||||
// record in a parent query
|
||||
func (r *RecordAccess) SubAggregateQuery(query *Query, groupBy ...string) ([]*AggregateResult, error) {
|
||||
return aggregateQuery(r.tx, r.record, query, groupBy...)
|
||||
return r.s.aggregateQuery(r.tx, r.record, query, groupBy...)
|
||||
}
|
||||
|
||||
// MatchFunc will test if a field matches the passed in function
|
||||
@@ -419,14 +420,14 @@ func (c *Criterion) MatchFunc(match interface{}) *Query {
|
||||
}
|
||||
|
||||
// test if the criterion passes with the passed in value
|
||||
func (c *Criterion) test(testValue interface{}, encoded bool, currentRow interface{}) (bool, error) {
|
||||
func (c *Criterion) test(s *Store, testValue interface{}, encoded bool, currentRow interface{}) (bool, error) {
|
||||
var recordValue interface{}
|
||||
if encoded {
|
||||
if len(testValue.([]byte)) != 0 {
|
||||
if c.operator == in || c.operator == any || c.operator == all {
|
||||
// value is a slice of values, use c.values
|
||||
recordValue = reflect.New(reflect.TypeOf(c.values[0])).Interface()
|
||||
err := decode(testValue.([]byte), recordValue)
|
||||
err := s.decode(testValue.([]byte), recordValue)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
@@ -434,7 +435,7 @@ func (c *Criterion) test(testValue interface{}, encoded bool, currentRow interfa
|
||||
} else {
|
||||
// used with keys
|
||||
recordValue = reflect.New(reflect.TypeOf(c.value)).Interface()
|
||||
err := decode(testValue.([]byte), recordValue)
|
||||
err := s.decode(testValue.([]byte), recordValue)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
@@ -465,6 +466,7 @@ func (c *Criterion) test(testValue interface{}, encoded bool, currentRow interfa
|
||||
fnVal := reflect.ValueOf(c.value)
|
||||
fnType := reflect.TypeOf(c.value)
|
||||
ra := &RecordAccess{
|
||||
s: s,
|
||||
field: recordValue,
|
||||
record: currentRow,
|
||||
tx: c.query.tx,
|
||||
@@ -575,9 +577,10 @@ func (c *Criterion) test(testValue interface{}, encoded bool, currentRow interfa
|
||||
}
|
||||
}
|
||||
|
||||
func matchesAllCriteria(criteria []*Criterion, value interface{}, encoded bool, currentRow interface{}) (bool, error) {
|
||||
func matchesAllCriteria(s *Store, criteria []*Criterion, value interface{}, encoded bool,
|
||||
currentRow interface{}) (bool, error) {
|
||||
for i := range criteria {
|
||||
ok, err := criteria[i].test(value, encoded, currentRow)
|
||||
ok, err := criteria[i].test(s, value, encoded, currentRow)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
@@ -24,8 +24,8 @@ func (s *Store) TxDelete(tx *bolt.Tx, key, dataType interface{}) error {
|
||||
return bolt.ErrTxNotWritable
|
||||
}
|
||||
|
||||
storer := newStorer(dataType)
|
||||
gk, err := encode(key)
|
||||
storer := s.newStorer(dataType)
|
||||
gk, err := s.encode(key)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -40,7 +40,7 @@ func (s *Store) TxDelete(tx *bolt.Tx, key, dataType interface{}) error {
|
||||
|
||||
bVal := b.Get(gk)
|
||||
|
||||
err = decode(bVal, value)
|
||||
err = s.decode(bVal, value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -53,7 +53,7 @@ func (s *Store) TxDelete(tx *bolt.Tx, key, dataType interface{}) error {
|
||||
}
|
||||
|
||||
// remove any indexes
|
||||
return indexDelete(storer, tx, gk, value)
|
||||
return s.indexDelete(storer, tx, gk, value)
|
||||
}
|
||||
|
||||
// DeleteMatching deletes all of the records that match the passed in query
|
||||
@@ -65,5 +65,5 @@ func (s *Store) DeleteMatching(dataType interface{}, query *Query) error {
|
||||
|
||||
// TxDeleteMatching does the same as DeleteMatching, but allows you to specify your own transaction
|
||||
func (s *Store) TxDeleteMatching(tx *bolt.Tx, dataType interface{}, query *Query) error {
|
||||
return deleteQuery(tx, dataType, query)
|
||||
return s.deleteQuery(tx, dataType, query)
|
||||
}
|
||||
|
||||
@@ -15,9 +15,6 @@ type EncodeFunc func(value interface{}) ([]byte, error)
|
||||
// DecodeFunc is a function for decoding a value from bytes
|
||||
type DecodeFunc func(data []byte, value interface{}) error
|
||||
|
||||
var encode EncodeFunc
|
||||
var decode DecodeFunc
|
||||
|
||||
// DefaultEncode is the default encoding func for bolthold (Gob)
|
||||
func DefaultEncode(value interface{}) ([]byte, error) {
|
||||
var buff bytes.Buffer
|
||||
|
||||
@@ -22,9 +22,9 @@ func (s *Store) Get(key, result interface{}) error {
|
||||
|
||||
// TxGet allows you to pass in your own bolt transaction to retrieve a value from the bolthold and puts it into result
|
||||
func (s *Store) TxGet(tx *bolt.Tx, key, result interface{}) error {
|
||||
storer := newStorer(result)
|
||||
storer := s.newStorer(result)
|
||||
|
||||
gk, err := encode(key)
|
||||
gk, err := s.encode(key)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -40,7 +40,7 @@ func (s *Store) TxGet(tx *bolt.Tx, key, result interface{}) error {
|
||||
return ErrNotFound
|
||||
}
|
||||
|
||||
return decode(value, result)
|
||||
return s.decode(value, result)
|
||||
}
|
||||
|
||||
// Find retrieves a set of values from the bolthold that matches the passed in query
|
||||
@@ -55,7 +55,7 @@ func (s *Store) Find(result interface{}, query *Query) error {
|
||||
|
||||
// TxFind allows you to pass in your own bolt transaction to retrieve a set of values from the bolthold
|
||||
func (s *Store) TxFind(tx *bolt.Tx, result interface{}, query *Query) error {
|
||||
return findQuery(tx, result, query)
|
||||
return s.findQuery(tx, result, query)
|
||||
}
|
||||
|
||||
// FindOne returns a single record, and so result is NOT a slice, but an pointer to a struct, if no record is found
|
||||
@@ -68,7 +68,7 @@ func (s *Store) FindOne(result interface{}, query *Query) error {
|
||||
|
||||
// TxFindOne allows you to pass in your own bolt transaction to retrieve a single record from the bolthold
|
||||
func (s *Store) TxFindOne(tx *bolt.Tx, result interface{}, query *Query) error {
|
||||
return findOneQuery(tx, result, query)
|
||||
return s.findOneQuery(tx, result, query)
|
||||
}
|
||||
|
||||
// Count returns the current record count for the passed in datatype
|
||||
@@ -84,5 +84,5 @@ func (s *Store) Count(dataType interface{}, query *Query) (int, error) {
|
||||
|
||||
// TxCount returns the current record count from within the given transaction for the passed in datatype
|
||||
func (s *Store) TxCount(tx *bolt.Tx, dataType interface{}, query *Query) (int, error) {
|
||||
return countQuery(tx, dataType, query)
|
||||
return s.countQuery(tx, dataType, query)
|
||||
}
|
||||
|
||||
@@ -24,10 +24,10 @@ const iteratorKeyMinCacheSize = 100
|
||||
type Index func(name string, value interface{}) ([]byte, error)
|
||||
|
||||
// adds an item to the index
|
||||
func indexAdd(storer Storer, tx *bolt.Tx, key []byte, data interface{}) error {
|
||||
func (s *Store) indexAdd(storer Storer, tx *bolt.Tx, key []byte, data interface{}) error {
|
||||
indexes := storer.Indexes()
|
||||
for name, index := range indexes {
|
||||
err := indexUpdate(storer.Type(), name, index, tx, key, data, false)
|
||||
err := s.indexUpdate(storer.Type(), name, index, tx, key, data, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -38,11 +38,11 @@ func indexAdd(storer Storer, tx *bolt.Tx, key []byte, data interface{}) error {
|
||||
|
||||
// removes an item from the index
|
||||
// be sure to pass the data from the old record, not the new one
|
||||
func indexDelete(storer Storer, tx *bolt.Tx, key []byte, originalData interface{}) error {
|
||||
func (s *Store) indexDelete(storer Storer, tx *bolt.Tx, key []byte, originalData interface{}) error {
|
||||
indexes := storer.Indexes()
|
||||
|
||||
for name, index := range indexes {
|
||||
err := indexUpdate(storer.Type(), name, index, tx, key, originalData, true)
|
||||
err := s.indexUpdate(storer.Type(), name, index, tx, key, originalData, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -52,7 +52,8 @@ func indexDelete(storer Storer, tx *bolt.Tx, key []byte, originalData interface{
|
||||
}
|
||||
|
||||
// adds or removes a specific index on an item
|
||||
func indexUpdate(typeName, indexName string, index Index, tx *bolt.Tx, key []byte, value interface{}, delete bool) error {
|
||||
func (s *Store) indexUpdate(typeName, indexName string, index Index, tx *bolt.Tx, key []byte, value interface{},
|
||||
delete bool) error {
|
||||
indexKey, err := index(indexName, value)
|
||||
if indexKey == nil {
|
||||
return nil
|
||||
@@ -71,7 +72,7 @@ func indexUpdate(typeName, indexName string, index Index, tx *bolt.Tx, key []byt
|
||||
|
||||
iVal := b.Get(indexKey)
|
||||
if iVal != nil {
|
||||
err = decode(iVal, &indexValue)
|
||||
err = s.decode(iVal, &indexValue)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -87,7 +88,7 @@ func indexUpdate(typeName, indexName string, index Index, tx *bolt.Tx, key []byt
|
||||
return b.Delete(indexKey)
|
||||
}
|
||||
|
||||
iVal, err = encode(indexValue)
|
||||
iVal, err = s.encode(indexValue)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -152,7 +153,7 @@ type iterator struct {
|
||||
err error
|
||||
}
|
||||
|
||||
func newIterator(tx *bolt.Tx, typeName string, query *Query) *iterator {
|
||||
func (s *Store) newIterator(tx *bolt.Tx, typeName string, query *Query) *iterator {
|
||||
|
||||
iter := &iterator{
|
||||
dataBucket: tx.Bucket([]byte(typeName)),
|
||||
@@ -186,12 +187,12 @@ func newIterator(tx *bolt.Tx, typeName string, query *Query) *iterator {
|
||||
|
||||
val := reflect.New(query.dataType)
|
||||
v := iter.dataBucket.Get(k)
|
||||
err := decode(v, val.Interface())
|
||||
err := s.decode(v, val.Interface())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ok, err := matchesAllCriteria(criteria, k, true, val.Interface())
|
||||
ok, err := matchesAllCriteria(s, criteria, k, true, val.Interface())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -259,7 +260,7 @@ func newIterator(tx *bolt.Tx, typeName string, query *Query) *iterator {
|
||||
}
|
||||
|
||||
// no currentRow on indexes as it refers to multiple rows
|
||||
ok, err := matchesAllCriteria(criteria, k, true, nil)
|
||||
ok, err := matchesAllCriteria(s, criteria, k, true, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -267,7 +268,7 @@ func newIterator(tx *bolt.Tx, typeName string, query *Query) *iterator {
|
||||
if ok {
|
||||
// append the slice of keys stored in the index
|
||||
var keys = make(keyList, 0)
|
||||
err := decode(v, &keys)
|
||||
err := s.decode(v, &keys)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ func (s *Store) TxInsert(tx *bolt.Tx, key, data interface{}) error {
|
||||
return bolt.ErrTxNotWritable
|
||||
}
|
||||
|
||||
storer := newStorer(data)
|
||||
storer := s.newStorer(data)
|
||||
|
||||
b, err := tx.CreateBucketIfNotExists([]byte(storer.Type()))
|
||||
if err != nil {
|
||||
@@ -59,7 +59,7 @@ func (s *Store) TxInsert(tx *bolt.Tx, key, data interface{}) error {
|
||||
}
|
||||
}
|
||||
|
||||
gk, err := encode(key)
|
||||
gk, err := s.encode(key)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -69,7 +69,7 @@ func (s *Store) TxInsert(tx *bolt.Tx, key, data interface{}) error {
|
||||
return ErrKeyExists
|
||||
}
|
||||
|
||||
value, err := encode(data)
|
||||
value, err := s.encode(data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -82,7 +82,7 @@ func (s *Store) TxInsert(tx *bolt.Tx, key, data interface{}) error {
|
||||
}
|
||||
|
||||
// insert any indexes
|
||||
err = indexAdd(storer, tx, gk, data)
|
||||
err = s.indexAdd(storer, tx, gk, data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -131,9 +131,9 @@ func (s *Store) TxUpdate(tx *bolt.Tx, key interface{}, data interface{}) error {
|
||||
return bolt.ErrTxNotWritable
|
||||
}
|
||||
|
||||
storer := newStorer(data)
|
||||
storer := s.newStorer(data)
|
||||
|
||||
gk, err := encode(key)
|
||||
gk, err := s.encode(key)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -153,17 +153,17 @@ func (s *Store) TxUpdate(tx *bolt.Tx, key interface{}, data interface{}) error {
|
||||
// delete any existing indexes
|
||||
existingVal := reflect.New(reflect.TypeOf(data)).Interface()
|
||||
|
||||
err = decode(existing, existingVal)
|
||||
err = s.decode(existing, existingVal)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = indexDelete(storer, tx, gk, existingVal)
|
||||
err = s.indexDelete(storer, tx, gk, existingVal)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
value, err := encode(data)
|
||||
value, err := s.encode(data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -175,7 +175,7 @@ func (s *Store) TxUpdate(tx *bolt.Tx, key interface{}, data interface{}) error {
|
||||
}
|
||||
|
||||
// insert any new indexes
|
||||
return indexAdd(storer, tx, gk, data)
|
||||
return s.indexAdd(storer, tx, gk, data)
|
||||
}
|
||||
|
||||
// Upsert inserts the record into the bolthold if it doesn't exist. If it does already exist, then it updates
|
||||
@@ -192,9 +192,9 @@ func (s *Store) TxUpsert(tx *bolt.Tx, key interface{}, data interface{}) error {
|
||||
return bolt.ErrTxNotWritable
|
||||
}
|
||||
|
||||
storer := newStorer(data)
|
||||
storer := s.newStorer(data)
|
||||
|
||||
gk, err := encode(key)
|
||||
gk, err := s.encode(key)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -212,19 +212,19 @@ func (s *Store) TxUpsert(tx *bolt.Tx, key interface{}, data interface{}) error {
|
||||
// delete any existing indexes
|
||||
existingVal := reflect.New(reflect.TypeOf(data)).Interface()
|
||||
|
||||
err = decode(existing, existingVal)
|
||||
err = s.decode(existing, existingVal)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = indexDelete(storer, tx, gk, existingVal)
|
||||
err = s.indexDelete(storer, tx, gk, existingVal)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
value, err := encode(data)
|
||||
value, err := s.encode(data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -236,7 +236,7 @@ func (s *Store) TxUpsert(tx *bolt.Tx, key interface{}, data interface{}) error {
|
||||
}
|
||||
|
||||
// insert any new indexes
|
||||
return indexAdd(storer, tx, gk, data)
|
||||
return s.indexAdd(storer, tx, gk, data)
|
||||
}
|
||||
|
||||
// UpdateMatching runs the update function for every record that match the passed in query
|
||||
@@ -249,5 +249,5 @@ func (s *Store) UpdateMatching(dataType interface{}, query *Query, update func(r
|
||||
|
||||
// TxUpdateMatching does the same as UpdateMatching, but allows you to specify your own transaction
|
||||
func (s *Store) TxUpdateMatching(tx *bolt.Tx, dataType interface{}, query *Query, update func(record interface{}) error) error {
|
||||
return updateQuery(tx, dataType, query, update)
|
||||
return s.updateQuery(tx, dataType, query, update)
|
||||
}
|
||||
|
||||
@@ -18,9 +18,9 @@ type record struct {
|
||||
value reflect.Value
|
||||
}
|
||||
|
||||
func runQuery(tx *bolt.Tx, dataType interface{}, query *Query, retrievedKeys keyList, skip int,
|
||||
func (s *Store) runQuery(tx *bolt.Tx, dataType interface{}, query *Query, retrievedKeys keyList, skip int,
|
||||
action func(r *record) error) error {
|
||||
storer := newStorer(dataType)
|
||||
storer := s.newStorer(dataType)
|
||||
|
||||
bkt := tx.Bucket([]byte(storer.Type()))
|
||||
if bkt == nil || bkt.Stats().KeyN == 0 {
|
||||
@@ -41,10 +41,10 @@ func runQuery(tx *bolt.Tx, dataType interface{}, query *Query, retrievedKeys key
|
||||
query.dataType = reflect.TypeOf(tp)
|
||||
|
||||
if len(query.sort) > 0 {
|
||||
return runQuerySort(tx, dataType, query, action)
|
||||
return s.runQuerySort(tx, dataType, query, action)
|
||||
}
|
||||
|
||||
iter := newIterator(tx, storer.Type(), query)
|
||||
iter := s.newIterator(tx, storer.Type(), query)
|
||||
|
||||
newKeys := make(keyList, 0)
|
||||
|
||||
@@ -60,14 +60,14 @@ func runQuery(tx *bolt.Tx, dataType interface{}, query *Query, retrievedKeys key
|
||||
|
||||
val := reflect.New(reflect.TypeOf(tp))
|
||||
|
||||
err := decode(v, val.Interface())
|
||||
err := s.decode(v, val.Interface())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
query.tx = tx
|
||||
|
||||
ok, err := query.matchesAllFields(k, val, val.Interface())
|
||||
ok, err := query.matchesAllFields(s, k, val, val.Interface())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -113,7 +113,7 @@ func runQuery(tx *bolt.Tx, dataType interface{}, query *Query, retrievedKeys key
|
||||
}
|
||||
|
||||
for i := range query.ors {
|
||||
err := runQuery(tx, tp, query.ors[i], retrievedKeys, skip, action)
|
||||
err := s.runQuery(tx, tp, query.ors[i], retrievedKeys, skip, action)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -124,7 +124,7 @@ func runQuery(tx *bolt.Tx, dataType interface{}, query *Query, retrievedKeys key
|
||||
}
|
||||
|
||||
// runQuerySort runs the query without sort, skip, or limit, then applies them to the entire result set
|
||||
func runQuerySort(tx *bolt.Tx, dataType interface{}, query *Query, action func(r *record) error) error {
|
||||
func (s *Store) runQuerySort(tx *bolt.Tx, dataType interface{}, query *Query, action func(r *record) error) error {
|
||||
// Validate sort fields
|
||||
for _, field := range query.sort {
|
||||
fields := strings.Split(field, ".")
|
||||
@@ -154,7 +154,7 @@ func runQuerySort(tx *bolt.Tx, dataType interface{}, query *Query, action func(r
|
||||
qCopy.skip = 0
|
||||
|
||||
var records []*record
|
||||
err := runQuery(tx, dataType, &qCopy, nil, 0,
|
||||
err := s.runQuery(tx, dataType, &qCopy, nil, 0,
|
||||
func(r *record) error {
|
||||
records = append(records, r)
|
||||
|
||||
@@ -232,7 +232,7 @@ func runQuerySort(tx *bolt.Tx, dataType interface{}, query *Query, action func(r
|
||||
|
||||
}
|
||||
|
||||
func findQuery(tx *bolt.Tx, result interface{}, query *Query) error {
|
||||
func (s *Store) findQuery(tx *bolt.Tx, result interface{}, query *Query) error {
|
||||
if query == nil {
|
||||
query = &Query{}
|
||||
}
|
||||
@@ -265,7 +265,7 @@ func findQuery(tx *bolt.Tx, result interface{}, query *Query) error {
|
||||
|
||||
val := reflect.New(tp)
|
||||
|
||||
err := runQuery(tx, val.Interface(), query, nil, query.skip,
|
||||
err := s.runQuery(tx, val.Interface(), query, nil, query.skip,
|
||||
func(r *record) error {
|
||||
var rowValue reflect.Value
|
||||
|
||||
@@ -281,7 +281,7 @@ func findQuery(tx *bolt.Tx, result interface{}, query *Query) error {
|
||||
for rowKey.Kind() == reflect.Ptr {
|
||||
rowKey = rowKey.Elem()
|
||||
}
|
||||
err := decode(r.key, rowKey.FieldByName(keyField).Addr().Interface())
|
||||
err := s.decode(r.key, rowKey.FieldByName(keyField).Addr().Interface())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -301,14 +301,14 @@ func findQuery(tx *bolt.Tx, result interface{}, query *Query) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func deleteQuery(tx *bolt.Tx, dataType interface{}, query *Query) error {
|
||||
func (s *Store) deleteQuery(tx *bolt.Tx, dataType interface{}, query *Query) error {
|
||||
if query == nil {
|
||||
query = &Query{}
|
||||
}
|
||||
|
||||
var records []*record
|
||||
|
||||
err := runQuery(tx, dataType, query, nil, query.skip,
|
||||
err := s.runQuery(tx, dataType, query, nil, query.skip,
|
||||
func(r *record) error {
|
||||
records = append(records, r)
|
||||
|
||||
@@ -319,7 +319,7 @@ func deleteQuery(tx *bolt.Tx, dataType interface{}, query *Query) error {
|
||||
return err
|
||||
}
|
||||
|
||||
storer := newStorer(dataType)
|
||||
storer := s.newStorer(dataType)
|
||||
|
||||
b := tx.Bucket([]byte(storer.Type()))
|
||||
for i := range records {
|
||||
@@ -329,7 +329,7 @@ func deleteQuery(tx *bolt.Tx, dataType interface{}, query *Query) error {
|
||||
}
|
||||
|
||||
// remove any indexes
|
||||
err = indexDelete(storer, tx, records[i].key, records[i].value.Interface())
|
||||
err = s.indexDelete(storer, tx, records[i].key, records[i].value.Interface())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -338,14 +338,14 @@ func deleteQuery(tx *bolt.Tx, dataType interface{}, query *Query) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func updateQuery(tx *bolt.Tx, dataType interface{}, query *Query, update func(record interface{}) error) error {
|
||||
func (s *Store) updateQuery(tx *bolt.Tx, dataType interface{}, query *Query, update func(record interface{}) error) error {
|
||||
if query == nil {
|
||||
query = &Query{}
|
||||
}
|
||||
|
||||
var records []*record
|
||||
|
||||
err := runQuery(tx, dataType, query, nil, query.skip,
|
||||
err := s.runQuery(tx, dataType, query, nil, query.skip,
|
||||
func(r *record) error {
|
||||
records = append(records, r)
|
||||
|
||||
@@ -357,14 +357,14 @@ func updateQuery(tx *bolt.Tx, dataType interface{}, query *Query, update func(re
|
||||
return err
|
||||
}
|
||||
|
||||
storer := newStorer(dataType)
|
||||
storer := s.newStorer(dataType)
|
||||
b := tx.Bucket([]byte(storer.Type()))
|
||||
|
||||
for i := range records {
|
||||
upVal := records[i].value.Interface()
|
||||
|
||||
// delete any existing indexes bad on original value
|
||||
err := indexDelete(storer, tx, records[i].key, upVal)
|
||||
err := s.indexDelete(storer, tx, records[i].key, upVal)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -374,7 +374,7 @@ func updateQuery(tx *bolt.Tx, dataType interface{}, query *Query, update func(re
|
||||
return err
|
||||
}
|
||||
|
||||
encVal, err := encode(upVal)
|
||||
encVal, err := s.encode(upVal)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -385,7 +385,7 @@ func updateQuery(tx *bolt.Tx, dataType interface{}, query *Query, update func(re
|
||||
}
|
||||
|
||||
// insert any new indexes
|
||||
err = indexAdd(storer, tx, records[i].key, upVal)
|
||||
err = s.indexAdd(storer, tx, records[i].key, upVal)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -394,7 +394,8 @@ func updateQuery(tx *bolt.Tx, dataType interface{}, query *Query, update func(re
|
||||
return nil
|
||||
}
|
||||
|
||||
func aggregateQuery(tx *bolt.Tx, dataType interface{}, query *Query, groupBy ...string) ([]*AggregateResult, error) {
|
||||
func (s *Store) aggregateQuery(tx *bolt.Tx, dataType interface{}, query *Query,
|
||||
groupBy ...string) ([]*AggregateResult, error) {
|
||||
if query == nil {
|
||||
query = &Query{}
|
||||
}
|
||||
@@ -405,7 +406,7 @@ func aggregateQuery(tx *bolt.Tx, dataType interface{}, query *Query, groupBy ...
|
||||
result = append(result, &AggregateResult{})
|
||||
}
|
||||
|
||||
err := runQuery(tx, dataType, query, nil, query.skip,
|
||||
err := s.runQuery(tx, dataType, query, nil, query.skip,
|
||||
func(r *record) error {
|
||||
if len(groupBy) == 0 {
|
||||
result[0].reduction = append(result[0].reduction, r.value)
|
||||
@@ -472,14 +473,14 @@ func aggregateQuery(tx *bolt.Tx, dataType interface{}, query *Query, groupBy ...
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func countQuery(tx *bolt.Tx, dataType interface{}, query *Query) (int, error) {
|
||||
func (s *Store) countQuery(tx *bolt.Tx, dataType interface{}, query *Query) (int, error) {
|
||||
if query == nil {
|
||||
query = &Query{}
|
||||
}
|
||||
|
||||
count := 0
|
||||
|
||||
err := runQuery(tx, dataType, query, nil, query.skip,
|
||||
err := s.runQuery(tx, dataType, query, nil, query.skip,
|
||||
func(r *record) error {
|
||||
count++
|
||||
return nil
|
||||
@@ -492,7 +493,7 @@ func countQuery(tx *bolt.Tx, dataType interface{}, query *Query) (int, error) {
|
||||
return count, nil
|
||||
}
|
||||
|
||||
func findOneQuery(tx *bolt.Tx, result interface{}, query *Query) error {
|
||||
func (s *Store) findOneQuery(tx *bolt.Tx, result interface{}, query *Query) error {
|
||||
if query == nil {
|
||||
query = &Query{}
|
||||
}
|
||||
@@ -521,7 +522,7 @@ func findOneQuery(tx *bolt.Tx, result interface{}, query *Query) error {
|
||||
|
||||
found := false
|
||||
|
||||
err := runQuery(tx, result, query, nil, query.skip,
|
||||
err := s.runQuery(tx, result, query, nil, query.skip,
|
||||
func(r *record) error {
|
||||
found = true
|
||||
|
||||
@@ -530,7 +531,7 @@ func findOneQuery(tx *bolt.Tx, result interface{}, query *Query) error {
|
||||
for rowKey.Kind() == reflect.Ptr {
|
||||
rowKey = rowKey.Elem()
|
||||
}
|
||||
err := decode(r.key, rowKey.FieldByName(keyField).Addr().Interface())
|
||||
err := s.decode(r.key, rowKey.FieldByName(keyField).Addr().Interface())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -14,7 +14,9 @@ import (
|
||||
|
||||
// Store is a bolthold wrapper around a bolt DB
|
||||
type Store struct {
|
||||
db *bolt.DB
|
||||
db *bolt.DB
|
||||
encode EncodeFunc
|
||||
decode DecodeFunc
|
||||
}
|
||||
|
||||
// Options allows you set different options from the defaults
|
||||
@@ -29,16 +31,15 @@ type Options struct {
|
||||
func Open(filename string, mode os.FileMode, options *Options) (*Store, error) {
|
||||
options = fillOptions(options)
|
||||
|
||||
encode = options.Encoder
|
||||
decode = options.Decoder
|
||||
|
||||
db, err := bolt.Open(filename, mode, options.Options)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &Store{
|
||||
db: db,
|
||||
db: db,
|
||||
encode: options.Encoder,
|
||||
decode: options.Decoder,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -73,7 +74,7 @@ func (s *Store) Close() error {
|
||||
// if bucketName is nil, then we'll assume a bucketName of storer.Type()
|
||||
// if a bucketname is specified, then the data will be copied to the bolthold standard bucket of storer.Type()
|
||||
func (s *Store) ReIndex(exampleType interface{}, bucketName []byte) error {
|
||||
storer := newStorer(exampleType)
|
||||
storer := s.newStorer(exampleType)
|
||||
|
||||
return s.Bolt().Update(func(tx *bolt.Tx) error {
|
||||
indexes := storer.Indexes()
|
||||
@@ -109,11 +110,11 @@ func (s *Store) ReIndex(exampleType interface{}, bucketName []byte) error {
|
||||
return err
|
||||
}
|
||||
}
|
||||
err := decode(v, exampleType)
|
||||
err := s.decode(v, exampleType)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = indexAdd(storer, tx, k, exampleType)
|
||||
err = s.indexAdd(storer, tx, k, exampleType)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -125,7 +126,7 @@ func (s *Store) ReIndex(exampleType interface{}, bucketName []byte) error {
|
||||
|
||||
// RemoveIndex removes an index from the store.
|
||||
func (s *Store) RemoveIndex(dataType interface{}, indexName string) error {
|
||||
storer := newStorer(dataType)
|
||||
storer := s.newStorer(dataType)
|
||||
return s.Bolt().Update(func(tx *bolt.Tx) error {
|
||||
return tx.DeleteBucket(indexBucketName(storer.Type(), indexName))
|
||||
|
||||
@@ -157,11 +158,11 @@ func (t *anonStorer) Indexes() map[string]Index {
|
||||
// newStorer creates a type which satisfies the Storer interface based on reflection of the passed in dataType
|
||||
// if the Type doesn't meet the requirements of a Storer (i.e. doesn't have a name) it panics
|
||||
// You can avoid any reflection costs, by implementing the Storer interface on a type
|
||||
func newStorer(dataType interface{}) Storer {
|
||||
s, ok := dataType.(Storer)
|
||||
func (s *Store) newStorer(dataType interface{}) Storer {
|
||||
str, ok := dataType.(Storer)
|
||||
|
||||
if ok {
|
||||
return s
|
||||
return str
|
||||
}
|
||||
|
||||
tp := reflect.TypeOf(dataType)
|
||||
@@ -197,7 +198,7 @@ func newStorer(dataType interface{}) Storer {
|
||||
tp = tp.Elem()
|
||||
}
|
||||
|
||||
return encode(tp.FieldByName(name).Interface())
|
||||
return s.encode(tp.FieldByName(name).Interface())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+65
-6
@@ -53,7 +53,7 @@ func TestRemoveIndex(t *testing.T) {
|
||||
|
||||
err := store.Bolt().View(func(tx *bolt.Tx) error {
|
||||
if tx.Bucket(iName) == nil {
|
||||
return fmt.Errorf("Index %s doesn't exist!", iName)
|
||||
return fmt.Errorf("index %s doesn't exist", iName)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
@@ -69,7 +69,7 @@ func TestRemoveIndex(t *testing.T) {
|
||||
|
||||
err = store.Bolt().View(func(tx *bolt.Tx) error {
|
||||
if tx.Bucket(iName) != nil {
|
||||
return fmt.Errorf("Index %s wasn't removed!", iName)
|
||||
return fmt.Errorf("index %s wasn't removed", iName)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
@@ -94,7 +94,7 @@ func TestReIndex(t *testing.T) {
|
||||
|
||||
err = store.Bolt().View(func(tx *bolt.Tx) error {
|
||||
if tx.Bucket(iName) != nil {
|
||||
return fmt.Errorf("Index %s wasn't removed!", iName)
|
||||
return fmt.Errorf("index %s wasn't removed", iName)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
@@ -109,7 +109,7 @@ func TestReIndex(t *testing.T) {
|
||||
|
||||
err = store.Bolt().View(func(tx *bolt.Tx) error {
|
||||
if tx.Bucket(iName) == nil {
|
||||
return fmt.Errorf("Index %s wasn't rebuilt!", iName)
|
||||
return fmt.Errorf("index %s wasn't rebuilt", iName)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
@@ -126,7 +126,7 @@ func TestIndexExists(t *testing.T) {
|
||||
insertTestData(t, store)
|
||||
err := store.Bolt().View(func(tx *bolt.Tx) error {
|
||||
if !store.IndexExists(tx, "ItemTest", "Category") {
|
||||
return fmt.Errorf("Index %s doesn't exist!", "ItemTest:Category")
|
||||
return fmt.Errorf("index %s doesn't exist", "ItemTest:Category")
|
||||
}
|
||||
return nil
|
||||
})
|
||||
@@ -155,7 +155,7 @@ func TestReIndexWithCopy(t *testing.T) {
|
||||
|
||||
err = store.Bolt().View(func(tx *bolt.Tx) error {
|
||||
if tx.Bucket(iName) == nil {
|
||||
return fmt.Errorf("Index %s wasn't rebuilt!", iName)
|
||||
return fmt.Errorf("index %s wasn't rebuilt", iName)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
@@ -201,6 +201,65 @@ func TestAlternateEncoding(t *testing.T) {
|
||||
|
||||
}
|
||||
|
||||
func TestPerStoreEncoding(t *testing.T) {
|
||||
jsnFilename := tempfile()
|
||||
jsnStore, err := bolthold.Open(jsnFilename, 0666, &bolthold.Options{
|
||||
Encoder: json.Marshal,
|
||||
Decoder: json.Unmarshal,
|
||||
})
|
||||
defer jsnStore.Close()
|
||||
defer os.Remove(jsnFilename)
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("Error opening %s: %s", jsnFilename, err)
|
||||
}
|
||||
|
||||
gobFilename := tempfile()
|
||||
gobStore, err := bolthold.Open(gobFilename, 0666, &bolthold.Options{})
|
||||
defer gobStore.Close()
|
||||
defer os.Remove(gobFilename)
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("Error opening %s: %s", gobFilename, err)
|
||||
}
|
||||
|
||||
insertTestData(t, jsnStore)
|
||||
insertTestData(t, gobStore)
|
||||
|
||||
tData := testData[3]
|
||||
|
||||
var result []ItemTest
|
||||
|
||||
jsnStore.Find(&result, bolthold.Where(bolthold.Key).Eq(tData.Key))
|
||||
|
||||
if len(result) != 1 {
|
||||
if testing.Verbose() {
|
||||
t.Fatalf("Find result count is %d wanted %d. Results: %v", len(result), 1, result)
|
||||
}
|
||||
t.Fatalf("Find result count is %d wanted %d.", len(result), 1)
|
||||
}
|
||||
|
||||
if !result[0].equal(&tData) {
|
||||
t.Fatalf("Results not equal! Wanted %v, got %v", tData, result[0])
|
||||
}
|
||||
|
||||
result = []ItemTest{}
|
||||
|
||||
gobStore.Find(&result, bolthold.Where(bolthold.Key).Eq(tData.Key))
|
||||
|
||||
if len(result) != 1 {
|
||||
if testing.Verbose() {
|
||||
t.Fatalf("Find result count is %d wanted %d. Results: %v", len(result), 1, result)
|
||||
}
|
||||
t.Fatalf("Find result count is %d wanted %d.", len(result), 1)
|
||||
}
|
||||
|
||||
if !result[0].equal(&tData) {
|
||||
t.Fatalf("Results not equal! Wanted %v, got %v", tData, result[0])
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestGetUnknownType(t *testing.T) {
|
||||
filename := tempfile()
|
||||
store, err := bolthold.Open(filename, 0666, &bolthold.Options{
|
||||
|
||||
Reference in New Issue
Block a user