github.com/songzhibin97/gkit@v1.2.13/tools/vto/votodo.go (about)

     1  package vto
     2  
     3  import (
     4  	"reflect"
     5  	"strings"
     6  
     7  	"github.com/songzhibin97/gkit/tools"
     8  
     9  	"github.com/songzhibin97/gkit/tools/bind"
    10  )
    11  
    12  type BindModel int
    13  
    14  const (
    15  	FieldBind BindModel = 1 << iota
    16  	TagBind
    17  	DefaultValueBind // 默认值绑定,在最后的情况下,如果还未绑定到相关值则设置为默认值
    18  	OverlayBind      // 设置多个条件的情况下可以覆盖,根据代码语义,应该是会以tag优先,不设置以field为优先
    19  )
    20  
    21  type ModelParameters struct {
    22  	Model     BindModel `json:"model"`      // 绑定参数 默认值为 field bind
    23  	Tag       string    `json:"tag"`        // tag bind 指定tag,default 为 json
    24  	TagSqlite string    `json:"tag_sqlite"` // 切分tag标识
    25  	FilterTag []string  `json:"filter_tag"` // 过滤tag
    26  }
    27  
    28  // VoToDo 试图对象与domino对象转换,只能转相同字段且类型相同的
    29  // dst: 目标
    30  // src: 源位置
    31  // 支持简单的 default模式 在基础类型增加default可以指定默认值
    32  func VoToDo(dst interface{}, src interface{}) error {
    33  	dstT, srcT := reflect.TypeOf(dst), reflect.TypeOf(src)
    34  	if dstT.Kind() != srcT.Kind() {
    35  		return tools.ErrorNoEquals
    36  	}
    37  	if dstT.Kind() != reflect.Ptr {
    38  		return tools.ErrorMustPtr
    39  	}
    40  	dstT, srcT = dstT.Elem(), srcT.Elem()
    41  	if dstT.Kind() != reflect.Struct || srcT.Kind() != reflect.Struct {
    42  		return tools.ErrorMustStructPtr
    43  	}
    44  	dstV, srcV := reflect.ValueOf(dst).Elem(), reflect.ValueOf(src).Elem()
    45  	for i := 0; i < dstT.NumField(); i++ {
    46  		field := dstT.Field(i)
    47  		if !field.IsExported() {
    48  			continue
    49  		}
    50  		defaultTag := field.Tag.Get("default")
    51  		if _, ok := srcT.FieldByName(field.Name); !ok {
    52  			continue
    53  		}
    54  		d := dstV.Field(i)
    55  		s := srcV.FieldByName(field.Name)
    56  		for s.Kind() == reflect.Ptr && d.Kind() != s.Kind() {
    57  			s = s.Elem()
    58  		}
    59  
    60  		if d.Kind() != s.Kind() && !d.CanConvert(s.Type()) {
    61  			continue
    62  		}
    63  
    64  		if d.Kind() != s.Kind() && d.Kind() == reflect.Struct {
    65  			err := VoToDo(d.Addr().Interface(), s.Addr().Interface())
    66  			if err != nil {
    67  				return err
    68  			}
    69  			continue
    70  		}
    71  
    72  		if !s.IsZero() {
    73  			if d.Type() == s.Type() {
    74  				d.Set(s)
    75  			} else if s.CanConvert(d.Type()) {
    76  				d.Set(reflect.ValueOf(s.Interface()).Convert(d.Type()))
    77  			}
    78  		}
    79  
    80  		// 如果源位置的内容为空,并且默认值不为0
    81  		if d.IsZero() && len(defaultTag) > 0 {
    82  			if d.Kind() == reflect.Ptr {
    83  				ss := reflect.New(d.Type().Elem())
    84  				err := bindDefault(ss.Elem(), defaultTag, field)
    85  				if err != nil {
    86  					return err
    87  				}
    88  				d.Set(ss)
    89  			} else {
    90  				err := bindDefault(d, defaultTag, field)
    91  				if err != nil {
    92  					return err
    93  				}
    94  			}
    95  		}
    96  	}
    97  	return nil
    98  }
    99  
   100  // VoToDoPlus View对象与domino对象转换,根据不同模式进行转换
   101  // dst: 目标
   102  // src: 源位置
   103  // ModelParameters: 模式匹配
   104  func VoToDoPlus(dst interface{}, src interface{}, model ModelParameters) error {
   105  	dstT, srcT := reflect.TypeOf(dst), reflect.TypeOf(src)
   106  	if dstT.Kind() != srcT.Kind() {
   107  		return tools.ErrorNoEquals
   108  	}
   109  	if dstT.Kind() != reflect.Ptr {
   110  		return tools.ErrorMustPtr
   111  	}
   112  	dstT, srcT = dstT.Elem(), srcT.Elem()
   113  	if dstT.Kind() != reflect.Struct || srcT.Kind() != reflect.Struct {
   114  		return tools.ErrorMustStructPtr
   115  	}
   116  	dstV, srcV := reflect.ValueOf(dst).Elem(), reflect.ValueOf(src).Elem()
   117  
   118  	if model.Model&TagBind == TagBind && len(model.Tag) == 0 {
   119  		model.Tag = "json"
   120  	}
   121  	if model.Model&TagBind == TagBind && len(model.TagSqlite) == 0 {
   122  		model.TagSqlite = ","
   123  	}
   124  	if model.Model&TagBind == TagBind && len(model.FilterTag) == 0 {
   125  		model.FilterTag = []string{"omitempty"}
   126  	}
   127  	filterTag := make(map[string]struct{})
   128  	for _, s := range model.FilterTag {
   129  		filterTag[s] = struct{}{}
   130  	}
   131  
   132  	if model.Model&FieldBind == FieldBind {
   133  		for i := 0; i < dstT.NumField(); i++ {
   134  			field := dstT.Field(i)
   135  			if !field.IsExported() {
   136  				continue
   137  			}
   138  			d := dstV.Field(i)
   139  			if _, ok := srcT.FieldByName(field.Name); !ok {
   140  				continue
   141  			}
   142  
   143  			s := srcV.FieldByName(field.Name)
   144  			for s.Kind() == reflect.Ptr && d.Kind() != s.Kind() {
   145  				s = s.Elem()
   146  			}
   147  			if d.Kind() != s.Kind() && !d.CanConvert(s.Type()) {
   148  				continue
   149  			}
   150  
   151  			if d.Kind() != s.Kind() && d.Kind() == reflect.Struct {
   152  				err := VoToDoPlus(d.Addr().Interface(), s.Addr().Interface(), model)
   153  				if err != nil {
   154  					return err
   155  				}
   156  				continue
   157  			}
   158  
   159  			if !s.IsZero() {
   160  				if d.Type() == s.Type() {
   161  					d.Set(s)
   162  				} else if s.CanConvert(d.Type()) {
   163  					d.Set(reflect.ValueOf(s.Interface()).Convert(d.Type()))
   164  				}
   165  			}
   166  		}
   167  	}
   168  
   169  	if model.Model&TagBind == TagBind {
   170  
   171  		srcMapping := make(map[string]reflect.StructField)
   172  		for i := 0; i < srcT.NumField(); i++ {
   173  			srcField := srcT.Field(i)
   174  			if !srcField.IsExported() {
   175  				continue
   176  			}
   177  			tag := srcField.Tag.Get(model.Tag)
   178  			if tag == "" || tag == "-" {
   179  				continue
   180  			}
   181  			for _, s := range strings.Split(tag, model.TagSqlite) {
   182  				if _, ok := filterTag[s]; ok {
   183  					continue
   184  				}
   185  				srcMapping[s] = srcField
   186  			}
   187  		}
   188  
   189  		for i := 0; i < dstT.NumField(); i++ {
   190  			field := dstT.Field(i)
   191  			if !field.IsExported() {
   192  				continue
   193  			}
   194  			d := dstV.Field(i)
   195  
   196  			if !d.IsZero() && !(model.Model&OverlayBind == OverlayBind) {
   197  				continue
   198  			}
   199  
   200  			currentFieldTag := field.Tag.Get(model.Tag)
   201  			if currentFieldTag == "" || currentFieldTag == "-" {
   202  				continue
   203  			}
   204  			for _, s := range strings.Split(currentFieldTag, model.TagSqlite) {
   205  				if _, ok := filterTag[s]; ok {
   206  					continue
   207  				}
   208  				srcField, ok := srcMapping[s]
   209  				if !ok {
   210  					continue
   211  				}
   212  
   213  				ss := srcV.FieldByName(srcField.Name)
   214  				for ss.Kind() == reflect.Ptr && d.Kind() != ss.Kind() {
   215  					ss = ss.Elem()
   216  				}
   217  				if d.Kind() != ss.Kind() {
   218  					continue
   219  				}
   220  				if d.Type() != ss.Type() && d.Kind() == reflect.Struct {
   221  					err := VoToDoPlus(d.Addr().Interface(), ss.Addr().Interface(), model)
   222  					if err != nil {
   223  						return err
   224  					}
   225  					continue
   226  				}
   227  
   228  				if !ss.IsZero() {
   229  					if d.Type() == ss.Type() {
   230  						d.Set(ss)
   231  					} else if d.CanConvert(ss.Type()) {
   232  						d.Set(reflect.ValueOf(ss.Interface()).Convert(d.Type()))
   233  					}
   234  				}
   235  				break
   236  			}
   237  		}
   238  	}
   239  
   240  	if model.Model&DefaultValueBind == DefaultValueBind {
   241  		for i := 0; i < dstT.NumField(); i++ {
   242  			field := dstT.Field(i)
   243  			if !field.IsExported() {
   244  				continue
   245  			}
   246  			defaultTag := field.Tag.Get("default")
   247  			if len(defaultTag) == 0 || defaultTag == "-" {
   248  				continue
   249  			}
   250  			d := dstV.Field(i)
   251  			// 如果源位置的内容为空,并且默认值不为0
   252  			if d.IsZero() && len(defaultTag) > 0 {
   253  				if d.Kind() == reflect.Ptr {
   254  					s := reflect.New(d.Type().Elem())
   255  					err := bindDefault(s.Elem(), defaultTag, field)
   256  					if err != nil {
   257  						return err
   258  					}
   259  					d.Set(s)
   260  				} else {
   261  					err := bindDefault(d, defaultTag, field)
   262  					if err != nil {
   263  						return err
   264  					}
   265  				}
   266  			}
   267  		}
   268  	}
   269  
   270  	return nil
   271  }
   272  
   273  func bindDefault(value reflect.Value, val string, field reflect.StructField) error {
   274  	return bind.SetWithProperType(val, value, field)
   275  }