Files
opencloud/vendor/github.com/gookit/goutil/maputil/maputil.go
dependabot[bot] 89a7d171ee build(deps): bump github.com/gookit/config/v2 from 2.2.6 to 2.2.7
Bumps [github.com/gookit/config/v2](https://github.com/gookit/config) from 2.2.6 to 2.2.7.
- [Release notes](https://github.com/gookit/config/releases)
- [Commits](https://github.com/gookit/config/compare/v2.2.6...v2.2.7)

---
updated-dependencies:
- dependency-name: github.com/gookit/config/v2
  dependency-version: 2.2.7
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-15 14:15:33 +00:00

192 lines
3.9 KiB
Go

// Package maputil provide map data util functions. eg: convert, sub-value get, simple merge
package maputil
import (
"reflect"
"strings"
"github.com/gookit/goutil/arrutil"
)
// Key, value sep char consts
const (
ValSepStr = ","
ValSepChar = ','
KeySepStr = "."
KeySepChar = '.'
)
// SimpleMerge simple merge two data map by string key. will merge the src to dst map
func SimpleMerge(src, dst map[string]any) map[string]any {
if len(src) == 0 {
return dst
}
if len(dst) == 0 {
return src
}
for key, val := range src {
if mp, ok := val.(map[string]any); ok {
if dmp, ok := dst[key].(map[string]any); ok {
dst[key] = SimpleMerge(mp, dmp)
continue
}
}
// simple merge
dst[key] = val
}
return dst
}
// Merge1level merge multi any map[string]any data. only merge one level data.
func Merge1level(mps ...map[string]any) map[string]any {
newMp := make(map[string]any)
for _, mp := range mps {
for k, v := range mp {
newMp[k] = v
}
}
return newMp
}
// func DeepMerge(src, dst map[string]any, deep int) map[string]any { TODO
// }
// MergeSMap simple merge two string map. merge src to dst map
func MergeSMap(src, dst map[string]string, ignoreCase bool) map[string]string {
return MergeStringMap(src, dst, ignoreCase)
}
// MergeStrMap simple merge two string map. merge src to dst map
func MergeStrMap(src, dst map[string]string) map[string]string {
return MergeStringMap(src, dst, false)
}
// MergeStringMap simple merge two string map. merge src to dst map
func MergeStringMap(src, dst map[string]string, ignoreCase bool) map[string]string {
if len(src) == 0 {
return dst
}
if len(dst) == 0 {
return src
}
for k, v := range src {
if ignoreCase {
k = strings.ToLower(k)
}
dst[k] = v
}
return dst
}
// MergeMultiSMap quick merge multi string-map data.
func MergeMultiSMap(mps ...map[string]string) map[string]string {
newMp := make(map[string]string)
for _, mp := range mps {
for k, v := range mp {
newMp[k] = v
}
}
return newMp
}
// MergeL2StrMap merge multi level2 string-map data. The back map covers the front.
func MergeL2StrMap(mps ...map[string]map[string]string) map[string]map[string]string {
newMp := make(map[string]map[string]string)
for _, mp := range mps {
for k, v := range mp {
// merge level 2 value
if oldV, ok := newMp[k]; ok {
for k1, v1 := range v {
oldV[k1] = v1
}
newMp[k] = oldV
} else {
newMp[k] = v
}
}
}
return newMp
}
// FilterSMap filter empty elem for the string map.
func FilterSMap(sm map[string]string) map[string]string {
for key, val := range sm {
if val == "" {
delete(sm, key)
}
}
return sm
}
// MakeByPath build new value by key names
//
// Example:
//
// "site.info"
// ->
// map[string]any {
// site: {info: val}
// }
//
// // case 2, last key is slice:
// "site.tags[1]"
// ->
// map[string]any {
// site: {tags: [val]}
// }
func MakeByPath(path string, val any) (mp map[string]any) {
return MakeByKeys(strings.Split(path, KeySepStr), val)
}
// MakeByKeys build new value by key names
//
// Example:
//
// // case 1:
// []string{"site", "info"}
// ->
// map[string]any {
// site: {info: val}
// }
//
// // case 2, last key is slice:
// []string{"site", "tags[1]"}
// ->
// map[string]any {
// site: {tags: [val]}
// }
func MakeByKeys(keys []string, val any) (mp map[string]any) {
size := len(keys)
// if last key contains slice index, make slice wrap the val
lastKey := keys[size-1]
if newK, idx, ok := parseArrKeyIndex(lastKey); ok {
// valTyp := reflect.TypeOf(val)
sliTyp := reflect.SliceOf(reflect.TypeOf(val))
sliVal := reflect.MakeSlice(sliTyp, idx+1, idx+1)
sliVal.Index(idx).Set(reflect.ValueOf(val))
// update val and last key
val = sliVal.Interface()
keys[size-1] = newK
}
if size == 1 {
return map[string]any{keys[0]: val}
}
// multi nodes
arrutil.Reverse(keys)
for _, p := range keys {
if mp == nil {
mp = map[string]any{p: val}
} else {
mp = map[string]any{p: mp}
}
}
return
}