Compare commits
12 Commits
1147ca4733
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8bcc2cbdad | ||
|
|
7187205143 | ||
|
|
3b804b83da | ||
|
|
a714d4a3a9 | ||
|
|
1fac55115d | ||
|
|
3759295afa | ||
|
|
099bdfc7d9 | ||
|
|
3b902509f7 | ||
|
|
ec1fa93033 | ||
|
|
2b0ee0e61c | ||
|
|
906858dbd6 | ||
|
|
b4cc2347e5 |
4
.gitignore
vendored
4
.gitignore
vendored
@@ -21,4 +21,6 @@
|
|||||||
# Go workspace file
|
# Go workspace file
|
||||||
go.work
|
go.work
|
||||||
|
|
||||||
test/*
|
tests/*
|
||||||
|
atomctl
|
||||||
|
AGENTS.md
|
||||||
|
|||||||
19
.vscode/settings.json
vendored
19
.vscode/settings.json
vendored
@@ -1,3 +1,20 @@
|
|||||||
{
|
{
|
||||||
"editor.fontSize": 10
|
"editor.fontSize": 10,
|
||||||
|
"dbcode.connections": [
|
||||||
|
{
|
||||||
|
"connectionId": "l6fEOogu2kQt5G3BashDt",
|
||||||
|
"name": "10.1.1.2",
|
||||||
|
"driver": "postgres",
|
||||||
|
"connectionType": "host",
|
||||||
|
"host": "10.1.1.2",
|
||||||
|
"port": 5432,
|
||||||
|
"ssl": false,
|
||||||
|
"username": "postgres",
|
||||||
|
"password": "",
|
||||||
|
"savePassword": "secretStorage",
|
||||||
|
"database": "quyun",
|
||||||
|
"readOnly": false,
|
||||||
|
"connectionTimeout": 30
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
33
cmd/buf.go
33
cmd/buf.go
@@ -2,23 +2,30 @@ package cmd
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
func CommandBuf(root *cobra.Command) {
|
func CommandBuf(root *cobra.Command) {
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
Use: "buf",
|
Use: "buf",
|
||||||
Short: "run buf commands",
|
Short: "run buf commands",
|
||||||
RunE: commandBufE,
|
RunE: commandBufE,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cmd.Flags().String("dir", ".", "Directory to run buf from")
|
||||||
|
cmd.Flags().Bool("dry-run", false, "Preview buf command without executing")
|
||||||
|
|
||||||
root.AddCommand(cmd)
|
root.AddCommand(cmd)
|
||||||
}
|
}
|
||||||
|
|
||||||
func commandBufE(cmd *cobra.Command, args []string) error {
|
func commandBufE(cmd *cobra.Command, args []string) error {
|
||||||
|
dir := cmd.Flag("dir").Value.String()
|
||||||
|
dryRun, _ := cmd.Flags().GetBool("dry-run")
|
||||||
if _, err := exec.LookPath("buf"); err != nil {
|
if _, err := exec.LookPath("buf"); err != nil {
|
||||||
log.Warn("buf 命令不存在,正在安装 buf...")
|
log.Warn("buf 命令不存在,正在安装 buf...")
|
||||||
log.Info("go install github.com/bufbuild/buf/cmd/buf@v1.48.0")
|
log.Info("go install github.com/bufbuild/buf/cmd/buf@v1.48.0")
|
||||||
@@ -33,9 +40,19 @@ func commandBufE(cmd *cobra.Command, args []string) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Info("buf 命令已存在,正在运行 buf generate...")
|
// preflight: ensure buf.yaml exists
|
||||||
log.Info("PROTOBUF GUIDE: https://buf.build/docs/best-practices/style-guide/")
|
if _, err := os.Stat(filepath.Join(dir, "buf.yaml")); err != nil {
|
||||||
generateCmd := exec.Command("buf", "generate")
|
log.Warnf("未找到 %s,buf generate 可能失败", filepath.Join(dir, "buf.yaml"))
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Info("buf 命令已存在,正在运行 buf generate...")
|
||||||
|
log.Info("PROTOBUF GUIDE: https://buf.build/docs/best-practices/style-guide/")
|
||||||
|
if dryRun {
|
||||||
|
log.Infof("[dry-run] (cd %s && buf generate)", dir)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
generateCmd := exec.Command("buf", "generate")
|
||||||
|
generateCmd.Dir = dir
|
||||||
if err := generateCmd.Run(); err != nil {
|
if err := generateCmd.Run(); err != nil {
|
||||||
return fmt.Errorf("运行 buf generate 失败: %v", err)
|
return fmt.Errorf("运行 buf generate 失败: %v", err)
|
||||||
}
|
}
|
||||||
|
|||||||
50
cmd/fmt.go
50
cmd/fmt.go
@@ -10,17 +10,20 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func CommandFmt(root *cobra.Command) {
|
func CommandFmt(root *cobra.Command) {
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
Use: "fmt",
|
Use: "fmt",
|
||||||
Short: "fmt codes",
|
Short: "fmt codes",
|
||||||
RunE: commandFmtE,
|
RunE: commandFmtE,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cmd.Flags().Bool("check", false, "Check formatting without writing changes")
|
||||||
|
cmd.Flags().String("path", ".", "Path to format (default .)")
|
||||||
|
|
||||||
root.AddCommand(cmd)
|
root.AddCommand(cmd)
|
||||||
}
|
}
|
||||||
|
|
||||||
func commandFmtE(cmd *cobra.Command, args []string) error {
|
func commandFmtE(cmd *cobra.Command, args []string) error {
|
||||||
log.Info("开始格式化代码")
|
log.Info("开始格式化代码")
|
||||||
if _, err := exec.LookPath("gofumpt"); err != nil {
|
if _, err := exec.LookPath("gofumpt"); err != nil {
|
||||||
log.Info("gofumpt 不存在,正在安装...")
|
log.Info("gofumpt 不存在,正在安装...")
|
||||||
installCmd := exec.Command("go", "install", "mvdan.cc/gofumpt@latest")
|
installCmd := exec.Command("go", "install", "mvdan.cc/gofumpt@latest")
|
||||||
@@ -34,14 +37,31 @@ func commandFmtE(cmd *cobra.Command, args []string) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Info("运行 gofumpt...")
|
check, _ := cmd.Flags().GetBool("check")
|
||||||
gofumptCmd := exec.Command("gofumpt", "-l", "-extra", "-w", ".")
|
path, _ := cmd.Flags().GetString("path")
|
||||||
gofumptCmd.Stdout = os.Stdout
|
|
||||||
gofumptCmd.Stderr = os.Stderr
|
|
||||||
if err := gofumptCmd.Run(); err != nil {
|
|
||||||
return fmt.Errorf("运行 gofumpt 失败: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Info("格式化代码完成")
|
if check {
|
||||||
return nil
|
log.Info("运行 gofumpt 检查模式...")
|
||||||
|
out, err := exec.Command("gofumpt", "-l", "-extra", path).CombinedOutput()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("运行 gofumpt 失败: %v", err)
|
||||||
|
}
|
||||||
|
if len(out) > 0 {
|
||||||
|
fmt.Fprintln(os.Stdout, string(out))
|
||||||
|
return fmt.Errorf("发现未格式化文件,请运行: gofumpt -l -extra -w %s", path)
|
||||||
|
}
|
||||||
|
log.Info("代码格式良好")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Info("运行 gofumpt...")
|
||||||
|
gofumptCmd := exec.Command("gofumpt", "-l", "-extra", "-w", path)
|
||||||
|
gofumptCmd.Stdout = os.Stdout
|
||||||
|
gofumptCmd.Stderr = os.Stderr
|
||||||
|
if err := gofumptCmd.Run(); err != nil {
|
||||||
|
return fmt.Errorf("运行 gofumpt 失败: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Info("格式化代码完成")
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,12 +25,16 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func CommandGenModel(root *cobra.Command) {
|
func CommandGenModel(root *cobra.Command) {
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
Use: "model",
|
Use: "model",
|
||||||
Aliases: []string{"m"},
|
Aliases: []string{"m"},
|
||||||
Short: "Generate jet models",
|
Short: "Generate jet models",
|
||||||
RunE: commandGenModelE,
|
RunE: commandGenModelE,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cmd.Flags().String("schema", "", "Override database schema")
|
||||||
|
cmd.Flags().Bool("rename-schemas", true, "Rename generated database/<db> to database/schemas")
|
||||||
|
cmd.Flags().String("schemas-out", "database/schemas", "Schemas output directory when renaming")
|
||||||
|
|
||||||
root.AddCommand(cmd)
|
root.AddCommand(cmd)
|
||||||
}
|
}
|
||||||
@@ -40,10 +44,15 @@ func commandGenModelE(cmd *cobra.Command, args []string) error {
|
|||||||
return errors.Wrap(err, "parse go.mod")
|
return errors.Wrap(err, "parse go.mod")
|
||||||
}
|
}
|
||||||
|
|
||||||
_, dbConf, err := pgDatabase.GetDB(cmd.Flag("config").Value.String())
|
_, dbConf, err := pgDatabase.GetDB(cmd.Flag("config").Value.String())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrap(err, "get db")
|
return errors.Wrap(err, "get db")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// optional schema override
|
||||||
|
if s := cmd.Flag("schema").Value.String(); s != "" {
|
||||||
|
dbConf.Schema = s
|
||||||
|
}
|
||||||
|
|
||||||
v := viper.New()
|
v := viper.New()
|
||||||
v.SetConfigType("yaml")
|
v.SetConfigType("yaml")
|
||||||
@@ -166,14 +175,16 @@ func commandGenModelE(cmd *cobra.Command, args []string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := os.RemoveAll("database/schemas"); err != nil {
|
if rename, _ := cmd.Flags().GetBool("rename-schemas"); rename {
|
||||||
return err
|
out := cmd.Flag("schemas-out").Value.String()
|
||||||
}
|
if err := os.RemoveAll(out); err != nil {
|
||||||
|
return err
|
||||||
dataPath := fmt.Sprintf("database/%s", cfg.Database)
|
}
|
||||||
if err := os.Rename(dataPath, "database/schemas"); err != nil {
|
dataPath := fmt.Sprintf("database/%s", cfg.Database)
|
||||||
return err
|
if err := os.Rename(dataPath, out); err != nil {
|
||||||
}
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if err := astModel.Generate(generatedTables, transformer); err != nil {
|
if err := astModel.Generate(generatedTables, transformer); err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"io/fs"
|
"io/fs"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
@@ -14,28 +15,35 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func CommandGenRoute(root *cobra.Command) {
|
func CommandGenRoute(root *cobra.Command) {
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
Use: "route",
|
Use: "route",
|
||||||
Short: "generate routes",
|
Short: "generate routes",
|
||||||
RunE: commandGenRouteE,
|
RunE: commandGenRouteE,
|
||||||
PostRunE: commandGenProviderE,
|
PostRunE: commandGenProviderE,
|
||||||
}
|
}
|
||||||
|
|
||||||
root.AddCommand(cmd)
|
cmd.Flags().String("path", ".", "Base path to scan (defaults to CWD)")
|
||||||
|
|
||||||
|
root.AddCommand(cmd)
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://go.ipao.vip/atomctl/pkg/swag?tab=readme-ov-file#api-operation
|
// https://go.ipao.vip/atomctl/pkg/swag?tab=readme-ov-file#api-operation
|
||||||
func commandGenRouteE(cmd *cobra.Command, args []string) error {
|
func commandGenRouteE(cmd *cobra.Command, args []string) error {
|
||||||
var err error
|
var err error
|
||||||
var path string
|
var path string
|
||||||
if len(args) > 0 {
|
if len(args) > 0 {
|
||||||
path = args[0]
|
path = args[0]
|
||||||
} else {
|
} else {
|
||||||
path, err = os.Getwd()
|
path, err = os.Getwd()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// allow overriding via --path flag
|
||||||
|
if f := cmd.Flag("path"); f != nil && f.Value.String() != "." && f.Value.String() != "" {
|
||||||
|
path = f.Value.String()
|
||||||
|
}
|
||||||
|
|
||||||
path, _ = filepath.Abs(path)
|
path, _ = filepath.Abs(path)
|
||||||
|
|
||||||
@@ -48,7 +56,7 @@ func commandGenRouteE(cmd *cobra.Command, args []string) error {
|
|||||||
|
|
||||||
modulePath := filepath.Join(path, "app/http")
|
modulePath := filepath.Join(path, "app/http")
|
||||||
if _, err := os.Stat(modulePath); os.IsNotExist(err) {
|
if _, err := os.Stat(modulePath); os.IsNotExist(err) {
|
||||||
log.Fatal("modules dir not exist, ", modulePath)
|
return fmt.Errorf("routes directory not found: %s (set --path to your project root)", modulePath)
|
||||||
}
|
}
|
||||||
|
|
||||||
// controllerPattern := regexp.MustCompile(`controller(_?\w+)?\.go`)
|
// controllerPattern := regexp.MustCompile(`controller(_?\w+)?\.go`)
|
||||||
|
|||||||
@@ -13,12 +13,14 @@ import (
|
|||||||
|
|
||||||
// migrate
|
// migrate
|
||||||
func CommandMigrate(root *cobra.Command) {
|
func CommandMigrate(root *cobra.Command) {
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
Use: "migrate [up|up-by-one|up-to|create|down|down-to|fix|redo|reset|status|version]",
|
Use: "migrate [up|up-by-one|up-to|create|down|down-to|fix|redo|reset|status|version]",
|
||||||
Aliases: []string{"m"},
|
Aliases: []string{"m"},
|
||||||
RunE: commandMigrate,
|
RunE: commandMigrate,
|
||||||
}
|
}
|
||||||
cmd.Flags().StringP("config", "c", "config.toml", "database config file")
|
cmd.Flags().StringP("config", "c", "config.toml", "database config file")
|
||||||
|
cmd.Flags().String("dir", "database/migrations", "migrations directory")
|
||||||
|
cmd.Flags().String("table", "migrations", "migrations table name")
|
||||||
|
|
||||||
root.AddCommand(cmd)
|
root.AddCommand(cmd)
|
||||||
}
|
}
|
||||||
@@ -39,10 +41,13 @@ func commandMigrate(cmd *cobra.Command, args []string) error {
|
|||||||
return errors.Wrap(err, "get db")
|
return errors.Wrap(err, "get db")
|
||||||
}
|
}
|
||||||
|
|
||||||
action, args := args[0], args[1:]
|
action, args := args[0], args[1:]
|
||||||
log.Infof("migration action: %s args: %+v", action, args)
|
log.Infof("migration action: %s args: %+v", action, args)
|
||||||
|
|
||||||
goose.SetTableName("migrations")
|
dir := cmd.Flag("dir").Value.String()
|
||||||
|
table := cmd.Flag("table").Value.String()
|
||||||
|
|
||||||
return goose.RunContext(context.Background(), action, db, "database/migrations", args...)
|
goose.SetTableName(table)
|
||||||
|
|
||||||
|
return goose.RunContext(context.Background(), action, db, dir, args...)
|
||||||
}
|
}
|
||||||
|
|||||||
26
cmd/new.go
26
cmd/new.go
@@ -5,20 +5,22 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func CommandInit(root *cobra.Command) {
|
func CommandInit(root *cobra.Command) {
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
Use: "new [project|module]",
|
Use: "new [project|module]",
|
||||||
Short: "new project/module",
|
Short: "new project/module",
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd.PersistentFlags().BoolP("force", "f", false, "Force init project if exists")
|
cmd.PersistentFlags().BoolP("force", "f", false, "Force overwrite existing files or directories")
|
||||||
|
cmd.PersistentFlags().Bool("dry-run", false, "Preview actions without writing files")
|
||||||
|
cmd.PersistentFlags().String("dir", ".", "Base directory for outputs")
|
||||||
|
|
||||||
cmds := []func(*cobra.Command){
|
cmds := []func(*cobra.Command){
|
||||||
CommandNewProject,
|
CommandNewProject,
|
||||||
// deprecate CommandNewModule,
|
// deprecate CommandNewModule,
|
||||||
CommandNewProvider,
|
CommandNewProvider,
|
||||||
CommandNewEvent,
|
CommandNewEvent,
|
||||||
CommandNewJob,
|
CommandNewJob,
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, c := range cmds {
|
for _, c := range cmds {
|
||||||
c(cmd)
|
c(cmd)
|
||||||
|
|||||||
127
cmd/new_event.go
127
cmd/new_event.go
@@ -1,11 +1,12 @@
|
|||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/fs"
|
"io/fs"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"text/template"
|
"strings"
|
||||||
|
"text/template"
|
||||||
|
|
||||||
"go.ipao.vip/atomctl/pkg/utils/gomod"
|
"go.ipao.vip/atomctl/pkg/utils/gomod"
|
||||||
"go.ipao.vip/atomctl/templates"
|
"go.ipao.vip/atomctl/templates"
|
||||||
@@ -15,23 +16,30 @@ import (
|
|||||||
|
|
||||||
// CommandNewProvider 注册 new_provider 命令
|
// CommandNewProvider 注册 new_provider 命令
|
||||||
func CommandNewEvent(root *cobra.Command) {
|
func CommandNewEvent(root *cobra.Command) {
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
Use: "event",
|
Use: "event",
|
||||||
Aliases: []string{"e"},
|
Aliases: []string{"e"},
|
||||||
Short: "创建新的 event publish & subscriber",
|
Short: "创建新的 event publish & subscriber",
|
||||||
Args: cobra.ExactArgs(1),
|
Args: cobra.ExactArgs(1),
|
||||||
RunE: commandNewEventE,
|
RunE: commandNewEventE,
|
||||||
}
|
}
|
||||||
|
|
||||||
root.AddCommand(cmd)
|
cmd.Flags().String("only", "", "仅生成: publisher 或 subscriber")
|
||||||
|
|
||||||
|
root.AddCommand(cmd)
|
||||||
}
|
}
|
||||||
|
|
||||||
func commandNewEventE(cmd *cobra.Command, args []string) error {
|
func commandNewEventE(cmd *cobra.Command, args []string) error {
|
||||||
snakeName := lo.SnakeCase(args[0])
|
snakeName := lo.SnakeCase(args[0])
|
||||||
camelName := lo.PascalCase(args[0])
|
camelName := lo.PascalCase(args[0])
|
||||||
|
|
||||||
publisherPath := "app/events/publishers"
|
// shared flags
|
||||||
subscriberPath := "app/events/subscribers"
|
dryRun, _ := cmd.Flags().GetBool("dry-run")
|
||||||
|
baseDir, _ := cmd.Flags().GetString("dir")
|
||||||
|
only, _ := cmd.Flags().GetString("only")
|
||||||
|
|
||||||
|
publisherPath := filepath.Join(baseDir, "app/events/publishers")
|
||||||
|
subscriberPath := filepath.Join(baseDir, "app/events/subscribers")
|
||||||
|
|
||||||
path, err := os.Getwd()
|
path, err := os.Getwd()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -44,13 +52,17 @@ func commandNewEventE(cmd *cobra.Command, args []string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := os.MkdirAll(publisherPath, os.ModePerm); err != nil {
|
if dryRun {
|
||||||
return err
|
fmt.Printf("[dry-run] mkdir -p %s\n", publisherPath)
|
||||||
}
|
fmt.Printf("[dry-run] mkdir -p %s\n", subscriberPath)
|
||||||
|
} else {
|
||||||
if err := os.MkdirAll(subscriberPath, os.ModePerm); err != nil {
|
if err := os.MkdirAll(publisherPath, os.ModePerm); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
if err := os.MkdirAll(subscriberPath, os.ModePerm); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
err = fs.WalkDir(templates.Events, "events", func(path string, d fs.DirEntry, err error) error {
|
err = fs.WalkDir(templates.Events, "events", func(path string, d fs.DirEntry, err error) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -65,42 +77,59 @@ func commandNewEventE(cmd *cobra.Command, args []string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
var destPath string
|
var destPath string
|
||||||
if relPath == "publisher.go.tpl" {
|
if relPath == "publisher.go.tpl" {
|
||||||
destPath = filepath.Join(publisherPath, snakeName+".go")
|
if only == "subscriber" { return nil }
|
||||||
} else if relPath == "subscriber.go.tpl" {
|
destPath = filepath.Join(publisherPath, snakeName+".go")
|
||||||
destPath = filepath.Join(subscriberPath, snakeName+".go")
|
} else if relPath == "subscriber.go.tpl" {
|
||||||
}
|
if only == "publisher" { return nil }
|
||||||
|
destPath = filepath.Join(subscriberPath, snakeName+".go")
|
||||||
|
} else { return nil }
|
||||||
|
|
||||||
tmpl, err := template.ParseFS(templates.Events, path)
|
tmpl, err := template.ParseFS(templates.Events, path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
destFile, err := os.Create(destPath)
|
if dryRun {
|
||||||
if err != nil {
|
fmt.Printf("[dry-run] render > %s\n", destPath)
|
||||||
return err
|
return nil
|
||||||
}
|
}
|
||||||
defer destFile.Close()
|
|
||||||
|
|
||||||
return tmpl.Execute(destFile, map[string]string{
|
destFile, err := os.Create(destPath)
|
||||||
"Name": camelName,
|
if err != nil {
|
||||||
"ModuleName": gomod.GetModuleName(),
|
return err
|
||||||
})
|
}
|
||||||
})
|
defer destFile.Close()
|
||||||
|
|
||||||
topicStr := fmt.Sprintf("const Topic%s = %q\n", camelName, snakeName)
|
return tmpl.Execute(destFile, map[string]string{
|
||||||
// 写入到 app/events/topic.go
|
"Name": camelName,
|
||||||
topicFile, err := os.OpenFile("app/events/topics.go", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0o644)
|
"ModuleName": gomod.GetModuleName(),
|
||||||
if err != nil {
|
})
|
||||||
return err
|
})
|
||||||
}
|
|
||||||
defer topicFile.Close()
|
|
||||||
|
|
||||||
_, err = topicFile.WriteString(topicStr)
|
// 写入或追加 topic 常量,避免重复。
|
||||||
if err != nil {
|
topicsPath := filepath.Join(baseDir, "app/events/topics.go")
|
||||||
return err
|
topicLine := fmt.Sprintf("const Topic%s = %q\n", camelName, snakeName)
|
||||||
}
|
|
||||||
|
if dryRun {
|
||||||
|
fmt.Printf("[dry-run] ensure topics file and add constant > %s\n", topicsPath)
|
||||||
|
} else {
|
||||||
|
// ensure file exists with basic header
|
||||||
|
if _, statErr := os.Stat(topicsPath); os.IsNotExist(statErr) {
|
||||||
|
if err := os.MkdirAll(filepath.Dir(topicsPath), os.ModePerm); err != nil { return err }
|
||||||
|
header := "package events\n\n// topics generated by atomctl\n\n"
|
||||||
|
if err := os.WriteFile(topicsPath, []byte(header), 0o644); err != nil { return err }
|
||||||
|
}
|
||||||
|
// check duplicate
|
||||||
|
content, _ := os.ReadFile(topicsPath)
|
||||||
|
if !strings.Contains(string(content), "Topic"+camelName+" ") && !strings.Contains(string(content), topicLine) {
|
||||||
|
f, err := os.OpenFile(topicsPath, os.O_APPEND|os.O_WRONLY, 0o644)
|
||||||
|
if err != nil { return err }
|
||||||
|
defer f.Close()
|
||||||
|
if _, err := f.WriteString(topicLine); err != nil { return err }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fmt.Printf("event 已创建: %s\n", snakeName)
|
fmt.Printf("event 已创建: %s\n", snakeName)
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -26,10 +26,14 @@ func CommandNewJob(root *cobra.Command) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func commandNewJobE(cmd *cobra.Command, args []string) error {
|
func commandNewJobE(cmd *cobra.Command, args []string) error {
|
||||||
snakeName := lo.SnakeCase(args[0])
|
snakeName := lo.SnakeCase(args[0])
|
||||||
camelName := lo.PascalCase(args[0])
|
camelName := lo.PascalCase(args[0])
|
||||||
|
|
||||||
destPath := "app/jobs"
|
// shared flags
|
||||||
|
dryRun, _ := cmd.Flags().GetBool("dry-run")
|
||||||
|
baseDir, _ := cmd.Flags().GetString("dir")
|
||||||
|
|
||||||
|
basePath := filepath.Join(baseDir, "app/jobs")
|
||||||
|
|
||||||
path, err := os.Getwd()
|
path, err := os.Getwd()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -42,9 +46,13 @@ func commandNewJobE(cmd *cobra.Command, args []string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := os.MkdirAll(destPath, os.ModePerm); err != nil {
|
if dryRun {
|
||||||
return err
|
fmt.Printf("[dry-run] mkdir -p %s\n", basePath)
|
||||||
}
|
} else {
|
||||||
|
if err := os.MkdirAll(basePath, os.ModePerm); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
err = fs.WalkDir(templates.Jobs, "jobs", func(path string, d fs.DirEntry, err error) error {
|
err = fs.WalkDir(templates.Jobs, "jobs", func(path string, d fs.DirEntry, err error) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -55,22 +63,27 @@ func commandNewJobE(cmd *cobra.Command, args []string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
destPath := filepath.Join(destPath, snakeName+".go")
|
filePath := filepath.Join(basePath, snakeName+".go")
|
||||||
tmpl, err := template.ParseFS(templates.Jobs, path)
|
tmpl, err := template.ParseFS(templates.Jobs, path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
destFile, err := os.Create(destPath)
|
if dryRun {
|
||||||
if err != nil {
|
fmt.Printf("[dry-run] render > %s\n", filePath)
|
||||||
return err
|
return nil
|
||||||
}
|
}
|
||||||
defer destFile.Close()
|
|
||||||
|
|
||||||
return tmpl.Execute(destFile, map[string]string{
|
destFile, err := os.Create(filePath)
|
||||||
"Name": camelName,
|
if err != nil {
|
||||||
"ModuleName": gomod.GetModuleName(),
|
return err
|
||||||
})
|
}
|
||||||
|
defer destFile.Close()
|
||||||
|
|
||||||
|
return tmpl.Execute(destFile, map[string]string{
|
||||||
|
"Name": camelName,
|
||||||
|
"ModuleName": gomod.GetModuleName(),
|
||||||
|
})
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/fs"
|
"io/fs"
|
||||||
"os"
|
"os"
|
||||||
@@ -9,10 +10,11 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"text/template"
|
"text/template"
|
||||||
|
|
||||||
"go.ipao.vip/atomctl/templates"
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
"go.ipao.vip/atomctl/pkg/utils/gomod"
|
||||||
|
"go.ipao.vip/atomctl/templates"
|
||||||
)
|
)
|
||||||
|
|
||||||
// 验证包名是否合法:支持域名、路径分隔符和常见字符
|
// 验证包名是否合法:支持域名、路径分隔符和常见字符
|
||||||
@@ -34,9 +36,31 @@ func CommandNewProject(root *cobra.Command) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func commandNewProjectE(cmd *cobra.Command, args []string) error {
|
func commandNewProjectE(cmd *cobra.Command, args []string) error {
|
||||||
moduleName := args[0]
|
var (
|
||||||
if !isValidGoPackageName(moduleName) {
|
moduleName string
|
||||||
return fmt.Errorf("invalid module name: %s, should be a valid go package name", moduleName)
|
inPlace bool
|
||||||
|
)
|
||||||
|
|
||||||
|
// shared flags
|
||||||
|
dryRun, _ := cmd.Flags().GetBool("dry-run")
|
||||||
|
baseDir, _ := cmd.Flags().GetString("dir")
|
||||||
|
|
||||||
|
if len(args) == 0 {
|
||||||
|
if _, err := os.Stat("go.mod"); err == nil {
|
||||||
|
pwd, _ := os.Getwd()
|
||||||
|
if err := gomod.Parse(filepath.Join(pwd, "go.mod")); err != nil {
|
||||||
|
return fmt.Errorf("parse go.mod failed: %v", err)
|
||||||
|
}
|
||||||
|
moduleName = gomod.GetModuleName()
|
||||||
|
inPlace = true
|
||||||
|
} else {
|
||||||
|
return fmt.Errorf("module name required or run inside an existing module (go.mod)")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
moduleName = args[0]
|
||||||
|
if !isValidGoPackageName(moduleName) {
|
||||||
|
return fmt.Errorf("invalid module name: %s, should be a valid go package name", moduleName)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Info("创建项目: ", moduleName)
|
log.Info("创建项目: ", moduleName)
|
||||||
@@ -50,90 +74,126 @@ func commandNewProjectE(cmd *cobra.Command, args []string) error {
|
|||||||
moduleSplitInfo := strings.Split(projectInfo.ModuleName, "/")
|
moduleSplitInfo := strings.Split(projectInfo.ModuleName, "/")
|
||||||
projectInfo.ProjectName = moduleSplitInfo[len(moduleSplitInfo)-1]
|
projectInfo.ProjectName = moduleSplitInfo[len(moduleSplitInfo)-1]
|
||||||
|
|
||||||
// 检查目录是否存在
|
|
||||||
force, _ := cmd.Flags().GetBool("force")
|
force, _ := cmd.Flags().GetBool("force")
|
||||||
if _, err := os.Stat(projectInfo.ProjectName); err == nil {
|
|
||||||
if !force {
|
|
||||||
return fmt.Errorf("project directory %s already exists", projectInfo.ProjectName)
|
|
||||||
}
|
|
||||||
log.Warnf("强制删除已存在的目录: %s", projectInfo.ProjectName)
|
|
||||||
if err := os.RemoveAll(projectInfo.ProjectName); err != nil {
|
|
||||||
return fmt.Errorf("failed to remove existing directory: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 创建项目根目录
|
rootDir := "."
|
||||||
if err := os.MkdirAll(projectInfo.ProjectName, 0o755); err != nil {
|
if !inPlace {
|
||||||
return fmt.Errorf("failed to create project directory: %v", err)
|
// honor base dir when creating a new project
|
||||||
}
|
rootDir = filepath.Join(baseDir, projectInfo.ProjectName)
|
||||||
|
if _, err := os.Stat(rootDir); err == nil {
|
||||||
|
if !force {
|
||||||
|
return fmt.Errorf("project directory %s already exists", rootDir)
|
||||||
|
}
|
||||||
|
log.Warnf("强制删除已存在的目录: %s", rootDir)
|
||||||
|
if dryRun {
|
||||||
|
log.Infof("[dry-run] 将删除目录: %s", rootDir)
|
||||||
|
} else if err := os.RemoveAll(rootDir); err != nil {
|
||||||
|
return fmt.Errorf("failed to remove existing directory: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if dryRun {
|
||||||
|
log.Infof("[dry-run] 将创建目录: %s", rootDir)
|
||||||
|
} else if err := os.MkdirAll(rootDir, 0o755); err != nil {
|
||||||
|
return fmt.Errorf("failed to create project directory: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 遍历和处理模板文件
|
|
||||||
if err := fs.WalkDir(templates.Project, "project", func(path string, d fs.DirEntry, err error) error {
|
if err := fs.WalkDir(templates.Project, "project", func(path string, d fs.DirEntry, err error) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// 计算相对路径,并处理隐藏文件
|
|
||||||
relPath, err := filepath.Rel("project", path)
|
relPath, err := filepath.Rel("project", path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// 如果是隐藏文件模板,将文件名中的前缀 "-" 替换为 "."
|
|
||||||
fileName := filepath.Base(relPath)
|
fileName := filepath.Base(relPath)
|
||||||
if strings.HasPrefix(fileName, "-") {
|
if strings.HasPrefix(fileName, "-") {
|
||||||
fileName = "." + strings.TrimPrefix(fileName, "-")
|
fileName = "." + strings.TrimPrefix(fileName, "-")
|
||||||
relPath = filepath.Join(filepath.Dir(relPath), fileName)
|
relPath = filepath.Join(filepath.Dir(relPath), fileName)
|
||||||
}
|
}
|
||||||
|
|
||||||
targetPath := filepath.Join(projectInfo.ProjectName, relPath)
|
targetPath := filepath.Join(rootDir, relPath)
|
||||||
if d.IsDir() {
|
if d.IsDir() {
|
||||||
log.Infof("创建目录: %s", targetPath)
|
log.Infof("创建目录: %s", targetPath)
|
||||||
return os.MkdirAll(targetPath, 0o755)
|
if dryRun {
|
||||||
}
|
log.Infof("[dry-run] mkdir -p %s", targetPath)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return os.MkdirAll(targetPath, 0o755)
|
||||||
|
}
|
||||||
|
|
||||||
// 读取模板内容
|
|
||||||
content, err := templates.Project.ReadFile(path)
|
content, err := templates.Project.ReadFile(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// 处理模板文件
|
// 渲染判定:优先(.tpl/.raw) > 行内指令 > 模板分隔符
|
||||||
|
isTpl := false
|
||||||
if strings.HasSuffix(path, ".tpl") {
|
if strings.HasSuffix(path, ".tpl") {
|
||||||
|
isTpl = true
|
||||||
|
targetPath = strings.TrimSuffix(targetPath, ".tpl")
|
||||||
|
} else if strings.HasSuffix(path, ".raw") {
|
||||||
|
isTpl = false
|
||||||
|
targetPath = strings.TrimSuffix(targetPath, ".raw")
|
||||||
|
} else if bytes.Contains(content, []byte("atomctl:mode=tpl")) {
|
||||||
|
isTpl = true
|
||||||
|
} else if bytes.Contains(content, []byte("atomctl:mode=raw")) {
|
||||||
|
isTpl = false
|
||||||
|
} else if bytes.Contains(content, []byte("{{")) && bytes.Contains(content, []byte("}}")) {
|
||||||
|
isTpl = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if inPlace && strings.HasSuffix(path, string(os.PathSeparator)+"go.mod.tpl") {
|
||||||
|
if _, err := os.Stat(filepath.Join(rootDir, "go.mod")); err == nil {
|
||||||
|
log.Infof("跳过已有文件: %s", filepath.Join(rootDir, "go.mod"))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !force {
|
||||||
|
if _, err := os.Stat(targetPath); err == nil {
|
||||||
|
log.Warnf("文件已存在,跳过: %s", targetPath)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if isTpl {
|
||||||
tmpl, err := template.New(filepath.Base(path)).Parse(string(content))
|
tmpl, err := template.New(filepath.Base(path)).Parse(string(content))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
log.Infof("[渲染] 文件: %s", targetPath)
|
||||||
|
if dryRun {
|
||||||
|
log.Infof("[dry-run] render > %s", targetPath)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
f, err := os.Create(targetPath)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrapf(err, "创建文件失败 %s", targetPath)
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
return tmpl.Execute(f, projectInfo)
|
||||||
|
}
|
||||||
|
|
||||||
// 创建目标文件(去除.tpl后缀)
|
log.Infof("[复制] 文件: %s", targetPath)
|
||||||
targetPath = strings.TrimSuffix(targetPath, ".tpl")
|
if dryRun {
|
||||||
log.Infof("创建文件: %s", targetPath)
|
log.Infof("[dry-run] write > %s", targetPath)
|
||||||
f, err := os.Create(targetPath)
|
return nil
|
||||||
if err != nil {
|
}
|
||||||
return errors.Wrapf(err, "创建文件失败 %s", targetPath)
|
return os.WriteFile(targetPath, content, 0o644)
|
||||||
}
|
}); err != nil {
|
||||||
defer f.Close()
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
return tmpl.Execute(f, projectInfo)
|
if inPlace {
|
||||||
}
|
log.Info("🎉 项目初始化成功 (当前目录)!")
|
||||||
|
} else {
|
||||||
// 处理模板文件
|
log.Info("🎉 项目创建成功!")
|
||||||
if strings.HasSuffix(path, ".raw") {
|
log.Info("后续步骤:")
|
||||||
// 创建目标文件(去除.tpl后缀)
|
log.Infof(" cd %s", projectInfo.ProjectName)
|
||||||
targetPath = strings.TrimSuffix(targetPath, ".raw")
|
|
||||||
log.Infof("创建文件: %s", targetPath)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 复制非模板文件
|
|
||||||
return os.WriteFile(targetPath, content, 0o644)
|
|
||||||
}); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 添加成功提示
|
|
||||||
log.Info("🎉 项目创建成功!")
|
|
||||||
log.Info("后续步骤:")
|
|
||||||
log.Infof(" cd %s", projectInfo.ProjectName)
|
|
||||||
log.Info(" go mod tidy")
|
log.Info(" go mod tidy")
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -27,16 +27,24 @@ func CommandNewProvider(root *cobra.Command) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func commandNewProviderE(cmd *cobra.Command, args []string) error {
|
func commandNewProviderE(cmd *cobra.Command, args []string) error {
|
||||||
providerName := args[0]
|
providerName := args[0]
|
||||||
targetPath := filepath.Join("providers", providerName)
|
// shared flags
|
||||||
|
dryRun, _ := cmd.Flags().GetBool("dry-run")
|
||||||
|
baseDir, _ := cmd.Flags().GetString("dir")
|
||||||
|
|
||||||
if _, err := os.Stat(targetPath); err == nil {
|
targetPath := filepath.Join(baseDir, "providers", providerName)
|
||||||
return fmt.Errorf("目录 %s 已存在", targetPath)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := os.MkdirAll(targetPath, os.ModePerm); err != nil {
|
if _, err := os.Stat(targetPath); err == nil {
|
||||||
return err
|
return fmt.Errorf("目录 %s 已存在", targetPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if dryRun {
|
||||||
|
fmt.Printf("[dry-run] mkdir -p %s\n", targetPath)
|
||||||
|
} else {
|
||||||
|
if err := os.MkdirAll(targetPath, os.ModePerm); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
err := fs.WalkDir(templates.Provider, "provider", func(path string, d fs.DirEntry, err error) error {
|
err := fs.WalkDir(templates.Provider, "provider", func(path string, d fs.DirEntry, err error) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -51,26 +59,35 @@ func commandNewProviderE(cmd *cobra.Command, args []string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
destPath := filepath.Join(targetPath, strings.TrimSuffix(relPath, ".tpl"))
|
destPath := filepath.Join(targetPath, strings.TrimSuffix(relPath, ".tpl"))
|
||||||
if err := os.MkdirAll(filepath.Dir(destPath), os.ModePerm); err != nil {
|
if dryRun {
|
||||||
return err
|
fmt.Printf("[dry-run] mkdir -p %s\n", filepath.Dir(destPath))
|
||||||
}
|
} else {
|
||||||
|
if err := os.MkdirAll(filepath.Dir(destPath), os.ModePerm); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
tmpl, err := template.ParseFS(templates.Provider, path)
|
tmpl, err := template.ParseFS(templates.Provider, path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
destFile, err := os.Create(destPath)
|
if dryRun {
|
||||||
if err != nil {
|
fmt.Printf("[dry-run] render > %s\n", destPath)
|
||||||
return err
|
return nil
|
||||||
}
|
}
|
||||||
defer destFile.Close()
|
|
||||||
|
|
||||||
return tmpl.Execute(destFile, map[string]string{
|
destFile, err := os.Create(destPath)
|
||||||
"Name": providerName,
|
if err != nil {
|
||||||
"CamelName": strcase.ToCamel(providerName),
|
return err
|
||||||
})
|
}
|
||||||
|
defer destFile.Close()
|
||||||
|
|
||||||
|
return tmpl.Execute(destFile, map[string]string{
|
||||||
|
"Name": providerName,
|
||||||
|
"CamelName": strcase.ToCamel(providerName),
|
||||||
|
})
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("渲染 provider 模板失败")
|
return errors.New("渲染 provider 模板失败")
|
||||||
|
|||||||
@@ -6,20 +6,25 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func CommandSwagFmt(root *cobra.Command) {
|
func CommandSwagFmt(root *cobra.Command) {
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
Use: "fmt",
|
Use: "fmt",
|
||||||
Aliases: []string{"f"},
|
Aliases: []string{"f"},
|
||||||
Short: "swag format",
|
Short: "swag format",
|
||||||
RunE: commandSwagFmtE,
|
RunE: commandSwagFmtE,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cmd.Flags().String("dir", "./app/http", "SearchDir for swag format")
|
||||||
|
cmd.Flags().String("main", "main.go", "MainFile for swag format")
|
||||||
|
|
||||||
root.AddCommand(cmd)
|
root.AddCommand(cmd)
|
||||||
}
|
}
|
||||||
|
|
||||||
func commandSwagFmtE(cmd *cobra.Command, args []string) error {
|
func commandSwagFmtE(cmd *cobra.Command, args []string) error {
|
||||||
return format.New().Build(&format.Config{
|
dir := cmd.Flag("dir").Value.String()
|
||||||
SearchDir: "./app/http",
|
main := cmd.Flag("main").Value.String()
|
||||||
Excludes: "",
|
return format.New().Build(&format.Config{
|
||||||
MainFile: "main.go",
|
SearchDir: dir,
|
||||||
})
|
Excludes: "",
|
||||||
|
MainFile: main,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,39 +11,45 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func CommandSwagInit(root *cobra.Command) {
|
func CommandSwagInit(root *cobra.Command) {
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
Use: "init",
|
Use: "init",
|
||||||
Short: "swag init",
|
Short: "swag init",
|
||||||
Aliases: []string{"i"},
|
Aliases: []string{"i"},
|
||||||
RunE: commandSwagInitE,
|
RunE: commandSwagInitE,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cmd.Flags().String("dir", ".", "SearchDir (project root)")
|
||||||
|
cmd.Flags().String("out", "docs", "Output dir for generated docs")
|
||||||
|
cmd.Flags().String("main", "main.go", "Main API file path")
|
||||||
|
|
||||||
root.AddCommand(cmd)
|
root.AddCommand(cmd)
|
||||||
}
|
}
|
||||||
|
|
||||||
func commandSwagInitE(cmd *cobra.Command, args []string) error {
|
func commandSwagInitE(cmd *cobra.Command, args []string) error {
|
||||||
pwd, err := os.Getwd()
|
root := cmd.Flag("dir").Value.String()
|
||||||
if err != nil {
|
if root == "" {
|
||||||
return err
|
var err error
|
||||||
}
|
root, err = os.Getwd()
|
||||||
if len(args) > 0 {
|
if err != nil { return err }
|
||||||
pwd = args[0]
|
}
|
||||||
}
|
|
||||||
|
|
||||||
leftDelim, rightDelim := "{{", "}}"
|
leftDelim, rightDelim := "{{", "}}"
|
||||||
|
|
||||||
return gen.New().Build(&gen.Config{
|
outDir := cmd.Flag("out").Value.String()
|
||||||
SearchDir: pwd,
|
mainFile := cmd.Flag("main").Value.String()
|
||||||
Excludes: "",
|
|
||||||
ParseExtension: "",
|
return gen.New().Build(&gen.Config{
|
||||||
MainAPIFile: "main.go",
|
SearchDir: root,
|
||||||
PropNamingStrategy: swag.CamelCase,
|
Excludes: "",
|
||||||
OutputDir: filepath.Join(pwd, "docs"),
|
ParseExtension: "",
|
||||||
OutputTypes: []string{"go", "json", "yaml"},
|
MainAPIFile: mainFile,
|
||||||
ParseVendor: false,
|
PropNamingStrategy: swag.CamelCase,
|
||||||
ParseDependency: 0,
|
OutputDir: filepath.Join(root, outDir),
|
||||||
MarkdownFilesDir: "",
|
OutputTypes: []string{"go", "json", "yaml"},
|
||||||
ParseInternal: false,
|
ParseVendor: false,
|
||||||
|
ParseDependency: 0,
|
||||||
|
MarkdownFilesDir: "",
|
||||||
|
ParseInternal: false,
|
||||||
Strict: false,
|
Strict: false,
|
||||||
GeneratedTime: false,
|
GeneratedTime: false,
|
||||||
RequiredByDefault: false,
|
RequiredByDefault: false,
|
||||||
|
|||||||
@@ -106,18 +106,12 @@ func Generate(tables []string, transformer Transformer) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
tableInfo := TableModelParam{
|
tableInfo := TableModelParam{
|
||||||
CamelTable: lo.CamelCase(table),
|
CamelTable: lo.CamelCase(table),
|
||||||
PascalTable: lo.PascalCase(table),
|
PascalTable: lo.PascalCase(table),
|
||||||
PkgName: gomod.GetModuleName(),
|
PkgName: gomod.GetModuleName(),
|
||||||
}
|
SoftDelete: strings.Contains(modelContent[table], "DeletedAt"),
|
||||||
if strings.Contains(table, "DeletedAt") {
|
HasUpdatedAt: strings.Contains(modelContent[table], "UpdatedAt"),
|
||||||
tableInfo.SoftDelete = true
|
HasCreatedAt: strings.Contains(modelContent[table], "CreatedAt"),
|
||||||
}
|
|
||||||
if strings.Contains(table, "UpdatedAt") {
|
|
||||||
tableInfo.HasUpdatedAt = true
|
|
||||||
}
|
|
||||||
if strings.Contains(table, "CreatedAt") {
|
|
||||||
tableInfo.HasCreatedAt = true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
items = append(items, tableInfo)
|
items = append(items, tableInfo)
|
||||||
|
|||||||
@@ -6,12 +6,75 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
|
|
||||||
|
|
||||||
|
{{ if gt (len .) 0 }}
|
||||||
|
"{{ (index . 0).PkgName }}/database/table"
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
"go.ipao.vip/atom"
|
"go.ipao.vip/atom"
|
||||||
"go.ipao.vip/atom/container"
|
"go.ipao.vip/atom/container"
|
||||||
"go.ipao.vip/atom/contracts"
|
"go.ipao.vip/atom/contracts"
|
||||||
"go.ipao.vip/atom/opt"
|
"go.ipao.vip/atom/opt"
|
||||||
|
. "github.com/go-jet/jet/v2/postgres"
|
||||||
|
"github.com/samber/lo"
|
||||||
|
"golang.org/x/exp/constraints"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type Cond func(BoolExpression) BoolExpression
|
||||||
|
|
||||||
|
func ExprCond(expr BoolExpression) Cond {
|
||||||
|
return func(cond BoolExpression) BoolExpression {
|
||||||
|
return cond.AND(expr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func CondTrue(conds ...Cond) BoolExpression {
|
||||||
|
cond:= BoolExp(Bool(true))
|
||||||
|
for _, c := range conds {
|
||||||
|
cond = c(cond)
|
||||||
|
}
|
||||||
|
return cond
|
||||||
|
}
|
||||||
|
|
||||||
|
func CondJoin(cond Cond, conds ...Cond) []Cond {
|
||||||
|
return append([]Cond{cond}, conds...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// converts
|
||||||
|
func IntExprSlice[T constraints.Integer](slice []T) []Expression {
|
||||||
|
if len(slice) == 0 { return nil }
|
||||||
|
|
||||||
|
return lo.Map(slice, func(item T, _ int) Expression {
|
||||||
|
switch any(item).(type) {
|
||||||
|
case int8:
|
||||||
|
return Int8(int8(item))
|
||||||
|
case int16:
|
||||||
|
return Int16(int16(item))
|
||||||
|
case int32:
|
||||||
|
return Int32(int32(item))
|
||||||
|
case int64:
|
||||||
|
return Int64(int64(item))
|
||||||
|
case uint8:
|
||||||
|
return Uint8(uint8(item))
|
||||||
|
case uint16:
|
||||||
|
return Uint16(uint16(item))
|
||||||
|
case uint32:
|
||||||
|
return Uint32(uint32(item))
|
||||||
|
case uint64:
|
||||||
|
return Uint64(uint64(item))
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// tables
|
||||||
|
{{- range . }}
|
||||||
|
var tbl{{.PascalTable}} = table.{{.PascalTable}}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
|
||||||
|
// models
|
||||||
var db *sql.DB
|
var db *sql.DB
|
||||||
{{- range . }}
|
{{- range . }}
|
||||||
func {{.PascalTable}}Model() *{{.PascalTable}} { return &{{.PascalTable}}{} }
|
func {{.PascalTable}}Model() *{{.PascalTable}} { return &{{.PascalTable}}{} }
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
package model
|
package model
|
||||||
|
|
||||||
var {{.CamelTable}}UpdateExcludeColumns = []Column{
|
var tbl{{.PascalTable}}UpdateMutableColumns = tbl{{.PascalTable}}.MutableColumns.Except(
|
||||||
{{- if .HasCreatedAt}}
|
{{- if .HasCreatedAt}}
|
||||||
table.{{.PascalTable}}.CreatedAt,
|
tbl{{.PascalTable}}.CreatedAt,
|
||||||
{{- end}}
|
{{- end}}
|
||||||
|
|
||||||
{{- if .SoftDelete}}
|
{{- if .SoftDelete}}
|
||||||
table.{{.PascalTable}}.DeletedAt,
|
tbl{{.PascalTable}}.DeletedAt,
|
||||||
{{- end}}
|
{{- end}}
|
||||||
}
|
)
|
||||||
|
|||||||
@@ -1,17 +1,37 @@
|
|||||||
|
// Code generated by the atomctl ; DO NOT EDIT.
|
||||||
|
// Code generated by the atomctl ; DO NOT EDIT.
|
||||||
|
// Code generated by the atomctl ; DO NOT EDIT.
|
||||||
package model
|
package model
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"{{ .PkgName }}/database/table"
|
|
||||||
|
|
||||||
"github.com/samber/lo"
|
"github.com/samber/lo"
|
||||||
. "github.com/go-jet/jet/v2/postgres"
|
. "github.com/go-jet/jet/v2/postgres"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
// conds
|
||||||
|
{{- if .SoftDelete }}
|
||||||
|
func (m *{{.PascalTable}}) CondNotDeleted() Cond {
|
||||||
|
return func(cond BoolExpression) BoolExpression {
|
||||||
|
return cond.AND(tbl{{.PascalTable}}.DeletedAt.IS_NULL())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *{{.PascalTable}}) CondDeleted() Cond {
|
||||||
|
return func(cond BoolExpression) BoolExpression {
|
||||||
|
return cond.AND(tbl{{.PascalTable}}.DeletedAt.IS_NOT_NULL())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{{- end}}
|
||||||
|
|
||||||
|
func (m *{{.PascalTable}}) CondID(id int64) Cond {
|
||||||
|
return func(cond BoolExpression) BoolExpression {
|
||||||
|
return cond.AND(tbl{{.PascalTable}}.ID.EQ(Int(id)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// funcs
|
||||||
func (m *{{.PascalTable}}) log() *log.Entry {
|
func (m *{{.PascalTable}}) log() *log.Entry {
|
||||||
return log.WithField("model", "{{.PascalTable}}")
|
return log.WithField("model", "{{.PascalTable}}")
|
||||||
}
|
}
|
||||||
@@ -26,7 +46,7 @@ func (m *{{.PascalTable}}) Create(ctx context.Context) error {
|
|||||||
{{- end}}
|
{{- end}}
|
||||||
|
|
||||||
|
|
||||||
stmt := table.Medias.INSERT(table.{{.PascalTable}}.MutableColumns).MODEL(m).RETURNING(table.Medias.AllColumns)
|
stmt := tbl{{.PascalTable}}.INSERT(tbl{{.PascalTable}}.MutableColumns).MODEL(m).RETURNING(tbl{{.PascalTable}}.AllColumns)
|
||||||
m.log().WithField("func","Create").Info( stmt.DebugSql())
|
m.log().WithField("func","Create").Info( stmt.DebugSql())
|
||||||
|
|
||||||
if err := stmt.QueryContext(ctx, db, m); err != nil {
|
if err := stmt.QueryContext(ctx, db, m); err != nil {
|
||||||
@@ -40,7 +60,7 @@ func (m *{{.PascalTable}}) Create(ctx context.Context) error {
|
|||||||
|
|
||||||
|
|
||||||
func (m *{{.PascalTable}}) BatchCreate(ctx context.Context, models []*{{.PascalTable}}) error {
|
func (m *{{.PascalTable}}) BatchCreate(ctx context.Context, models []*{{.PascalTable}}) error {
|
||||||
stmt := table.{{.PascalTable}}.INSERT(table.{{.PascalTable}}.MutableColumns).MODELS(models)
|
stmt := tbl{{.PascalTable}}.INSERT(tbl{{.PascalTable}}.MutableColumns).MODELS(models)
|
||||||
m.log().WithField("func", "BatchCreate").Info(stmt.DebugSql())
|
m.log().WithField("func", "BatchCreate").Info(stmt.DebugSql())
|
||||||
|
|
||||||
if _, err := stmt.ExecContext(ctx, db); err != nil {
|
if _, err := stmt.ExecContext(ctx, db); err != nil {
|
||||||
@@ -52,10 +72,9 @@ func (m *{{.PascalTable}}) BatchCreate(ctx context.Context, models []*{{.PascalT
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// if SoftDelete
|
|
||||||
{{- if .SoftDelete }}
|
{{- if .SoftDelete }}
|
||||||
func (m *{{.PascalTable}}) Delete(ctx context.Context) error {
|
func (m *{{.PascalTable}}) Delete(ctx context.Context) error {
|
||||||
stmt := table.{{.PascalTable}}.UPDATE().SET(table.{{.PascalTable}}.DeletedAt.Set(TimestampzT(time.Now()))).WHERE(table.{{.PascalTable}}.ID.EQ(Int(m.ID)))
|
stmt := tbl{{.PascalTable}}.UPDATE().SET(tbl{{.PascalTable}}.DeletedAt.SET(TimestampT(time.Now()))).WHERE(tbl{{.PascalTable}}.ID.EQ(Int(m.ID)))
|
||||||
m.log().WithField("func", "SoftDelete").Info(stmt.DebugSql())
|
m.log().WithField("func", "SoftDelete").Info(stmt.DebugSql())
|
||||||
|
|
||||||
if err := stmt.QueryContext(ctx, db, m); err != nil {
|
if err := stmt.QueryContext(ctx, db, m); err != nil {
|
||||||
@@ -73,7 +92,7 @@ func (m *{{.PascalTable}}) BatchDelete(ctx context.Context, ids []int64) error {
|
|||||||
return Int64(id)
|
return Int64(id)
|
||||||
})
|
})
|
||||||
|
|
||||||
stmt := table.{{.PascalTable}}.UPDATE().SET(table.{{.PascalTable}}.DeletedAt.Set(TimestampzT(time.Now()))).WHERE(table.{{.PascalTable}}.ID.IN(condIds...))
|
stmt := tbl{{.PascalTable}}.UPDATE().SET(tbl{{.PascalTable}}.DeletedAt.SET(TimestampT(time.Now()))).WHERE(tbl{{.PascalTable}}.ID.IN(condIds...))
|
||||||
m.log().WithField("func", "BatchSoftDelete").Info(stmt.DebugSql())
|
m.log().WithField("func", "BatchSoftDelete").Info(stmt.DebugSql())
|
||||||
|
|
||||||
if err := stmt.QueryContext(ctx, db, m); err != nil {
|
if err := stmt.QueryContext(ctx, db, m); err != nil {
|
||||||
@@ -81,14 +100,13 @@ func (m *{{.PascalTable}}) BatchDelete(ctx context.Context, ids []int64) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
m.log().WithField("func", "BatchSoftDelete").Infof("{{.PascalTable}} items soft deleted successfully")
|
m.log().WithField("func", "BatchSoftDelete").WithField("ids", ids).Infof("{{.PascalTable}} items soft deleted successfully")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
{{- end}}
|
|
||||||
|
|
||||||
|
|
||||||
func (m *{{.PascalTable}}) ForceDelete(ctx context.Context) error {
|
func (m *{{.PascalTable}}) ForceDelete(ctx context.Context) error {
|
||||||
stmt := table.{{.PascalTable}}.DELETE().WHERE(table.{{.PascalTable}}.ID.EQ(Int(m.ID)))
|
stmt := tbl{{.PascalTable}}.DELETE().WHERE(tbl{{.PascalTable}}.ID.EQ(Int(m.ID)))
|
||||||
m.log().WithField("func", "Delete").Info(stmt.DebugSql())
|
m.log().WithField("func", "Delete").Info(stmt.DebugSql())
|
||||||
|
|
||||||
if _, err := stmt.ExecContext(ctx, db); err != nil {
|
if _, err := stmt.ExecContext(ctx, db); err != nil {
|
||||||
@@ -105,24 +123,56 @@ func (m *{{.PascalTable}}) BatchForceDelete(ctx context.Context, ids []int64) er
|
|||||||
return Int64(id)
|
return Int64(id)
|
||||||
})
|
})
|
||||||
|
|
||||||
stmt := table.{{.PascalTable}}.DELETE().WHERE(table.{{.PascalTable}}.ID.IN(condIds...))
|
stmt := tbl{{.PascalTable}}.DELETE().WHERE(tbl{{.PascalTable}}.ID.IN(condIds...))
|
||||||
m.log().WithField("func", "BatchDelete").Info(stmt.DebugSql())
|
m.log().WithField("func", "BatchDelete").Info(stmt.DebugSql())
|
||||||
|
|
||||||
if _, err := stmt.ExecContext(ctx, db); err != nil {
|
if _, err := stmt.ExecContext(ctx, db); err != nil {
|
||||||
|
m.log().WithField("func","BatchForceDelete").Errorf("error deleting {{.PascalTable}} items: %v", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
m.log().WithField("func", "BatchForceDelete").WithField("ids", ids).Infof("{{.PascalTable}} items deleted successfully")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
{{- else}}
|
||||||
|
func (m *{{.PascalTable}}) Delete(ctx context.Context) error {
|
||||||
|
stmt := tbl{{.PascalTable}}.DELETE().WHERE(tbl{{.PascalTable}}.ID.EQ(Int(m.ID)))
|
||||||
|
m.log().WithField("func", "Delete").Info(stmt.DebugSql())
|
||||||
|
|
||||||
|
if err := stmt.QueryContext(ctx, db, m); err != nil {
|
||||||
|
m.log().WithField("func","Delete").Errorf("error deleting {{.PascalTable}} item: %v", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
m.log().WithField("func", "Delete").Infof("{{.PascalTable}} item deleted successfully")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// BatchDelete
|
||||||
|
func (m *{{.PascalTable}}) BatchDelete(ctx context.Context, ids []int64) error {
|
||||||
|
condIds := lo.Map(ids, func(id int64, _ int) Expression {
|
||||||
|
return Int64(id)
|
||||||
|
})
|
||||||
|
|
||||||
|
stmt := tbl{{.PascalTable}}.DELETE().WHERE(tbl{{.PascalTable}}.ID.IN(condIds...))
|
||||||
|
m.log().WithField("func", "BatchDelete").Info(stmt.DebugSql())
|
||||||
|
|
||||||
|
if err := stmt.QueryContext(ctx, db, m); err != nil {
|
||||||
m.log().WithField("func","BatchDelete").Errorf("error deleting {{.PascalTable}} items: %v", err)
|
m.log().WithField("func","BatchDelete").Errorf("error deleting {{.PascalTable}} items: %v", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
m.log().WithField("func", "BatchDelete").Infof("{{.PascalTable}} items deleted successfully")
|
m.log().WithField("func", "BatchDelete").WithField("ids", ids).Infof("{{.PascalTable}} items deleted successfully")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
{{- end}}
|
||||||
|
|
||||||
func (m *{{.PascalTable}}) Update(ctx context.Context) error {
|
func (m *{{.PascalTable}}) Update(ctx context.Context) error {
|
||||||
{{- if .HasUpdatedAt}}
|
{{- if .HasUpdatedAt}}
|
||||||
m.UpdatedAt = time.Now()
|
m.UpdatedAt = time.Now()
|
||||||
{{- end}}
|
{{- end}}
|
||||||
|
|
||||||
stmt := table.{{.PascalTable}}.UPDATE(table.{{.PascalTable}}.MutableColumns.Except({{.CamelTable}}UpdateExcludeColumns...)).SET(m).WHERE(table.{{.PascalTable}}.ID.EQ(Int(m.ID))).RETURNING(table.{{.PascalTable}}.AllColumns)
|
stmt := tbl{{.PascalTable}}.UPDATE(tbl{{.PascalTable}}UpdateMutableColumns).MODEL(m).WHERE(tbl{{.PascalTable}}.ID.EQ(Int(m.ID))).RETURNING(tbl{{.PascalTable}}.AllColumns)
|
||||||
m.log().WithField("func", "Update").Info(stmt.DebugSql())
|
m.log().WithField("func", "Update").Info(stmt.DebugSql())
|
||||||
|
|
||||||
if err := stmt.QueryContext(ctx, db, m); err != nil {
|
if err := stmt.QueryContext(ctx, db, m); err != nil {
|
||||||
@@ -133,38 +183,34 @@ func (m *{{.PascalTable}}) Update(ctx context.Context) error {
|
|||||||
m.log().WithField("func", "Update").Infof("{{.PascalTable}} item updated successfully")
|
m.log().WithField("func", "Update").Infof("{{.PascalTable}} item updated successfully")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
// GetByID
|
|
||||||
func (m *{{.PascalTable}}) GetByID(ctx context.Context, id int64, conds ...BoolExpression) (*{{.PascalTable}}, error) {
|
// GetByCond
|
||||||
expr := table.{{.PascalTable}}.ID.EQ(Int(m.ID))
|
func (m *{{.PascalTable}}) GetByCond(ctx context.Context, conds ...Cond) (*{{.PascalTable}}, error) {
|
||||||
if len(conds) > 0 {
|
cond := CondTrue(conds...)
|
||||||
for _, c := range conds {
|
|
||||||
expr = expr.AND(c)
|
stmt := tbl{{.PascalTable}}.SELECT(tbl{{.PascalTable}}.AllColumns).WHERE(cond)
|
||||||
}
|
m.log().WithField("func", "GetByCond").Info(stmt.DebugSql())
|
||||||
}
|
|
||||||
stmt := table.{{.PascalTable}}.SELECT(table.{{.PascalTable}}.AllColumns).WHERE(expr)
|
|
||||||
m.log().WithField("func", "GetByID").Info(stmt.DebugSql())
|
|
||||||
|
|
||||||
if err := stmt.QueryContext(ctx, db, m); err != nil {
|
if err := stmt.QueryContext(ctx, db, m); err != nil {
|
||||||
m.log().WithField("func","GetByID").Errorf("error getting {{.PascalTable}} item by ID: %v", err)
|
m.log().WithField("func","GetByCond").Errorf("error getting {{.PascalTable}} item by ID: %v", err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
m.log().WithField("func", "GetByID").Infof("{{.PascalTable}} item retrieved successfully")
|
m.log().WithField("func", "GetByCond").Infof("{{.PascalTable}} item retrieved successfully")
|
||||||
return m, nil
|
return m, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetByID
|
||||||
|
func (m *{{.PascalTable}}) GetByID(ctx context.Context, id int64, conds ...Cond) (*{{.PascalTable}}, error) {
|
||||||
|
return m.GetByCond(ctx, CondJoin(m.CondID(id), conds...)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Count
|
// Count
|
||||||
func (m *{{.PascalTable}}) Count(ctx context.Context, conds ...BoolExpression) (int64, error) {
|
func (m *{{.PascalTable}}) Count(ctx context.Context, conds ...Cond) (int64, error) {
|
||||||
cond := Bool(true)
|
cond := CondTrue(conds...)
|
||||||
if len(conds) > 0 {
|
|
||||||
for _, c := range conds {
|
|
||||||
cond = cond.AND(c)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tbl := table.{{.PascalTable}}
|
stmt := tbl{{.PascalTable}}.SELECT(COUNT(tbl{{.PascalTable}}.ID).AS("count")).WHERE(cond)
|
||||||
stmt := tbl.SELECT(COUNT(tbl.ID).AS("count")).WHERE(cond)
|
|
||||||
m.log().Infof("sql: %s", stmt.DebugSql())
|
m.log().Infof("sql: %s", stmt.DebugSql())
|
||||||
|
|
||||||
var count struct {
|
var count struct {
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import (
|
|||||||
|
|
||||||
"{{ .PkgName }}/app/service/testx"
|
"{{ .PkgName }}/app/service/testx"
|
||||||
"{{ .PkgName }}/database"
|
"{{ .PkgName }}/database"
|
||||||
"{{ .PkgName }}/database/schemas/public/table"
|
"{{ .PkgName }}/database/table"
|
||||||
|
|
||||||
. "github.com/smartystreets/goconvey/convey"
|
. "github.com/smartystreets/goconvey/convey"
|
||||||
"go.ipao.vip/atom/contracts"
|
"go.ipao.vip/atom/contracts"
|
||||||
@@ -38,6 +38,6 @@ func Test_{{ .PascalTable }}(t *testing.T) {
|
|||||||
|
|
||||||
func (s *{{ .PascalTable }}TestSuite) Test_Demo() {
|
func (s *{{ .PascalTable }}TestSuite) Test_Demo() {
|
||||||
Convey("Test_Demo", s.T(), func() {
|
Convey("Test_Demo", s.T(), func() {
|
||||||
database.Truncate(context.Background(), db, table.{{ .PascalTable }}.TableName())
|
database.Truncate(context.Background(), db, tbl{{ .PascalTable }}.TableName())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user