github.com/wangyougui/gf/v2@v2.6.5/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/wangyougui/gf.
     6  
     7  package gconv
     8  
     9  import (
    10  	"reflect"
    11  
    12  	"github.com/wangyougui/gf/v2/errors/gcode"
    13  	"github.com/wangyougui/gf/v2/errors/gerror"
    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 Scan(params, pointer, mapping...)
    20  }
    21  
    22  // doMapToMaps converts any map type variable `params` to another map slice variable `pointer`.
    23  //
    24  // The parameter `params` can be type of []map, []*map, []struct, []*struct.
    25  //
    26  // The parameter `pointer` should be type of []map, []*map.
    27  //
    28  // The optional parameter `mapping` is used for struct attribute to map key mapping, which makes
    29  // sense only if the item of `params` is type struct.
    30  func doMapToMaps(params interface{}, pointer interface{}, paramKeyToAttrMap ...map[string]string) (err error) {
    31  	// Params and its element type check.
    32  	var (
    33  		paramsRv   reflect.Value
    34  		paramsKind reflect.Kind
    35  	)
    36  	if v, ok := params.(reflect.Value); ok {
    37  		paramsRv = v
    38  	} else {
    39  		paramsRv = reflect.ValueOf(params)
    40  	}
    41  	paramsKind = paramsRv.Kind()
    42  	if paramsKind == reflect.Ptr {
    43  		paramsRv = paramsRv.Elem()
    44  		paramsKind = paramsRv.Kind()
    45  	}
    46  	if paramsKind != reflect.Array && paramsKind != reflect.Slice {
    47  		return gerror.NewCode(
    48  			gcode.CodeInvalidParameter,
    49  			"params should be type of slice, example: []map/[]*map/[]struct/[]*struct",
    50  		)
    51  	}
    52  	var (
    53  		paramsElem     = paramsRv.Type().Elem()
    54  		paramsElemKind = paramsElem.Kind()
    55  	)
    56  	if paramsElemKind == reflect.Ptr {
    57  		paramsElem = paramsElem.Elem()
    58  		paramsElemKind = paramsElem.Kind()
    59  	}
    60  	if paramsElemKind != reflect.Map &&
    61  		paramsElemKind != reflect.Struct &&
    62  		paramsElemKind != reflect.Interface {
    63  		return gerror.NewCodef(
    64  			gcode.CodeInvalidParameter,
    65  			"params element should be type of map/*map/struct/*struct, but got: %s",
    66  			paramsElemKind,
    67  		)
    68  	}
    69  	// Empty slice, no need continue.
    70  	if paramsRv.Len() == 0 {
    71  		return nil
    72  	}
    73  	// Pointer and its element type check.
    74  	var (
    75  		pointerRv   = reflect.ValueOf(pointer)
    76  		pointerKind = pointerRv.Kind()
    77  	)
    78  	for pointerKind == reflect.Ptr {
    79  		pointerRv = pointerRv.Elem()
    80  		pointerKind = pointerRv.Kind()
    81  	}
    82  	if pointerKind != reflect.Array && pointerKind != reflect.Slice {
    83  		return gerror.NewCode(gcode.CodeInvalidParameter, "pointer should be type of *[]map/*[]*map")
    84  	}
    85  	var (
    86  		pointerElemType = pointerRv.Type().Elem()
    87  		pointerElemKind = pointerElemType.Kind()
    88  	)
    89  	if pointerElemKind == reflect.Ptr {
    90  		pointerElemKind = pointerElemType.Elem().Kind()
    91  	}
    92  	if pointerElemKind != reflect.Map {
    93  		return gerror.NewCode(gcode.CodeInvalidParameter, "pointer element should be type of map/*map")
    94  	}
    95  	defer func() {
    96  		// Catch the panic, especially the reflection operation panics.
    97  		if exception := recover(); exception != nil {
    98  			if v, ok := exception.(error); ok && gerror.HasStack(v) {
    99  				err = v
   100  			} else {
   101  				err = gerror.NewCodeSkipf(gcode.CodeInternalPanic, 1, "%+v", exception)
   102  			}
   103  		}
   104  	}()
   105  	var (
   106  		pointerSlice = reflect.MakeSlice(pointerRv.Type(), paramsRv.Len(), paramsRv.Len())
   107  	)
   108  	for i := 0; i < paramsRv.Len(); i++ {
   109  		var item reflect.Value
   110  		if pointerElemType.Kind() == reflect.Ptr {
   111  			item = reflect.New(pointerElemType.Elem())
   112  			if err = MapToMap(paramsRv.Index(i).Interface(), item, paramKeyToAttrMap...); err != nil {
   113  				return err
   114  			}
   115  			pointerSlice.Index(i).Set(item)
   116  		} else {
   117  			item = reflect.New(pointerElemType)
   118  			if err = MapToMap(paramsRv.Index(i).Interface(), item, paramKeyToAttrMap...); err != nil {
   119  				return err
   120  			}
   121  			pointerSlice.Index(i).Set(item.Elem())
   122  		}
   123  	}
   124  	pointerRv.Set(pointerSlice)
   125  	return
   126  }