Skip to content

Commit

Permalink
Fix Query with Json has contain period keys
Browse files Browse the repository at this point in the history
  • Loading branch information
simeji committed Mar 31, 2019
1 parent 9f0f53f commit e2eb926
Show file tree
Hide file tree
Showing 6 changed files with 190 additions and 43 deletions.
50 changes: 48 additions & 2 deletions json_manager_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@ package jid

import (
"bytes"
"github.com/bitly/go-simplejson"
"github.com/stretchr/testify/assert"
"io/ioutil"
"testing"

simplejson "github.com/bitly/go-simplejson"
"github.com/stretchr/testify/assert"
)

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

// case 7 key contains '.'
rr = bytes.NewBufferString(`{"na.me":"go","age":20}`)
buf, _ = ioutil.ReadAll(rr)
sj, _ = simplejson.NewJson(buf)

d, _ = getItem(sj, "na.me")
result, _ = d.Encode()
assert.Equal(`"go"`, string(result))

}

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

func TestGetFilteredDataWithContainDots(t *testing.T) {
var assert = assert.New(t)

// data
data := `{"abc.de":"2AA2","abcde_fgh":{"aaa":[123,"cccc",[1,2]],"c":"JJJJ"},"cc":{"a":[3,4]}}`
r := bytes.NewBufferString(data)
jm, _ := NewJsonManager(r)

// case 1
q := NewQueryWithString(`.\"abc.de\"`)
result, s, c, err := jm.GetFilteredData(q, false)
assert.Nil(err)
d, _ := result.Encode()
assert.Equal(`"2AA2"`, string(d))
assert.Equal([]string{``, ``}, s)
assert.Equal([]string{}, c)

// case 2
q = NewQueryWithString(`."abc.de"`)
result, s, c, err = jm.GetFilteredData(q, false)
assert.Nil(err)
d, _ = result.Encode()
assert.Equal(`null`, string(d))
assert.Equal([]string{``, ``}, s)
assert.Equal([]string{}, c)

// case 3
q = NewQueryWithString(`.abc.de`)
result, s, c, err = jm.GetFilteredData(q, false)
assert.Nil(err)
d, _ = result.Encode()
assert.Equal(`null`, string(d))
assert.Equal([]string{"", ""}, s)
assert.Equal([]string{}, c)
}

