# Specification of generating crdt.Object with literal ref: https://pkg.go.dev/encoding/json#Marshal kor : https://hackmd.io/hTqCSWCESqaWjRorXSTgUQ # A. json.Array #### 1. Use SetNewArray method ```go= root.SetNewArray("k1") ``` #### 2. Initialize json.Array with specific type(including user defined struct) slice, array > primitive, interface{ }, Counter, Text, Tree, []map[string]interface{ }, user defined struct ``` go= // int root.SetNewArray("k1", []int{0, 1, 2}) // void interface root.SetNewArray("k2", []interface{}{0,1,2}) // Counter cnt := json.NewCounter(0, crdt.LongCnt) root.SetNewArray("counters", []json.Counter{cnt, cnt, cnt}) // User defined struct type T1 struct { msg string Msg string } root.SetNewArray("structs", []T1{{"hello", "Hello"}, {"world", "World"}}) // typed slice in typed slice arr := []int{1, 2, 3} root.SetNewArray("arrays", []([]int){arr, arr}) // typed slice in typed array arr := [3]int{1, 2, 3} root.SetNewArray("arrays", []([3]int){arr}) ``` # B. json.Object #### 1. Use SetNewObject method ```go= root.SetNewObject("obj") ``` #### 2. Initialize json.Object with Map[string]inteface{} ```go= root.SetNewObject("obj", map[string]interface{}{ // 1: object "str": "v", // 1: string "arr": []interface{}{1, "str"}, // 3: array, 1, "str" "obj": map[string]interface{}{"key3": 42.2}, // 2: object, 42.2 "cnt": json.NewCounter(0, crdt.LongCnt), // 1: counter "txt": json.NewText(), // 1: text "tree": json.NewTree(&json.TreeNode{ // 1: tree Type: "doc", Children: []json.TreeNode{{ Type: "p", Children: []json.TreeNode{{Type: "text", Value: "ab"}}, }}, }), }) ``` #### 3. Initialize json.Object with user defined struct ```go= root.SetNewObject("obj", struct{ M string }{M: text}) ``` - only exposed field in struct can be converted json.Object field. > The struct and map forms can also receive addresses. ## B.1. Struct field tag - You can use struct tags when you initializing json.Object, json.Array with user defined struct - Tag follows the format below. Based on comma, the front is name and the back is option. ```format `yorkie:(user defined name || - ),options` ``` > blank is allowed to name options doesn't allow blank. (It will be trimed) ```go= type Temp struct{ // user defined name, - K1 string `yorkie:"-"` // case1 K2 string `yorkie:"k2"` // case2 // options K3 string `yorkie:",omitEmpty"` // case3 } ``` ### 1. - always omit - `-` tag field omitted when generating crdt.Object - In the case of 'yorkie:"-,omitEmpty"', the '-' will be treated user defined name. ```go= struct { M1 string `yorkie:"-"` M2 string }{M1: str, M2: str} ``` ```shell= {"obj":{"M2":"foo"}} ``` ### 2. field name mapping - You can define the field's key name without using the name of an existing field. - `yorkie:"new_name,options"` > unexposed field will not convert to json.elements ```go= struct { M1 string `yorkie:"m1"` M2 string `yorkie:"m2"` {M1: str, M2: str} ``` ```shell= {"obj":{"m1":"foo","m2":"foo"}} ``` ### 3. omitEmpty - The "omitEmpty" option specifies that the field should be omitted if the field has an empty value. - The empty array is treated as empty. ```go= // zero value struct { M1 string `yorkie:",omitEmpty"` M2 string `yorkie:",omitEmpty"` }{M1: str} ``` ```shell= {"obj":{"M1":"foo"}} ``` ```go= // empty array struct { M1 []int `yorkie:",omitEmpty"` }{M1: []int{}} ``` ```shell= {"obj":{}} ``` ## B.2. Nil, Zerovalue, Empty --- ```go {"zeroValue int struct", struct{ M int }{}, `{"obj":{"M":0}}`}, {"zeroValue string struct", struct{ M string }{}, `{"obj":{"M":""}}`}, ``` ```go {"zeroValue bytes struct", struct{ M []byte }{M: nil}, `{"obj":{"M":""}}`}, {"empty bytes struct", struct{ M []byte }{M: []byte{}}, `{"obj":{"M":""}}`}, {"zeroValue array struct", struct{ M []int }{M: nil}, `{"obj":{"M":[]}}`}, {"empty array struct", struct{ M []int }{M: []int{}}, `{"obj":{"M":[]}}`}, ``` - handle empty array and nil in the same way - The following table summarizes how the default values are handled when each field is declared in the structure | Type | zero value(not initialized) | Empty value(initialized but empty) | Initialize method | | --------------- | --------------- | --------------- | --------------- | | int | 0 | | String | "" | "" |"" | []byte | "" | "" | []byte | json.Array | [ ] | [ ] | []int{} | json.Counter | 0 | | NewCounter| | json.Tree | {"type":"root","children":[]} | {"type":"root","children":[]} | NewTree | json.Text | [ ] | [ ] | NewText | json.Object | { } | | | pointer | null | | nil > Blank means there is no way ## B.3. Pointer - The pointer in array, slice, struct interpreted *pointer(the value the pointer points to) when generating json.Object. - but this conversion does not support for json.Text, Counter, Tree, Object. (& operater will not work for them) ```go= // available {"struct pointers", []*T1{&t1, &t1}, `[{"M":"a"},{"M":"a"}]`, 5}, {"array pointers", []*[3]int{&arr, &arr}, `[[1,2,3],[1,2,3]]`, 9}, // does not support {"Counter Pointer", []*json.Counter{&json.NewCounter(1, crdt.LongCnt)}, `[1]`} ``` - If the pointer has null, it converted to null of json.primitive. ```go= {"nested &struct with nil", struct{ M *T1 }{M: nil}, `{"obj":{"M":null}}`, 2}, ``` - When generating json.Object, you can use pointer of map[string]interface{} or struct. ```go= {"null &map", &map[string]interface{}{"M": nil}, `{"obj":{"M":null}}`, 2}, ``` ## B.4. Named type - you can also use your named type. ```go= type MyInt int type S struct{ MyInt } {"named type", struct{ M MyInt }{M: 5}, `{"obj":{"M":5}}`, 2}, {"named type", MyStruct{5}, `{"obj":{"M":5}}`, 2}, ``` ## B.5. Anonymous field - If the anonymous field type starts with lowercase letters, it will be omitted. ```go= type MyInt int type S1 struct{ MyInt } type S2 struct{ int } {"anonymous field", S1{5}, `{"obj":{"MyInt":5}}`, 2} {"lowercase", S2{5}, `{"obj":{}}`} ``` ## B.6. Embedded struct - It also support Embedded struct. ```go= T4 struct { T1 t1 M string } embedded := T4{ T1: T1{M: str}, t1: t1{M: str}, // It will be omitted M: "foo", } {"embedded struct", embedded, `{"obj":{"M":"foo","T1":{"M":"foo"}}}`, 4}, {"&embedded struct", &embedded, `{"obj":{"M":"foo","T1":{"M":"foo"}}}`, 4}, ``` ## B.7. Unsupported Values --- - If these values are included in the structure array, panic will occur. ```go= pointerCycle, pointerCycleIndirect, mapCycle, sliceCycle, recursiveSliceCycle, ```