mirror of
https://github.com/zeromicro/go-zero.git
synced 2025-02-02 16:28:39 +08:00
feat: Replace mongo package with monc & mon (#2002)
* Replace mongo package with monc & mon * Add terminal whitespace * format code
This commit is contained in:
parent
ed1c937998
commit
c27e00b45c
@ -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 {
|
||||
|
@ -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)
|
||||
})
|
||||
}
|
||||
|
@ -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.
|
||||
|
41
tools/goctl/model/mongo/generate/template_test.go
Normal file
41
tools/goctl/model/mongo/generate/template_test.go
Normal file
@ -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())
|
||||
})
|
||||
}
|
@ -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,
|
||||
|
@ -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名称和模板中一致就行。
|
||||
|
@ -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")
|
||||
)
|
||||
|
@ -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
|
||||
}
|
||||
|
28
tools/goctl/model/mongo/template/model_custom.tpl
Normal file
28
tools/goctl/model/mongo/template/model_custom.tpl
Normal file
@ -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),
|
||||
}
|
||||
}
|
@ -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
|
||||
)
|
||||
|
14
tools/goctl/model/mongo/template/types.tpl
Normal file
14
tools/goctl/model/mongo/template/types.tpl
Normal file
@ -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"`
|
||||
}
|
25
tools/goctl/test/common/echo.sh
Normal file
25
tools/goctl/test/common/echo.sh
Normal file
@ -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 "<<<<<<<<<<<<<<<< $* >>>>>>>>>>>>>>>>"
|
||||
}
|
12
tools/goctl/test/integration/model/mongo/Dockerfile
Normal file
12
tools/goctl/test/integration/model/mongo/Dockerfile
Normal file
@ -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"]
|
32
tools/goctl/test/integration/model/mongo/cmd.sh
Normal file
32
tools/goctl/test/integration/model/mongo/cmd.sh
Normal file
@ -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
|
38
tools/goctl/test/integration/model/mongo/mongo.sh
Normal file
38
tools/goctl/test/integration/model/mongo/mongo.sh
Normal file
@ -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
|
6
tools/goctl/test/main.sh
Normal file
6
tools/goctl/test/main.sh
Normal file
@ -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
|
Loading…
Reference in New Issue
Block a user