Skip to content

Commit

Permalink
Add micro issues list; fix 1.1.3 error
Browse files Browse the repository at this point in the history
  • Loading branch information
bhmj committed Jul 29, 2024
1 parent 02f5942 commit 8549394
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 36 deletions.
14 changes: 14 additions & 0 deletions issues.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
TODO
- $[?(...)].count()
- distinct
- suggestion:
- $.object.distinct(.*) // any nested value
- $.object.distinct(..*) // any recursive nested value
- $.object.distinct(.field) // nested field
- $.object.distinct(..field) // nested recursive field
- $.object.distinct(field[?(...)]) // syntax error: distinct does not support atomic values (string, bool, number)
- $.object.distinct(field[?(...)].field) // distinct filtered values
- and so on
FIX
- $[?(@.field =~ /word word/)]
- not working because of space!
75 changes: 39 additions & 36 deletions jsonslice.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,8 +102,8 @@ func getEmptyNode() *tNode {

// Get returns a part of input, matching jsonpath.
// In terms of allocations there are two cases of retreiving data from the input:
// 1) simple case: the result is a simple subslice of a source input.
// 2) the result is a merge of several non-contiguous parts of input. More allocations are needed.
// 1. simple case: the result is a simple subslice of a source input.
// 2. the result is a merge of several non-contiguous parts of input. More allocations are needed.
func Get(input []byte, path string) ([]byte, error) {

if len(path) == 0 {
Expand Down Expand Up @@ -286,12 +286,13 @@ func readBrackets(nod *tNode, path []byte, i int) (int, error) {
// readKey reads next key from path[i].
// Key must be any of the following: quoted string, word bounded by keyTerminator, *, 123
// returns:
// key = the key
// ikey = integer converted key
// sep = key list separator (expected , : [ ] . +-*/=! 0)
// i = current i (on separator)
// flags = cWild if wildcard
// err = error
//
// key = the key
// ikey = integer converted key
// sep = key list separator (expected , : [ ] . +-*/=! 0)
// i = current i (on separator)
// flags = cWild if wildcard
// err = error
func readKey(path []byte, i int) ([]byte, int, byte, int, int, error) {
l := len(path)
var bound byte
Expand Down Expand Up @@ -390,7 +391,7 @@ func detectFn(path []byte, i int, nod *tNode) (bool, int, error) {
return true, i + 2, nil
}

// returns value specified by nod or nil if no match
// getValue returns value specified by nod or nil if no match
// 'inside' specifies recursive mode
func getValue(input []byte, nod *tNode, inside bool) (result []byte, err error) {

Expand Down Expand Up @@ -527,7 +528,7 @@ func objectValueByKey(input []byte, nod *tNode, inside bool) ([]byte, error) {
if err != nil {
return nil, err
}
if nod.Type&cDot > 0 && len(res) > 0 {
if nod.Type&cDot > 0 && len(res) > 0 && nod.Type&cDeep == 0 {
return res, nil
}
}
Expand Down Expand Up @@ -581,7 +582,6 @@ func objectDeep(input []byte, nod *tNode) ([]byte, error) {
// seek to value
//
// return key, i
//
func readObjectKey(input []byte, i int) ([]byte, int, error) {
l := len(input)
for input[i] != '"' {
Expand Down Expand Up @@ -610,7 +610,6 @@ func readObjectKey(input []byte, i int) ([]byte, int, error) {
// $..[3] or $..[1,2,-3]
//
// recurse inside
//
func arrayElemByIndex(input []byte, nod *tNode, inside bool) ([]byte, error) {
var res []byte
elems, elem, err := arrayIterateElems(input, nod)
Expand Down Expand Up @@ -639,7 +638,6 @@ func arrayElemByIndex(input []byte, nod *tNode, inside bool) ([]byte, error) {
// $..[1:5] or $..[5:1:-1]
//
// recurse inside
//
func arraySlice(input []byte, nod *tNode) ([]byte, error) {
elems, _, err := arrayIterateElems(input, nod)
if err != nil {
Expand All @@ -653,20 +651,22 @@ func arraySlice(input []byte, nod *tNode) ([]byte, error) {
}

// iterate over array elements
// cases
// 1) $[2] cDot: nod.Left (>0) --> seek to elem
// 2) $[2,3] cDot: nod.Elems (>0) --> scan collecting elems
// 3) $[-3] cDot: nod.Left (<0) --> full scan (cFullScan)
// 4) $[2,-3] cDot: nod.Elems (<0) --> full scan (cFullScan)
// 5) $[1:3] cSlice: Left < Right --> scan up to right --> elems
// 5.1) terminal: return input[left:right]
// 5.2) non-term: iterate and recurse
// 6) ..... cSlice: other --> full scan (cFullScan), apply bounds & recurse
// 7) cWild, cDeep: --> full scan (cFullScan), apply bounds & recurse
//
// cases
// 1) $[2] cDot: nod.Left (>0) --> seek to elem
// 2) $[2,3] cDot: nod.Elems (>0) --> scan collecting elems
// 3) $[-3] cDot: nod.Left (<0) --> full scan (cFullScan)
// 4) $[2,-3] cDot: nod.Elems (<0) --> full scan (cFullScan)
// 5) $[1:3] cSlice: Left < Right --> scan up to right --> elems
// 5.1) terminal: return input[left:right]
// 5.2) non-term: iterate and recurse
// 6) ..... cSlice: other --> full scan (cFullScan), apply bounds & recurse
// 7) cWild, cDeep: --> full scan (cFullScan), apply bounds & recurse
//
// returns
// elem - for a single index or cDeep
// elems - for a list of indexes or cDeep
//
// elem - for a single index or cDeep
// elems - for a list of indexes or cDeep
func arrayIterateElems(input []byte, nod *tNode) (elems []tElem, elem []byte, err error) {
var i, s, e int
l := len(input)
Expand Down Expand Up @@ -711,7 +711,6 @@ BFOR:
}

// aggregate non-empty elems and possibly non-empty ret
//
func collectRecurse(input []byte, nod *tNode, elems []tElem, res []byte, inside bool) ([]byte, error) {
var err error

Expand Down Expand Up @@ -803,7 +802,6 @@ func subSlice(input []byte, nod *tNode, elems []tElem, i int, res []byte, inside
// "key" has been found earlier in input json
// If match then get value, if not match then skip value
// return "res" with a value and "i" pointing after the value
//
func keyCheck(key []byte, input []byte, i int, nod *tNode, elems [][]byte, res []byte, inside bool) ([][]byte, []byte, int, error) {
var err error

Expand Down Expand Up @@ -895,9 +893,13 @@ func processKey(
}
}
deep, err = getValue(input[i:e:e], nod, true) // deepscan
if err != nil {
return elems, res, i, err
}
if len(deep) > 0 {
res = plus(res, deep)
}
e, err = skipSpaces(input, e)
}
}
return elems, res, e, err
Expand All @@ -919,9 +921,10 @@ func matchKeys(key []byte, nodkey []byte) bool {

// get current value from input
// returns
// s = start of value
// e = end of value
// i = next item
//
// s = start of value
// e = end of value
// i = next item
func valuate(input []byte, i int) (int, int, int, error) {
var err error
var s int
Expand Down Expand Up @@ -958,13 +961,13 @@ type tElem struct {
// non-empty end bound always excluded;
//
// empty bound rules:
// positive step:
// empty start = 0
// empty end = last item (included)
// negative step:
// empty start = last item
// empty end = first item (included)
//
// positive step:
// empty start = 0
// empty end = last item (included)
// negative step:
// empty start = last item
// empty end = first item (included)
func adjustBounds(start int, stop int, step int, n int) (int, int, int, error) {
if n == 0 {
return 0, 0, 0, nil
Expand Down
7 changes: 7 additions & 0 deletions jsonslice_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -569,6 +569,8 @@ func Test_Fixes(t *testing.T) {
Query string
Expected []byte
}{
// fixed in 1.1.3: now deep scan does not stop on first occurence of the key and keeps traversing deeper
{[]byte(`{ "k": [{"key": "some value"}, {"key":1}] }`), `$..[1].key`, []byte(`[1]`)},
// using indexing of array element inside expression
// fixed in 1.1.1
{[]byte(`[ [2,3], ["a"], [0,2], [2] ]`), `$[?(@[-1]==2)]`, []byte(`[[0,2],[2]]`)},
Expand Down Expand Up @@ -606,6 +608,11 @@ func Test_Fixes(t *testing.T) {
}
}

func Test_FutureFixes(t *testing.T) {
// ref := `$[?(Q[)?8W?D-lIeM%|e9b33<sERpU.(2)&D`
// _, _, _ = readRef([]byte(ref), 1, 0)
}

func Test_Unicode(t *testing.T) {

tests := []struct {
Expand Down

0 comments on commit 8549394

Please sign in to comment.