1 // Copyright 2014 Benny Scetbun. All rights reserved.
2 // Use of this source code is governed by a MIT-style
3 // license that can be found in the LICENSE file.
5 // Package Jsongo is a simple library to help you build Json without static struct
7 // Source code and project home:
8 // https://github.com/benny-deluxe/jsongo
20 //ErrorKeyAlreadyExist error if a key already exist in current JSONNode
21 var ErrorKeyAlreadyExist = errors.New("jsongo key already exist")
23 //ErrorMultipleType error if a JSONNode already got a different type of value
24 var ErrorMultipleType = errors.New("jsongo this node is already set to a different jsonNodeType")
26 //ErrorArrayNegativeValue error if you ask for a negative index in an array
27 var ErrorArrayNegativeValue = errors.New("jsongo negative index for array")
29 //ErrorArrayNegativeValue error if you ask for a negative index in an array
30 var ErrorAtUnsupportedType = errors.New("jsongo Unsupported Type as At argument")
32 //ErrorRetrieveUserValue error if you ask the value of a node that is not a value node
33 var ErrorRetrieveUserValue = errors.New("jsongo Cannot retrieve node's value which is not of type value")
35 //ErrorTypeUnmarshaling error if you try to unmarshal something in the wrong type
36 var ErrorTypeUnmarshaling = errors.New("jsongo Wrong type when Unmarshaling")
38 //ErrorUnknowType error if you try to use an unknow JSONNodeType
39 var ErrorUnknowType = errors.New("jsongo Unknow JSONNodeType")
41 //ErrorValNotPointer error if you try to use Val without a valid pointer
42 var ErrorValNotPointer = errors.New("jsongo: Val: arguments must be a pointer and not nil")
44 //ErrorGetKeys error if you try to get the keys from a JSONNode that isnt a TypeMap or a TypeArray
45 var ErrorGetKeys = errors.New("jsongo: GetKeys: JSONNode is not a TypeMap or TypeArray")
47 //ErrorDeleteKey error if you try to call DelKey on a JSONNode that isnt a TypeMap
48 var ErrorDeleteKey = errors.New("jsongo: DelKey: This JSONNode is not a TypeMap")
50 //ErrorCopyType error if you try to call Copy on a JSONNode that isnt a TypeUndefined
51 var ErrorCopyType = errors.New("jsongo: Copy: This JSONNode is not a TypeUndefined")
53 //JSONNode Datastructure to build and maintain Nodes
54 type JSONNode struct {
55 m map[string]*JSONNode
58 vChanged bool //True if we changed the type of the value
59 t JSONNodeType //Type of that JSONNode 0: Not defined, 1: map, 2: array, 3: value
60 dontExpand bool //dont expand while Unmarshal
63 //JSONNodeType is used to set, check and get the inner type of a JSONNode
64 type JSONNodeType uint
67 //TypeUndefined is set by default for empty JSONNode
68 TypeUndefined JSONNodeType = iota
69 //TypeMap is set when a JSONNode is a Map
71 //TypeArray is set when a JSONNode is an Array
73 //TypeValue is set when a JSONNode is a Value Node
75 //typeError help us detect errors
79 //At helps you move through your node by building them on the fly
81 //val can be string or int only
83 //strings are keys for TypeMap
85 //ints are index in TypeArray (it will make array grow on the fly, so you should start to populate with the biggest index first)*
86 func (that *JSONNode) At(val ...interface{}) *JSONNode {
90 switch vv := val[0].(type) {
92 return that.atMap(vv, val[1:]...)
94 return that.atArray(vv, val[1:]...)
96 panic(ErrorAtUnsupportedType)
99 //atMap return the JSONNode in current map
100 func (that *JSONNode) atMap(key string, val ...interface{}) *JSONNode {
101 if that.t != TypeUndefined && that.t != TypeMap {
102 panic(ErrorMultipleType)
105 that.m = make(map[string]*JSONNode)
108 if next, ok := that.m[key]; ok {
109 return next.At(val...)
111 that.m[key] = new(JSONNode)
112 return that.m[key].At(val...)
115 //atArray return the JSONNode in current TypeArray (and make it grow if necessary)
116 func (that *JSONNode) atArray(key int, val ...interface{}) *JSONNode {
117 if that.t == TypeUndefined {
119 } else if that.t != TypeArray {
120 panic(ErrorMultipleType)
123 panic(ErrorArrayNegativeValue)
125 if key >= len(that.a) {
126 newa := make([]JSONNode, key+1)
127 for i := 0; i < len(that.a); i++ {
132 return that.a[key].At(val...)
135 //Map Turn this JSONNode to a TypeMap and/or Create a new element for key if necessary and return it
136 func (that *JSONNode) Map(key string) *JSONNode {
137 if that.t != TypeUndefined && that.t != TypeMap {
138 panic(ErrorMultipleType)
141 that.m = make(map[string]*JSONNode)
144 if _, ok := that.m[key]; ok {
147 that.m[key] = &JSONNode{}
151 //Array Turn this JSONNode to a TypeArray and/or set the array size (reducing size will make you loose data)
152 func (that *JSONNode) Array(size int) *[]JSONNode {
153 if that.t == TypeUndefined {
155 } else if that.t != TypeArray {
156 panic(ErrorMultipleType)
159 panic(ErrorArrayNegativeValue)
162 if size < len(that.a) {
167 newa := make([]JSONNode, size)
168 for i := 0; i < min; i++ {
175 //Val Turn this JSONNode to Value type and/or set that value to val
176 func (that *JSONNode) Val(val interface{}) {
177 if that.t == TypeUndefined {
179 } else if that.t != TypeValue {
180 panic(ErrorMultipleType)
182 rt := reflect.TypeOf(val)
183 var finalval interface{}
187 } else if rt.Kind() != reflect.Ptr {
188 rv := reflect.ValueOf(val)
189 var tmp reflect.Value
193 tmp = reflect.New(rt)
196 finalval = tmp.Interface()
204 //Get Return value of a TypeValue as interface{}
205 func (that *JSONNode) Get() interface{} {
206 if that.t != TypeValue {
207 panic(ErrorRetrieveUserValue)
210 rv := reflect.ValueOf(that.v)
211 return rv.Elem().Interface()
216 //GetKeys Return a slice interface that represent the keys to use with the At fonction (Works only on TypeMap and TypeArray)
217 func (that *JSONNode) GetKeys() []interface{} {
218 var ret []interface{}
222 ret = make([]interface{}, nb)
223 for key := range that.m {
229 ret = make([]interface{}, nb)
240 //Len Return the length of the current Node
242 // if TypeUndefined return 0
244 // if TypeValue return 1
246 // if TypeArray return the size of the array
248 // if TypeMap return the size of the map
249 func (that *JSONNode) Len() int {
262 //SetType Is use to set the Type of a node and return the current Node you are working on
263 func (that *JSONNode) SetType(t JSONNodeType) *JSONNode {
264 if that.t != TypeUndefined && that.t != t {
265 panic(ErrorMultipleType)
268 panic(ErrorUnknowType)
273 that.m = make(map[string]*JSONNode, 0)
275 that.a = make([]JSONNode, 0)
282 //GetType Is use to Get the Type of a node
283 func (that *JSONNode) GetType() JSONNodeType {
287 //Copy Will set this node like the one in argument. this node must be of type TypeUndefined
289 //if deepCopy is true we will copy all the children recursively else we will share the children
291 //return the current JSONNode
292 func (that *JSONNode) Copy(other *JSONNode, deepCopy bool) *JSONNode {
293 if that.t != TypeUndefined {
297 if other.t == TypeValue {
299 } else if other.t == TypeArray {
303 that.Array(len(other.a))
304 for i := range other.a {
305 that.At(i).Copy(other.At(i), deepCopy)
308 } else if other.t == TypeMap {
309 that.SetType(other.t)
311 for val := range other.m {
312 that.m[val] = other.m[val]
315 for val := range other.m {
316 that.Map(val).Copy(other.At(val), deepCopy)
324 //Unset Will unset everything in the JSONnode. All the children data will be lost
325 func (that *JSONNode) Unset() {
329 //DelKey will remove a key in the map.
331 //return the current JSONNode.
332 func (that *JSONNode) DelKey(key string) *JSONNode {
333 if that.t != TypeMap {
334 panic(ErrorDeleteKey)
340 //UnmarshalDontExpand set or not if Unmarshall will generate anything in that JSONNode and its children
342 //val: will change the expanding rules for this node
344 //- The type wont be change for any type
348 //- New keys wont be added to Map
350 //- Values set to nil "*.Val(nil)*" will be turn into the type decide by Json
352 //- It will respect any current mapping and will return errors if needed
354 //recurse: if true, it will set all the children of that JSONNode with val
355 func (that *JSONNode) UnmarshalDontExpand(val bool, recurse bool) *JSONNode {
356 that.dontExpand = val
360 for k := range that.m {
361 that.m[k].UnmarshalDontExpand(val, recurse)
364 for k := range that.a {
365 that.a[k].UnmarshalDontExpand(val, recurse)
372 //MarshalJSON Make JSONNode a Marshaler Interface compatible
373 func (that *JSONNode) MarshalJSON() ([]byte, error) {
378 ret, err = json.Marshal(that.m)
380 ret, err = json.Marshal(that.a)
382 ret, err = json.Marshal(that.v)
384 ret, err = json.Marshal(nil)
392 func (that *JSONNode) unmarshalMap(data []byte) error {
393 tmp := make(map[string]json.RawMessage)
394 err := json.Unmarshal(data, &tmp)
399 if _, ok := that.m[k]; ok {
400 err := json.Unmarshal(tmp[k], that.m[k])
404 } else if !that.dontExpand {
405 err := json.Unmarshal(tmp[k], that.Map(k))
414 func (that *JSONNode) unmarshalArray(data []byte) error {
415 var tmp []json.RawMessage
416 err := json.Unmarshal(data, &tmp)
420 for i := len(tmp) - 1; i >= 0; i-- {
421 if !that.dontExpand || i < len(that.a) {
422 err := json.Unmarshal(tmp[i], that.At(i))
431 func (that *JSONNode) unmarshalValue(data []byte) error {
433 return json.Unmarshal(data, that.v)
436 err := json.Unmarshal(data, &tmp)
444 //UnmarshalJSON Make JSONNode a Unmarshaler Interface compatible
445 func (that *JSONNode) UnmarshalJSON(data []byte) error {
449 if that.dontExpand && that.t == TypeUndefined {
452 if that.t == TypeValue {
453 return that.unmarshalValue(data)
456 if that.t != TypeMap && that.t != TypeUndefined {
457 return ErrorTypeUnmarshaling
459 return that.unmarshalMap(data)
462 if that.t != TypeArray && that.t != TypeUndefined {
463 return ErrorTypeUnmarshaling
465 return that.unmarshalArray(data)
468 if that.t == TypeUndefined {
469 return that.unmarshalValue(data)
471 return ErrorTypeUnmarshaling