package mapx import ( "encoding/json" "fmt" "net/url" "reflect" "sort" "strconv" "strings" "time" ) const dot = "." type Mapx map[string]interface{} func (m *Mapx) IsNil(key string) bool { return m.Get(key) == nil } func (m *Mapx) GetString(key string) string { return fmt.Sprintf("%v", m.Get(key)) } func (m *Mapx) GetTime(key string) time.Time { t, _ := time.ParseInLocation(time.RFC3339, m.GetString(key), time.Local) return t } func (m *Mapx) GetInt(key string) int64 { i, _ := strconv.ParseInt(m.GetString(key), 10, 64) return i } func (m *Mapx) GetFloat(key string) float64 { f, _ := strconv.ParseFloat(fmt.Sprintf("%v", m.Get(key)), 64) return f } func (m *Mapx) GetBool(key string) bool { b, _ := strconv.ParseBool(fmt.Sprintf("%v", m.Get(key))) return b } func (m *Mapx) GetMapx(key string) *Mapx { v, _ := m.Get(key).(map[string]interface{}) return (*Mapx)(&v) } func (m *Mapx) GetSlice(key string, fn func(item *Mapx, index int) bool) { value := reflect.ValueOf(m.Get(key)) if value.Kind() != reflect.Slice { return } for i := 0; i < value.Len(); i++ { item := value.Index(i) if item.Kind() != reflect.Invalid { v, _ := item.Interface().(map[string]interface{}) if !fn((*Mapx)(&v), i) { break } } } } func (m *Mapx) Set(key string, val any) *Mapx { (*m)[key] = val return m } func (m *Mapx) Get(key string) any { if m == nil { return nil } var v any = map[string]interface{}(*m) keys := strings.Split(key, dot) for i := 0; i < len(keys); i++ { if v == nil { return nil } k := keys[i] switch kind := reflect.TypeOf(v).Kind(); kind { case reflect.Map: _v := reflect.ValueOf(v).MapIndex(reflect.ValueOf(k)) if _v.Kind() != reflect.Invalid { v = _v.Interface() } else { v = nil } case reflect.Slice: if len(k) > 2 && k[0] == '[' && k[len(k)-1] == ']' { idx, err := strconv.Atoi(k[1 : len(k)-1]) if err != nil { return nil } _v := reflect.ValueOf(v).Index(idx) if _v.Kind() != reflect.Invalid { v = _v.Interface() } else { v = nil } } case reflect.Struct: _v := reflect.ValueOf(v).FieldByName(k) if _v.Kind() != reflect.Invalid { v = _v.Interface() } else { v = nil } case reflect.Ptr: v = reflect.ValueOf(v).Elem().Interface() i-- case reflect.Invalid: return nil default: return nil } } return v } func (m *Mapx) Remove(key string) { delete(*m, key) } func (m *Mapx) Json() string { b, _ := json.Marshal(&m) return string(b) } func UnmarshalJSON(data []byte) (m *Mapx) { _ = json.Unmarshal(data, &m) return } // EncodeAliPaySignParams ("bar=baz&foo=quux") sorted by key. func (m *Mapx) EncodeAliPaySignParams() string { if m == nil { return "" } var ( buf strings.Builder keyList []string ) for k := range *m { keyList = append(keyList, k) } sort.Strings(keyList) for _, k := range keyList { if v := m.GetString(k); v != "" { buf.WriteString(k) buf.WriteByte('=') buf.WriteString(v) buf.WriteByte('&') } } if buf.Len() <= 0 { return "" } return buf.String()[:buf.Len()-1] } // EncodeURLParams ("bar=baz&foo=quux") sorted by key. func (m *Mapx) EncodeURLParams() string { if m == nil { return "" } var ( buf strings.Builder keys []string ) for k := range *m { keys = append(keys, k) } sort.Strings(keys) for _, k := range keys { if v := m.GetString(k); v != "" { buf.WriteString(url.QueryEscape(k)) buf.WriteByte('=') buf.WriteString(url.QueryEscape(v)) buf.WriteByte('&') } } if buf.Len() <= 0 { return "" } return buf.String()[:buf.Len()-1] } func (m *Mapx) ValidateEmpty(keys ...string) error { var emptyKeys []string for _, k := range keys { if m.IsNil(k) { emptyKeys = append(emptyKeys, k) } } if len(emptyKeys) > 0 { return fmt.Errorf("[miss param error], %v", strings.Join(emptyKeys, ", ")) } return nil }