484 lines
15 KiB
Markdown
484 lines
15 KiB
Markdown
# mongoctl
|
||
|
||
### 1.介绍
|
||
|
||
mongoctl是一个自动化生成MongoDB数据访问对象(Data Access Object)的工具。
|
||
|
||
### 2.优势
|
||
|
||
* 支持primitive.ObjectID、primitive.DateTime类型的自动填充。
|
||
|
||
* 支持int、int8、int16、int32、int64、uint、uint8、uint16、uint32、uint64类型的自增长。
|
||
|
||
* 提供了对数据库字段的统一生成方案,避免了业务代码中随处可见的数据库字段的问题。
|
||
|
||
* 提供了包括InsertOne、InsertMany、UpdateOne、UpdateOneByID、UpdateMany、FindOne、FindOneByID、FindMany、DeleteOne、DeleteOneByID、DeleteMany、Count、Aggregate等多种数据库操作接口。
|
||
|
||
* 提供了对数据库操作接口的扩展能力。
|
||
|
||
* 提供了分包与不分包两种包解决方案。
|
||
|
||
* 支持目录和文件名风格的自定义。
|
||
|
||
### 3.安装
|
||
|
||
```bash
|
||
go install
|
||
```
|
||
|
||
### 4.用法
|
||
|
||
```bash
|
||
用法 mongoctl:
|
||
mongoctl [flags] -model-dir=. -model-names=T,T -dao-dir=./dao
|
||
Flags:
|
||
-counter-name string
|
||
自增模型名称; 默认是 counter
|
||
-dao-dir string
|
||
生成代码所在目录; 必需
|
||
-dao-pkg-path string
|
||
生成代码所在目录的包名; 默认自动生成
|
||
-file-style string
|
||
代码文件名称风格; 选项: kebab | underscore | lower | camel | pascal; 默认是 underscore (default "underscore")
|
||
-model-dir string
|
||
模型所在目录; 必需
|
||
-model-names string
|
||
模型结构体名称; 必需
|
||
-model-pkg-alias string
|
||
模型包别名
|
||
-model-pkg-path string
|
||
模型包名; 默认自动生成
|
||
-sub-pkg-enable
|
||
每个模型创建一个子包; 默认关闭
|
||
-sub-pkg-style string
|
||
模型子包目录名称风格; 选项: kebab | underscore | lower | camel | pascal; 默认是 kebab (default "kebab")
|
||
|
||
```
|
||
|
||
### 5.标签
|
||
|
||
在模型定义中支持对gen标签的解析,目前支持以下标签解析:
|
||
|
||
| 标签名称 | | 示例 | 说明 |
|
||
| -------- | ---------------------------------------------------------- | ------------------ | -------------------------- |
|
||
| autoFill | primitive.ObjectID、primitive.DateTime | gen:"autoFill" | |
|
||
| autoIncr | int、int8、int16、int32、int64、uint、uint8、uint16、uint32、uint64 | gen:"autoIncr:uid" | 该自增为原子操作,会在生成代码时同步生成计数器代码。 |
|
||
|
||
### 6.示例
|
||
|
||
###### 6-1.创建模型
|
||
|
||
model/mail.go
|
||
|
||
```go
|
||
package model
|
||
|
||
import "go.mongodb.org/mongo-driver/bson/primitive"
|
||
|
||
//go:generate mongoctl -model-dir=. -model-names=Mail -dao-dir=../dao/
|
||
type Mail struct {
|
||
ID primitive.ObjectID `bson:"_id" gen:"autoFill"` // 邮件ID
|
||
Title string `bson:"title"` // 邮件标题
|
||
Content string `bson:"content"` // 邮件内容
|
||
Sender int64 `bson:"sender"` // 邮件发送者
|
||
Receiver int64 `bson:"receiver"` // 邮件接受者
|
||
Status int `bson:"status"` // 邮件状态
|
||
SendTime primitive.DateTime `bson:"send_time" gen:"autoFill"` // 发送时间
|
||
}
|
||
```
|
||
|
||
###### 6-2.生成dao文件
|
||
|
||
```bash
|
||
go generate ./...
|
||
```
|
||
|
||
###### 6-3.生成的dao文件示例
|
||
|
||
dao/internal/mail.go
|
||
|
||
```go
|
||
// --------------------------------------------------------------------------------------------
|
||
// The following code is automatically generated by the mongo-dao-generator tool.
|
||
// Please do not modify this code manually to avoid being overwritten in the next generation.
|
||
// For more tool details, please click the link to view https://github.com/dobyte/mongo-dao-generator
|
||
// --------------------------------------------------------------------------------------------
|
||
|
||
package internal
|
||
|
||
import (
|
||
"context"
|
||
"errors"
|
||
models "github.com/dobyte/mongo-dao-generator/example/model"
|
||
"go.mongodb.org/mongo-driver/bson"
|
||
"go.mongodb.org/mongo-driver/bson/primitive"
|
||
"go.mongodb.org/mongo-driver/mongo"
|
||
"go.mongodb.org/mongo-driver/mongo/options"
|
||
"time"
|
||
)
|
||
|
||
type MailFilterFunc func(cols *MailColumns) interface{}
|
||
type MailUpdateFunc func(cols *MailColumns) interface{}
|
||
type MailPipelineFunc func(cols *MailColumns) interface{}
|
||
type MailCountOptionsFunc func(cols *MailColumns) *options.CountOptions
|
||
type MailAggregateOptionsFunc func(cols *MailColumns) *options.AggregateOptions
|
||
type MailFindOneOptionsFunc func(cols *MailColumns) *options.FindOneOptions
|
||
type MailFindManyOptionsFunc func(cols *MailColumns) *options.FindOptions
|
||
type MailUpdateOptionsFunc func(cols *MailColumns) *options.UpdateOptions
|
||
type MailDeleteOptionsFunc func(cols *MailColumns) *options.DeleteOptions
|
||
type MailInsertOneOptionsFunc func(cols *MailColumns) *options.InsertOneOptions
|
||
type MailInsertManyOptionsFunc func(cols *MailColumns) *options.InsertManyOptions
|
||
|
||
type Mail struct {
|
||
Columns *MailColumns
|
||
Database *mongo.Database
|
||
Collection *mongo.Collection
|
||
}
|
||
|
||
type MailColumns struct {
|
||
ID string // 邮件ID
|
||
Title string // 邮件标题
|
||
Content string // 邮件内容
|
||
Sender string // 邮件发送者
|
||
Receiver string // 邮件接受者
|
||
Status string // 邮件状态
|
||
SendTime string // 发送时间
|
||
}
|
||
|
||
var mailColumns = &MailColumns{
|
||
ID: "_id", // 邮件ID
|
||
Title: "title", // 邮件标题
|
||
Content: "content", // 邮件内容
|
||
Sender: "sender", // 邮件发送者
|
||
Receiver: "receiver", // 邮件接受者
|
||
Status: "status", // 邮件状态
|
||
SendTime: "send_time", // 发送时间
|
||
}
|
||
|
||
func NewMail(db *mongo.Database) *Mail {
|
||
return &Mail{
|
||
Columns: mailColumns,
|
||
Database: db,
|
||
Collection: db.Collection("mail"),
|
||
}
|
||
}
|
||
|
||
// Count returns the number of documents in the collection.
|
||
func (dao *Mail) Count(ctx context.Context, filterFunc MailFilterFunc, optionsFunc ...MailCountOptionsFunc) (int64, error) {
|
||
var (
|
||
opts *options.CountOptions
|
||
filter = filterFunc(dao.Columns)
|
||
)
|
||
|
||
if len(optionsFunc) > 0 {
|
||
opts = optionsFunc[0](dao.Columns)
|
||
}
|
||
|
||
return dao.Collection.CountDocuments(ctx, filter, opts)
|
||
}
|
||
|
||
// Aggregate executes an aggregate command against the collection and returns a cursor over the resulting documents.
|
||
func (dao *Mail) Aggregate(ctx context.Context, pipelineFunc MailPipelineFunc, optionsFunc ...MailAggregateOptionsFunc) (*mongo.Cursor, error) {
|
||
var (
|
||
opts *options.AggregateOptions
|
||
pipeline = pipelineFunc(dao.Columns)
|
||
)
|
||
|
||
if len(optionsFunc) > 0 {
|
||
opts = optionsFunc[0](dao.Columns)
|
||
}
|
||
|
||
return dao.Collection.Aggregate(ctx, pipeline, opts)
|
||
}
|
||
|
||
// InsertOne executes an insert command to insert a single document into the collection.
|
||
func (dao *Mail) InsertOne(ctx context.Context, model *models.Mail, optionsFunc ...MailInsertOneOptionsFunc) (*mongo.InsertOneResult, error) {
|
||
if model == nil {
|
||
return nil, errors.New("model is nil")
|
||
}
|
||
|
||
if err := dao.autofill(ctx, model); err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
var opts *options.InsertOneOptions
|
||
|
||
if len(optionsFunc) > 0 {
|
||
opts = optionsFunc[0](dao.Columns)
|
||
}
|
||
|
||
return dao.Collection.InsertOne(ctx, model, opts)
|
||
}
|
||
|
||
// InsertMany executes an insert command to insert multiple documents into the collection.
|
||
func (dao *Mail) InsertMany(ctx context.Context, models []*models.Mail, optionsFunc ...MailInsertManyOptionsFunc) (*mongo.InsertManyResult, error) {
|
||
if len(models) == 0 {
|
||
return nil, errors.New("models is empty")
|
||
}
|
||
|
||
documents := make([]interface{}, 0, len(models))
|
||
for i := range models {
|
||
model := models[i]
|
||
if err := dao.autofill(ctx, model); err != nil {
|
||
return nil, err
|
||
}
|
||
documents = append(documents, model)
|
||
}
|
||
|
||
var opts *options.InsertManyOptions
|
||
|
||
if len(optionsFunc) > 0 {
|
||
opts = optionsFunc[0](dao.Columns)
|
||
}
|
||
|
||
return dao.Collection.InsertMany(ctx, documents, opts)
|
||
}
|
||
|
||
// UpdateOne executes an update command to update at most one document in the collection.
|
||
func (dao *Mail) UpdateOne(ctx context.Context, filterFunc MailFilterFunc, updateFunc MailUpdateFunc, optionsFunc ...MailUpdateOptionsFunc) (*mongo.UpdateResult, error) {
|
||
var (
|
||
opts *options.UpdateOptions
|
||
filter = filterFunc(dao.Columns)
|
||
update = updateFunc(dao.Columns)
|
||
)
|
||
|
||
if len(optionsFunc) > 0 {
|
||
opts = optionsFunc[0](dao.Columns)
|
||
}
|
||
|
||
return dao.Collection.UpdateOne(ctx, filter, update, opts)
|
||
}
|
||
|
||
// UpdateOneByID executes an update command to update at most one document in the collection.
|
||
func (dao *Mail) UpdateOneByID(ctx context.Context, id string, updateFunc MailUpdateFunc, optionsFunc ...MailUpdateOptionsFunc) (*mongo.UpdateResult, error) {
|
||
objectID, err := primitive.ObjectIDFromHex(id)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
return dao.UpdateOne(ctx, func(cols *MailColumns) interface{} {
|
||
return bson.M{"_id": objectID}
|
||
}, updateFunc, optionsFunc...)
|
||
}
|
||
|
||
// UpdateMany executes an update command to update documents in the collection.
|
||
func (dao *Mail) UpdateMany(ctx context.Context, filterFunc MailFilterFunc, updateFunc MailUpdateFunc, optionsFunc ...MailUpdateOptionsFunc) (*mongo.UpdateResult, error) {
|
||
var (
|
||
opts *options.UpdateOptions
|
||
filter = filterFunc(dao.Columns)
|
||
update = updateFunc(dao.Columns)
|
||
)
|
||
|
||
if len(optionsFunc) > 0 {
|
||
opts = optionsFunc[0](dao.Columns)
|
||
}
|
||
|
||
return dao.Collection.UpdateMany(ctx, filter, update, opts)
|
||
}
|
||
|
||
// FindOne executes a find command and returns a model for one document in the collection.
|
||
func (dao *Mail) FindOne(ctx context.Context, filterFunc MailFilterFunc, optionsFunc ...MailFindOneOptionsFunc) (*models.Mail, error) {
|
||
var (
|
||
opts *options.FindOneOptions
|
||
model = &models.Mail{}
|
||
filter = filterFunc(dao.Columns)
|
||
)
|
||
|
||
if len(optionsFunc) > 0 {
|
||
opts = optionsFunc[0](dao.Columns)
|
||
}
|
||
|
||
err := dao.Collection.FindOne(ctx, filter, opts).Decode(model)
|
||
if err != nil {
|
||
if err == mongo.ErrNoDocuments {
|
||
return nil, nil
|
||
}
|
||
return nil, err
|
||
}
|
||
|
||
return model, nil
|
||
}
|
||
|
||
// FindOneByID executes a find command and returns a model for one document in the collection.
|
||
func (dao *Mail) FindOneByID(ctx context.Context, id string, optionsFunc ...MailFindOneOptionsFunc) (*models.Mail, error) {
|
||
objectID, err := primitive.ObjectIDFromHex(id)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
return dao.FindOne(ctx, func(cols *MailColumns) interface{} {
|
||
return bson.M{"_id": objectID}
|
||
}, optionsFunc...)
|
||
}
|
||
|
||
// FindMany executes a find command and returns many models the matching documents in the collection.
|
||
func (dao *Mail) FindMany(ctx context.Context, filterFunc MailFilterFunc, optionsFunc ...MailFindManyOptionsFunc) ([]*models.Mail, error) {
|
||
var (
|
||
opts *options.FindOptions
|
||
filter = filterFunc(dao.Columns)
|
||
)
|
||
|
||
if len(optionsFunc) > 0 {
|
||
opts = optionsFunc[0](dao.Columns)
|
||
}
|
||
|
||
cur, err := dao.Collection.Find(ctx, filter, opts)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
models := make([]*models.Mail, 0)
|
||
|
||
if err = cur.All(ctx, &models); err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
return models, nil
|
||
}
|
||
|
||
// DeleteOne executes a delete command to delete at most one document from the collection.
|
||
func (dao *Mail) DeleteOne(ctx context.Context, filterFunc MailFilterFunc, optionsFunc ...MailDeleteOptionsFunc) (*mongo.DeleteResult, error) {
|
||
var (
|
||
opts *options.DeleteOptions
|
||
filter = filterFunc(dao.Columns)
|
||
)
|
||
|
||
if len(optionsFunc) > 0 {
|
||
opts = optionsFunc[0](dao.Columns)
|
||
}
|
||
|
||
return dao.Collection.DeleteOne(ctx, filter, opts)
|
||
}
|
||
|
||
// DeleteOneByID executes a delete command to delete at most one document from the collection.
|
||
func (dao *Mail) DeleteOneByID(ctx context.Context, id string, optionsFunc ...MailDeleteOptionsFunc) (*mongo.DeleteResult, error) {
|
||
objectID, err := primitive.ObjectIDFromHex(id)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
return dao.DeleteOne(ctx, func(cols *MailColumns) interface{} {
|
||
return bson.M{"_id": objectID}
|
||
}, optionsFunc...)
|
||
}
|
||
|
||
// DeleteMany executes a delete command to delete documents from the collection.
|
||
func (dao *Mail) DeleteMany(ctx context.Context, filterFunc MailFilterFunc, optionsFunc ...MailDeleteOptionsFunc) (*mongo.DeleteResult, error) {
|
||
var (
|
||
opts *options.DeleteOptions
|
||
filter = filterFunc(dao.Columns)
|
||
)
|
||
|
||
if len(optionsFunc) > 0 {
|
||
opts = optionsFunc[0](dao.Columns)
|
||
}
|
||
|
||
return dao.Collection.DeleteMany(ctx, filter, opts)
|
||
}
|
||
|
||
// autofill when inserting data
|
||
func (dao *Mail) autofill(ctx context.Context, model *models.Mail) error {
|
||
if model.ID.IsZero() {
|
||
model.ID = primitive.NewObjectID()
|
||
}
|
||
|
||
if model.SendTime == 0 {
|
||
model.SendTime = primitive.NewDateTimeFromTime(time.Now())
|
||
}
|
||
|
||
return nil
|
||
}
|
||
```
|
||
|
||
dao/mail.go
|
||
|
||
```go
|
||
package dao
|
||
|
||
import (
|
||
"github.com/dobyte/mongo-dao-generator/example/dao/internal"
|
||
"go.mongodb.org/mongo-driver/mongo"
|
||
)
|
||
|
||
type MailColumns = internal.MailColumns
|
||
|
||
type Mail struct {
|
||
*internal.Mail
|
||
}
|
||
|
||
func NewMail(db *mongo.Database) *Mail {
|
||
return &Mail{Mail: internal.NewMail(db)}
|
||
}
|
||
```
|
||
|
||
###### 6-4.使用生成的dao文件
|
||
|
||
```go
|
||
package main
|
||
|
||
import (
|
||
"context"
|
||
"github.com/dobyte/mongo-dao-generator/example/dao"
|
||
"github.com/dobyte/mongo-dao-generator/example/model"
|
||
"go.mongodb.org/mongo-driver/bson"
|
||
"go.mongodb.org/mongo-driver/mongo"
|
||
"go.mongodb.org/mongo-driver/mongo/options"
|
||
"go.mongodb.org/mongo-driver/mongo/readpref"
|
||
"log"
|
||
"time"
|
||
)
|
||
|
||
func main() {
|
||
var (
|
||
uri = "mongodb://root:12345678@127.0.0.1:27017"
|
||
opts = options.Client().ApplyURI(uri)
|
||
baseCtx = context.Background()
|
||
)
|
||
|
||
ctx, cancel := context.WithTimeout(baseCtx, 5*time.Second)
|
||
client, err := mongo.Connect(ctx, opts)
|
||
cancel()
|
||
if err != nil {
|
||
log.Fatalf("connect mongo server failed: %v", err)
|
||
}
|
||
|
||
ctx, cancel = context.WithTimeout(baseCtx, 5*time.Second)
|
||
defer cancel()
|
||
err = client.Ping(ctx, readpref.Primary())
|
||
cancel()
|
||
if err != nil {
|
||
log.Fatalf("ping mongo server failed: %v", err)
|
||
}
|
||
|
||
db := client.Database("dao_test")
|
||
|
||
mailDao := dao.NewMail(db)
|
||
|
||
_, err = mailDao.InsertOne(baseCtx, &model.Mail{
|
||
Title: "mongo-dao-generator introduction",
|
||
Content: "the mongo-dao-generator is a tool for automatically generating MongoDB Data Access Object.",
|
||
Sender: 1,
|
||
Receiver: 2,
|
||
Status: 1,
|
||
})
|
||
if err != nil {
|
||
log.Fatalf("failed to insert into mongo database: %v", err)
|
||
}
|
||
|
||
mail, err := mailDao.FindOne(baseCtx, func(cols *dao.MailColumns) interface{} {
|
||
return bson.M{cols.Receiver: 2}
|
||
})
|
||
if err != nil {
|
||
log.Fatalf("failed to find a row of data from mongo database: %v", err)
|
||
}
|
||
|
||
log.Printf("%+v", mail)
|
||
}
|
||
```
|
||
|
||
运行结果:
|
||
|
||
```bash
|
||
2023/02/17 16:05:31 &{ID:ObjectID("63ef354a4ddc485f0d9c5ea3") Title:mongo-dao-generator introduction Content:the mongo-dao-generator is a tool for automatically generating MongoDB Data Access Object. Sender:1 Receiver:2 Status:1 SendTime:1676621130323}
|
||
```
|