-
Notifications
You must be signed in to change notification settings - Fork 2
/
helper.go
122 lines (116 loc) · 3.57 KB
/
helper.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
package m2obj
import (
"strings"
)
// split splits the keyStr to keys.
func split(keyStr string) (keys []string) {
keys = make([]string, 0)
if keyStr = strings.TrimSpace(keyStr); keyStr == "" {
return
}
return strings.Split(keyStr, ".")
}
// splitAndDig digs into current object in-depth assigned by `keyStr`, until it gets the last element and returns it.
//
// Set `createLost` to true if you want to create lost keys in the `keyStr`.
// All of lost middle keys of `keyStr` will be checked:
// If it is marked as an Array (There is an `[index]` key behind it), send panic always.
// Else, create as a Group Object.
// The last key of `keyStr` just lost will be created as an empty Value Object. You can do something by yourself.
//
// The func panic at:
// 1. the key is not found and `createLost` is false
// 2. the key is middle of `keyStr` and has an object type neither *groupData nor *arrayData
// 3. the key behind an Array Object key doesn't satisfy the rule with ArrayName.[index]
func splitAndDig(current *Object, keyStr string, createLost bool) (obj, objParent *Object) {
tObjParent := current.Parent()
tObj := current
keys := split(keyStr)
for i, key := range keys {
if key == "" {
continue
}
tObjParent = tObj
// Once the code runs here, the tObj means the parent of the param key.
// After this switch, the tObj will be the object self assigned by the param key.
switch tObj.val.(type) {
case *groupData:
if next, ok := (*tObj.val.(*groupData))[key]; ok { // the key exists
tObj = next
} else if createLost { // not exists but can be created
mapObj := *tObj.val.(*groupData)
if i != len(keys)-1 { // is a middle key
if arrCheckIndexFormat(keys[i+1]) { // is Array
panic(invalidTypeErr(keyStr))
} else { // is Group
mapObj[key] = New(groupData{})
}
} else { // is the last key
mapObj[key] = New(nil)
}
tObj = mapObj[key]
} else { // not found and panic
panic(invalidKeyStrErr(keyStr))
}
case *arrayData:
if index, err := tObj.arrCheckIndexKey(key, keyStr); err == nil {
tObj = (*tObj.val.(*arrayData))[index]
} else {
panic(err)
}
default:
panic(invalidTypeErr(key))
}
}
return tObj, tObjParent
}
// The process to make sure the param v is one of [*groupData, *arrayData, UnknownValue].
// All other recognizable types will be transform as:
// Object and *Object get their value and trans again
// groupData and arrayData trans to the pointer to them.
// Group and Array trans to the object-safe types (groupData and arrayData) to them
func getDeepestValue(v interface{}) interface{} {
tv := v
for {
switch tv.(type) {
case Object:
tv = tv.(Object).val
case *Object:
tv = tv.(*Object).val
case groupData:
group := tv.(groupData)
return &group
case *groupData:
return tv.(*groupData)
case arrayData:
arr := tv.(arrayData)
return &arr
case *arrayData:
return tv.(*arrayData)
case map[string]interface{}:
tv = transGroupToGroupData(Group(tv.(map[string]interface{})))
case []interface{}:
tv = transArrayToArrayData(Array(tv.([]interface{})))
case Group:
tv = transGroupToGroupData(tv.(Group))
case Array:
tv = transArrayToArrayData(tv.(Array))
default:
return tv
}
}
}
func transArrayToArrayData(array Array) *arrayData {
data := New(arrayData{})
for _, v := range array {
data.ArrPush(getDeepestValue(v))
}
return data.val.(*arrayData)
}
func transGroupToGroupData(group Group) *groupData {
data := New(groupData{})
for k, v := range group {
_ = data.Set(k, getDeepestValue(v))
}
return data.val.(*groupData)
}