mongoctl工具
This commit is contained in:
parent
94ad9f9835
commit
81a0e50bca
|
@ -0,0 +1,3 @@
|
||||||
|
.idea/
|
||||||
|
*/.DS_Store
|
||||||
|
.vscode
|
|
@ -0,0 +1,21 @@
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2022 dobyte
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
|
@ -0,0 +1,483 @@
|
||||||
|
# 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}
|
||||||
|
```
|
|
@ -0,0 +1,51 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type counter struct {
|
||||||
|
opts *options
|
||||||
|
modelName string
|
||||||
|
daoClassName string
|
||||||
|
daoVariableName string
|
||||||
|
daoPkgPath string
|
||||||
|
daoPkgName string
|
||||||
|
daoOutputDir string
|
||||||
|
daoOutputFile string
|
||||||
|
daoPrefixName string
|
||||||
|
collectionName string
|
||||||
|
}
|
||||||
|
|
||||||
|
func newCounter(opts *options) *counter {
|
||||||
|
c := &counter{}
|
||||||
|
c.opts = opts
|
||||||
|
c.modelName = toPascalCase(opts.counterName)
|
||||||
|
c.daoClassName = toPascalCase(c.modelName)
|
||||||
|
c.daoVariableName = toCamelCase(c.modelName)
|
||||||
|
c.daoOutputFile = fmt.Sprintf("%s.go", toFileName(c.modelName, c.opts.fileNameStyle))
|
||||||
|
c.collectionName = toUnderscoreCase(c.modelName)
|
||||||
|
|
||||||
|
dir := strings.TrimSuffix(opts.daoDir, "/")
|
||||||
|
|
||||||
|
if opts.subPkgEnable {
|
||||||
|
c.daoOutputDir = dir + "/" + toPackagePath(c.modelName, c.opts.subPkgStyle)
|
||||||
|
} else {
|
||||||
|
c.daoOutputDir = dir
|
||||||
|
c.daoPrefixName = toPascalCase(c.modelName)
|
||||||
|
}
|
||||||
|
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *counter) setDaoPkgPath(path string) {
|
||||||
|
if c.opts.subPkgEnable {
|
||||||
|
c.daoPkgPath = path + "/" + toPackagePath(c.modelName, c.opts.subPkgStyle)
|
||||||
|
} else {
|
||||||
|
c.daoPkgPath = path
|
||||||
|
}
|
||||||
|
|
||||||
|
c.daoPkgName = toPackageName(filepath.Base(c.daoPkgPath))
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
package dao
|
||||||
|
|
||||||
|
import (
|
||||||
|
"go.mongodb.org/mongo-driver/mongo"
|
||||||
|
"mongo.games.com/mongoctl/example/dao/internal"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Counter struct {
|
||||||
|
*internal.Counter
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewCounter(db *mongo.Database) *Counter {
|
||||||
|
return &Counter{Counter: internal.NewCounter(db)}
|
||||||
|
}
|
|
@ -0,0 +1,76 @@
|
||||||
|
// --------------------------------------------------------------------------------------------------
|
||||||
|
// 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"
|
||||||
|
"go.mongodb.org/mongo-driver/bson"
|
||||||
|
"go.mongodb.org/mongo-driver/mongo"
|
||||||
|
"go.mongodb.org/mongo-driver/mongo/options"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Counter struct {
|
||||||
|
Columns *CounterColumns
|
||||||
|
Database *mongo.Database
|
||||||
|
Collection *mongo.Collection
|
||||||
|
}
|
||||||
|
|
||||||
|
type CounterModel struct {
|
||||||
|
ID string `bson:"_id"`
|
||||||
|
Value int64 `bson:"value"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type CounterColumns struct {
|
||||||
|
ID string
|
||||||
|
Value string
|
||||||
|
}
|
||||||
|
|
||||||
|
var counterColumns = &CounterColumns{
|
||||||
|
ID: "_id",
|
||||||
|
Value: "value",
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewCounter(db *mongo.Database) *Counter {
|
||||||
|
return &Counter{
|
||||||
|
Columns: counterColumns,
|
||||||
|
Database: db,
|
||||||
|
Collection: db.Collection("counter"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Incr 自增值
|
||||||
|
func (dao *Counter) Incr(ctx context.Context, key string, incr ...int) (int64, error) {
|
||||||
|
var (
|
||||||
|
upsert = true
|
||||||
|
returnDocument = options.After
|
||||||
|
counter = &CounterModel{}
|
||||||
|
value = 1
|
||||||
|
)
|
||||||
|
|
||||||
|
if len(incr) > 0 {
|
||||||
|
if incr[0] == 0 {
|
||||||
|
return 0, errors.New("invalid increment value")
|
||||||
|
}
|
||||||
|
value = incr[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
rst := dao.Collection.FindOneAndUpdate(ctx, bson.M{
|
||||||
|
dao.Columns.ID: key,
|
||||||
|
}, bson.M{"$inc": bson.M{
|
||||||
|
dao.Columns.Value: value,
|
||||||
|
}}, &options.FindOneAndUpdateOptions{
|
||||||
|
Upsert: &upsert,
|
||||||
|
ReturnDocument: &returnDocument,
|
||||||
|
})
|
||||||
|
|
||||||
|
if err := rst.Decode(counter); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return counter.Value, nil
|
||||||
|
}
|
|
@ -0,0 +1,290 @@
|
||||||
|
// --------------------------------------------------------------------------------------------
|
||||||
|
// 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"
|
||||||
|
"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"
|
||||||
|
modelpkg "mongo.games.com/mongoctl/example/model"
|
||||||
|
"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 *modelpkg.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 []*modelpkg.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) (*modelpkg.Mail, error) {
|
||||||
|
var (
|
||||||
|
opts *options.FindOneOptions
|
||||||
|
model = &modelpkg.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) (*modelpkg.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) ([]*modelpkg.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([]*modelpkg.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 *modelpkg.Mail) error {
|
||||||
|
if model.ID.IsZero() {
|
||||||
|
model.ID = primitive.NewObjectID()
|
||||||
|
}
|
||||||
|
|
||||||
|
if model.SendTime == 0 {
|
||||||
|
model.SendTime = primitive.NewDateTimeFromTime(time.Now())
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -0,0 +1,330 @@
|
||||||
|
// --------------------------------------------------------------------------------------------
|
||||||
|
// 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"
|
||||||
|
"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"
|
||||||
|
modelpkg "mongo.games.com/mongoctl/example/model"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type UserFilterFunc func(cols *UserColumns) interface{}
|
||||||
|
type UserUpdateFunc func(cols *UserColumns) interface{}
|
||||||
|
type UserPipelineFunc func(cols *UserColumns) interface{}
|
||||||
|
type UserCountOptionsFunc func(cols *UserColumns) *options.CountOptions
|
||||||
|
type UserAggregateOptionsFunc func(cols *UserColumns) *options.AggregateOptions
|
||||||
|
type UserFindOneOptionsFunc func(cols *UserColumns) *options.FindOneOptions
|
||||||
|
type UserFindManyOptionsFunc func(cols *UserColumns) *options.FindOptions
|
||||||
|
type UserUpdateOptionsFunc func(cols *UserColumns) *options.UpdateOptions
|
||||||
|
type UserDeleteOptionsFunc func(cols *UserColumns) *options.DeleteOptions
|
||||||
|
type UserInsertOneOptionsFunc func(cols *UserColumns) *options.InsertOneOptions
|
||||||
|
type UserInsertManyOptionsFunc func(cols *UserColumns) *options.InsertManyOptions
|
||||||
|
|
||||||
|
type User struct {
|
||||||
|
Columns *UserColumns
|
||||||
|
Database *mongo.Database
|
||||||
|
Collection *mongo.Collection
|
||||||
|
}
|
||||||
|
|
||||||
|
type UserColumns struct {
|
||||||
|
ID string
|
||||||
|
UID string // 用户ID
|
||||||
|
Account string // 用户账号
|
||||||
|
Password string // 用户密码
|
||||||
|
Salt string // 密码
|
||||||
|
Mobile string // 用户手机
|
||||||
|
Email string // 用户邮箱
|
||||||
|
Nickname string // 用户昵称
|
||||||
|
Signature string // 用户签名
|
||||||
|
Gender string // 用户性别
|
||||||
|
Level string // 用户等级
|
||||||
|
Experience string // 用户经验
|
||||||
|
Coin string // 用户金币
|
||||||
|
Type string // 用户类型
|
||||||
|
Status string // 用户状态
|
||||||
|
DeviceID string // 设备ID
|
||||||
|
ThirdPlatforms string // 第三方平台
|
||||||
|
RegisterIP string // 注册IP
|
||||||
|
RegisterTime string // 注册时间
|
||||||
|
LastLoginIP string // 最近登录IP
|
||||||
|
LastLoginTime string // 最近登录时间
|
||||||
|
}
|
||||||
|
|
||||||
|
var userColumns = &UserColumns{
|
||||||
|
ID: "_id",
|
||||||
|
UID: "uid", // 用户ID
|
||||||
|
Account: "account", // 用户账号
|
||||||
|
Password: "password", // 用户密码
|
||||||
|
Salt: "salt", // 密码
|
||||||
|
Mobile: "mobile", // 用户手机
|
||||||
|
Email: "email", // 用户邮箱
|
||||||
|
Nickname: "nickname", // 用户昵称
|
||||||
|
Signature: "signature", // 用户签名
|
||||||
|
Gender: "gender", // 用户性别
|
||||||
|
Level: "level", // 用户等级
|
||||||
|
Experience: "experience", // 用户经验
|
||||||
|
Coin: "coin", // 用户金币
|
||||||
|
Type: "type", // 用户类型
|
||||||
|
Status: "status", // 用户状态
|
||||||
|
DeviceID: "device_id", // 设备ID
|
||||||
|
ThirdPlatforms: "third_platforms", // 第三方平台
|
||||||
|
RegisterIP: "register_ip", // 注册IP
|
||||||
|
RegisterTime: "register_time", // 注册时间
|
||||||
|
LastLoginIP: "last_login_ip", // 最近登录IP
|
||||||
|
LastLoginTime: "last_login_time", // 最近登录时间
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewUser(db *mongo.Database) *User {
|
||||||
|
return &User{
|
||||||
|
Columns: userColumns,
|
||||||
|
Database: db,
|
||||||
|
Collection: db.Collection("user"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Count returns the number of documents in the collection.
|
||||||
|
func (dao *User) Count(ctx context.Context, filterFunc UserFilterFunc, optionsFunc ...UserCountOptionsFunc) (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 *User) Aggregate(ctx context.Context, pipelineFunc UserPipelineFunc, optionsFunc ...UserAggregateOptionsFunc) (*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 *User) InsertOne(ctx context.Context, model *modelpkg.User, optionsFunc ...UserInsertOneOptionsFunc) (*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 *User) InsertMany(ctx context.Context, models []*modelpkg.User, optionsFunc ...UserInsertManyOptionsFunc) (*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 *User) UpdateOne(ctx context.Context, filterFunc UserFilterFunc, updateFunc UserUpdateFunc, optionsFunc ...UserUpdateOptionsFunc) (*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 *User) UpdateOneByID(ctx context.Context, id string, updateFunc UserUpdateFunc, optionsFunc ...UserUpdateOptionsFunc) (*mongo.UpdateResult, error) {
|
||||||
|
objectID, err := primitive.ObjectIDFromHex(id)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return dao.UpdateOne(ctx, func(cols *UserColumns) interface{} {
|
||||||
|
return bson.M{"_id": objectID}
|
||||||
|
}, updateFunc, optionsFunc...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateMany executes an update command to update documents in the collection.
|
||||||
|
func (dao *User) UpdateMany(ctx context.Context, filterFunc UserFilterFunc, updateFunc UserUpdateFunc, optionsFunc ...UserUpdateOptionsFunc) (*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 *User) FindOne(ctx context.Context, filterFunc UserFilterFunc, optionsFunc ...UserFindOneOptionsFunc) (*modelpkg.User, error) {
|
||||||
|
var (
|
||||||
|
opts *options.FindOneOptions
|
||||||
|
model = &modelpkg.User{}
|
||||||
|
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 *User) FindOneByID(ctx context.Context, id string, optionsFunc ...UserFindOneOptionsFunc) (*modelpkg.User, error) {
|
||||||
|
objectID, err := primitive.ObjectIDFromHex(id)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return dao.FindOne(ctx, func(cols *UserColumns) interface{} {
|
||||||
|
return bson.M{"_id": objectID}
|
||||||
|
}, optionsFunc...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// FindMany executes a find command and returns many models the matching documents in the collection.
|
||||||
|
func (dao *User) FindMany(ctx context.Context, filterFunc UserFilterFunc, optionsFunc ...UserFindManyOptionsFunc) ([]*modelpkg.User, 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([]*modelpkg.User, 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 *User) DeleteOne(ctx context.Context, filterFunc UserFilterFunc, optionsFunc ...UserDeleteOptionsFunc) (*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 *User) DeleteOneByID(ctx context.Context, id string, optionsFunc ...UserDeleteOptionsFunc) (*mongo.DeleteResult, error) {
|
||||||
|
objectID, err := primitive.ObjectIDFromHex(id)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return dao.DeleteOne(ctx, func(cols *UserColumns) interface{} {
|
||||||
|
return bson.M{"_id": objectID}
|
||||||
|
}, optionsFunc...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteMany executes a delete command to delete documents from the collection.
|
||||||
|
func (dao *User) DeleteMany(ctx context.Context, filterFunc UserFilterFunc, optionsFunc ...UserDeleteOptionsFunc) (*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 *User) autofill(ctx context.Context, model *modelpkg.User) error {
|
||||||
|
if model.ID.IsZero() {
|
||||||
|
model.ID = primitive.NewObjectID()
|
||||||
|
}
|
||||||
|
|
||||||
|
if model.UID == 0 {
|
||||||
|
if id, err := NewCounter(dao.Database).Incr(ctx, "uid"); err != nil {
|
||||||
|
return err
|
||||||
|
} else {
|
||||||
|
model.UID = int32(id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if model.RegisterTime == 0 {
|
||||||
|
model.RegisterTime = primitive.NewDateTimeFromTime(time.Now())
|
||||||
|
}
|
||||||
|
|
||||||
|
if model.LastLoginTime == 0 {
|
||||||
|
model.LastLoginTime = primitive.NewDateTimeFromTime(time.Now())
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
package dao
|
||||||
|
|
||||||
|
import (
|
||||||
|
"go.mongodb.org/mongo-driver/mongo"
|
||||||
|
"mongo.games.com/mongoctl/example/dao/internal"
|
||||||
|
)
|
||||||
|
|
||||||
|
type MailColumns = internal.MailColumns
|
||||||
|
|
||||||
|
type Mail struct {
|
||||||
|
*internal.Mail
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewMail(db *mongo.Database, c *mongo.Collection) *Mail {
|
||||||
|
v := internal.NewMail(nil)
|
||||||
|
v.Database = db
|
||||||
|
v.Collection = c
|
||||||
|
panic("创建索引")
|
||||||
|
//c.Indexes().CreateOne()
|
||||||
|
//c.Indexes().CreateMany()
|
||||||
|
return &Mail{Mail: v}
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
package dao
|
||||||
|
|
||||||
|
import (
|
||||||
|
"go.mongodb.org/mongo-driver/mongo"
|
||||||
|
"mongo.games.com/mongoctl/example/dao/internal"
|
||||||
|
)
|
||||||
|
|
||||||
|
type UserColumns = internal.UserColumns
|
||||||
|
|
||||||
|
type User struct {
|
||||||
|
*internal.User
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewUser(db *mongo.Database, c *mongo.Collection) *User {
|
||||||
|
v := internal.NewUser(nil)
|
||||||
|
v.Database = db
|
||||||
|
v.Collection = c
|
||||||
|
panic("创建索引")
|
||||||
|
//c.Indexes().CreateOne()
|
||||||
|
//c.Indexes().CreateMany()
|
||||||
|
return &User{User: v}
|
||||||
|
}
|
|
@ -0,0 +1,62 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"log"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"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"
|
||||||
|
|
||||||
|
"mongo.games.com/mongoctl/example/dao"
|
||||||
|
"mongo.games.com/mongoctl/example/model"
|
||||||
|
)
|
||||||
|
|
||||||
|
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, db.Collection("mail"))
|
||||||
|
|
||||||
|
_, 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)
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
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"` // 发送时间
|
||||||
|
}
|
|
@ -0,0 +1,61 @@
|
||||||
|
package model
|
||||||
|
|
||||||
|
import "go.mongodb.org/mongo-driver/bson/primitive"
|
||||||
|
|
||||||
|
type Gender int
|
||||||
|
|
||||||
|
const (
|
||||||
|
GenderUnknown Gender = iota // 未知
|
||||||
|
GenderMale // 男性
|
||||||
|
GenderFemale // 女性
|
||||||
|
)
|
||||||
|
|
||||||
|
// Type 用户类型
|
||||||
|
type Type int
|
||||||
|
|
||||||
|
const (
|
||||||
|
TypeRobot Type = 0 // 机器人用户
|
||||||
|
TypeGuest Type = 1 // 游客用户
|
||||||
|
TypeGeneral Type = 2 // 普通用户
|
||||||
|
TypeSystem Type = 3 // 系统用户
|
||||||
|
)
|
||||||
|
|
||||||
|
// Status 用户状态
|
||||||
|
type Status int
|
||||||
|
|
||||||
|
const (
|
||||||
|
StatusNormal Status = iota // 正常
|
||||||
|
StatusForbidden // 封禁
|
||||||
|
)
|
||||||
|
|
||||||
|
//go:generate mongoctl -model-dir=. -model-names=User -dao-dir=../dao/
|
||||||
|
type User struct {
|
||||||
|
ID primitive.ObjectID `bson:"_id" gen:"autoFill"`
|
||||||
|
UID int32 `bson:"uid" gen:"autoIncr:uid"` // 用户ID
|
||||||
|
Account string `bson:"account"` // 用户账号
|
||||||
|
Password string `bson:"password"` // 用户密码
|
||||||
|
Salt string `bson:"salt"` // 密码
|
||||||
|
Mobile string `bson:"mobile"` // 用户手机
|
||||||
|
Email string `bson:"email"` // 用户邮箱
|
||||||
|
Nickname string `bson:"nickname"` // 用户昵称
|
||||||
|
Signature string `bson:"signature"` // 用户签名
|
||||||
|
Gender Gender `bson:"gender"` // 用户性别
|
||||||
|
Level int `bson:"level"` // 用户等级
|
||||||
|
Experience int `bson:"experience"` // 用户经验
|
||||||
|
Coin int `bson:"coin"` // 用户金币
|
||||||
|
Type Type `bson:"type"` // 用户类型
|
||||||
|
Status Status `bson:"status"` // 用户状态
|
||||||
|
DeviceID string `bson:"device_id"` // 设备ID
|
||||||
|
ThirdPlatforms ThirdPlatforms `bson:"third_platforms"` // 第三方平台
|
||||||
|
RegisterIP string `bson:"register_ip"` // 注册IP
|
||||||
|
RegisterTime primitive.DateTime `bson:"register_time" gen:"autoFill"` // 注册时间
|
||||||
|
LastLoginIP string `bson:"last_login_ip"` // 最近登录IP
|
||||||
|
LastLoginTime primitive.DateTime `bson:"last_login_time" gen:"autoFill"` // 最近登录时间
|
||||||
|
}
|
||||||
|
|
||||||
|
// ThirdPlatforms 第三方平台
|
||||||
|
type ThirdPlatforms struct {
|
||||||
|
Wechat string `bson:"wechat"` // 微信登录openid
|
||||||
|
Google string `bson:"google"` // 谷歌登录userid
|
||||||
|
Facebook string `bson:"facebook"` // 脸书登录userid
|
||||||
|
}
|
|
@ -0,0 +1,393 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"go/ast"
|
||||||
|
"go/token"
|
||||||
|
"golang.org/x/tools/go/packages"
|
||||||
|
"log"
|
||||||
|
"mongo.games.com/mongoctl/template"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"reflect"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
symbolBacktick = "`"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
symbolBacktickKey = "SymbolBacktick"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
varPackagesKey = "VarPackages"
|
||||||
|
varModelClassNameKey = "VarModelClassName"
|
||||||
|
varModelPackageNameKey = "VarModelPackageName"
|
||||||
|
varModelPackagePathKey = "VarModelPackagePath"
|
||||||
|
varModelVariableNameKey = "VarModelVariableName"
|
||||||
|
varModelColumnsDefineKey = "VarModelColumnsDefine"
|
||||||
|
varModelColumnsInstanceKey = "VarModelColumnsInstance"
|
||||||
|
varDaoClassNameKey = "VarDaoClassName"
|
||||||
|
varDaoVariableNameKey = "VarDaoVariableName"
|
||||||
|
varDaoPackageNameKey = "VarDaoPackageName"
|
||||||
|
varDaoPackagePathKey = "VarDaoPackagePath"
|
||||||
|
varDaoPrefixNameKey = "VarDaoPrefixName"
|
||||||
|
varCollectionNameKey = "VarCollectionName"
|
||||||
|
varAutofillCodeKey = "VarAutofillCode"
|
||||||
|
)
|
||||||
|
|
||||||
|
const defaultCounterName = "Counter"
|
||||||
|
|
||||||
|
type options struct {
|
||||||
|
modelDir string //
|
||||||
|
modelPkgPath string //
|
||||||
|
modelPkgAlias string //
|
||||||
|
modelNames []string //
|
||||||
|
daoDir string
|
||||||
|
daoPkgPath string
|
||||||
|
subPkgEnable bool
|
||||||
|
subPkgStyle style
|
||||||
|
counterName string
|
||||||
|
fileNameStyle style
|
||||||
|
}
|
||||||
|
|
||||||
|
type generator struct {
|
||||||
|
opts *options
|
||||||
|
counter *counter
|
||||||
|
modelNames map[string]struct{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func newGenerator(opts *options) *generator {
|
||||||
|
modelNames := make(map[string]struct{}, len(opts.modelNames))
|
||||||
|
for _, modelName := range opts.modelNames {
|
||||||
|
if isExportable(modelName) { // 是否导出字段
|
||||||
|
modelNames[modelName] = struct{}{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(modelNames) == 0 {
|
||||||
|
log.Fatalf("error: %d model type names found", len(modelNames))
|
||||||
|
}
|
||||||
|
|
||||||
|
if opts.counterName == "" {
|
||||||
|
opts.counterName = defaultCounterName
|
||||||
|
}
|
||||||
|
|
||||||
|
return &generator{
|
||||||
|
opts: opts,
|
||||||
|
counter: newCounter(opts),
|
||||||
|
modelNames: modelNames,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *generator) makeDao() {
|
||||||
|
models := g.parseModels()
|
||||||
|
|
||||||
|
for _, m := range models {
|
||||||
|
g.makeModelInternalDao(m)
|
||||||
|
|
||||||
|
g.makeModelExternalDao(m)
|
||||||
|
|
||||||
|
fmt.Printf("%s's dao file generated successfully\n", m.modelName)
|
||||||
|
|
||||||
|
if !m.isDependCounter {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
g.makeCounterInternalDao()
|
||||||
|
|
||||||
|
g.makeCounterExternalDao()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// generate an internal dao file based on model
|
||||||
|
func (g *generator) makeModelInternalDao(m *model) {
|
||||||
|
replaces := make(map[string]string)
|
||||||
|
replaces[varModelClassNameKey] = m.modelClassName
|
||||||
|
replaces[varModelPackageNameKey] = m.modelPkgName
|
||||||
|
replaces[varModelPackagePathKey] = m.modelPkgPath
|
||||||
|
replaces[varModelVariableNameKey] = m.modelVariableName
|
||||||
|
replaces[varDaoPrefixNameKey] = m.daoPrefixName
|
||||||
|
replaces[varDaoClassNameKey] = m.daoClassName
|
||||||
|
replaces[varDaoVariableNameKey] = m.daoVariableName
|
||||||
|
replaces[varCollectionNameKey] = m.collectionName
|
||||||
|
replaces[varModelColumnsDefineKey] = m.modelColumnsDefined()
|
||||||
|
replaces[varModelColumnsInstanceKey] = m.modelColumnsInstance()
|
||||||
|
replaces[varAutofillCodeKey] = m.autoFillCode()
|
||||||
|
replaces[varPackagesKey] = m.packages()
|
||||||
|
|
||||||
|
file := m.daoOutputDir + "/internal/" + m.daoOutputFile
|
||||||
|
|
||||||
|
err := doWrite(file, template.InternalTemplate, replaces)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// generate an external dao file based on model
|
||||||
|
func (g *generator) makeModelExternalDao(m *model) {
|
||||||
|
file := m.daoOutputDir + "/" + m.daoOutputFile
|
||||||
|
|
||||||
|
_, err := os.Stat(file)
|
||||||
|
if err != nil {
|
||||||
|
switch {
|
||||||
|
case os.IsNotExist(err):
|
||||||
|
// ignore
|
||||||
|
case os.IsExist(err):
|
||||||
|
return
|
||||||
|
default:
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
replaces := make(map[string]string)
|
||||||
|
replaces[varDaoClassNameKey] = m.daoClassName
|
||||||
|
replaces[varDaoPrefixNameKey] = m.daoPrefixName
|
||||||
|
replaces[varDaoPackageNameKey] = m.daoPkgName
|
||||||
|
replaces[varDaoPackagePathKey] = m.daoPkgPath
|
||||||
|
|
||||||
|
err = doWrite(file, template.ExternalTemplate, replaces)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// generate an internal dao file based on counter model
|
||||||
|
func (g *generator) makeCounterInternalDao() {
|
||||||
|
replaces := make(map[string]string)
|
||||||
|
replaces[varDaoClassNameKey] = g.counter.daoClassName
|
||||||
|
replaces[varDaoPrefixNameKey] = g.counter.daoPrefixName
|
||||||
|
replaces[varDaoVariableNameKey] = g.counter.daoVariableName
|
||||||
|
replaces[varCollectionNameKey] = g.counter.collectionName
|
||||||
|
replaces[symbolBacktickKey] = symbolBacktick
|
||||||
|
|
||||||
|
file := g.counter.daoOutputDir + "/internal/" + g.counter.daoOutputFile
|
||||||
|
|
||||||
|
err := doWrite(file, template.CounterInternalTemplate, replaces)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// generate an external dao file based on counter model
|
||||||
|
func (g *generator) makeCounterExternalDao() {
|
||||||
|
file := g.counter.daoOutputDir + "/" + g.counter.daoOutputFile
|
||||||
|
|
||||||
|
_, err := os.Stat(file)
|
||||||
|
if err != nil {
|
||||||
|
switch {
|
||||||
|
case os.IsNotExist(err):
|
||||||
|
// ignore
|
||||||
|
case os.IsExist(err):
|
||||||
|
return
|
||||||
|
default:
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
replaces := make(map[string]string)
|
||||||
|
replaces[varDaoClassNameKey] = g.counter.daoClassName
|
||||||
|
replaces[varDaoPackageNameKey] = g.counter.daoPkgName
|
||||||
|
replaces[varDaoPackagePathKey] = g.counter.daoPkgPath
|
||||||
|
|
||||||
|
err = doWrite(file, template.CounterExternalTemplate, replaces)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse multiple models from the go file
|
||||||
|
func (g *generator) parseModels() []*model {
|
||||||
|
var (
|
||||||
|
pkg = g.loadPackage()
|
||||||
|
models = make([]*model, 0, len(pkg.Syntax))
|
||||||
|
daoPkgPath = g.opts.daoPkgPath
|
||||||
|
modelPkgPath = g.opts.modelPkgPath
|
||||||
|
modelPkgName = g.opts.modelPkgAlias
|
||||||
|
)
|
||||||
|
|
||||||
|
if g.opts.daoPkgPath == "" && pkg.Module != nil {
|
||||||
|
outPath, err := filepath.Abs(g.opts.daoDir)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
daoPkgPath = pkg.Module.Path + outPath[len(pkg.Module.Dir):]
|
||||||
|
}
|
||||||
|
|
||||||
|
daoPkgPath = strings.ReplaceAll(daoPkgPath, `\`, `/`)
|
||||||
|
|
||||||
|
g.counter.setDaoPkgPath(daoPkgPath)
|
||||||
|
|
||||||
|
for _, file := range pkg.Syntax {
|
||||||
|
if g.opts.modelPkgPath == "" && pkg.Module != nil && pkg.Fset != nil {
|
||||||
|
filePath := filepath.Dir(pkg.Fset.Position(file.Package).Filename)
|
||||||
|
modelPkgPath = pkg.Module.Path + filePath[len(pkg.Module.Dir):]
|
||||||
|
}
|
||||||
|
|
||||||
|
modelPkgPath = strings.ReplaceAll(modelPkgPath, `\`, `/`)
|
||||||
|
modelPkgName = file.Name.Name
|
||||||
|
|
||||||
|
ast.Inspect(file, func(node ast.Node) bool {
|
||||||
|
decl, ok := node.(*ast.GenDecl)
|
||||||
|
if !ok || decl.Tok != token.TYPE {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, s := range decl.Specs {
|
||||||
|
spec, ok := s.(*ast.TypeSpec)
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
_, ok = g.modelNames[spec.Name.Name]
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
st, ok := spec.Type.(*ast.StructType)
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
model := newModel(g.opts)
|
||||||
|
model.setModelName(spec.Name.Name)
|
||||||
|
model.setModelPkg(modelPkgName, modelPkgPath)
|
||||||
|
model.setDaoPkgPath(daoPkgPath)
|
||||||
|
|
||||||
|
for _, item := range st.Fields.List {
|
||||||
|
name := item.Names[0].Name
|
||||||
|
|
||||||
|
if !isExportable(name) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
field := &field{name: name, column: name}
|
||||||
|
|
||||||
|
if item.Tag != nil && len(item.Tag.Value) > 2 {
|
||||||
|
runes := []rune(item.Tag.Value)
|
||||||
|
if runes[0] != '`' || runes[len(runes)-1] != '`' {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
tag := reflect.StructTag(runes[1 : len(runes)-1])
|
||||||
|
|
||||||
|
if column := tag.Get("bson"); column != "" {
|
||||||
|
field.column = column
|
||||||
|
}
|
||||||
|
|
||||||
|
val, ok := tag.Lookup("gen")
|
||||||
|
if ok {
|
||||||
|
parts := strings.Split(val, ";")
|
||||||
|
for _, part := range parts {
|
||||||
|
if part == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
switch eles := strings.SplitN(part, ":", 2); eles[0] {
|
||||||
|
case "autoFill":
|
||||||
|
expr, ok := item.Type.(*ast.SelectorExpr)
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
switch fmt.Sprintf("%s.%s", expr.X.(*ast.Ident).Name, expr.Sel.Name) {
|
||||||
|
case "primitive.ObjectID":
|
||||||
|
field.autoFill = objectID
|
||||||
|
model.addImport(pkg3)
|
||||||
|
case "primitive.DateTime":
|
||||||
|
field.autoFill = dateTime
|
||||||
|
model.addImport(pkg1)
|
||||||
|
model.addImport(pkg3)
|
||||||
|
}
|
||||||
|
case "autoIncr":
|
||||||
|
if len(eles) != 2 || eles[1] == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
expr, ok := item.Type.(*ast.Ident)
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
switch expr.Name {
|
||||||
|
case "int", "int8", "int16", "int32", "int64", "uint", "uint8", "uint16", "uint32", "uint64":
|
||||||
|
field.autoFill = autoIncr
|
||||||
|
field.autoIncrFieldName = eles[1]
|
||||||
|
|
||||||
|
if g.opts.subPkgEnable {
|
||||||
|
model.addImport(g.counter.daoPkgPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
switch expr.Name {
|
||||||
|
case "int":
|
||||||
|
field.autoIncrFieldKind = reflect.Int
|
||||||
|
case "int8":
|
||||||
|
field.autoIncrFieldKind = reflect.Int8
|
||||||
|
case "int16":
|
||||||
|
field.autoIncrFieldKind = reflect.Int16
|
||||||
|
case "int32":
|
||||||
|
field.autoIncrFieldKind = reflect.Int32
|
||||||
|
case "int64":
|
||||||
|
field.autoIncrFieldKind = reflect.Int64
|
||||||
|
case "uint":
|
||||||
|
field.autoIncrFieldKind = reflect.Uint
|
||||||
|
case "uint8":
|
||||||
|
field.autoIncrFieldKind = reflect.Uint8
|
||||||
|
case "uint16":
|
||||||
|
field.autoIncrFieldKind = reflect.Uint16
|
||||||
|
case "uint32":
|
||||||
|
field.autoIncrFieldKind = reflect.Uint32
|
||||||
|
case "uint64":
|
||||||
|
field.autoIncrFieldKind = reflect.Uint64
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if item.Doc != nil {
|
||||||
|
field.documents = make([]string, 0, len(item.Doc.List))
|
||||||
|
for _, doc := range item.Doc.List {
|
||||||
|
field.documents = append(field.documents, doc.Text)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if item.Comment != nil {
|
||||||
|
field.comment = item.Comment.List[0].Text
|
||||||
|
}
|
||||||
|
|
||||||
|
model.addFields(field)
|
||||||
|
}
|
||||||
|
|
||||||
|
models = append(models, model)
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return models
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *generator) loadPackage() *packages.Package {
|
||||||
|
cfg := &packages.Config{
|
||||||
|
Mode: packages.NeedName | packages.NeedFiles | packages.NeedCompiledGoFiles | packages.NeedImports | packages.NeedTypes | packages.NeedTypesSizes | packages.NeedSyntax | packages.NeedTypesInfo | packages.NeedModule,
|
||||||
|
Tests: false,
|
||||||
|
}
|
||||||
|
pkgs, err := packages.Load(cfg, g.opts.modelDir)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(pkgs) != 1 {
|
||||||
|
log.Fatalf("error: %d packages found", len(pkgs))
|
||||||
|
}
|
||||||
|
|
||||||
|
return pkgs[0]
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
module mongo.games.com/mongoctl
|
||||||
|
|
||||||
|
go 1.22.5
|
||||||
|
|
||||||
|
require (
|
||||||
|
go.mongodb.org/mongo-driver v1.17.1
|
||||||
|
golang.org/x/tools v0.26.0
|
||||||
|
)
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/golang/snappy v0.0.4 // indirect
|
||||||
|
github.com/klauspost/compress v1.13.6 // indirect
|
||||||
|
github.com/montanaflynn/stats v0.7.1 // indirect
|
||||||
|
github.com/xdg-go/pbkdf2 v1.0.0 // indirect
|
||||||
|
github.com/xdg-go/scram v1.1.2 // indirect
|
||||||
|
github.com/xdg-go/stringprep v1.0.4 // indirect
|
||||||
|
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // indirect
|
||||||
|
golang.org/x/crypto v0.26.0 // indirect
|
||||||
|
golang.org/x/mod v0.21.0 // indirect
|
||||||
|
golang.org/x/sync v0.8.0 // indirect
|
||||||
|
golang.org/x/text v0.17.0 // indirect
|
||||||
|
)
|
|
@ -0,0 +1,54 @@
|
||||||
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
|
||||||
|
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||||
|
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||||
|
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||||
|
github.com/klauspost/compress v1.13.6 h1:P76CopJELS0TiO2mebmnzgWaajssP/EszplttgQxcgc=
|
||||||
|
github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
|
||||||
|
github.com/montanaflynn/stats v0.7.1 h1:etflOAAHORrCC44V+aR6Ftzort912ZU+YLiSTuV8eaE=
|
||||||
|
github.com/montanaflynn/stats v0.7.1/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow=
|
||||||
|
github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c=
|
||||||
|
github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
|
||||||
|
github.com/xdg-go/scram v1.1.2 h1:FHX5I5B4i4hKRVRBCFRxq1iQRej7WO3hhBuJf+UUySY=
|
||||||
|
github.com/xdg-go/scram v1.1.2/go.mod h1:RT/sEzTbU5y00aCK8UOx6R7YryM0iF1N2MOmC3kKLN4=
|
||||||
|
github.com/xdg-go/stringprep v1.0.4 h1:XLI/Ng3O1Atzq0oBs3TWm+5ZVgkq2aqdlvP9JtoZ6c8=
|
||||||
|
github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM=
|
||||||
|
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 h1:ilQV1hzziu+LLM3zUTJ0trRztfwgjqKnBWNtSRkbmwM=
|
||||||
|
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78/go.mod h1:aL8wCCfTfSfmXjznFBSZNN13rSJjlIOI1fUNAtF7rmI=
|
||||||
|
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||||
|
go.mongodb.org/mongo-driver v1.17.1 h1:Wic5cJIwJgSpBhe3lx3+/RybR5PiYRMpVFgO7cOHyIM=
|
||||||
|
go.mongodb.org/mongo-driver v1.17.1/go.mod h1:wwWm/+BuOddhcq3n68LKRmgk2wXzmF6s0SFOa0GINL4=
|
||||||
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
|
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
|
golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw=
|
||||||
|
golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54=
|
||||||
|
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||||
|
golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0=
|
||||||
|
golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
|
||||||
|
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||||
|
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||||
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
|
||||||
|
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||||
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
|
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||||
|
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
|
||||||
|
golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc=
|
||||||
|
golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
|
||||||
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
|
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||||
|
golang.org/x/tools v0.26.0 h1:v/60pFQmzmT9ExmjDv2gGIfi3OqfKoEP6I5+umXlbnQ=
|
||||||
|
golang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0=
|
||||||
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
|
@ -0,0 +1,36 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestModule(t *testing.T) {
|
||||||
|
m := newModel(&options{
|
||||||
|
modelDir: "./model",
|
||||||
|
modelPkgPath: "./modelpkgpath",
|
||||||
|
modelPkgAlias: "test",
|
||||||
|
modelNames: []string{"names"},
|
||||||
|
daoDir: "./dao",
|
||||||
|
daoPkgPath: "./daopkgpath",
|
||||||
|
subPkgEnable: false,
|
||||||
|
subPkgStyle: lowerCase,
|
||||||
|
counterName: "",
|
||||||
|
fileNameStyle: lowerCase,
|
||||||
|
})
|
||||||
|
|
||||||
|
m.setModelName("mymodel")
|
||||||
|
m.setModelPkg("mypkg", "mypath")
|
||||||
|
m.setDaoPkgPath("daopath")
|
||||||
|
|
||||||
|
fmt.Println(m.packages())
|
||||||
|
fmt.Println(m.modelColumnsInstance())
|
||||||
|
fmt.Println(m.modelColumnsDefined())
|
||||||
|
fmt.Println(m.autoFillCode())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestToName(t *testing.T) {
|
||||||
|
|
||||||
|
var f func()
|
||||||
|
f()
|
||||||
|
}
|
|
@ -0,0 +1,66 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
modelDir = flag.String("model-dir", "", "模型所在目录; 必需")
|
||||||
|
modelNames = flag.String("model-names", "", "模型结构体名称; 必需")
|
||||||
|
modelPkgPath = flag.String("model-pkg-path", "", "模型包名; 默认自动生成")
|
||||||
|
modelPkgAlias = flag.String("model-pkg-alias", "", "模型包别名")
|
||||||
|
daoDir = flag.String("dao-dir", "", "生成代码所在目录; 必需")
|
||||||
|
daoPkgPath = flag.String("dao-pkg-path", "", "生成代码所在目录的包名; 默认自动生成")
|
||||||
|
subPkgEnable = flag.Bool("sub-pkg-enable", false, "每个模型创建一个子包; 默认关闭")
|
||||||
|
subPkgStyle = flag.String("sub-pkg-style", "kebab", "模型子包目录名称风格; 选项: kebab | underscore | lower | camel | pascal; 默认是 kebab")
|
||||||
|
counterName = flag.String("counter-name", "", "自增模型名称; 默认是 counter")
|
||||||
|
fileNameStyle = flag.String("file-style", "underscore", "代码文件名称风格; 选项: kebab | underscore | lower | camel | pascal; 默认是 underscore")
|
||||||
|
)
|
||||||
|
|
||||||
|
// Usage is a replacement usage function for the flags package.
|
||||||
|
func usage() {
|
||||||
|
fmt.Fprintf(os.Stderr, "用法 mongoctl:\n")
|
||||||
|
fmt.Fprintf(os.Stderr, "\tmongoctl [flags] -model-dir=. -model-names=T,T -dao-dir=./dao\n")
|
||||||
|
fmt.Fprintf(os.Stderr, "Flags:\n")
|
||||||
|
flag.PrintDefaults()
|
||||||
|
}
|
||||||
|
|
||||||
|
//go:generate mongoctl -type=Mail,User
|
||||||
|
func main() {
|
||||||
|
log.SetFlags(0)
|
||||||
|
log.SetPrefix("mongoctl: ")
|
||||||
|
flag.Usage = usage
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
if len(*modelDir) == 0 {
|
||||||
|
flag.Usage()
|
||||||
|
os.Exit(2)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(*modelNames) == 0 {
|
||||||
|
flag.Usage()
|
||||||
|
os.Exit(2)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(*daoDir) == 0 {
|
||||||
|
flag.Usage()
|
||||||
|
os.Exit(2)
|
||||||
|
}
|
||||||
|
|
||||||
|
newGenerator(&options{
|
||||||
|
daoDir: *daoDir,
|
||||||
|
daoPkgPath: *daoPkgPath,
|
||||||
|
modelDir: *modelDir,
|
||||||
|
modelNames: strings.Split(*modelNames, ","),
|
||||||
|
modelPkgPath: *modelPkgPath,
|
||||||
|
modelPkgAlias: *modelPkgAlias,
|
||||||
|
subPkgEnable: *subPkgEnable,
|
||||||
|
subPkgStyle: style(*subPkgStyle),
|
||||||
|
counterName: *counterName,
|
||||||
|
fileNameStyle: style(*fileNameStyle),
|
||||||
|
}).makeDao()
|
||||||
|
}
|
|
@ -0,0 +1,273 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"path/filepath"
|
||||||
|
"reflect"
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
defaultModelPkgAlias = "modelpkg"
|
||||||
|
defaultModelVariableName = "model"
|
||||||
|
)
|
||||||
|
|
||||||
|
type autoFill int
|
||||||
|
|
||||||
|
const (
|
||||||
|
objectID autoFill = iota + 1 // primitive.NewObjectID()
|
||||||
|
dateTime // primitive.NewDateTimeFromTime(time.Now())
|
||||||
|
autoIncr // auto-increment
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
pkg1 = "time"
|
||||||
|
pkg2 = "context"
|
||||||
|
pkg3 = "go.mongodb.org/mongo-driver/bson/primitive"
|
||||||
|
pkg4 = "go.mongodb.org/mongo-driver/mongo"
|
||||||
|
pkg5 = "go.mongodb.org/mongo-driver/mongo/options"
|
||||||
|
pkg6 = "errors"
|
||||||
|
pkg7 = "go.mongodb.org/mongo-driver/bson"
|
||||||
|
)
|
||||||
|
|
||||||
|
type field struct {
|
||||||
|
name string
|
||||||
|
column string
|
||||||
|
comment string
|
||||||
|
documents []string
|
||||||
|
autoFill autoFill
|
||||||
|
autoIncrFieldName string
|
||||||
|
autoIncrFieldKind reflect.Kind
|
||||||
|
}
|
||||||
|
|
||||||
|
type model struct {
|
||||||
|
opts *options
|
||||||
|
fields []*field
|
||||||
|
imports map[string]string
|
||||||
|
modelName string
|
||||||
|
modelClassName string
|
||||||
|
modelVariableName string
|
||||||
|
modelPkgPath string
|
||||||
|
modelPkgName string
|
||||||
|
daoClassName string
|
||||||
|
daoVariableName string
|
||||||
|
daoPkgPath string
|
||||||
|
daoPkgName string
|
||||||
|
daoOutputDir string
|
||||||
|
daoOutputFile string
|
||||||
|
daoPrefixName string
|
||||||
|
collectionName string
|
||||||
|
fieldNameMaxLen int
|
||||||
|
fieldComplexMaxLen int
|
||||||
|
isDependCounter bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func newModel(opts *options) *model {
|
||||||
|
m := &model{
|
||||||
|
opts: opts,
|
||||||
|
fields: make([]*field, 0),
|
||||||
|
imports: make(map[string]string, 8),
|
||||||
|
}
|
||||||
|
|
||||||
|
m.addImport(pkg2)
|
||||||
|
m.addImport(pkg4)
|
||||||
|
m.addImport(pkg5)
|
||||||
|
m.addImport(pkg6)
|
||||||
|
m.addImport(pkg7)
|
||||||
|
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *model) setModelName(name string) {
|
||||||
|
m.modelName = name
|
||||||
|
m.modelClassName = toPascalCase(m.modelName)
|
||||||
|
m.modelVariableName = toCamelCase(m.modelName)
|
||||||
|
m.daoClassName = toPascalCase(m.modelName)
|
||||||
|
m.daoVariableName = toCamelCase(m.modelName)
|
||||||
|
m.daoOutputFile = fmt.Sprintf("%s.go", toFileName(m.modelName, m.opts.fileNameStyle))
|
||||||
|
m.collectionName = toUnderscoreCase(m.modelName)
|
||||||
|
|
||||||
|
dir := strings.TrimSuffix(m.opts.daoDir, "/")
|
||||||
|
|
||||||
|
if m.opts.subPkgEnable {
|
||||||
|
m.daoOutputDir = dir + "/" + toPackagePath(m.modelName, m.opts.subPkgStyle)
|
||||||
|
} else {
|
||||||
|
m.daoOutputDir = dir
|
||||||
|
m.daoPrefixName = toPascalCase(m.modelName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *model) setModelPkg(name, path string) {
|
||||||
|
m.modelPkgPath = path
|
||||||
|
|
||||||
|
if m.opts.modelPkgAlias != "" {
|
||||||
|
m.modelPkgName = m.opts.modelPkgAlias
|
||||||
|
m.addImport(m.modelPkgPath, m.modelPkgName)
|
||||||
|
} else {
|
||||||
|
m.modelPkgName = name
|
||||||
|
m.addImport(m.modelPkgPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
if m.modelPkgName == defaultModelVariableName {
|
||||||
|
m.modelPkgName = defaultModelPkgAlias
|
||||||
|
m.addImport(m.modelPkgPath, m.modelPkgName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *model) setDaoPkgPath(path string) {
|
||||||
|
if m.opts.subPkgEnable {
|
||||||
|
m.daoPkgPath = path + "/" + toPackagePath(m.modelName, m.opts.subPkgStyle)
|
||||||
|
} else {
|
||||||
|
m.daoPkgPath = path
|
||||||
|
}
|
||||||
|
|
||||||
|
m.daoPkgName = toPackageName(filepath.Base(m.daoPkgPath))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *model) addImport(pkg string, alias ...string) {
|
||||||
|
if len(alias) > 0 {
|
||||||
|
m.imports[pkg] = alias[0]
|
||||||
|
} else {
|
||||||
|
m.imports[pkg] = ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *model) addFields(fields ...*field) {
|
||||||
|
for _, f := range fields {
|
||||||
|
if l := len(f.name); l > m.fieldNameMaxLen {
|
||||||
|
m.fieldNameMaxLen = l
|
||||||
|
}
|
||||||
|
|
||||||
|
if l := len(f.name) + len(f.column) + 5; l > m.fieldComplexMaxLen {
|
||||||
|
m.fieldComplexMaxLen = l
|
||||||
|
}
|
||||||
|
|
||||||
|
if f.autoFill == autoIncr {
|
||||||
|
m.isDependCounter = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m.fields = append(m.fields, fields...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *model) modelColumnsDefined() (str string) {
|
||||||
|
for i, f := range m.fields {
|
||||||
|
str += fmt.Sprintf("\t%s%s%s %s", f.name, strings.Repeat(" ", m.fieldNameMaxLen-len(f.name)+1), "string", f.comment)
|
||||||
|
if i != len(m.fields)-1 {
|
||||||
|
str += "\n"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
str = strings.TrimPrefix(str, "\t")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *model) modelColumnsInstance() (str string) {
|
||||||
|
for i, f := range m.fields {
|
||||||
|
s := fmt.Sprintf("%s:%s\"%s\",", f.name, strings.Repeat(" ", m.fieldNameMaxLen-len(f.name)+1), f.column)
|
||||||
|
s += strings.Repeat(" ", m.fieldComplexMaxLen-len(s)+1) + f.comment
|
||||||
|
str += "\t" + s
|
||||||
|
if i != len(m.fields)-1 {
|
||||||
|
str += "\n"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
str = strings.TrimLeft(str, "\t")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *model) packages() (str string) {
|
||||||
|
packages := make([]string, 0, len(m.imports))
|
||||||
|
for pkg := range m.imports {
|
||||||
|
packages = append(packages, pkg)
|
||||||
|
}
|
||||||
|
|
||||||
|
sort.Slice(packages, func(i, j int) bool {
|
||||||
|
return packages[i] < packages[j]
|
||||||
|
})
|
||||||
|
|
||||||
|
for _, pkg := range packages {
|
||||||
|
if alias := m.imports[pkg]; alias != "" {
|
||||||
|
str += fmt.Sprintf("\t%s \"%s\"\n", alias, pkg)
|
||||||
|
} else {
|
||||||
|
str += fmt.Sprintf("\t\"%s\"\n", pkg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
str = strings.TrimPrefix(str, "\t")
|
||||||
|
str = strings.TrimSuffix(str, "\n")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *model) autoFillCode() (str string) {
|
||||||
|
var (
|
||||||
|
counterName = toPascalCase(m.opts.counterName)
|
||||||
|
counterPkgPrefix string
|
||||||
|
)
|
||||||
|
|
||||||
|
if m.opts.subPkgEnable {
|
||||||
|
counterPkgPrefix = fmt.Sprintf("%s.", toPackageName(counterName))
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, f := range m.fields {
|
||||||
|
if f.autoFill == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if str != "" {
|
||||||
|
str += "\n\n"
|
||||||
|
}
|
||||||
|
|
||||||
|
switch f.autoFill {
|
||||||
|
case objectID:
|
||||||
|
str += fmt.Sprintf("\tif model.%s.IsZero() {\n", f.name)
|
||||||
|
str += fmt.Sprintf("\t\tmodel.%s = primitive.NewObjectID()\n", f.name)
|
||||||
|
str += "\t}"
|
||||||
|
case dateTime:
|
||||||
|
str += fmt.Sprintf("\tif model.%s == 0 {\n", f.name)
|
||||||
|
str += fmt.Sprintf("\t\tmodel.%s = primitive.NewDateTimeFromTime(time.Now())\n", f.name)
|
||||||
|
str += "\t}"
|
||||||
|
case autoIncr:
|
||||||
|
str += fmt.Sprintf("\tif model.%s == 0 {\n", f.name)
|
||||||
|
str += fmt.Sprintf("\t\tif id, err := %sNew%s(dao.Database).Incr(ctx, \"%s\"); err != nil {\n", counterPkgPrefix, counterName, f.autoIncrFieldName)
|
||||||
|
str += "\t\t\treturn err\n"
|
||||||
|
str += "\t\t} else {\n"
|
||||||
|
|
||||||
|
switch f.autoIncrFieldKind {
|
||||||
|
case reflect.Int:
|
||||||
|
str += fmt.Sprintf("\t\t\tmodel.%s = int(id)\n", f.name)
|
||||||
|
case reflect.Int8:
|
||||||
|
str += fmt.Sprintf("\t\t\tmodel.%s = int8(id)\n", f.name)
|
||||||
|
case reflect.Int16:
|
||||||
|
str += fmt.Sprintf("\t\t\tmodel.%s = int16(id)\n", f.name)
|
||||||
|
case reflect.Int32:
|
||||||
|
str += fmt.Sprintf("\t\t\tmodel.%s = int32(id)\n", f.name)
|
||||||
|
case reflect.Int64:
|
||||||
|
str += fmt.Sprintf("\t\t\tmodel.%s = id\n", f.name)
|
||||||
|
case reflect.Uint:
|
||||||
|
str += fmt.Sprintf("\t\t\tmodel.%s = uint(id)\n", f.name)
|
||||||
|
case reflect.Uint8:
|
||||||
|
str += fmt.Sprintf("\t\t\tmodel.%s = uint8(id)\n", f.name)
|
||||||
|
case reflect.Uint16:
|
||||||
|
str += fmt.Sprintf("\t\t\tmodel.%s = uint16(id)\n", f.name)
|
||||||
|
case reflect.Uint32:
|
||||||
|
str += fmt.Sprintf("\t\t\tmodel.%s = uint32(id)\n", f.name)
|
||||||
|
case reflect.Uint64:
|
||||||
|
str += fmt.Sprintf("\t\t\tmodel.%s = uint64(id)\n", f.name)
|
||||||
|
}
|
||||||
|
|
||||||
|
str += "\t\t}\n"
|
||||||
|
str += "\t}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if str != "" {
|
||||||
|
str += "\n\n"
|
||||||
|
}
|
||||||
|
|
||||||
|
str += "\treturn nil"
|
||||||
|
str = strings.TrimPrefix(str, "\t")
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
|
@ -0,0 +1,97 @@
|
||||||
|
package template
|
||||||
|
|
||||||
|
const CounterExternalTemplate = `
|
||||||
|
package ${VarDaoPackageName}
|
||||||
|
|
||||||
|
import (
|
||||||
|
"go.mongodb.org/mongo-driver/mongo"
|
||||||
|
"${VarDaoPackagePath}/internal"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ${VarDaoClassName} struct {
|
||||||
|
*internal.${VarDaoClassName}
|
||||||
|
}
|
||||||
|
|
||||||
|
func New${VarDaoClassName}(db *mongo.Database) *${VarDaoClassName} {
|
||||||
|
return &${VarDaoClassName}{${VarDaoClassName}: internal.New${VarDaoClassName}(db)}
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
const CounterInternalTemplate = `
|
||||||
|
// --------------------------------------------------------------------------------------------------
|
||||||
|
// 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"
|
||||||
|
"go.mongodb.org/mongo-driver/bson"
|
||||||
|
"go.mongodb.org/mongo-driver/mongo"
|
||||||
|
"go.mongodb.org/mongo-driver/mongo/options"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ${VarDaoClassName} struct {
|
||||||
|
Columns *${VarDaoPrefixName}Columns
|
||||||
|
Database *mongo.Database
|
||||||
|
Collection *mongo.Collection
|
||||||
|
}
|
||||||
|
|
||||||
|
type ${VarDaoPrefixName}Model struct {
|
||||||
|
ID string ${SymbolBacktick}bson:"_id"${SymbolBacktick}
|
||||||
|
Value int64 ${SymbolBacktick}bson:"value"${SymbolBacktick}
|
||||||
|
}
|
||||||
|
|
||||||
|
type ${VarDaoPrefixName}Columns struct {
|
||||||
|
ID string
|
||||||
|
Value string
|
||||||
|
}
|
||||||
|
|
||||||
|
var ${VarDaoVariableName}Columns = &${VarDaoPrefixName}Columns{
|
||||||
|
ID: "_id",
|
||||||
|
Value: "value",
|
||||||
|
}
|
||||||
|
|
||||||
|
func New${VarDaoClassName}(db *mongo.Database) *${VarDaoClassName} {
|
||||||
|
return &${VarDaoClassName}{
|
||||||
|
Columns: ${VarDaoVariableName}Columns,
|
||||||
|
Database: db,
|
||||||
|
Collection: db.Collection("${VarCollectionName}"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Incr 自增值
|
||||||
|
func (dao *${VarDaoClassName}) Incr(ctx context.Context, key string, incr ...int) (int64, error) {
|
||||||
|
var (
|
||||||
|
upsert = true
|
||||||
|
returnDocument = options.After
|
||||||
|
counter = &${VarDaoPrefixName}Model{}
|
||||||
|
value = 1
|
||||||
|
)
|
||||||
|
|
||||||
|
if len(incr) > 0 {
|
||||||
|
if incr[0] == 0 {
|
||||||
|
return 0, errors.New("invalid increment value")
|
||||||
|
}
|
||||||
|
value = incr[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
rst := dao.Collection.FindOneAndUpdate(ctx, bson.M{
|
||||||
|
dao.Columns.ID: key,
|
||||||
|
}, bson.M{"$inc": bson.M{
|
||||||
|
dao.Columns.Value: value,
|
||||||
|
}}, &options.FindOneAndUpdateOptions{
|
||||||
|
Upsert: &upsert,
|
||||||
|
ReturnDocument: &returnDocument,
|
||||||
|
})
|
||||||
|
|
||||||
|
if err := rst.Decode(counter); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return counter.Value, nil
|
||||||
|
}
|
||||||
|
`
|
|
@ -0,0 +1,292 @@
|
||||||
|
package template
|
||||||
|
|
||||||
|
const ExternalTemplate = `
|
||||||
|
package ${VarDaoPackageName}
|
||||||
|
|
||||||
|
import (
|
||||||
|
"go.mongodb.org/mongo-driver/mongo"
|
||||||
|
"${VarDaoPackagePath}/internal"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ${VarDaoPrefixName}Columns = internal.${VarDaoPrefixName}Columns
|
||||||
|
|
||||||
|
type ${VarDaoClassName} struct {
|
||||||
|
*internal.${VarDaoClassName}
|
||||||
|
}
|
||||||
|
|
||||||
|
func New${VarDaoClassName}(db *mongo.Database, c *mongo.Collection) *${VarDaoClassName} {
|
||||||
|
v := internal.New${VarDaoClassName}(nil)
|
||||||
|
v.Database = db
|
||||||
|
v.Collection = c
|
||||||
|
panic("创建索引")
|
||||||
|
//c.Indexes().CreateOne()
|
||||||
|
//c.Indexes().CreateMany()
|
||||||
|
return &${VarDaoClassName}{${VarDaoClassName}: v}
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
const InternalTemplate = `
|
||||||
|
// --------------------------------------------------------------------------------------------
|
||||||
|
// 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 (
|
||||||
|
${VarPackages}
|
||||||
|
)
|
||||||
|
|
||||||
|
type ${VarDaoPrefixName}FilterFunc func(cols *${VarDaoPrefixName}Columns) interface{}
|
||||||
|
type ${VarDaoPrefixName}UpdateFunc func(cols *${VarDaoPrefixName}Columns) interface{}
|
||||||
|
type ${VarDaoPrefixName}PipelineFunc func(cols *${VarDaoPrefixName}Columns) interface{}
|
||||||
|
type ${VarDaoPrefixName}CountOptionsFunc func(cols *${VarDaoPrefixName}Columns) *options.CountOptions
|
||||||
|
type ${VarDaoPrefixName}AggregateOptionsFunc func(cols *${VarDaoPrefixName}Columns) *options.AggregateOptions
|
||||||
|
type ${VarDaoPrefixName}FindOneOptionsFunc func(cols *${VarDaoPrefixName}Columns) *options.FindOneOptions
|
||||||
|
type ${VarDaoPrefixName}FindManyOptionsFunc func(cols *${VarDaoPrefixName}Columns) *options.FindOptions
|
||||||
|
type ${VarDaoPrefixName}UpdateOptionsFunc func(cols *${VarDaoPrefixName}Columns) *options.UpdateOptions
|
||||||
|
type ${VarDaoPrefixName}DeleteOptionsFunc func(cols *${VarDaoPrefixName}Columns) *options.DeleteOptions
|
||||||
|
type ${VarDaoPrefixName}InsertOneOptionsFunc func(cols *${VarDaoPrefixName}Columns) *options.InsertOneOptions
|
||||||
|
type ${VarDaoPrefixName}InsertManyOptionsFunc func(cols *${VarDaoPrefixName}Columns) *options.InsertManyOptions
|
||||||
|
|
||||||
|
type ${VarDaoClassName} struct {
|
||||||
|
Columns *${VarDaoPrefixName}Columns
|
||||||
|
Database *mongo.Database
|
||||||
|
Collection *mongo.Collection
|
||||||
|
}
|
||||||
|
|
||||||
|
type ${VarDaoPrefixName}Columns struct {
|
||||||
|
${VarModelColumnsDefine}
|
||||||
|
}
|
||||||
|
|
||||||
|
var ${VarDaoVariableName}Columns = &${VarDaoPrefixName}Columns{
|
||||||
|
${VarModelColumnsInstance}
|
||||||
|
}
|
||||||
|
|
||||||
|
func New${VarDaoClassName}(db *mongo.Database) *${VarDaoClassName} {
|
||||||
|
return &${VarDaoClassName}{
|
||||||
|
Columns: ${VarDaoVariableName}Columns,
|
||||||
|
Database: db,
|
||||||
|
Collection: db.Collection("${VarCollectionName}"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Count returns the number of documents in the collection.
|
||||||
|
func (dao *${VarDaoClassName}) Count(ctx context.Context, filterFunc ${VarDaoPrefixName}FilterFunc, optionsFunc ...${VarDaoPrefixName}CountOptionsFunc) (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 *${VarDaoClassName}) Aggregate(ctx context.Context, pipelineFunc ${VarDaoPrefixName}PipelineFunc, optionsFunc ...${VarDaoPrefixName}AggregateOptionsFunc) (*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 *${VarDaoClassName}) InsertOne(ctx context.Context, model *${VarModelPackageName}.${VarModelClassName}, optionsFunc ...${VarDaoPrefixName}InsertOneOptionsFunc) (*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 *${VarDaoClassName}) InsertMany(ctx context.Context, models []*${VarModelPackageName}.${VarModelClassName}, optionsFunc ...${VarDaoPrefixName}InsertManyOptionsFunc) (*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 *${VarDaoClassName}) UpdateOne(ctx context.Context, filterFunc ${VarDaoPrefixName}FilterFunc, updateFunc ${VarDaoPrefixName}UpdateFunc, optionsFunc ...${VarDaoPrefixName}UpdateOptionsFunc) (*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 *${VarDaoClassName}) UpdateOneByID(ctx context.Context, id string, updateFunc ${VarDaoPrefixName}UpdateFunc, optionsFunc ...${VarDaoPrefixName}UpdateOptionsFunc) (*mongo.UpdateResult, error) {
|
||||||
|
objectID, err := primitive.ObjectIDFromHex(id)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return dao.UpdateOne(ctx, func(cols *${VarDaoPrefixName}Columns) interface{} {
|
||||||
|
return bson.M{"_id": objectID}
|
||||||
|
}, updateFunc, optionsFunc...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateMany executes an update command to update documents in the collection.
|
||||||
|
func (dao *${VarDaoClassName}) UpdateMany(ctx context.Context, filterFunc ${VarDaoPrefixName}FilterFunc, updateFunc ${VarDaoPrefixName}UpdateFunc, optionsFunc ...${VarDaoPrefixName}UpdateOptionsFunc) (*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 *${VarDaoClassName}) FindOne(ctx context.Context, filterFunc ${VarDaoPrefixName}FilterFunc, optionsFunc ...${VarDaoPrefixName}FindOneOptionsFunc) (*${VarModelPackageName}.${VarModelClassName}, error) {
|
||||||
|
var (
|
||||||
|
opts *options.FindOneOptions
|
||||||
|
model = &${VarModelPackageName}.${VarModelClassName}{}
|
||||||
|
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 *${VarDaoClassName}) FindOneByID(ctx context.Context, id string, optionsFunc ...${VarDaoPrefixName}FindOneOptionsFunc) (*${VarModelPackageName}.${VarModelClassName}, error) {
|
||||||
|
objectID, err := primitive.ObjectIDFromHex(id)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return dao.FindOne(ctx, func(cols *${VarDaoPrefixName}Columns) interface{} {
|
||||||
|
return bson.M{"_id": objectID}
|
||||||
|
}, optionsFunc...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// FindMany executes a find command and returns many models the matching documents in the collection.
|
||||||
|
func (dao *${VarDaoClassName}) FindMany(ctx context.Context, filterFunc ${VarDaoPrefixName}FilterFunc, optionsFunc ...${VarDaoPrefixName}FindManyOptionsFunc) ([]*${VarModelPackageName}.${VarModelClassName}, 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([]*${VarModelPackageName}.${VarModelClassName}, 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 *${VarDaoClassName}) DeleteOne(ctx context.Context, filterFunc ${VarDaoPrefixName}FilterFunc, optionsFunc ...${VarDaoPrefixName}DeleteOptionsFunc) (*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 *${VarDaoClassName}) DeleteOneByID(ctx context.Context, id string, optionsFunc ...${VarDaoPrefixName}DeleteOptionsFunc) (*mongo.DeleteResult, error) {
|
||||||
|
objectID, err := primitive.ObjectIDFromHex(id)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return dao.DeleteOne(ctx, func(cols *${VarDaoPrefixName}Columns) interface{} {
|
||||||
|
return bson.M{"_id": objectID}
|
||||||
|
}, optionsFunc...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteMany executes a delete command to delete documents from the collection.
|
||||||
|
func (dao *${VarDaoClassName}) DeleteMany(ctx context.Context, filterFunc ${VarDaoPrefixName}FilterFunc, optionsFunc ...${VarDaoPrefixName}DeleteOptionsFunc) (*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 *${VarDaoClassName}) autofill(ctx context.Context, model *${VarModelPackageName}.${VarModelClassName}) error {
|
||||||
|
${VarAutofillCode}
|
||||||
|
}
|
||||||
|
`
|
|
@ -0,0 +1,160 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
"unicode"
|
||||||
|
"unicode/utf8"
|
||||||
|
)
|
||||||
|
|
||||||
|
type style string
|
||||||
|
|
||||||
|
const (
|
||||||
|
kebabCase style = "kebab" // 全小写中划线
|
||||||
|
underscoreCase style = "underscore" // 小写下划线
|
||||||
|
camelCase style = "camel" // 小写字母开头驼峰
|
||||||
|
pascalCase style = "pascal" // 大写字母开头驼峰
|
||||||
|
lowerCase style = "lower" // 全小写
|
||||||
|
)
|
||||||
|
|
||||||
|
// convert to underscore style, example: UserProfile > user_profile
|
||||||
|
func toUnderscoreCase(s string) string {
|
||||||
|
return toLowerCase(s, 95)
|
||||||
|
}
|
||||||
|
|
||||||
|
// convert to kebab style, example: UserProfile > user-profile
|
||||||
|
func toKebabCase(s string) string {
|
||||||
|
return toLowerCase(s, 45)
|
||||||
|
}
|
||||||
|
|
||||||
|
// convert to camel style, example: user-profile > userProfile
|
||||||
|
func toCamelCase(s string) string {
|
||||||
|
chars := make([]rune, 0, len(s))
|
||||||
|
upper := false
|
||||||
|
first := true
|
||||||
|
|
||||||
|
for i := 0; i < len(s); i++ {
|
||||||
|
switch {
|
||||||
|
case s[i] >= 65 && s[i] <= 90:
|
||||||
|
if first {
|
||||||
|
chars = append(chars, rune(s[i]+32))
|
||||||
|
} else {
|
||||||
|
chars = append(chars, rune(s[i]))
|
||||||
|
}
|
||||||
|
first = false
|
||||||
|
upper = false
|
||||||
|
case s[i] >= 97 && s[i] <= 122:
|
||||||
|
if upper && !first {
|
||||||
|
chars = append(chars, rune(s[i]-32))
|
||||||
|
} else {
|
||||||
|
chars = append(chars, rune(s[i]))
|
||||||
|
}
|
||||||
|
first = false
|
||||||
|
upper = false
|
||||||
|
case s[i] == 45:
|
||||||
|
upper = true
|
||||||
|
case s[i] == 95:
|
||||||
|
upper = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return string(chars)
|
||||||
|
}
|
||||||
|
|
||||||
|
// convert to pascal style, example: user-profile > UserProfile
|
||||||
|
func toPascalCase(s string) string {
|
||||||
|
s = toCamelCase(s)
|
||||||
|
return strings.ToUpper(string(s[0])) + s[1:]
|
||||||
|
}
|
||||||
|
|
||||||
|
func toLowerCase(s string, c rune) string {
|
||||||
|
chars := make([]rune, 0)
|
||||||
|
|
||||||
|
for i := 0; i < len(s); i++ {
|
||||||
|
if s[i] >= 65 && s[i] <= 90 {
|
||||||
|
if i == 0 {
|
||||||
|
chars = append(chars, rune(s[i]+32))
|
||||||
|
} else {
|
||||||
|
chars = append(chars, c, rune(s[i]+32))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
chars = append(chars, rune(s[i]))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return string(chars)
|
||||||
|
}
|
||||||
|
|
||||||
|
func toPackageName(s string) string {
|
||||||
|
chars := make([]rune, 0, len(s))
|
||||||
|
for i := 0; i < len(s); i++ {
|
||||||
|
switch {
|
||||||
|
case s[i] >= 65 && s[i] <= 90:
|
||||||
|
chars = append(chars, rune(s[i]+32))
|
||||||
|
case s[i] >= 97 && s[i] <= 122:
|
||||||
|
chars = append(chars, rune(s[i]))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return string(chars)
|
||||||
|
}
|
||||||
|
|
||||||
|
func toPackagePath(s string, style style) string {
|
||||||
|
switch style {
|
||||||
|
case kebabCase:
|
||||||
|
return toKebabCase(s)
|
||||||
|
case underscoreCase:
|
||||||
|
return toUnderscoreCase(s)
|
||||||
|
case camelCase:
|
||||||
|
return toCamelCase(s)
|
||||||
|
case pascalCase:
|
||||||
|
return toPascalCase(s)
|
||||||
|
case lowerCase:
|
||||||
|
return toPackageName(s)
|
||||||
|
default:
|
||||||
|
return toKebabCase(s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func toFileName(s string, style style) string {
|
||||||
|
switch style {
|
||||||
|
case kebabCase:
|
||||||
|
return toKebabCase(s)
|
||||||
|
case underscoreCase:
|
||||||
|
return toUnderscoreCase(s)
|
||||||
|
case camelCase:
|
||||||
|
return toCamelCase(s)
|
||||||
|
case pascalCase:
|
||||||
|
return toPascalCase(s)
|
||||||
|
case lowerCase:
|
||||||
|
return toPackageName(s)
|
||||||
|
default:
|
||||||
|
return toUnderscoreCase(s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func doWrite(file string, tpl string, replaces map[string]string) error {
|
||||||
|
s := os.Expand(tpl, func(s string) string {
|
||||||
|
switch {
|
||||||
|
case len(s) >= 3 && s[:3] == "Var":
|
||||||
|
return replaces[s]
|
||||||
|
case len(s) >= 6 && s[:6] == "Symbol":
|
||||||
|
return replaces[s]
|
||||||
|
default:
|
||||||
|
return "$" + s
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
if err := os.MkdirAll(filepath.Dir(file), os.ModePerm); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return os.WriteFile(file, []byte(strings.TrimPrefix(s, "\n")), os.ModePerm)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 大写字母开头的字段才是导出的
|
||||||
|
func isExportable(s string) bool {
|
||||||
|
r, _ := utf8.DecodeRuneInString(s)
|
||||||
|
return unicode.IsUpper(r)
|
||||||
|
}
|
Loading…
Reference in New Issue