# 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} ```