gitee.com/eden-framework/sqlx@v0.0.3/builder/utils.go (about)

     1  package builder
     2  
     3  import (
     4  	"fmt"
     5  	"go/ast"
     6  	"reflect"
     7  	"strings"
     8  
     9  	"gitee.com/eden-framework/reflectx"
    10  )
    11  
    12  type FieldValues map[string]interface{}
    13  
    14  func ForEachStructFieldValue(rv reflect.Value, fn func(structFieldValue reflect.Value, structField reflect.StructField, columnName string, tagValue string)) {
    15  	rv = reflect.Indirect(rv)
    16  	structType := rv.Type()
    17  	for i := 0; i < structType.NumField(); i++ {
    18  		field := structType.Field(i)
    19  
    20  		if field.Type.Kind() == reflect.Interface {
    21  			continue
    22  		}
    23  
    24  		if ast.IsExported(field.Name) {
    25  			fieldValue := rv.Field(i)
    26  
    27  			tagValue, exists := field.Tag.Lookup("db")
    28  			if exists {
    29  				if tagValue != "-" {
    30  					fn(fieldValue, field, GetColumnName(field.Name, tagValue), tagValue)
    31  				}
    32  			} else if field.Anonymous {
    33  				ForEachStructFieldValue(fieldValue, fn)
    34  				continue
    35  			}
    36  		}
    37  	}
    38  }
    39  
    40  func GetColumnName(fieldName, tagValue string) string {
    41  	columnName := strings.Split(tagValue, ",")[0]
    42  	if columnName == "" {
    43  		return "f_" + strings.ToLower(fieldName)
    44  	}
    45  	return strings.ToLower(columnName)
    46  }
    47  
    48  func ToMap(list []string) map[string]bool {
    49  	m := make(map[string]bool, len(list))
    50  	for _, fieldName := range list {
    51  		m[fieldName] = true
    52  	}
    53  	return m
    54  }
    55  
    56  func FieldValuesFromStructBy(structValue interface{}, fieldNames []string) (fieldValues FieldValues) {
    57  	fieldValues = FieldValues{}
    58  	rv := reflect.Indirect(reflect.ValueOf(structValue))
    59  	fieldMap := ToMap(fieldNames)
    60  	ForEachStructFieldValue(rv, func(structFieldValue reflect.Value, structField reflect.StructField, columnName string, tagValue string) {
    61  		if fieldMap != nil && fieldMap[structField.Name] {
    62  			fieldValues[structField.Name] = structFieldValue.Interface()
    63  		}
    64  	})
    65  	return fieldValues
    66  }
    67  
    68  func FieldValuesFromStructByNonZero(structValue interface{}, excludes ...string) (fieldValues FieldValues) {
    69  	fieldValues = FieldValues{}
    70  	rv := reflect.Indirect(reflect.ValueOf(structValue))
    71  	fieldMap := ToMap(excludes)
    72  	ForEachStructFieldValue(rv, func(structFieldValue reflect.Value, structField reflect.StructField, columnName string, tagValue string) {
    73  		if !reflectx.IsEmptyValue(structFieldValue) || (fieldMap != nil && fieldMap[structField.Name]) {
    74  			fieldValues[structField.Name] = structFieldValue.Interface()
    75  		}
    76  	})
    77  	return
    78  }
    79  
    80  func TableFromModel(model Model) *Table {
    81  	tpe := reflect.TypeOf(model)
    82  	if tpe.Kind() != reflect.Ptr {
    83  		panic(fmt.Errorf("model %s must be a pointer", tpe.Name()))
    84  	}
    85  	tpe = tpe.Elem()
    86  	if tpe.Kind() != reflect.Struct {
    87  		panic(fmt.Errorf("model %s must be a struct", tpe.Name()))
    88  	}
    89  
    90  	table := T(model.TableName())
    91  	table.Model = model
    92  
    93  	ScanDefToTable(reflect.Indirect(reflect.ValueOf(model)), table)
    94  
    95  	return table
    96  }
    97  
    98  func ScanDefToTable(rv reflect.Value, table *Table) {
    99  	table.ModelName = rv.Type().Name()
   100  
   101  	ForEachStructFieldValue(reflect.Indirect(rv), func(structFieldValue reflect.Value, structField reflect.StructField, columnName string, tagValue string) {
   102  		table.AddCol(Col(columnName).Field(structField.Name).Type(structFieldValue.Interface(), tagValue))
   103  	})
   104  
   105  	if rv.CanAddr() {
   106  		addr := rv.Addr()
   107  		if addr.CanInterface() {
   108  			i := addr.Interface()
   109  
   110  			if withTableDescription, ok := i.(WithTableDescription); ok {
   111  				desc := withTableDescription.TableDescription()
   112  				table.Description = desc
   113  			}
   114  
   115  			if withComments, ok := i.(WithComments); ok {
   116  				for fieldName, comment := range withComments.Comments() {
   117  					field := table.F(fieldName)
   118  					if field != nil {
   119  						field.Comment = comment
   120  					}
   121  				}
   122  			}
   123  
   124  			if withColDescriptions, ok := i.(WithColDescriptions); ok {
   125  				for fieldName, desc := range withColDescriptions.ColDescriptions() {
   126  					field := table.F(fieldName)
   127  					if field != nil {
   128  						field.Description = desc
   129  					}
   130  				}
   131  			}
   132  
   133  			if withRelations, ok := i.(WithRelations); ok {
   134  				for fieldName, rel := range withRelations.ColRelations() {
   135  					field := table.F(fieldName)
   136  					if field != nil {
   137  						field.Relation = rel
   138  					}
   139  				}
   140  			}
   141  
   142  			if primaryKeyHook, ok := i.(WithPrimaryKey); ok {
   143  				cols, err := table.Fields(primaryKeyHook.PrimaryKey()...)
   144  				if err != nil {
   145  					panic(fmt.Errorf("invalid primary key of table %s: %s", table.Name, err))
   146  				}
   147  				table.AddKey(PrimaryKey(cols))
   148  			}
   149  
   150  			if uniqueIndexesHook, ok := i.(WithUniqueIndexes); ok {
   151  				for indexNameAndMethod, fieldNames := range uniqueIndexesHook.UniqueIndexes() {
   152  					indexName, method := ResolveIndexNameAndMethod(indexNameAndMethod)
   153  					cols, err := table.Fields(fieldNames...)
   154  					if err != nil {
   155  						panic(fmt.Errorf("invalid unique index %s of table %s: %s", indexName, table.Name, err))
   156  					}
   157  					table.AddKey(UniqueIndex(indexName, cols).Using(method))
   158  				}
   159  			}
   160  
   161  			if indexesHook, ok := i.(WithIndexes); ok {
   162  				for indexNameAndMethod, fieldNames := range indexesHook.Indexes() {
   163  					indexName, method := ResolveIndexNameAndMethod(indexNameAndMethod)
   164  					cols, err := table.Fields(fieldNames...)
   165  					if err != nil {
   166  						panic(fmt.Errorf("invalid index %s of table %s: %s", indexName, table.Name, err))
   167  					}
   168  					table.AddKey(Index(indexName, cols).Using(method))
   169  				}
   170  			}
   171  		}
   172  	}
   173  }
   174  
   175  func ResolveIndexNameAndMethod(n string) (name string, method string) {
   176  	nameAndMethod := strings.Split(n, "/")
   177  	name = nameAndMethod[0]
   178  	if len(nameAndMethod) > 1 {
   179  		method = nameAndMethod[1]
   180  	}
   181  	return
   182  }