Skip to content

Commit c3dfed2

Browse files
committed
feat: filter added
1 parent ce5f984 commit c3dfed2

5 files changed

Lines changed: 64 additions & 1 deletion

File tree

etcd/etcdv3.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,12 @@ func (e *Backend) Get(key string, ops ...store.GetOption) ([]store.Entry, error)
175175
return []store.Entry{}, store.ErrKeyNotFound
176176
}
177177

178+
if opts.Filter == nil {
179+
opts.Filter = func([]byte, []byte) bool {
180+
return true
181+
}
182+
}
183+
178184
if opts.Handler == nil {
179185
opts.Handler = func([]byte, []byte) error {
180186
return nil
@@ -184,6 +190,10 @@ func (e *Backend) Get(key string, ops ...store.GetOption) ([]store.Entry, error)
184190
result := []store.Entry{}
185191

186192
for _, value := range resp.Kvs {
193+
if ok := opts.Filter([]byte(e.RelKey(string(value.Key))), value.Value); !ok {
194+
continue
195+
}
196+
187197
if err := opts.Handler([]byte(e.RelKey(string(value.Key))), value.Value); err != nil {
188198
return result, err
189199
}

etcd/etcdv3_test.go

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"context"
55
"encoding/json"
66
"fmt"
7+
"strings"
78
"testing"
89
"time"
910

@@ -105,6 +106,15 @@ func TestGet(t *testing.T) {
105106
assert.Equal(t, expEntries, e)
106107
})
107108

109+
t.Run("get with filter", func(t *testing.T) {
110+
filter := func(k []byte, v []byte) bool {
111+
return strings.HasSuffix(string(k), "6")
112+
}
113+
e, err := b.Get("key", store.WithPrefix(), store.WithFilter(filter))
114+
require.NoError(t, err)
115+
assert.Equal(t, expEntries[6], e[0])
116+
})
117+
108118
t.Run("get with handler", func(t *testing.T) {
109119
entry := store.Entry{}
110120
handler := func(k []byte, v []byte) error {
@@ -517,7 +527,7 @@ func setupTestStore(t *testing.T, log bool, opts []Opt) (store.BackendKeyer, *cl
517527

518528
backend, err := New(append([]Opt{WithClient(cli)}, opts...)...)
519529
if err != nil {
520-
t.Errorf("failed to create backend: %w", err)
530+
t.Errorf("failed to create backend: %v", err)
521531
}
522532

523533
return backend, cli, func() { cluster.Terminate(t) }

hash/hash.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,13 +148,20 @@ func (h *Backend) keys(prefix string) []string {
148148
// Get returns a list of store entries
149149
// WithPrefix, WithHandler are supported
150150
// WithContext will be ignored
151+
//nolint:gocyclo // review
151152
func (h *Backend) Get(key string, ops ...store.GetOption) ([]store.Entry, error) {
152153
opts := &store.GetOptions{}
153154

154155
for _, op := range ops {
155156
op.SetGetOption(opts)
156157
}
157158

159+
if opts.Filter == nil {
160+
opts.Filter = func([]byte, []byte) bool {
161+
return true
162+
}
163+
}
164+
158165
if opts.Handler == nil {
159166
opts.Handler = func([]byte, []byte) error {
160167
return nil
@@ -176,6 +183,10 @@ func (h *Backend) Get(key string, ops ...store.GetOption) ([]store.Entry, error)
176183
h.RUnlock()
177184

178185
if ok && h.exists(v) {
186+
if ok := opts.Filter([]byte(v.Data.Key), v.Data.Value); !ok {
187+
continue
188+
}
189+
179190
if opts.Unmarshal != nil && !opts.Unmarshal.IsSlice() {
180191
return nil, json.Unmarshal(v.Data.Value, &opts.Unmarshal.Input)
181192
}

hash/hash_test.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"context"
55
"encoding/json"
66
"fmt"
7+
"strings"
78
"testing"
89
"time"
910

@@ -105,6 +106,15 @@ func TestGet(t *testing.T) {
105106
assert.Equal(t, expEntries, e)
106107
})
107108

109+
t.Run("get with filter", func(t *testing.T) {
110+
filter := func(k []byte, v []byte) bool {
111+
return strings.HasSuffix(string(k), "6")
112+
}
113+
e, err := b.Get("key", store.WithPrefix(), store.WithFilter(filter))
114+
require.NoError(t, err)
115+
assert.Equal(t, expEntries[6], e[0])
116+
})
117+
108118
t.Run("get with handler", func(t *testing.T) {
109119
entry := store.Entry{}
110120
handler := func(k []byte, v []byte) error {

store.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@ var (
1616
ErrResponseChannelClosed = errors.New("keepalive response channel has been closed")
1717
)
1818

19+
// FilterFunc is a function that is called on (each) returned
20+
// key-value pair during a Get request.
21+
type FilterFunc func([]byte, []byte) bool
22+
1923
// HandlerFunc is a function that is called on (each) returned
2024
// key-value pair during a Get request.
2125
type HandlerFunc func([]byte, []byte) error
@@ -96,6 +100,7 @@ func Put(b Backend, key string, v interface{}, opts ...PutOption) (bool, error)
96100
// GetOptions represent all possible options for Get requests.
97101
type GetOptions struct {
98102
Prefix bool
103+
Filter FilterFunc
99104
Handler HandlerFunc
100105
Context context.Context
101106
Unmarshal *unmarshal
@@ -142,6 +147,14 @@ func WithContext(ctx context.Context) interface {
142147
return &contextOption{Context: ctx}
143148
}
144149

150+
// WithFilter is an option to use an FilterFunc on each
151+
// key-value pair during a Get request.
152+
func WithFilter(f FilterFunc) interface {
153+
GetOption
154+
} {
155+
return &filterOption{Filter: f}
156+
}
157+
145158
// WithHandler is an option to use an HandlerFunc on each
146159
// key-value pair during a Get request.
147160
func WithHandler(h HandlerFunc) interface {
@@ -257,6 +270,15 @@ func (c *contextOption) SetDelOption(opts *DelOptions) {
257270
opts.Context = c.Context
258271
}
259272

273+
// filter
274+
type filterOption struct {
275+
Filter FilterFunc
276+
}
277+
278+
func (h *filterOption) SetGetOption(opts *GetOptions) {
279+
opts.Filter = h.Filter
280+
}
281+
260282
// handler
261283
type handlerOption struct {
262284
Handler HandlerFunc

0 commit comments

Comments
 (0)