From c27e00b45cd9e7eba825ed7cfea5e7e76bb0de3b Mon Sep 17 00:00:00 2001 From: anqiansong Date: Sun, 12 Jun 2022 23:02:34 +0800 Subject: [PATCH] feat: Replace mongo package with monc & mon (#2002) * Replace mongo package with monc & mon * Add terminal whitespace * format code --- tools/goctl/model/mongo/generate/generate.go | 67 +++- .../model/mongo/generate/generate_test.go | 57 ++- tools/goctl/model/mongo/generate/template.go | 14 +- .../model/mongo/generate/template_test.go | 41 +++ tools/goctl/model/mongo/mongo.go | 6 + tools/goctl/model/mongo/readme.md | 328 +++++++++--------- tools/goctl/model/mongo/template/error.tpl | 12 +- tools/goctl/model/mongo/template/model.tpl | 97 ++---- .../model/mongo/template/model_custom.tpl | 28 ++ tools/goctl/model/mongo/template/template.go | 22 +- tools/goctl/model/mongo/template/types.tpl | 14 + tools/goctl/test/common/echo.sh | 25 ++ .../test/integration/model/mongo/Dockerfile | 12 + .../goctl/test/integration/model/mongo/cmd.sh | 32 ++ .../test/integration/model/mongo/mongo.sh | 38 ++ tools/goctl/test/main.sh | 6 + 16 files changed, 544 insertions(+), 255 deletions(-) create mode 100644 tools/goctl/model/mongo/generate/template_test.go create mode 100644 tools/goctl/model/mongo/template/model_custom.tpl create mode 100644 tools/goctl/model/mongo/template/types.tpl create mode 100644 tools/goctl/test/common/echo.sh create mode 100644 tools/goctl/test/integration/model/mongo/Dockerfile create mode 100644 tools/goctl/test/integration/model/mongo/cmd.sh create mode 100644 tools/goctl/test/integration/model/mongo/mongo.sh create mode 100644 tools/goctl/test/main.sh diff --git a/tools/goctl/model/mongo/generate/generate.go b/tools/goctl/model/mongo/generate/generate.go index 6bc8c005..bbdf9123 100644 --- a/tools/goctl/model/mongo/generate/generate.go +++ b/tools/goctl/model/mongo/generate/generate.go @@ -9,6 +9,7 @@ import ( "github.com/zeromicro/go-zero/tools/goctl/util" "github.com/zeromicro/go-zero/tools/goctl/util/format" "github.com/zeromicro/go-zero/tools/goctl/util/pathx" + "github.com/zeromicro/go-zero/tools/goctl/util/stringx" ) // Context defines the model generation data what they needs @@ -25,8 +26,15 @@ func Do(ctx *Context) error { return errors.New("missing config") } - err := generateModel(ctx) - if err != nil { + if err := generateTypes(ctx); err != nil { + return err + } + + if err := generateModel(ctx); err != nil { + return err + } + + if err := generateCustomModel(ctx); err != nil { return err } @@ -34,21 +42,47 @@ func Do(ctx *Context) error { } func generateModel(ctx *Context) error { + for _, t := range ctx.Types { + fn, err := format.FileNamingFormat(ctx.Cfg.NamingFormat, t+"_model_gen") + if err != nil { + return err + } + + text, err := pathx.LoadTemplate(category, modelTemplateFile, template.ModelText) + if err != nil { + return err + } + + output := filepath.Join(ctx.Output, fn+".go") + if err = util.With("model").Parse(text).GoFmt(true).SaveTo(map[string]interface{}{ + "Type": stringx.From(t).Title(), + "lowerType": stringx.From(t).Untitle(), + "Cache": ctx.Cache, + }, output, true); err != nil { + return err + } + } + + return nil +} + +func generateCustomModel(ctx *Context) error { for _, t := range ctx.Types { fn, err := format.FileNamingFormat(ctx.Cfg.NamingFormat, t+"_model") if err != nil { return err } - text, err := pathx.LoadTemplate(category, modelTemplateFile, template.Text) + text, err := pathx.LoadTemplate(category, modelCustomTemplateFile, template.ModelCustomText) if err != nil { return err } output := filepath.Join(ctx.Output, fn+".go") err = util.With("model").Parse(text).GoFmt(true).SaveTo(map[string]interface{}{ - "Type": t, - "Cache": ctx.Cache, + "Type": stringx.From(t).Title(), + "lowerType": stringx.From(t).Untitle(), + "Cache": ctx.Cache, }, output, false) if err != nil { return err @@ -58,6 +92,29 @@ func generateModel(ctx *Context) error { return nil } +func generateTypes(ctx *Context) error { + for _, t := range ctx.Types { + fn, err := format.FileNamingFormat(ctx.Cfg.NamingFormat, t+"types") + if err != nil { + return err + } + + text, err := pathx.LoadTemplate(category, modelTypesTemplateFile, template.ModelTypesText) + if err != nil { + return err + } + + output := filepath.Join(ctx.Output, fn+".go") + if err = util.With("model").Parse(text).GoFmt(true).SaveTo(map[string]interface{}{ + "Type": stringx.From(t).Title(), + }, output, false);err!=nil{ + return err + } + } + + return nil +} + func generateError(ctx *Context) error { text, err := pathx.LoadTemplate(category, errTemplateFile, template.Error) if err != nil { diff --git a/tools/goctl/model/mongo/generate/generate_test.go b/tools/goctl/model/mongo/generate/generate_test.go index c214ac74..3586b60a 100644 --- a/tools/goctl/model/mongo/generate/generate_test.go +++ b/tools/goctl/model/mongo/generate/generate_test.go @@ -16,20 +16,53 @@ var testTypes = ` ` func TestDo(t *testing.T) { - cfg, err := config.NewConfig(config.DefaultFormat) - assert.Nil(t, err) + t.Run("should generate model", func(t *testing.T) { + cfg, err := config.NewConfig(config.DefaultFormat) + assert.Nil(t, err) - tempDir := pathx.MustTempDir() - typesfile := filepath.Join(tempDir, "types.go") - err = ioutil.WriteFile(typesfile, []byte(testTypes), 0o666) - assert.Nil(t, err) + tempDir := pathx.MustTempDir() + typesfile := filepath.Join(tempDir, "types.go") + err = ioutil.WriteFile(typesfile, []byte(testTypes), 0o666) + assert.Nil(t, err) - err = Do(&Context{ - Types: []string{"User", "Class"}, - Cache: false, - Output: tempDir, - Cfg: cfg, + err = Do(&Context{ + Types: []string{"User", "Class"}, + Cache: false, + Output: tempDir, + Cfg: cfg, + }) + + assert.Nil(t, err) }) - assert.Nil(t, err) + t.Run("missing config", func(t *testing.T) { + tempDir := t.TempDir() + typesfile := filepath.Join(tempDir, "types.go") + err := ioutil.WriteFile(typesfile, []byte(testTypes), 0o666) + assert.Nil(t, err) + + err = Do(&Context{ + Types: []string{"User", "Class"}, + Cache: false, + Output: tempDir, + Cfg: nil, + }) + assert.Error(t, err) + }) + + t.Run("invalid config", func(t *testing.T) { + cfg := &config.Config{NamingFormat: "foo"} + tempDir := t.TempDir() + typesfile := filepath.Join(tempDir, "types.go") + err := ioutil.WriteFile(typesfile, []byte(testTypes), 0o666) + assert.Nil(t, err) + + err = Do(&Context{ + Types: []string{"User", "Class"}, + Cache: false, + Output: tempDir, + Cfg: cfg, + }) + assert.Error(t, err) + }) } diff --git a/tools/goctl/model/mongo/generate/template.go b/tools/goctl/model/mongo/generate/template.go index a86f96d8..1adbddcb 100644 --- a/tools/goctl/model/mongo/generate/template.go +++ b/tools/goctl/model/mongo/generate/template.go @@ -8,14 +8,18 @@ import ( ) const ( - category = "mongo" - modelTemplateFile = "model.tpl" - errTemplateFile = "err.tpl" + category = "mongo" + modelTemplateFile = "model.tpl" + modelCustomTemplateFile = "model_custom.tpl" + modelTypesTemplateFile = "model_types.tpl" + errTemplateFile = "err.tpl" ) var templates = map[string]string{ - modelTemplateFile: template.Text, - errTemplateFile: template.Error, + modelTemplateFile: template.ModelText, + modelCustomTemplateFile: template.ModelCustomText, + modelTypesTemplateFile: template.ModelTypesText, + errTemplateFile: template.Error, } // Category returns the mongo category. diff --git a/tools/goctl/model/mongo/generate/template_test.go b/tools/goctl/model/mongo/generate/template_test.go new file mode 100644 index 00000000..ea580fb2 --- /dev/null +++ b/tools/goctl/model/mongo/generate/template_test.go @@ -0,0 +1,41 @@ +package generate + +import ( + "path/filepath" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/zeromicro/go-zero/tools/goctl/util/pathx" +) + +func TestTemplate(t *testing.T) { + tempDir := t.TempDir() + pathx.RegisterGoctlHome(tempDir) + t.Cleanup(func() { + pathx.RegisterGoctlHome("") + }) + + t.Run("Category", func(t *testing.T) { + assert.Equal(t, category, Category()) + }) + + t.Run("Clean", func(t *testing.T) { + err := Clean() + assert.NoError(t, err) + }) + + t.Run("Templates", func(t *testing.T) { + err := Templates() + assert.NoError(t, err) + assert.True(t, pathx.FileExists(filepath.Join(tempDir, category, modelTemplateFile))) + }) + + t.Run("RevertTemplate", func(t *testing.T) { + assert.NoError(t, RevertTemplate(modelTemplateFile)) + assert.Error(t, RevertTemplate("foo")) + }) + + t.Run("Update", func(t *testing.T) { + assert.NoError(t, Update()) + }) +} diff --git a/tools/goctl/model/mongo/mongo.go b/tools/goctl/model/mongo/mongo.go index ab3d4ae6..022c47b0 100644 --- a/tools/goctl/model/mongo/mongo.go +++ b/tools/goctl/model/mongo/mongo.go @@ -38,12 +38,14 @@ func Action(_ *cobra.Command, _ []string) error { home := VarStringHome remote := VarStringRemote branch := VarStringBranch + if len(remote) > 0 { repo, _ := file.CloneIntoGitHome(remote, branch) if len(repo) > 0 { home = repo } } + if len(home) > 0 { pathx.RegisterGoctlHome(home) } @@ -62,6 +64,10 @@ func Action(_ *cobra.Command, _ []string) error { return err } + if err = pathx.MkdirIfNotExist(a); err != nil { + return err + } + return generate.Do(&generate.Context{ Types: tp, Cache: c, diff --git a/tools/goctl/model/mongo/readme.md b/tools/goctl/model/mongo/readme.md index 9e2bb80e..3317cce3 100644 --- a/tools/goctl/model/mongo/readme.md +++ b/tools/goctl/model/mongo/readme.md @@ -15,196 +15,194 @@ mongo的生成不同于mysql,mysql可以从scheme_information库中读取到 而mongo是文档型数据库,我们暂时无法从db中读取某一条记录来实现字段信息获取,就算有也不一定是完整信息(某些字段可能是omitempty修饰,可有可无), 这里采用type自己编写+代码生成方式实现 ## 使用示例 - -假设我们需要生成一个usermodel.go的代码文件,其包含用户信息字段有 - -|字段名称|字段类型| -|---|---| -|_id|bson.ObejctId| -|name|string| - -### 编写types.go - -```shell -$ vim types.go +为 User 生成 mongo model +```bahs +$ goctl model mongo -t User -c --dir . ``` -```golang -package model - -//go:generate goctl model mongo -t User -import "github.com/globalsign/mgo/bson" - -type User struct { - ID bson.ObjectId `bson:"_id"` - Name string `bson:"name"` -} -``` - -### 生成代码 - -生成代码的方式有两种 - -* 命令行生成 在types.go所在文件夹执行命令 - ```shell - $ goctl model mongo -t User -style gozero - ``` -* 在types.go中添加`//go:generate`,然后点击执行按钮即可生成,内容示例如下: - ```golang - //go:generate goctl model mongo -t User - ``` - ### 生成示例代码 -* usermodel.go +#### usermodel.go +```go +package model - ```golang - package model - - import ( - "context" - - "github.com/globalsign/mgo/bson" - cachec "github.com/zeromicro/go-zero/core/stores/cache" - "github.com/zeromicro/go-zero/core/stores/mongoc" - ) - - type UserModel interface { - Insert(data *User, ctx context.Context) error - FindOne(id string, ctx context.Context) (*User, error) - Update(data *User, ctx context.Context) error - Delete(id string, ctx context.Context) error - } - - type defaultUserModel struct { - *mongoc.Model - } - - func NewUserModel(url, collection string, c cachec.CacheConf) UserModel { - return &defaultUserModel{ - Model: mongoc.MustNewModel(url, collection, c), - } - } - - func (m *defaultUserModel) Insert(data *User, ctx context.Context) error { - if !data.ID.Valid() { - data.ID = bson.NewObjectId() - } - - session, err := m.TakeSession() - if err != nil { - return err - } - - defer m.PutSession(session) - return m.GetCollection(session).Insert(data) - } - - func (m *defaultUserModel) FindOne(id string, ctx context.Context) (*User, error) { - if !bson.IsObjectIdHex(id) { - return nil, ErrInvalidObjectId - } - - session, err := m.TakeSession() - if err != nil { - return nil, err - } - - defer m.PutSession(session) - var data User - - err = m.GetCollection(session).FindOneIdNoCache(&data, bson.ObjectIdHex(id)) - switch err { - case nil: - return &data, nil - case mongoc.ErrNotFound: - return nil, ErrNotFound - default: - return nil, err - } - } - - func (m *defaultUserModel) Update(data *User, ctx context.Context) error { - session, err := m.TakeSession() - if err != nil { - return err - } - - defer m.PutSession(session) - - return m.GetCollection(session).UpdateIdNoCache(data.ID, data) - } - - func (m *defaultUserModel) Delete(id string, ctx context.Context) error { - session, err := m.TakeSession() - if err != nil { - return err - } - - defer m.PutSession(session) - - return m.GetCollection(session).RemoveIdNoCache(bson.ObjectIdHex(id)) - } - ``` +import ( + "github.com/zeromicro/go-zero/core/stores/cache" + "github.com/zeromicro/go-zero/core/stores/monc" +) -* error.go +var _ UserModel = (*customUserModel)(nil) - ```golang - package model +type ( + // UserModel is an interface to be customized, add more methods here, + // and implement the added methods in customUserModel. + UserModel interface { + userModel + } - import "errors" - - var ErrNotFound = errors.New("not found") - var ErrInvalidObjectId = errors.New("invalid objectId") - ``` + customUserModel struct { + *defaultUserModel + } +) + +// NewUserModel returns a model for the mongo. +func NewUserModel(url, db, collection string, c cache.CacheConf) UserModel { + conn := monc.MustNewModel(url, db, collection, c) + return &customUserModel{ + defaultUserModel: newDefaultUserModel(conn), + } +} + +``` + +#### usermodelgen.go +```go +// Code generated by goctl. DO NOT EDIT! +package model + +import ( + "context" + "time" + + "github.com/zeromicro/go-zero/core/stores/monc" + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/bson/primitive" +) + +var prefixUserCacheKey = "cache:user:" + +type userModel interface { + Insert(ctx context.Context, data *User) error + FindOne(ctx context.Context, id string) (*User, error) + Update(ctx context.Context, data *User) error + Delete(ctx context.Context, id string) error +} + +type defaultUserModel struct { + conn *monc.Model +} + +func newDefaultUserModel(conn *monc.Model) *defaultUserModel { + return &defaultUserModel{conn: conn} +} + +func (m *defaultUserModel) Insert(ctx context.Context, data *User) error { + if !data.ID.IsZero() { + data.ID = primitive.NewObjectID() + data.CreateAt = time.Now() + data.UpdateAt = time.Now() + } + + key := prefixUserCacheKey + data.ID.Hex() + _, err := m.conn.InsertOne(ctx, key, data) + return err +} + +func (m *defaultUserModel) FindOne(ctx context.Context, id string) (*User, error) { + oid, err := primitive.ObjectIDFromHex(id) + if err != nil { + return nil, ErrInvalidObjectId + } + + var data User + key := prefixUserCacheKey + data.ID.Hex() + err = m.conn.FindOne(ctx, key, &data, bson.M{"_id": oid}) + switch err { + case nil: + return &data, nil + case monc.ErrNotFound: + return nil, ErrNotFound + default: + return nil, err + } +} + +func (m *defaultUserModel) Update(ctx context.Context, data *User) error { + data.UpdateAt = time.Now() + key := prefixUserCacheKey + data.ID.Hex() + _, err := m.conn.ReplaceOne(ctx, key, bson.M{"_id": data.ID}, data) + return err +} + +func (m *defaultUserModel) Delete(ctx context.Context, id string) error { + oid, err := primitive.ObjectIDFromHex(id) + if err != nil { + return ErrInvalidObjectId + } + key := prefixUserCacheKey + id + _, err = m.conn.DeleteOne(ctx, key, bson.M{"_id": oid}) + return err +} + +``` + +#### usertypes.go +```go +package model + +import ( + "time" + + "go.mongodb.org/mongo-driver/bson/primitive" +) + +type User struct { + ID primitive.ObjectID `bson:"_id,omitempty" json:"id,omitempty"` + // TODO: Fill your own fields + UpdateAt time.Time `bson:"updateAt,omitempty" json:"updateAt,omitempty"` + CreateAt time.Time `bson:"createAt,omitempty" json:"createAt,omitempty"` +} + +``` + +#### error.go +```go +package model + +import ( + "errors" + + "github.com/zeromicro/go-zero/core/stores/mon" +) + +var ( + ErrNotFound = mon.ErrNotFound + ErrInvalidObjectId = errors.New("invalid objectId") +) +``` ### 文件目录预览 ```text . ├── error.go -├── types.go -└── usermodel.go - +├── usermodel.go +├── usermodelgen.go +└── usertypes.go ``` ## 命令预览 ```text -NAME: - goctl model - generate model code +Generate mongo model -USAGE: - goctl model command [command options] [arguments...] +Usage: + goctl model mongo [flags] -COMMANDS: - mysql generate mysql model - mongo generate mongo model - -OPTIONS: - --help, -h show help -``` - -```text -NAME: - goctl model mongo - generate mongo model - -USAGE: - goctl model mongo [command options] [arguments...] - -OPTIONS: - --type value, -t value specified model type name - --cache, -c generate code with cache [optional] - --dir value, -d value the target dir - --style value the file naming format, see [https://github.com/zeromicro/go-zero/tree/master/tools/goctl/config/readme.md] +Flags: + --branch string The branch of the remote repo, it does work with --remote + -c, --cache Generate code with cache [optional] + -d, --dir string The target dir + -h, --help help for mongo + --home string The goctl home path of the template, --home and --remote cannot be set at the same time, if they are, --remote has higher priority + --remote string The remote git repo of the template, --home and --remote cannot be set at the same time, if they are, --remote has higher priority + The git repo directory must be consistent with the https://github.com/zeromicro/go-zero-template directory structure + --style string The file naming format, see [https://github.com/zeromicro/go-zero/tree/master/tools/goctl/config/readme.md] + -t, --type strings Specified model type name ``` > 温馨提示 > > `--type` 支持slice传值,示例 `goctl model mongo -t=User -t=Class` -## 注意事项 -types.go本质上与xxxmodel.go无关,只是将type定义部分交给开发人员自己编写了,在xxxmodel.go中,mongo文档的存储结构必须包含 -`_id`字段,对应到types中的field为`ID`,model中的findOne,update均以data.ID来进行操作的,当然,如果不符合你的命名风格,你也 可以修改模板,只要保证`id` -在types中的field名称和模板中一致就行。 diff --git a/tools/goctl/model/mongo/template/error.tpl b/tools/goctl/model/mongo/template/error.tpl index cb8be412..27d92449 100644 --- a/tools/goctl/model/mongo/template/error.tpl +++ b/tools/goctl/model/mongo/template/error.tpl @@ -1,6 +1,12 @@ package model -import "errors" +import ( + "errors" -var ErrNotFound = errors.New("not found") -var ErrInvalidObjectId = errors.New("invalid objectId") + "github.com/zeromicro/go-zero/core/stores/mon" +) + +var ( + ErrNotFound = mon.ErrNotFound + ErrInvalidObjectId = errors.New("invalid objectId") +) diff --git a/tools/goctl/model/mongo/template/model.tpl b/tools/goctl/model/mongo/template/model.tpl index bf807d01..c88f1462 100644 --- a/tools/goctl/model/mongo/template/model.tpl +++ b/tools/goctl/model/mongo/template/model.tpl @@ -1,98 +1,77 @@ +// Code generated by goctl. DO NOT EDIT! package model import ( "context" + "time" - "github.com/globalsign/mgo/bson" - {{if .Cache}}cachec "github.com/zeromicro/go-zero/core/stores/cache" - "github.com/zeromicro/go-zero/core/stores/mongoc"{{else}}"github.com/zeromicro/go-zero/core/stores/mongo"{{end}} + {{if .Cache}}"github.com/zeromicro/go-zero/core/stores/monc"{{else}}"github.com/zeromicro/go-zero/core/stores/mon"{{end}} + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/bson/primitive" ) -{{if .Cache}}var prefix{{.Type}}CacheKey = "cache:{{.Type}}:"{{end}} +{{if .Cache}}var prefix{{.Type}}CacheKey = "cache:{{.lowerType}}:"{{end}} -type {{.Type}}Model interface{ - Insert(ctx context.Context,data *{{.Type}}) error - FindOne(ctx context.Context,id string) (*{{.Type}}, error) - Update(ctx context.Context,data *{{.Type}}) error - Delete(ctx context.Context,id string) error +type {{.lowerType}}Model interface{ + Insert(ctx context.Context,data *{{.Type}}) error + FindOne(ctx context.Context,id string) (*{{.Type}}, error) + Update(ctx context.Context,data *{{.Type}}) error + Delete(ctx context.Context,id string) error } type default{{.Type}}Model struct { - {{if .Cache}}*mongoc.Model{{else}}*mongo.Model{{end}} + conn {{if .Cache}}*monc.Model{{else}}*mon.Model{{end}} } -func New{{.Type}}Model(url, collection string{{if .Cache}}, c cachec.CacheConf{{end}}) {{.Type}}Model { - return &default{{.Type}}Model{ - Model: {{if .Cache}}mongoc.MustNewModel(url, collection, c){{else}}mongo.MustNewModel(url, collection){{end}}, - } +func newDefault{{.Type}}Model(conn {{if .Cache}}*monc.Model{{else}}*mon.Model{{end}}) *default{{.Type}}Model { + return &default{{.Type}}Model{conn: conn} } func (m *default{{.Type}}Model) Insert(ctx context.Context, data *{{.Type}}) error { - if !data.ID.Valid() { - data.ID = bson.NewObjectId() + if !data.ID.IsZero() { + data.ID = primitive.NewObjectID() + data.CreateAt = time.Now() + data.UpdateAt = time.Now() } - session, err := m.TakeSession() - if err != nil { - return err - } - - defer m.PutSession(session) - return m.GetCollection(session).Insert(data) + {{if .Cache}}key := prefix{{.Type}}CacheKey + data.ID.Hex(){{end}} + _, err := m.conn.InsertOne(ctx, {{if .Cache}}key, {{end}} data) + return err } func (m *default{{.Type}}Model) FindOne(ctx context.Context, id string) (*{{.Type}}, error) { - if !bson.IsObjectIdHex(id) { + oid, err := primitive.ObjectIDFromHex(id) + if err != nil { return nil, ErrInvalidObjectId } - session, err := m.TakeSession() - if err != nil { - return nil, err - } - - defer m.PutSession(session) var data {{.Type}} - {{if .Cache}}key := prefix{{.Type}}CacheKey + id - err = m.GetCollection(session).FindOneId(&data, key, bson.ObjectIdHex(id)) - {{- else}} - err = m.GetCollection(session).FindId(bson.ObjectIdHex(id)).One(&data) - {{- end}} + {{if .Cache}}key := prefix{{.Type}}CacheKey + data.ID.Hex(){{end}} + err = m.conn.FindOne(ctx, {{if .Cache}}key, {{end}}&data, bson.M{"_id": oid}) switch err { case nil: - return &data,nil - case {{if .Cache}}mongoc.ErrNotFound{{else}}mongo.ErrNotFound{{end}}: - return nil,ErrNotFound + return &data, nil + case {{if .Cache}}monc{{else}}mon{{end}}.ErrNotFound: + return nil, ErrNotFound default: - return nil,err + return nil, err } } func (m *default{{.Type}}Model) Update(ctx context.Context, data *{{.Type}}) error { - session, err := m.TakeSession() - if err != nil { - return err - } - - defer m.PutSession(session) - {{if .Cache}}key := prefix{{.Type}}CacheKey + data.ID.Hex() - return m.GetCollection(session).UpdateId(data.ID, data, key) - {{- else}} - return m.GetCollection(session).UpdateId(data.ID, data) - {{- end}} + data.UpdateAt = time.Now() + {{if .Cache}}key := prefix{{.Type}}CacheKey + data.ID.Hex(){{end}} + _, err := m.conn.ReplaceOne(ctx, {{if .Cache}}key, {{end}}bson.M{"_id": data.ID}, data) + return err } func (m *default{{.Type}}Model) Delete(ctx context.Context, id string) error { - session, err := m.TakeSession() + oid, err := primitive.ObjectIDFromHex(id) if err != nil { - return err + return ErrInvalidObjectId } - - defer m.PutSession(session) - {{if .Cache}}key := prefix{{.Type}}CacheKey + id - return m.GetCollection(session).RemoveId(bson.ObjectIdHex(id), key) - {{- else}} - return m.GetCollection(session).RemoveId(bson.ObjectIdHex(id)) - {{- end}} + {{if .Cache}}key := prefix{{.Type}}CacheKey +id{{end}} + _, err = m.conn.DeleteOne(ctx, {{if .Cache}}key, {{end}}bson.M{"_id": oid}) + return err } diff --git a/tools/goctl/model/mongo/template/model_custom.tpl b/tools/goctl/model/mongo/template/model_custom.tpl new file mode 100644 index 00000000..244e5c5a --- /dev/null +++ b/tools/goctl/model/mongo/template/model_custom.tpl @@ -0,0 +1,28 @@ +package model + +{{if .Cache}}import ( + "github.com/zeromicro/go-zero/core/stores/cache" + "github.com/zeromicro/go-zero/core/stores/monc" +){{else}}import "github.com/zeromicro/go-zero/core/stores/mon"{{end}} + +var _ {{.Type}}Model = (*custom{{.Type}}Model)(nil) + +type ( + // {{.Type}}Model is an interface to be customized, add more methods here, + // and implement the added methods in custom{{.Type}}Model. + {{.Type}}Model interface { + {{.lowerType}}Model + } + + custom{{.Type}}Model struct { + *default{{.Type}}Model + } +) + +// New{{.Type}}Model returns a model for the mongo. +func New{{.Type}}Model(url, db, collection string{{if .Cache}}, c cache.CacheConf{{end}}) {{.Type}}Model { + conn := {{if .Cache}}monc{{else}}mon{{end}}.MustNewModel(url, db, collection{{if .Cache}}, c{{end}}) + return &custom{{.Type}}Model{ + default{{.Type}}Model: newDefault{{.Type}}Model(conn), + } +} diff --git a/tools/goctl/model/mongo/template/template.go b/tools/goctl/model/mongo/template/template.go index 9477f5f2..72e160e3 100644 --- a/tools/goctl/model/mongo/template/template.go +++ b/tools/goctl/model/mongo/template/template.go @@ -2,10 +2,20 @@ package template import _ "embed" -// Text provides the default template for model to generate. -//go:embed model.tpl -var Text string +var ( + // ModelText provides the default template for model to generate. + //go:embed model.tpl + ModelText string -// Error provides the default template for error definition in mongo code generation. -//go:embed error.tpl -var Error string + // ModelCustomText provides the default template for model to generate. + //go:embed model_custom.tpl + ModelCustomText string + + // ModelTypesText provides the default template for model to generate. + //go:embed types.tpl + ModelTypesText string + + // Error provides the default template for error definition in mongo code generation. + //go:embed error.tpl + Error string +) diff --git a/tools/goctl/model/mongo/template/types.tpl b/tools/goctl/model/mongo/template/types.tpl new file mode 100644 index 00000000..8da006f4 --- /dev/null +++ b/tools/goctl/model/mongo/template/types.tpl @@ -0,0 +1,14 @@ +package model + +import ( + "time" + + "go.mongodb.org/mongo-driver/bson/primitive" +) + +type {{.Type}} struct { + ID primitive.ObjectID `bson:"_id,omitempty" json:"id,omitempty"` + // TODO: Fill your own fields + UpdateAt time.Time `bson:"updateAt,omitempty" json:"updateAt,omitempty"` + CreateAt time.Time `bson:"createAt,omitempty" json:"createAt,omitempty"` +} diff --git a/tools/goctl/test/common/echo.sh b/tools/goctl/test/common/echo.sh new file mode 100644 index 00000000..3314209a --- /dev/null +++ b/tools/goctl/test/common/echo.sh @@ -0,0 +1,25 @@ +#!/bin/bash + +function console_red() { + echo -e "\033[31m "$*" \033[0m" +} + +function console_green() { + echo -e "\033[32m "$*" \033[0m" +} + +function console_yellow() { + echo -e "\033[33m "$*" \033[0m" +} + +function console_blue() { + echo -e "\033[34m "$*" \033[0m" +} + +function console_tip() { + console_blue "========================== $* ==============================" +} + +function console_step() { + console_blue "<<<<<<<<<<<<<<<< $* >>>>>>>>>>>>>>>>" +} diff --git a/tools/goctl/test/integration/model/mongo/Dockerfile b/tools/goctl/test/integration/model/mongo/Dockerfile new file mode 100644 index 00000000..4116de77 --- /dev/null +++ b/tools/goctl/test/integration/model/mongo/Dockerfile @@ -0,0 +1,12 @@ +FROM golang:1.18 + +ENV TZ Asia/Shanghai +ENV GOPROXY https://goproxy.cn,direct + +WORKDIR /app +ADD goctl /usr/bin/goctl +ADD cmd.sh . + +RUN chmod +x /usr/bin/goctl +RUN chmod +x cmd.sh +CMD ["/bin/bash", "cmd.sh"] diff --git a/tools/goctl/test/integration/model/mongo/cmd.sh b/tools/goctl/test/integration/model/mongo/cmd.sh new file mode 100644 index 00000000..c8ba2edb --- /dev/null +++ b/tools/goctl/test/integration/model/mongo/cmd.sh @@ -0,0 +1,32 @@ +#!/bin/bash + +wd=$(dirname $0) +project=test +testDir=$wd/$project +mkdir -p $testDir + +cd $testDir + +# go mod init +go mod init $project + +# generate cache code +goctl model mongo -t User -c --dir cache +if [ $? -ne 0 ]; then + exit 1 +fi + +# generate non-cache code +goctl model mongo -t User --dir nocache +if [ $? -ne 0 ]; then + exit 1 +fi + +# go mod tidy +GOPROXY=https://goproxy.cn && go mod tidy + +# code inspection +go test -race ./... +if [ $? -ne 0 ]; then + echo +fi diff --git a/tools/goctl/test/integration/model/mongo/mongo.sh b/tools/goctl/test/integration/model/mongo/mongo.sh new file mode 100644 index 00000000..73c80ef3 --- /dev/null +++ b/tools/goctl/test/integration/model/mongo/mongo.sh @@ -0,0 +1,38 @@ +#!/bin/bash + +cd $(dirname $0) + +# source functions +source ../../../common/echo.sh + +console_tip "mongo test" + +# build goctl +console_step "goctl building" + +buildFile=goctl +CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o $buildFile ../../../../goctl.go +image=goctl-mongo:latest + +# docker build +console_step "docker building" +docker build -t $image . +if [ $? -ne 0 ]; then + rm -f $buildFile + console_red "docker build failed" + exit 1 +fi + +# run docker image +console_step "docker running" +docker run $image +if [ $? -ne 0 ]; then + rm -f $buildFile + console_red "docker run failed" + docker image rm -f $image + exit 1 +fi + +rm -f $buildFile +console_green "PASS" +docker image rm -f $image > /dev/null 2>&1 diff --git a/tools/goctl/test/main.sh b/tools/goctl/test/main.sh new file mode 100644 index 00000000..a9d94cea --- /dev/null +++ b/tools/goctl/test/main.sh @@ -0,0 +1,6 @@ +#!/bin/bash + +# main.sh is the entry point for the goctl tests. + +# testing mongo code generation. +/bin/bash integration/model/mongo/mongo.sh