@@ -3,7 +3,6 @@ package types
33import (
44 "bytes"
55 "errors"
6- "fmt"
76 "io"
87 "reflect"
98 "strings"
@@ -29,13 +28,20 @@ var (
2928//
3029// Both stores are used for reads, but only the subjectStore is used for writes. For all operations, the key
3130// is checked to determine which store to use and must be prefixed with either "subject/" or "substitute/" accordingly.
32- // If the key is not prefixed with either "subject/" or "substitute/", a panic is thrown .
31+ // If the key is not prefixed with either "subject/" or "substitute/", a default action is taken (e.g. no-op for Set/Delete) .
3332type migrateClientWrappedStore struct {
3433 subjectStore storetypes.KVStore
3534 substituteStore storetypes.KVStore
3635}
3736
3837func newMigrateClientWrappedStore (subjectStore , substituteStore storetypes.KVStore ) migrateClientWrappedStore {
38+ if subjectStore == nil {
39+ panic (errors .New ("subjectStore must not be nil" ))
40+ }
41+ if substituteStore == nil {
42+ panic (errors .New ("substituteStore must not be nil" ))
43+ }
44+
3945 return migrateClientWrappedStore {
4046 subjectStore : subjectStore ,
4147 substituteStore : substituteStore ,
@@ -44,11 +50,17 @@ func newMigrateClientWrappedStore(subjectStore, substituteStore storetypes.KVSto
4450
4551// Get implements the storetypes.KVStore interface. It allows reads from both the subjectStore and substituteStore.
4652//
47- // Get will panic if the key is not prefixed with either "subject/" or "substitute/".
53+ // Get will return an empty byte slice if the key is not prefixed with either "subject/" or "substitute/".
4854func (ws migrateClientWrappedStore ) Get (key []byte ) []byte {
4955 prefix , key := splitPrefix (key )
5056
51- return ws .getStore (prefix ).Get (key )
57+ store , found := ws .getStore (prefix )
58+ if ! found {
59+ // return a nil byte slice as KVStore.Get() does by default
60+ return []byte (nil )
61+ }
62+
63+ return store .Get (key )
5264}
5365
5466// Has implements the storetypes.KVStore interface. It allows reads from both the subjectStore and substituteStore.
@@ -57,59 +69,75 @@ func (ws migrateClientWrappedStore) Get(key []byte) []byte {
5769func (ws migrateClientWrappedStore ) Has (key []byte ) bool {
5870 prefix , key := splitPrefix (key )
5971
60- return ws .getStore (prefix ).Has (key )
72+ store , found := ws .getStore (prefix )
73+ if ! found {
74+ // return false as value when store is not found
75+ return false
76+ }
77+
78+ return store .Has (key )
6179}
6280
6381// Set implements the storetypes.KVStore interface. It allows writes solely to the subjectStore.
6482//
65- // Set will panic if the key is not prefixed with "subject/".
83+ // Set will no-op if the key is not prefixed with "subject/".
6684func (ws migrateClientWrappedStore ) Set (key , value []byte ) {
6785 prefix , key := splitPrefix (key )
6886 if ! bytes .Equal (prefix , subjectPrefix ) {
69- panic ( fmt . Errorf ( "writes only allowed on subject store; key must be prefixed with \" %s \" " , subjectPrefix ))
87+ return // no-op
7088 }
7189
7290 ws .subjectStore .Set (key , value )
7391}
7492
7593// Delete implements the storetypes.KVStore interface. It allows deletions solely to the subjectStore.
7694//
77- // Delete will panic if the key is not prefixed with "subject/".
95+ // Delete will no-op if the key is not prefixed with "subject/".
7896func (ws migrateClientWrappedStore ) Delete (key []byte ) {
7997 prefix , key := splitPrefix (key )
8098 if ! bytes .Equal (prefix , subjectPrefix ) {
81- panic ( fmt . Errorf ( "writes only allowed on subject store; key must be prefixed with \" %s \" " , subjectPrefix ))
99+ return // no-op
82100 }
83101
84102 ws .subjectStore .Delete (key )
85103}
86104
87105// Iterator implements the storetypes.KVStore interface. It allows iteration over both the subjectStore and substituteStore.
88106//
89- // Iterator will panic if the start or end keys are not prefixed with either "subject/" or "substitute/".
107+ // Iterator will return a closed iterator if the start or end keys are not prefixed with either "subject/" or "substitute/".
90108func (ws migrateClientWrappedStore ) Iterator (start , end []byte ) storetypes.Iterator {
91109 prefixStart , start := splitPrefix (start )
92110 prefixEnd , end := splitPrefix (end )
93111
94112 if ! bytes .Equal (prefixStart , prefixEnd ) {
95- panic ( errors . New ( "start and end keys must be prefixed with the same prefix" ) )
113+ return ws . closedIterator ( )
96114 }
97115
98- return ws .getStore (prefixStart ).Iterator (start , end )
116+ store , found := ws .getStore (prefixStart )
117+ if ! found {
118+ return ws .closedIterator ()
119+ }
120+
121+ return store .Iterator (start , end )
99122}
100123
101124// ReverseIterator implements the storetypes.KVStore interface. It allows iteration over both the subjectStore and substituteStore.
102125//
103- // ReverseIterator will panic if the start or end keys are not prefixed with either "subject/" or "substitute/".
126+ // ReverseIterator will return a closed iterator if the start or end keys are not prefixed with either "subject/" or "substitute/".
104127func (ws migrateClientWrappedStore ) ReverseIterator (start , end []byte ) storetypes.Iterator {
105128 prefixStart , start := splitPrefix (start )
106129 prefixEnd , end := splitPrefix (end )
107130
108131 if ! bytes .Equal (prefixStart , prefixEnd ) {
109- panic (errors .New ("start and end keys must be prefixed with the same prefix" ))
132+ return ws .closedIterator ()
133+ }
134+
135+ store , found := ws .getStore (prefixStart )
136+ if ! found {
137+ return ws .closedIterator ()
110138 }
111139
112- return ws . getStore ( prefixStart ) .ReverseIterator (start , end )
140+ return store .ReverseIterator (start , end )
113141}
114142
115143// GetStoreType implements the storetypes.KVStore interface, it is implemented solely to satisfy the interface.
@@ -127,18 +155,29 @@ func (ws migrateClientWrappedStore) CacheWrapWithTrace(w io.Writer, tc storetype
127155 return cachekv .NewStore (tracekv .NewStore (ws , w , tc ))
128156}
129157
130- // getStore returns the store to be used for the given key. If the key is prefixed with "subject/", the subjectStore
131- // is returned. If the key is prefixed with "substitute/", the substituteStore is returned.
158+ // getStore returns the store to be used for the given key and a boolean flag indicating if that store was found.
159+ // If the key is prefixed with "subject/", the subjectStore is returned. If the key is prefixed with "substitute/",
160+ // the substituteStore is returned.
132161//
133- // If the key is not prefixed with either "subject/" or "substitute/", a panic is thrown .
134- func (ws migrateClientWrappedStore ) getStore (prefix []byte ) storetypes.KVStore {
162+ // If the key is not prefixed with either "subject/" or "substitute/", a nil store is returned and the boolean flag is false .
163+ func (ws migrateClientWrappedStore ) getStore (prefix []byte ) ( storetypes.KVStore , bool ) {
135164 if bytes .Equal (prefix , subjectPrefix ) {
136- return ws .subjectStore
165+ return ws .subjectStore , true
137166 } else if bytes .Equal (prefix , substitutePrefix ) {
138- return ws .substituteStore
167+ return ws .substituteStore , true
139168 }
140169
141- panic (fmt .Errorf ("key must be prefixed with either \" %s\" or \" %s\" " , subjectPrefix , substitutePrefix ))
170+ return nil , false
171+ }
172+
173+ // closedIterator returns an iterator that is always closed, used when Iterator() or ReverseIterator() is called
174+ // with an invalid prefix or start/end key.
175+ func (ws migrateClientWrappedStore ) closedIterator () storetypes.Iterator {
176+ // Create a dummy iterator that is always closed right away.
177+ it := ws .subjectStore .Iterator ([]byte {0 }, []byte {1 })
178+ it .Close ()
179+
180+ return it
142181}
143182
144183// splitPrefix splits the key into the prefix and the key itself, if the key is prefixed with either "subject/" or "substitute/".
0 commit comments