Skip to content

Commit

Permalink
✨ feat: add NestedObject
Browse files Browse the repository at this point in the history
🎨 improve: improve `Templatee`
  • Loading branch information
jingyuexing committed Jan 2, 2024
1 parent f87bb7b commit 2b13cae
Show file tree
Hide file tree
Showing 2 changed files with 295 additions and 159 deletions.
126 changes: 105 additions & 21 deletions utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package utils

import (
"encoding/json"
"errors"
"fmt"
"log"
"os"
Expand Down Expand Up @@ -29,10 +30,10 @@ func ToString(val any) string {
}

func Template(source string, data map[string]any, placeholder string) string {
tempSyntax := "{}"
if placeholder != ""{
tempSyntax = placeholder
}
tempSyntax := "{}"
if placeholder != "" {
tempSyntax = placeholder
}
key := ""
sourceCopy := &source
for k, val := range data {
Expand All @@ -41,29 +42,29 @@ func Template(source string, data map[string]any, placeholder string) string {
switch tempSyntax {
case "{}":
key = strings.Join([]string{"{", k, "}"}, "")
case "[]":
key = strings.Join([]string{"[", k, "]"}, "")
case "()":
key = strings.Join([]string{"(", k, ")"}, "")
case "[]":
key = strings.Join([]string{"[", k, "]"}, "")
case "()":
key = strings.Join([]string{"(", k, ")"}, "")
case ":":
key = strings.Join([]string{tempSyntax, k}, "")
case "@":
key = strings.Join([]string{tempSyntax, k}, "")
case "#":
key = strings.Join([]string{tempSyntax, k}, "")
case "@":
key = strings.Join([]string{tempSyntax, k}, "")
case "#":
key = strings.Join([]string{tempSyntax, k}, "")
case "$":
key = strings.Join([]string{tempSyntax, k}, "")
case "?":
key = tempSyntax
default:
if (len(tempSyntax) & 1) == 1 {
key = strings.Join([]string{tempSyntax, k}, "")
break
}
if (len(tempSyntax) & 1) == 0 {
halfLength := len(tempSyntax) / 2
key = strings.Join([]string{tempSyntax[:halfLength],k,tempSyntax[halfLength:]},"")
}
default:
if (len(tempSyntax) & 1) == 1 {
key = strings.Join([]string{tempSyntax, k}, "")
break
}
if (len(tempSyntax) & 1) == 0 {
halfLength := len(tempSyntax) / 2
key = strings.Join([]string{tempSyntax[:halfLength], k, tempSyntax[halfLength:]}, "")
}

}
*sourceCopy = strings.Replace(*sourceCopy, key, valStr, 1)
Expand Down Expand Up @@ -100,6 +101,31 @@ func pathParse(target string) []string {
return obj
}

func CreateNestedObject(keys string, value interface{}, delimiter string) map[string]interface{} {
if delimiter == "" {
delimiter = "."
}
keyList := strings.Split(keys, delimiter)
result := make(map[string]interface{})
current := reflect.ValueOf(result)

for i, key := range keyList {
if i == len(keyList)-1 {
current.SetMapIndex(reflect.ValueOf(key), reflect.ValueOf(value).Elem())
} else {
if current.MapIndex(reflect.ValueOf(key)).IsValid() {
current = current.MapIndex(reflect.ValueOf(key))
} else {
newMap := make(map[string]interface{})
current.SetMapIndex(reflect.ValueOf(key), reflect.ValueOf(newMap))
current = reflect.ValueOf(newMap)
}
}
}

return result
}

func AccessNested(data any, path string, delimiter string) any {
keys := strings.Split(path, delimiter)
value := reflect.ValueOf(data)
Expand Down Expand Up @@ -139,6 +165,64 @@ func AccessNested(data any, path string, delimiter string) any {
return nil
}

func NestedObject[T any](target T, path string, cb func(target reflect.Value, key string)) error {
keys := strings.Split(path, ".")
v := reflect.ValueOf(target)

if v.Kind() == reflect.Ptr {
v = v.Elem()
}

for _, key := range keys {
switch v.Kind() {
case reflect.Map:
mapValue := v.MapIndex(reflect.ValueOf(key))

if mapValue.Kind() == reflect.Interface ||
mapValue.Kind() == reflect.Pointer {
mapValue = mapValue.Elem()
}
if mapValue.IsValid() {
cb(mapValue, key)
if mapValue.Kind() == reflect.Map || mapValue.Kind() == reflect.Pointer {
v = mapValue
}
} else {
return errors.New("unreachable access path")
}
case reflect.Struct:
field := v.FieldByName(key)
if field.Kind() == reflect.Pointer ||
field.Kind() == reflect.Interface ||
field.Kind() == reflect.Map {
field = field.Elem()
}
if field.IsValid() {
v = field
cb(v, key)
} else {
return errors.New("unreachable access path")
}
case reflect.Interface:
if v.Elem().Kind() == reflect.Map || v.Elem().Kind() == reflect.Pointer {
v = v.Elem()
} else {
return errors.New("unreachable access path")
}
case reflect.Pointer:
if v.Elem().IsValid() {
v = v.Elem()
} else {
return errors.New("unreachable access path")
}
default:
return errors.New("invalid target type")
}
}

return nil
}

func GetPathValue(raw string, realPath string) map[string]string {
rawObj := pathParse(raw)
realObj := pathParse(realPath)
Expand Down
Loading

0 comments on commit 2b13cae

Please sign in to comment.