github.com/gogf/gf@v1.16.9/util/gconv/gconv_maptomaps.go (about)

     1  // Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
     2  //
     3  // This Source Code Form is subject to the terms of the MIT License.
     4  // If a copy of the MIT was not distributed with this file,
     5  // You can obtain one at https://github.com/gogf/gf.
     6  
     7  package gconv
     8  
     9  import (
    10  	"github.com/gogf/gf/errors/gcode"
    11  	"github.com/gogf/gf/errors/gerror"
    12  	"github.com/gogf/gf/internal/json"
    13  	"reflect"
    14  )
    15  
    16  // MapToMaps converts any slice type variable `params` to another map slice type variable `pointer`.
    17  // See doMapToMaps.
    18  func MapToMaps(params interface{}, pointer interface{}, mapping ...map[string]string) error {
    19  	return doMapToMaps(params, pointer, mapping...)
    20  }
    21  
    22  // MapToMapsDeep converts any slice type variable `params` to another map slice type variable
    23  // `pointer` recursively.
    24  // Deprecated, use MapToMaps instead.
    25  func MapToMapsDeep(params interface{}, pointer interface{}, mapping ...map[string]string) error {
    26  	return doMapToMaps(params, pointer, mapping...)
    27  }
    28  
    29  // doMapToMaps converts any map type variable `params` to another map slice variable `pointer`.
    30  //
    31  // The parameter `params` can be type of []map, []*map, []struct, []*struct.
    32  //
    33  // The parameter `pointer` should be type of []map, []*map.
    34  //
    35  // The optional parameter `mapping` is used for struct attribute to map key mapping, which makes
    36  // sense only if the item of `params` is type struct.
    37  func doMapToMaps(params interface{}, pointer interface{}, mapping ...map[string]string) (err error) {
    38  	// If given `params` is JSON, it then uses json.Unmarshal doing the converting.
    39  	switch r := params.(type) {
    40  	case []byte:
    41  		if json.Valid(r) {
    42  			if rv, ok := pointer.(reflect.Value); ok {
    43  				if rv.Kind() == reflect.Ptr {
    44  					return json.UnmarshalUseNumber(r, rv.Interface())
    45  				}
    46  			} else {
    47  				return json.UnmarshalUseNumber(r, pointer)
    48  			}
    49  		}
    50  	case string:
    51  		if paramsBytes := []byte(r); json.Valid(paramsBytes) {
    52  			if rv, ok := pointer.(reflect.Value); ok {
    53  				if rv.Kind() == reflect.Ptr {
    54  					return json.UnmarshalUseNumber(paramsBytes, rv.Interface())
    55  				}
    56  			} else {
    57  				return json.UnmarshalUseNumber(paramsBytes, pointer)
    58  			}
    59  		}
    60  	}
    61  	// Params and its element type check.
    62  	var (
    63  		paramsRv   reflect.Value
    64  		paramsKind reflect.Kind
    65  	)
    66  	if v, ok := params.(reflect.Value); ok {
    67  		paramsRv = v
    68  	} else {
    69  		paramsRv = reflect.ValueOf(params)
    70  	}
    71  	paramsKind = paramsRv.Kind()
    72  	if paramsKind == reflect.Ptr {
    73  		paramsRv = paramsRv.Elem()
    74  		paramsKind = paramsRv.Kind()
    75  	}
    76  	if paramsKind != reflect.Array && paramsKind != reflect.Slice {
    77  		return gerror.NewCode(gcode.CodeInvalidParameter, "params should be type of slice, eg: []map/[]*map/[]struct/[]*struct")
    78  	}
    79  	var (
    80  		paramsElem     = paramsRv.Type().Elem()
    81  		paramsElemKind = paramsElem.Kind()
    82  	)
    83  	if paramsElemKind == reflect.Ptr {
    84  		paramsElem = paramsElem.Elem()
    85  		paramsElemKind = paramsElem.Kind()
    86  	}
    87  	if paramsElemKind != reflect.Map && paramsElemKind != reflect.Struct && paramsElemKind != reflect.Interface {
    88  		return gerror.NewCodef(gcode.CodeInvalidParameter, "params element should be type of map/*map/struct/*struct, but got: %s", paramsElemKind)
    89  	}
    90  	// Empty slice, no need continue.
    91  	if paramsRv.Len() == 0 {
    92  		return nil
    93  	}
    94  	// Pointer and its element type check.
    95  	var (
    96  		pointerRv   = reflect.ValueOf(pointer)
    97  		pointerKind = pointerRv.Kind()
    98  	)
    99  	for pointerKind == reflect.Ptr {
   100  		pointerRv = pointerRv.Elem()
   101  		pointerKind = pointerRv.Kind()
   102  	}
   103  	if pointerKind != reflect.Array && pointerKind != reflect.Slice {
   104  		return gerror.NewCode(gcode.CodeInvalidParameter, "pointer should be type of *[]map/*[]*map")
   105  	}
   106  	var (
   107  		pointerElemType = pointerRv.Type().Elem()
   108  		pointerElemKind = pointerElemType.Kind()
   109  	)
   110  	if pointerElemKind == reflect.Ptr {
   111  		pointerElemKind = pointerElemType.Elem().Kind()
   112  	}
   113  	if pointerElemKind != reflect.Map {
   114  		return gerror.NewCode(gcode.CodeInvalidParameter, "pointer element should be type of map/*map")
   115  	}
   116  	defer func() {
   117  		// Catch the panic, especially the reflect operation panics.
   118  		if exception := recover(); exception != nil {
   119  			if e, ok := exception.(errorStack); ok {
   120  				err = e
   121  			} else {
   122  				err = gerror.NewCodeSkipf(gcode.CodeInternalError, 1, "%v", exception)
   123  			}
   124  		}
   125  	}()
   126  	var (
   127  		pointerSlice = reflect.MakeSlice(pointerRv.Type(), paramsRv.Len(), paramsRv.Len())
   128  	)
   129  	for i := 0; i < paramsRv.Len(); i++ {
   130  		var item reflect.Value
   131  		if pointerElemType.Kind() == reflect.Ptr {
   132  			item = reflect.New(pointerElemType.Elem())
   133  			if err = MapToMap(paramsRv.Index(i).Interface(), item, mapping...); err != nil {
   134  				return err
   135  			}
   136  			pointerSlice.Index(i).Set(item)
   137  		} else {
   138  			item = reflect.New(pointerElemType)
   139  			if err = MapToMap(paramsRv.Index(i).Interface(), item, mapping...); err != nil {
   140  				return err
   141  			}
   142  			pointerSlice.Index(i).Set(item.Elem())
   143  		}
   144  	}
   145  	pointerRv.Set(pointerSlice)
   146  	return
   147  }