Files
gorose/parser/structsParser.go
2024-04-03 14:25:18 +08:00

189 lines
4.7 KiB
Go

package parser
import (
"database/sql/driver"
"reflect"
"slices"
"strings"
)
func StructsToTableName(rft reflect.Type) (tab string) {
if field, ok := rft.FieldByName("TableName"); ok {
if field.Tag.Get("db") != "" {
tab = field.Tag.Get("db")
}
}
if tab == "" {
if tn := reflect.New(rft).Elem().MethodByName("TableName"); tn.IsValid() {
tab = tn.Call(nil)[0].String()
}
}
if tab == "" {
tab = rft.Name()
}
return
}
func StructsParse(obj any) (FieldTag []string, FieldStruct []string, pkField string) {
rfv := reflect.Indirect(reflect.ValueOf(obj))
switch rfv.Kind() {
case reflect.Struct:
return StructsTypeParse(rfv.Type())
case reflect.Slice:
return StructsTypeParse(rfv.Type())
default:
return
}
}
func StructsTypeParse(rft reflect.Type) (fieldTag []string, fieldStruct []string, pkField string) {
//rfv := reflect.Indirect(reflect.ValueOf(obj))
if rft.Kind() == reflect.Slice {
rft2 := rft.Elem()
if rft2.Kind() == reflect.Struct {
return StructsTypeParse(rft2)
}
} else {
for i := 0; i < rft.NumField(); i++ {
field := rft.Field(i)
if field.Anonymous {
continue
}
tag := field.Tag.Get("db")
if tag == "-" || field.Name == "TableName" {
continue
}
if tag == "" {
//field.Tag = reflect.StructTag("db:" + field.Name)
fieldStruct = append(fieldStruct, field.Name)
tag = field.Name
} else {
if strings.Contains(tag, ",") {
tags := strings.Split(tag, ",")
if slices.Contains(tags, "pk") {
pkField = field.Name
tag = tags[0]
}
}
fieldStruct = append(fieldStruct, field.Name)
}
//else {
// fieldStruct = append(fieldStruct, field.Tag.Get("db"))
//}
//if field.Tag.Get("pkField") == "true" {
// pkField = field.Name
// pkValue = rfv.FieldByName(field.Name)
//}
fieldTag = append(fieldTag, tag)
}
}
return
}
//func StructsToSelects(obj any) []string {
// tag, fieldStruct, _ := StructsParse(obj)
// if len(tag) > 0 {
// return tag
// } else {
// return fieldStruct
// }
//}
func StructDataToMap(rfv reflect.Value, tags, fieldStruct []string, mustColumn ...string) (data map[string]any, err error) {
data = make(map[string]any)
for i, fieldName := range fieldStruct {
field := rfv.FieldByName(fieldName)
if (field.Kind() == reflect.Ptr && field.IsNil()) || (field.IsZero() && !slices.Contains(mustColumn, tags[i])) {
continue
}
var rfvVal = field.Interface()
if v, ok := rfvVal.(driver.Valuer); ok {
var value driver.Value
value, err = v.Value()
if err != nil {
return
}
data[tags[i]] = value
} else {
data[tags[i]] = rfvVal
}
}
return
}
func structUpdateDataToMap(rfv reflect.Value, tags, fieldStruct []string, pkField string, mustColumn ...string) (data map[string]any, err error) {
data = make(map[string]any)
for i, fieldName := range fieldStruct {
field := rfv.FieldByName(fieldName)
if (field.Kind() == reflect.Ptr && field.IsNil()) || (field.IsZero() && !slices.Contains(mustColumn, tags[i])) || fieldName == pkField {
continue
}
var rfvVal = field.Interface()
if v, ok := rfvVal.(driver.Valuer); ok {
var value driver.Value
value, err = v.Value()
if err != nil {
return
}
data[tags[i]] = value
} else {
data[tags[i]] = rfvVal
}
}
return
}
func StructToDelete(obj any, mustColumn ...string) (data map[string]any, err error) {
rfv := reflect.Indirect(reflect.ValueOf(obj))
if rfv.Kind() == reflect.Struct {
tag, fieldStruct, _ := StructsTypeParse(rfv.Type())
data, err = StructDataToMap(rfv, tag, fieldStruct, mustColumn...)
}
return
}
func StructsToInsert(obj any, mustColumn ...string) (datas []map[string]any, err error) {
rfv := reflect.Indirect(reflect.ValueOf(obj))
switch rfv.Kind() {
case reflect.Struct:
fieldTag, fieldStruct, _ := StructsTypeParse(rfv.Type())
var data = make(map[string]any)
data, err = StructDataToMap(rfv, fieldTag, fieldStruct, mustColumn...)
if err != nil {
return
}
datas = append(datas, data)
case reflect.Slice:
tag, fieldStruct, _ := StructsTypeParse(rfv.Type())
for i := 0; i < rfv.Len(); i++ {
var data = make(map[string]any)
data, err = StructDataToMap(rfv.Index(i), tag, fieldStruct, mustColumn...)
if err != nil {
return
}
datas = append(datas, data)
}
default:
return
}
return
}
func StructToUpdate(obj any, mustColumn ...string) (data map[string]any, pkTag string, pkValue any, err error) {
tag, fieldStruct, pkField := StructsParse(obj)
if len(tag) > 0 {
data = make(map[string]any)
rfv := reflect.Indirect(reflect.ValueOf(obj))
data, err = structUpdateDataToMap(rfv, tag, fieldStruct, pkField, mustColumn...)
if err != nil {
return
}
if pkField != "" {
pkTag = tag[slices.Index(fieldStruct, pkField)]
pkValue = rfv.FieldByName(pkField).Interface()
}
}
return
}