123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828 |
- package copier
- import (
- "database/sql"
- "database/sql/driver"
- "fmt"
- "reflect"
- "strings"
- "sync"
- "unicode"
- )
- // These flags define options for tag handling
- const (
- // Denotes that a destination field must be copied to. If copying fails then a panic will ensue.
- tagMust uint8 = 1 << iota
- // Denotes that the program should not panic when the must flag is on and
- // value is not copied. The program will return an error instead.
- tagNoPanic
- // Ignore a destination field from being copied to.
- tagIgnore
- // Denotes that the value as been copied
- hasCopied
- // Some default converter types for a nicer syntax
- String string = ""
- Bool bool = false
- Int int = 0
- Float32 float32 = 0
- Float64 float64 = 0
- )
- // Option sets copy options
- type Option struct {
- // setting this value to true will ignore copying zero values of all the fields, including bools, as well as a
- // struct having all it's fields set to their zero values respectively (see IsZero() in reflect/value.go)
- IgnoreEmpty bool
- CaseSensitive bool
- DeepCopy bool
- Converters []TypeConverter
- // Custom field name mappings to copy values with different names in `fromValue` and `toValue` types.
- // Examples can be found in `copier_field_name_mapping_test.go`.
- FieldNameMapping []FieldNameMapping
- }
- func (opt Option) converters() map[converterPair]TypeConverter {
- var converters = map[converterPair]TypeConverter{}
- // save converters into map for faster lookup
- for i := range opt.Converters {
- pair := converterPair{
- SrcType: reflect.TypeOf(opt.Converters[i].SrcType),
- DstType: reflect.TypeOf(opt.Converters[i].DstType),
- }
- converters[pair] = opt.Converters[i]
- }
- return converters
- }
- type TypeConverter struct {
- SrcType interface{}
- DstType interface{}
- Fn func(src interface{}) (dst interface{}, err error)
- }
- type converterPair struct {
- SrcType reflect.Type
- DstType reflect.Type
- }
- func (opt Option) fieldNameMapping() map[converterPair]FieldNameMapping {
- var mapping = map[converterPair]FieldNameMapping{}
- for i := range opt.FieldNameMapping {
- pair := converterPair{
- SrcType: reflect.TypeOf(opt.FieldNameMapping[i].SrcType),
- DstType: reflect.TypeOf(opt.FieldNameMapping[i].DstType),
- }
- mapping[pair] = opt.FieldNameMapping[i]
- }
- return mapping
- }
- type FieldNameMapping struct {
- SrcType interface{}
- DstType interface{}
- Mapping map[string]string
- }
- // Tag Flags
- type flags struct {
- BitFlags map[string]uint8
- SrcNames tagNameMapping
- DestNames tagNameMapping
- }
- // Field Tag name mapping
- type tagNameMapping struct {
- FieldNameToTag map[string]string
- TagToFieldName map[string]string
- }
- // Copy copy things
- func Copy(toValue interface{}, fromValue interface{}) (err error) {
- return copier(toValue, fromValue, Option{})
- }
- // CopyWithOption copy with option
- func CopyWithOption(toValue interface{}, fromValue interface{}, opt Option) (err error) {
- return copier(toValue, fromValue, opt)
- }
- func copier(toValue interface{}, fromValue interface{}, opt Option) (err error) {
- var (
- isSlice bool
- amount = 1
- from = indirect(reflect.ValueOf(fromValue))
- to = indirect(reflect.ValueOf(toValue))
- converters = opt.converters()
- mappings = opt.fieldNameMapping()
- )
- if !to.CanAddr() {
- return ErrInvalidCopyDestination
- }
- // Return is from value is invalid
- if !from.IsValid() {
- return ErrInvalidCopyFrom
- }
- fromType, isPtrFrom := indirectType(from.Type())
- toType, _ := indirectType(to.Type())
- if fromType.Kind() == reflect.Interface {
- fromType = reflect.TypeOf(from.Interface())
- }
- if toType.Kind() == reflect.Interface {
- toType, _ = indirectType(reflect.TypeOf(to.Interface()))
- oldTo := to
- to = reflect.New(reflect.TypeOf(to.Interface())).Elem()
- defer func() {
- oldTo.Set(to)
- }()
- }
- // Just set it if possible to assign for normal types
- if from.Kind() != reflect.Slice && from.Kind() != reflect.Struct && from.Kind() != reflect.Map && (from.Type().AssignableTo(to.Type()) || from.Type().ConvertibleTo(to.Type())) {
- if !isPtrFrom || !opt.DeepCopy {
- to.Set(from.Convert(to.Type()))
- } else {
- fromCopy := reflect.New(from.Type())
- fromCopy.Set(from.Elem())
- to.Set(fromCopy.Convert(to.Type()))
- }
- return
- }
- if from.Kind() != reflect.Slice && fromType.Kind() == reflect.Map && toType.Kind() == reflect.Map {
- if !fromType.Key().ConvertibleTo(toType.Key()) {
- return ErrMapKeyNotMatch
- }
- if to.IsNil() {
- to.Set(reflect.MakeMapWithSize(toType, from.Len()))
- }
- for _, k := range from.MapKeys() {
- toKey := indirect(reflect.New(toType.Key()))
- isSet, err := set(toKey, k, opt.DeepCopy, converters)
- if err != nil {
- return err
- }
- if !isSet {
- return fmt.Errorf("%w map, old key: %v, new key: %v", ErrNotSupported, k.Type(), toType.Key())
- }
- elemType := toType.Elem()
- if elemType.Kind() != reflect.Slice {
- elemType, _ = indirectType(elemType)
- }
- toValue := indirect(reflect.New(elemType))
- isSet, err = set(toValue, from.MapIndex(k), opt.DeepCopy, converters)
- if err != nil {
- return err
- }
- if !isSet {
- if err = copier(toValue.Addr().Interface(), from.MapIndex(k).Interface(), opt); err != nil {
- return err
- }
- }
- for {
- if elemType == toType.Elem() {
- to.SetMapIndex(toKey, toValue)
- break
- }
- elemType = reflect.PtrTo(elemType)
- toValue = toValue.Addr()
- }
- }
- return
- }
- if from.Kind() == reflect.Slice && to.Kind() == reflect.Slice {
- if to.IsNil() {
- slice := reflect.MakeSlice(reflect.SliceOf(to.Type().Elem()), from.Len(), from.Cap())
- to.Set(slice)
- }
- if fromType.ConvertibleTo(toType) {
- for i := 0; i < from.Len(); i++ {
- if to.Len() < i+1 {
- to.Set(reflect.Append(to, reflect.New(to.Type().Elem()).Elem()))
- }
- isSet, err := set(to.Index(i), from.Index(i), opt.DeepCopy, converters)
- if err != nil {
- return err
- }
- if !isSet {
- // ignore error while copy slice element
- err = copier(to.Index(i).Addr().Interface(), from.Index(i).Interface(), opt)
- if err != nil {
- continue
- }
- }
- }
- return
- }
- }
- if fromType.Kind() != reflect.Struct || toType.Kind() != reflect.Struct {
- // skip not supported type
- return
- }
- if len(converters) > 0 {
- if ok, e := set(to, from, opt.DeepCopy, converters); e == nil && ok {
- // converter supported
- return
- }
- }
- if from.Kind() == reflect.Slice || to.Kind() == reflect.Slice {
- isSlice = true
- if from.Kind() == reflect.Slice {
- amount = from.Len()
- }
- }
- for i := 0; i < amount; i++ {
- var dest, source reflect.Value
- if isSlice {
- // source
- if from.Kind() == reflect.Slice {
- source = indirect(from.Index(i))
- } else {
- source = indirect(from)
- }
- // dest
- dest = indirect(reflect.New(toType).Elem())
- } else {
- source = indirect(from)
- dest = indirect(to)
- }
- if len(converters) > 0 {
- if ok, e := set(dest, source, opt.DeepCopy, converters); e == nil && ok {
- if isSlice {
- // FIXME: maybe should check the other types?
- if to.Type().Elem().Kind() == reflect.Ptr {
- to.Index(i).Set(dest.Addr())
- } else {
- if to.Len() < i+1 {
- reflect.Append(to, dest)
- } else {
- to.Index(i).Set(dest)
- }
- }
- } else {
- to.Set(dest)
- }
- continue
- }
- }
- destKind := dest.Kind()
- initDest := false
- if destKind == reflect.Interface {
- initDest = true
- dest = indirect(reflect.New(toType))
- }
- // Get tag options
- flgs, err := getFlags(dest, source, toType, fromType)
- if err != nil {
- return err
- }
- // check source
- if source.IsValid() {
- copyUnexportedStructFields(dest, source)
- // Copy from source field to dest field or method
- fromTypeFields := deepFields(fromType)
- for _, field := range fromTypeFields {
- name := field.Name
- // Get bit flags for field
- fieldFlags := flgs.BitFlags[name]
- // Check if we should ignore copying
- if (fieldFlags & tagIgnore) != 0 {
- continue
- }
- fieldNamesMapping := getFieldNamesMapping(mappings, fromType, toType)
- srcFieldName, destFieldName := getFieldName(name, flgs, fieldNamesMapping)
- if fromField := fieldByNameOrZeroValue(source, srcFieldName); fromField.IsValid() && !shouldIgnore(fromField, opt.IgnoreEmpty) {
- // process for nested anonymous field
- destFieldNotSet := false
- if f, ok := dest.Type().FieldByName(destFieldName); ok {
- // only initialize parent embedded struct pointer in the path
- for idx := range f.Index[:len(f.Index)-1] {
- destField := dest.FieldByIndex(f.Index[:idx+1])
- if destField.Kind() != reflect.Ptr {
- continue
- }
- if !destField.IsNil() {
- continue
- }
- if !destField.CanSet() {
- destFieldNotSet = true
- break
- }
- // destField is a nil pointer that can be set
- newValue := reflect.New(destField.Type().Elem())
- destField.Set(newValue)
- }
- }
- if destFieldNotSet {
- break
- }
- toField := fieldByName(dest, destFieldName, opt.CaseSensitive)
- if toField.IsValid() {
- if toField.CanSet() {
- isSet, err := set(toField, fromField, opt.DeepCopy, converters)
- if err != nil {
- return err
- }
- if !isSet {
- if err := copier(toField.Addr().Interface(), fromField.Interface(), opt); err != nil {
- return err
- }
- }
- if fieldFlags != 0 {
- // Note that a copy was made
- flgs.BitFlags[name] = fieldFlags | hasCopied
- }
- }
- } else {
- // try to set to method
- var toMethod reflect.Value
- if dest.CanAddr() {
- toMethod = dest.Addr().MethodByName(destFieldName)
- } else {
- toMethod = dest.MethodByName(destFieldName)
- }
- if toMethod.IsValid() && toMethod.Type().NumIn() == 1 && fromField.Type().AssignableTo(toMethod.Type().In(0)) {
- toMethod.Call([]reflect.Value{fromField})
- }
- }
- }
- }
- // Copy from from method to dest field
- for _, field := range deepFields(toType) {
- name := field.Name
- srcFieldName, destFieldName := getFieldName(name, flgs, getFieldNamesMapping(mappings, fromType, toType))
- var fromMethod reflect.Value
- if source.CanAddr() {
- fromMethod = source.Addr().MethodByName(srcFieldName)
- } else {
- fromMethod = source.MethodByName(srcFieldName)
- }
- if fromMethod.IsValid() && fromMethod.Type().NumIn() == 0 && fromMethod.Type().NumOut() == 1 && !shouldIgnore(fromMethod, opt.IgnoreEmpty) {
- if toField := fieldByName(dest, destFieldName, opt.CaseSensitive); toField.IsValid() && toField.CanSet() {
- values := fromMethod.Call([]reflect.Value{})
- if len(values) >= 1 {
- set(toField, values[0], opt.DeepCopy, converters)
- }
- }
- }
- }
- }
- if isSlice && to.Kind() == reflect.Slice {
- if dest.Addr().Type().AssignableTo(to.Type().Elem()) {
- if to.Len() < i+1 {
- to.Set(reflect.Append(to, dest.Addr()))
- } else {
- isSet, err := set(to.Index(i), dest.Addr(), opt.DeepCopy, converters)
- if err != nil {
- return err
- }
- if !isSet {
- // ignore error while copy slice element
- err = copier(to.Index(i).Addr().Interface(), dest.Addr().Interface(), opt)
- if err != nil {
- continue
- }
- }
- }
- } else if dest.Type().AssignableTo(to.Type().Elem()) {
- if to.Len() < i+1 {
- to.Set(reflect.Append(to, dest))
- } else {
- isSet, err := set(to.Index(i), dest, opt.DeepCopy, converters)
- if err != nil {
- return err
- }
- if !isSet {
- // ignore error while copy slice element
- err = copier(to.Index(i).Addr().Interface(), dest.Interface(), opt)
- if err != nil {
- continue
- }
- }
- }
- }
- } else if initDest {
- to.Set(dest)
- }
- err = checkBitFlags(flgs.BitFlags)
- }
- return
- }
- func getFieldNamesMapping(mappings map[converterPair]FieldNameMapping, fromType reflect.Type, toType reflect.Type) map[string]string {
- var fieldNamesMapping map[string]string
- if len(mappings) > 0 {
- pair := converterPair{
- SrcType: fromType,
- DstType: toType,
- }
- if v, ok := mappings[pair]; ok {
- fieldNamesMapping = v.Mapping
- }
- }
- return fieldNamesMapping
- }
- func fieldByNameOrZeroValue(source reflect.Value, fieldName string) (value reflect.Value) {
- defer func() {
- if err := recover(); err != nil {
- value = reflect.Value{}
- }
- }()
- return source.FieldByName(fieldName)
- }
- func copyUnexportedStructFields(to, from reflect.Value) {
- if from.Kind() != reflect.Struct || to.Kind() != reflect.Struct || !from.Type().AssignableTo(to.Type()) {
- return
- }
- // create a shallow copy of 'to' to get all fields
- tmp := indirect(reflect.New(to.Type()))
- tmp.Set(from)
- // revert exported fields
- for i := 0; i < to.NumField(); i++ {
- if tmp.Field(i).CanSet() {
- tmp.Field(i).Set(to.Field(i))
- }
- }
- to.Set(tmp)
- }
- func shouldIgnore(v reflect.Value, ignoreEmpty bool) bool {
- return ignoreEmpty && v.IsZero()
- }
- var deepFieldsLock sync.RWMutex
- var deepFieldsMap = make(map[reflect.Type][]reflect.StructField)
- func deepFields(reflectType reflect.Type) []reflect.StructField {
- deepFieldsLock.RLock()
- cache, ok := deepFieldsMap[reflectType]
- deepFieldsLock.RUnlock()
- if ok {
- return cache
- }
- var res []reflect.StructField
- if reflectType, _ = indirectType(reflectType); reflectType.Kind() == reflect.Struct {
- fields := make([]reflect.StructField, 0, reflectType.NumField())
- for i := 0; i < reflectType.NumField(); i++ {
- v := reflectType.Field(i)
- // PkgPath is the package path that qualifies a lower case (unexported)
- // field name. It is empty for upper case (exported) field names.
- // See https://golang.org/ref/spec#Uniqueness_of_identifiers
- if v.PkgPath == "" {
- fields = append(fields, v)
- if v.Anonymous {
- // also consider fields of anonymous fields as fields of the root
- fields = append(fields, deepFields(v.Type)...)
- }
- }
- }
- res = fields
- }
- deepFieldsLock.Lock()
- deepFieldsMap[reflectType] = res
- deepFieldsLock.Unlock()
- return res
- }
- func indirect(reflectValue reflect.Value) reflect.Value {
- for reflectValue.Kind() == reflect.Ptr {
- reflectValue = reflectValue.Elem()
- }
- return reflectValue
- }
- func indirectType(reflectType reflect.Type) (_ reflect.Type, isPtr bool) {
- for reflectType.Kind() == reflect.Ptr || reflectType.Kind() == reflect.Slice {
- reflectType = reflectType.Elem()
- isPtr = true
- }
- return reflectType, isPtr
- }
- func set(to, from reflect.Value, deepCopy bool, converters map[converterPair]TypeConverter) (bool, error) {
- if !from.IsValid() {
- return true, nil
- }
- if ok, err := lookupAndCopyWithConverter(to, from, converters); err != nil {
- return false, err
- } else if ok {
- return true, nil
- }
- if to.Kind() == reflect.Ptr {
- // set `to` to nil if from is nil
- if from.Kind() == reflect.Ptr && from.IsNil() {
- to.Set(reflect.Zero(to.Type()))
- return true, nil
- } else if to.IsNil() {
- // `from` -> `to`
- // sql.NullString -> *string
- if fromValuer, ok := driverValuer(from); ok {
- v, err := fromValuer.Value()
- if err != nil {
- return true, nil
- }
- // if `from` is not valid do nothing with `to`
- if v == nil {
- return true, nil
- }
- }
- // allocate new `to` variable with default value (eg. *string -> new(string))
- to.Set(reflect.New(to.Type().Elem()))
- }
- // depointer `to`
- to = to.Elem()
- }
- if deepCopy {
- toKind := to.Kind()
- if toKind == reflect.Interface && to.IsNil() {
- if reflect.TypeOf(from.Interface()) != nil {
- to.Set(reflect.New(reflect.TypeOf(from.Interface())).Elem())
- toKind = reflect.TypeOf(to.Interface()).Kind()
- }
- }
- if from.Kind() == reflect.Ptr && from.IsNil() {
- return true, nil
- }
- if _, ok := to.Addr().Interface().(sql.Scanner); !ok && (toKind == reflect.Struct || toKind == reflect.Map || toKind == reflect.Slice) {
- return false, nil
- }
- }
- if from.Type().ConvertibleTo(to.Type()) {
- to.Set(from.Convert(to.Type()))
- } else if toScanner, ok := to.Addr().Interface().(sql.Scanner); ok {
- // `from` -> `to`
- // *string -> sql.NullString
- if from.Kind() == reflect.Ptr {
- // if `from` is nil do nothing with `to`
- if from.IsNil() {
- return true, nil
- }
- // depointer `from`
- from = indirect(from)
- }
- // `from` -> `to`
- // string -> sql.NullString
- // set `to` by invoking method Scan(`from`)
- err := toScanner.Scan(from.Interface())
- if err != nil {
- return false, nil
- }
- } else if fromValuer, ok := driverValuer(from); ok {
- // `from` -> `to`
- // sql.NullString -> string
- v, err := fromValuer.Value()
- if err != nil {
- return false, nil
- }
- // if `from` is not valid do nothing with `to`
- if v == nil {
- return true, nil
- }
- rv := reflect.ValueOf(v)
- if rv.Type().AssignableTo(to.Type()) {
- to.Set(rv)
- } else if to.CanSet() && rv.Type().ConvertibleTo(to.Type()) {
- to.Set(rv.Convert(to.Type()))
- }
- } else if from.Kind() == reflect.Ptr {
- return set(to, from.Elem(), deepCopy, converters)
- } else {
- return false, nil
- }
- return true, nil
- }
- // lookupAndCopyWithConverter looks up the type pair, on success the TypeConverter Fn func is called to copy src to dst field.
- func lookupAndCopyWithConverter(to, from reflect.Value, converters map[converterPair]TypeConverter) (copied bool, err error) {
- pair := converterPair{
- SrcType: from.Type(),
- DstType: to.Type(),
- }
- if cnv, ok := converters[pair]; ok {
- result, err := cnv.Fn(from.Interface())
- if err != nil {
- return false, err
- }
- if result != nil {
- to.Set(reflect.ValueOf(result))
- } else {
- // in case we've got a nil value to copy
- to.Set(reflect.Zero(to.Type()))
- }
- return true, nil
- }
- return false, nil
- }
- // parseTags Parses struct tags and returns uint8 bit flags.
- func parseTags(tag string) (flg uint8, name string, err error) {
- for _, t := range strings.Split(tag, ",") {
- switch t {
- case "-":
- flg = tagIgnore
- return
- case "must":
- flg = flg | tagMust
- case "nopanic":
- flg = flg | tagNoPanic
- default:
- if unicode.IsUpper([]rune(t)[0]) {
- name = strings.TrimSpace(t)
- } else {
- err = ErrFieldNameTagStartNotUpperCase
- }
- }
- }
- return
- }
- // getTagFlags Parses struct tags for bit flags, field name.
- func getFlags(dest, src reflect.Value, toType, fromType reflect.Type) (flags, error) {
- flgs := flags{
- BitFlags: map[string]uint8{},
- SrcNames: tagNameMapping{
- FieldNameToTag: map[string]string{},
- TagToFieldName: map[string]string{},
- },
- DestNames: tagNameMapping{
- FieldNameToTag: map[string]string{},
- TagToFieldName: map[string]string{},
- },
- }
- var toTypeFields, fromTypeFields []reflect.StructField
- if dest.IsValid() {
- toTypeFields = deepFields(toType)
- }
- if src.IsValid() {
- fromTypeFields = deepFields(fromType)
- }
- // Get a list dest of tags
- for _, field := range toTypeFields {
- tags := field.Tag.Get("copier")
- if tags != "" {
- var name string
- var err error
- if flgs.BitFlags[field.Name], name, err = parseTags(tags); err != nil {
- return flags{}, err
- } else if name != "" {
- flgs.DestNames.FieldNameToTag[field.Name] = name
- flgs.DestNames.TagToFieldName[name] = field.Name
- }
- }
- }
- // Get a list source of tags
- for _, field := range fromTypeFields {
- tags := field.Tag.Get("copier")
- if tags != "" {
- var name string
- var err error
- if _, name, err = parseTags(tags); err != nil {
- return flags{}, err
- } else if name != "" {
- flgs.SrcNames.FieldNameToTag[field.Name] = name
- flgs.SrcNames.TagToFieldName[name] = field.Name
- }
- }
- }
- return flgs, nil
- }
- // checkBitFlags Checks flags for error or panic conditions.
- func checkBitFlags(flagsList map[string]uint8) (err error) {
- // Check flag conditions were met
- for name, flgs := range flagsList {
- if flgs&hasCopied == 0 {
- switch {
- case flgs&tagMust != 0 && flgs&tagNoPanic != 0:
- err = fmt.Errorf("field %s has must tag but was not copied", name)
- return
- case flgs&(tagMust) != 0:
- panic(fmt.Sprintf("Field %s has must tag but was not copied", name))
- }
- }
- }
- return
- }
- func getFieldName(fieldName string, flgs flags, fieldNameMapping map[string]string) (srcFieldName string, destFieldName string) {
- // get dest field name
- if name, ok := fieldNameMapping[fieldName]; ok {
- srcFieldName = fieldName
- destFieldName = name
- return
- }
- if srcTagName, ok := flgs.SrcNames.FieldNameToTag[fieldName]; ok {
- destFieldName = srcTagName
- if destTagName, ok := flgs.DestNames.TagToFieldName[srcTagName]; ok {
- destFieldName = destTagName
- }
- } else {
- if destTagName, ok := flgs.DestNames.TagToFieldName[fieldName]; ok {
- destFieldName = destTagName
- }
- }
- if destFieldName == "" {
- destFieldName = fieldName
- }
- // get source field name
- if destTagName, ok := flgs.DestNames.FieldNameToTag[fieldName]; ok {
- srcFieldName = destTagName
- if srcField, ok := flgs.SrcNames.TagToFieldName[destTagName]; ok {
- srcFieldName = srcField
- }
- } else {
- if srcField, ok := flgs.SrcNames.TagToFieldName[fieldName]; ok {
- srcFieldName = srcField
- }
- }
- if srcFieldName == "" {
- srcFieldName = fieldName
- }
- return
- }
- func driverValuer(v reflect.Value) (i driver.Valuer, ok bool) {
- if !v.CanAddr() {
- i, ok = v.Interface().(driver.Valuer)
- return
- }
- i, ok = v.Addr().Interface().(driver.Valuer)
- return
- }
- func fieldByName(v reflect.Value, name string, caseSensitive bool) reflect.Value {
- if caseSensitive {
- return v.FieldByName(name)
- }
- return v.FieldByNameFunc(func(n string) bool { return strings.EqualFold(n, name) })
- }
|