Files
my-rook-config/pkg/operator/ceph/object/json_helpers.go
T
Artem Torubarov f6a25b0c4b rgw: support v19 zone pools
add rgw shared pools rados ns to topics_pool, account_pool, and group_pool

Signed-off-by: Artem Torubarov <artem.torubarov@clyso.com>
2024-10-22 11:23:42 +02:00

125 lines
3.5 KiB
Go

package object
import (
"encoding/json"
"fmt"
"strings"
)
// getObjProperty - helper function to manipulate JSON Objects.
// returns nested property of json object.
// Example:
//
// obj = {"a":{"b":"foo"}}
// // will return "foo"
// getObjProperty(obj,"a","b")
func getObjProperty[T string | map[string]interface{} | []interface{}](obj map[string]interface{}, path ...string) (T, error) {
var res T
if len(path) == 0 {
return res, fmt.Errorf("json property path is empty")
}
for i, p := range path {
val, ok := obj[p]
if !ok {
return res, fmt.Errorf("json property %q not found", strings.Join(path[:i+1], "."))
}
last := i == len(path)-1
if last {
// last path segment: get result
res, ok = val.(T)
if !ok {
return res, fmt.Errorf("json property %q is not a %T, got %+v", strings.Join(path, "."), res, val)
}
return res, nil
}
// walk to the next obj in the path
obj, ok = val.(map[string]interface{})
if !ok {
return res, fmt.Errorf("json property %q is not an object, got %+v", strings.Join(path[:i+1], "."), val)
}
}
// not reachable
return res, fmt.Errorf("json property %q not found", strings.Join(path, "."))
}
// updateObjProperty - helper function to manipulate JSON Objects.
// sets new value to json object nested field only if it is already exists in json and returns previous value.
func updateObjProperty[T string | []string | map[string]interface{} | []interface{}](obj map[string]interface{}, val T, path ...string) (T, error) {
var prev T
if len(path) == 0 {
return prev, fmt.Errorf("json property path is empty")
}
for i, p := range path {
last := i == len(path)-1
if last {
// last path segment: set result and return prev value
prevVal, ok := obj[p]
if !ok {
// not exists:
return prev, fmt.Errorf("json property %q not exists", strings.Join(path, "."))
}
if ok {
prevRes, ok := prevVal.(T)
if ok {
prev = prevRes
} else {
// in go json all arrays are []interface{}, extra conversion for typed arrays (e.g. []string) needed:
p := new(T)
if castJson(prevVal, p) {
prev = *p
}
}
}
obj[p] = val
return prev, nil
}
// walk to the next obj in the path
next, ok := obj[p]
if !ok {
return prev, fmt.Errorf("json property %q is not found", strings.Join(path[:i+1], "."))
}
obj, ok = next.(map[string]interface{})
if !ok {
return prev, fmt.Errorf("json property %q is not an object, got %+v", strings.Join(path[:i+1], "."), next)
}
}
// not reachable
return prev, fmt.Errorf("json property %q not found", strings.Join(path, "."))
}
// castJson - helper function to manipulate JSON Objects.
// Tries to cast any type to any type by converting to JSON and back.
// Returns true on success.
func castJson(in, out interface{}) bool {
bytes, err := json.Marshal(in)
if err != nil {
return false
}
err = json.Unmarshal(bytes, out)
return err == nil
}
// toObj - helper function to manipulate JSON Objects.
// Casts any go struct to map representing JSON object.
func toObj(val interface{}) (map[string]interface{}, error) {
bytes, err := json.Marshal(val)
if err != nil {
return nil, err
}
obj := map[string]interface{}{}
return obj, json.Unmarshal(bytes, &obj)
}
// deepCopyJson - helper function to manipulate JSON Objects.
// Makes deep copy of json object by converting to JSON and back.
func deepCopyJson(in map[string]interface{}) (map[string]interface{}, error) {
bytes, err := json.Marshal(in)
if err != nil {
return nil, err
}
res := map[string]interface{}{}
err = json.Unmarshal(bytes, &res)
return res, err
}