Skip to content

Commit

Permalink
Support queries
Browse files Browse the repository at this point in the history
  • Loading branch information
sspaink committed Jun 30, 2021
1 parent 1d8cc0a commit 3a2e299
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 48 deletions.
11 changes: 6 additions & 5 deletions README.md
Expand Up @@ -123,11 +123,12 @@ nil, for JSON null
To directly access the value:

```go
result.Type // can be String, Number, True, False, Null, or JSON
result.Str // holds the string
result.Num // holds the float64 number
result.Raw // holds the raw json
result.Index // index of raw value in original json, zero means index unknown
result.Type // can be String, Number, True, False, Null, or JSON
result.Str // holds the string
result.Num // holds the float64 number
result.Raw // holds the raw json
result.Index // index of raw value in original json, zero means index unknown
result.HashtagIndexes // hashtagIndexes contains the indexes of the elements returned by a query containing the '#' character
```

There are a variety of handy functions that work on a result:
Expand Down
29 changes: 18 additions & 11 deletions gjson.go
Expand Up @@ -64,8 +64,8 @@ type Result struct {
Num float64
// Index of raw value in original json, zero means index unknown
Index int
// ArrayIndex is the Index of each returned element in the original json
ArrayIndex []int
// HashtagIndexes contains the Indexes of the elements returned by a query containing the '#' character
HashtagIndexes []int
}

