1
0
mirror of https://github.com/gogf/gf.git synced 2025-04-05 11:18:50 +08:00

add map/[]map converting support for gconv.Scan;improve gconv.MaptoMaps

This commit is contained in:
John Guo 2021-03-23 17:53:20 +08:00
parent 042f903157
commit 482e093331
39 changed files with 688 additions and 685 deletions

View File

@ -71,13 +71,6 @@ func (v *Var) MapToMap(pointer interface{}, mapping ...map[string]string) (err e
return gconv.MapToMap(v.Val(), pointer, mapping...)
}
// MapToMapDeep converts any map type variable <params> to another map type variable
// <pointer> recursively.
// See gconv.MapToMapDeep.
func (v *Var) MapToMapDeep(pointer interface{}, mapping ...map[string]string) (err error) {
return gconv.MapToMapDeep(v.Val(), pointer, mapping...)
}
// MapToMaps converts any map type variable <params> to another map type variable <pointer>.
// See gconv.MapToMaps.
func (v *Var) MapToMaps(pointer interface{}, mapping ...map[string]string) (err error) {

View File

@ -354,13 +354,6 @@ func (j *Json) GetMapToMap(pattern string, pointer interface{}, mapping ...map[s
return gconv.MapToMap(j.Get(pattern), pointer, mapping...)
}
// GetMapToMapDeep retrieves the value by specified <pattern> and converts it to specified map
// variable recursively.
// See gconv.MapToMapDeep.
func (j *Json) GetMapToMapDeep(pattern string, pointer interface{}, mapping ...map[string]string) error {
return gconv.MapToMapDeep(j.Get(pattern), pointer, mapping...)
}
// GetMapToMaps retrieves the value by specified <pattern> and converts it to specified map slice
// variable.
// See gconv.MapToMaps.

View File

@ -85,15 +85,6 @@ func (j *Json) ToMapToMap(pointer interface{}, mapping ...map[string]string) err
return gconv.MapToMap(*(j.p), pointer, mapping...)
}
// ToMapToMapDeep converts current Json object to specified map variable recursively.
// The parameter of <pointer> should be type of *map.
// Deprecated, use MapToMap instead.
func (j *Json) ToMapToMapDeep(pointer interface{}, mapping ...map[string]string) error {
j.mu.RLock()
defer j.mu.RUnlock()
return gconv.MapToMapDeep(*(j.p), pointer, mapping...)
}
// ToMapToMaps converts current Json object to specified map variable slice.
// The parameter of <pointer> should be type of []map/*map.
// Deprecated, use MapToMaps instead.

View File

@ -333,16 +333,6 @@ func (c *Config) GetMapToMap(pattern string, pointer interface{}, mapping ...map
return errors.New("configuration not found")
}
// GetMapToMapDeep retrieves the value by specified `pattern` and converts it to specified map
// variable recursively.
// See gconv.MapToMapDeep.
func (c *Config) GetMapToMapDeep(pattern string, pointer interface{}, mapping ...map[string]string) error {
if j := c.getJson(); j != nil {
return j.GetMapToMapDeep(pattern, pointer, mapping...)
}
return errors.New("configuration not found")
}
// GetMapToMaps retrieves the value by specified `pattern` and converts it to specified map slice
// variable.
// See gconv.MapToMaps.
@ -426,15 +416,6 @@ func (c *Config) ToMapToMap(pointer interface{}, mapping ...map[string]string) e
return errors.New("configuration not found")
}
// ToMapToMapDeep converts current Json object to specified map variable recursively.
// The parameter of `pointer` should be type of *map.
func (c *Config) ToMapToMapDeep(pointer interface{}, mapping ...map[string]string) error {
if j := c.getJson(); j != nil {
return j.ToMapToMapDeep(pointer, mapping...)
}
return errors.New("configuration not found")
}
// ToMapToMaps converts current Json object to specified map variable slice.
// The parameter of `pointer` should be type of []map/*map.
func (c *Config) ToMapToMaps(pointer interface{}, mapping ...map[string]string) error {

View File

@ -45,8 +45,8 @@ var (
StructTagPriority = []string{"gconv", "param", "params", "c", "p", "json"}
)
// Convert converts the variable <i> to the type <t>, the type <t> is specified by string.
// The optional parameter <params> is used for additional necessary parameter for this conversion.
// Convert converts the variable `i` to the type `t`, the type `t` is specified by string.
// The optional parameter `params` is used for additional necessary parameter for this conversion.
// It supports common types conversion as its conversion based on type name string.
func Convert(any interface{}, t string, params ...interface{}) interface{} {
switch t {
@ -277,7 +277,7 @@ func Convert(any interface{}, t string, params ...interface{}) interface{} {
}
}
// Byte converts <i> to byte.
// Byte converts `i` to byte.
func Byte(any interface{}) byte {
if v, ok := any.(byte); ok {
return v
@ -285,7 +285,7 @@ func Byte(any interface{}) byte {
return Uint8(any)
}
// Bytes converts <i> to []byte.
// Bytes converts `i` to []byte.
func Bytes(any interface{}) []byte {
if any == nil {
return nil
@ -303,7 +303,7 @@ func Bytes(any interface{}) []byte {
}
}
// Rune converts <i> to rune.
// Rune converts `i` to rune.
func Rune(any interface{}) rune {
if v, ok := any.(rune); ok {
return v
@ -311,7 +311,7 @@ func Rune(any interface{}) rune {
return rune(Int32(any))
}
// Runes converts <i> to []rune.
// Runes converts `i` to []rune.
func Runes(any interface{}) []rune {
if v, ok := any.([]rune); ok {
return v
@ -319,7 +319,7 @@ func Runes(any interface{}) []rune {
return []rune(String(any))
}
// String converts <i> to string.
// String converts `i` to string.
// It's most common used converting function.
func String(any interface{}) string {
if any == nil {
@ -422,8 +422,8 @@ func String(any interface{}) string {
}
}
// Bool converts <i> to bool.
// It returns false if <i> is: false, "", 0, "false", "off", "no", empty slice/map.
// Bool converts `i` to bool.
// It returns false if `i` is: false, "", 0, "false", "off", "no", empty slice/map.
func Bool(any interface{}) bool {
if any == nil {
return false
@ -467,7 +467,7 @@ func Bool(any interface{}) bool {
}
}
// Int converts <i> to int.
// Int converts `i` to int.
func Int(any interface{}) int {
if any == nil {
return 0
@ -478,7 +478,7 @@ func Int(any interface{}) int {
return int(Int64(any))
}
// Int8 converts <i> to int8.
// Int8 converts `i` to int8.
func Int8(any interface{}) int8 {
if any == nil {
return 0
@ -489,7 +489,7 @@ func Int8(any interface{}) int8 {
return int8(Int64(any))
}
// Int16 converts <i> to int16.
// Int16 converts `i` to int16.
func Int16(any interface{}) int16 {
if any == nil {
return 0
@ -500,7 +500,7 @@ func Int16(any interface{}) int16 {
return int16(Int64(any))
}
// Int32 converts <i> to int32.
// Int32 converts `i` to int32.
func Int32(any interface{}) int32 {
if any == nil {
return 0
@ -511,7 +511,7 @@ func Int32(any interface{}) int32 {
return int32(Int64(any))
}
// Int64 converts <i> to int64.
// Int64 converts `i` to int64.
func Int64(any interface{}) int64 {
if any == nil {
return 0
@ -592,7 +592,7 @@ func Int64(any interface{}) int64 {
}
}
// Uint converts <i> to uint.
// Uint converts `i` to uint.
func Uint(any interface{}) uint {
if any == nil {
return 0
@ -603,7 +603,7 @@ func Uint(any interface{}) uint {
return uint(Uint64(any))
}
// Uint8 converts <i> to uint8.
// Uint8 converts `i` to uint8.
func Uint8(any interface{}) uint8 {
if any == nil {
return 0
@ -614,7 +614,7 @@ func Uint8(any interface{}) uint8 {
return uint8(Uint64(any))
}
// Uint16 converts <i> to uint16.
// Uint16 converts `i` to uint16.
func Uint16(any interface{}) uint16 {
if any == nil {
return 0
@ -625,7 +625,7 @@ func Uint16(any interface{}) uint16 {
return uint16(Uint64(any))
}
// Uint32 converts <i> to uint32.
// Uint32 converts `i` to uint32.
func Uint32(any interface{}) uint32 {
if any == nil {
return 0
@ -636,7 +636,7 @@ func Uint32(any interface{}) uint32 {
return uint32(Uint64(any))
}
// Uint64 converts <i> to uint64.
// Uint64 converts `i` to uint64.
func Uint64(any interface{}) uint64 {
if any == nil {
return 0
@ -699,7 +699,7 @@ func Uint64(any interface{}) uint64 {
}
}
// Float32 converts <i> to float32.
// Float32 converts `i` to float32.
func Float32(any interface{}) float32 {
if any == nil {
return 0
@ -720,7 +720,7 @@ func Float32(any interface{}) float32 {
}
}
// Float64 converts <i> to float64.
// Float64 converts `i` to float64.
func Float64(any interface{}) float64 {
if any == nil {
return 0

View File

@ -7,7 +7,6 @@
package gconv
import (
"github.com/gogf/gf/errors/gerror"
"github.com/gogf/gf/internal/json"
"reflect"
"strings"
@ -16,17 +15,17 @@ import (
"github.com/gogf/gf/internal/utils"
)
// Map converts any variable <value> to map[string]interface{}. If the parameter <value> is not a
// Map converts any variable `value` to map[string]interface{}. If the parameter `value` is not a
// map/struct/*struct type, then the conversion will fail and returns nil.
//
// If <value> is a struct/*struct object, the second parameter <tags> specifies the most priority
// If `value` is a struct/*struct object, the second parameter `tags` specifies the most priority
// tags that will be detected, otherwise it detects the tags in order of:
// gconv, json, field name.
func Map(value interface{}, tags ...string) map[string]interface{} {
return doMapConvert(value, false, tags...)
}
// MapDeep does Map function recursively, which means if the attribute of <value>
// MapDeep does Map function recursively, which means if the attribute of `value`
// is also a struct/*struct, calls Map function on this attribute converting it to
// a map[string]interface{} type variable.
// Also see Map.
@ -35,7 +34,7 @@ func MapDeep(value interface{}, tags ...string) map[string]interface{} {
}
// doMapConvert implements the map converting.
// It automatically checks and converts json string to map if <value> is string/[]byte.
// It automatically checks and converts json string to map if `value` is string/[]byte.
//
// TODO completely implement the recursive converting for all types, especially the map.
func doMapConvert(value interface{}, recursive bool, tags ...string) map[string]interface{} {
@ -154,7 +153,7 @@ func doMapConvert(value interface{}, recursive bool, tags ...string) map[string]
reflectKind = reflectValue.Kind()
}
switch reflectKind {
// If <value> is type of array, it converts the value of even number index as its key and
// If `value` is type of array, it converts the value of even number index as its key and
// the value of odd number index as its corresponding value, for example:
// []string{"k1","v1","k2","v2"} => map[string]interface{}{"k1":"v1", "k2":"v2"}
// []string{"k1","v1","k2"} => map[string]interface{}{"k1":"v1", "k2":nil}
@ -354,7 +353,7 @@ func doMapConvertForMapOrStructValue(isRoot bool, value interface{}, recursive b
return value
}
// MapStrStr converts <value> to map[string]string.
// MapStrStr converts `value` to map[string]string.
// Note that there might be data copy for this map type converting.
func MapStrStr(value interface{}, tags ...string) map[string]string {
if r, ok := value.(map[string]string); ok {
@ -371,7 +370,7 @@ func MapStrStr(value interface{}, tags ...string) map[string]string {
return nil
}
// MapStrStrDeep converts <value> to map[string]string recursively.
// MapStrStrDeep converts `value` to map[string]string recursively.
// Note that there might be data copy for this map type converting.
func MapStrStrDeep(value interface{}, tags ...string) map[string]string {
if r, ok := value.(map[string]string); ok {
@ -387,196 +386,3 @@ func MapStrStrDeep(value interface{}, tags ...string) map[string]string {
}
return nil
}
// MapToMap converts any map type variable <params> to another map type variable <pointer>
// using reflect.
// See doMapToMap.
func MapToMap(params interface{}, pointer interface{}, mapping ...map[string]string) error {
return doMapToMap(params, pointer, mapping...)
}
// MapToMapDeep converts any map type variable <params> to another map type variable <pointer>
// using reflect recursively.
// Deprecated, use MapToMap instead.
func MapToMapDeep(params interface{}, pointer interface{}, mapping ...map[string]string) error {
return doMapToMap(params, pointer, mapping...)
}
// doMapToMap converts any map type variable <params> to another map type variable <pointer>.
//
// The parameter <params> can be any type of map, like:
// map[string]string, map[string]struct, , map[string]*struct, etc.
//
// The parameter <pointer> should be type of *map, like:
// map[int]string, map[string]struct, , map[string]*struct, etc.
//
// The optional parameter <mapping> is used for struct attribute to map key mapping, which makes
// sense only if the items of original map <params> is type struct.
func doMapToMap(params interface{}, pointer interface{}, mapping ...map[string]string) (err error) {
var (
paramsRv = reflect.ValueOf(params)
paramsKind = paramsRv.Kind()
)
if paramsKind == reflect.Ptr {
paramsRv = paramsRv.Elem()
paramsKind = paramsRv.Kind()
}
if paramsKind != reflect.Map {
return gerror.New("params should be type of map")
}
// Empty params map, no need continue.
if paramsRv.Len() == 0 {
return nil
}
var pointerRv reflect.Value
if v, ok := pointer.(reflect.Value); ok {
pointerRv = v
} else {
pointerRv = reflect.ValueOf(pointer)
}
pointerKind := pointerRv.Kind()
for pointerKind == reflect.Ptr {
pointerRv = pointerRv.Elem()
pointerKind = pointerRv.Kind()
}
if pointerKind != reflect.Map {
return gerror.New("pointer should be type of *map")
}
defer func() {
// Catch the panic, especially the reflect operation panics.
if exception := recover(); exception != nil {
if e, ok := exception.(errorStack); ok {
err = e
} else {
err = gerror.NewSkipf(1, "%v", exception)
}
}
}()
var (
paramsKeys = paramsRv.MapKeys()
pointerKeyType = pointerRv.Type().Key()
pointerValueType = pointerRv.Type().Elem()
pointerValueKind = pointerValueType.Kind()
dataMap = reflect.MakeMapWithSize(pointerRv.Type(), len(paramsKeys))
)
// Retrieve the true element type of target map.
if pointerValueKind == reflect.Ptr {
pointerValueKind = pointerValueType.Elem().Kind()
}
for _, key := range paramsKeys {
e := reflect.New(pointerValueType).Elem()
switch pointerValueKind {
case reflect.Map, reflect.Struct:
if err = Struct(paramsRv.MapIndex(key).Interface(), e, mapping...); err != nil {
return err
}
default:
e.Set(
reflect.ValueOf(
Convert(
paramsRv.MapIndex(key).Interface(),
pointerValueType.String(),
),
),
)
}
dataMap.SetMapIndex(
reflect.ValueOf(
Convert(
key.Interface(),
pointerKeyType.Name(),
),
),
e,
)
}
pointerRv.Set(dataMap)
return nil
}
// MapToMaps converts any map type variable <params> to another map type variable <pointer>.
// See doMapToMaps.
func MapToMaps(params interface{}, pointer interface{}, mapping ...map[string]string) error {
return doMapToMaps(params, pointer, mapping...)
}
// MapToMapsDeep converts any map type variable <params> to another map type variable
// <pointer> recursively.
// Deprecated, use MapToMaps instead.
func MapToMapsDeep(params interface{}, pointer interface{}, mapping ...map[string]string) error {
return doMapToMaps(params, pointer, mapping...)
}
// doMapToMaps converts any map type variable <params> to another map type variable <pointer>.
//
// The parameter <params> can be any type of map, of which the item type is slice map, like:
// map[int][]map, map[string][]map.
//
// The parameter <pointer> should be type of *map, of which the item type is slice map, like:
// map[string][]struct, map[string][]*struct.
//
// The optional parameter <mapping> is used for struct attribute to map key mapping, which makes
// sense only if the items of original map is type struct.
//
// TODO it's supposed supporting target type <pointer> like: map[int][]map, map[string][]map.
func doMapToMaps(params interface{}, pointer interface{}, mapping ...map[string]string) (err error) {
var (
paramsRv = reflect.ValueOf(params)
paramsKind = paramsRv.Kind()
)
if paramsKind == reflect.Ptr {
paramsRv = paramsRv.Elem()
paramsKind = paramsRv.Kind()
}
if paramsKind != reflect.Map {
return gerror.New("params should be type of map")
}
// Empty params map, no need continue.
if paramsRv.Len() == 0 {
return nil
}
var (
pointerRv = reflect.ValueOf(pointer)
pointerKind = pointerRv.Kind()
)
for pointerKind == reflect.Ptr {
pointerRv = pointerRv.Elem()
pointerKind = pointerRv.Kind()
}
if pointerKind != reflect.Map {
return gerror.New("pointer should be type of *map/**map")
}
defer func() {
// Catch the panic, especially the reflect operation panics.
if exception := recover(); exception != nil {
if e, ok := exception.(errorStack); ok {
err = e
} else {
err = gerror.NewSkipf(1, "%v", exception)
}
}
}()
var (
paramsKeys = paramsRv.MapKeys()
pointerKeyType = pointerRv.Type().Key()
pointerValueType = pointerRv.Type().Elem()
dataMap = reflect.MakeMapWithSize(pointerRv.Type(), len(paramsKeys))
)
for _, key := range paramsKeys {
e := reflect.New(pointerValueType).Elem()
if err = Structs(paramsRv.MapIndex(key).Interface(), e.Addr(), mapping...); err != nil {
return err
}
dataMap.SetMapIndex(
reflect.ValueOf(
Convert(
key.Interface(),
pointerKeyType.Name(),
),
),
e,
)
}
pointerRv.Set(dataMap)
return nil
}

119
util/gconv/gconv_maps.go Normal file
View File

@ -0,0 +1,119 @@
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
package gconv
import "github.com/gogf/gf/internal/json"
// SliceMap is alias of Maps.
func SliceMap(any interface{}) []map[string]interface{} {
return Maps(any)
}
// SliceMapDeep is alias of MapsDeep.
func SliceMapDeep(any interface{}) []map[string]interface{} {
return MapsDeep(any)
}
// SliceStruct is alias of Structs.
func SliceStruct(params interface{}, pointer interface{}, mapping ...map[string]string) (err error) {
return Structs(params, pointer, mapping...)
}
// Maps converts `i` to []map[string]interface{}.
// Note that it automatically checks and converts json string to []map if `value` is string/[]byte.
func Maps(value interface{}, tags ...string) []map[string]interface{} {
if value == nil {
return nil
}
switch r := value.(type) {
case string:
list := make([]map[string]interface{}, 0)
if len(r) > 0 && r[0] == '[' && r[len(r)-1] == ']' {
if err := json.Unmarshal([]byte(r), &list); err != nil {
return nil
}
return list
} else {
return nil
}
case []byte:
list := make([]map[string]interface{}, 0)
if len(r) > 0 && r[0] == '[' && r[len(r)-1] == ']' {
if err := json.Unmarshal(r, &list); err != nil {
return nil
}
return list
} else {
return nil
}
case []map[string]interface{}:
return r
default:
array := Interfaces(value)
if len(array) == 0 {
return nil
}
list := make([]map[string]interface{}, len(array))
for k, v := range array {
list[k] = Map(v, tags...)
}
return list
}
}
// MapsDeep converts `i` to []map[string]interface{} recursively.
//
// TODO completely implement the recursive converting for all types.
func MapsDeep(value interface{}, tags ...string) []map[string]interface{} {
if value == nil {
return nil
}
switch r := value.(type) {
case string:
list := make([]map[string]interface{}, 0)
if len(r) > 0 && r[0] == '[' && r[len(r)-1] == ']' {
if err := json.Unmarshal([]byte(r), &list); err != nil {
return nil
}
return list
} else {
return nil
}
case []byte:
list := make([]map[string]interface{}, 0)
if len(r) > 0 && r[0] == '[' && r[len(r)-1] == ']' {
if err := json.Unmarshal(r, &list); err != nil {
return nil
}
return list
} else {
return nil
}
case []map[string]interface{}:
list := make([]map[string]interface{}, len(r))
for k, v := range r {
list[k] = MapDeep(v, tags...)
}
return list
default:
array := Interfaces(value)
if len(array) == 0 {
return nil
}
list := make([]map[string]interface{}, len(array))
for k, v := range array {
list[k] = MapDeep(v, tags...)
}
return list
}
}

View File

@ -0,0 +1,141 @@
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
package gconv
import (
"github.com/gogf/gf/errors/gerror"
"github.com/gogf/gf/internal/json"
"reflect"
)
// MapToMap converts any map type variable `params` to another map type variable `pointer`
// using reflect.
// See doMapToMap.
func MapToMap(params interface{}, pointer interface{}, mapping ...map[string]string) error {
return doMapToMap(params, pointer, mapping...)
}
// doMapToMap converts any map type variable `params` to another map type variable `pointer`.
//
// The parameter `params` can be any type of map, like:
// map[string]string, map[string]struct, , map[string]*struct, etc.
//
// The parameter `pointer` should be type of *map, like:
// map[int]string, map[string]struct, , map[string]*struct, etc.
//
// The optional parameter `mapping` is used for struct attribute to map key mapping, which makes
// sense only if the items of original map `params` is type struct.
func doMapToMap(params interface{}, pointer interface{}, mapping ...map[string]string) (err error) {
// If given `params` is JSON, it then uses json.Unmarshal doing the converting.
switch r := params.(type) {
case []byte:
if json.Valid(r) {
if rv, ok := pointer.(reflect.Value); ok {
if rv.Kind() == reflect.Ptr {
return json.Unmarshal(r, rv.Interface())
}
} else {
return json.Unmarshal(r, pointer)
}
}
case string:
if paramsBytes := []byte(r); json.Valid(paramsBytes) {
if rv, ok := pointer.(reflect.Value); ok {
if rv.Kind() == reflect.Ptr {
return json.Unmarshal(paramsBytes, rv.Interface())
}
} else {
return json.Unmarshal(paramsBytes, pointer)
}
}
}
var (
paramsRv reflect.Value
paramsKind reflect.Kind
)
if v, ok := params.(reflect.Value); ok {
paramsRv = v
} else {
paramsRv = reflect.ValueOf(params)
}
paramsKind = paramsRv.Kind()
if paramsKind == reflect.Ptr {
paramsRv = paramsRv.Elem()
paramsKind = paramsRv.Kind()
}
if paramsKind != reflect.Map {
return doMapToMap(Map(params), pointer, mapping...)
}
// Empty params map, no need continue.
if paramsRv.Len() == 0 {
return nil
}
var pointerRv reflect.Value
if v, ok := pointer.(reflect.Value); ok {
pointerRv = v
} else {
pointerRv = reflect.ValueOf(pointer)
}
pointerKind := pointerRv.Kind()
for pointerKind == reflect.Ptr {
pointerRv = pointerRv.Elem()
pointerKind = pointerRv.Kind()
}
if pointerKind != reflect.Map {
return gerror.Newf("pointer should be type of *map, but got:%s", pointerKind)
}
defer func() {
// Catch the panic, especially the reflect operation panics.
if exception := recover(); exception != nil {
if e, ok := exception.(errorStack); ok {
err = e
} else {
err = gerror.NewSkipf(1, "%v", exception)
}
}
}()
var (
paramsKeys = paramsRv.MapKeys()
pointerKeyType = pointerRv.Type().Key()
pointerValueType = pointerRv.Type().Elem()
pointerValueKind = pointerValueType.Kind()
dataMap = reflect.MakeMapWithSize(pointerRv.Type(), len(paramsKeys))
)
// Retrieve the true element type of target map.
if pointerValueKind == reflect.Ptr {
pointerValueKind = pointerValueType.Elem().Kind()
}
for _, key := range paramsKeys {
e := reflect.New(pointerValueType).Elem()
switch pointerValueKind {
case reflect.Map, reflect.Struct:
if err = Struct(paramsRv.MapIndex(key).Interface(), e, mapping...); err != nil {
return err
}
default:
e.Set(
reflect.ValueOf(
Convert(
paramsRv.MapIndex(key).Interface(),
pointerValueType.String(),
),
),
)
}
dataMap.SetMapIndex(
reflect.ValueOf(
Convert(
key.Interface(),
pointerKeyType.Name(),
),
),
e,
)
}
pointerRv.Set(dataMap)
return nil
}

View File

@ -0,0 +1,146 @@
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
package gconv
import (
"github.com/gogf/gf/errors/gerror"
"github.com/gogf/gf/internal/json"
"reflect"
)
// MapToMaps converts any slice type variable `params` to another map slice type variable `pointer`.
// See doMapToMaps.
func MapToMaps(params interface{}, pointer interface{}, mapping ...map[string]string) error {
return doMapToMaps(params, pointer, mapping...)
}
// MapToMapsDeep converts any slice type variable `params` to another map slice type variable
// `pointer` recursively.
// Deprecated, use MapToMaps instead.
func MapToMapsDeep(params interface{}, pointer interface{}, mapping ...map[string]string) error {
return doMapToMaps(params, pointer, mapping...)
}
// doMapToMaps converts any map type variable `params` to another map slice variable `pointer`.
//
// The parameter `params` can be type of []map, []*map, []struct, []*struct.
//
// The parameter `pointer` should be type of []map, []*map.
//
// The optional parameter `mapping` is used for struct attribute to map key mapping, which makes
// sense only if the item of `params` is type struct.
func doMapToMaps(params interface{}, pointer interface{}, mapping ...map[string]string) (err error) {
// If given `params` is JSON, it then uses json.Unmarshal doing the converting.
switch r := params.(type) {
case []byte:
if json.Valid(r) {
if rv, ok := pointer.(reflect.Value); ok {
if rv.Kind() == reflect.Ptr {
return json.Unmarshal(r, rv.Interface())
}
} else {
return json.Unmarshal(r, pointer)
}
}
case string:
if paramsBytes := []byte(r); json.Valid(paramsBytes) {
if rv, ok := pointer.(reflect.Value); ok {
if rv.Kind() == reflect.Ptr {
return json.Unmarshal(paramsBytes, rv.Interface())
}
} else {
return json.Unmarshal(paramsBytes, pointer)
}
}
}
// Params and its element type check.
var (
paramsRv reflect.Value
paramsKind reflect.Kind
)
if v, ok := params.(reflect.Value); ok {
paramsRv = v
} else {
paramsRv = reflect.ValueOf(params)
}
paramsKind = paramsRv.Kind()
if paramsKind == reflect.Ptr {
paramsRv = paramsRv.Elem()
paramsKind = paramsRv.Kind()
}
if paramsKind != reflect.Array && paramsKind != reflect.Slice {
return gerror.New("params should be type of slice, eg: []map/[]*map/[]struct/[]*struct")
}
var (
paramsElem = paramsRv.Type().Elem()
paramsElemKind = paramsElem.Kind()
)
if paramsElemKind == reflect.Ptr {
paramsElem = paramsElem.Elem()
paramsElemKind = paramsElem.Kind()
}
if paramsElemKind != reflect.Map && paramsElemKind != reflect.Struct && paramsElemKind != reflect.Interface {
return gerror.Newf("params element should be type of map/*map/struct/*struct, but got: %s", paramsElemKind)
}
// Empty slice, no need continue.
if paramsRv.Len() == 0 {
return nil
}
// Pointer and its element type check.
var (
pointerRv = reflect.ValueOf(pointer)
pointerKind = pointerRv.Kind()
)
for pointerKind == reflect.Ptr {
pointerRv = pointerRv.Elem()
pointerKind = pointerRv.Kind()
}
if pointerKind != reflect.Array && pointerKind != reflect.Slice {
return gerror.New("pointer should be type of *[]map/*[]*map")
}
var (
pointerElemType = pointerRv.Type().Elem()
pointerElemKind = pointerElemType.Kind()
)
if pointerElemKind == reflect.Ptr {
pointerElemKind = pointerElemType.Elem().Kind()
}
if pointerElemKind != reflect.Map {
return gerror.New("pointer element should be type of map/*map")
}
defer func() {
// Catch the panic, especially the reflect operation panics.
if exception := recover(); exception != nil {
if e, ok := exception.(errorStack); ok {
err = e
} else {
err = gerror.NewSkipf(1, "%v", exception)
}
}
}()
var (
pointerSlice = reflect.MakeSlice(pointerRv.Type(), paramsRv.Len(), paramsRv.Len())
)
for i := 0; i < paramsRv.Len(); i++ {
var item reflect.Value
if pointerElemType.Kind() == reflect.Ptr {
item = reflect.New(pointerElemType.Elem())
if err = MapToMap(paramsRv.Index(i).Interface(), item, mapping...); err != nil {
return err
}
pointerSlice.Index(i).Set(item)
} else {
item = reflect.New(pointerElemType)
if err = MapToMap(paramsRv.Index(i).Interface(), item, mapping...); err != nil {
return err
}
pointerSlice.Index(i).Set(item.Elem())
}
}
pointerRv.Set(pointerSlice)
return
}

View File

@ -11,18 +11,39 @@ import (
"reflect"
)
// Scan automatically calls Struct or Structs function according to the type of parameter
// <pointer> to implement the converting.
// It calls function Struct if <pointer> is type of *struct/**struct to do the converting.
// It calls function Structs if <pointer> is type of *[]struct/*[]*struct to do the converting.
// Scan automatically calls MapToMap, MapToMaps, Struct or Structs function according to
// the type of parameter `pointer` to implement the converting.
// It calls function MapToMap if `pointer` is type of *map to do the converting.
// It calls function MapToMaps if `pointer` is type of *[]map/*[]*map to do the converting.
// It calls function Struct if `pointer` is type of *struct/**struct to do the converting.
// It calls function Structs if `pointer` is type of *[]struct/*[]*struct to do the converting.
func Scan(params interface{}, pointer interface{}, mapping ...map[string]string) (err error) {
t := reflect.TypeOf(pointer)
k := t.Kind()
if k != reflect.Ptr {
return gerror.Newf("params should be type of pointer, but got: %v", k)
var (
pointerType = reflect.TypeOf(pointer)
pointerKind = pointerType.Kind()
)
if pointerKind != reflect.Ptr {
return gerror.Newf("params should be type of pointer, but got: %v", pointerKind)
}
switch t.Elem().Kind() {
var (
pointerElem = pointerType.Elem()
pointerElemKind = pointerElem.Kind()
)
switch pointerElemKind {
case reflect.Map:
return MapToMap(params, pointer, mapping...)
case reflect.Array, reflect.Slice:
var (
sliceElem = pointerElem.Elem()
sliceElemKind = sliceElem.Kind()
)
for sliceElemKind == reflect.Ptr {
sliceElem = sliceElem.Elem()
sliceElemKind = sliceElem.Kind()
}
if sliceElemKind == reflect.Map {
return MapToMaps(params, pointer, mapping...)
}
return Structs(params, pointer, mapping...)
default:
return Struct(params, pointer, mapping...)
@ -30,9 +51,9 @@ func Scan(params interface{}, pointer interface{}, mapping ...map[string]string)
}
// ScanDeep automatically calls StructDeep or StructsDeep function according to the type of
// parameter <pointer> to implement the converting..
// It calls function StructDeep if <pointer> is type of *struct/**struct to do the converting.
// It calls function StructsDeep if <pointer> is type of *[]struct/*[]*struct to do the converting.
// parameter `pointer` to implement the converting..
// It calls function StructDeep if `pointer` is type of *struct/**struct to do the converting.
// It calls function StructsDeep if `pointer` is type of *[]struct/*[]*struct to do the converting.
// Deprecated, use Scan instead.
func ScanDeep(params interface{}, pointer interface{}, mapping ...map[string]string) (err error) {
t := reflect.TypeOf(pointer)

View File

@ -5,123 +5,3 @@
// You can obtain one at https://github.com/gogf/gf.
package gconv
import (
"github.com/gogf/gf/internal/json"
)
// SliceMap is alias of Maps.
func SliceMap(any interface{}) []map[string]interface{} {
return Maps(any)
}
// SliceMapDeep is alias of MapsDeep.
func SliceMapDeep(any interface{}) []map[string]interface{} {
return MapsDeep(any)
}
// SliceStruct is alias of Structs.
func SliceStruct(params interface{}, pointer interface{}, mapping ...map[string]string) (err error) {
return Structs(params, pointer, mapping...)
}
// SliceStructDeep is alias of StructsDeep.
// Deprecated, use SliceStruct instead.
func SliceStructDeep(params interface{}, pointer interface{}, mapping ...map[string]string) (err error) {
return StructsDeep(params, pointer, mapping...)
}
// Maps converts <i> to []map[string]interface{}.
// Note that it automatically checks and converts json string to []map if <value> is string/[]byte.
func Maps(value interface{}, tags ...string) []map[string]interface{} {
if value == nil {
return nil
}
switch r := value.(type) {
case string:
list := make([]map[string]interface{}, 0)
if len(r) > 0 && r[0] == '[' && r[len(r)-1] == ']' {
if err := json.Unmarshal([]byte(r), &list); err != nil {
return nil
}
return list
} else {
return nil
}
case []byte:
list := make([]map[string]interface{}, 0)
if len(r) > 0 && r[0] == '[' && r[len(r)-1] == ']' {
if err := json.Unmarshal(r, &list); err != nil {
return nil
}
return list
} else {
return nil
}
case []map[string]interface{}:
return r
default:
array := Interfaces(value)
if len(array) == 0 {
return nil
}
list := make([]map[string]interface{}, len(array))
for k, v := range array {
list[k] = Map(v, tags...)
}
return list
}
}
// MapsDeep converts <i> to []map[string]interface{} recursively.
//
// TODO completely implement the recursive converting for all types.
func MapsDeep(value interface{}, tags ...string) []map[string]interface{} {
if value == nil {
return nil
}
switch r := value.(type) {
case string:
list := make([]map[string]interface{}, 0)
if len(r) > 0 && r[0] == '[' && r[len(r)-1] == ']' {
if err := json.Unmarshal([]byte(r), &list); err != nil {
return nil
}
return list
} else {
return nil
}
case []byte:
list := make([]map[string]interface{}, 0)
if len(r) > 0 && r[0] == '[' && r[len(r)-1] == ']' {
if err := json.Unmarshal(r, &list); err != nil {
return nil
}
return list
} else {
return nil
}
case []map[string]interface{}:
list := make([]map[string]interface{}, len(r))
for k, v := range r {
list[k] = MapDeep(v, tags...)
}
return list
default:
array := Interfaces(value)
if len(array) == 0 {
return nil
}
list := make([]map[string]interface{}, len(array))
for k, v := range array {
list[k] = MapDeep(v, tags...)
}
return list
}
}

View File

@ -15,7 +15,7 @@ func SliceAny(any interface{}) []interface{} {
return Interfaces(any)
}
// Interfaces converts <i> to []interface{}.
// Interfaces converts `i` to []interface{}.
func Interfaces(any interface{}) []interface{} {
if any == nil {
return nil

View File

@ -23,12 +23,12 @@ func SliceFloat64(any interface{}) []float64 {
return Floats(any)
}
// Floats converts <i> to []float64.
// Floats converts `i` to []float64.
func Floats(any interface{}) []float64 {
return Float64s(any)
}
// Float32s converts <i> to []float32.
// Float32s converts `i` to []float32.
func Float32s(any interface{}) []float32 {
if any == nil {
return nil
@ -148,7 +148,7 @@ func Float32s(any interface{}) []float32 {
return array
}
// Float64s converts <i> to []float64.
// Float64s converts `i` to []float64.
func Float64s(any interface{}) []float64 {
if any == nil {
return nil

View File

@ -23,7 +23,7 @@ func SliceInt64(any interface{}) []int64 {
return Int64s(any)
}
// Ints converts <i> to []int.
// Ints converts `i` to []int.
func Ints(any interface{}) []int {
if any == nil {
return nil
@ -153,7 +153,7 @@ func Ints(any interface{}) []int {
return array
}
// Int32s converts <i> to []int32.
// Int32s converts `i` to []int32.
func Int32s(any interface{}) []int32 {
if any == nil {
return nil
@ -283,7 +283,7 @@ func Int32s(any interface{}) []int32 {
return array
}
// Int64s converts <i> to []int64.
// Int64s converts `i` to []int64.
func Int64s(any interface{}) []int64 {
if any == nil {
return nil

View File

@ -13,7 +13,7 @@ func SliceStr(any interface{}) []string {
return Strings(any)
}
// Strings converts <i> to []string.
// Strings converts `i` to []string.
func Strings(any interface{}) []string {
if any == nil {
return nil

View File

@ -23,7 +23,7 @@ func SliceUint64(any interface{}) []uint64 {
return Uint64s(any)
}
// Uints converts <i> to []uint.
// Uints converts `i` to []uint.
func Uints(any interface{}) []uint {
if any == nil {
return nil
@ -149,7 +149,7 @@ func Uints(any interface{}) []uint {
return array
}
// Uint32s converts <i> to []uint32.
// Uint32s converts `i` to []uint32.
func Uint32s(any interface{}) []uint32 {
if any == nil {
return nil
@ -274,7 +274,7 @@ func Uint32s(any interface{}) []uint32 {
return array
}
// Uint64s converts <i> to []uint64.
// Uint64s converts `i` to []uint64.
func Uint64s(any interface{}) []uint64 {
if any == nil {
return nil

View File

@ -19,15 +19,15 @@ import (
)
// Struct maps the params key-value pairs to the corresponding struct object's attributes.
// The third parameter <mapping> is unnecessary, indicating the mapping rules between the
// The third parameter `mapping` is unnecessary, indicating the mapping rules between the
// custom key name and the attribute name(case sensitive).
//
// Note:
// 1. The <params> can be any type of map/struct, usually a map.
// 2. The <pointer> should be type of *struct/**struct, which is a pointer to struct object
// 1. The `params` can be any type of map/struct, usually a map.
// 2. The `pointer` should be type of *struct/**struct, which is a pointer to struct object
// or struct pointer.
// 3. Only the public attributes of struct object can be mapped.
// 4. If <params> is a map, the key of the map <params> can be lowercase.
// 4. If `params` is a map, the key of the map `params` can be lowercase.
// It will automatically convert the first letter of the key to uppercase
// in mapping procedure to do the matching.
// It ignores the map key, if it does not match.
@ -59,7 +59,7 @@ func StructDeep(params interface{}, pointer interface{}, mapping ...map[string]s
// doStruct is the core internal converting function for any data to struct.
func doStruct(params interface{}, pointer interface{}, mapping map[string]string, priorityTag string) (err error) {
if params == nil {
// If <params> is nil, no conversion.
// If `params` is nil, no conversion.
return nil
}
if pointer == nil {
@ -77,7 +77,7 @@ func doStruct(params interface{}, pointer interface{}, mapping map[string]string
}
}()
// If given <params> is JSON, it then uses json.Unmarshal doing the converting.
// If given `params` is JSON, it then uses json.Unmarshal doing the converting.
switch r := params.(type) {
case []byte:
if json.Valid(r) {
@ -140,7 +140,7 @@ func doStruct(params interface{}, pointer interface{}, mapping map[string]string
}
// It automatically creates struct object if necessary.
// For example, if <pointer> is **User, then <elem> is *User, which is a pointer to User.
// For example, if `pointer` is **User, then `elem` is *User, which is a pointer to User.
if pointerElemReflectValue.Kind() == reflect.Ptr {
if !pointerElemReflectValue.IsValid() || pointerElemReflectValue.IsNil() {
e := reflect.New(pointerElemReflectValue.Type().Elem()).Elem()
@ -249,7 +249,7 @@ func doStruct(params interface{}, pointer interface{}, mapping map[string]string
// string cases and chars like '-'/'_'/'.'/' '.
// Matching the parameters to struct tag names.
// The <tagV> is the attribute name of the struct.
// The `tagV` is the attribute name of the struct.
for attrKey, cmpKey := range tagMap {
if strings.EqualFold(checkName, cmpKey) {
attrName = attrKey
@ -349,7 +349,7 @@ func bindVarToReflectValueWithInterfaceCheck(reflectValue reflect.Value, value i
return nil, false
}
// bindVarToReflectValue sets <value> to reflect value object <structFieldValue>.
// bindVarToReflectValue sets `value` to reflect value object `structFieldValue`.
func bindVarToReflectValue(structFieldValue reflect.Value, value interface{}, mapping map[string]string, priorityTag string) (err error) {
if err, ok := bindVarToReflectValueWithInterfaceCheck(structFieldValue, value); ok {
return err
@ -455,7 +455,7 @@ func bindVarToReflectValue(structFieldValue reflect.Value, value interface{}, ma
)
}
}()
// It here uses reflect converting <value> to type of the attribute and assigns
// It here uses reflect converting `value` to type of the attribute and assigns
// the result value to the attribute. It might fail and panic if the usual Go
// conversion rules do not allow conversion.
structFieldValue.Set(reflect.ValueOf(value).Convert(structFieldValue.Type()))

View File

@ -40,14 +40,14 @@ func StructsDeep(params interface{}, pointer interface{}, mapping ...map[string]
// doStructs converts any slice to given struct slice.
//
// It automatically checks and converts json string to []map if <params> is string/[]byte.
// It automatically checks and converts json string to []map if `params` is string/[]byte.
//
// The parameter <pointer> should be type of pointer to slice of struct.
// Note that if <pointer> is a pointer to another pointer of type of slice of struct,
// The parameter `pointer` should be type of pointer to slice of struct.
// Note that if `pointer` is a pointer to another pointer of type of slice of struct,
// it will create the struct/pointer internally.
func doStructs(params interface{}, pointer interface{}, mapping map[string]string, priorityTag string) (err error) {
if params == nil {
// If <params> is nil, no conversion.
// If `params` is nil, no conversion.
return nil
}
if pointer == nil {
@ -68,7 +68,7 @@ func doStructs(params interface{}, pointer interface{}, mapping map[string]strin
}
}
}()
// If given <params> is JSON, it then uses json.Unmarshal doing the converting.
// If given `params` is JSON, it then uses json.Unmarshal doing the converting.
switch r := params.(type) {
case []byte:
if json.Valid(r) {
@ -99,9 +99,9 @@ func doStructs(params interface{}, pointer interface{}, mapping map[string]strin
return gerror.Newf("pointer should be type of pointer, but got: %v", kind)
}
}
// Converting <params> to map slice.
// Converting `params` to map slice.
paramsMaps := Maps(params)
// If <params> is an empty slice, no conversion.
// If `params` is an empty slice, no conversion.
if len(paramsMaps) == 0 {
return nil
}

View File

@ -13,7 +13,7 @@ import (
"github.com/gogf/gf/os/gtime"
)
// Time converts <i> to time.Time.
// Time converts `i` to time.Time.
func Time(any interface{}, format ...string) time.Time {
// It's already this type.
if len(format) == 0 {
@ -27,9 +27,9 @@ func Time(any interface{}, format ...string) time.Time {
return time.Time{}
}
// Duration converts <i> to time.Duration.
// If <i> is string, then it uses time.ParseDuration to convert it.
// If <i> is numeric, then it converts <i> as nanoseconds.
// Duration converts `i` to time.Duration.
// If `i` is string, then it uses time.ParseDuration to convert it.
// If `i` is numeric, then it converts `i` as nanoseconds.
func Duration(any interface{}) time.Duration {
// It's already this type.
if v, ok := any.(time.Duration); ok {
@ -43,10 +43,10 @@ func Duration(any interface{}) time.Duration {
return time.Duration(Int64(any))
}
// GTime converts <i> to *gtime.Time.
// The parameter <format> can be used to specify the format of <i>.
// If no <format> given, it converts <i> using gtime.NewFromTimeStamp if <i> is numeric,
// or using gtime.StrToTime if <i> is string.
// GTime converts `i` to *gtime.Time.
// The parameter `format` can be used to specify the format of `i`.
// If no `format` given, it converts `i` using gtime.NewFromTimeStamp if `i` is numeric,
// or using gtime.StrToTime if `i` is string.
func GTime(any interface{}, format ...string) *gtime.Time {
if any == nil {
return nil

View File

@ -9,14 +9,14 @@ package gconv
import "unsafe"
// UnsafeStrToBytes converts string to []byte without memory copy.
// Note that, if you completely sure you will never use <s> variable in the feature,
// Note that, if you completely sure you will never use `s` variable in the feature,
// you can use this unsafe function to implement type conversion in high performance.
func UnsafeStrToBytes(s string) []byte {
return *(*[]byte)(unsafe.Pointer(&s))
}
// UnsafeBytesToStr converts []byte to string without memory copy.
// Note that, if you completely sure you will never use <b> variable in the feature,
// Note that, if you completely sure you will never use `b` variable in the feature,
// you can use this unsafe function to implement type conversion in high performance.
func UnsafeBytesToStr(b []byte) string {
return *(*string)(unsafe.Pointer(&b))

View File

@ -143,184 +143,46 @@ func Test_MapToMapDeep(t *testing.T) {
})
}
func Test_MapToMaps1(t *testing.T) {
func Test_MapToMaps(t *testing.T) {
params := g.Slice{
g.Map{"id": 1, "name": "john"},
g.Map{"id": 2, "name": "smith"},
}
gtest.C(t, func(t *gtest.T) {
var s []g.Map
err := gconv.MapToMaps(params, &s)
t.AssertNil(err)
t.Assert(len(s), 2)
t.Assert(s, params)
})
gtest.C(t, func(t *gtest.T) {
var s []*g.Map
err := gconv.MapToMaps(params, &s)
t.AssertNil(err)
t.Assert(len(s), 2)
t.Assert(s, params)
})
}
func Test_MapToMaps_StructParams(t *testing.T) {
type User struct {
Id int
Name int
}
params := g.Map{
"key1": g.Slice{
g.Map{"id": 1, "name": "john"},
g.Map{"id": 2, "name": "smith"},
},
"key2": g.Slice{
g.Map{"id": 3, "name": "green"},
g.Map{"id": 4, "name": "jim"},
},
}
gtest.C(t, func(t *gtest.T) {
m := make(map[string][]User)
err := gconv.MapToMaps(params, &m)
t.Assert(err, nil)
t.Assert(len(m), 2)
t.Assert(m["key1"][0].Id, 1)
t.Assert(m["key1"][1].Id, 2)
t.Assert(m["key2"][0].Id, 3)
t.Assert(m["key2"][1].Id, 4)
})
gtest.C(t, func(t *gtest.T) {
m := (map[string][]User)(nil)
err := gconv.MapToMaps(params, &m)
t.Assert(err, nil)
t.Assert(len(m), 2)
t.Assert(m["key1"][0].Id, 1)
t.Assert(m["key1"][1].Id, 2)
t.Assert(m["key2"][0].Id, 3)
t.Assert(m["key2"][1].Id, 4)
})
gtest.C(t, func(t *gtest.T) {
m := make(map[string][]*User)
err := gconv.MapToMaps(params, &m)
t.Assert(err, nil)
t.Assert(len(m), 2)
t.Assert(m["key1"][0].Id, 1)
t.Assert(m["key1"][1].Id, 2)
t.Assert(m["key2"][0].Id, 3)
t.Assert(m["key2"][1].Id, 4)
})
gtest.C(t, func(t *gtest.T) {
m := (map[string][]*User)(nil)
err := gconv.MapToMaps(params, &m)
t.Assert(err, nil)
t.Assert(len(m), 2)
t.Assert(m["key1"][0].Id, 1)
t.Assert(m["key1"][1].Id, 2)
t.Assert(m["key2"][0].Id, 3)
t.Assert(m["key2"][1].Id, 4)
})
}
func Test_MapToMaps2(t *testing.T) {
type User struct {
Id int
Name int
}
params := g.MapIntAny{
100: g.Slice{
g.Map{"id": 1, "name": "john"},
g.Map{"id": 2, "name": "smith"},
},
200: g.Slice{
g.Map{"id": 3, "name": "green"},
g.Map{"id": 4, "name": "jim"},
},
}
gtest.C(t, func(t *gtest.T) {
m := make(map[int][]User)
err := gconv.MapToMaps(params, &m)
t.Assert(err, nil)
t.Assert(len(m), 2)
t.Assert(m[100][0].Id, 1)
t.Assert(m[100][1].Id, 2)
t.Assert(m[200][0].Id, 3)
t.Assert(m[200][1].Id, 4)
})
gtest.C(t, func(t *gtest.T) {
m := make(map[int][]*User)
err := gconv.MapToMaps(params, &m)
t.Assert(err, nil)
t.Assert(len(m), 2)
t.Assert(m[100][0].Id, 1)
t.Assert(m[100][1].Id, 2)
t.Assert(m[200][0].Id, 3)
t.Assert(m[200][1].Id, 4)
})
gtest.C(t, func(t *gtest.T) {
m := make(map[string][]*User)
err := gconv.MapToMaps(params, &m)
t.Assert(err, nil)
t.Assert(len(m), 2)
t.Assert(m["100"][0].Id, 1)
t.Assert(m["100"][1].Id, 2)
t.Assert(m["200"][0].Id, 3)
t.Assert(m["200"][1].Id, 4)
})
}
func Test_MapToMaps3(t *testing.T) {
type Ids struct {
Id int
Uid int
}
type Base struct {
Ids
Time string
}
type User struct {
Base
Name string
}
params := g.MapIntAny{
100: g.Slice{
g.Map{"id": 1, "name": "john"},
g.Map{"id": 2, "name": "smith"},
},
200: g.Slice{
g.Map{"id": 3, "name": "green"},
g.Map{"id": 4, "name": "jim"},
},
params := g.Slice{
User{1, "name1"},
User{2, "name2"},
}
gtest.C(t, func(t *gtest.T) {
m := make(map[string][]*User)
err := gconv.MapToMaps(params, &m)
t.Assert(err, nil)
t.Assert(len(m), 2)
t.Assert(m["100"][0].Id, 1)
t.Assert(m["100"][1].Id, 2)
t.Assert(m["100"][0].Name, "john")
t.Assert(m["100"][1].Name, "smith")
t.Assert(m["200"][0].Id, 3)
t.Assert(m["200"][1].Id, 4)
t.Assert(m["200"][0].Name, "green")
t.Assert(m["200"][1].Name, "jim")
var s []g.Map
err := gconv.MapToMaps(params, &s)
t.AssertNil(err)
t.Assert(len(s), 2)
})
}
func Test_MapToMapsWithTag(t *testing.T) {
type Ids struct {
Id int
Uid int
}
type Base struct {
Ids `json:"ids"`
Time string
}
type User struct {
Base `json:"base"`
Name string
}
params := g.MapIntAny{
100: g.Slice{
g.Map{"id": 1, "name": "john"},
g.Map{"id": 2, "name": "smith"},
},
200: g.Slice{
g.Map{"id": 3, "name": "green"},
g.Map{"id": 4, "name": "jim"},
},
}
gtest.C(t, func(t *gtest.T) {
m := make(map[string][]*User)
err := gconv.MapToMaps(params, &m)
t.Assert(err, nil)
t.Assert(len(m), 2)
t.Assert(m["100"][0].Id, 1)
t.Assert(m["100"][1].Id, 2)
t.Assert(m["100"][0].Name, "john")
t.Assert(m["100"][1].Name, "smith")
t.Assert(m["200"][0].Id, 3)
t.Assert(m["200"][1].Id, 4)
t.Assert(m["200"][0].Name, "green")
t.Assert(m["200"][1].Name, "jim")
var s []*g.Map
err := gconv.MapToMaps(params, &s)
t.AssertNil(err)
t.Assert(len(s), 2)
})
}

View File

@ -13,7 +13,7 @@ import (
"testing"
)
func Test_Scan(t *testing.T) {
func Test_Scan_StructStructs(t *testing.T) {
type User struct {
Uid int
Name string
@ -76,7 +76,7 @@ func Test_Scan(t *testing.T) {
})
}
func Test_ScanStr(t *testing.T) {
func Test_Scan_StructStr(t *testing.T) {
type User struct {
Uid int
Name string
@ -123,3 +123,73 @@ func Test_ScanStr(t *testing.T) {
})
})
}
func Test_Scan_Map(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
var m map[string]string
data := g.Map{
"k1": "v1",
"k2": "v2",
}
err := gconv.Scan(data, &m)
t.AssertNil(err)
t.Assert(data, m)
})
gtest.C(t, func(t *gtest.T) {
var m map[int]int
data := g.Map{
"1": "11",
"2": "22",
}
err := gconv.Scan(data, &m)
t.AssertNil(err)
t.Assert(data, m)
})
// json string parameter.
gtest.C(t, func(t *gtest.T) {
var m map[string]string
data := `{"k1":"v1","k2":"v2"}`
err := gconv.Scan(data, &m)
t.AssertNil(err)
t.Assert(m, g.Map{
"k1": "v1",
"k2": "v2",
})
})
}
func Test_Scan_Maps(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
var maps []map[string]string
data := g.Slice{
g.Map{
"k1": "v1",
"k2": "v2",
},
g.Map{
"k3": "v3",
"k4": "v4",
},
}
err := gconv.Scan(data, &maps)
t.AssertNil(err)
t.Assert(data, maps)
})
// json string parameter.
gtest.C(t, func(t *gtest.T) {
var maps []map[string]string
data := `[{"k1":"v1","k2":"v2"},{"k3":"v3","k4":"v4"}]`
err := gconv.Scan(data, &maps)
t.AssertNil(err)
t.Assert(maps, g.Slice{
g.Map{
"k1": "v1",
"k2": "v2",
},
g.Map{
"k3": "v3",
"k4": "v4",
},
})
})
}

View File

@ -21,9 +21,9 @@ type Page struct {
TotalPage int // Total page, which is automatically calculated.
CurrentPage int // Current page number >= 1.
UrlTemplate string // Custom url template for page url producing.
LinkStyle string // CSS style name for HTML link tag <a>.
SpanStyle string // CSS style name for HTML span tag <span>, which is used for first, current and last page tag.
SelectStyle string // CSS style name for HTML select tag <select>.
LinkStyle string // CSS style name for HTML link tag `a`.
SpanStyle string // CSS style name for HTML span tag `span`, which is used for first, current and last page tag.
SelectStyle string // CSS style name for HTML select tag `select`.
NextPageTag string // Tag name for next p.
PrevPageTag string // Tag name for prev p.
FirstPageTag string // Tag name for first p.
@ -40,9 +40,9 @@ const (
)
// New creates and returns a pagination manager.
// Note that the parameter <urlTemplate> specifies the URL producing template, like:
// Note that the parameter `urlTemplate` specifies the URL producing template, like:
// /user/list/{.page}, /user/list/{.page}.html, /user/list?page={.page}&type=1, etc.
// The build-in variable in <urlTemplate> "{.page}" specifies the page number, which will be replaced by certain
// The build-in variable in `urlTemplate` "{.page}" specifies the page number, which will be replaced by certain
// page number when producing.
func New(totalSize, pageSize, currentPage int, urlTemplate string) *Page {
p := &Page{
@ -209,7 +209,7 @@ func (p *Page) GetUrl(page int) string {
return gstr.Replace(p.UrlTemplate, PAGE_PLACE_HOLDER, gconv.String(page))
}
// GetLink returns the HTML link tag <a> content for given page number.
// GetLink returns the HTML link tag `a` content for given page number.
func (p *Page) GetLink(page int, text, title string) string {
if len(p.AjaxActionName) > 0 {
return fmt.Sprintf(

View File

@ -109,7 +109,7 @@ func Test_PredefinedContent(t *testing.T) {
page.AjaxActionName = "LoadPage"
t.Assert(page.GetContent(1), `<a class="GPageLink" href="javascript:LoadPage('/user/list/1')" title="">上一页</a> <span class="current">2</span> <a class="GPageLink" href="javascript:LoadPage('/user/list/3')" title="">下一页</a>`)
t.Assert(page.GetContent(2), `<a class="GPageLink" href="javascript:LoadPage('/user/list/1')" title="">首页</a><a class="GPageLink" href="javascript:LoadPage('/user/list/1')" title=""><<上一页</a><span class="current">[第2页]</span><a class="GPageLink" href="javascript:LoadPage('/user/list/3')" title="">下一页>></a><a class="GPageLink" href="javascript:LoadPage('/user/list/5')" title="">尾页</a>第<select name="GPageSelect" onchange="window.location.href=this.value"><option value="/user/list/1">1</option><option value="/user/list/2" selected>2</option><option value="/user/list/3">3</option><option value="/user/list/4">4</option><option value="/user/list/5">5</option></select>页`)
t.Assert(page.GetContent(3), `<a class="GPageLink" href="javascript:LoadPage('/user/list/1')" title="">首页</a><a class="GPageLink" href="javascript:LoadPage('/user/list/1')" title="">上一页</a><a class="GPageLink" href="javascript:LoadPage('/user/list/1')" title="1">1</a><span class="GPageSpan">2</span><a class="GPageLink" href="javascript:LoadPage('/user/list/3')" title="3">3</a><a class="GPageLink" href="javascript:LoadPage('/user/list/4')" title="4">4</a><a class="GPageLink" href="javascript:LoadPage('/user/list/5')" title="5">5</a><a class="GPageLink" href="javascript:LoadPage('/user/list/3')" title="">下一页</a><a class="GPageLink" href="javascript:LoadPage('/user/list/5')" title="">尾页</a><span>当前页2/5</span> <span>共5条</span>`)
t.Assert(page.GetContent(3), `<a class="GPageLink" href="javascript:LoadPage('/user/list/1')" title="">首页</a><a class="GPageLink" href="javascript:LoadPage('/user/list/1')" title="">上一页</a><a class="GPageLink" href="javascript:LoadPage('/user/list/1')" title="1">1</a><span class="GPageSpan">2</span><a class="GPageLink" href="javascript:LoadPage('/user/list/3')" title="3">3</a><a class="GPageLink" href="javascript:LoadPage('/user/list/4')" title="4">4</a><a class="GPageLink" href="javascript:LoadPage('/user/list/5')" title="5">5</a><a class="GPageLink" href="javascript:LoadPage('/user/list/3')" title="">下一页</a><a class="GPageLink" href="javascript:LoadPage('/user/list/5')" title="">尾页</a>`span`当前页2/5</span> `span`共5条</span>`)
t.Assert(page.GetContent(4), `<a class="GPageLink" href="javascript:LoadPage('/user/list/1')" title="">首页</a><a class="GPageLink" href="javascript:LoadPage('/user/list/1')" title="">上一页</a><a class="GPageLink" href="javascript:LoadPage('/user/list/1')" title="1">1</a><span class="GPageSpan">2</span><a class="GPageLink" href="javascript:LoadPage('/user/list/3')" title="3">3</a><a class="GPageLink" href="javascript:LoadPage('/user/list/4')" title="4">4</a><a class="GPageLink" href="javascript:LoadPage('/user/list/5')" title="5">5</a><a class="GPageLink" href="javascript:LoadPage('/user/list/3')" title="">下一页</a><a class="GPageLink" href="javascript:LoadPage('/user/list/5')" title="">尾页</a>`)
t.Assert(page.GetContent(5), ``)
})

View File

@ -23,8 +23,8 @@ var (
// Intn returns a int number which is between 0 and max: [0, max).
//
// Note that:
// 1. The <max> can only be greater than 0, or else it returns <max> directly;
// 2. The result is greater than or equal to 0, but less than <max>;
// 1. The `max` can only be greater than 0, or else it returns `max` directly;
// 2. The result is greater than or equal to 0, but less than `max`;
// 3. The result number is 32bit and less than math.MaxUint32.
func Intn(max int) int {
if max <= 0 {
@ -37,7 +37,7 @@ func Intn(max int) int {
return n
}
// B retrieves and returns random bytes of given length <n>.
// B retrieves and returns random bytes of given length `n`.
func B(n int) []byte {
if n <= 0 {
return nil
@ -55,7 +55,7 @@ func B(n int) []byte {
}
// N returns a random int between min and max: [min, max].
// The <min> and <max> also support negative numbers.
// The `min` and `max` also support negative numbers.
func N(min, max int) int {
if min >= max {
return min
@ -77,8 +77,8 @@ func N(min, max int) int {
return 0
}
// S returns a random string which contains digits and letters, and its length is <n>.
// The optional parameter <symbols> specifies whether the result could contain symbols,
// S returns a random string which contains digits and letters, and its length is `n`.
// The optional parameter `symbols` specifies whether the result could contain symbols,
// which is false in default.
func S(n int, symbols ...bool) string {
if n <= 0 {
@ -112,7 +112,7 @@ func D(min, max time.Duration) time.Duration {
return time.Duration(n * multiple)
}
// Str randomly picks and returns <n> count of chars from given string <s>.
// Str randomly picks and returns `n` count of chars from given string `s`.
// It also supports unicode string like Chinese/Russian/Japanese, etc.
func Str(s string, n int) string {
if n <= 0 {
@ -135,7 +135,7 @@ func Str(s string, n int) string {
return string(b)
}
// Digits returns a random string which contains only digits, and its length is <n>.
// Digits returns a random string which contains only digits, and its length is `n`.
func Digits(n int) string {
if n <= 0 {
return ""
@ -150,7 +150,7 @@ func Digits(n int) string {
return *(*string)(unsafe.Pointer(&b))
}
// Letters returns a random string which contains only letters, and its length is <n>.
// Letters returns a random string which contains only letters, and its length is `n`.
func Letters(n int) string {
if n <= 0 {
return ""
@ -165,7 +165,7 @@ func Letters(n int) string {
return *(*string)(unsafe.Pointer(&b))
}
// Symbols returns a random string which contains only symbols, and its length is <n>.
// Symbols returns a random string which contains only symbols, and its length is `n`.
func Symbols(n int) string {
if n <= 0 {
return ""
@ -192,7 +192,7 @@ func Perm(n int) []int {
return m
}
// Meet randomly calculate whether the given probability <num>/<total> is met.
// Meet randomly calculate whether the given probability `num`/`total` is met.
func Meet(num, total int) bool {
return Intn(total) < num
}

View File

@ -50,11 +50,11 @@ func init() {
// S creates and returns a global unique string in 32 bytes that meets most common
// usages without strict UUID algorithm. It returns an unique string using default
// unique algorithm if no <data> is given.
// unique algorithm if no `data` is given.
//
// The specified <data> can be no more than 2 parts. No matter how long each of the
// <data> size is, each of them will be hashed into 7 bytes as part of the result.
// If given <data> parts is less than 2, the leftover size of the result bytes will
// The specified `data` can be no more than 2 parts. No matter how long each of the
// `data` size is, each of them will be hashed into 7 bytes as part of the result.
// If given `data` parts is less than 2, the leftover size of the result bytes will
// be token by random string.
//
// The returned string is composed with:
@ -63,7 +63,7 @@ func init() {
//
// Note that
// 1. The returned length is fixed to 32 bytes for performance purpose.
// 2. The custom parameter <data> composed should have unique attribute in your
// 2. The custom parameter `data` composed should have unique attribute in your
// business situation.
func S(data ...[]byte) string {
var (
@ -103,7 +103,7 @@ func getSequence() []byte {
return b
}
// getRandomStr randomly picks and returns <n> count of chars from randomStrBase.
// getRandomStr randomly picks and returns `n` count of chars from randomStrBase.
func getRandomStr(n int) []byte {
if n <= 0 {
return []byte{}

View File

@ -32,7 +32,7 @@ func Try(try func()) (err error) {
}
// TryCatch implements try...catch... logistics using internal panic...recover.
// It automatically calls function <catch> if any exception occurs ans passes the exception as an error.
// It automatically calls function `catch` if any exception occurs ans passes the exception as an error.
func TryCatch(try func(), catch ...func(exception error)) {
defer func() {
if exception := recover(); exception != nil && len(catch) > 0 {
@ -46,8 +46,8 @@ func TryCatch(try func(), catch ...func(exception error)) {
try()
}
// IsEmpty checks given <value> empty or not.
// It returns false if <value> is: integer(0), bool(false), slice/map(len=0), nil;
// IsEmpty checks given `value` empty or not.
// It returns false if `value` is: integer(0), bool(false), slice/map(len=0), nil;
// or else returns true.
func IsEmpty(value interface{}) bool {
return empty.IsEmpty(value)

View File

@ -10,16 +10,16 @@ import (
"reflect"
)
// ListItemValues retrieves and returns the elements of all item struct/map with key <key>.
// Note that the parameter <list> should be type of slice which contains elements of map or struct,
// ListItemValues retrieves and returns the elements of all item struct/map with key `key`.
// Note that the parameter `list` should be type of slice which contains elements of map or struct,
// or else it returns an empty slice.
//
// The parameter <list> supports types like:
// The parameter `list` supports types like:
// []map[string]interface{}
// []map[string]sub-map
// []struct
// []struct:sub-struct
// Note that the sub-map/sub-struct makes sense only if the optional parameter <subKey> is given.
// Note that the sub-map/sub-struct makes sense only if the optional parameter `subKey` is given.
func ListItemValues(list interface{}, key interface{}, subKey ...interface{}) (values []interface{}) {
var reflectValue reflect.Value
if v, ok := list.(reflect.Value); ok {
@ -58,8 +58,8 @@ func ListItemValues(list interface{}, key interface{}, subKey ...interface{}) (v
return
}
// ItemValue retrieves and returns its value of which name/attribute specified by <key>.
// The parameter <item> can be type of map/*map/struct/*struct.
// ItemValue retrieves and returns its value of which name/attribute specified by `key`.
// The parameter `item` can be type of map/*map/struct/*struct.
func ItemValue(item interface{}, key interface{}) (value interface{}, found bool) {
var reflectValue reflect.Value
if v, ok := item.(reflect.Value); ok {
@ -84,7 +84,7 @@ func ItemValue(item interface{}, key interface{}) (value interface{}, found bool
}
switch reflectKind {
case reflect.Array, reflect.Slice:
// The <key> must be type of string.
// The `key` must be type of string.
values := ListItemValues(reflectValue, keyValue.String())
if values == nil {
return nil, false
@ -99,7 +99,7 @@ func ItemValue(item interface{}, key interface{}) (value interface{}, found bool
}
case reflect.Struct:
// The <mapKey> must be type of string.
// The `mapKey` must be type of string.
v := reflectValue.FieldByName(keyValue.String())
if v.IsValid() {
found = true
@ -109,8 +109,8 @@ func ItemValue(item interface{}, key interface{}) (value interface{}, found bool
return
}
// ListItemValuesUnique retrieves and returns the unique elements of all struct/map with key <key>.
// Note that the parameter <list> should be type of slice which contains elements of map or struct,
// ListItemValuesUnique retrieves and returns the unique elements of all struct/map with key `key`.
// Note that the parameter `list` should be type of slice which contains elements of map or struct,
// or else it returns an empty slice.
func ListItemValuesUnique(list interface{}, key string, subKey ...interface{}) []interface{} {
values := ListItemValues(list, key, subKey...)

View File

@ -11,7 +11,7 @@ import (
"reflect"
)
// MapCopy does a shallow copy from map <data> to <copy> for most commonly used map type
// MapCopy does a shallow copy from map `data` to `copy` for most commonly used map type
// map[string]interface{}.
func MapCopy(data map[string]interface{}) (copy map[string]interface{}) {
copy = make(map[string]interface{}, len(data))
@ -21,7 +21,7 @@ func MapCopy(data map[string]interface{}) (copy map[string]interface{}) {
return
}
// MapContains checks whether map <data> contains <key>.
// MapContains checks whether map `data` contains `key`.
func MapContains(data map[string]interface{}, key string) (ok bool) {
if len(data) == 0 {
return
@ -30,7 +30,7 @@ func MapContains(data map[string]interface{}, key string) (ok bool) {
return
}
// MapDelete deletes all <keys> from map <data>.
// MapDelete deletes all `keys` from map `data`.
func MapDelete(data map[string]interface{}, keys ...string) {
if len(data) == 0 {
return
@ -40,7 +40,7 @@ func MapDelete(data map[string]interface{}, keys ...string) {
}
}
// MapMerge merges all map from <src> to map <dst>.
// MapMerge merges all map from `src` to map `dst`.
func MapMerge(dst map[string]interface{}, src ...map[string]interface{}) {
if dst == nil {
return
@ -52,7 +52,7 @@ func MapMerge(dst map[string]interface{}, src ...map[string]interface{}) {
}
}
// MapMergeCopy creates and returns a new map which merges all map from <src>.
// MapMergeCopy creates and returns a new map which merges all map from `src`.
func MapMergeCopy(src ...map[string]interface{}) (copy map[string]interface{}) {
copy = make(map[string]interface{})
for _, m := range src {
@ -82,7 +82,7 @@ func MapPossibleItemByKey(data map[string]interface{}, key string) (foundKey str
return "", nil
}
// MapContainsPossibleKey checks if the given <key> is contained in given map <data>.
// MapContainsPossibleKey checks if the given `key` is contained in given map `data`.
// It checks the key ignoring cases and symbols.
//
// Note that this function might be of low performance.

View File

@ -11,7 +11,7 @@ import (
"reflect"
)
// SliceCopy does a shallow copy of slice <data> for most commonly used slice type
// SliceCopy does a shallow copy of slice `data` for most commonly used slice type
// []interface{}.
func SliceCopy(data []interface{}) []interface{} {
newData := make([]interface{}, len(data))
@ -19,8 +19,8 @@ func SliceCopy(data []interface{}) []interface{} {
return newData
}
// SliceDelete deletes an element at <index> and returns the new slice.
// It does nothing if the given <index> is invalid.
// SliceDelete deletes an element at `index` and returns the new slice.
// It does nothing if the given `index` is invalid.
func SliceDelete(data []interface{}, index int) (newSlice []interface{}) {
if index < 0 || index >= len(data) {
return data

View File

@ -163,12 +163,12 @@ var (
// Check checks single value with specified rules.
// It returns nil if successful validation.
//
// The parameter <value> can be any type of variable, which will be converted to string
// The parameter `value` can be any type of variable, which will be converted to string
// for validation.
// The parameter <rules> can be one or more rules, multiple rules joined using char '|'.
// The parameter <messages> specifies the custom error messages, which can be type of:
// The parameter `rules` can be one or more rules, multiple rules joined using char '|'.
// The parameter `messages` specifies the custom error messages, which can be type of:
// string/map/struct/*struct.
// The optional parameter <params> specifies the extra validation parameters for some rules
// The optional parameter `params` specifies the extra validation parameters for some rules
// like: required-*、same、different, etc.
func Check(value interface{}, rules string, messages interface{}, params ...interface{}) *Error {
return defaultValidator.Check(value, rules, messages, params...)
@ -176,19 +176,19 @@ func Check(value interface{}, rules string, messages interface{}, params ...inte
// CheckMap validates map and returns the error result. It returns nil if with successful validation.
//
// The parameter <rules> can be type of []string/map[string]string. It supports sequence in error result
// if <rules> is type of []string.
// The optional parameter <messages> specifies the custom error messages for specified keys and rules.
// The parameter `rules` can be type of []string/map[string]string. It supports sequence in error result
// if `rules` is type of []string.
// The optional parameter `messages` specifies the custom error messages for specified keys and rules.
func CheckMap(params interface{}, rules interface{}, messages ...CustomMsg) *Error {
return defaultValidator.CheckMap(params, rules, messages...)
}
// CheckStruct validates strcut and returns the error result.
//
// The parameter <object> should be type of struct/*struct.
// The parameter <rules> can be type of []string/map[string]string. It supports sequence in error result
// if <rules> is type of []string.
// The optional parameter <messages> specifies the custom error messages for specified keys and rules.
// The parameter `object` should be type of struct/*struct.
// The parameter `rules` can be type of []string/map[string]string. It supports sequence in error result
// if `rules` is type of []string.
// The optional parameter `messages` specifies the custom error messages for specified keys and rules.
func CheckStruct(object interface{}, rules interface{}, messages ...CustomMsg) *Error {
return defaultValidator.CheckStruct(object, rules, messages...)
}

View File

@ -7,10 +7,10 @@
package gvalid
// RuleFunc is the custom function for data validation.
// The parameter <rule> specifies the validation rule string, like "required", "between:1,100", etc.
// The parameter <value> specifies the value for this rule to validate.
// The parameter <message> specifies the custom error message or configured i18n message for this rule.
// The parameter <params> specifies all the parameters that needs. You can ignore parameter <params> if
// The parameter `rule` specifies the validation rule string, like "required", "between:1,100", etc.
// The parameter `value` specifies the value for this rule to validate.
// The parameter `message` specifies the custom error message or configured i18n message for this rule.
// The parameter `params` specifies all the parameters that needs. You can ignore parameter `params` if
// you do not really need it in your custom validation rule.
type RuleFunc func(rule string, value interface{}, message string, params map[string]interface{}) error

View File

@ -21,12 +21,12 @@ import (
// Check checks single value with specified rules.
// It returns nil if successful validation.
//
// The parameter <value> can be any type of variable, which will be converted to string
// The parameter `value` can be any type of variable, which will be converted to string
// for validation.
// The parameter <rules> can be one or more rules, multiple rules joined using char '|'.
// The parameter <messages> specifies the custom error messages, which can be type of:
// The parameter `rules` can be one or more rules, multiple rules joined using char '|'.
// The parameter `messages` specifies the custom error messages, which can be type of:
// string/map/struct/*struct.
// The optional parameter <params> specifies the extra validation parameters for some rules
// The optional parameter `params` specifies the extra validation parameters for some rules
// like: required-*、same、different, etc.
func (v *Validator) Check(value interface{}, rules string, messages interface{}, params ...interface{}) *Error {
return v.doCheck("", value, rules, messages, params...)

View File

@ -13,9 +13,9 @@ import (
// CheckMap validates map and returns the error result. It returns nil if with successful validation.
//
// The parameter <rules> can be type of []string/map[string]string. It supports sequence in error result
// if <rules> is type of []string.
// The optional parameter <messages> specifies the custom error messages for specified keys and rules.
// The parameter `rules` can be type of []string/map[string]string. It supports sequence in error result
// if `rules` is type of []string.
// The optional parameter `messages` specifies the custom error messages for specified keys and rules.
func (v *Validator) CheckMap(params interface{}, rules interface{}, messages ...CustomMsg) *Error {
// If there's no validation rules, it does nothing and returns quickly.
if params == nil || rules == nil {

View File

@ -20,10 +20,10 @@ var (
// CheckStruct validates struct and returns the error result.
//
// The parameter <object> should be type of struct/*struct.
// The parameter <rules> can be type of []string/map[string]string. It supports sequence in error result
// if <rules> is type of []string.
// The optional parameter <messages> specifies the custom error messages for specified keys and rules.
// The parameter `object` should be type of struct/*struct.
// The parameter `rules` can be type of []string/map[string]string. It supports sequence in error result
// if `rules` is type of []string.
// The optional parameter `messages` specifies the custom error messages for specified keys and rules.
func (v *Validator) CheckStruct(object interface{}, rules interface{}, messages ...CustomMsg) *Error {
var (
errorMaps = make(ErrorMap) // Returned error.
@ -56,7 +56,7 @@ func (v *Validator) CheckStruct(object interface{}, rules interface{}, messages
params = make(map[string]interface{})
checkRules = make(map[string]string)
customMessage = make(CustomMsg)
fieldAliases = make(map[string]string) // Alias names for <messages> overwriting struct tag names.
fieldAliases = make(map[string]string) // Alias names for `messages` overwriting struct tag names.
errorRules = make([]string, 0) // Sequence rules.
)
switch v := rules.(type) {
@ -159,7 +159,7 @@ func (v *Validator) CheckStruct(object interface{}, rules interface{}, messages
}
// Custom error messages,
// which have the most priority than <rules> and struct tag.
// which have the most priority than `rules` and struct tag.
if len(messages) > 0 && len(messages[0]) > 0 {
for k, v := range messages[0] {
if a, ok := fieldAliases[k]; ok {

View File

@ -12,7 +12,7 @@ import (
"strings"
)
// checkLength checks <value> using length rules.
// checkLength checks `value` using length rules.
// The length is calculated using unicode string, which means one chinese character or letter
// both has the length of 1.
func (v *Validator) checkLength(value, ruleKey, ruleVal string, customMsgMap map[string]string) string {

View File

@ -6,7 +6,7 @@
package gvalid
// checkLuHn checks <value> with LUHN algorithm.
// checkLuHn checks `value` with LUHN algorithm.
// It's usually used for bank card number validation.
func (v *Validator) checkLuHn(value string) bool {
var (

View File

@ -11,7 +11,7 @@ import (
"strings"
)
// checkRange checks <value> using range rules.
// checkRange checks `value` using range rules.
func (v *Validator) checkRange(value, ruleKey, ruleVal string, customMsgMap map[string]string) string {
msg := ""
switch ruleKey {

View File

@ -12,7 +12,7 @@ import (
"strings"
)
// checkRequired checks <value> using required rules.
// checkRequired checks `value` using required rules.
// It also supports require checks for `value` of type: slice, map.
func (v *Validator) checkRequired(value interface{}, ruleKey, rulePattern string, params map[string]string) bool {
required := false