Skip to content

Commit e2eb926

Browse files
committed
Fix Query with Json has contain period keys
1 parent 9f0f53f commit e2eb926

6 files changed

+190
-43
lines changed

json_manager_test.go

+48-2
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,11 @@ package jid
22

33
import (
44
"bytes"
5-
"github.com/bitly/go-simplejson"
6-
"github.com/stretchr/testify/assert"
75
"io/ioutil"
86
"testing"
7+
8+
simplejson "github.com/bitly/go-simplejson"
9+
"github.com/stretchr/testify/assert"
910
)
1011

1112
func TestNewJson(t *testing.T) {
@@ -185,6 +186,15 @@ func TestGetItem(t *testing.T) {
185186
result, _ = d.Encode()
186187
assert.Equal(`{"age":20,"name":"go"}`, string(result))
187188

189+
// case 7 key contains '.'
190+
rr = bytes.NewBufferString(`{"na.me":"go","age":20}`)
191+
buf, _ = ioutil.ReadAll(rr)
192+
sj, _ = simplejson.NewJson(buf)
193+
194+
d, _ = getItem(sj, "na.me")
195+
result, _ = d.Encode()
196+
assert.Equal(`"go"`, string(result))
197+
188198
}
189199

190200
func TestGetFilteredData(t *testing.T) {
@@ -363,6 +373,42 @@ func TestGetFilteredDataWithMatchQuery(t *testing.T) {
363373
assert.Equal([]string{"test", "testing"}, c)
364374
}
365375

376+
func TestGetFilteredDataWithContainDots(t *testing.T) {
377+
var assert = assert.New(t)
378+
379+
// data
380+
data := `{"abc.de":"2AA2","abcde_fgh":{"aaa":[123,"cccc",[1,2]],"c":"JJJJ"},"cc":{"a":[3,4]}}`
381+
r := bytes.NewBufferString(data)
382+
jm, _ := NewJsonManager(r)
383+
384+
// case 1
385+
q := NewQueryWithString(`.\"abc.de\"`)
386+
result, s, c, err := jm.GetFilteredData(q, false)
387+
assert.Nil(err)
388+
d, _ := result.Encode()
389+
assert.Equal(`"2AA2"`, string(d))
390+
assert.Equal([]string{``, ``}, s)
391+
assert.Equal([]string{}, c)
392+
393+
// case 2
394+
q = NewQueryWithString(`."abc.de"`)
395+
result, s, c, err = jm.GetFilteredData(q, false)
396+
assert.Nil(err)
397+
d, _ = result.Encode()
398+
assert.Equal(`null`, string(d))
399+
assert.Equal([]string{``, ``}, s)
400+
assert.Equal([]string{}, c)
401+
402+
// case 3
403+
q = NewQueryWithString(`.abc.de`)
404+
result, s, c, err = jm.GetFilteredData(q, false)
405+
assert.Nil(err)
406+
d, _ = result.Encode()
407+
assert.Equal(`null`, string(d))
408+
assert.Equal([]string{"", ""}, s)
409+
assert.Equal([]string{}, c)
410+
}
411+
366412
func TestGetCandidateKeys(t *testing.T) {
367413
var assert = assert.New(t)
368414
data := `{"name":[1,2,3], "naming":{"account":"simeji"}, "test":"simeji", "testing":"ok"}`

query.go

+39-21
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import (
44
"regexp"
55
"strings"
66

7-
"github.com/mattn/go-runewidth"
7+
runewidth "github.com/mattn/go-runewidth"
88
)
99

1010
type QueryInterface interface {
@@ -128,13 +128,37 @@ func (q *Query) Clear() []rune {
128128
}
129129

130130
func (q *Query) GetKeywords() [][]rune {
131-
query := string(*q.query)
131+
qq := *q.query
132132

133-
if query == "" {
133+
if qq == nil || string(qq) == "" {
134134
return [][]rune{}
135135
}
136136

137-
splitQuery := strings.Split(query, ".")
137+
splitQuery := []string{}
138+
rr := []rune{}
139+
enclosed := true
140+
ql := len(*q.query)
141+
for i := 0; i < ql; i++ {
142+
r := qq[i]
143+
if ii := i + 1; r == '\\' && ql > ii && qq[ii] == '"' {
144+
enclosed = !enclosed
145+
i++ // skip '"(double quortation)'
146+
continue
147+
}
148+
if enclosed && r == '.' {
149+
splitQuery = append(splitQuery, string(rr))
150+
rr = []rune{}
151+
} else {
152+
rr = append(rr, r)
153+
}
154+
}
155+
if rr != nil {
156+
v := []string{string(rr)}
157+
if !enclosed {
158+
v = strings.Split(string(rr), ".")
159+
}
160+
splitQuery = append(splitQuery, v...)
161+
}
138162
lastIdx := len(splitQuery) - 1
139163

140164
keywords := [][]rune{}
@@ -171,27 +195,21 @@ func (q *Query) StringGetLastKeyword() string {
171195
}
172196

173197
func (q *Query) PopKeyword() ([]rune, []rune) {
174-
var keyword []rune
175-
var lastSepIdx int
176-
var lastBracketIdx int
177-
qq := q.Get()
178-
for i, e := range qq {
179-
if e == '.' {
180-
lastSepIdx = i
181-
} else if e == '[' {
182-
lastBracketIdx = i
198+
keyword := q.GetLastKeyword()
199+
nq := string(keyword)
200+
qq := q.StringGet()
201+
202+
for _, r := range keyword {
203+
if r == '.' {
204+
nq = `\"` + string(keyword) + `\"`
205+
break
183206
}
184207
}
208+
re := regexp.MustCompile(`(\.)?(\\")?` + regexp.QuoteMeta(nq) + "$")
185209

186-
if lastBracketIdx > lastSepIdx {
187-
lastSepIdx = lastBracketIdx
188-
}
210+
qq = re.ReplaceAllString(qq, "")
189211

190-
keywords := q.GetKeywords()
191-
if l := len(keywords); l > 0 {
192-
keyword = keywords[l-1]
193-
}
194-
query := q.Set(qq[0:lastSepIdx])
212+
query := q.Set([]rune(qq))
195213
return keyword, query
196214
}
197215

query_test.go

+72-12
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
package jid
22

33
import (
4-
"github.com/stretchr/testify/assert"
54
"testing"
5+
6+
"github.com/stretchr/testify/assert"
67
)
78

89
func TestValidate(t *testing.T) {
@@ -226,22 +227,22 @@ func TestGetKeywords(t *testing.T) {
226227

227228
v := []rune(".test.name")
228229
q := NewQuery(v)
229-
assert.Equal(q.GetKeywords(), [][]rune{
230+
assert.Equal([][]rune{
230231
[]rune("test"),
231232
[]rune("name"),
232-
})
233+
}, q.GetKeywords())
233234

234235
v = []rune("")
235236
q = NewQuery(v)
236-
assert.Equal(q.GetKeywords(), [][]rune{})
237+
assert.Equal([][]rune{}, q.GetKeywords())
237238

238239
v = []rune(".test.name.")
239240
q = NewQuery(v)
240-
assert.Equal(q.GetKeywords(), [][]rune{
241+
assert.Equal([][]rune{
241242
[]rune("test"),
242243
[]rune("name"),
243244
[]rune(""),
244-
})
245+
}, q.GetKeywords())
245246

246247
v = []rune(".hello")
247248
q = NewQuery(v)
@@ -295,6 +296,25 @@ func TestGetKeywords(t *testing.T) {
295296
[]rune("[0]"),
296297
})
297298

299+
}
300+
func TestGetKeywordsWithDots(t *testing.T) {
301+
var assert = assert.New(t)
302+
303+
v := []rune(`.test.\"na.me\"`)
304+
q := NewQuery(v)
305+
assert.Equal([][]rune{
306+
[]rune("test"),
307+
[]rune("na.me"),
308+
}, q.GetKeywords())
309+
310+
v = []rune(`.test.\"na.me\`)
311+
q = NewQuery(v)
312+
assert.Equal([][]rune{
313+
[]rune("test"),
314+
[]rune("na"),
315+
[]rune(`me\`),
316+
}, q.GetKeywords())
317+
298318
}
299319

300320
func TestGetLastKeyword(t *testing.T) {
@@ -343,16 +363,56 @@ func TestPopKeyword(t *testing.T) {
343363
v := []rune(".test.name")
344364
q := NewQuery(v)
345365
k, query := q.PopKeyword()
346-
assert.Equal(k, []rune("name"))
347-
assert.Equal(query, []rune(".test"))
348-
assert.Equal(q.Get(), []rune(".test"))
366+
assert.Equal([]rune("name"), k)
367+
assert.Equal([]rune(".test"), query)
368+
assert.Equal([]rune(".test"), q.Get())
369+
370+
v = []rune(".a[0")
371+
q = NewQuery(v)
372+
k, query = q.PopKeyword()
373+
assert.Equal([]rune("[0"), k)
374+
assert.Equal([]rune(".a"), query)
375+
assert.Equal([]rune(".a"), q.Get())
376+
377+
k, query = q.PopKeyword()
378+
assert.Equal([]rune("a"), k)
379+
assert.Equal([]rune(""), query)
380+
assert.Equal([]rune(""), q.Get())
381+
382+
v = []rune(".")
383+
q = NewQuery(v)
384+
k, query = q.PopKeyword()
385+
assert.Equal([]rune(""), k)
386+
assert.Equal([]rune(""), query)
387+
assert.Equal([]rune(""), q.Get())
349388

350389
v = []rune(".test.name.")
351390
q = NewQuery(v)
352391
k, query = q.PopKeyword()
353-
assert.Equal(k, []rune(""))
354-
assert.Equal(query, []rune(".test.name"))
355-
assert.Equal(q.Get(), []rune(".test.name"))
392+
assert.Equal([]rune(""), k)
393+
assert.Equal([]rune(".test.name"), query)
394+
assert.Equal([]rune(".test.name"), q.Get())
395+
396+
v = []rune(`.name.\"te.st\"`)
397+
q = NewQuery(v)
398+
k, query = q.PopKeyword()
399+
assert.Equal([]rune("te.st"), k)
400+
assert.Equal([]rune(".name"), query)
401+
assert.Equal([]rune(".name"), q.Get())
402+
403+
v = []rune(`.name.\"te.st\".hoge`)
404+
q = NewQuery(v)
405+
k, query = q.PopKeyword()
406+
assert.Equal([]rune("hoge"), k)
407+
assert.Equal([]rune(`.name.\"te.st\"`), query)
408+
assert.Equal([]rune(`.name.\"te.st\"`), q.Get())
409+
410+
v = []rune(`.name.\"te`)
411+
q = NewQuery(v)
412+
k, query = q.PopKeyword()
413+
assert.Equal([]rune(`te`), k)
414+
assert.Equal([]rune(`.name`), query)
415+
assert.Equal([]rune(`.name`), q.Get())
356416
}
357417

358418
func TestQueryStringGet(t *testing.T) {

suggestion.go

+19-5
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
package jid
22

33
import (
4-
"github.com/bitly/go-simplejson"
54
"regexp"
65
"sort"
76
"strings"
7+
8+
simplejson "github.com/bitly/go-simplejson"
89
)
910

1011
type SuggestionInterface interface {
@@ -97,7 +98,7 @@ func (s *Suggestion) GetCandidateKeys(json *simplejson.Json, keyword string) []s
9798
return getCurrentKeys(json)
9899
}
99100

100-
reg, err := regexp.Compile("(?i)^" + keyword)
101+
reg, err := regexp.Compile(`(?i)^(\\")?` + keyword + `(\\")?`)
101102
if err != nil {
102103
return []string{}
103104
}
@@ -111,16 +112,29 @@ func (s *Suggestion) GetCandidateKeys(json *simplejson.Json, keyword string) []s
111112

112113
func getCurrentKeys(json *simplejson.Json) []string {
113114

114-
keys := []string{}
115+
kk := []string{}
115116
m, err := json.Map()
116117

117118
if err != nil {
118-
return keys
119+
return kk
119120
}
120121
for k := range m {
122+
kk = append(kk, k)
123+
}
124+
sort.Strings(kk)
125+
126+
keys := []string{}
127+
for _, k := range kk {
128+
if strings.Contains(k, ".") {
129+
var sb strings.Builder
130+
sb.Grow(len(k) + 4)
131+
sb.WriteString(`\"`)
132+
sb.WriteString(k)
133+
sb.WriteString(`\"`)
134+
k = sb.String()
135+
}
121136
keys = append(keys, k)
122137
}
123-
sort.Strings(keys)
124138
return keys
125139
}
126140

suggestion_test.go

+11-2
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,11 @@ package jid
22

33
import (
44
"bytes"
5-
"github.com/bitly/go-simplejson"
6-
"github.com/stretchr/testify/assert"
75
"io/ioutil"
86
"testing"
7+
8+
simplejson "github.com/bitly/go-simplejson"
9+
"github.com/stretchr/testify/assert"
910
)
1011

1112
func TestNewSuggestion(t *testing.T) {
@@ -83,6 +84,14 @@ func TestSuggestionGetCandidateKeys(t *testing.T) {
8384
s = NewSuggestion()
8485
assert.Equal([]string{}, s.GetCandidateKeys(j, "["))
8586
}
87+
func TestSuggestionGetCandidateKeysWithDots(t *testing.T) {
88+
var assert = assert.New(t)
89+
j := createJson(`{"nam.ing":"simeji", "nickname":"simejisimeji", "city":"tokyo", "name":"simeji-github" }`)
90+
s := NewSuggestion()
91+
92+
assert.Equal([]string{"city", `\"nam.ing\"`, "name", "nickname"}, s.GetCandidateKeys(j, ""))
93+
assert.Equal([]string{`\"nam.ing\"`, "name", "nickname"}, s.GetCandidateKeys(j, "n"))
94+
}
8695

8796
func createJson(s string) *simplejson.Json {
8897
r := bytes.NewBufferString(s)

terminal.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -238,7 +238,7 @@ func (t *Terminal) drawCandidates(x int, y int, index int, candidates []string)
238238
w, _ := termbox.Size()
239239

240240
ss := candidates[index]
241-
re := regexp.MustCompile("[[:space:]]" + ss + "[[:space:]]")
241+
re := regexp.MustCompile("[[:space:]]" + regexp.QuoteMeta(ss) + "[[:space:]]")
242242

243243
var rows []string
244244
var str string

0 commit comments

Comments
 (0)