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 }