github.com/yaoapp/kun@v0.9.0/maps/strany.go (about)

     1  package maps
     2  
     3  import (
     4  	"fmt"
     5  	"reflect"
     6  	"sort"
     7  	"strings"
     8  
     9  	"github.com/yaoapp/kun/interfaces"
    10  	"github.com/yaoapp/kun/share"
    11  )
    12  
    13  // Map alias of MapStrAny
    14  type Map = MapStrAny
    15  
    16  // Str alias of MapStrAny
    17  type Str = MapStrAny
    18  
    19  // StrAny alias of MapStrAny
    20  type StrAny = MapStrAny
    21  
    22  // MapStr alias of MapStrAny
    23  type MapStr = MapStrAny
    24  
    25  // MapStrAny type of map[string}]inteface{}
    26  type MapStrAny map[string]interface{}
    27  
    28  // Make create a new instance (the default type of map)
    29  func Make() MapStrAny {
    30  	return MakeMapStrAny()
    31  }
    32  
    33  // MakeMap create a new instance
    34  func MakeMap() MapStrAny {
    35  	return MakeMapStrAny()
    36  }
    37  
    38  // MakeMapStr create a new instance
    39  func MakeMapStr() MapStrAny {
    40  	return MakeMapStrAny()
    41  }
    42  
    43  // MakeStr create a new instance
    44  func MakeStr() MapStrAny {
    45  	return MakeMapStrAny()
    46  }
    47  
    48  // MakeStrAny create a new instance
    49  func MakeStrAny() MapStrAny {
    50  	return MakeMapStrAny()
    51  }
    52  
    53  // MakeMapStrAny create a new instance
    54  func MakeMapStrAny() MapStrAny {
    55  	return MapStrAny{}
    56  }
    57  
    58  // Of create a new instance (the default type of map)
    59  func Of(values map[string]interface{}) MapStrAny {
    60  	return MapStrAnyOf(values)
    61  }
    62  
    63  // MapOf create a new instance
    64  func MapOf(values map[string]interface{}) MapStrAny {
    65  	return MapStrAnyOf(values)
    66  }
    67  
    68  // MapStrOf create a new instance
    69  func MapStrOf(values map[string]interface{}) MapStrAny {
    70  	return MapStrAnyOf(values)
    71  }
    72  
    73  // StrOf create a new instance
    74  func StrOf(values map[string]interface{}) MapStrAny {
    75  	return MapStrAnyOf(values)
    76  }
    77  
    78  // StrAnyOf create a new instance
    79  func StrAnyOf(values map[string]interface{}) MapStrAny {
    80  	return MapStrAnyOf(values)
    81  }
    82  
    83  // MapStrAnyOf create a new instance (the default type of map)
    84  func MapStrAnyOf(values map[string]interface{}) MapStrAny {
    85  	m := MakeMapStrAny()
    86  	for key, value := range values {
    87  		m.Set(key, value)
    88  	}
    89  	return m
    90  }
    91  
    92  // Flatten The Flatten method is alias of Dot, to flatten a multi-dimensional map[string]inteface{} into a single level  map[string]inteface{}
    93  // that uses "dot" notation to indicate depth
    94  func (m MapStrAny) Flatten() MapStrAny {
    95  	return m.Dot()
    96  }
    97  
    98  // UnFlatten The UnFlatten method unflatten a single level map[string]inteface{} into  multi-dimensional  map[string]inteface{}
    99  // that uses "dot" notation to indicate depth
   100  func (m MapStrAny) UnFlatten() MapStrAny {
   101  	return m.UnDot()
   102  }
   103  
   104  // Dot The Dot method flattens a multi-dimensional map[string]inteface{} into a single level  map[string]inteface{}
   105  // that uses "dot" notation to indicate depth
   106  func (m MapStrAny) Dot() MapStrAny {
   107  	res := MakeMapStrAny()
   108  	m.Range(func(key string, value interface{}) bool {
   109  		res.dotSet(key, value)
   110  		return true
   111  	})
   112  	return res
   113  }
   114  
   115  // dotSet set the value for a key uses "dot" notation
   116  func (m MapStrAny) dotSet(key string, value interface{}) {
   117  
   118  	reflectValue := reflect.ValueOf(value)
   119  	reflectValue = reflect.Indirect(reflectValue)
   120  	valueKind := reflectValue.Kind()
   121  
   122  	if valueKind == reflect.Slice || valueKind == reflect.Array { // Slice || Array
   123  		for i := 0; i < reflectValue.Len(); i++ {
   124  			m.dotSet(fmt.Sprintf("%s.%d", key, i), reflectValue.Index(i).Interface())
   125  		}
   126  
   127  	} else if valueKind == reflect.Map { // Map
   128  		for _, sub := range reflectValue.MapKeys() {
   129  			m.dotSet(fmt.Sprintf("%s.%v", key, sub), reflectValue.MapIndex(sub).Interface())
   130  		}
   131  
   132  	} else if valueKind == reflect.Struct { // Struct
   133  
   134  		if toMap := reflect.ValueOf(value).MethodByName("ToMap"); toMap.IsValid() {
   135  			args := []reflect.Value{}
   136  			values := toMap.Call(args)
   137  			if len(values) == 1 {
   138  				v, ok := values[0].Interface().(map[string]interface{})
   139  				if ok {
   140  					m.dotSet(key, v)
   141  				}
   142  			}
   143  			return
   144  		}
   145  
   146  		// auto struct
   147  		typeOfS := reflectValue.Type()
   148  		for i := 0; i < reflectValue.NumField(); i++ {
   149  			sub := share.GetTagName(typeOfS.Field(i), "json")
   150  			if reflectValue.Field(i).CanInterface() {
   151  				v := reflectValue.Field(i).Interface()
   152  				m.dotSet(fmt.Sprintf("%s.%v", key, sub), v)
   153  			}
   154  		}
   155  	}
   156  
   157  	m.Set(key, value)
   158  }
   159  
   160  // UnDot The UnDot method unflatten a single level map[string]inteface{} into  multi-dimensional  map[string]inteface{}
   161  // that uses "dot" notation to indicate depth
   162  func (m MapStrAny) UnDot() MapStrAny {
   163  	res := MakeMapStrAny()
   164  	m.Range(func(key string, value interface{}) bool {
   165  		res.SetUnDot(key, value)
   166  		return true
   167  	})
   168  	return res
   169  }
   170  
   171  // SetUnDot set the value for a key uses "dot" notation
   172  func (m MapStrAny) SetUnDot(key string, value interface{}) {
   173  	if !strings.Contains(key, ".") {
   174  		m.Set(key, value)
   175  		return
   176  	}
   177  
   178  	keys := strings.Split(key, ".")
   179  	tail := strings.Join(keys[1:], ".")
   180  	v, ok := m.Get(keys[0]).(MapStrAny)
   181  	if !ok {
   182  		v = MapStrAny{}
   183  	}
   184  	v[tail] = value
   185  
   186  	v.Range(func(key string, value interface{}) bool {
   187  		v.SetUnDot(key, value)
   188  		return true
   189  	})
   190  
   191  	m.Set(keys[0], v)
   192  	m.Del(key)
   193  }
   194  
   195  // Set set the value for a key
   196  func (m MapStrAny) Set(key string, value interface{}) {
   197  	m[key] = value
   198  }
   199  
   200  // Get returns the value stored in the map for a key, or nil if no value is present.
   201  func (m MapStrAny) Get(key string) interface{} {
   202  	return m[key]
   203  }
   204  
   205  // Has return true whether value was found in the map.
   206  func (m MapStrAny) Has(key string) bool {
   207  	_, has := m[key]
   208  	return has
   209  }
   210  
   211  // Del deletes the value for a key.
   212  func (m MapStrAny) Del(key string) {
   213  	delete(m, key)
   214  }
   215  
   216  // GetOrSet returns the existing value for the key if present. Otherwise, it stores and returns the given value.
   217  func (m MapStrAny) GetOrSet(key string, value interface{}) interface{} {
   218  	if res, has := m[key]; has {
   219  		return res
   220  	}
   221  	m.Set(key, value)
   222  	return value
   223  }
   224  
   225  // GetAndDel deletes the value for a key, returning the previous value if any. The loaded result reports whether the key was present.
   226  func (m MapStrAny) GetAndDel(key string) interface{} {
   227  	if res, has := m[key]; has {
   228  		m.Del(key)
   229  		return res
   230  	}
   231  	return nil
   232  }
   233  
   234  // Len returns the length of the map.
   235  func (m MapStrAny) Len() int {
   236  	return len(m)
   237  }
   238  
   239  // Range calls f sequentially for each key and value present in the map. If f returns false, range stops the iteration.
   240  func (m MapStrAny) Range(cb func(key string, value interface{}) bool) {
   241  	for key, value := range m {
   242  		if !cb(key, value) {
   243  			break
   244  		}
   245  	}
   246  }
   247  
   248  // Keys returns all keys of the map as a slice.
   249  func (m MapStrAny) Keys() []string {
   250  	keys := []string{}
   251  	m.Range(func(key string, value interface{}) bool {
   252  		keys = append(keys, key)
   253  		return true
   254  	})
   255  	sort.Strings(keys)
   256  	return keys
   257  }
   258  
   259  // Values returns all values of the map as a slice.
   260  func (m MapStrAny) Values() []interface{} {
   261  	values := []interface{}{}
   262  	keys := m.Keys()
   263  	for _, key := range keys {
   264  		values = append(values, m.Get(key))
   265  	}
   266  	return values
   267  }
   268  
   269  // IsEmpty checks whether the map is empty. It returns true if map is empty, or else false.
   270  func (m MapStrAny) IsEmpty() bool {
   271  	return len(m) == 0
   272  }
   273  
   274  // Merge merges hash maps
   275  func (m MapStrAny) Merge(maps ...interfaces.MapStrAny) {
   276  	for _, new := range maps {
   277  		new.Range(func(key string, value interface{}) bool {
   278  			m.Set(key, value)
   279  			return true
   280  		})
   281  	}
   282  }