From 5fc81c787b46fc9cbf9ef37cfae41d461f960e62 Mon Sep 17 00:00:00 2001 From: Evgeniy Stratonikov Date: Fri, 7 May 2021 19:48:57 +0300 Subject: [PATCH] jsonpath: use ordered map json unmarshaler --- go.mod | 1 + go.sum | 2 ++ pkg/services/oracle/filter.go | 10 +++++-- pkg/services/oracle/jsonpath/jsonpath.go | 26 ++++++++----------- pkg/services/oracle/jsonpath/jsonpath_test.go | 17 +++++++----- 5 files changed, 32 insertions(+), 24 deletions(-) diff --git a/go.mod b/go.mod index f824717eb..daa944e09 100644 --- a/go.mod +++ b/go.mod @@ -19,6 +19,7 @@ require ( github.com/stretchr/testify v1.6.1 github.com/syndtr/goleveldb v0.0.0-20180307113352-169b1b37be73 github.com/urfave/cli v1.20.0 + github.com/virtuald/go-ordered-json v0.0.0-20170621173500-b18e6e673d74 go.etcd.io/bbolt v1.3.4 go.uber.org/atomic v1.4.0 go.uber.org/zap v1.10.0 diff --git a/go.sum b/go.sum index 85cbb14d8..48cc9472a 100644 --- a/go.sum +++ b/go.sum @@ -230,6 +230,8 @@ github.com/syndtr/goleveldb v0.0.0-20180307113352-169b1b37be73/go.mod h1:Z4AUp2K github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= github.com/urfave/cli v1.20.0 h1:fDqGv3UG/4jbVl/QkFwEdddtEDjh/5Ov6X+0B/3bPaw= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= +github.com/virtuald/go-ordered-json v0.0.0-20170621173500-b18e6e673d74 h1:JwtAtbp7r/7QSyGz8mKUbYJBg2+6Cd7OjM8o/GNOcVo= +github.com/virtuald/go-ordered-json v0.0.0-20170621173500-b18e6e673d74/go.mod h1:RmMWU37GKR2s6pgrIEB4ixgpVCt/cf7dnJv3fuH1J1c= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/yuin/gopher-lua v0.0.0-20190514113301-1cd887cd7036/go.mod h1:gqRgreBUhTSL0GeU64rtZ3Uq3wtjOa/TB2YfrtkCbVQ= github.com/yuin/gopher-lua v0.0.0-20191128022950-c6266f4fe8d7 h1:Y17pEjKgx2X0A69WQPGa8hx/Myzu+4NdUxlkZpbAYio= diff --git a/pkg/services/oracle/filter.go b/pkg/services/oracle/filter.go index 1aa5508a3..65eeed59e 100644 --- a/pkg/services/oracle/filter.go +++ b/pkg/services/oracle/filter.go @@ -1,21 +1,27 @@ package oracle import ( - "encoding/json" + "bytes" "errors" "unicode/utf8" "github.com/nspcc-dev/neo-go/pkg/core/state" "github.com/nspcc-dev/neo-go/pkg/core/transaction" "github.com/nspcc-dev/neo-go/pkg/services/oracle/jsonpath" + json "github.com/virtuald/go-ordered-json" ) func filter(value []byte, path string) ([]byte, error) { if !utf8.Valid(value) { return nil, errors.New("not an UTF-8") } + + buf := bytes.NewBuffer(value) + d := json.NewDecoder(buf) + d.UseOrderedObject() + var v interface{} - if err := json.Unmarshal(value, &v); err != nil { + if err := d.Decode(&v); err != nil { return nil, err } diff --git a/pkg/services/oracle/jsonpath/jsonpath.go b/pkg/services/oracle/jsonpath/jsonpath.go index 94887926e..105776d12 100644 --- a/pkg/services/oracle/jsonpath/jsonpath.go +++ b/pkg/services/oracle/jsonpath/jsonpath.go @@ -1,10 +1,10 @@ package jsonpath import ( - "encoding/json" - "sort" "strconv" "strings" + + json "github.com/virtuald/go-ordered-json" ) type ( @@ -193,16 +193,9 @@ func (p *pathParser) descend(objs []interface{}) ([]interface{}, bool) { switch obj := objs[i].(type) { case []interface{}: values = append(values, obj...) - case map[string]interface{}: - keys := make([]string, 0, len(obj)) - for k := range obj { - keys = append(keys, k) - } - - sort.Strings(keys) - - for _, k := range keys { - values = append(values, obj[k]) + case json.OrderedObject: + for i := range obj { + values = append(values, obj[i].Value) } } } @@ -243,14 +236,17 @@ func (p *pathParser) descendByIdentAux(objs []interface{}, checkDepth bool, name var values []interface{} for i := range objs { - obj, ok := objs[i].(map[string]interface{}) + obj, ok := objs[i].(json.OrderedObject) if !ok { continue } for j := range names { - if v, ok := obj[names[j]]; ok { - values = append(values, v) + for k := range obj { + if obj[k].Key == names[j] { + values = append(values, obj[k].Value) + break + } } } } diff --git a/pkg/services/oracle/jsonpath/jsonpath_test.go b/pkg/services/oracle/jsonpath/jsonpath_test.go index c6cff988c..cd9f40ae9 100644 --- a/pkg/services/oracle/jsonpath/jsonpath_test.go +++ b/pkg/services/oracle/jsonpath/jsonpath_test.go @@ -1,12 +1,13 @@ package jsonpath import ( - "encoding/json" + "bytes" "math" "strconv" "testing" "github.com/stretchr/testify/require" + json "github.com/virtuald/go-ordered-json" ) type pathTestCase struct { @@ -16,7 +17,10 @@ type pathTestCase struct { func unmarshalGet(t *testing.T, js string, path string) ([]interface{}, bool) { var v interface{} - require.NoError(t, json.Unmarshal([]byte(js), &v)) + buf := bytes.NewBuffer([]byte(js)) + d := json.NewDecoder(buf) + d.UseOrderedObject() + require.NoError(t, d.Decode(&v)) return Get(path, v) } @@ -94,8 +98,8 @@ func TestDescendByIdent(t *testing.T) { testCases := []pathTestCase{ {"$.store.name", `["big"]`}, {"$['store']['name']", `["big"]`}, - {"$[*].name", `["small","big"]`}, - {"$.*.name", `["small","big"]`}, + {"$[*].name", `["big","small"]`}, + {"$.*.name", `["big","small"]`}, {"$..store.name", `["big"]`}, {"$.store..name", `["big","ppp","sub1","sub2"]`}, {"$..sub.name", `[]`}, @@ -248,11 +252,10 @@ func TestCSharpCompat(t *testing.T) { "expensive": 10 }` - // FIXME(fyrchik): some tests are commented because of how maps are processed. testCases := []pathTestCase{ {"$.store.book[*].author", `["Nigel Rees","Evelyn Waugh","Herman Melville","J. R. R. Tolkien"]`}, {"$..author", `["Nigel Rees","Evelyn Waugh","Herman Melville","J. R. R. Tolkien"]`}, - //{"$.store.*", `[[{"category":"reference","author":"Nigel Rees","title":"Sayings of the Century","price":8.95},{"category":"fiction","author":"Evelyn Waugh","title":"Sword of Honour","price":12.99},{"category":"fiction","author":"Herman Melville","title":"Moby Dick","isbn":"0-553-21311-3","price":8.99},{"category":"fiction","author":"J. R. R. Tolkien","title":"The Lord of the Rings","isbn":"0-395-19395-8","price":22.99}],{"color":"red","price":19.95}]`}, + {"$.store.*", `[[{"category":"reference","author":"Nigel Rees","title":"Sayings of the Century","price":8.95},{"category":"fiction","author":"Evelyn Waugh","title":"Sword of Honour","price":12.99},{"category":"fiction","author":"Herman Melville","title":"Moby Dick","isbn":"0-553-21311-3","price":8.99},{"category":"fiction","author":"J. R. R. Tolkien","title":"The Lord of the Rings","isbn":"0-395-19395-8","price":22.99}],{"color":"red","price":19.95}]`}, {"$.store..price", `[19.95,8.95,12.99,8.99,22.99]`}, {"$..book[2]", `[{"category":"fiction","author":"Herman Melville","title":"Moby Dick","isbn":"0-553-21311-3","price":8.99}]`}, {"$..book[-2]", `[{"category":"fiction","author":"Herman Melville","title":"Moby Dick","isbn":"0-553-21311-3","price":8.99}]`}, @@ -261,7 +264,7 @@ func TestCSharpCompat(t *testing.T) { {"$..book[1:2]", `[{"category":"fiction","author":"Evelyn Waugh","title":"Sword of Honour","price":12.99}]`}, {"$..book[-2:]", `[{"category":"fiction","author":"Herman Melville","title":"Moby Dick","isbn":"0-553-21311-3","price":8.99},{"category":"fiction","author":"J. R. R. Tolkien","title":"The Lord of the Rings","isbn":"0-395-19395-8","price":22.99}]`}, {"$..book[2:]", `[{"category":"fiction","author":"Herman Melville","title":"Moby Dick","isbn":"0-553-21311-3","price":8.99},{"category":"fiction","author":"J. R. R. Tolkien","title":"The Lord of the Rings","isbn":"0-395-19395-8","price":22.99}]`}, - //{"$..*", `[{"book":[{"category":"reference","author":"Nigel Rees","title":"Sayings of the Century","price":8.95},{"category":"fiction","author":"Evelyn Waugh","title":"Sword of Honour","price":12.99},{"category":"fiction","author":"Herman Melville","title":"Moby Dick","isbn":"0-553-21311-3","price":8.99},{"category":"fiction","author":"J. R. R. Tolkien","title":"The Lord of the Rings","isbn":"0-395-19395-8","price":22.99}],"bicycle":{"color":"red","price":19.95}},10,[{"category":"reference","author":"Nigel Rees","title":"Sayings of the Century","price":8.95},{"category":"fiction","author":"Evelyn Waugh","title":"Sword of Honour","price":12.99},{"category":"fiction","author":"Herman Melville","title":"Moby Dick","isbn":"0-553-21311-3","price":8.99},{"category":"fiction","author":"J. R. R. Tolkien","title":"The Lord of the Rings","isbn":"0-395-19395-8","price":22.99}],{"color":"red","price":19.95},{"category":"reference","author":"Nigel Rees","title":"Sayings of the Century","price":8.95},{"category":"fiction","author":"Evelyn Waugh","title":"Sword of Honour","price":12.99},{"category":"fiction","author":"Herman Melville","title":"Moby Dick","isbn":"0-553-21311-3","price":8.99},{"category":"fiction","author":"J. R. R. Tolkien","title":"The Lord of the Rings","isbn":"0-395-19395-8","price":22.99},"red",19.95,"reference","Nigel Rees","Sayings of the Century",8.95,"fiction","Evelyn Waugh","Sword of Honour",12.99,"fiction","Herman Melville","Moby Dick","0-553-21311-3",8.99,"fiction","J. R. R. Tolkien","The Lord of the Rings","0-395-19395-8",22.99]`}, + {"$.*", `[{"book":[{"category":"reference","author":"Nigel Rees","title":"Sayings of the Century","price":8.95},{"category":"fiction","author":"Evelyn Waugh","title":"Sword of Honour","price":12.99},{"category":"fiction","author":"Herman Melville","title":"Moby Dick","isbn":"0-553-21311-3","price":8.99},{"category":"fiction","author":"J. R. R. Tolkien","title":"The Lord of the Rings","isbn":"0-395-19395-8","price":22.99}],"bicycle":{"color":"red","price":19.95}},10]`}, {"$..invalidfield", `[]`}, }