func TestGetCandidateKeys(t *testing.T) {
var assert = assert.New(t)
data := `{"name":[1,2,3], "naming":{"account":"simeji"}, "test":"simeji", "testing":"ok"}`
Expand Down
60 changes: 39 additions & 21 deletions query.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import (
"regexp"
"strings"

"github.com/mattn/go-runewidth"
runewidth "github.com/mattn/go-runewidth"
)

type QueryInterface interface {
Expand Down Expand Up @@ -128,13 +128,37 @@ func (q *Query) Clear() []rune {
}

func (q *Query) GetKeywords() [][]rune {
query := string(*q.query)
qq := *q.query

if query == "" {
if qq == nil || string(qq) == "" {
return [][]rune{}
}

splitQuery := strings.Split(query, ".")
splitQuery := []string{}
rr := []rune{}
enclosed := true
ql := len(*q.query)
for i := 0; i < ql; i++ {
r := qq[i]
if ii := i + 1; r == '\\' && ql > ii && qq[ii] == '"' {
enclosed = !enclosed
i++ // skip '"(double quortation)'
continue
}
if enclosed && r == '.' {
splitQuery = append(splitQuery, string(rr))
rr = []rune{}
} else {
rr = append(rr, r)
}
}
if rr != nil {
v := []string{string(rr)}
if !enclosed {
v = strings.Split(string(rr), ".")
}
splitQuery = append(splitQuery, v...)
}
lastIdx := len(splitQuery) - 1

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

func (q *Query) PopKeyword() ([]rune, []rune) {
var keyword []rune
var lastSepIdx int
var lastBracketIdx int
qq := q.Get()
for i, e := range qq {
if e == '.' {
lastSepIdx = i
} else if e == '[' {
lastBracketIdx = i
keyword := q.GetLastKeyword()
nq := string(keyword)
qq := q.StringGet()

for _, r := range keyword {
if r == '.' {
nq = `\"` + string(keyword) + `\"`
break
}
}
re := regexp.MustCompile(`(\.)?(\\")?` + regexp.QuoteMeta(nq) + "$")

if lastBracketIdx > lastSepIdx {
lastSepIdx = lastBracketIdx
}
qq = re.ReplaceAllString(qq, "")

keywords := q.GetKeywords()
if l := len(keywords); l > 0 {
keyword = keywords[l-1]
}
query := q.Set(qq[0:lastSepIdx])
query := q.Set([]rune(qq))
return keyword, query
}

Expand Down
84 changes: 72 additions & 12 deletions query_test.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
package jid

import (
"github.com/stretchr/testify/assert"
"testing"

"github.com/stretchr/testify/assert"
)

func TestValidate(t *testing.T) {
Expand Down Expand Up @@ -226,22 +227,22 @@ func TestGetKeywords(t *testing.T) {

v := []rune(".test.name")
q := NewQuery(v)
assert.Equal(q.GetKeywords(), [][]rune{
assert.Equal([][]rune{
[]rune("test"),
[]rune("name"),
})
}, q.GetKeywords())

v = []rune("")
q = NewQuery(v)
assert.Equal(q.GetKeywords(), [][]rune{})
assert.Equal([][]rune{}, q.GetKeywords())

v = []rune(".test.name.")
q = NewQuery(v)
assert.Equal(q.GetKeywords(), [][]rune{
assert.Equal([][]rune{
[]rune("test"),
[]rune("name"),
[]rune(""),
})
}, q.GetKeywords())

v = []rune(".hello")
q = NewQuery(v)
Expand Down Expand Up @@ -295,6 +296,25 @@ func TestGetKeywords(t *testing.T) {
[]rune("[0]"),
})

}
func TestGetKeywordsWithDots(t *testing.T) {
var assert = assert.New(t)

v := []rune(`.test.\"na.me\"`)
q := NewQuery(v)
assert.Equal([][]rune{
[]rune("test"),
[]rune("na.me"),
}, q.GetKeywords())

v = []rune(`.test.\"na.me\`)
q = NewQuery(v)
assert.Equal([][]rune{
[]rune("test"),
[]rune("na"),
[]rune(`me\`),
}, q.GetKeywords())

}

func TestGetLastKeyword(t *testing.T) {
Expand Down Expand Up @@ -343,16 +363,56 @@ func TestPopKeyword(t *testing.T) {
v := []rune(".test.name")
q := NewQuery(v)
k, query := q.PopKeyword()
assert.Equal(k, []rune("name"))
assert.Equal(query, []rune(".test"))
assert.Equal(q.Get(), []rune(".test"))
assert.Equal([]rune("name"), k)
assert.Equal([]rune(".test"), query)
assert.Equal([]rune(".test"), q.Get())

v = []rune(".a[0")
q = NewQuery(v)
k, query = q.PopKeyword()
assert.Equal([]rune("[0"), k)
assert.Equal([]rune(".a"), query)
assert.Equal([]rune(".a"), q.Get())

k, query = q.PopKeyword()
assert.Equal([]rune("a"), k)
assert.Equal([]rune(""), query)
assert.Equal([]rune(""), q.Get())

v = []rune(".")
q = NewQuery(v)
k, query = q.PopKeyword()
assert.Equal([]rune(""), k)
assert.Equal([]rune(""), query)
assert.Equal([]rune(""), q.Get())

v = []rune(".test.name.")
q = NewQuery(v)
k, query = q.PopKeyword()
assert.Equal(k, []rune(""))
assert.Equal(query, []rune(".test.name"))
assert.Equal(q.Get(), []rune(".test.name"))
assert.Equal([]rune(""), k)
assert.Equal([]rune(".test.name"), query)
assert.Equal([]rune(".test.name"), q.Get())

v = []rune(`.name.\"te.st\"`)
q = NewQuery(v)
k, query = q.PopKeyword()
assert.Equal([]rune("te.st"), k)
assert.Equal([]rune(".name"), query)
assert.Equal([]rune(".name"), q.Get())

v = []rune(`.name.\"te.st\".hoge`)
q = NewQuery(v)
k, query = q.PopKeyword()
assert.Equal([]rune("hoge"), k)
assert.Equal([]rune(`.name.\"te.st\"`), query)
assert.Equal([]rune(`.name.\"te.st\"`), q.Get())

v = []rune(`.name.\"te`)
q = NewQuery(v)
k, query = q.PopKeyword()
assert.Equal([]rune(`te`), k)
assert.Equal([]rune(`.name`), query)
assert.Equal([]rune(`.name`), q.Get())
}

func TestQueryStringGet(t *testing.T) {
Expand Down
24 changes: 19 additions & 5 deletions suggestion.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
package jid

import (
"github.com/bitly/go-simplejson"
"regexp"
"sort"
"strings"

simplejson "github.com/bitly/go-simplejson"
)

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

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

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

keys := []string{}
kk := []string{}
m, err := json.Map()

if err != nil {
return keys
return kk
}
for k := range m {
kk = append(kk, k)
}
sort.Strings(kk)

keys := []string{}
for _, k := range kk {
if strings.Contains(k, ".") {
var sb strings.Builder
sb.Grow(len(k) + 4)
sb.WriteString(`\"`)
sb.WriteString(k)
sb.WriteString(`\"`)
k = sb.String()
}
keys = append(keys, k)
}
sort.Strings(keys)
return keys
}

Expand Down
13 changes: 11 additions & 2 deletions suggestion_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@ package jid

import (
"bytes"
"github.com/bitly/go-simplejson"
"github.com/stretchr/testify/assert"
"io/ioutil"
"testing"

simplejson "github.com/bitly/go-simplejson"
"github.com/stretchr/testify/assert"
)

func TestNewSuggestion(t *testing.T) {
Expand Down Expand Up @@ -83,6 +84,14 @@ func TestSuggestionGetCandidateKeys(t *testing.T) {
s = NewSuggestion()
assert.Equal([]string{}, s.GetCandidateKeys(j, "["))
}
func TestSuggestionGetCandidateKeysWithDots(t *testing.T) {
var assert = assert.New(t)
j := createJson(`{"nam.ing":"simeji", "nickname":"simejisimeji", "city":"tokyo", "name":"simeji-github" }`)
s := NewSuggestion()

assert.Equal([]string{"city", `\"nam.ing\"`, "name", "nickname"}, s.GetCandidateKeys(j, ""))
assert.Equal([]string{`\"nam.ing\"`, "name", "nickname"}, s.GetCandidateKeys(j, "n"))
}

func createJson(s string) *simplejson.Json {
r := bytes.NewBufferString(s)
Expand Down
2 changes: 1 addition & 1 deletion terminal.go
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,7 @@ func (t *Terminal) drawCandidates(x int, y int, index int, candidates []string)
w, _ := termbox.Size()

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

var rows []string
var str string
Expand Down

0 comments on commit e2eb926

Please sign in to comment.