| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442 |
- // Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.
- //
- // This Source Code Form is subject to the terms of the MIT License.
- // If a copy of the MIT was not distributed with this file,
- // You can obtain one at https://github.com/gogf/gf.
- package gendao
- import (
- "context"
- "fmt"
- "golang.org/x/mod/modfile"
- "strings"
- "github.com/gogf/gf/cmd/gf/v2/internal/utility/utils"
- "github.com/gogf/gf/v2/container/garray"
- "github.com/gogf/gf/v2/database/gdb"
- "github.com/gogf/gf/v2/frame/g"
- "github.com/gogf/gf/v2/os/gfile"
- "github.com/gogf/gf/v2/os/gproc"
- "github.com/gogf/gf/v2/os/gtime"
- "github.com/gogf/gf/v2/text/gstr"
- "github.com/gogf/gf/v2/util/gtag"
- "github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog"
- )
- const (
- CGenDaoConfig = `gfcli.gen.dao`
- CGenDaoUsage = `gf gen dao [OPTION]`
- CGenDaoBrief = `automatically generate go files for dao/do/entity`
- CGenDaoEg = `
- gf gen dao
- gf gen dao -l "mysql:root:12345678@tcp(127.0.0.1:3306)/test"
- gf gen dao -p ./model -g user-center -t user,user_detail,user_login
- gf gen dao -r user_
- `
- CGenDaoAd = `
- CONFIGURATION SUPPORT
- Options are also supported by configuration file.
- It's suggested using configuration file instead of command line arguments making producing.
- The configuration node name is "gfcli.gen.dao", which also supports multiple databases, for example(config.yaml):
- gfcli:
- gen:
- dao:
- - link: "mysql:root:12345678@tcp(127.0.0.1:3306)/test"
- tables: "order,products"
- jsonCase: "CamelLower"
- - link: "mysql:root:12345678@tcp(127.0.0.1:3306)/primary"
- path: "./my-app"
- prefix: "primary_"
- tables: "user, userDetail"
- typeMapping:
- decimal:
- type: decimal.Decimal
- import: github.com/shopspring/decimal
- numeric:
- type: string
- `
- CGenDaoBriefPath = `directory path for generated files`
- CGenDaoBriefLink = `database configuration, the same as the ORM configuration of GoFrame`
- CGenDaoBriefTables = `generate models only for given tables, multiple table names separated with ','`
- CGenDaoBriefTablesEx = `generate models excluding given tables, multiple table names separated with ','`
- CGenDaoBriefPrefix = `add prefix for all table of specified link/database tables`
- CGenDaoBriefRemovePrefix = `remove specified prefix of the table, multiple prefix separated with ','`
- CGenDaoBriefStdTime = `use time.Time from stdlib instead of gtime.Time for generated time/date fields of tables`
- CGenDaoBriefWithTime = `add created time for auto produced go files`
- CGenDaoBriefGJsonSupport = `use gJsonSupport to use *gjson.Json instead of string for generated json fields of tables`
- CGenDaoBriefImportPrefix = `custom import prefix for generated go files`
- CGenDaoBriefDaoPath = `directory path for storing generated dao files under path`
- CGenDaoBriefDoPath = `directory path for storing generated do files under path`
- CGenDaoBriefEntityPath = `directory path for storing generated entity files under path`
- CGenDaoBriefOverwriteDao = `overwrite all dao files both inside/outside internal folder`
- CGenDaoBriefModelFile = `custom file name for storing generated model content`
- CGenDaoBriefModelFileForDao = `custom file name generating model for DAO operations like Where/Data. It's empty in default`
- CGenDaoBriefDescriptionTag = `add comment to description tag for each field`
- CGenDaoBriefNoJsonTag = `no json tag will be added for each field`
- CGenDaoBriefNoModelComment = `no model comment will be added for each field`
- CGenDaoBriefClear = `delete all generated go files that do not exist in database`
- CGenDaoBriefTypeMapping = `custom local type mapping for generated struct attributes relevant to fields of table`
- CGenDaoBriefGroup = `
- specifying the configuration group name of database for generated ORM instance,
- it's not necessary and the default value is "default"
- `
- CGenDaoBriefJsonCase = `
- generated json tag case for model struct, cases are as follows:
- | Case | Example |
- |---------------- |--------------------|
- | Camel | AnyKindOfString |
- | CamelLower | anyKindOfString | default
- | Snake | any_kind_of_string |
- | SnakeScreaming | ANY_KIND_OF_STRING |
- | SnakeFirstUpper | rgb_code_md5 |
- | Kebab | any-kind-of-string |
- | KebabScreaming | ANY-KIND-OF-STRING |
- `
- CGenDaoBriefTplDaoIndexPath = `template file path for dao index file`
- CGenDaoBriefTplDaoInternalPath = `template file path for dao internal file`
- CGenDaoBriefTplDaoDoPathPath = `template file path for dao do file`
- CGenDaoBriefTplDaoEntityPath = `template file path for dao entity file`
- tplVarTableName = `{TplTableName}`
- tplVarTableNameCamelCase = `{TplTableNameCamelCase}`
- tplVarTableNameCamelLowerCase = `{TplTableNameCamelLowerCase}`
- tplVarPackageImports = `{TplPackageImports}`
- tplVarImportPrefix = `{TplImportPrefix}`
- tplVarStructDefine = `{TplStructDefine}`
- tplVarColumnDefine = `{TplColumnDefine}`
- tplVarColumnNames = `{TplColumnNames}`
- tplVarGroupName = `{TplGroupName}`
- tplVarDatetimeStr = `{TplDatetimeStr}`
- tplVarCreatedAtDatetimeStr = `{TplCreatedAtDatetimeStr}`
- )
- var (
- createdAt = gtime.Now()
- defaultTypeMapping = map[string]TypeMapping{
- "decimal": {
- Type: "float64",
- },
- "money": {
- Type: "float64",
- },
- "numeric": {
- Type: "float64",
- },
- "smallmoney": {
- Type: "float64",
- },
- "tinyint": {
- Type: "int64",
- },
- "smallint": {
- Type: "int64",
- },
- "mediumint": {
- Type: "int64",
- },
- "int": {
- Type: "int64",
- },
- "bigint": {
- Type: "int64",
- },
- }
- )
- func init() {
- gtag.Sets(g.MapStrStr{
- `CGenDaoConfig`: CGenDaoConfig,
- `CGenDaoUsage`: CGenDaoUsage,
- `CGenDaoBrief`: CGenDaoBrief,
- `CGenDaoEg`: CGenDaoEg,
- `CGenDaoAd`: CGenDaoAd,
- `CGenDaoBriefPath`: CGenDaoBriefPath,
- `CGenDaoBriefLink`: CGenDaoBriefLink,
- `CGenDaoBriefTables`: CGenDaoBriefTables,
- `CGenDaoBriefTablesEx`: CGenDaoBriefTablesEx,
- `CGenDaoBriefPrefix`: CGenDaoBriefPrefix,
- `CGenDaoBriefRemovePrefix`: CGenDaoBriefRemovePrefix,
- `CGenDaoBriefStdTime`: CGenDaoBriefStdTime,
- `CGenDaoBriefWithTime`: CGenDaoBriefWithTime,
- `CGenDaoBriefDaoPath`: CGenDaoBriefDaoPath,
- `CGenDaoBriefDoPath`: CGenDaoBriefDoPath,
- `CGenDaoBriefEntityPath`: CGenDaoBriefEntityPath,
- `CGenDaoBriefGJsonSupport`: CGenDaoBriefGJsonSupport,
- `CGenDaoBriefImportPrefix`: CGenDaoBriefImportPrefix,
- `CGenDaoBriefOverwriteDao`: CGenDaoBriefOverwriteDao,
- `CGenDaoBriefModelFile`: CGenDaoBriefModelFile,
- `CGenDaoBriefModelFileForDao`: CGenDaoBriefModelFileForDao,
- `CGenDaoBriefDescriptionTag`: CGenDaoBriefDescriptionTag,
- `CGenDaoBriefNoJsonTag`: CGenDaoBriefNoJsonTag,
- `CGenDaoBriefNoModelComment`: CGenDaoBriefNoModelComment,
- `CGenDaoBriefClear`: CGenDaoBriefClear,
- `CGenDaoBriefTypeMapping`: CGenDaoBriefTypeMapping,
- `CGenDaoBriefGroup`: CGenDaoBriefGroup,
- `CGenDaoBriefJsonCase`: CGenDaoBriefJsonCase,
- `CGenDaoBriefTplDaoIndexPath`: CGenDaoBriefTplDaoIndexPath,
- `CGenDaoBriefTplDaoInternalPath`: CGenDaoBriefTplDaoInternalPath,
- `CGenDaoBriefTplDaoDoPathPath`: CGenDaoBriefTplDaoDoPathPath,
- `CGenDaoBriefTplDaoEntityPath`: CGenDaoBriefTplDaoEntityPath,
- })
- }
- type (
- CGenDao struct{}
- CGenDaoInput struct {
- g.Meta `name:"dao" config:"{CGenDaoConfig}" usage:"{CGenDaoUsage}" brief:"{CGenDaoBrief}" eg:"{CGenDaoEg}" ad:"{CGenDaoAd}"`
- Path string `name:"path" short:"p" brief:"{CGenDaoBriefPath}" d:"internal"`
- Link string `name:"link" short:"l" brief:"{CGenDaoBriefLink}"`
- Tables string `name:"tables" short:"t" brief:"{CGenDaoBriefTables}"`
- TablesEx string `name:"tablesEx" short:"x" brief:"{CGenDaoBriefTablesEx}"`
- Group string `name:"group" short:"g" brief:"{CGenDaoBriefGroup}" d:"default"`
- Prefix string `name:"prefix" short:"f" brief:"{CGenDaoBriefPrefix}"`
- RemovePrefix string `name:"removePrefix" short:"r" brief:"{CGenDaoBriefRemovePrefix}"`
- JsonCase string `name:"jsonCase" short:"j" brief:"{CGenDaoBriefJsonCase}" d:"CamelLower"`
- ImportPrefix string `name:"importPrefix" short:"i" brief:"{CGenDaoBriefImportPrefix}"`
- DaoPath string `name:"daoPath" short:"d" brief:"{CGenDaoBriefDaoPath}" d:"dao"`
- DoPath string `name:"doPath" short:"o" brief:"{CGenDaoBriefDoPath}" d:"model/do"`
- EntityPath string `name:"entityPath" short:"e" brief:"{CGenDaoBriefEntityPath}" d:"model/entity"`
- TplDaoIndexPath string `name:"tplDaoIndexPath" short:"t1" brief:"{CGenDaoBriefTplDaoIndexPath}"`
- TplDaoInternalPath string `name:"tplDaoInternalPath" short:"t2" brief:"{CGenDaoBriefTplDaoInternalPath}"`
- TplDaoDoPath string `name:"tplDaoDoPath" short:"t3" brief:"{CGenDaoBriefTplDaoDoPathPath}"`
- TplDaoEntityPath string `name:"tplDaoEntityPath" short:"t4" brief:"{CGenDaoBriefTplDaoEntityPath}"`
- StdTime bool `name:"stdTime" short:"s" brief:"{CGenDaoBriefStdTime}" orphan:"true"`
- WithTime bool `name:"withTime" short:"w" brief:"{CGenDaoBriefWithTime}" orphan:"true"`
- GJsonSupport bool `name:"gJsonSupport" short:"n" brief:"{CGenDaoBriefGJsonSupport}" orphan:"true"`
- OverwriteDao bool `name:"overwriteDao" short:"v" brief:"{CGenDaoBriefOverwriteDao}" orphan:"true"`
- DescriptionTag bool `name:"descriptionTag" short:"c" brief:"{CGenDaoBriefDescriptionTag}" orphan:"true"`
- NoJsonTag bool `name:"noJsonTag" short:"k" brief:"{CGenDaoBriefNoJsonTag}" orphan:"true"`
- NoModelComment bool `name:"noModelComment" short:"m" brief:"{CGenDaoBriefNoModelComment}" orphan:"true"`
- Clear bool `name:"clear" short:"a" brief:"{CGenDaoBriefClear}" orphan:"true"`
- TypeMapping map[string]TypeMapping `name:"typeMapping" short:"y" brief:"{CGenDaoBriefTypeMapping}" orphan:"true"`
- }
- CGenDaoOutput struct{}
- CGenDaoInternalInput struct {
- CGenDaoInput
- DB gdb.DB
- TableNames []string
- NewTableNames []string
- }
- TypeMapping struct {
- Type string `brief:"custom attribute type name"`
- Import string `brief:"custom import for this type"`
- }
- )
- func (c CGenDao) Dao(ctx context.Context, in CGenDaoInput) (out *CGenDaoOutput, err error) {
- if g.Cfg().Available(ctx) {
- v := g.Cfg().MustGet(ctx, CGenDaoConfig)
- if v.IsSlice() {
- for i := 0; i < len(v.Interfaces()); i++ {
- doGenDaoForArray(ctx, i, in)
- }
- } else {
- doGenDaoForArray(ctx, -1, in)
- }
- } else {
- doGenDaoForArray(ctx, -1, in)
- }
- mlog.Print("done!")
- return
- }
- // doGenDaoForArray implements the "gen dao" command for configuration array.
- func doGenDaoForArray(ctx context.Context, index int, in CGenDaoInput) {
- var (
- err error
- db gdb.DB
- )
- if index >= 0 {
- err = g.Cfg().MustGet(
- ctx,
- fmt.Sprintf(`%s.%d`, CGenDaoConfig, index),
- ).Scan(&in)
- if err != nil {
- mlog.Fatalf(`invalid configuration of "%s": %+v`, CGenDaoConfig, err)
- }
- }
- if dirRealPath := gfile.RealPath(in.Path); dirRealPath == "" {
- mlog.Fatalf(`path "%s" does not exist`, in.Path)
- }
- removePrefixArray := gstr.SplitAndTrim(in.RemovePrefix, ",")
- // It uses user passed database configuration.
- if in.Link != "" {
- var tempGroup = gtime.TimestampNanoStr()
- gdb.AddConfigNode(tempGroup, gdb.ConfigNode{
- Link: in.Link,
- })
- if db, err = gdb.Instance(tempGroup); err != nil {
- mlog.Fatalf(`database initialization failed: %+v`, err)
- }
- } else {
- db = g.DB(in.Group)
- }
- if db == nil {
- mlog.Fatal(`database initialization failed, may be invalid database configuration`)
- }
- var tableNames []string
- if in.Tables != "" {
- tableNames = gstr.SplitAndTrim(in.Tables, ",")
- } else {
- tableNames, err = db.Tables(context.TODO())
- if err != nil {
- mlog.Fatalf("fetching tables failed: %+v", err)
- }
- }
- // Table excluding.
- if in.TablesEx != "" {
- array := garray.NewStrArrayFrom(tableNames)
- for _, v := range gstr.SplitAndTrim(in.TablesEx, ",") {
- array.RemoveValue(v)
- }
- tableNames = array.Slice()
- }
- // merge default typeMapping to input typeMapping.
- if in.TypeMapping == nil {
- in.TypeMapping = defaultTypeMapping
- } else {
- for key, typeMapping := range defaultTypeMapping {
- if _, ok := in.TypeMapping[key]; !ok {
- in.TypeMapping[key] = typeMapping
- }
- }
- }
- // Generating dao & model go files one by one according to given table name.
- newTableNames := make([]string, len(tableNames))
- for i, tableName := range tableNames {
- newTableName := tableName
- for _, v := range removePrefixArray {
- newTableName = gstr.TrimLeftStr(newTableName, v, 1)
- }
- newTableName = in.Prefix + newTableName
- newTableNames[i] = newTableName
- }
- // Dao: index and internal.
- generateDao(ctx, CGenDaoInternalInput{
- CGenDaoInput: in,
- DB: db,
- TableNames: tableNames,
- NewTableNames: newTableNames,
- })
- // Do.
- generateDo(ctx, CGenDaoInternalInput{
- CGenDaoInput: in,
- DB: db,
- TableNames: tableNames,
- NewTableNames: newTableNames,
- })
- // Entity.
- generateEntity(ctx, CGenDaoInternalInput{
- CGenDaoInput: in,
- DB: db,
- TableNames: tableNames,
- NewTableNames: newTableNames,
- })
- }
- func getImportPartContent(ctx context.Context, source string, isDo bool, appendImports []string) string {
- var packageImportsArray = garray.NewStrArray()
- if isDo {
- packageImportsArray.Append(`"github.com/gogf/gf/v2/frame/g"`)
- }
- // Time package recognition.
- if strings.Contains(source, "gtime.Time") {
- packageImportsArray.Append(`"github.com/gogf/gf/v2/os/gtime"`)
- } else if strings.Contains(source, "time.Time") {
- packageImportsArray.Append(`"time"`)
- }
- // Json type.
- if strings.Contains(source, "gjson.Json") {
- packageImportsArray.Append(`"github.com/gogf/gf/v2/encoding/gjson"`)
- }
- // Check and update imports in go.mod
- if appendImports != nil && len(appendImports) > 0 {
- goModPath := utils.GetModPath()
- if goModPath == "" {
- mlog.Fatal("go.mod not found in current project")
- }
- mod, err := modfile.Parse(goModPath, gfile.GetBytes(goModPath), nil)
- if err != nil {
- mlog.Fatalf("parse go.mod failed: %+v", err)
- }
- for _, appendImport := range appendImports {
- found := false
- for _, require := range mod.Require {
- if gstr.Contains(appendImport, require.Mod.Path) {
- found = true
- break
- }
- }
- if !found {
- err = gproc.ShellRun(ctx, `go get `+appendImport)
- mlog.Fatalf(`%+v`, err)
- }
- packageImportsArray.Append(fmt.Sprintf(`"%s"`, appendImport))
- }
- }
- // Generate and write content to golang file.
- packageImportsStr := ""
- if packageImportsArray.Len() > 0 {
- packageImportsStr = fmt.Sprintf("import(\n%s\n)", packageImportsArray.Join("\n"))
- }
- return packageImportsStr
- }
- func replaceDefaultVar(in CGenDaoInternalInput, origin string) string {
- var tplCreatedAtDatetimeStr string
- var tplDatetimeStr string = createdAt.String()
- if in.WithTime {
- tplCreatedAtDatetimeStr = fmt.Sprintf(`Created at %s`, tplDatetimeStr)
- }
- return gstr.ReplaceByMap(origin, g.MapStrStr{
- tplVarDatetimeStr: tplDatetimeStr,
- tplVarCreatedAtDatetimeStr: tplCreatedAtDatetimeStr,
- })
- }
- func sortFieldKeyForDao(fieldMap map[string]*gdb.TableField) []string {
- names := make(map[int]string)
- for _, field := range fieldMap {
- names[field.Index] = field.Name
- }
- var (
- i = 0
- j = 0
- result = make([]string, len(names))
- )
- for {
- if len(names) == 0 {
- break
- }
- if val, ok := names[i]; ok {
- result[j] = val
- j++
- delete(names, i)
- }
- i++
- }
- return result
- }
- func getTemplateFromPathOrDefault(filePath string, def string) string {
- if filePath != "" {
- if contents := gfile.GetContents(filePath); contents != "" {
- return contents
- }
- }
- return def
- }
|