diff --git a/cmd/gf/internal/cmd/cmd_gen_dao.go b/cmd/gf/internal/cmd/cmd_gen_dao.go index b5674d62b..4528da444 100644 --- a/cmd/gf/internal/cmd/cmd_gen_dao.go +++ b/cmd/gf/internal/cmd/cmd_gen_dao.go @@ -512,11 +512,12 @@ func generateDaoInternal( } func replaceDefaultVar(in cGenDaoInternalInput, origin string) string { - if !in.WithTime { - return origin + var tplDatetimeStr string + if in.WithTime { + tplDatetimeStr = fmt.Sprintf(`Created at %s`, createdAt.String()) } return gstr.ReplaceByMap(origin, g.MapStrStr{ - tplVarDatetimeStr: createdAt.String(), + tplVarDatetimeStr: tplDatetimeStr, }) } diff --git a/util/gconv/gconv_struct.go b/util/gconv/gconv_struct.go index aaddf01be..628baf3c5 100644 --- a/util/gconv/gconv_struct.go +++ b/util/gconv/gconv_struct.go @@ -453,51 +453,84 @@ func bindVarToReflectValue(structFieldValue reflect.Value, value interface{}, ma // Note that the slice element might be type of struct, // so it uses Struct function doing the converting internally. case reflect.Slice, reflect.Array: - a := reflect.Value{} - v := reflect.ValueOf(value) - if v.Kind() == reflect.Slice || v.Kind() == reflect.Array { - a = reflect.MakeSlice(structFieldValue.Type(), v.Len(), v.Len()) - if v.Len() > 0 { - t := a.Index(0).Type() - for i := 0; i < v.Len(); i++ { - if t.Kind() == reflect.Ptr { - e := reflect.New(t.Elem()).Elem() - if err = doStruct(v.Index(i).Interface(), e, nil, ""); err != nil { - // Note there's reflect conversion mechanism here. - e.Set(reflect.ValueOf(v.Index(i).Interface()).Convert(t)) - } - a.Index(i).Set(e.Addr()) - } else { - e := reflect.New(t).Elem() - if err = doStruct(v.Index(i).Interface(), e, nil, ""); err != nil { - // Note there's reflect conversion mechanism here. - e.Set(reflect.ValueOf(v.Index(i).Interface()).Convert(t)) - } - a.Index(i).Set(e) + var ( + reflectArray reflect.Value + reflectValue = reflect.ValueOf(value) + ) + if reflectValue.Kind() == reflect.Slice || reflectValue.Kind() == reflect.Array { + reflectArray = reflect.MakeSlice(structFieldValue.Type(), reflectValue.Len(), reflectValue.Len()) + if reflectValue.Len() > 0 { + var ( + elemType = reflectArray.Index(0).Type() + elemTypeName string + converted bool + ) + for i := 0; i < reflectValue.Len(); i++ { + converted = false + elemTypeName = elemType.Name() + if elemTypeName == "" { + elemTypeName = elemType.String() } + var elem reflect.Value + if elemType.Kind() == reflect.Ptr { + elem = reflect.New(elemType.Elem()).Elem() + } else { + elem = reflect.New(elemType).Elem() + } + if elem.Kind() == reflect.Struct { + if err = doStruct(reflectValue.Index(i).Interface(), elem, nil, ""); err == nil { + converted = true + } + } + if !converted { + elem.Set(reflect.ValueOf(doConvert(doConvertInput{ + FromValue: reflectValue.Index(i).Interface(), + ToTypeName: elemTypeName, + ReferValue: elem, + }))) + } + if elemType.Kind() == reflect.Ptr { + // Before it sets the `elem` to array, do pointer converting if necessary. + elem = elem.Addr() + } + reflectArray.Index(i).Set(elem) } } } else { - a = reflect.MakeSlice(structFieldValue.Type(), 1, 1) - t := a.Index(0).Type() - if t.Kind() == reflect.Ptr { - // Pointer element. - e := reflect.New(t.Elem()).Elem() - if err = doStruct(value, e, nil, ""); err != nil { - // Note there's reflect conversion mechanism here. - e.Set(reflect.ValueOf(value).Convert(t)) - } - a.Index(0).Set(e.Addr()) - } else { - // Just consider it as struct element. (Although it might be other types but not basic types, eg: map) - e := reflect.New(t).Elem() - if err = doStruct(value, e, nil, ""); err != nil { - return err - } - a.Index(0).Set(e) + reflectArray = reflect.MakeSlice(structFieldValue.Type(), 1, 1) + var ( + elem reflect.Value + elemType = reflectArray.Index(0).Type() + elemTypeName = elemType.Name() + converted bool + ) + if elemTypeName == "" { + elemTypeName = elemType.String() } + if elemType.Kind() == reflect.Ptr { + elem = reflect.New(elemType.Elem()).Elem() + } else { + elem = reflect.New(elemType).Elem() + } + if elem.Kind() == reflect.Struct { + if err = doStruct(value, elem, nil, ""); err == nil { + converted = true + } + } + if !converted { + elem.Set(reflect.ValueOf(doConvert(doConvertInput{ + FromValue: value, + ToTypeName: elemTypeName, + ReferValue: elem, + }))) + } + if elemType.Kind() == reflect.Ptr { + // Before it sets the `elem` to array, do pointer converting if necessary. + elem = elem.Addr() + } + reflectArray.Index(0).Set(elem) } - structFieldValue.Set(a) + structFieldValue.Set(reflectArray) case reflect.Ptr: item := reflect.New(structFieldValue.Type().Elem()) diff --git a/util/gconv/gconv_z_unit_struct_test.go b/util/gconv/gconv_z_unit_struct_test.go index c91a66468..50b4a17f2 100644 --- a/util/gconv/gconv_z_unit_struct_test.go +++ b/util/gconv/gconv_z_unit_struct_test.go @@ -356,7 +356,7 @@ func Test_Struct_Attr_CustomType2(t *testing.T) { gtest.C(t, func(t *gtest.T) { user := new(User) err := gconv.Struct(g.Map{"id": g.Slice{1, 2}, "name": "john"}, user) - t.Assert(err, nil) + t.AssertNil(err) t.Assert(user.Id, g.Slice{1, 2}) t.Assert(user.Name, "john") }) @@ -1301,3 +1301,22 @@ func Test_Struct_Issue1597(t *testing.T) { t.Assert(s.B, `{"c":3}`) }) } + +func Test_Scan_WithDoubleSliceAttribute(t *testing.T) { + inputData := [][]string{ + {"aa", "bb", "cc"}, + {"11", "22", "33"}, + } + data := struct { + Data [][]string + }{ + Data: inputData, + } + gtest.C(t, func(t *gtest.T) { + jv := gjson.New(gjson.MustEncodeString(data)) + err := jv.Scan(&data) + t.AssertNil(err) + t.Assert(data.Data, inputData) + }) + +}