// String returns a string representation of the value.
Expand Down Expand Up @@ -1263,6 +1263,7 @@ func parseArray(c *parseContext, i int, path string) (int, bool) {
var alog []int
var partidx int
var multires []byte
var hashtagQueryIndex []int
rp := parseArrayPath(path)
if !rp.arrch {
n, ok := parseUint(rp.part)
Expand All @@ -1283,6 +1284,10 @@ func parseArray(c *parseContext, i int, path string) (int, bool) {
multires = append(multires, '[')
}
}
var tmp parseContext
tmp.value = qval
fillIndex(c.json, &tmp)
parentIndex := tmp.value.Index
var res Result
if qval.Type == JSON {
res = qval.Get(rp.query.path)
Expand Down Expand Up @@ -1314,6 +1319,7 @@ func parseArray(c *parseContext, i int, path string) (int, bool) {
multires = append(multires, ',')
}
multires = append(multires, raw...)
hashtagQueryIndex = append(hashtagQueryIndex, res.Index+parentIndex)
}
} else {
c.value = res
Expand Down Expand Up @@ -1478,7 +1484,7 @@ func parseArray(c *parseContext, i int, path string) (int, bool) {
c.pipe = right
c.piped = true
}
var arrayIndex = make([]int, 0, 64)
var hashtagIndexes = make([]int, 0, 64)
var jsons = make([]byte, 0, 64)
jsons = append(jsons, '[')
for j, k := 0, 0; j < len(alog); j++ {
Expand All @@ -1505,7 +1511,7 @@ func parseArray(c *parseContext, i int, path string) (int, bool) {
raw = res.String()
}
jsons = append(jsons, []byte(raw)...)
arrayIndex = append(arrayIndex, res.Index+parentIndex)
hashtagIndexes = append(hashtagIndexes, res.Index+parentIndex)
k++
}
}
Expand All @@ -1514,7 +1520,7 @@ func parseArray(c *parseContext, i int, path string) (int, bool) {
jsons = append(jsons, ']')
c.value.Type = JSON
c.value.Raw = string(jsons)
c.value.ArrayIndex = arrayIndex
c.value.HashtagIndexes = hashtagIndexes
return i + 1, true
}
if rp.alogok {
Expand All @@ -1530,8 +1536,9 @@ func parseArray(c *parseContext, i int, path string) (int, bool) {
if !c.value.Exists() {
if len(multires) > 0 {
c.value = Result{
Raw: string(append(multires, ']')),
Type: JSON,
Raw: string(append(multires, ']')),
Type: JSON,
HashtagIndexes: hashtagQueryIndex,
}
} else if rp.query.all {
c.value = Result{
Expand Down Expand Up @@ -2052,10 +2059,10 @@ func parseAny(json string, i int, hit bool) (int, Result, bool) {
res.Raw = val
res.Type = JSON
}
var c parseContext
c.value = res
fillIndex(json, &c)
return i, c.value, true
var tmp parseContext
tmp.value = res
fillIndex(json, &tmp)
return i, tmp.value, true
}
if json[i] <= ' ' {
continue
Expand Down
89 changes: 57 additions & 32 deletions gjson_test.go
Expand Up @@ -858,9 +858,9 @@ func TestIssue20(t *testing.T) {
}

func TestIssue21(t *testing.T) {
json := `{ "Level1Field1":3,
"Level1Field4":4,
"Level1Field2":{ "Level2Field1":[ "value1", "value2" ],
json := `{ "Level1Field1":3,
"Level1Field4":4,
"Level1Field2":{ "Level2Field1":[ "value1", "value2" ],
"Level2Field2":{ "Level3Field1":[ { "key1":"value1" } ] } } }`
paths := []string{"Level1Field1", "Level1Field2.Level2Field1",
"Level1Field2.Level2Field2.Level3Field1", "Level1Field4"}
Expand Down Expand Up @@ -1491,7 +1491,7 @@ func TestDeepSelectors(t *testing.T) {
}
},
{
"first": "Roger", "last": "Craig",
"first": "Roger", "last": "Craig",
"extra": [40,50,60],
"details": {
"city": "Phoenix",
Expand Down Expand Up @@ -2087,48 +2087,73 @@ func TestBoolConvertQuery(t *testing.T) {
assert(t, falses == "[3,4,5,9,10,11]")
}

func TestArrayIndex(t *testing.T) {
json := `{
func TestHashtagIndexes(t *testing.T) {
var exampleJSON = `{
"vals": [
[
2,
2,
{
"wut",
"yup"
}
],
[
4,
5,
6
]
[1,66,{test: 3}],
[4,5,[6]]
],
"objectArray":[
{"first": "Dale", "age": 44},
{"first": "Roger", "age": 68},
]
}`
r := Get(json, `vals.#.2`)
fmt.Println(r.ArrayIndex)
fmt.Println(string(json[37]))

all := Get(json, `@this`)
testCases := []struct {
path string
expected []string
}{
{
`vals.#.1`,
[]string{`6`, "5"},
},
{
`vals.#.2`,
[]string{"{", "["},
},
{
`objectArray.#(age>43)#.first`,
[]string{`"`, `"`},
},
}

for _, tc := range testCases {
r := Get(exampleJSON, tc.path)

assert(t, len(r.HashtagIndexes) == len(tc.expected))

for i, a := range r.HashtagIndexes {
assert(t, string(exampleJSON[a]) == tc.expected[i])
}
}
}

func TestHashtagIndexesMatchesRaw(t *testing.T) {
var exampleJSON = `{
"objectArray":[
{"first": "Dale", "age": 44},
{"first": "Roger", "age": 68},
]
}`
r := Get(exampleJSON, `objectArray.#(age>43)#.first`)
all := Get(exampleJSON, `@this`)
all.ForEach(func(_, value Result) bool {
println(value.Raw, "index", value.Index)
println(string(json[value.Index : value.Index+len(value.Raw)]))
if value.IsArray() {
value.ForEach(func(_, v Result) bool {
println(v.Raw, "index", v.Index)
parentIndex := value.Index + v.Index
println(string(json[parentIndex : parentIndex+len(v.Raw)]))

if v.IsArray() {
v.ForEach(func(_, sv Result) bool {
println(sv.Raw, "index", sv.Index+parentIndex)
println(string(json[sv.Index+parentIndex : sv.Index+parentIndex+len(sv.Raw)]))
if sv.IsObject() {
assert(t, string(exampleJSON[r.HashtagIndexes[0]:r.HashtagIndexes[0]+len(sv.Raw)]) == sv.Raw)
}
if sv.IsArray() {
assert(t, string(exampleJSON[r.HashtagIndexes[1]:r.HashtagIndexes[1]+len(sv.Raw)]) == sv.Raw)
}
return true
})
}
return true
})
}
return true // keep iterating
return true
})
}

0 comments on commit 3a2e299

Please sign in to comment.