github.com/eden-framework/sqlx@v0.0.2/generator/utils.go (about) 1 package generator 2 3 import ( 4 "fmt" 5 "go/types" 6 "reflect" 7 "regexp" 8 "strings" 9 10 "github.com/eden-framework/codegen" 11 "github.com/eden-framework/sqlx/builder" 12 ) 13 14 var ( 15 defRegexp = regexp.MustCompile(`@def ([^\n]+)`) 16 relRegexp = regexp.MustCompile(`@rel ([^\n]+)`) 17 ) 18 19 type Keys struct { 20 Primary []string 21 Indexes builder.Indexes 22 UniqueIndexes builder.Indexes 23 } 24 25 func (ks *Keys) PatchUniqueIndexesWithSoftDelete(softDeleteField string) { 26 if len(ks.UniqueIndexes) > 0 { 27 for name, fieldNames := range ks.UniqueIndexes { 28 ks.UniqueIndexes[name] = stringUniq(append(fieldNames, softDeleteField)) 29 } 30 } 31 } 32 33 func (ks *Keys) Bind(table *builder.Table) { 34 if len(ks.Primary) > 0 { 35 cols, err := table.Fields(ks.Primary...) 36 if err != nil { 37 panic(fmt.Errorf("%s, please check primary def", err)) 38 } 39 ks.Primary = cols.FieldNames() 40 table.AddKey(builder.PrimaryKey(cols)) 41 } 42 43 if len(ks.UniqueIndexes) > 0 { 44 for indexNameAndMethod, fieldNames := range ks.UniqueIndexes { 45 indexName, method := builder.ResolveIndexNameAndMethod(indexNameAndMethod) 46 cols, err := table.Fields(fieldNames...) 47 if err != nil { 48 panic(fmt.Errorf("%s, please check unique_index def", err)) 49 } 50 ks.UniqueIndexes[indexNameAndMethod] = cols.FieldNames() 51 table.AddKey(builder.UniqueIndex(indexName, cols).Using(method)) 52 } 53 } 54 55 if len(ks.Indexes) > 0 { 56 for indexNameAndMethod, fieldNames := range ks.Indexes { 57 indexName, method := builder.ResolveIndexNameAndMethod(indexNameAndMethod) 58 cols, err := table.Fields(fieldNames...) 59 if err != nil { 60 panic(fmt.Errorf("%s, please check index def", err)) 61 } 62 ks.Indexes[indexNameAndMethod] = cols.FieldNames() 63 table.AddKey(builder.Index(indexName, cols).Using(method)) 64 } 65 } 66 } 67 68 func parseColRelFromComment(doc string) (string, []string) { 69 others := make([]string, 0) 70 71 rel := "" 72 73 for _, line := range strings.Split(doc, "\n") { 74 if len(line) == 0 { 75 continue 76 } 77 78 matches := relRegexp.FindAllStringSubmatch(line, 1) 79 80 if matches == nil { 81 others = append(others, line) 82 continue 83 } 84 85 if len(matches) == 1 { 86 rel = matches[0][1] 87 } 88 } 89 90 return rel, others 91 } 92 93 func parseKeysFromDoc(doc string) (*Keys, []string) { 94 ks := &Keys{} 95 96 others := make([]string, 0) 97 98 for _, line := range strings.Split(doc, "\n") { 99 if len(line) == 0 { 100 continue 101 } 102 103 matches := defRegexp.FindAllStringSubmatch(line, -1) 104 105 if matches == nil { 106 others = append(others, line) 107 continue 108 } 109 110 for _, subMatch := range matches { 111 if len(subMatch) == 2 { 112 defs := defSplit(subMatch[1]) 113 114 switch strings.ToLower(defs[0]) { 115 case "primary": 116 if len(defs) < 2 { 117 panic(fmt.Errorf("primary at lease 1 Field")) 118 } 119 ks.Primary = defs[1:] 120 case "unique_index": 121 if len(defs) < 3 { 122 panic(fmt.Errorf("unique indexes at lease 1 Field")) 123 } 124 if ks.UniqueIndexes == nil { 125 ks.UniqueIndexes = builder.Indexes{} 126 } 127 ks.UniqueIndexes[defs[1]] = defs[2:] 128 case "index": 129 if len(defs) < 3 { 130 panic(fmt.Errorf("index at lease 1 Field")) 131 } 132 if ks.Indexes == nil { 133 ks.Indexes = builder.Indexes{} 134 } 135 ks.Indexes[defs[1]] = defs[2:] 136 } 137 } 138 } 139 } 140 141 return ks, others 142 } 143 144 func defSplit(def string) (defs []string) { 145 vs := strings.Split(def, " ") 146 for _, s := range vs { 147 if s != "" { 148 defs = append(defs, s) 149 } 150 } 151 return 152 } 153 154 func toDefaultTableName(name string) string { 155 return codegen.LowerSnakeCase("t_" + name) 156 } 157 158 func forEachStructField(structType *types.Struct, fn func(fieldVar *types.Var, columnName string, tagValue string)) { 159 for i := 0; i < structType.NumFields(); i++ { 160 field := structType.Field(i) 161 tag := structType.Tag(i) 162 if field.Exported() { 163 structTag := reflect.StructTag(tag) 164 tagValue, exists := structTag.Lookup("db") 165 if exists { 166 if tagValue != "-" { 167 fn(field, builder.GetColumnName(field.Name(), tagValue), tagValue) 168 } 169 } else if field.Anonymous() { 170 if nextStructType, ok := field.Type().Underlying().(*types.Struct); ok { 171 forEachStructField(nextStructType, fn) 172 } 173 continue 174 } 175 } 176 } 177 } 178 179 func stringPartition(list []string, checker func(item string, i int) bool) ([]string, []string) { 180 newLeftList := make([]string, 0) 181 newRightList := make([]string, 0) 182 for i, item := range list { 183 if checker(item, i) { 184 newLeftList = append(newLeftList, item) 185 } else { 186 newRightList = append(newRightList, item) 187 } 188 } 189 return newLeftList, newRightList 190 } 191 192 func stringFilter(list []string, checker func(item string, i int) bool) []string { 193 newList, _ := stringPartition(list, checker) 194 return newList 195 } 196 197 func stringUniq(list []string) (result []string) { 198 strMap := make(map[string]bool) 199 for _, str := range list { 200 strMap[str] = true 201 } 202 203 for i := range list { 204 str := list[i] 205 if _, ok := strMap[str]; ok { 206 delete(strMap, str) 207 result = append(result, str) 208 } 209 } 210 return 211 }