Skip to content
4 changes: 4 additions & 0 deletions cmd/gf/internal/cmd/cmd_z_unit_gen_dao_issue_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ func Test_Gen_Dao_Issue2572(t *testing.T) {
NoJsonTag: false,
NoModelComment: false,
Clear: false,
GenTable: false,
TypeMapping: nil,
FieldMapping: nil,
}
Expand Down Expand Up @@ -155,6 +156,7 @@ func Test_Gen_Dao_Issue2616(t *testing.T) {
NoJsonTag: false,
NoModelComment: false,
Clear: false,
GenTable: false,
TypeMapping: nil,
FieldMapping: nil,
}
Expand Down Expand Up @@ -266,6 +268,7 @@ func Test_Gen_Dao_Issue2746(t *testing.T) {
NoJsonTag: false,
NoModelComment: false,
Clear: false,
GenTable: false,
TypeMapping: nil,
FieldMapping: nil,
}
Expand Down Expand Up @@ -338,6 +341,7 @@ func Test_Gen_Dao_Issue3459(t *testing.T) {
NoJsonTag: false,
NoModelComment: false,
Clear: false,
GenTable: false,
TypeMapping: nil,
}
)
Expand Down
3 changes: 3 additions & 0 deletions cmd/gf/internal/cmd/cmd_z_unit_gen_dao_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ func Test_Gen_Dao_Default(t *testing.T) {
NoJsonTag: false,
NoModelComment: false,
Clear: false,
GenTable: false,
TypeMapping: nil,
FieldMapping: nil,
}
Expand Down Expand Up @@ -161,6 +162,7 @@ func Test_Gen_Dao_TypeMapping(t *testing.T) {
NoJsonTag: false,
NoModelComment: false,
Clear: false,
GenTable: false,
TypeMapping: map[gendao.DBFieldTypeName]gendao.CustomAttributeType{
"int": {
Type: "int64",
Expand Down Expand Up @@ -263,6 +265,7 @@ func Test_Gen_Dao_FieldMapping(t *testing.T) {
NoJsonTag: false,
NoModelComment: false,
Clear: false,
GenTable: false,
TypeMapping: map[gendao.DBFieldTypeName]gendao.CustomAttributeType{
"int": {
Type: "int64",
Expand Down
Binary file added cmd/gf/internal/cmd/gendao.zip
Binary file not shown.
11 changes: 11 additions & 0 deletions cmd/gf/internal/cmd/gendao/gendao.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,10 @@ type (
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"`
TablePath string `name:"tablePath" short:"tp" brief:"{CGenDaoBriefTablePath}" d:"table"`
DoPath string `name:"doPath" short:"o" brief:"{CGenDaoBriefDoPath}" d:"model/do"`
EntityPath string `name:"entityPath" short:"e" brief:"{CGenDaoBriefEntityPath}" d:"model/entity"`
TplDaoTablePath string `name:"tplDaoTablePath" short:"t0" brief:"{CGenDaoBriefTplDaoTablePath}"`
TplDaoIndexPath string `name:"tplDaoIndexPath" short:"t1" brief:"{CGenDaoBriefTplDaoIndexPath}"`
TplDaoInternalPath string `name:"tplDaoInternalPath" short:"t2" brief:"{CGenDaoBriefTplDaoInternalPath}"`
TplDaoDoPath string `name:"tplDaoDoPath" short:"t3" brief:"{CGenDaoBriefTplDaoDoPathPath}"`
Expand All @@ -61,6 +63,7 @@ type (
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"`
GenTable bool `name:"genTable" short:"gt" brief:"{CGenDaoBriefGenTable}" orphan:"true"`

TypeMapping map[DBFieldTypeName]CustomAttributeType `name:"typeMapping" short:"y" brief:"{CGenDaoBriefTypeMapping}" orphan:"true"`
FieldMapping map[DBTableFieldName]CustomAttributeType `name:"fieldMapping" short:"fm" brief:"{CGenDaoBriefFieldMapping}" orphan:"true"`
Expand Down Expand Up @@ -279,6 +282,14 @@ func doGenDaoForArray(ctx context.Context, index int, in CGenDaoInput) {
NewTableNames: newTableNames,
ShardingTableSet: shardingNewTableSet,
})
// Table: table fields.
generateTable(ctx, CGenDaoInternalInput{
CGenDaoInput: in,
DB: db,
TableNames: tableNames,
NewTableNames: newTableNames,
ShardingTableSet: shardingNewTableSet,
})
// Do.
generateDo(ctx, CGenDaoInternalInput{
CGenDaoInput: in,
Expand Down
147 changes: 147 additions & 0 deletions cmd/gf/internal/cmd/gendao/gendao_table.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
// 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 (
"bytes"
"context"
"path/filepath"
"sort"
"strconv"
"strings"

"github.com/gogf/gf/v2/database/gdb"
"github.com/gogf/gf/v2/os/gfile"
"github.com/gogf/gf/v2/os/gview"
"github.com/gogf/gf/v2/text/gstr"
"github.com/gogf/gf/v2/util/gconv"

"github.com/gogf/gf/cmd/gf/v2/internal/consts"
"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog"
"github.com/gogf/gf/cmd/gf/v2/internal/utility/utils"
)

// generateTable generates dao files for given tables.
func generateTable(ctx context.Context, in CGenDaoInternalInput) {
dirPathTable := gfile.Join(in.Path, in.TablePath)
if !in.GenTable {
if gfile.Exists(dirPathTable) {
in.genItems.AppendDirPath(dirPathTable)
}
return
}
in.genItems.AppendDirPath(dirPathTable)
for i := 0; i < len(in.TableNames); i++ {
var (
realTableName = in.TableNames[i]
newTableName = in.NewTableNames[i]
)
generateTableSingle(ctx, generateTableSingleInput{
CGenDaoInternalInput: in,
TableName: realTableName,
NewTableName: newTableName,
DirPathTable: dirPathTable,
})
}
}

// generateTableSingleInput is the input parameter for generateTableSingle.
type generateTableSingleInput struct {
CGenDaoInternalInput
// TableName specifies the table name of the table.
TableName string
// NewTableName specifies the prefix-stripped or custom edited name of the table.
NewTableName string
DirPathTable string
}

// generateTableSingle generates dao files for a single table.
func generateTableSingle(ctx context.Context, in generateTableSingleInput) {
// Generating table data preparing.
fieldMap, err := in.DB.TableFields(ctx, in.TableName)
if err != nil {
mlog.Fatalf(`fetching tables fields failed for table "%s": %+v`, in.TableName, err)
}

tableNameSnakeCase := gstr.CaseSnake(in.NewTableName)
fileName := gstr.Trim(tableNameSnakeCase, "-_.")
if len(fileName) > 5 && fileName[len(fileName)-5:] == "_test" {
// Add suffix to avoid the table name which contains "_test",
// which would make the go file a testing file.
fileName += "_table"
}
path := filepath.FromSlash(gfile.Join(in.DirPathTable, fileName+".go"))
in.genItems.AppendGeneratedFilePath(path)
if in.OverwriteDao || !gfile.Exists(path) {
var (
ctx = context.Background()
tplContent = getTemplateFromPathOrDefault(
in.TplDaoTablePath, consts.TemplateGenTableContent,
)
)
tplView.ClearAssigns()
tplView.Assigns(gview.Params{
tplVarGroupName: in.Group,
tplVarTableName: in.TableName,
tplVarTableNameCamelCase: formatFieldName(in.NewTableName, FieldNameCaseCamel),
tplVarPackageName: filepath.Base(in.TablePath),
tplVarTableFields: generateTableFields(fieldMap),
})
indexContent, err := tplView.ParseContent(ctx, tplContent)
if err != nil {
mlog.Fatalf("parsing template content failed: %v", err)
}
if err = gfile.PutContents(path, strings.TrimSpace(indexContent)); err != nil {
mlog.Fatalf("writing content to '%s' failed: %v", path, err)
} else {
utils.GoFmt(path)
mlog.Print("generated:", gfile.RealPath(path))
}
}
}

// generateTableFields generates and returns the field definition content for specified table.
func generateTableFields(fields map[string]*gdb.TableField) string {
var buf bytes.Buffer
fieldNames := make([]string, 0, len(fields))
for fieldName := range fields {
fieldNames = append(fieldNames, fieldName)
}
sort.Slice(fieldNames, func(i, j int) bool {
return fields[fieldNames[i]].Index < fields[fieldNames[j]].Index // asc
})
for index, fieldName := range fieldNames {
field := fields[fieldName]
buf.WriteString(" " + strconv.Quote(field.Name) + ": {\n")
buf.WriteString(" Index: " + gconv.String(field.Index) + ",\n")
buf.WriteString(" Name: " + strconv.Quote(field.Name) + ",\n")
buf.WriteString(" Type: " + strconv.Quote(field.Type) + ",\n")
buf.WriteString(" Null: " + gconv.String(field.Null) + ",\n")
buf.WriteString(" Key: " + strconv.Quote(field.Key) + ",\n")
buf.WriteString(" Default: " + generateDefaultValue(field.Default) + ",\n")
buf.WriteString(" Extra: " + strconv.Quote(field.Extra) + ",\n")
buf.WriteString(" Comment: " + strconv.Quote(field.Comment) + ",\n")
buf.WriteString(" },")
if index != len(fieldNames)-1 {
buf.WriteString("\n")
}
}
return buf.String()
}

// generateDefaultValue generates and returns the default value definition for specified field.
func generateDefaultValue(value interface{}) string {
if value == nil {
return "nil"
}
switch v := value.(type) {
case string:
return strconv.Quote(v)
default:
return gconv.String(v)
}
}
5 changes: 5 additions & 0 deletions cmd/gf/internal/cmd/gendao/gendao_tag.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ CONFIGURATION SUPPORT
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`
CGenDaoBriefTablePath = `directory path for storing generated table 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`
Expand All @@ -69,6 +70,7 @@ CONFIGURATION SUPPORT
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`
CGenDaoBriefGenTable = `generate table files`
CGenDaoBriefTypeMapping = `custom local type mapping for generated struct attributes relevant to fields of table`
CGenDaoBriefFieldMapping = `custom local type mapping for generated struct attributes relevant to specific fields of table`
CGenDaoBriefShardingPattern = `sharding pattern for table name, e.g. "users_?" will be replace tables "users_001,users_002,..." to "users" dao`
Expand Down Expand Up @@ -98,6 +100,7 @@ generated json tag case for model struct, cases are as follows:
tplVarTableNameCamelLowerCase = `TplTableNameCamelLowerCase`
tplVarTableSharding = `TplTableSharding`
tplVarTableShardingPrefix = `TplTableShardingPrefix`
tplVarTableFields = `TplTableFields`
tplVarPackageImports = `TplPackageImports`
tplVarImportPrefix = `TplImportPrefix`
tplVarStructDefine = `TplStructDefine`
Expand Down Expand Up @@ -126,6 +129,7 @@ func init() {
`CGenDaoBriefStdTime`: CGenDaoBriefStdTime,
`CGenDaoBriefWithTime`: CGenDaoBriefWithTime,
`CGenDaoBriefDaoPath`: CGenDaoBriefDaoPath,
`CGenDaoBriefTablePath`: CGenDaoBriefTablePath,
`CGenDaoBriefDoPath`: CGenDaoBriefDoPath,
`CGenDaoBriefEntityPath`: CGenDaoBriefEntityPath,
`CGenDaoBriefGJsonSupport`: CGenDaoBriefGJsonSupport,
Expand All @@ -137,6 +141,7 @@ func init() {
`CGenDaoBriefNoJsonTag`: CGenDaoBriefNoJsonTag,
`CGenDaoBriefNoModelComment`: CGenDaoBriefNoModelComment,
`CGenDaoBriefClear`: CGenDaoBriefClear,
`CGenDaoBriefGenTable`: CGenDaoBriefGenTable,
`CGenDaoBriefTypeMapping`: CGenDaoBriefTypeMapping,
`CGenDaoBriefFieldMapping`: CGenDaoBriefFieldMapping,
`CGenDaoBriefShardingPattern`: CGenDaoBriefShardingPattern,
Expand Down
35 changes: 35 additions & 0 deletions cmd/gf/internal/consts/consts_gen_dao_template_table.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// 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 consts

const TemplateGenTableContent = `
// =================================================================================
// This file is auto-generated by the GoFrame CLI tool. You may modify it as needed.
// =================================================================================

package {{.TplPackageName}}

import (
"context"

"github.com/gogf/gf/v2/database/gdb"
)

// {{.TplTableNameCamelCase}} defines the fields of table "{{.TplTableName}}" with their properties.
// This map is used internally by GoFrame ORM to understand table structure.
var {{.TplTableNameCamelCase}} = map[string]*gdb.TableField{
{{.TplTableFields}}
}

// Set{{.TplTableNameCamelCase}}TableFields registers the table fields definition to the database instance.
// db: database instance that implements gdb.DB interface.
// schema: optional schema/namespace name, especially for databases that support schemas.
func Set{{.TplTableNameCamelCase}}TableFields(ctx context.Context, db gdb.DB, schema ...string) error {
return db.GetCore().SetTableFields(ctx, "{{.TplTableName}}", {{.TplTableNameCamelCase}}, schema...)
}

`
24 changes: 24 additions & 0 deletions database/gdb/gdb_core.go
Original file line number Diff line number Diff line change
Expand Up @@ -757,6 +757,30 @@ func (c *Core) GetInnerMemCache() *gcache.Cache {
return c.innerMemCache
}

func (c *Core) SetTableFields(ctx context.Context, table string, fields map[string]*TableField, schema ...string) error {
if table == "" {
return gerror.NewCode(gcode.CodeInvalidParameter, "table name cannot be empty")
}
charL, charR := c.db.GetChars()
table = gstr.Trim(table, charL+charR)
if gstr.Contains(table, " ") {
return gerror.NewCode(
gcode.CodeInvalidParameter,
"function TableFields supports only single table operations",
)
}
var (
innerMemCache = c.GetInnerMemCache()
// prefix:group@schema#table
cacheKey = genTableFieldsCacheKey(
c.db.GetGroup(),
gutil.GetOrDefaultStr(c.db.GetSchema(), schema...),
table,
)
)
return innerMemCache.Set(ctx, cacheKey, fields, gcache.DurationNoExpire)
}

// GetTablesWithCache retrieves and returns the table names of current database with cache.
func (c *Core) GetTablesWithCache() ([]string, error) {
var (
Expand Down
Loading