Skip to content

Commit 42fe70e

Browse files
committed
refactor: optimize object handling by introducing TryGet method and preallocating storage in JsonObject
1 parent c1794ee commit 42fe70e

3 files changed

Lines changed: 51 additions & 17 deletions

File tree

jsonte/json_processor.go

Lines changed: 33 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -576,10 +576,10 @@ func (v *TemplateVisitor) visitObject(obj *types.JsonObject, path string) (types
576576
}
577577
if arr, ok := eval.Value.(*types.JsonArray); ok {
578578
for i, val := range arr.Value {
579-
v.pushScope(types.AsObject(map[string]interface{}{
580-
eval.IndexName: types.AsNumber(i),
581-
eval.Name: val,
582-
}))
579+
scopeObj := types.NewJsonObjectWithCapacity(2)
580+
scopeObj.Put(eval.IndexName, types.AsNumber(i))
581+
scopeObj.Put(eval.Name, val)
582+
v.pushScope(scopeObj)
583583
if obj, ok := val.(*types.JsonObject); ok {
584584
v.pushScope(obj)
585585
}
@@ -673,15 +673,36 @@ func PutValue(result *types.JsonObject, key string, r types.JsonType, path strin
673673
if r == nil || types.IsNull(r) {
674674
result.Put(key, types.Null)
675675
} else {
676-
if strings.HasPrefix(key, "$") && result.ContainsKey(key) && !types.IsReservedKey(key) {
676+
existing, hasExisting := result.TryGet(key)
677+
if !hasExisting || existing == nil || types.IsNull(existing) {
677678
result.Put(key, r)
678-
} else {
679-
json, err := types.MergeJSON(result.Get(key), r, true)
679+
return nil
680+
}
681+
682+
if strings.HasPrefix(key, "$") && !types.IsReservedKey(key) {
683+
result.Put(key, r)
684+
return nil
685+
}
686+
687+
if types.IsObject(existing) && types.IsObject(r) {
688+
merged, err := types.MergeJSON(existing, r, true)
680689
if err != nil {
681690
return utils.WrapJsonErrorf(path, err, "Failed to merge %s", key)
682691
}
683-
result.Put(key, json)
692+
result.Put(key, merged)
693+
return nil
684694
}
695+
696+
if types.IsArray(existing) && types.IsArray(r) {
697+
merged, err := types.MergeJSON(existing, r, true)
698+
if err != nil {
699+
return utils.WrapJsonErrorf(path, err, "Failed to merge %s", key)
700+
}
701+
result.Put(key, merged)
702+
return nil
703+
}
704+
705+
result.Put(key, r)
685706
}
686707
return nil
687708
}
@@ -723,10 +744,10 @@ func (v *TemplateVisitor) visitArrayElement(array []types.JsonType, element type
723744
case types.Iteration:
724745
if arr, ok := eval.Value.(*types.JsonArray); ok {
725746
for i, val := range arr.Value {
726-
v.pushScope(types.AsObject(map[string]interface{}{
727-
eval.IndexName: types.AsNumber(i),
728-
eval.Name: val,
729-
}))
747+
scopeObj := types.NewJsonObjectWithCapacity(2)
748+
scopeObj.Put(eval.IndexName, types.AsNumber(i))
749+
scopeObj.Put(eval.Name, val)
750+
v.pushScope(scopeObj)
730751
if obj, ok := val.(*types.JsonObject); ok {
731752
v.pushScope(obj)
732753
}

jsonte/types/object.go

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -41,20 +41,27 @@ func (t *JsonObject) Keys() []string {
4141
}
4242

4343
func (t *JsonObject) Get(key string) JsonType {
44-
if t.Value != nil && t.ContainsKey(key) {
45-
return t.Value.Get(key)
44+
if val, ok := t.TryGet(key); ok {
45+
return val
46+
}
47+
return Null
48+
}
49+
50+
func (t *JsonObject) TryGet(key string) (JsonType, bool) {
51+
if t.Value != nil {
52+
return t.Value.TryGet(key)
4653
}
4754
if t.StackValue != nil {
4855
if t.StackTarget.ContainsKey(key) {
49-
return t.StackTarget.Get(key)
56+
return t.StackTarget.Get(key), true
5057
}
5158
for i := t.StackValue.Len() - 1; i >= 0; i-- {
5259
if t.StackValue.At(i).ContainsKey(key) {
53-
return t.StackValue.At(i).Get(key)
60+
return t.StackValue.At(i).Get(key), true
5461
}
5562
}
5663
}
57-
return Null
64+
return Null, false
5865
}
5966

6067
func (t *JsonObject) Put(key string, value JsonType) {

jsonte/utils/navigable_map.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,12 @@ func (m *NavigableMap[K, V]) Get(key K) V {
5757
return m.data[key]
5858
}
5959

60+
// TryGet returns the value and whether it exists.
61+
func (m *NavigableMap[K, V]) TryGet(key K) (V, bool) {
62+
value, ok := m.data[key]
63+
return value, ok
64+
}
65+
6066
// Put puts the value associated with the key.
6167
func (m *NavigableMap[K, V]) Put(key K, value V) {
6268
if !m.ContainsKey(key) {

0 commit comments

Comments
 (0)