Skip to content

Commit 9f162ad

Browse files
Merge pull request #3 from evilmonkeyinc/fix/union-repeat
feat: support repeat keys in unions
2 parents 272f1b3 + ae69ba1 commit 9f162ad

File tree

4 files changed

+59
-28
lines changed

4 files changed

+59
-28
lines changed

test/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -268,7 +268,7 @@ This implementation would be closer to the `Scalar consensus` as it does not alw
268268
|---|---|---|---|---|
269269
|`$[0,1]`|`["first", "second", "third"]`|`[first second]`|`[first second]`|:white_check_mark:|
270270
|`$[0,0]`|`["a"]`|`[a a]`|`[a a]`|:white_check_mark:|
271-
|`$['a','a']`|`{"a":1}`|`[1 1]`|`[1]`|:no_entry:|
271+
|`$['a','a']`|`{"a":1}`|`[1 1]`|`[1 1]`|:white_check_mark:|
272272
|`$[?(@.key<3),?(@.key>6)]`|`[{"key": 1}, {"key": 8}, {"key": 3}, {"key": 10}, {"key": 7}, {"key": 2}, {"key": 6}, {"key": 4}]`|none|`[]`|:question:|
273273
|`$['key','another']`|`{ "key": "value", "another": "entry" }`|`[value entry]`|`[value entry]`|:white_check_mark:|
274274
|`$['missing','key']`|`{ "key": "value", "another": "entry" }`|`[value]`|`nil`|:no_entry:|

test/union_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,9 @@ func Test_Union(t *testing.T) {
2020
expectedError: "",
2121
},
2222
{
23-
query: `$['a','a']`, // TODO : need to support repeat keys?
23+
query: `$['a','a']`,
2424
data: `{"a":1}`,
25-
expected: []interface{}{float64(1)},
25+
expected: []interface{}{float64(1), float64(1)},
2626
consensus: []interface{}{float64(1), float64(1)},
2727
expectedError: "",
2828
},

token/union.go

Lines changed: 22 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -141,54 +141,51 @@ func (token *unionToken) getUnionByKey(obj interface{}, keys []string) ([]interf
141141
return nil, getInvalidTokenTargetNilError(token.Type(), reflect.Map)
142142
}
143143

144-
keyMap := make(map[string]bool)
145-
for _, key := range keys {
146-
keyMap[key] = true
147-
}
148-
149144
switch objType.Kind() {
150145
case reflect.Map:
151146
mapKeys := objVal.MapKeys()
152147
sortMapKeys(mapKeys)
153148

154149
elements := make([]interface{}, 0)
155150

151+
keysMap := make(map[string]reflect.Value)
156152
for _, key := range mapKeys {
157-
if keyMap[key.String()] {
158-
delete(keyMap, key.String())
153+
keysMap[key.String()] = key
154+
}
155+
156+
missingKeys := make([]string, 0)
157+
158+
for _, requestedKey := range keys {
159+
if key, ok := keysMap[requestedKey]; ok {
159160
elements = append(elements, objVal.MapIndex(key).Interface())
161+
} else {
162+
missingKeys = append(missingKeys, requestedKey)
160163
}
161164
}
162165

163-
if len(keyMap) > 0 {
164-
remaining := make([]string, 0)
165-
for key := range keyMap {
166-
remaining = append(remaining, key)
167-
}
168-
sort.Strings(remaining)
169-
return nil, getInvalidTokenKeyNotFoundError(token.Type(), strings.Join(remaining, ","))
166+
if len(missingKeys) > 0 {
167+
sort.Strings(missingKeys)
168+
return nil, getInvalidTokenKeyNotFoundError(token.Type(), strings.Join(missingKeys, ","))
170169
}
171170

172171
return elements, nil
173172
case reflect.Struct:
174173
elements := make([]interface{}, 0)
175174

176-
mapKeys := getStructFields(objVal, false)
175+
keysMap := getStructFields(objVal, false)
176+
missingKeys := make([]string, 0)
177177

178-
for key, field := range mapKeys {
179-
if keyMap[key] {
180-
delete(keyMap, key)
178+
for _, requestedKey := range keys {
179+
if field, ok := keysMap[requestedKey]; ok {
181180
elements = append(elements, objVal.FieldByName(field.Name).Interface())
181+
} else {
182+
missingKeys = append(missingKeys, requestedKey)
182183
}
183184
}
184185

185-
if len(keyMap) > 0 {
186-
remaining := make([]string, 0)
187-
for key := range keyMap {
188-
remaining = append(remaining, key)
189-
}
190-
sort.Strings(remaining)
191-
return nil, getInvalidTokenKeyNotFoundError(token.Type(), strings.Join(remaining, ","))
186+
if len(missingKeys) > 0 {
187+
sort.Strings(missingKeys)
188+
return nil, getInvalidTokenKeyNotFoundError(token.Type(), strings.Join(missingKeys, ","))
192189
}
193190

194191
return elements, nil

token/union_test.go

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -610,6 +610,16 @@ func Test_UnionToken_getUnionByIndex(t *testing.T) {
610610
},
611611
},
612612
},
613+
{
614+
input: input{
615+
token: &unionToken{},
616+
obj: []string{"one", "two", "three"},
617+
keys: []int64{1, 1},
618+
},
619+
expected: expected{
620+
obj: []interface{}{"two", "two"},
621+
},
622+
},
613623
}
614624

615625
for idx, test := range tests {
@@ -764,6 +774,30 @@ func Test_UnionToken_getUnionByKey(t *testing.T) {
764774
err: "union: invalid token key 'gone,missing' not found",
765775
},
766776
},
777+
{
778+
input: input{
779+
token: &unionToken{},
780+
obj: sampleStruct{
781+
One: "value",
782+
},
783+
keys: []string{"one", "one"},
784+
},
785+
expected: expected{
786+
obj: []interface{}{"value", "value"},
787+
},
788+
},
789+
{
790+
input: input{
791+
token: &unionToken{},
792+
obj: map[string]interface{}{
793+
"a": "value",
794+
},
795+
keys: []string{"a", "a", "a"},
796+
},
797+
expected: expected{
798+
obj: []interface{}{"value", "value", "value"},
799+
},
800+
},
767801
}
768802

769803
for idx, test := range tests {

0 commit comments

Comments
 (0)