Removed global encode/decode func; added to store

This commit is contained in:
Tim Shannon
2019-08-12 11:43:35 -05:00
parent 322df21f30
commit ccc782476d
10 changed files with 166 additions and 103 deletions
+3 -2
View File
@@ -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
View File
@@ -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
}
+5 -5
View File
@@ -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)
}
-3
View File
@@ -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
+6 -6
View File
@@ -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)
}
+13 -12
View File
@@ -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
}
+17 -17
View File
@@ -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)
}
+30 -29
View File
@@ -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 -13
View File
@@ -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
View File
@@ -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{