|
@@ -15,196 +15,194 @@ mongo的生成不同于mysql,mysql可以从scheme_information库中读取到
|
|
|
而mongo是文档型数据库,我们暂时无法从db中读取某一条记录来实现字段信息获取,就算有也不一定是完整信息(某些字段可能是omitempty修饰,可有可无), 这里采用type自己编写+代码生成方式实现
|
|
|
|
|
|
## 使用示例
|
|
|
+为 User 生成 mongo model
|
|
|
+```bahs
|
|
|
+$ goctl model mongo -t User -c --dir .
|
|
|
+```
|
|
|
|
|
|
-假设我们需要生成一个usermodel.go的代码文件,其包含用户信息字段有
|
|
|
+### 生成示例代码
|
|
|
|
|
|
-|字段名称|字段类型|
|
|
|
-|---|---|
|
|
|
-|_id|bson.ObejctId|
|
|
|
-|name|string|
|
|
|
+#### usermodel.go
|
|
|
+```go
|
|
|
+package model
|
|
|
|
|
|
-### 编写types.go
|
|
|
+import (
|
|
|
+ "github.com/zeromicro/go-zero/core/stores/cache"
|
|
|
+ "github.com/zeromicro/go-zero/core/stores/monc"
|
|
|
+)
|
|
|
+
|
|
|
+var _ UserModel = (*customUserModel)(nil)
|
|
|
+
|
|
|
+type (
|
|
|
+ // UserModel is an interface to be customized, add more methods here,
|
|
|
+ // and implement the added methods in customUserModel.
|
|
|
+ UserModel interface {
|
|
|
+ userModel
|
|
|
+ }
|
|
|
+
|
|
|
+ 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),
|
|
|
+ }
|
|
|
+}
|
|
|
|
|
|
-```shell
|
|
|
-$ vim types.go
|
|
|
```
|
|
|
|
|
|
-```golang
|
|
|
+#### usermodelgen.go
|
|
|
+```go
|
|
|
+// Code generated by goctl. DO NOT EDIT!
|
|
|
package model
|
|
|
|
|
|
-//go:generate goctl model mongo -t User
|
|
|
-import "github.com/globalsign/mgo/bson"
|
|
|
+import (
|
|
|
+ "context"
|
|
|
+ "time"
|
|
|
|
|
|
-type User struct {
|
|
|
- ID bson.ObjectId `bson:"_id"`
|
|
|
- Name string `bson:"name"`
|
|
|
+ "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}
|
|
|
+}
|
|
|
|
|
|
-* 命令行生成 在types.go所在文件夹执行命令
|
|
|
- ```shell
|
|
|
- $ goctl model mongo -t User -style gozero
|
|
|
- ```
|
|
|
-* 在types.go中添加`//go:generate`,然后点击执行按钮即可生成,内容示例如下:
|
|
|
- ```golang
|
|
|
- //go:generate goctl model mongo -t User
|
|
|
- ```
|
|
|
+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
|
|
|
+}
|
|
|
|
|
|
-* usermodel.go
|
|
|
-
|
|
|
- ```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))
|
|
|
- }
|
|
|
- ```
|
|
|
-
|
|
|
-* error.go
|
|
|
-
|
|
|
- ```golang
|
|
|
- package model
|
|
|
-
|
|
|
- import "errors"
|
|
|
-
|
|
|
- var ErrNotFound = errors.New("not found")
|
|
|
- var ErrInvalidObjectId = errors.New("invalid objectId")
|
|
|
- ```
|
|
|
+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
|
|
|
+}
|
|
|
|
|
|
-```text
|
|
|
-.
|
|
|
-├── error.go
|
|
|
-├── types.go
|
|
|
-└── usermodel.go
|
|
|
+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
|
|
|
|
|
|
-```text
|
|
|
-NAME:
|
|
|
- goctl model - generate model code
|
|
|
+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"`
|
|
|
+}
|
|
|
+
|
|
|
+```
|
|
|
|
|
|
-USAGE:
|
|
|
- goctl model command [command options] [arguments...]
|
|
|
+#### error.go
|
|
|
+```go
|
|
|
+package model
|
|
|
+
|
|
|
+import (
|
|
|
+ "errors"
|
|
|
|
|
|
-COMMANDS:
|
|
|
- mysql generate mysql model
|
|
|
- mongo generate mongo model
|
|
|
+ "github.com/zeromicro/go-zero/core/stores/mon"
|
|
|
+)
|
|
|
|
|
|
-OPTIONS:
|
|
|
- --help, -h show help
|
|
|
+var (
|
|
|
+ ErrNotFound = mon.ErrNotFound
|
|
|
+ ErrInvalidObjectId = errors.New("invalid objectId")
|
|
|
+)
|
|
|
```
|
|
|
|
|
|
+### 文件目录预览
|
|
|
+
|
|
|
```text
|
|
|
-NAME:
|
|
|
- goctl model mongo - generate mongo model
|
|
|
+.
|
|
|
+├── error.go
|
|
|
+├── usermodel.go
|
|
|
+├── usermodelgen.go
|
|
|
+└── usertypes.go
|
|
|
+```
|
|
|
|
|
|
-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]
|
|
|
+```text
|
|
|
+Generate mongo model
|
|
|
+
|
|
|
+Usage:
|
|
|
+ goctl model mongo [flags]
|
|
|
+
|
|
|
+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名称和模板中一致就行。
|