-
Notifications
You must be signed in to change notification settings - Fork 46
/
helpers.go
97 lines (85 loc) · 2.89 KB
/
helpers.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
package app
import (
"github.com/iov-one/weave"
"github.com/iov-one/weave/errors"
"github.com/iov-one/weave/store"
abci "github.com/tendermint/tendermint/abci/types"
)
// Queryable is implemented by an abci.Application, but also weave/client.Client (over tendermint)
type Queryable interface {
Query(query abci.RequestQuery) abci.ResponseQuery
}
// ABCIStore exposes the weave abci.Query interface as a ReadonlyKVStore
type ABCIStore struct {
app Queryable
}
var _ weave.ReadOnlyKVStore = (*ABCIStore)(nil)
func NewABCIStore(app Queryable) *ABCIStore {
return &ABCIStore{app: app}
}
// Get will query for exactly one value over the abci store.
// This can be wrapped with a bucket to reuse key/index/parse logic
func (a *ABCIStore) Get(key []byte) ([]byte, error) {
query := a.app.Query(abci.RequestQuery{
Path: "/",
Data: key,
})
// if only the interface supported returning errors....
if query.Code != 0 {
return nil, errors.Wrap(errors.ErrDatabase, query.Log)
}
var value ResultSet
if err := value.Unmarshal(query.Value); err != nil {
return nil, errors.Wrapf(errors.ErrState, "unmarshal result set: %v", err.Error())
}
if len(value.Results) == 0 {
return nil, nil
}
// TODO: assert error if len > 1 ???
return value.Results[0], nil
}
// Has returns true if the given key in in the abci app store
func (a *ABCIStore) Has(key []byte) (bool, error) {
got, err := a.Get(key)
if err != nil {
return false, err
}
return len(got) > 0, nil
}
// Iterator attempts to do a range iteration over the store,
// We only support prefix queries in the abci server for now.
// This client only supports listing everything...
func (a *ABCIStore) Iterator(start, end []byte) (weave.Iterator, error) {
// TODO: support all prefix searches (later even more ranges)
// look at orm/query.go:prefixRange for an idea how we turn prefix->iterator,
// we should detect this case and reverse it so we can serialize over abci query
if start != nil || end != nil {
return nil, errors.Wrap(errors.ErrDatabase, "iterator only implemented for entire range")
}
query := a.app.Query(abci.RequestQuery{
Path: "/?prefix",
Data: nil,
})
if query.Code != 0 {
return nil, errors.Wrap(errors.ErrDatabase, query.Log)
}
models, err := toModels(query.Key, query.Value)
if err != nil {
return nil, err
}
return store.NewSliceIterator(models), nil
}
func (a *ABCIStore) ReverseIterator(start, end []byte) (weave.Iterator, error) {
// TODO: load normal iterator but then play it backwards?
return nil, errors.Wrap(errors.ErrDatabase, "not implemented")
}
func toModels(keys, values []byte) ([]weave.Model, error) {
var k, v ResultSet
if err := k.Unmarshal(keys); err != nil {
return nil, errors.Wrapf(errors.ErrState, "cannot unmarshal keys: %v", err.Error())
}
if err := v.Unmarshal(values); err != nil {
return nil, errors.Wrapf(errors.ErrState, "cannot unmarshal values: %v", err.Error())
}
return JoinResults(&k, &v)
}