2020-01-14 23:20:23 +01:00
|
|
|
|
/*
|
|
|
|
|
* Copyright (c) 2020 Alex aka mailoman <alex@webz.asia>
|
|
|
|
|
*
|
|
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
|
* you may not use this file except in compliance with the License.
|
|
|
|
|
* You may obtain a copy of the License at
|
|
|
|
|
*
|
|
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
|
*
|
|
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
|
* See the License for the specific language governing permissions and
|
|
|
|
|
* limitations under the License.
|
|
|
|
|
*
|
|
|
|
|
* @author Alex aka mailoman <alex@webz.asia>
|
|
|
|
|
* @copyright Copyright (c) 2020 Alex aka mailoman <alex@webz.asia>
|
|
|
|
|
* @since 14.01.2020
|
|
|
|
|
*
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
package fields
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"log"
|
|
|
|
|
"reflect"
|
|
|
|
|
"strings"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
//Convert copies field values from one struct to another based on tags setup
|
|
|
|
|
func Сonvert(from interface{}, kind string, to interface{}) {
|
|
|
|
|
if nil == from {
|
|
|
|
|
log.Print("nil value is not supported")
|
|
|
|
|
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
v := reflect.ValueOf(from)
|
|
|
|
|
vt := reflect.ValueOf(to)
|
|
|
|
|
t := v.Type()
|
|
|
|
|
|
|
|
|
|
if t.Kind() != reflect.Struct {
|
|
|
|
|
log.Printf("type %s is not supported", t.Kind())
|
|
|
|
|
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if vt.Kind() == reflect.Ptr {
|
|
|
|
|
vt = reflect.ValueOf(to).Elem()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for i := 0; i < t.NumField(); i++ {
|
|
|
|
|
f := t.Field(i)
|
|
|
|
|
// skip unexported fields. from godoc:
|
|
|
|
|
// PkgPath is the package path that qualifies a lower case (unexported)
|
|
|
|
|
// field name. It is empty for upper case (exported) field names.
|
2020-01-26 16:44:37 +01:00
|
|
|
|
if f.PkgPath != "" && f.Name == "" {
|
2020-01-14 23:20:23 +01:00
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
fv := v.Field(i)
|
|
|
|
|
found, omit, omitempty := readTag(f, kind)
|
|
|
|
|
// skip if tag "omit" set.
|
|
|
|
|
if omit {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
// skip empty values when "omitempty" set.
|
|
|
|
|
if omitempty && fv.String() == "" {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if found {
|
|
|
|
|
ft := vt.FieldByName(f.Name)
|
2020-01-26 16:44:37 +01:00
|
|
|
|
if !ft.IsValid() && fv.Kind() == reflect.Struct {
|
|
|
|
|
Сonvert(fv.Interface(), kind, to)
|
|
|
|
|
} else {
|
|
|
|
|
ft.Set(fv)
|
|
|
|
|
}
|
2020-01-14 23:20:23 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func readTag(f reflect.StructField, kind string) (bool, bool, bool) {
|
|
|
|
|
val, ok := f.Tag.Lookup(ConvertTagName())
|
|
|
|
|
if !ok {
|
|
|
|
|
return false, false, false
|
|
|
|
|
}
|
|
|
|
|
opts := strings.Split(val, ",")
|
|
|
|
|
|
|
|
|
|
return indexOf(opts, kind) > -1, indexOf(opts, OmitTagName()) > -1, indexOf(opts, OmitEmptyTagName()) > -1
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func indexOf(a []string, x string) int {
|
|
|
|
|
for i, n := range a {
|
|
|
|
|
if x == n {
|
|
|
|
|
return i
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return -1
|
|
|
|
|
}
|