diff --git a/ast/raw.go b/ast/raw.go index 83cdce267..62d7a1046 100644 --- a/ast/raw.go +++ b/ast/raw.go @@ -780,18 +780,18 @@ func (self *Value) SetManyByIndex(ids []int, vals []Value) (bool, error) { } } -// Add appends the given node under self. -func (self *Value) AddAny(val interface{}) error { - return self.AddMany([]Value{NewValue(val)}) +// Add inserts single val into the left of the node at `from` (-1 means last) +func (self *Value) AddAny(from int, val interface{}) error { + return self.AddMany(from, []Value{NewValue(val)}) } -// Add appends the given node under self. -func (self *Value) Add(val Value) error { - return self.AddMany([]Value{val}) +// Add inserts single val into the left of the node at `from` (-1 means last) +func (self *Value) Add(from int, val Value) error { + return self.AddMany(from, []Value{val}) } -// Add appends the given node under self. -func (self *Value) AddMany(vals []Value) error { +// Add inserts multiple vals into the left of the node at `from` (-1 means last) +func (self *Value) AddMany(from int, vals []Value) error { if self.Check() != nil { return self } @@ -805,26 +805,46 @@ func (self *Value) AddMany(vals []Value) error { return ErrUnsupportType } + e := 1 // from == 0 + if from > 0 { + p := NewParserObj(self.js) + _, err := p.searchIndex(from) + if err != 0 { + if err == _ERR_NOT_FOUND { + e = len(self.js) - 1 // end before ']' + } else { + return p.ExportError(err) + } + } else { + e = p.p + } + } else if from < 0 { + e = len(self.js) - 1 + } + n := len(self.js) for _, v := range vals { n += len(v.js) + 1 } b := make([]byte, 0, n) - s := len(self.js) - 2 // start before ']' - for ; s >= 0 && isSpace(self.js[s]); s-- { - } - empty := self.js[s] == '[' + lastComma := self.js[e] != ']' + s := e - 1 + for ;s>=0 && isSpace(self.js[s]); s++ {} + firstComma := self.js[s] != ',' && self.js[s] != '[' - b = append(b, self.js[:s+1]...) - for _, val := range vals { - if !empty { + b = append(b, self.js[:e]...) + for i, val := range vals { + if i == 0 && firstComma { b = append(b, ","...) } - empty = false b = append(b, val.js...) + if i < len(vals)-1 || lastComma { + b = append(b, ","...) + } } - b = append(b, "]"...) + b = append(b, self.js[e:]...) + self.js = rt.Mem2Str(b) return nil } @@ -840,7 +860,7 @@ var intsPool = sync.Pool{ }, } -// PopMany pops at most n trailling elements in the array. +// PopMany pops at most n trailling elements in the array. -1 means clears all func (self *Value) PopMany(n int) error { if self.Check() != nil { return self diff --git a/ast/raw_test.go b/ast/raw_test.go index 6fe733587..490d946d0 100644 --- a/ast/raw_test.go +++ b/ast/raw_test.go @@ -675,6 +675,38 @@ func TestRawNode_UnsetMany(t *testing.T) { } } +func TestValue_Add(t *testing.T) { + tests := []struct{ + name string + js string + adds []interface{} + from int + err string + out string + }{ + {"empty +1", `[]`, []interface{}{1}, 0, "", `[1]`}, + {"empty +1", `[]`, []interface{}{1}, 1, "", `[1]`}, + {"empty +1", `[]`, []interface{}{1}, -1, "", `[1]`}, + {"1+1", `[0]`, []interface{}{1}, 0, "", `[1,0]`}, + {"1+1", `[0]`, []interface{}{1}, 1, "", `[0,1]`}, + {"1+1", `[0]`, []interface{}{1}, -1, "", `[0,1]`}, + {"2+1", `[-1,0]`, []interface{}{1}, 0, "", `[1,-1,0]`}, + {"2+1", `[-1,0]`, []interface{}{1}, 1, "", `[-1,1,0]`}, + {"2+1", `[-1,0]`, []interface{}{1}, 2, "", `[-1,0,1]`}, + {"2+1", `[-1,0]`, []interface{}{1}, -1, "", `[-1,0,1]`}, + } + for _, c := range tests { + println(c.name) + root := NewValueJSON(c.js) + vals := []Value{} + for _, val := range c.adds { + vals = append(vals, NewValue(val)) + } + require.NoError(t, root.AddMany(c.from, vals)) + require.Equal(t, c.out, root.js) + } +} + func TestValue_Add_Pop(t *testing.T) { tests := []struct{ name string @@ -692,6 +724,7 @@ func TestValue_Add_Pop(t *testing.T) { {"1+1-0", `[0]`, []interface{}{1}, 0, "", `[0,1]`}, {"1+1-1", `[0]`, []interface{}{1}, 1, "", `[0]`}, {"1+1-2", `[0]`, []interface{}{1}, 2, "", `[]`}, + {"1+1-3", `[0]`, []interface{}{1}, 3, "", `[]`}, {"1+2-0", `[0]`, []interface{}{1,2}, 0, "", `[0,1,2]`}, {"1+2-1", `[0]`, []interface{}{1,2}, 1, "", `[0,1]`}, } @@ -702,7 +735,7 @@ func TestValue_Add_Pop(t *testing.T) { for i, val := range c.adds { vals = append(vals, NewValue(val)) println("add", i) - if err := root.AddAny(val); err != nil { + if err := root.AddAny(-1, val); err != nil { t.Fatal(err) } println(root.js) @@ -712,7 +745,7 @@ func TestValue_Add_Pop(t *testing.T) { println(root.js) } require.Equal(t, c.js, root.js) - require.NoError(t, root.AddMany(vals)) + require.NoError(t, root.AddMany(-1, vals)) require.NoError(t, root.PopMany(c.pops)) require.Equal(t, c.out, root.js) }