This commit is contained in:
孟帅
2025-10-25 00:35:30 +08:00
parent 5ebc33f28b
commit 7313d22cdb
168 changed files with 2349 additions and 1455 deletions

View File

@@ -30,12 +30,10 @@ import (
"hotgo/internal/library/hggen/internal/utility/mlog"
)
var (
Build = cBuild{
nodeNameInConfigFile: "gfcli.build",
packedGoFileName: "internal/packed/build_pack_data.go",
}
)
var Build = cBuild{
nodeNameInConfigFile: "gfcli.build",
packedGoFileName: "internal/packed/build_pack_data.go",
}
type cBuild struct {
g.Meta `name:"build" brief:"{cBuildBrief}" dc:"{cBuildDc}" eg:"{cBuildEg}" ad:"{cBuildAd}"`
@@ -65,45 +63,67 @@ It provides much more features for building binary:
`
cBuildAd = `
PLATFORMS
aix ppc64
android 386,amd64,arm,arm64
darwin amd64,arm64
dragonfly amd64
freebsd 386,amd64,arm
linux 386,amd64,arm,arm64,ppc64,ppc64le,mips,mipsle,mips64,mips64le
illumos amd64
ios arm64
js wasm
linux 386,amd64,arm,arm64,loong64,mips,mipsle,mips64,mips64le,ppc64,ppc64le,riscv64,s390x
netbsd 386,amd64,arm
openbsd 386,amd64,arm
windows 386,amd64
openbsd 386,amd64,arm,arm64
plan9 386,amd64,arm
solaris amd64
wasip1 wasm
windows 386,amd64,arm,arm64
`
// https://golang.google.cn/doc/install/source
cBuildPlatforms = `
aix ppc64
android 386
android amd64
android arm
android arm64
darwin amd64
darwin arm64
ios amd64
ios arm64
dragonfly amd64
freebsd 386
freebsd amd64
freebsd arm
illumos amd64
ios arm64
js wasm
linux 386
linux amd64
linux arm
linux arm64
linux ppc64
linux ppc64le
linux loong64
linux mips
linux mipsle
linux mips64
linux mips64le
linux ppc64
linux ppc64le
linux riscv64
linux s390x
netbsd 386
netbsd amd64
netbsd arm
openbsd 386
openbsd amd64
openbsd arm
windows 386
windows amd64
android arm
dragonfly amd64
openbsd arm64
plan9 386
plan9 amd64
plan9 arm
solaris amd64
wasip1 wasm
windows 386
windows amd64
windows arm
windows arm64
`
)

View File

@@ -11,6 +11,8 @@ import (
"context"
"github.com/olekukonko/tablewriter"
"github.com/olekukonko/tablewriter/renderer"
"github.com/olekukonko/tablewriter/tw"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gproc"
@@ -61,10 +63,23 @@ func (c cEnv) Index(ctx context.Context, in cEnvInput) (out *cEnvOutput, err err
}
array = append(array, []string{gstr.Trim(match[1]), gstr.Trim(match[2])})
}
tw := tablewriter.NewWriter(buffer)
tw.SetColumnAlignment([]int{tablewriter.ALIGN_LEFT, tablewriter.ALIGN_LEFT})
tw.AppendBulk(array)
tw.Render()
table := tablewriter.NewTable(buffer,
tablewriter.WithRenderer(renderer.NewBlueprint(tw.Rendition{
Settings: tw.Settings{
Separators: tw.Separators{BetweenRows: tw.Off, BetweenColumns: tw.On},
},
Symbols: tw.NewSymbols(tw.StyleASCII),
})),
tablewriter.WithConfig(tablewriter.Config{
Row: tw.CellConfig{
Formatting: tw.CellFormatting{AutoWrap: tw.WrapNone},
Alignment: tw.CellAlignment{PerColumn: []tw.Align{tw.AlignLeft, tw.AlignLeft}},
ColMaxWidths: tw.CellWidth{Global: 84},
},
}),
)
table.Bulk(array)
table.Render()
mlog.Print(buffer.String())
return
}

View File

@@ -13,6 +13,7 @@ import (
"path/filepath"
"runtime"
"strings"
"time"
"github.com/gogf/gf/v2/container/gtype"
"github.com/gogf/gf/v2/frame/g"
@@ -26,9 +27,7 @@ import (
"hotgo/internal/library/hggen/internal/utility/mlog"
)
var (
Run = cRun{}
)
var Run = cRun{}
type cRun struct {
g.Meta `name:"run" usage:"{cRunUsage}" brief:"{cRunBrief}" eg:"{cRunEg}" dc:"{cRunDc}"`
@@ -62,9 +61,7 @@ which compiles and runs the go codes asynchronously when codes change.
cRunWatchPathsBrief = `watch additional paths for live reload, separated by ",". i.e. "manifest/config/*.yaml"`
)
var (
process *gproc.Process
)
var process *gproc.Process
func init() {
gtag.Sets(g.MapStrStr{
@@ -118,8 +115,12 @@ func (c cRun) Index(ctx context.Context, in cRunInput) (out *cRunOutput, err err
}
dirty := gtype.NewBool()
var outputPath = app.genOutputPath()
outputPath := app.genOutputPath()
callbackFunc := func(event *gfsnotify.Event) {
if !event.IsWrite() && !event.IsCreate() && !event.IsRemove() && !event.IsRename() {
return
}
if gfile.ExtName(event.Path) != "go" {
return
}
@@ -207,8 +208,37 @@ func (app *cRunApp) End(ctx context.Context, sig os.Signal, outputPath string) {
// Delete the binary file.
// firstly, kill the process.
if process != nil {
if err := process.Kill(); err != nil {
mlog.Debugf("kill process error: %s", err.Error())
if sig != nil && runtime.GOOS != "windows" {
if err := process.Signal(sig); err != nil {
mlog.Debugf("send signal to process error: %s", err.Error())
if err := process.Kill(); err != nil {
mlog.Debugf("kill process error: %s", err.Error())
}
} else {
waitCtx, cancel := context.WithTimeout(ctx, 30*time.Second)
defer cancel()
done := make(chan error, 1)
go func() {
select {
case <-waitCtx.Done():
done <- waitCtx.Err()
case done <- process.Wait():
}
}()
err := <-done
if err != nil {
mlog.Debugf("process wait error: %s", err.Error())
if err := process.Kill(); err != nil {
mlog.Debugf("kill process error: %s", err.Error())
}
} else {
mlog.Debug("process exited gracefully")
}
}
} else {
if err := process.Kill(); err != nil {
mlog.Debugf("kill process error: %s", err.Error())
}
}
}
if err := gfile.RemoveFile(outputPath); err != nil {

View File

@@ -15,6 +15,7 @@ import (
"github.com/gogf/gf/v2/container/gset"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/genv"
"github.com/gogf/gf/v2/os/gfile"
"github.com/gogf/gf/v2/os/gproc"
"github.com/gogf/gf/v2/text/gstr"
@@ -39,7 +40,11 @@ gf up
gf up -a
gf up -c
gf up -cf
gf up -a -m=install
gf up -a -m=install -p=github.com/gogf/gf/cmd/gf/v2@latest
`
cliMethodHttpDownload = "http"
cliMethodGoInstall = "install"
)
func init() {
@@ -49,10 +54,14 @@ func init() {
}
type cUpInput struct {
g.Meta `name:"up" config:"gfcli.up"`
All bool `name:"all" short:"a" brief:"upgrade both version and cli, auto fix codes" orphan:"true"`
Cli bool `name:"cli" short:"c" brief:"also upgrade CLI tool" orphan:"true"`
Fix bool `name:"fix" short:"f" brief:"auto fix codes(it only make sense if cli is to be upgraded)" orphan:"true"`
g.Meta `name:"up" config:"gfcli.up"`
All bool `name:"all" short:"a" brief:"upgrade both version and cli, auto fix codes" orphan:"true"`
Cli bool `name:"cli" short:"c" brief:"also upgrade CLI tool" orphan:"true"`
Fix bool `name:"fix" short:"f" brief:"auto fix codes(it only make sense if cli is to be upgraded)" orphan:"true"`
CliDownloadingMethod string `name:"cli-download-method" short:"m" brief:"cli upgrade method: http=download binary via HTTP GET, install=upgrade via go install" d:"http"`
// CliModulePath specifies the module path for CLI installation via go install.
// This is used when CliDownloadingMethod is set to "install".
CliModulePath string `name:"cli-module-path" short:"p" brief:"custom cli module path for upgrade CLI tool with go install method" d:"github.com/gogf/gf/cmd/gf/v2@latest"`
}
type cUpOutput struct{}
@@ -76,7 +85,7 @@ func (c cUp) Index(ctx context.Context, in cUpInput) (out *cUpOutput, err error)
}
if in.Cli {
if err = c.doUpgradeCLI(ctx); err != nil {
if err = c.doUpgradeCLI(ctx, in); err != nil {
return nil, err
}
}
@@ -170,8 +179,22 @@ func (c cUp) doUpgradeVersion(ctx context.Context, in cUpInput) (out *doUpgradeV
}
// doUpgradeCLI downloads the new version binary with process.
func (c cUp) doUpgradeCLI(ctx context.Context) (err error) {
func (c cUp) doUpgradeCLI(ctx context.Context, in cUpInput) (err error) {
mlog.Print(`start upgrading cli...`)
fmt.Println(` cli upgrade method:`, in.CliDownloadingMethod)
switch in.CliDownloadingMethod {
case cliMethodHttpDownload:
return c.doUpgradeCLIWithHttpDownload(ctx)
case cliMethodGoInstall:
return c.doUpgradeCLIWithGoInstall(ctx, in)
default:
mlog.Fatalf(`invalid cli upgrade method: "%s", please use "http" or "install"`, in.CliDownloadingMethod)
}
return
}
func (c cUp) doUpgradeCLIWithHttpDownload(ctx context.Context) (err error) {
mlog.Print(`start upgrading cli with http get download...`)
var (
downloadUrl = fmt.Sprintf(
`https://github.com/gogf/gf/releases/latest/download/gf_%s_%s`,
@@ -213,6 +236,41 @@ func (c cUp) doUpgradeCLI(ctx context.Context) (err error) {
return
}
func (c cUp) doUpgradeCLIWithGoInstall(ctx context.Context, in cUpInput) (err error) {
mlog.Print(`upgrading cli with go install...`)
if !genv.Contains("GOPATH") {
mlog.Fatal(`"GOPATH" environment variable does not exist, please check your go installation`)
}
command := fmt.Sprintf(`go install %s`, in.CliModulePath)
mlog.Printf(`running command: %s`, command)
err = gproc.ShellRun(ctx, command)
if err != nil {
return err
}
cliFilePath := gfile.Join(genv.Get("GOPATH").String(), "bin/gf")
if runtime.GOOS == "windows" {
cliFilePath += ".exe"
}
// It fails if file not exist or its size is less than 1MB.
if !gfile.Exists(cliFilePath) || gfile.Size(cliFilePath) < 1024*1024 {
mlog.Fatalf(`go install %s failed, "%s" does not exist or its size is less than 1MB`, in.CliModulePath, cliFilePath)
}
newFile, err := gfile.Open(cliFilePath)
if err != nil {
return err
}
// selfupdate
err = selfupdate.Apply(newFile, selfupdate.Options{})
if err != nil {
return err
}
return
}
func (c cUp) doAutoFixing(ctx context.Context, dirPath string, version string) (err error) {
mlog.Printf(`auto fixing directory path "%s" from version "%s" ...`, dirPath, version)
command := fmt.Sprintf(`gf fix -p %s`, dirPath)

View File

@@ -15,6 +15,7 @@ import (
"github.com/gogf/gf/v2/os/gtime"
"github.com/gogf/gf/v2/util/gconv"
"github.com/gogf/gf/v2/util/gtag"
"hotgo/internal/library/hggen/internal/utility/mlog"
)

View File

@@ -11,6 +11,9 @@ import (
"fmt"
"strings"
"github.com/olekukonko/tablewriter"
"github.com/olekukonko/tablewriter/renderer"
"github.com/olekukonko/tablewriter/tw"
"golang.org/x/mod/modfile"
"github.com/gogf/gf/v2/container/garray"
@@ -44,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}"`
@@ -58,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"`
@@ -99,6 +105,20 @@ var (
Type: "float64",
},
}
// tablewriter Options
twRenderer = tablewriter.WithRenderer(renderer.NewBlueprint(tw.Rendition{
Borders: tw.Border{Top: tw.Off, Bottom: tw.Off, Left: tw.Off, Right: tw.Off},
Settings: tw.Settings{
Separators: tw.Separators{BetweenRows: tw.Off, BetweenColumns: tw.Off},
},
Symbols: tw.NewSymbols(tw.StyleASCII),
}))
twConfig = tablewriter.WithConfig(tablewriter.Config{
Row: tw.CellConfig{
Formatting: tw.CellFormatting{AutoWrap: tw.WrapNone},
},
})
)
func (c CGenDao) Dao(ctx context.Context, in CGenDaoInput) (out *CGenDaoOutput, err error) {
@@ -127,7 +147,7 @@ func doGenDaoForArray(ctx context.Context, index int, in CGenDaoInput) {
if in.genItems == nil {
in.genItems = newCGenDaoInternalGenItems()
}
var (
err error
db gdb.DB
@@ -177,8 +197,29 @@ func doGenDaoForArray(ctx context.Context, index int, in CGenDaoInput) {
// Table excluding.
if in.TablesEx != "" {
array := garray.NewStrArrayFrom(tableNames)
for _, v := range gstr.SplitAndTrim(in.TablesEx, ",") {
array.RemoveValue(v)
for _, p := range gstr.SplitAndTrim(in.TablesEx, ",") {
if gstr.Contains(p, "*") || gstr.Contains(p, "?") {
p = gstr.ReplaceByMap(p, map[string]string{
"\r": "",
"\n": "",
})
p = gstr.ReplaceByMap(p, map[string]string{
"*": "\r",
"?": "\n",
})
p = gregex.Quote(p)
p = gstr.ReplaceByMap(p, map[string]string{
"\r": ".*",
"\n": ".",
})
for _, v := range array.Clone().Slice() {
if gregex.IsMatchString(p, v) {
array.RemoveValue(v)
}
}
} else {
array.RemoveValue(p)
}
}
tableNames = array.Slice()
}
@@ -223,14 +264,18 @@ func doGenDaoForArray(ctx context.Context, index int, in CGenDaoInput) {
tableNames[i] = ""
continue
}
shardingNewTableSet.Add(newTableName)
// Add prefix to sharding table name, if not, the isSharding check would not match.
shardingNewTableSet.Add(in.Prefix + newTableName)
}
}
newTableName = in.Prefix + newTableName
newTableNames[i] = newTableName
if tableNames[i] != "" {
// If shardingNewTableSet contains newTableName (tableName is empty), it should not be added to tableNames, make it empty and filter later.
newTableNames[i] = newTableName
}
}
tableNames = garray.NewStrArrayFrom(tableNames).FilterEmpty().Slice()
newTableNames = garray.NewStrArrayFrom(newTableNames).FilterEmpty().Slice() // Filter empty table names. make sure that newTableNames and tableNames have the same length.
in.genItems.Scale()
// Dao: index and internal.
@@ -241,6 +286,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,

View File

@@ -127,6 +127,7 @@ func generateDaoIndex(in generateDaoIndexInput) {
tplView.ClearAssigns()
tplView.Assigns(gview.Params{
tplVarTableSharding: in.IsSharding,
tplVarTableShardingPrefix: in.NewTableName + "_",
tplVarImportPrefix: in.ImportPrefix,
tplVarTableName: in.TableName,
tplVarTableNameCamelCase: in.TableNameCamelCase,
@@ -210,13 +211,9 @@ func generateColumnNamesForDao(fieldMap map[string]*gdb.TableField, removeFieldP
fmt.Sprintf(` #"%s",`, field.Name),
}
}
tw := tablewriter.NewWriter(buffer)
tw.SetBorder(false)
tw.SetRowLine(false)
tw.SetAutoWrapText(false)
tw.SetColumnSeparator("")
tw.AppendBulk(array)
tw.Render()
table := tablewriter.NewTable(buffer, twRenderer, twConfig)
table.Bulk(array)
table.Render()
namesContent := buffer.String()
// Let's do this hack of table writer for indent!
namesContent = gstr.Replace(namesContent, " #", "")
@@ -251,13 +248,9 @@ func generateColumnDefinitionForDao(fieldMap map[string]*gdb.TableField, removeF
" #" + fmt.Sprintf(`// %s`, comment),
}
}
tw := tablewriter.NewWriter(buffer)
tw.SetBorder(false)
tw.SetRowLine(false)
tw.SetAutoWrapText(false)
tw.SetColumnSeparator("")
tw.AppendBulk(array)
tw.Render()
table := tablewriter.NewTable(buffer, twRenderer, twConfig)
table.Bulk(array)
table.Render()
defineContent := buffer.String()
// Let's do this hack of table writer for indent!
defineContent = gstr.Replace(defineContent, " #", "")

View File

@@ -45,14 +45,14 @@ func generateDo(ctx context.Context, in CGenDaoInternalInput) {
IsDo: true,
})
)
// replace all types to interface{}.
// replace all types to any.
structDefinition, _ = gregex.ReplaceStringFuncMatch(
"([A-Z]\\w*?)\\s+([\\w\\*\\.]+?)\\s+(//)",
structDefinition,
func(match []string) string {
// If the type is already a pointer/slice/map, it does nothing.
if !gstr.HasPrefix(match[2], "*") && !gstr.HasPrefix(match[2], "[]") && !gstr.HasPrefix(match[2], "map") {
return fmt.Sprintf(`%s interface{} %s`, match[1], match[3])
return fmt.Sprintf(`%s any %s`, match[1], match[3])
}
return match[0]
},

View File

@@ -41,28 +41,55 @@ func generateStructDefinition(ctx context.Context, in generateStructDefinitionIn
appendImports = append(appendImports, imports)
}
}
tw := tablewriter.NewWriter(buffer)
tw.SetBorder(false)
tw.SetRowLine(false)
tw.SetAutoWrapText(false)
tw.SetColumnSeparator("")
tw.AppendBulk(array)
tw.Render()
table := tablewriter.NewTable(buffer, twRenderer, twConfig)
table.Bulk(array)
table.Render()
stContent := buffer.String()
// Let's do this hack of table writer for indent!
stContent = gstr.Replace(stContent, " #", "")
stContent = gstr.Replace(stContent, "` ", "`")
stContent = gstr.Replace(stContent, "``", "")
buffer.Reset()
buffer.WriteString(fmt.Sprintf("type %s struct {\n", in.StructName))
fmt.Fprintf(buffer, "type %s struct {\n", in.StructName)
if in.IsDo {
buffer.WriteString(fmt.Sprintf("g.Meta `orm:\"table:%s, do:true\"`\n", in.TableName))
fmt.Fprintf(buffer, "g.Meta `orm:\"table:%s, do:true\"`\n", in.TableName)
}
buffer.WriteString(stContent)
buffer.WriteString("}")
return buffer.String(), appendImports
}
func getTypeMappingInfo(
ctx context.Context, fieldType string, inTypeMapping map[DBFieldTypeName]CustomAttributeType,
) (typeNameStr, importStr string) {
if typeMapping, ok := inTypeMapping[strings.ToLower(fieldType)]; ok {
typeNameStr = typeMapping.Type
importStr = typeMapping.Import
return
}
tryTypeMatch, _ := gregex.MatchString(`(.+?)\(([^\(\)]+)\)([\s\)]*)`, fieldType)
var (
tryTypeName string
moreTry bool
)
if len(tryTypeMatch) == 4 {
tryTypeMatch3, _ := gregex.ReplaceString(`\s+`, "", tryTypeMatch[3])
tryTypeName = gstr.Trim(tryTypeMatch[1]) + tryTypeMatch3
moreTry = tryTypeMatch3 != ""
} else {
tryTypeName = gstr.Split(fieldType, " ")[0]
}
if tryTypeName != "" {
if typeMapping, ok := inTypeMapping[strings.ToLower(tryTypeName)]; ok {
typeNameStr = typeMapping.Type
importStr = typeMapping.Import
} else if moreTry {
typeNameStr, importStr = getTypeMappingInfo(ctx, tryTypeName, inTypeMapping)
}
}
return
}
// generateStructFieldDefinition generates and returns the attribute definition for specified field.
func generateStructFieldDefinition(
ctx context.Context, field *gdb.TableField, in generateStructDefinitionInput,
@@ -75,21 +102,7 @@ func generateStructFieldDefinition(
)
if in.TypeMapping != nil && len(in.TypeMapping) > 0 {
var (
tryTypeName string
)
tryTypeMatch, _ := gregex.MatchString(`(.+?)\((.+)\)`, field.Type)
if len(tryTypeMatch) == 3 {
tryTypeName = gstr.Trim(tryTypeMatch[1])
} else {
tryTypeName = gstr.Split(field.Type, " ")[0]
}
if tryTypeName != "" {
if typeMapping, ok := in.TypeMapping[strings.ToLower(tryTypeName)]; ok {
localTypeNameStr = typeMapping.Type
appendImport = typeMapping.Import
}
}
localTypeNameStr, appendImport = getTypeMappingInfo(ctx, field.Type, in.TypeMapping)
}
if localTypeNameStr == "" {

View File

@@ -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"
"hotgo/internal/library/hggen/internal/consts"
"hotgo/internal/library/hggen/internal/utility/mlog"
"hotgo/internal/library/hggen/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)
}
}

View File

@@ -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`
@@ -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`
@@ -97,6 +99,8 @@ generated json tag case for model struct, cases are as follows:
tplVarTableNameCamelCase = `TplTableNameCamelCase`
tplVarTableNameCamelLowerCase = `TplTableNameCamelLowerCase`
tplVarTableSharding = `TplTableSharding`
tplVarTableShardingPrefix = `TplTableShardingPrefix`
tplVarTableFields = `TplTableFields`
tplVarPackageImports = `TplPackageImports`
tplVarImportPrefix = `TplImportPrefix`
tplVarStructDefine = `TplStructDefine`
@@ -125,6 +129,7 @@ func init() {
`CGenDaoBriefStdTime`: CGenDaoBriefStdTime,
`CGenDaoBriefWithTime`: CGenDaoBriefWithTime,
`CGenDaoBriefDaoPath`: CGenDaoBriefDaoPath,
`CGenDaoBriefTablePath`: CGenDaoBriefTablePath,
`CGenDaoBriefDoPath`: CGenDaoBriefDoPath,
`CGenDaoBriefEntityPath`: CGenDaoBriefEntityPath,
`CGenDaoBriefGJsonSupport`: CGenDaoBriefGJsonSupport,
@@ -136,6 +141,7 @@ func init() {
`CGenDaoBriefNoJsonTag`: CGenDaoBriefNoJsonTag,
`CGenDaoBriefNoModelComment`: CGenDaoBriefNoModelComment,
`CGenDaoBriefClear`: CGenDaoBriefClear,
`CGenDaoBriefGenTable`: CGenDaoBriefGenTable,
`CGenDaoBriefTypeMapping`: CGenDaoBriefTypeMapping,
`CGenDaoBriefFieldMapping`: CGenDaoBriefFieldMapping,
`CGenDaoBriefShardingPattern`: CGenDaoBriefShardingPattern,

View File

@@ -113,12 +113,12 @@ func (p *EnumsParser) ParsePackage(pkg *packages.Package) {
}
func (p *EnumsParser) Export() string {
var typeEnumMap = make(map[string][]interface{})
var typeEnumMap = make(map[string][]any)
for _, enum := range p.enums {
if typeEnumMap[enum.Type] == nil {
typeEnumMap[enum.Type] = make([]interface{}, 0)
typeEnumMap[enum.Type] = make([]any, 0)
}
var value interface{}
var value any
switch enum.Kind {
case constant.Int:
value = gconv.Int64(enum.Value)

View File

@@ -109,7 +109,7 @@ func (c CGenPb) tagCommentIntoListMap(comment string, lineTagMap *gmap.ListMap)
func (c CGenPb) listMapToStructTag(lineTagMap *gmap.ListMap) string {
var tag string
lineTagMap.Iterator(func(key, value interface{}) bool {
lineTagMap.Iterator(func(key, value any) bool {
if tag != "" {
tag += " "
}

View File

@@ -15,6 +15,8 @@ import (
"strings"
"github.com/olekukonko/tablewriter"
"github.com/olekukonko/tablewriter/renderer"
"github.com/olekukonko/tablewriter/tw"
"github.com/gogf/gf/v2/container/garray"
"github.com/gogf/gf/v2/container/gset"
@@ -37,18 +39,19 @@ type (
CGenPbEntity struct{}
CGenPbEntityInput struct {
g.Meta `name:"pbentity" config:"{CGenPbEntityConfig}" brief:"{CGenPbEntityBrief}" eg:"{CGenPbEntityEg}" ad:"{CGenPbEntityAd}"`
Path string `name:"path" short:"p" brief:"{CGenPbEntityBriefPath}" d:"manifest/protobuf/pbentity"`
Package string `name:"package" short:"k" brief:"{CGenPbEntityBriefPackage}"`
GoPackage string `name:"goPackage" short:"g" brief:"{CGenPbEntityBriefGoPackage}"`
Link string `name:"link" short:"l" brief:"{CGenPbEntityBriefLink}"`
Tables string `name:"tables" short:"t" brief:"{CGenPbEntityBriefTables}"`
Prefix string `name:"prefix" short:"f" brief:"{CGenPbEntityBriefPrefix}"`
RemovePrefix string `name:"removePrefix" short:"r" brief:"{CGenPbEntityBriefRemovePrefix}"`
RemoveFieldPrefix string `name:"removeFieldPrefix" short:"rf" brief:"{CGenPbEntityBriefRemoveFieldPrefix}"`
TablesEx string `name:"tablesEx" short:"x" brief:"{CGenDaoBriefTablesEx}"`
NameCase string `name:"nameCase" short:"n" brief:"{CGenPbEntityBriefNameCase}" d:"Camel"`
JsonCase string `name:"jsonCase" short:"j" brief:"{CGenPbEntityBriefJsonCase}" d:"none"`
Option string `name:"option" short:"o" brief:"{CGenPbEntityBriefOption}"`
Path string `name:"path" short:"p" brief:"{CGenPbEntityBriefPath}" d:"manifest/protobuf/pbentity"`
Package string `name:"package" short:"k" brief:"{CGenPbEntityBriefPackage}"`
GoPackage string `name:"goPackage" short:"g" brief:"{CGenPbEntityBriefGoPackage}"`
Link string `name:"link" short:"l" brief:"{CGenPbEntityBriefLink}"`
Tables string `name:"tables" short:"t" brief:"{CGenPbEntityBriefTables}"`
Prefix string `name:"prefix" short:"f" brief:"{CGenPbEntityBriefPrefix}"`
RemovePrefix string `name:"removePrefix" short:"r" brief:"{CGenPbEntityBriefRemovePrefix}"`
RemoveFieldPrefix string `name:"removeFieldPrefix" short:"rf" brief:"{CGenPbEntityBriefRemoveFieldPrefix}"`
TablesEx string `name:"tablesEx" short:"x" brief:"{CGenDaoBriefTablesEx}"`
NameCase string `name:"nameCase" short:"n" brief:"{CGenPbEntityBriefNameCase}" d:"Camel"`
JsonCase string `name:"jsonCase" short:"j" brief:"{CGenPbEntityBriefJsonCase}" d:"none"`
Option string `name:"option" short:"o" brief:"{CGenPbEntityBriefOption}"`
ShardingPattern []string `name:"shardingPattern" short:"sp" brief:"{CGenDaoBriefShardingPattern}"`
TypeMapping map[DBFieldTypeName]CustomAttributeType `name:"typeMapping" short:"y" brief:"{CGenPbEntityBriefTypeMapping}" orphan:"true"`
FieldMapping map[DBTableFieldName]CustomAttributeType `name:"fieldMapping" short:"fm" brief:"{CGenPbEntityBriefFieldMapping}" orphan:"true"`
@@ -122,6 +125,7 @@ CONFIGURATION SUPPORT
CGenPbEntityBriefTablesEx = `generate all models exclude the specified tables, multiple prefix separated with ','`
CGenPbEntityBriefRemoveFieldPrefix = `remove specified prefix of the field, multiple prefix separated with ','`
CGenPbEntityBriefOption = `extra protobuf options`
CGenPbEntityBriefShardingPattern = `sharding pattern for table name, e.g. "users_?" will replace tables "users_001,users_002,..." to "users" pbentity`
CGenPbEntityBriefGroup = `
specifying the configuration group name of database for generated ORM instance,
it's not necessary and the default value is "default"
@@ -252,6 +256,7 @@ func init() {
`CGenPbEntityBriefNameCase`: CGenPbEntityBriefNameCase,
`CGenPbEntityBriefJsonCase`: CGenPbEntityBriefJsonCase,
`CGenPbEntityBriefOption`: CGenPbEntityBriefOption,
`CGenPbEntityBriefShardingPattern`: CGenPbEntityBriefShardingPattern,
`CGenPbEntityBriefTypeMapping`: CGenPbEntityBriefTypeMapping,
`CGenPbEntityBriefFieldMapping`: CGenPbEntityBriefFieldMapping,
})
@@ -321,6 +326,7 @@ func doGenPbEntityForArray(ctx context.Context, index int, in CGenPbEntityInput)
}
tableNames := ([]string)(nil)
shardingNewTableSet := gset.NewStrSet()
if in.Tables != "" {
tableNames = gstr.SplitAndTrim(in.Tables, ",")
} else {
@@ -348,6 +354,31 @@ func doGenPbEntityForArray(ctx context.Context, index int, in CGenPbEntityInput)
for _, v := range removePrefixArray {
newTableName = gstr.TrimLeftStr(newTableName, v, 1)
}
var shardingTableName string
if len(in.ShardingPattern) > 0 {
for _, pattern := range in.ShardingPattern {
var (
match []string
regPattern = gstr.Replace(pattern, "?", `(.+)`)
)
match, err = gregex.MatchString(regPattern, newTableName)
if err != nil {
mlog.Fatalf(`invalid sharding pattern "%s": %+v`, pattern, err)
}
if len(match) < 2 {
continue
}
shardingTableName = gstr.Replace(pattern, "?", "")
shardingTableName = gstr.Trim(shardingTableName, `_.-`)
}
}
if shardingTableName != "" {
if shardingNewTableSet.Contains(shardingTableName) {
continue
}
shardingNewTableSet.Add(shardingTableName)
newTableName = shardingTableName
}
generatePbEntityContentFile(ctx, CGenPbEntityInternalInput{
CGenPbEntityInput: in,
DB: db,
@@ -414,13 +445,22 @@ func generateEntityMessageDefinition(entityName string, fieldMap map[string]*gdb
appendImports = append(appendImports, imports)
}
}
tw := tablewriter.NewWriter(buffer)
tw.SetBorder(false)
tw.SetRowLine(false)
tw.SetAutoWrapText(false)
tw.SetColumnSeparator("")
tw.AppendBulk(array)
tw.Render()
table := tablewriter.NewTable(buffer,
tablewriter.WithRenderer(renderer.NewBlueprint(tw.Rendition{
Borders: tw.Border{Top: tw.Off, Bottom: tw.Off, Left: tw.On, Right: tw.Off},
Settings: tw.Settings{
Separators: tw.Separators{BetweenRows: tw.Off, BetweenColumns: tw.Off},
},
Symbols: tw.NewSymbolCustom("Proto").WithColumn(" "),
})),
tablewriter.WithConfig(tablewriter.Config{
Row: tw.CellConfig{
Formatting: tw.CellFormatting{AutoWrap: tw.WrapNone},
},
}),
)
table.Bulk(array)
table.Render()
stContent := buffer.String()
// Let's do this hack of table writer for indent!
stContent = regexp.MustCompile(`\s+\n`).ReplaceAllString(gstr.Replace(stContent, " #", ""), "\n")
@@ -441,14 +481,23 @@ func generateMessageFieldForPbEntity(index int, field *gdb.TableField, in CGenPb
err error
ctx = gctx.GetInitCtx()
)
if in.TypeMapping != nil && len(in.TypeMapping) > 0 {
// match typeMapping after local type transform.
// eg: double => string, varchar => string etc.
localTypeName, err = in.DB.CheckLocalTypeForField(ctx, field.Type, nil)
if err != nil {
panic(err)
}
if localTypeName != "" {
if typeMapping, ok := in.TypeMapping[strings.ToLower(string(localTypeName))]; ok {
if typeMappingLocal, localOk := in.TypeMapping[strings.ToLower(string(localTypeName))]; localOk {
localTypeNameStr = typeMappingLocal.Type
appendImport = typeMappingLocal.Import
}
}
// Try match unknown / string localTypeName with db type.
if localTypeName == "" || localTypeName == gdb.LocalTypeString {
formattedFieldType, _ := in.DB.GetFormattedDBTypeNameForField(field.Type)
if typeMapping, ok := in.TypeMapping[strings.ToLower(formattedFieldType)]; ok {
localTypeNameStr = typeMapping.Type
appendImport = typeMapping.Import
}

View File

@@ -23,6 +23,7 @@ import (
"github.com/gogf/gf/v2/text/gstr"
"github.com/gogf/gf/v2/util/gconv"
"github.com/gogf/gf/v2/util/gtag"
"hotgo/internal/library/hggen/internal/utility/mlog"
"hotgo/internal/library/hggen/internal/utility/utils"
)

View File

@@ -33,7 +33,7 @@ func (c CGenService) generateType(generatedContent *bytes.Buffer, srcStructFunct
generatedContent.WriteString("type(")
generatedContent.WriteString("\n")
srcStructFunctions.Iterator(func(key, value interface{}) bool {
srcStructFunctions.Iterator(func(key, value any) bool {
var (
funcContents = make([]string, 0)
funcContent string
@@ -71,7 +71,7 @@ func (c CGenService) generateVar(generatedContent *bytes.Buffer, srcStructFuncti
// Generating variable and register definitions.
var variableContent string
srcStructFunctions.Iterator(func(key, value interface{}) bool {
srcStructFunctions.Iterator(func(key, value any) bool {
structName := key.(string)
variableContent += gstr.Trim(gstr.ReplaceByMap(consts.TemplateGenServiceContentVariable, g.MapStrStr{
"{StructName}": structName,
@@ -93,7 +93,7 @@ func (c CGenService) generateVar(generatedContent *bytes.Buffer, srcStructFuncti
// See: const.TemplateGenServiceContentRegister
func (c CGenService) generateFunc(generatedContent *bytes.Buffer, srcStructFunctions *gmap.ListMap) {
// Variable register function definitions.
srcStructFunctions.Iterator(func(key, value interface{}) bool {
srcStructFunctions.Iterator(func(key, value any) bool {
structName := key.(string)
generatedContent.WriteString(gstr.Trim(gstr.ReplaceByMap(consts.TemplateGenServiceContentRegister, g.MapStrStr{
"{StructName}": structName,

View File

@@ -27,7 +27,7 @@ var (
// {{.TplTableNameCamelCase}} is a globally accessible object for table {{.TplTableName}} operations.
{{.TplTableNameCamelCase}} = {{.TplTableNameCamelLowerCase}}Dao{
{{- if .TplTableSharding -}}
internal.New{{.TplTableNameCamelCase}}Dao(userShardingHandler),
internal.New{{.TplTableNameCamelCase}}Dao({{.TplTableNameCamelLowerCase}}ShardingHandler),
{{- else -}}
internal.New{{.TplTableNameCamelCase}}Dao(),
{{- end -}}
@@ -35,13 +35,13 @@ var (
)
{{if .TplTableSharding -}}
// userShardingHandler is the handler for sharding operations.
// {{.TplTableNameCamelLowerCase}}ShardingHandler is the handler for sharding operations.
// You can fill this sharding handler with your custom implementation.
func userShardingHandler(m *gdb.Model) *gdb.Model {
func {{.TplTableNameCamelLowerCase}}ShardingHandler(m *gdb.Model) *gdb.Model {
m = m.Sharding(gdb.ShardingConfig{
Table: gdb.ShardingTableConfig{
Enable: true,
Prefix: "",
Prefix: "{{.TplTableShardingPrefix}}",
// Replace Rule field with your custom sharding rule.
// Or you can use "&gdb.DefaultShardingRule{}" for default sharding rule.
Rule: nil,

View File

@@ -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...)
}
`

View File

@@ -1,7 +0,0 @@
// 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 packed

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -51,26 +51,26 @@ func SetHeaderPrint(enabled bool) {
}
}
func Print(v ...interface{}) {
func Print(v ...any) {
logger.Print(ctx, v...)
}
func Printf(format string, v ...interface{}) {
func Printf(format string, v ...any) {
logger.Printf(ctx, format, v...)
}
func Fatal(v ...interface{}) {
func Fatal(v ...any) {
logger.Fatal(ctx, v...)
}
func Fatalf(format string, v ...interface{}) {
func Fatalf(format string, v ...any) {
logger.Fatalf(ctx, format, v...)
}
func Debug(v ...interface{}) {
func Debug(v ...any) {
logger.Debug(ctx, v...)
}
func Debugf(format string, v ...interface{}) {
func Debugf(format string, v ...any) {
logger.Debugf(ctx, format, v...)
}

View File

@@ -16,6 +16,7 @@ import (
"github.com/gogf/gf/v2/os/gproc"
"github.com/gogf/gf/v2/text/gregex"
"github.com/gogf/gf/v2/text/gstr"
"hotgo/internal/library/hggen/internal/consts"
"hotgo/internal/library/hggen/internal/utility/mlog"
)

View File

@@ -1,23 +0,0 @@
// 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 utils_test
import (
"fmt"
"testing"
"github.com/gogf/gf/v2/test/gtest"
"hotgo/internal/library/hggen/internal/utility/utils"
)
func Test_GetModPath(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
goModPath := utils.GetModPath()
fmt.Println(goModPath)
})
}

View File

@@ -9,6 +9,8 @@ import (
"bytes"
"context"
"fmt"
"github.com/olekukonko/tablewriter/renderer"
"github.com/olekukonko/tablewriter/tw"
"strings"
"hotgo/internal/dao"
@@ -33,6 +35,22 @@ const (
EditInpValidatorYaml = "if err := validate.ValidateYAML(in.%s); err != nil {\n\t\treturn gerror.Newf(\"%s必须为有效的YAML格式: %%s\", err.Error())\n\t}\n"
)
var (
// tablewriter Options
twRenderer = tablewriter.WithRenderer(renderer.NewBlueprint(tw.Rendition{
Borders: tw.Border{Top: tw.Off, Bottom: tw.Off, Left: tw.Off, Right: tw.Off},
Settings: tw.Settings{
Separators: tw.Separators{BetweenRows: tw.Off, BetweenColumns: tw.Off},
},
Symbols: tw.NewSymbols(tw.StyleASCII),
}))
twConfig = tablewriter.WithConfig(tablewriter.Config{
Row: tw.CellConfig{
Formatting: tw.CellFormatting{AutoWrap: tw.WrapNone},
},
})
)
func (l *gCurd) inputTplData(ctx context.Context, in *CurdPreviewInput) (data g.Map, err error) {
data = make(g.Map)
data["listInpColumns"] = l.generateInputListColumns(ctx, in, InputTypeListInp)
@@ -68,13 +86,9 @@ func (l *gCurd) generateInputViewColumns(ctx context.Context, in *CurdPreviewInp
}
}
tw := tablewriter.NewWriter(buffer)
tw.SetBorder(false)
tw.SetRowLine(false)
tw.SetAutoWrapText(false)
tw.SetColumnSeparator("")
tw.AppendBulk(array)
tw.Render()
table := tablewriter.NewTable(buffer, twRenderer, twConfig)
table.Bulk(array)
table.Render()
stContent := buffer.String()
// Let's do this hack of table writer for indent!
stContent = gstr.Replace(stContent, " #", "")
@@ -132,13 +146,9 @@ func (l *gCurd) generateInputListColumns(ctx context.Context, in *CurdPreviewInp
}
}
tw := tablewriter.NewWriter(buffer)
tw.SetBorder(false)
tw.SetRowLine(false)
tw.SetAutoWrapText(false)
tw.SetColumnSeparator("")
tw.AppendBulk(array)
tw.Render()
table := tablewriter.NewTable(buffer, twRenderer, twConfig)
table.Bulk(array)
table.Render()
stContent := buffer.String()
// Let's do this hack of table writer for indent!
stContent = gstr.Replace(stContent, " #", "")

View File

@@ -182,12 +182,12 @@ func IsUnique(ctx context.Context, dao daoInstance, where g.Map, message string,
m = m.WhereNot(field, pkId[0])
}
count, err := m.Count(1)
exist, err := m.Exist()
if err != nil {
return err
}
if count > 0 {
if exist {
if message == "" {
for k := range where {
message = fmt.Sprintf("in the table%s, %v not uniqued", dao.Table(), where[k])

View File

@@ -1,6 +1,6 @@
// Package wechat
// @Link https://github.com/bufanyun/hotgo
// @Copyright Copyright (c) 2023 HotGo CLI
// @Copyright Copyright (c) 2025 HotGo CLI
// @Author Ms <133814250@qq.com>
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
package wechat

View File

@@ -1,18 +1,64 @@
// Package wechat
// @Link https://github.com/bufanyun/hotgo
// @Copyright Copyright (c) 2023 HotGo CLI
// @Copyright Copyright (c) 2025 HotGo CLI
// @Author Ms <133814250@qq.com>
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
package wechat
import "hotgo/internal/model"
import (
"context"
"github.com/gogf/gf/v2/os/gctx"
"github.com/silenceper/wechat/v2"
"github.com/silenceper/wechat/v2/officialaccount"
offConfig "github.com/silenceper/wechat/v2/officialaccount/config"
officialJs "github.com/silenceper/wechat/v2/officialaccount/js"
"hotgo/internal/model"
)
var config *model.WechatConfig
var (
config *model.WechatConfig
officialAccount *officialaccount.OfficialAccount // 微信公众号
)
func SetConfig(c *model.WechatConfig) {
config = c
ctx := gctx.GetInitCtx()
GetOfficialAccount(ctx, true)
}
func GetConfig() *model.WechatConfig {
return config
}
// NewOfficialAccount 微信公众号实例
func NewOfficialAccount(ctx context.Context) *officialaccount.OfficialAccount {
cfg := &offConfig.Config{
AppID: config.OfficialAppID,
AppSecret: config.OfficialAppSecret,
Token: config.OfficialToken,
EncodingAESKey: config.OfficialEncodingAESKey,
Cache: NewCache(ctx),
UseStableAK: true,
}
wc := wechat.NewWechat()
return wc.GetOfficialAccount(cfg)
}
// GetOfficialAccount 微信公众号实例
func GetOfficialAccount(ctx context.Context, refresh ...bool) *officialaccount.OfficialAccount {
isRefresh := false
if len(refresh) > 0 {
isRefresh = refresh[0]
}
if officialAccount != nil && !isRefresh {
return officialAccount
}
officialAccount = NewOfficialAccount(ctx)
return officialAccount
}
// GetJsConfig 获取js配置
func GetJsConfig(ctx context.Context, uri string) (config *officialJs.Config, err error) {
return GetOfficialAccount(ctx).GetJs().GetConfig(uri)
}

View File

@@ -1,6 +1,6 @@
// Package wechat
// @Link https://github.com/bufanyun/hotgo
// @Copyright Copyright (c) 2023 HotGo CLI
// @Copyright Copyright (c) 2025 HotGo CLI
// @Author Ms <133814250@qq.com>
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
package wechat
@@ -8,91 +8,26 @@ package wechat
import (
"context"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/silenceper/wechat/v2"
"github.com/silenceper/wechat/v2/officialaccount"
offConfig "github.com/silenceper/wechat/v2/officialaccount/config"
officialJs "github.com/silenceper/wechat/v2/officialaccount/js"
officialOauth "github.com/silenceper/wechat/v2/officialaccount/oauth"
"github.com/silenceper/wechat/v2/openplatform"
openConfig "github.com/silenceper/wechat/v2/openplatform/config"
"hotgo/internal/consts"
)
// NewOfficialAccount 微信公众号实例
func NewOfficialAccount(ctx context.Context) *officialaccount.OfficialAccount {
cfg := &offConfig.Config{
AppID: config.OfficialAppID,
AppSecret: config.OfficialAppSecret,
Token: config.OfficialToken,
EncodingAESKey: config.OfficialEncodingAESKey,
Cache: NewCache(ctx),
}
return wechat.NewWechat().GetOfficialAccount(cfg)
}
// NewOpenPlatform 开放平台实例
func NewOpenPlatform(ctx context.Context) *openplatform.OpenPlatform {
cfg := &openConfig.Config{
AppID: config.OpenAppID,
AppSecret: config.OpenAppSecret,
Token: config.OpenToken,
EncodingAESKey: config.OpenEncodingAESKey,
Cache: NewCache(ctx),
}
return wechat.NewWechat().GetOpenPlatform(cfg)
}
// GetOpenOauthURL 代第三方公众号 - 获取网页授权地址
func GetOpenOauthURL(ctx context.Context, redirectURI, scope, state string) (location string, err error) {
op := NewOpenPlatform(ctx)
appid := config.OfficialAppID // 公众号appid
oauth := op.GetOfficialAccount(appid).PlatformOauth()
if scope == "" {
scope = consts.WechatScopeBase
}
location, err = oauth.GetRedirectURL(redirectURI, scope, state, appid)
return
}
// GetOpenUserAccessToken 代第三方公众号 - 通过网页授权的code 换取access_token
func GetOpenUserAccessToken(ctx context.Context, code string) (accessToken officialOauth.ResAccessToken, err error) {
op := NewOpenPlatform(ctx)
appid := config.OfficialAppID // 公众号appid
officialAccount := op.GetOfficialAccount(appid)
componentAccessToken, err := op.GetComponentAccessToken()
if err != nil {
return
}
accessToken, err = officialAccount.PlatformOauth().GetUserAccessToken(code, appid, componentAccessToken)
if err != nil {
return
}
if accessToken.ErrCode > 0 {
err = gerror.Newf("GetOpenUserAccessToken err:%+v", accessToken.ErrMsg)
return
}
return
}
// GetUserInfo 获取用户信息
func GetUserInfo(ctx context.Context, token officialOauth.ResAccessToken) (info officialOauth.UserInfo, err error) {
oauth := NewOfficialAccount(ctx).GetOauth()
oauth := GetOfficialAccount(ctx).GetOauth()
info, err = oauth.GetUserInfo(token.AccessToken, token.OpenID, "")
return
}
// GetOauthURL 获取网页授权地址
func GetOauthURL(ctx context.Context, redirectURI, scope, state string) (location string, err error) {
oauth := NewOfficialAccount(ctx).GetOauth()
oauth := GetOfficialAccount(ctx).GetOauth()
location, err = oauth.GetRedirectURL(redirectURI, scope, state)
return
}
// GetUserAccessToken 通过网页授权的code 换取access_token
func GetUserAccessToken(ctx context.Context, code string) (accessToken officialOauth.ResAccessToken, err error) {
oauth := NewOfficialAccount(ctx).GetOauth()
oauth := GetOfficialAccount(ctx).GetOauth()
accessToken, err = oauth.GetUserAccessToken(code)
if err != nil {
return
@@ -104,8 +39,3 @@ func GetUserAccessToken(ctx context.Context, code string) (accessToken officialO
}
return
}
// GetJsConfig 获取js配置
func GetJsConfig(ctx context.Context, uri string) (config *officialJs.Config, err error) {
return NewOfficialAccount(ctx).GetJs().GetConfig(uri)
}