github.com/unionj-cloud/go-doudou/v2@v2.3.5/toolkit/gormgen/internal/generate/export.go (about) 1 package generate 2 3 import ( 4 "context" 5 "fmt" 6 "reflect" 7 "strings" 8 9 "gorm.io/gorm" 10 "gorm.io/gorm/schema" 11 "gorm.io/gorm/utils/tests" 12 13 "github.com/unionj-cloud/go-doudou/v2/toolkit/gormgen/field" 14 "github.com/unionj-cloud/go-doudou/v2/toolkit/gormgen/helper" 15 "github.com/unionj-cloud/go-doudou/v2/toolkit/gormgen/internal/model" 16 "github.com/unionj-cloud/go-doudou/v2/toolkit/gormgen/internal/parser" 17 ) 18 19 // GetQueryStructMeta generate db model by table name 20 func GetQueryStructMeta(db *gorm.DB, conf *model.Config) (*QueryStructMeta, error) { 21 if _, ok := db.Config.Dialector.(tests.DummyDialector); ok { 22 return nil, fmt.Errorf("UseDB() is necessary to generate model struct [%s] from database table [%s]", conf.ModelName, conf.TableName) 23 } 24 25 conf = conf.Preprocess() 26 tableName, structName, fileName := conf.GetNames() 27 if tableName == "" { 28 return nil, nil 29 } 30 if err := checkStructName(structName); err != nil { 31 return nil, fmt.Errorf("model name %q is invalid: %w", structName, err) 32 } 33 34 columns, err := getTableColumns(db, conf.GetSchemaName(db), tableName, conf.FieldWithIndexTag) 35 if err != nil { 36 return nil, err 37 } 38 39 fields := getFields(db, conf, columns) 40 priKeyType := "string" 41 for _, field := range fields { 42 if field.PriKey { 43 priKeyType = field.Type 44 break 45 } 46 } 47 48 return (&QueryStructMeta{ 49 db: db, 50 Source: model.Table, 51 Generated: true, 52 FileName: fileName, 53 TableName: tableName, 54 ModelStructName: structName, 55 QueryStructName: uncaptialize(structName), 56 S: strings.ToLower(structName[0:1]), 57 StructInfo: parser.Param{Type: structName, Package: conf.ModelPkg}, 58 ImportPkgPaths: conf.ImportPkgPaths, 59 Fields: fields, 60 PriKeyType: priKeyType, 61 }).addMethodFromAddMethodOpt(conf.GetModelMethods()...), nil 62 } 63 64 // GetQueryStructMetaFromObject generate base struct from object 65 func GetQueryStructMetaFromObject(obj helper.Object, conf *model.Config) (*QueryStructMeta, error) { 66 err := helper.CheckObject(obj) 67 if err != nil { 68 return nil, err 69 } 70 71 conf = conf.Preprocess() 72 73 tableName := obj.TableName() 74 if conf.TableNameNS != nil { 75 tableName = conf.TableNameNS(tableName) 76 } 77 78 structName := obj.StructName() 79 if conf.ModelNameNS != nil { 80 structName = conf.ModelNameNS(structName) 81 } 82 83 fileName := obj.FileName() 84 if fileName == "" { 85 fileName = tableName 86 } 87 if fileName == "" { 88 fileName = structName 89 } 90 if conf.FileNameNS != nil { 91 fileName = conf.FileNameNS(fileName) 92 } else { 93 fileName = schema.NamingStrategy{SingularTable: true}.TableName(fileName) 94 } 95 96 fields := make([]*model.Field, 0, 16) 97 for _, fl := range obj.Fields() { 98 tag := fl.Tag() 99 if tag == nil { 100 tag = field.Tag{} 101 } 102 if gt := fl.GORMTag(); gt != "" { 103 tag.Set(field.TagKeyGorm, gt) 104 } 105 if jt := fl.JSONTag(); jt != "" { 106 tag.Set(field.TagKeyJson, jt) 107 } 108 109 fields = append(fields, &model.Field{ 110 Name: fl.Name(), 111 Type: fl.Type(), 112 ColumnName: fl.ColumnName(), 113 Tag: tag, 114 ColumnComment: fl.Comment(), 115 MultilineComment: strings.Contains(fl.Comment(), "\n"), 116 }) 117 } 118 119 return &QueryStructMeta{ 120 Source: model.Object, 121 Generated: true, 122 FileName: fileName, 123 TableName: tableName, 124 ModelStructName: structName, 125 QueryStructName: uncaptialize(structName), 126 S: strings.ToLower(structName[0:1]), 127 StructInfo: parser.Param{Type: structName, Package: conf.ModelPkg}, 128 ImportPkgPaths: append(conf.ImportPkgPaths, obj.ImportPkgPaths()...), 129 Fields: fields, 130 }, nil 131 } 132 133 // ConvertStructs convert to base structures 134 func ConvertStructs(db *gorm.DB, structs ...interface{}) (metas []*QueryStructMeta, err error) { 135 for _, st := range structs { 136 if isNil(st) { 137 continue 138 } 139 if base, ok := st.(*QueryStructMeta); ok { 140 metas = append(metas, base) 141 continue 142 } 143 if !isStructType(reflect.ValueOf(st)) { 144 return nil, fmt.Errorf("%s is not a struct", reflect.TypeOf(st).String()) 145 } 146 147 structType := reflect.TypeOf(st) 148 name := getStructName(structType.String()) 149 newStructName := name 150 if st, ok := st.(interface{ GenInternalDoName() string }); ok { 151 newStructName = st.GenInternalDoName() 152 } 153 154 meta := &QueryStructMeta{ 155 S: getPureName(name), 156 ModelStructName: name, 157 QueryStructName: uncaptialize(newStructName), 158 StructInfo: parser.Param{PkgPath: structType.PkgPath(), Type: name, Package: getPackageName(structType.String())}, 159 Source: model.Struct, 160 db: db, 161 } 162 if err := meta.parseStruct(st); err != nil { 163 return nil, fmt.Errorf("transform struct [%s.%s] error:%s", meta.StructInfo.Package, name, err) 164 } 165 if err := meta.check(); err != nil { 166 db.Logger.Warn(context.Background(), err.Error()) 167 continue 168 } 169 170 metas = append(metas, meta) 171 } 172 return 173 } 174 175 func isNil(i interface{}) bool { 176 if i == nil { 177 return true 178 } 179 180 // if v is not ptr, return false(i is not nil) 181 // if v is ptr, return v.IsNil() 182 v := reflect.ValueOf(i) 183 return v.Kind() == reflect.Ptr && v.IsNil() 184 } 185 186 // BuildDIYMethod check the legitimacy of interfaces 187 func BuildDIYMethod(f *parser.InterfaceSet, s *QueryStructMeta, data []*InterfaceMethod) (checkResults []*InterfaceMethod, err error) { 188 for _, interfaceInfo := range f.Interfaces { 189 if interfaceInfo.MatchStruct(s.ModelStructName) { 190 for _, method := range interfaceInfo.Methods { 191 t := &InterfaceMethod{ 192 S: s.S, 193 TargetStruct: s.QueryStructName, 194 OriginStruct: s.StructInfo, 195 MethodName: method.MethodName, 196 Params: method.Params, 197 Doc: method.Doc, 198 Table: s.TableName, 199 InterfaceName: interfaceInfo.Name, 200 Package: getPackageName(interfaceInfo.Package), 201 } 202 if err = t.checkMethod(data, s); err != nil { 203 return nil, err 204 } 205 if err = t.checkParams(method.Params); err != nil { 206 return 207 } 208 if err = t.checkResult(method.Result); err != nil { 209 return 210 } 211 if err = t.checkSQL(); err != nil { 212 return 213 } 214 _, err = t.Section.BuildSQL() 215 if err != nil { 216 err = fmt.Errorf("sql [%s] build err:%w", t.SQLString, err) 217 return 218 } 219 checkResults = append(checkResults, t) 220 } 221 } 222 } 223 return 224 } 225 226 // ParseStructRelationShip parse struct's relationship 227 // No one should use it directly in project 228 func ParseStructRelationShip(relationship *schema.Relationships) []field.Relation { 229 cache := make(map[string]bool) 230 return append(append(append(append( 231 make([]field.Relation, 0, 4), 232 pullRelationShip(cache, relationship.HasOne)...), 233 pullRelationShip(cache, relationship.HasMany)...), 234 pullRelationShip(cache, relationship.BelongsTo)...), 235 pullRelationShip(cache, relationship.Many2Many)..., 236 ) 237 } 238 239 // GetStructNames get struct names from base structs 240 func GetStructNames(bases []*QueryStructMeta) (names []string) { 241 for _, base := range bases { 242 names = append(names, base.ModelStructName) 243 } 244 return names 245 }