2
0
Fork 0
mirror of https://github.com/ii64/sonic.git synced 2026-06-21 00:46:43 +08:00

chore!: return error for scanning API (#81)

* chore!: return error for cast API

BREAKING CHANGE:
- Set()/Unset()/SetByIndex()/UnsetByIndex/Add() 
- Raw()/Bool()/Int64()/Float64()/Number()/Len()/Cap()
- Values()/Properties()/Map()/Array()/Interface()

Co-authored-by: duanyi.aster <duanyi.aster@bytedance.com>
This commit is contained in:
Yi Duan 2021-08-30 17:14:38 +08:00 committed by GitHub
parent 6aec2f3722
commit 1f13d31b5a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 838 additions and 341 deletions

View file

@ -151,6 +151,23 @@ root, err := sonic.Get(input, "key1", 1, "key2")
sub := root.Get("key3").Index(2).Int64() // == 3
```
#### Set/Unset
Modify the json content by Set()/Unset()
```go
import "github.com/bytedance/sonic"
// Set
exist, err := root.Set("key4", NewBool(true)) // exist == false
alias1 := root.Get("key4")
println(alias1.Valid()) // true
alias2 := root.Index(1)
println(alias1 == alias2) // true
// Unset
exist, err := root.UnsetByIndex(1) // exist == true
println(root.Get("key4").Check()) // "value not exist"
```
#### Serialize
To encode `ast.Node` as json, use `MarshalJson()` or `json.Marshal()` (MUST pass the node's pointer)
```go

View file

@ -17,7 +17,6 @@
package ast
import (
`errors`
`sync`
)
@ -69,7 +68,8 @@ func (self *Node) encode(buf *[]byte) error {
return self.encodeRaw(buf)
}
switch self.Type() {
case V_NONE : return errors.New("value not exist")
case V_NONE : return ErrNotExist
case V_ERROR : return self.Check()
case V_NULL : return self.encodeNull(buf)
case V_TRUE : return self.encodeTrue(buf)
case V_FALSE : return self.encodeFalse(buf)
@ -77,13 +77,15 @@ func (self *Node) encode(buf *[]byte) error {
case V_OBJECT: return self.encodeObject(buf)
case V_STRING: return self.encodeString(buf)
case V_NUMBER: return self.encodeNumber(buf)
default : errors.New("unsupported type")
default : return ErrUnsupportType
}
return nil
}
func (self *Node) encodeRaw(buf *[]byte) error {
raw := self.Raw()
raw, err := self.Raw()
if err != nil {
return err
}
*buf = append(*buf, raw...)
return nil
}
@ -119,7 +121,9 @@ func (self *Node) encodeString(buf *[]byte) error {
func (self *Node) encodeArray(buf *[]byte) error {
if self.isLazy() {
self.skipAllIndex()
if err := self.skipAllIndex(); err != nil {
return err
}
}
nb := self.len()
@ -157,7 +161,9 @@ func (self *Pair) encode(buf *[]byte) error {
func (self *Node) encodeObject(buf *[]byte) error {
if self.isLazy() {
self.skipAllKey()
if err := self.skipAllKey(); err != nil {
return err
}
}
nb := self.len()

View file

@ -35,7 +35,7 @@ func (self *Iterator) Len() int {
}
func (self *Iterator) HasNext() bool {
return self.i < self.p.len()
return self.i < self.p.len() && self.p.Valid()
}
type ListIterator struct {

View file

@ -47,14 +47,15 @@ func TestRawIterator(t *testing.T) {
if err != nil {
t.Fatal(err)
}
ai := root.Values()
ai, _ := root.Values()
i := int64(0)
for ai.HasNext() {
v := &Node{}
if !ai.Next(v) {
t.Fatalf("no next")
}
if i < int64(loop) && v.Int64() != i {
}
x, _ := v.Int64()
if i < int64(loop) && x != i {
t.Fatalf("exp:%v, got:%v", i, v)
}
if i != int64(ai.Pos())-1 || i >= int64(ai.Len()) {
@ -67,15 +68,17 @@ func TestRawIterator(t *testing.T) {
if err != nil {
t.Fatal(err)
}
mi := root.Properties()
mi, _ := root.Properties()
i = int64(0)
for mi.HasNext() {
v := &Pair{}
if !mi.Next(v) {
t.Fatalf("no next")
}
if i < int64(loop) &&( v.Value.Int64() != i ||v.Key != fmt.Sprintf("k%d", i)) {
t.Fatalf("exp:%v, got:%v", i, v.Value.Interface())
}
x, _ := v.Value.Int64()
if i < int64(loop) &&( x != i ||v.Key != fmt.Sprintf("k%d", i)) {
vv, _ := v.Value.Interface()
t.Fatalf("exp:%v, got:%v", i, vv)
}
if i != int64(mi.Pos())-1 || i >= int64(mi.Len()) {
t.Fatal(i)
@ -92,14 +95,15 @@ func TestIterator(t *testing.T) {
if err != 0 {
t.Fatal(err)
}
ai := root.Get("array").Values()
ai, _ := root.Get("array").Values()
i := int64(0)
for ai.HasNext() {
v := &Node{}
if !ai.Next(v) {
t.Fatalf("no next")
}
if i < int64(loop) && v.Int64() != i {
x, _ := v.Int64()
if i < int64(loop) && x != i {
t.Fatalf("exp:%v, got:%v", i, v)
}
if i != int64(ai.Pos())-1 || i >= int64(ai.Len()) {
@ -112,15 +116,17 @@ func TestIterator(t *testing.T) {
if err != 0 {
t.Fatal(err)
}
mi := root.Get("object").Properties()
mi, _ := root.Get("object").Properties()
i = int64(0)
for mi.HasNext() {
v := &Pair{}
if !mi.Next(v) {
t.Fatalf("no next")
}
if i < int64(loop) &&( v.Value.Int64() != i ||v.Key != fmt.Sprintf("k%d", i)) {
t.Fatalf("exp:%v, got:%v", i, v.Value.Interface())
x, _ := v.Value.Int64()
if i < int64(loop) &&( x != i ||v.Key != fmt.Sprintf("k%d", i)) {
vv, _ := v.Value.Interface()
t.Fatalf("exp:%v, got:%v", i, vv)
}
if i != int64(mi.Pos())-1 || i >= int64(mi.Len()) {
t.Fatal(i)
@ -135,7 +141,7 @@ func BenchmarkArrays(b *testing.B) {
if err != nil {
b.Fatal(err)
}
a := root.Array()
a, _ := root.Array()
for _,v := range a {
_ = v
}
@ -148,7 +154,7 @@ func BenchmarkListIterator(b *testing.B) {
if err != nil {
b.Fatal(err)
}
it := root.Values()
it, _ := root.Values()
for it.HasNext() {
v := &Node{}
if !it.Next(v) {
@ -164,7 +170,7 @@ func BenchmarkMap(b *testing.B) {
if err != nil {
b.Fatal(err)
}
m := root.Map()
m, _ := root.Map()
for k,v := range m {
_ = v
_ = k
@ -178,7 +184,7 @@ func BenchmarkObjectIterator(b *testing.B) {
if err != nil {
b.Fatal(err)
}
it := root.Properties()
it, _ := root.Properties()
for it.HasNext() {
v := &Pair{}
if !it.Next(v) {

File diff suppressed because it is too large Load diff

View file

@ -18,6 +18,8 @@ package ast
import (
`encoding/json`
`fmt`
`reflect`
`strconv`
`testing`
@ -28,13 +30,134 @@ import (
var parallelism = 4
func TestTypeCast(t *testing.T) {
type tcase struct {
method string
node Node
exp interface{}
err error
}
lazyArray, _ := NewParser("[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16]").Parse()
lazyObject, _ := NewParser(`{"0":0,"1":1,"2":2,"3":3,"4":4,"5":5,"6":6,"7":7,"8":8,"9":9,"10":10,"11":11,"12":12,"13":13,"14":14,"15":15,"16":16}`).Parse()
var cases = []tcase{
{"Raw", Node{}, "", ErrUnsupportType},
{"Raw", newRawNode("[ ]", types.V_ARRAY), "[ ]", nil},
{"Bool", Node{}, false, ErrNotExist},
{"Bool", newRawNode("true", types.V_TRUE), true, nil},
{"Bool", newRawNode("false", types.V_FALSE), false, nil},
{"Int64", Node{}, int64(0), ErrNotExist},
{"Int64", newRawNode("0", _V_NUMBER), int64(0), nil},
{"Float64", Node{}, float64(0), ErrNotExist},
{"Float64", newRawNode("0.0", _V_NUMBER), float64(0.0), nil},
{"Number", Node{}, json.Number(""), ErrNotExist},
{"Number", newRawNode("0.0", _V_NUMBER), json.Number("0.0"), nil},
{"Number", newRawNode("true", types.V_TRUE), json.Number("1"), nil},
{"Number", newRawNode("false", types.V_FALSE), json.Number("0"), nil},
{"String", Node{}, "", ErrNotExist},
{"String", newRawNode(`""`, types.V_STRING), ``, nil},
{"String", newRawNode(`0.0`, _V_NUMBER), "0.0", nil},
{"String", newRawNode(`null`, types.V_NULL), "null", nil},
{"String", newRawNode(`true`, types.V_TRUE), "true", nil},
{"String", newRawNode(`false`, types.V_FALSE), "false", nil},
{"Len", NewNull(), 0, ErrUnsupportType},
{"Len", newRawNode(`"1"`, types.V_STRING), 1, nil},
{"Len", newRawNode(`[1]`, types.V_ARRAY), 0, nil},
{"Len", NewArray([]Node{NewNull()}), 1, nil},
{"Len", lazyArray, 0, nil},
{"Len", newRawNode(`{"a":1}`, types.V_OBJECT), 0, nil},
{"Len", lazyObject, 0, nil},
{"Cap", NewNull(), 0, ErrUnsupportType},
{"Cap", newRawNode(`[1]`, types.V_ARRAY), _DEFAULT_NODE_CAP, nil},
{"Cap", NewObject([]Pair{{"",NewNull()}}), 1, nil},
{"Cap", newRawNode(`{"a":1}`, types.V_OBJECT), _DEFAULT_NODE_CAP, nil},
}
lazyArray.skipAllIndex()
lazyObject.skipAllKey()
cases = append(cases,
tcase{"Len", lazyObject, 17, nil},
tcase{"Len", lazyObject, 17, nil},
tcase{"Cap", lazyObject, _DEFAULT_NODE_CAP*2, nil},
tcase{"Cap", lazyObject, _DEFAULT_NODE_CAP*2, nil},
)
for i, c := range cases {
fmt.Println(c)
rt := reflect.ValueOf(&c.node)
m := rt.MethodByName(c.method)
rets := m.Call([]reflect.Value{})
if len(rets) != 2 {
t.Fatal(i, rets)
}
if rets[0].Interface() != c.exp {
t.Fatal(i, rets[0].Interface())
}
if rets[1].Interface() != c.err {
t.Fatal(i, rets[1].Interface())
}
}
}
func TestCheckError(t *testing.T) {
s, err := NewParser(`{"a":{}, "b":talse, "c":{}}`).Parse()
if err != 0 {
t.Fatal(err)
}
root := s.GetByPath()
// fmt.Println(root.Check())
a := root.Get("a")
if a.Check() != nil {
t.Fatal(a.Check())
}
c := root.Get("c")
if c.Check() == nil {
t.Fatal()
}
fmt.Println(c.Check())
_, e := a.Properties()
if e != nil {
t.Fatal(e)
}
exist, e := a.Set("d", newRawNode("x", types.V_OBJECT))
if exist || e != nil {
t.Fatal(err)
}
if a.len() != 1 {
t.Fail()
}
d := a.Get("d").Get("")
if d.Check() == nil {
t.Fatal(d)
}
exist, e = a.Set("e", newRawNode("[}", types.V_ARRAY))
if e != nil {
t.Fatal(e)
}
if a.len() != 2 {
t.Fail()
}
d = a.Index(1).Index(0)
if d.Check() == nil {
t.Fatal(d)
}
it, e := root.Interface()
if e == nil {
t.Fatal(it)
}
fmt.Println(e)
}
func TestIndex(t *testing.T) {
root, derr := NewParser(_TwitterJson).Parse()
if derr != 0 {
t.Fatalf("decode failed: %v", derr.Error())
}
status := root.GetByPath("statuses", 0)
if status.Index(4).String() != status.Get("id_str").String() {
x, _ := status.Index(4).String()
y, _ := status.Get("id_str").String()
if x != y {
t.Fail()
}
}
@ -48,25 +171,26 @@ func TestUnset(t *testing.T) {
if !entities.Exists() {
t.Fatal()
}
exist := entities.Unset("urls")
if !exist {
exist, err := entities.Unset("urls")
if !exist || err != nil {
t.Fatal()
}
e := entities.Get("urls")
if e.Exists() {
t.Fatal()
}
if entities.Len() != 2 {
if entities.len() != 2 {
t.Fatal()
}
entities.Set("urls", NewString("a"))
e = entities.Get("urls")
if !e.Exists() || e.String() != "a" {
x, _ := e.String()
if !e.Exists() || x != "a" {
t.Fatal()
}
exist = entities.UnsetByIndex(entities.Len()-1)
if !exist {
exist, err = entities.UnsetByIndex(entities.len()-1)
if !exist || err != nil {
t.Fatal()
}
e = entities.Get("urls")
@ -76,11 +200,12 @@ func TestUnset(t *testing.T) {
hashtags := entities.Get("hashtags").Index(0)
hashtags.Set("text2", newRawNode(`{}`, types.V_OBJECT))
exist = hashtags.Unset("indices")
if !exist || hashtags.Len() != 2 {
exist, err = hashtags.Unset("indices")
if !exist || err != nil || hashtags.len() != 2 {
t.Fatal()
}
if hashtags.Get("text").String() != "freebandnames" {
y, _ := hashtags.Get("text").String()
if y != "freebandnames" {
t.Fatal()
}
if hashtags.Get("text2").Type() != V_OBJECT {
@ -91,14 +216,16 @@ func TestUnset(t *testing.T) {
ums.Add(NewNull())
ums.Add(NewBool(true))
ums.Add(NewBool(false))
if ums.Len() != 3 {
if ums.len() != 3 {
t.Fatal()
}
exist = ums.UnsetByIndex(1)
if !exist {
exist, err = ums.UnsetByIndex(1)
if !exist || err != nil {
t.Fatal()
}
if ums.Index(0).Interface() != nil || ums.Index(1).Interface() != false {
v1, _ := ums.Index(0).Interface()
v2, _ := ums.Index(1).Interface()
if v1 != nil || v2 != false {
t.Fatal()
}
@ -111,14 +238,15 @@ func TestUnsafeNode(t *testing.T) {
if err != nil {
t.Fatal(err)
}
a := root.UnsafeArray()
a, _ := root.UnsafeArray()
if len(a) != loop {
t.Fatalf("exp:%v, got:%v", loop, len(a))
}
for i := int64(0); i<int64(loop); i++{
in := a[i]
if in.Int64() != i {
t.Fatalf("exp:%v, got:%v", i, in.Int64())
x, _ := in.Int64()
if x != i {
t.Fatalf("exp:%v, got:%v", i, x)
}
}
@ -126,7 +254,7 @@ func TestUnsafeNode(t *testing.T) {
if err != nil {
t.Fatal(err)
}
b := root.UnsafeMap()
b, _ := root.UnsafeMap()
if len(b) != loop {
t.Fatalf("exp:%v, got:%v", loop, len(b))
}
@ -135,27 +263,37 @@ func TestUnsafeNode(t *testing.T) {
if k != b[i].Key {
t.Fatalf("unexpected element: %#v", b[i])
}
if b[i].Value.Int64() != i {
t.Fatalf("exp:%v, got:%v", i, b[i].Value.Int64())
x, _ := b[i].Value.Int64()
if x != i {
t.Fatalf("exp:%v, got:%v", i, x)
}
}
}
func TestUseNode(t *testing.T) {
str, loop := getTestIteratorSample()
root, e := NewParser(str).Parse()
if e != 0 {
t.Fatal(e)
}
_, er := root.InterfaceUseNode()
if er != nil {
t.Fatal(er)
}
root, err := NewSearcher(str).GetByPath("array")
if err != nil {
t.Fatal(err)
}
a := root.ArrayUseNode()
a, _ := root.ArrayUseNode()
if len(a) != loop {
t.Fatalf("exp:%v, got:%v", loop, len(a))
}
for i := int64(0); i<int64(loop); i++{
in := a[i]
if in.Int64() != i {
t.Fatalf("exp:%v, got:%v", i, in.Int64())
a, _ := in.Int64()
if a != i {
t.Fatalf("exp:%v, got:%v", i, a)
}
}
@ -163,14 +301,16 @@ func TestUseNode(t *testing.T) {
if err != nil {
t.Fatal(err)
}
a = root.InterfaceUseNode().([]Node)
x, _ := root.InterfaceUseNode()
a = x.([]Node)
if len(a) != loop {
t.Fatalf("exp:%v, got:%v", loop, len(a))
}
for i := int64(0); i<int64(loop); i++{
in := a[i]
if in.Int64() != i {
t.Fatalf("exp:%v, got:%v", i, in.Int64())
a, _ := in.Int64()
if a != i {
t.Fatalf("exp:%v, got:%v", i, a)
}
}
@ -178,7 +318,7 @@ func TestUseNode(t *testing.T) {
if err != nil {
t.Fatal(err)
}
b := root.MapUseNode()
b, _ := root.MapUseNode()
if len(b) != loop {
t.Fatalf("exp:%v, got:%v", loop, len(b))
}
@ -188,8 +328,9 @@ func TestUseNode(t *testing.T) {
if !ok {
t.Fatalf("unexpected element: %#v", xn)
}
if xn.Int64() != i {
t.Fatalf("exp:%v, got:%v", i, xn.Int64())
a, _ := xn.Int64()
if a != i {
t.Fatalf("exp:%v, got:%v", i, a)
}
}
@ -197,7 +338,8 @@ func TestUseNode(t *testing.T) {
if err != nil {
t.Fatal(err)
}
b = root.InterfaceUseNode().(map[string]Node)
x, _ = root.InterfaceUseNode()
b = x.(map[string]Node)
if len(b) != loop {
t.Fatalf("exp:%v, got:%v", loop, len(b))
}
@ -207,13 +349,24 @@ func TestUseNode(t *testing.T) {
if !ok {
t.Fatalf("unexpected element: %#v", xn)
}
if xn.Int64() != i {
t.Fatalf("exp:%v, got:%v", i, xn.Int64())
a, _ := xn.Int64()
if a != i {
t.Fatalf("exp:%v, got:%v", i, a)
}
}
}
func TestUseNumber(t *testing.T) {
str, _ := getTestIteratorSample()
root, e := NewParser(str).Parse()
if e != 0 {
t.Fatal(e)
}
_, er := root.InterfaceUseNumber()
if er != nil {
t.Fatal(er)
}
node, err := NewParser("1061346755812312312313").Parse()
if err != 0 {
t.Fatal(err)
@ -221,16 +374,19 @@ func TestUseNumber(t *testing.T) {
if node.Type() != V_NUMBER {
t.Fatalf("wrong type: %v", node.Type())
}
iv := node.InterfaceUseNumber().(json.Number)
x, _ := node.InterfaceUseNumber()
iv := x.(json.Number)
if iv.String() != "1061346755812312312313" {
t.Fatalf("exp:%#v, got:%#v", "1061346755812312312313", iv.String())
}
ix := node.Interface().(float64)
x, _ = node.Interface()
ix := x.(float64)
if ix != float64(1061346755812312312313) {
t.Fatalf("exp:%#v, got:%#v", float64(1061346755812312312313), ix)
}
ij,_ := node.Number().Int64()
jj,_ := json.Number("1061346755812312312313").Int64()
xj, _ := node.Number()
ij, _ := xj.Int64()
jj, _ := json.Number("1061346755812312312313").Int64()
if ij != jj {
t.Fatalf("exp:%#v, got:%#v", jj, ij)
}
@ -241,14 +397,14 @@ func TestMap(t *testing.T) {
if err != 0 {
t.Fatal(err)
}
m := node.Map()
m, _ := node.Map()
assert.Equal(t, m, map[string]interface{}{
"a": float64(0),
"b": float64(1),
"c": -1.2,
"d": -1.2e-10,
})
m1 := node.MapUseNumber()
m1, _ := node.MapUseNumber()
assert.Equal(t, m1, map[string]interface{}{
"a": json.Number("-0"),
"b": json.Number("1"),
@ -262,14 +418,14 @@ func TestArray(t *testing.T) {
if err != 0 {
t.Fatal(err)
}
m := node.Array()
m, _ := node.Array()
assert.Equal(t, m, []interface{}{
float64(0),
float64(1),
-1.2,
-1.2e-10,
})
m1 := node.ArrayUseNumber()
m1, _ := node.ArrayUseNumber()
assert.Equal(t, m1, []interface{}{
json.Number("-0"),
json.Number("1"),
@ -283,7 +439,7 @@ func TestNodeRaw(t *testing.T) {
if derr != nil {
t.Fatalf("decode failed: %v", derr.Error())
}
val := root.Raw()
val, _ := root.Raw()
var comp = `{
"max_id": 250126199840518145,
"since_id": 24012619984051000,
@ -303,7 +459,7 @@ func TestNodeRaw(t *testing.T) {
if derr != nil {
t.Fatalf("decode failed: %v", derr.Error())
}
val = root.Raw()
val, _ = root.Raw()
comp = `[
{
"text": "freebandnames",
@ -322,7 +478,7 @@ func TestNodeRaw(t *testing.T) {
if derr != nil {
t.Fatalf("decode failed: %v", derr.Error())
}
val = root.Raw()
val, _ = root.Raw()
comp = `{ "a" : "bc"}`
if val != comp {
t.Fatalf("exp: %+v, got: %+v", comp, val)
@ -332,7 +488,7 @@ func TestNodeRaw(t *testing.T) {
if derr != nil {
t.Fatalf("decode failed: %v", derr.Error())
}
val = root.Raw()
val, _ = root.Raw()
comp = `[1,2 ]`
if val != comp {
t.Fatalf("exp: %+v, got: %+v", comp, val)
@ -342,7 +498,7 @@ func TestNodeRaw(t *testing.T) {
if derr != nil {
t.Fatalf("decode failed: %v", derr.Error())
}
val = root.Raw()
val, _ = root.Raw()
comp = `{}`
if val != comp {
t.Fatalf("exp: %+v, got: %+v", comp, val)
@ -352,7 +508,7 @@ func TestNodeRaw(t *testing.T) {
if derr != nil {
t.Fatalf("decode failed: %v", derr.Error())
}
val = root.Raw()
val, _ = root.Raw()
comp = `[]`
if val != comp {
t.Fatalf("exp: %+v, got: %+v", comp, val)
@ -364,7 +520,7 @@ func TestNodeGet(t *testing.T) {
if derr != 0 {
t.Fatalf("decode failed: %v", derr.Error())
}
val := root.Get("search_metadata").Get("max_id").Int64()
val, _ := root.Get("search_metadata").Get("max_id").Int64()
if val != int64(250126199840518145) {
t.Fatalf("exp: %+v, got: %+v", 250126199840518145, val)
}
@ -375,7 +531,7 @@ func TestNodeIndex(t *testing.T) {
if derr != 0 {
t.Fatalf("decode failed: %v", derr.Error())
}
val := root.Get("statuses").Index(3).Get("id_str").String()
val, _ := root.Get("statuses").Index(3).Get("id_str").String()
if val != "249279667666817024" {
t.Fatalf("exp: %+v, got: %+v", "249279667666817024", val)
}
@ -386,7 +542,7 @@ func TestNodeGetByPath(t *testing.T) {
if derr != 0 {
t.Fatalf("decode failed: %v", derr.Error())
}
val := root.GetByPath("statuses", 3, "id_str").String()
val, _ := root.GetByPath("statuses", 3, "id_str").String()
if val != "249279667666817024" {
t.Fatalf("exp: %+v, got: %+v", "249279667666817024", val)
}
@ -399,14 +555,14 @@ func TestNodeSet(t *testing.T) {
}
app,_ := NewParser("111").Parse()
root.GetByPath("statuses", 3).Set("id_str", app)
val := root.GetByPath("statuses", 3, "id_str").Int64()
val, _ := root.GetByPath("statuses", 3, "id_str").Int64()
if val != 111 {
t.Fatalf("exp: %+v, got: %+v", 111, val)
}
for i := root.GetByPath("statuses", 3).Cap(); i >= 0; i-- {
for i := root.GetByPath("statuses", 3).cap(); i >= 0; i-- {
root.GetByPath("statuses", 3).Set("id_str"+strconv.Itoa(i), app)
}
val = root.GetByPath("statuses", 3, "id_str0").Int64()
val, _ = root.GetByPath("statuses", 3, "id_str0").Int64()
if val != 111 {
t.Fatalf("exp: %+v, got: %+v", 111, val)
}
@ -416,7 +572,7 @@ func TestNodeSet(t *testing.T) {
t.Fatalf("decode failed: %v", derr.Error())
}
root.GetByPath("statuses", 3).Set("id_str2", nroot)
val2 := root.GetByPath("statuses", 3, "id_str2", "a", 4, "b").String()
val2, _ := root.GetByPath("statuses", 3, "id_str2", "a", 4, "b").String()
if val2 != "c" {
t.Fatalf("exp:%+v, got:%+v", "c", val2)
}
@ -432,7 +588,8 @@ func TestNodeSetByIndex(t *testing.T) {
st.SetByIndex(0, app)
st = root.GetByPath("statuses")
val := st.Index(0)
if val.Int64() != 111 {
x, _ := val.Int64()
if x != 111 {
t.Fatalf("exp: %+v, got: %+v", 111, val)
}
@ -441,7 +598,7 @@ func TestNodeSetByIndex(t *testing.T) {
t.Fatalf("decode failed: %v", derr.Error())
}
root.GetByPath("statuses").SetByIndex(0, nroot)
val2 := root.GetByPath("statuses", 0, "a", 4, "b").String()
val2, _ := root.GetByPath("statuses", 0, "a", 4, "b").String()
if val2 != "c" {
t.Fatalf("exp:%+v, got:%+v", "c", val2)
}
@ -454,14 +611,14 @@ func TestNodeAdd(t *testing.T) {
}
app, _ := NewParser("111").Parse()
for i := root.GetByPath("statuses").Cap(); i >= 0; i-- {
for i := root.GetByPath("statuses").cap(); i >= 0; i-- {
root.GetByPath("statuses").Add(app)
}
val := root.GetByPath("statuses", 4).Int64()
val, _ := root.GetByPath("statuses", 4).Int64()
if val != 111 {
t.Fatalf("exp: %+v, got: %+v", 111, val)
}
val = root.GetByPath("statuses", root.GetByPath("statuses").Len()-1).Int64()
val, _ = root.GetByPath("statuses", root.GetByPath("statuses").len()-1).Int64()
if val != 111 {
t.Fatalf("exp: %+v, got: %+v", 111, val)
}
@ -471,7 +628,7 @@ func TestNodeAdd(t *testing.T) {
t.Fatalf("decode failed: %v", derr.Error())
}
root.GetByPath("statuses").Add(nroot)
val2 := root.GetByPath("statuses", root.GetByPath("statuses").Len()-1, "a", 4, "b").String()
val2, _ := root.GetByPath("statuses", root.GetByPath("statuses").len()-1, "a", 4, "b").String()
if val2 != "c" {
t.Fatalf("exp:%+v, got:%+v", "c", val2)
}
@ -497,13 +654,13 @@ func BenchmarkNodeGetByPath(b *testing.B) {
if derr != 0 {
b.Fatalf("decode failed: %v", derr.Error())
}
_ = root.GetByPath("statuses", 3, "entities", "hashtags", 0, "text").String()
_, _ = root.GetByPath("statuses", 3, "entities", "hashtags", 0, "text").String()
b.SetParallelism(parallelism)
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
_ = root.GetByPath("statuses", 3, "entities", "hashtags", 0, "text").String()
_, _ = root.GetByPath("statuses", 3, "entities", "hashtags", 0, "text").String()
}
})
}
@ -553,7 +710,7 @@ func BenchmarkMapGet(b *testing.B) {
node.Set("test3", NewNumber("3"))
node.Set("test4", NewNumber("4"))
node.Set("test5", NewNumber("5"))
m := node.Map()
m, _ := node.Map()
b.ResetTimer()
for i := 0; i < b.N; i++ {
_ = m["text"]
@ -578,7 +735,7 @@ func BenchmarkMapSet(b *testing.B) {
if derr != 0 {
b.Fatalf("decode failed: %v", derr.Error())
}
node := root.Get("statuses").Index(3).Get("entities").Get("hashtags").Index(0).Map()
node, _ := root.Get("statuses").Index(3).Get("entities").Get("hashtags").Index(0).Map()
b.SetParallelism(parallelism)
b.ResetTimer()
for i := 0; i < b.N; i++ {
@ -611,7 +768,7 @@ func BenchmarkSliceAdd(b *testing.B) {
b.ResetTimer()
for i := 0; i < b.N; i++ {
root, _ := NewParser(data).Parse()
node := root.Get("statuses").Array()
node, _ := root.Get("statuses").Array()
node = append(node, map[string]interface{}{"test": 1})
}
}

View file

@ -19,7 +19,7 @@ package ast
import (
`fmt`
`sync`
`unsafe`
`unsafe`
`github.com/bytedance/sonic/decoder`
`github.com/bytedance/sonic/internal/native`
@ -30,7 +30,18 @@ import (
const _DEFAULT_NODE_CAP int = 16
const _ERR_NOT_FOUND types.ParsingError = 33
const (
_ERR_NOT_FOUND types.ParsingError = 33
_ERR_UNSUPPORT_TYPE types.ParsingError = 34
)
var (
nodeNotExist = newError(_ERR_NOT_FOUND, "value not exists")
nodeUnsupportType = newError(_ERR_UNSUPPORT_TYPE, "unsupported type")
ErrNotExist error = nodeNotExist
ErrUnsupportType error = nodeUnsupportType
)
type Parser struct {
p int
@ -330,20 +341,24 @@ func (self *Parser) skip() (int, types.ParsingError) {
/** Parser Factory **/
// Loads parse all json into interface{}
func Loads(src string) (int, interface{}, types.ParsingError) {
func Loads(src string) (int, interface{}, error) {
ps := &Parser{s: src}
np, err := ps.Parse()
/* check for errors */
if err != 0 {
return 0, nil, err
return 0, nil, ps.ExportError(err)
} else {
return ps.Pos(), np.Interface(), 0
x, err := np.Interface()
if err != nil {
return 0, nil, err
}
return ps.Pos(), x, nil
}
}
// LoadsUseNumber parse all json into interface{}, with numeric nodes casted to json.Number
func LoadsUseNumber(src string) (int, interface{}, types.ParsingError) {
func LoadsUseNumber(src string) (int, interface{}, error) {
ps := &Parser{s: src}
np, err := ps.Parse()
@ -351,7 +366,11 @@ func LoadsUseNumber(src string) (int, interface{}, types.ParsingError) {
if err != 0 {
return 0, nil, err
} else {
return ps.Pos(), np.InterfaceUseNumber(), 0
x, err := np.InterfaceUseNumber()
if err != nil {
return 0, nil, err
}
return ps.Pos(), x, nil
}
}
@ -362,11 +381,19 @@ func NewParser(src string) *Parser {
// ExportError converts types.ParsingError to std Error
func (self *Parser) ExportError(err types.ParsingError) error {
if err == _ERR_NOT_FOUND {
return fmt.Errorf("node not exists")
return ErrNotExist
}
return fmt.Errorf("%q", decoder.SyntaxError{
Pos: self.p,
Src: self.s,
Pos : self.p,
Src : self.s,
Code: err,
}.Description())
}
func (self *Parser) syntaxError(err types.ParsingError) *decoder.SyntaxError {
return &decoder.SyntaxError{
Pos : self.p,
Src : self.s,
Code: err,
}
}

View file

@ -28,13 +28,14 @@ import (
func runDecoderTest(t *testing.T, src string, expect interface{}) {
vv, err := NewParser(src).Parse()
if err != 0 { panic(err) }
assert.Equal(t, expect, vv.Interface())
x, _ := vv.Interface()
assert.Equal(t, expect, x)
}
func runDecoderTestUseNumber(t *testing.T, src string, expect interface{}) {
vv, err := NewParser(src).Parse()
if err != 0 { panic(err) }
vvv := vv.InterfaceUseNumber()
vvv, _ := vv.InterfaceUseNumber()
switch vvv.(type) {
case json.Number:
assert.Equal(t, expect, n2f64(vvv.(json.Number)))
@ -156,12 +157,12 @@ func TestParser_Basic(t *testing.T) {
func TestLoads(t *testing.T) {
_,i,e := Loads(`{"a": "123", "b": true, "c": false, "d": null, "e": 2.4, "f": 1.2e15, "g": 1}`)
if e != 0 {
if e != nil {
t.Fatal(e)
}
assert.Equal(t, map[string]interface{}{"a": "123", "b": true, "c": false, "d": nil, "e": 2.4, "f": 1.2e15, "g": float64(1)}, i)
_,i,e = LoadsUseNumber(`{"a": "123", "b": true, "c": false, "d": null, "e": 2.4, "f": 1.2e15, "g": 1}`)
if e != 0 {
if e != nil {
t.Fatal(e)
}
assert.Equal(t, map[string]interface{}{"a": "123", "b": true, "c": false, "d": nil, "e": json.Number("2.4"), "f": json.Number("1.2e15"), "g": json.Number("1")}, i)
@ -284,7 +285,7 @@ func BenchmarkGetOne_Sonic(b *testing.B) {
b.SetBytes(int64(len(_TwitterJson)))
for i := 0; i < b.N; i++ {
ast, _ := NewParser(_TwitterJson).Parse()
node := ast.Get("statuses").Index(2).Get("id").Int64()
node, _ := ast.Get("statuses").Index(2).Get("id").Int64()
if node != 249289491129438208 {
b.Fail()
}

View file

@ -60,27 +60,32 @@ func TestSearcher_GetByPath(t *testing.T) {
s := NewSearcher(` { "xx" : [] ,"yy" :{ }, "test" : [ true , 0.1 , "abc", ["h"], {"a":"bc"} ] } `)
node, e := s.GetByPath("test", 0)
if e != nil || node.Bool() != true {
a, _ := node.Bool()
if e != nil || a != true {
t.Fatalf("node: %v, err: %v", node, e)
}
node, e = s.GetByPath("test", 1)
if e != nil || node.Float64() != 0.1 {
b, _ := node.Float64()
if e != nil || b != 0.1 {
t.Fatalf("node: %v, err: %v", node, e)
}
node, e = s.GetByPath("test", 2)
if e != nil || node.String() != "abc" {
c, _ := node.String()
if e != nil || c != "abc" {
t.Fatalf("node: %v, err: %v", node, e)
}
node, e = s.GetByPath("test", 3)
if e != nil || node.Array()[0] != "h" {
arr, _ := node.Array()
if e != nil || arr[0] != "h" {
t.Fatalf("node: %v, err: %v", node, e)
}
node, e = s.GetByPath("test", 4, "a")
if e != nil || node.String() != "bc" {
d, _ := node.String()
if e != nil || d != "bc" {
t.Fatalf("node: %v, err: %v", node, e)
}
}
@ -123,9 +128,9 @@ func TestLoadIndex(t *testing.T) {
if err != nil {
t.Fatal(err)
}
a := node.Index(3).Float64()
a, _ := node.Index(3).Float64()
assert.Equal(t, -1.2e-10, a)
m := node.Array()
m, _ := node.Array()
assert.Equal(t, m, []interface{}{
float64(0),
float64(1),
@ -185,7 +190,8 @@ func BenchmarkSearchOne_Sonic(b *testing.B) {
if err != nil {
b.Fatal(err)
}
if node.Int64() != 249279667666817024 {
x, _ := node.Int64()
if x != 249279667666817024 {
b.Fatal(node.Interface())
}
}
@ -230,7 +236,8 @@ func BenchmarkSearchOne_Parallel_Sonic(b *testing.B) {
if err != nil {
b.Fatal(err)
}
if node.Int64() != 249279667666817024 {
x, _ := node.Int64()
if x != 249279667666817024 {
b.Fatal(node.Interface())
}
}

View file

@ -48,27 +48,32 @@ func TestExampleSearch(t *testing.T) {
data := []byte(` { "xx" : [] ,"yy" :{ }, "test" : [ true , 0.1 , "abc", ["h"], {"a":"bc"} ] } `)
node, e := Get(data, "test", 0)
if e != nil || node.Bool() != true {
x, _ := node.Bool()
if e != nil || x != true {
t.Fatalf("node: %v, err: %v", node, e)
}
node, e = Get(data, "test", 1)
if e != nil || node.Float64() != 0.1 {
a, _ := node.Float64()
if e != nil || a != 0.1 {
t.Fatalf("node: %v, err: %v", node, e)
}
node, e = Get(data, "test", 2)
if e != nil || node.String() != "abc" {
b, _ := node.String()
if e != nil || b != "abc" {
t.Fatalf("node: %v, err: %v", node, e)
}
node, e = Get(data, "test", 3)
if e != nil || node.Array()[0] != "h" {
arr, _ := node.Array()
if e != nil || arr[0] != "h" {
t.Fatalf("node: %v, err: %v", node, e)
}
node, e = Get(data, "test", 4, "a")
if e != nil || node.String() != "bc" {
c, _ := node.String()
if e != nil || c != "bc" {
t.Fatalf("node: %v, err: %v", node, e)
}
}
@ -148,8 +153,9 @@ func TestRandomValidStrings(t *testing.T) {
if err != nil {
t.Fatal("search data failed:",err)
}
if token.Interface().(string) != su {
t.Fatalf("string mismatch, exp: %v, got: %v", su, token.Interface())
x, _ := token.Interface()
if x.(string) != su {
t.Fatalf("string mismatch, exp: %v, got: %v", su, x)
}
}
}
@ -166,8 +172,9 @@ func TestEmoji(t *testing.T) {
t.Fatal(err)
}
s, _ := v["utf8"].(string)
if value.String() != s {
t.Fatalf("expected '%v', got '%v'", s, value.String())
x, _ := value.String()
if x != s {
t.Fatalf("expected '%v', got '%v'", s, x)
}
}
@ -176,8 +183,10 @@ func testEscapePath(t *testing.T, json, expect string, path ...interface{}) {
if e != nil {
t.Fatal(e)
}
if n.String() != expect {
t.Fatalf("expected '%v', got '%v'", expect, n.Interface())
x, _ := n.String()
if x != expect {
x, _ := n.Interface()
t.Fatalf("expected '%v', got '%v'", expect, x)
}
}
@ -213,19 +222,23 @@ func TestParseAny(t *testing.T) {
if n == nil {
panic("n is nil")
}
assertCond(n.Float64() == 100)
x, _ := n.Float64()
assertCond(x == 100)
n, e = Parse("true")
assertCond(e == nil)
if n == nil {
panic("n is nil")
}
assertCond(n.Bool())
a, _ := n.Bool()
assertCond(a)
n, e = Parse("false")
assertCond(e == nil)
if n == nil {
panic("n is nil")
}
assertCond(n.Bool() == false)
b, _ := n.Bool()
assertCond(b == false)
n, e = Parse("yikes")
assertCond(e != nil)
}
@ -263,7 +276,9 @@ func TestTime(t *testing.T) {
if e != nil {
t.Fatal(e)
}
for _, v := range n.Array() {
arr, _ := n.Array()
for _, v := range arr {
s := v.(string)
num = append(num, s)
}
@ -303,7 +318,7 @@ func TestUnmarshalMap(t *testing.T) {
if err != nil || n == nil {
t.Fatal(err)
}
m1 := n.Map()
m1, _ := n.Map()
var m2 map[string]interface{}
if err := json.Unmarshal([]byte(exampleJSON), &m2); err != nil {
t.Fatal(err)
@ -337,7 +352,8 @@ func GetMany(src2 string, path ...string) (ret []string) {
ret = append(ret, "")
continue
}
ret = append(ret, fmt.Sprintf("%v", n.Interface()))
x, _ := n.Interface()
ret = append(ret, fmt.Sprintf("%v", x))
}
return
}
@ -361,7 +377,7 @@ func get(str string, path string) *ast.Node {
func TestSingleArrayValue(t *testing.T) {
var data = []byte(`{"key": "value","key2":[1,2,3,4,"A"]}`)
array := get(string(data), "key2").Array()
array, _ := get(string(data), "key2").Array()
if len(array) != 5 {
t.Fatalf("got '%v', expected '%v'", len(array), 5)
}
@ -392,6 +408,7 @@ var manyJSON = ` {
func TestManyBasic(t *testing.T) {
testMany := func(shouldFallback bool, expect string, paths ...string) {
println()
rs := GetMany(
manyJSON,
paths...,
@ -413,7 +430,8 @@ func TestManyBasic(t *testing.T) {
testMany(true, `[]`, strings.Repeat("a.", 40)+"hello")
res := get(manyJSON, strings.Repeat("a.", 48)+"a")
assertCond(res != nil)
testMany(true, "["+fmt.Sprint(res.Interface())+"]", strings.Repeat("a.", 48)+"a")
x, _ := res.Interface()
testMany(true, "["+fmt.Sprint(x)+"]", strings.Repeat("a.", 48)+"a")
// these should fallback
testMany(true, `[Cat Nancy]`, "name_first", "name.first")
testMany(true, `[world]`, strings.Repeat("a.", 70)+"hello")
@ -432,7 +450,8 @@ func testManyAny(t *testing.T, json string, paths, expected []string) {
which = "Get"
result = nil
for j := 0; j < len(expected); j++ {
result = append(result, fmt.Sprintf("%v", get(json, paths[j]).Interface()))
x, _ := get(json, paths[j]).Interface()
result = append(result, fmt.Sprintf("%v", x))
}
} else if i == 1 {
which = "GetMany"
@ -546,7 +565,7 @@ func TestGetMany2(t *testing.T) {
}
func TestNullArray(t *testing.T) {
n := get(`{"data":null}`, "data").Interface()
n, _ := get(`{"data":null}`, "data").Interface()
if n != nil {
t.Fatalf("expected '%v', got '%v'", nil, n)
}
@ -558,7 +577,8 @@ func TestNullArray(t *testing.T) {
if reflect.DeepEqual(n, &ast.Node{}) {
t.Fatalf("expected '%v', got '%v'", nil, n)
}
n = len(get(`{"data":[null]}`, "data").Array())
arr, _ := get(`{"data":[null]}`, "data").Array()
n = len(arr)
if n != 1 {
t.Fatalf("expected '%v', got '%v'", 1, n)
}
@ -613,7 +633,11 @@ func TestGetNotExist(t *testing.T) {
t.Fatal()
}
v2 := ret.GetByPath("m1", "m2")
if !v2.Exists() || !v2.IsRaw() || v2.Int64() != 3 {
if !v2.Exists() || !v2.IsRaw() {
t.Fatal(ret.Type())
}
x, _ := v2.Int64()
if x != 3 {
t.Fatal(x)
}
}