commit e7038a44e9baee50d0752a319175f01ff0558aba Author: xuthus5 Date: Thu Jun 22 23:14:51 2023 +0800 first commit diff --git a/README.md b/README.md new file mode 100644 index 0000000..30a3959 --- /dev/null +++ b/README.md @@ -0,0 +1,10 @@ +## mdbc + +mdbc: mongodb database connector + +项目命名为mdbc 一个mongodb数据库orm,对官方驱动进行封装,将protobuf的Message和mongodb的Collection进行绑定,实现对Message的操作可以同步到数据库中 + +## todo + +- [ ] 完成初始化程序 +- [ ] 封装CRUD \ No newline at end of file diff --git a/autogen_model_model.go b/autogen_model_model.go new file mode 100644 index 0000000..794bcc3 --- /dev/null +++ b/autogen_model_model.go @@ -0,0 +1,35 @@ +// Code generated by protoc-gen-coco. DO NOT EDIT. +// source: model.proto +// generate at: 2023-06-18 18:16:24 + +package mdbc + +const TableNameModelArticles = "articles" + +func (t *ModelArticles) TableName() string { + return "articles" +} + +func (m *ModelArticles) GetIdField() string { + return "_id" +} + +func (m *ModelArticles) GetTitleField() string { + return "title" +} + +func (m *ModelArticles) GetAvatarUrlField() string { + return "avatar_url" +} + +func (m *ModelArticles) GetPhoneField() string { + return "phone" +} + +func (m *ModelArticles) GetCreateTimeField() string { + return "create_time" +} + +func (m *ModelArticles) GetUpdateTimeField() string { + return "update_time" +} diff --git a/count.go b/count.go new file mode 100644 index 0000000..3c2c3ae --- /dev/null +++ b/count.go @@ -0,0 +1,71 @@ +package mdbc + +import ( + "context" + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/mongo/options" + "reflect" +) + +type countScope struct { + *scope + *mdbc + ctx context.Context + limit int64 + skip int64 + filter interface{} + opts options.CountOptions +} + +// SetContext set operate context, default timeout 30s +func (cs *countScope) SetContext(ctx context.Context) *countScope { + cs.ctx = ctx + return cs +} + +// SetLimit set filter limit size +func (cs *countScope) SetLimit(limit int64) *countScope { + cs.limit = limit + return cs +} + +// SetSkip set filter skip size +func (cs *countScope) SetSkip(skip int64) *countScope { + cs.skip = skip + return cs +} + +func (cs *countScope) SetFilter(filter interface{}) *countScope { + if filter == nil { + cs.filter = bson.M{} + return cs + } + v := reflect.ValueOf(filter) + if v.Kind() == reflect.Ptr || v.Kind() == reflect.Map || v.Kind() == reflect.Slice { + if v.IsNil() { + cs.filter = bson.M{} + } + } + cs.filter = filter + return cs +} + +func (cs *countScope) mergeOptions() { + if cs.ctx == nil { + cs.ctx = context.Background() + } + if cs.filter == nil { + cs.filter = bson.M{} + } + if cs.skip != 0 { + cs.opts.Skip = &cs.skip + } + if cs.limit != 0 { + cs.opts.Limit = &cs.limit + } +} + +func (cs *countScope) Count() (int64, error) { + cs.mergeOptions() + return cs.database.Collection(cs.tableName).CountDocuments(cs.ctx, cs.filter, &cs.opts) +} diff --git a/drop.go b/drop.go new file mode 100644 index 0000000..60e38d0 --- /dev/null +++ b/drop.go @@ -0,0 +1,25 @@ +package mdbc + +import "context" + +type dropScope struct { + *scope + *mdbc + ctx context.Context +} + +func (ds *dropScope) SetContext(ctx context.Context) *dropScope { + ds.ctx = ctx + return ds +} + +func (ds *dropScope) mergeOptions() { + if ds.ctx == nil { + ds.ctx = context.Background() + } +} + +func (ds *dropScope) Do() error { + ds.mergeOptions() + return ds.database.Collection(ds.tableName).Drop(ds.ctx) +} diff --git a/errors.go b/errors.go new file mode 100644 index 0000000..1ef0469 --- /dev/null +++ b/errors.go @@ -0,0 +1,13 @@ +package mdbc + +import "errors" + +var ( + ErrorRecordNotFound = errors.New("record not found") + ErrorNoInsertDocuments = errors.New("no insert documents") +) + +// IsRecordNotFound is record not found +func IsRecordNotFound(err error) bool { + return errors.Is(err, ErrorRecordNotFound) +} diff --git a/gen.sh b/gen.sh new file mode 100644 index 0000000..6d5babf --- /dev/null +++ b/gen.sh @@ -0,0 +1 @@ +protoc.exe model.proto --coco_out=. --go_out=. \ No newline at end of file diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..419e996 --- /dev/null +++ b/go.mod @@ -0,0 +1,30 @@ +module gitter.top/coco/mdbc + +go 1.20 + +require ( + github.com/sirupsen/logrus v1.9.3 + github.com/stretchr/testify v1.7.0 + gitter.top/coco/lormatter v0.0.0-20230409145644-f9cb43f740dc + gitter.top/common/goref v0.0.0-20230622151024-9b220e13c7cd + go.mongodb.org/mongo-driver v1.11.7 + google.golang.org/protobuf v1.30.0 +) + +require ( + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/golang/snappy v0.0.1 // indirect + github.com/klauspost/compress v1.13.6 // indirect + github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/xdg-go/pbkdf2 v1.0.0 // indirect + github.com/xdg-go/scram v1.1.1 // indirect + github.com/xdg-go/stringprep v1.0.3 // indirect + github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d // indirect + golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d // indirect + golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect + golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 // indirect + golang.org/x/text v0.3.7 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..75f1fd4 --- /dev/null +++ b/go.sum @@ -0,0 +1,77 @@ +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +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/protobuf v1.5.0 h1:LUVKkCeviFUMKqHa4tXIIij/lbhnMbP7Fn5wKdKkRh4= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4= +github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/klauspost/compress v1.13.6 h1:P76CopJELS0TiO2mebmnzgWaajssP/EszplttgQxcgc= +github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= +github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk= +github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1 h1:VkoXIwSboBpnk99O/KFauAEILuNHv5DVFKZMBN/gUgw= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe h1:iruDEfMl2E6fbMZ9s0scYfZQ84/6SPL6zC8ACM2oIL0= +github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= +github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4= +github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= +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.1 h1:VOMT+81stJgXW3CpHyqHN3AXDYIMsx56mEFrB37Mb/E= +github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g= +github.com/xdg-go/stringprep v1.0.3 h1:kdwGpVNwPFtjs98xCGkHjQtGKh86rDcRZN17QEMCOIs= +github.com/xdg-go/stringprep v1.0.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgklLGvcBnW8= +github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d h1:splanxYIlg+5LfHAM6xpdFEAYOk8iySO56hMFq6uLyA= +github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA= +gitter.top/coco/lormatter v0.0.0-20230409145644-f9cb43f740dc h1:B0bnfX8Y/dETV+zdcZNCwD/L+DLZN2wSf9szo/fxNCw= +gitter.top/coco/lormatter v0.0.0-20230409145644-f9cb43f740dc/go.mod h1:vyfU6MQ56tkoFKSzEzhYSwXjgZHMcu3AViHC3hIyO7I= +gitter.top/common/goref v0.0.0-20230622151024-9b220e13c7cd h1:EeOtSwGexcx0u1AE91wnemiOGedENxaKcJUXxpzcgiE= +gitter.top/common/goref v0.0.0-20230622151024-9b220e13c7cd/go.mod h1:oK6jZQ/ISS8gZ78rvww6p7FuLUzaJ+S5F5UXSqO7Lr0= +go.mongodb.org/mongo-driver v1.11.7 h1:LIwYxASDLGUg/8wOhgOOZhX8tQa/9tgZPgzZoVqJvcs= +go.mongodb.org/mongo-driver v1.11.7/go.mod h1:G9TgswdsWjX4tmDA5zfs2+6AEPpYJwqblyjsfuh8oXY= +golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d h1:sK3txAijHtOK88l68nt020reeT1ZdKLIYetKl95FzVY= +golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 h1:CIJ76btIcR3eFI5EgSo6k1qKw9KJexJuRLI9G7Hp5wE= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/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-20220715151400-c0bba94af5f8 h1:0A+M6Uqn+Eje4kHMK80dtF3JCXC4ykBgQG4Fe06QRhQ= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e h1:FDhOuMEY4JVRztM/gsbk+IKUQ8kj74bxZrgw87eMMVc= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= +google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/indexes.go b/indexes.go new file mode 100644 index 0000000..b5e6f3a --- /dev/null +++ b/indexes.go @@ -0,0 +1,26 @@ +package mdbc + +import "context" + +type indexesScope struct { + *scope + *mdbc + ctx context.Context +} + +func (is *indexesScope) SetContext(ctx context.Context) *indexesScope { + is.ctx = ctx + return is +} + +func (is *indexesScope) Create(ctx context.Context) error { + return nil +} + +func (is *indexesScope) Drop(ctx context.Context) error { + return nil +} + +func (is *indexesScope) List(ctx context.Context) error { + return nil +} diff --git a/insert.go b/insert.go new file mode 100644 index 0000000..be67b00 --- /dev/null +++ b/insert.go @@ -0,0 +1,103 @@ +package mdbc + +import ( + "context" + "gitter.top/common/goref" + "go.mongodb.org/mongo-driver/mongo/options" +) + +type insertScope struct { + *scope + *mdbc + ctx context.Context + opts any + docs any +} + +type insert interface { + insert(docs any) (*InsertResult, error) +} + +type insertOne struct { + *insertScope +} + +func (io *insertOne) insert(docs any) (*InsertResult, error) { + result, err := io.database.Collection(io.tableName).InsertOne(io.ctx, docs, io.opts.(*options.InsertOneOptions)) + if err != nil { + return nil, err + } + return &InsertResult{id: result.InsertedID}, nil +} + +type insertMany struct { + *insertScope +} + +func (im *insertMany) insert(docs any) (*InsertResult, error) { + vals, ok := goref.ToInterfaces(docs) + if !ok { + return nil, ErrorNoInsertDocuments + } + result, err := im.database.Collection(im.tableName).InsertMany(im.ctx, vals, im.opts.(*options.InsertManyOptions)) + if err != nil { + return nil, err + } + return &InsertResult{id: result.InsertedIDs}, nil +} + +type InsertResult struct { + id interface{} +} + +func (ir *InsertResult) GetID() string { + val, ok := goref.ToString(ir.id) + if !ok { + } + return val +} + +func (ir *InsertResult) GetIDs() []string { + vals, ok := goref.ToStrings(ir.id) + if !ok { + } + return vals +} + +func (is *insertScope) SetContext(ctx context.Context) *insertScope { + is.ctx = ctx + return is +} + +func (is *insertScope) SetInsertOneOptions(opts options.InsertOneOptions) *insertScope { + is.opts = opts + return is +} + +func (is *insertScope) SetInsertManyOptions(opts options.InsertManyOptions) *insertScope { + is.opts = opts + return is +} + +func (is *insertScope) mergeOptions(isMany bool) *insertScope { + if is.ctx == nil { + is.ctx = context.Background() + } + if is.opts == nil && isMany { + is.opts = &options.InsertManyOptions{} + } + if is.opts == nil && !isMany { + is.opts = &options.InsertOneOptions{} + } + return is +} + +func (is *insertScope) Insert(docs any) (*InsertResult, error) { + isMany := goref.IsBaseList(docs) + is.mergeOptions(isMany) + var action insert = &insertOne{is} + if isMany { + action = &insertMany{is} + } + return action.insert(docs) +} diff --git a/mdbc.go b/mdbc.go new file mode 100644 index 0000000..496190c --- /dev/null +++ b/mdbc.go @@ -0,0 +1,111 @@ +package mdbc + +import ( + "context" + "github.com/sirupsen/logrus" + "gitter.top/coco/lormatter" + "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/mongo/options" + "go.mongodb.org/mongo-driver/mongo/readpref" + "google.golang.org/protobuf/proto" + "reflect" + "time" +) + +func init() { + formatter := &lormatter.Formatter{} + logrus.SetFormatter(formatter) + logrus.SetReportCaller(true) +} + +type Config struct { + uri string + Username string `json:"username" yaml:"username"` + Password string `json:"password" yaml:"password"` + Address string `json:"address" yaml:"address"` + Port int `json:"port" yaml:"port"` + ProcessTimeout int `json:"process_timeout" yaml:"process_timeout"` + DbName string `json:"db_name" yaml:"db_name"` + ReadPref ReadPref `json:"read_pref" yaml:"read_pref"` +} + +func (c *Config) merge() { + if c.Address == "" { + c.Address = "localhost" + } + if c.Port == 0 { + c.Port = 27017 + } + if c.ProcessTimeout == 0 { + c.ProcessTimeout = 30 + } +} + +type mdbc struct { + client *mongo.Client + database *mongo.Database + readpref *readpref.ReadPref +} + +func NewMDBC(config *Config) *mdbc { + var driver = new(mdbc) + var clientOpts = options.Client() + config.merge() + clientOpts.ApplyURI(applyURI(config.Address, config.Port)) + if config.Username != "" && config.Password != "" { + credential := options.Credential{ + Username: config.Username, + Password: config.Password, + } + clientOpts.SetAuth(credential) + } + ctx, cancel := context.WithTimeout(context.Background(), time.Duration(config.ProcessTimeout)*time.Second) + defer cancel() + client, err := mongo.Connect(ctx, clientOpts) + if err != nil { + panic(err) + } + driver.readpref = readPref(config.ReadPref) + if err := client.Ping(context.Background(), driver.readpref); err != nil { + panic(err) + } + driver.client = client + if config.DbName != "" { + driver.database = client.Database(config.DbName) + } + return driver +} + +// GetClient get raw mongo client +func (m *mdbc) GetClient() *mongo.Client { + return m.client +} + +// GetDatabase get raw mongo database +func (m *mdbc) GetDatabase() *mongo.Database { + return m.database +} + +// BindModel mapping protobuf Message to mongo Collection +func (m *mdbc) BindModel(prototype any) Collection { + if prototype == nil { + panic("model can not be nil") + } + if _, impled := prototype.(tabler); !impled { + panic("model does not implement tabler interface") + } + protomsg, impled := prototype.(proto.Message) + if !impled { + panic("model does not implement message interface") + } + scope := &scope{ + &model{ + Type: protomsg, + modelKind: reflect.TypeOf(protomsg), + modelName: string(protomsg.ProtoReflect().Descriptor().FullName()), + tableName: prototype.(tabler).TableName(), + }, + m, + } + return scope +} diff --git a/mdbc_test.go b/mdbc_test.go new file mode 100644 index 0000000..59c7faf --- /dev/null +++ b/mdbc_test.go @@ -0,0 +1,47 @@ +package mdbc + +import ( + "context" + "github.com/stretchr/testify/assert" + "gitter.top/common/goref" + "go.mongodb.org/mongo-driver/bson" + "testing" +) + +func newDriver() *mdbc { + return NewMDBC(&Config{ + Address: "192.168.3.21", + Port: 0, + Username: "admin", + Password: "admin", + ProcessTimeout: 0, + ReadPref: 0, + DbName: "articles", + }) +} + +func TestNewMDBC(t *testing.T) { + driver := newDriver() + databases, err := driver.GetClient().ListDatabaseNames(context.Background(), bson.D{}) + assert.NoError(t, err) + t.Log(databases) +} + +func TestScope_Count(t *testing.T) { + driver := newDriver() + article := driver.BindModel(&ModelArticles{}) + value, err := article.Count().SetContext(context.Background()).Count() + assert.NoError(t, err) + t.Log(value) +} + +func TestDropScope_Do(t *testing.T) { + driver := newDriver() + article := driver.BindModel(&ModelArticles{}) + err := article.Drop().Do() + assert.NoError(t, err) +} + +func TestInsertScope_Insert(t *testing.T) { + +} diff --git a/model.pb.go b/model.pb.go new file mode 100644 index 0000000..03556c3 --- /dev/null +++ b/model.pb.go @@ -0,0 +1,191 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.26.0 +// protoc v3.21.5 +// source: model.proto + +package mdbc + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// @table_name: articles +type ModelArticles struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` // 主键ID + Title string `protobuf:"bytes,2,opt,name=title,proto3" json:"title,omitempty"` // 标题 + AvatarUrl string `protobuf:"bytes,5,opt,name=avatar_url,json=avatarUrl,proto3" json:"avatar_url,omitempty"` // 封面 + Phone string `protobuf:"bytes,6,opt,name=phone,proto3" json:"phone,omitempty"` // 手机号码 + CreateTime int64 `protobuf:"varint,12,opt,name=create_time,json=createTime,proto3" json:"create_time,omitempty"` // 创建时间 + UpdateTime int64 `protobuf:"varint,13,opt,name=update_time,json=updateTime,proto3" json:"update_time,omitempty"` // 更新时间 +} + +func (x *ModelArticles) Reset() { + *x = ModelArticles{} + if protoimpl.UnsafeEnabled { + mi := &file_model_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ModelArticles) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ModelArticles) ProtoMessage() {} + +func (x *ModelArticles) ProtoReflect() protoreflect.Message { + mi := &file_model_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ModelArticles.ProtoReflect.Descriptor instead. +func (*ModelArticles) Descriptor() ([]byte, []int) { + return file_model_proto_rawDescGZIP(), []int{0} +} + +func (x *ModelArticles) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *ModelArticles) GetTitle() string { + if x != nil { + return x.Title + } + return "" +} + +func (x *ModelArticles) GetAvatarUrl() string { + if x != nil { + return x.AvatarUrl + } + return "" +} + +func (x *ModelArticles) GetPhone() string { + if x != nil { + return x.Phone + } + return "" +} + +func (x *ModelArticles) GetCreateTime() int64 { + if x != nil { + return x.CreateTime + } + return 0 +} + +func (x *ModelArticles) GetUpdateTime() int64 { + if x != nil { + return x.UpdateTime + } + return 0 +} + +var File_model_proto protoreflect.FileDescriptor + +var file_model_proto_rawDesc = []byte{ + 0x0a, 0x0b, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x04, 0x6d, + 0x64, 0x62, 0x63, 0x22, 0xac, 0x01, 0x0a, 0x0d, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x41, 0x72, 0x74, + 0x69, 0x63, 0x6c, 0x65, 0x73, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x61, + 0x76, 0x61, 0x74, 0x61, 0x72, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x09, 0x61, 0x76, 0x61, 0x74, 0x61, 0x72, 0x55, 0x72, 0x6c, 0x12, 0x14, 0x0a, 0x05, 0x70, 0x68, + 0x6f, 0x6e, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x70, 0x68, 0x6f, 0x6e, 0x65, + 0x12, 0x1f, 0x0a, 0x0b, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, + 0x0c, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, + 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, + 0x18, 0x0d, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, 0x69, + 0x6d, 0x65, 0x42, 0x09, 0x5a, 0x07, 0x2e, 0x2f, 0x3b, 0x6d, 0x64, 0x62, 0x63, 0x62, 0x06, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_model_proto_rawDescOnce sync.Once + file_model_proto_rawDescData = file_model_proto_rawDesc +) + +func file_model_proto_rawDescGZIP() []byte { + file_model_proto_rawDescOnce.Do(func() { + file_model_proto_rawDescData = protoimpl.X.CompressGZIP(file_model_proto_rawDescData) + }) + return file_model_proto_rawDescData +} + +var file_model_proto_msgTypes = make([]protoimpl.MessageInfo, 1) +var file_model_proto_goTypes = []interface{}{ + (*ModelArticles)(nil), // 0: mdbc.ModelArticles +} +var file_model_proto_depIdxs = []int32{ + 0, // [0:0] is the sub-list for method output_type + 0, // [0:0] is the sub-list for method input_type + 0, // [0:0] is the sub-list for extension type_name + 0, // [0:0] is the sub-list for extension extendee + 0, // [0:0] is the sub-list for field type_name +} + +func init() { file_model_proto_init() } +func file_model_proto_init() { + if File_model_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_model_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ModelArticles); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_model_proto_rawDesc, + NumEnums: 0, + NumMessages: 1, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_model_proto_goTypes, + DependencyIndexes: file_model_proto_depIdxs, + MessageInfos: file_model_proto_msgTypes, + }.Build() + File_model_proto = out.File + file_model_proto_rawDesc = nil + file_model_proto_goTypes = nil + file_model_proto_depIdxs = nil +} diff --git a/model.proto b/model.proto new file mode 100644 index 0000000..97c3a2f --- /dev/null +++ b/model.proto @@ -0,0 +1,16 @@ +syntax = "proto3"; + +package mdbc; + +option go_package = "./;mdbc"; + + +// @table_name: articles +message ModelArticles { + string id = 1; // 主键ID + string title = 2; // 标题 + string avatar_url = 5; // 封面 + string phone = 6; // 手机号码 + int64 create_time = 12; // 创建时间 + int64 update_time = 13; // 更新时间 +} diff --git a/readpref.go b/readpref.go new file mode 100644 index 0000000..7f60a02 --- /dev/null +++ b/readpref.go @@ -0,0 +1,30 @@ +package mdbc + +import "go.mongodb.org/mongo-driver/mongo/readpref" + +type ReadPref uint8 + +const ( + PrimaryMode ReadPref = iota + 1 + PrimaryPreferredMode + SecondaryMode + SecondaryPreferredMode + NearestMode +) + +func readPref(pref ReadPref) *readpref.ReadPref { + switch pref { + case PrimaryMode: + return readpref.Primary() + case PrimaryPreferredMode: + return readpref.PrimaryPreferred() + case SecondaryMode: + return readpref.Secondary() + case SecondaryPreferredMode: + return readpref.SecondaryPreferred() + case NearestMode: + return readpref.Nearest() + default: + return readpref.Primary() + } +} diff --git a/scope.go b/scope.go new file mode 100644 index 0000000..c78678a --- /dev/null +++ b/scope.go @@ -0,0 +1,87 @@ +package mdbc + +import ( + "google.golang.org/protobuf/proto" + "reflect" +) + +// model props for protobuf Message +type model struct { + Type proto.Message // model prototype + modelKind reflect.Type // model low level type + modelName string // model struct name + tableName string // model mapping table name +} + +// Scope export operation for user +type scope struct { + *model + *mdbc +} + +type Collection interface { + Aggregate() + BulkWrite() + Clone() + Count() *countScope + Delete() + Find() + Drop() *dropScope + Indexes() *indexesScope + Insert() + Update() + Watch() +} + +// Aggregate aggregate operate for mongo +func (s *scope) Aggregate() { + +} + +func (s *scope) BulkWrite() { + +} + +func (s *scope) Clone() { + +} + +func (s *scope) Count() *countScope { + return &countScope{ + scope: s, + mdbc: s.mdbc, + } +} + +func (s *scope) Delete() { + +} + +func (s *scope) Find() { + +} + +func (s *scope) Drop() *dropScope { + return &dropScope{ + scope: s, + mdbc: s.mdbc, + } +} + +func (s *scope) Indexes() *indexesScope { + return &indexesScope{ + scope: s, + mdbc: s.mdbc, + } +} + +func (s *scope) Insert() { + +} + +func (s *scope) Update() { + +} +func (s *scope) Watch() { + +} diff --git a/tabler.go b/tabler.go new file mode 100644 index 0000000..086f45f --- /dev/null +++ b/tabler.go @@ -0,0 +1,5 @@ +package mdbc + +type tabler interface { + TableName() string +} diff --git a/utils.go b/utils.go new file mode 100644 index 0000000..2ca83c1 --- /dev/null +++ b/utils.go @@ -0,0 +1,8 @@ +package mdbc + +import "fmt" + +// applyURI get mongo uri from address and port +func applyURI(address string, port int) string { + return fmt.Sprintf("mongodb://%s:%d", address, port) +}