parent
2e9637c110
commit
913dcb2f1e
@ -0,0 +1,114 @@ |
|||||||
|
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'. |
||||||
|
|
||||||
|
|
||||||
|
[[projects]] |
||||||
|
digest = "1:586ea76dbd0374d6fb649a91d70d652b7fe0ccffb8910a77468e7702e7901f3d" |
||||||
|
name = "github.com/go-stack/stack" |
||||||
|
packages = ["."] |
||||||
|
pruneopts = "UT" |
||||||
|
revision = "2fee6af1a9795aafbe0253a0cfbdf668e1fb8a9a" |
||||||
|
version = "v1.8.0" |
||||||
|
|
||||||
|
[[projects]] |
||||||
|
branch = "master" |
||||||
|
digest = "1:4a0c6bb4805508a6287675fac876be2ac1182539ca8a32468d8128882e9d5009" |
||||||
|
name = "github.com/golang/snappy" |
||||||
|
packages = ["."] |
||||||
|
pruneopts = "UT" |
||||||
|
revision = "2e65f85255dbc3072edf28d6b5b8efc472979f5a" |
||||||
|
|
||||||
|
[[projects]] |
||||||
|
digest = "1:820eeb72f78947f9b2e87bd99a57b5cc791c8fb47676a5c3824d408441ab1546" |
||||||
|
name = "github.com/mongodb/mongo-go-driver" |
||||||
|
packages = [ |
||||||
|
"bson", |
||||||
|
"bson/bsoncodec", |
||||||
|
"bson/bsonrw", |
||||||
|
"bson/bsontype", |
||||||
|
"bson/primitive", |
||||||
|
"event", |
||||||
|
"internal", |
||||||
|
"mongo", |
||||||
|
"mongo/options", |
||||||
|
"mongo/readconcern", |
||||||
|
"mongo/readpref", |
||||||
|
"mongo/writeconcern", |
||||||
|
"tag", |
||||||
|
"version", |
||||||
|
"x/bsonx", |
||||||
|
"x/bsonx/bsoncore", |
||||||
|
"x/mongo/driver", |
||||||
|
"x/mongo/driver/auth", |
||||||
|
"x/mongo/driver/auth/internal/gssapi", |
||||||
|
"x/mongo/driver/session", |
||||||
|
"x/mongo/driver/topology", |
||||||
|
"x/mongo/driver/uuid", |
||||||
|
"x/network/address", |
||||||
|
"x/network/command", |
||||||
|
"x/network/compressor", |
||||||
|
"x/network/connection", |
||||||
|
"x/network/connstring", |
||||||
|
"x/network/description", |
||||||
|
"x/network/result", |
||||||
|
"x/network/wiremessage", |
||||||
|
] |
||||||
|
pruneopts = "UT" |
||||||
|
revision = "29905d4bda472574c8b499e2f93b5b2747d8fbd7" |
||||||
|
version = "v0.1.0" |
||||||
|
|
||||||
|
[[projects]] |
||||||
|
branch = "master" |
||||||
|
digest = "1:40fdfd6ab85ca32b6935853bbba35935dcb1d796c8135efd85947566c76e662e" |
||||||
|
name = "github.com/xdg/scram" |
||||||
|
packages = ["."] |
||||||
|
pruneopts = "UT" |
||||||
|
revision = "7eeb5667e42c09cb51bf7b7c28aea8c56767da90" |
||||||
|
|
||||||
|
[[projects]] |
||||||
|
branch = "master" |
||||||
|
digest = "1:f5c1d04bc09c644c592b45b9f0bad4030521b1a7d11c7dadbb272d9439fa6e8e" |
||||||
|
name = "github.com/xdg/stringprep" |
||||||
|
packages = ["."] |
||||||
|
pruneopts = "UT" |
||||||
|
revision = "73f8eece6fdcd902c185bf651de50f3828bed5ed" |
||||||
|
|
||||||
|
[[projects]] |
||||||
|
branch = "master" |
||||||
|
digest = "1:f92f6956e4059f6a3efc14924d2dd58ba90da25cc57fe07ae3779ef2f5e0c5f2" |
||||||
|
name = "golang.org/x/crypto" |
||||||
|
packages = ["pbkdf2"] |
||||||
|
pruneopts = "UT" |
||||||
|
revision = "505ab145d0a99da450461ae2c1a9f6cd10d1f447" |
||||||
|
|
||||||
|
[[projects]] |
||||||
|
branch = "master" |
||||||
|
digest = "1:5e4d81c50cffcb124b899e4f3eabec3930c73532f0096c27f94476728ba03028" |
||||||
|
name = "golang.org/x/sync" |
||||||
|
packages = ["semaphore"] |
||||||
|
pruneopts = "UT" |
||||||
|
revision = "42b317875d0fa942474b76e1b46a6060d720ae6e" |
||||||
|
|
||||||
|
[[projects]] |
||||||
|
digest = "1:8029e9743749d4be5bc9f7d42ea1659471767860f0cdc34d37c3111bd308a295" |
||||||
|
name = "golang.org/x/text" |
||||||
|
packages = [ |
||||||
|
"internal/gen", |
||||||
|
"internal/triegen", |
||||||
|
"internal/ucd", |
||||||
|
"transform", |
||||||
|
"unicode/cldr", |
||||||
|
"unicode/norm", |
||||||
|
] |
||||||
|
pruneopts = "UT" |
||||||
|
revision = "f21a4dfb5e38f5895301dc265a8def02365cc3d0" |
||||||
|
version = "v0.3.0" |
||||||
|
|
||||||
|
[solve-meta] |
||||||
|
analyzer-name = "dep" |
||||||
|
analyzer-version = 1 |
||||||
|
input-imports = [ |
||||||
|
"github.com/mongodb/mongo-go-driver/bson/primitive", |
||||||
|
"github.com/mongodb/mongo-go-driver/mongo", |
||||||
|
] |
||||||
|
solver-name = "gps-cdcl" |
||||||
|
solver-version = 1 |
@ -0,0 +1,34 @@ |
|||||||
|
# Gopkg.toml example |
||||||
|
# |
||||||
|
# Refer to https://golang.github.io/dep/docs/Gopkg.toml.html |
||||||
|
# for detailed Gopkg.toml documentation. |
||||||
|
# |
||||||
|
# required = ["github.com/user/thing/cmd/thing"] |
||||||
|
# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"] |
||||||
|
# |
||||||
|
# [[constraint]] |
||||||
|
# name = "github.com/user/project" |
||||||
|
# version = "1.0.0" |
||||||
|
# |
||||||
|
# [[constraint]] |
||||||
|
# name = "github.com/user/project2" |
||||||
|
# branch = "dev" |
||||||
|
# source = "github.com/myfork/project2" |
||||||
|
# |
||||||
|
# [[override]] |
||||||
|
# name = "github.com/x/y" |
||||||
|
# version = "2.4.0" |
||||||
|
# |
||||||
|
# [prune] |
||||||
|
# non-go = false |
||||||
|
# go-tests = true |
||||||
|
# unused-packages = true |
||||||
|
|
||||||
|
|
||||||
|
[[constraint]] |
||||||
|
name = "github.com/mongodb/mongo-go-driver" |
||||||
|
version = "0.1.0" |
||||||
|
|
||||||
|
[prune] |
||||||
|
go-tests = true |
||||||
|
unused-packages = true |
@ -0,0 +1,20 @@ |
|||||||
|
package base |
||||||
|
|
||||||
|
import ( |
||||||
|
"github.com/mongodb/mongo-go-driver/bson/primitive" |
||||||
|
) |
||||||
|
|
||||||
|
// ObjectID is a structure with objectId as an _id field
|
||||||
|
type ObjectID struct { |
||||||
|
ID primitive.ObjectID `bson:"_id" json:"_id"` |
||||||
|
} |
||||||
|
|
||||||
|
// GetID returns an _id
|
||||||
|
func (db *ObjectID) GetID() primitive.ObjectID { |
||||||
|
return db.ID |
||||||
|
} |
||||||
|
|
||||||
|
// SetID sets an _id
|
||||||
|
func (db *ObjectID) SetID(id primitive.ObjectID) { |
||||||
|
db.ID = id |
||||||
|
} |
@ -0,0 +1,13 @@ |
|||||||
|
package mongox |
||||||
|
|
||||||
|
type Saver interface { |
||||||
|
Save(db *Database) error |
||||||
|
} |
||||||
|
|
||||||
|
type Deleter interface { |
||||||
|
Delete(db *Database) error |
||||||
|
} |
||||||
|
|
||||||
|
type Loader interface { |
||||||
|
Load(db *Database, filters ...interface{}) error |
||||||
|
} |
@ -0,0 +1,35 @@ |
|||||||
|
package common |
||||||
|
|
||||||
|
import ( |
||||||
|
"github.com/mainnika/mongox-go-driver/mongox" |
||||||
|
"github.com/mainnika/mongox-go-driver/mongox/errors" |
||||||
|
"github.com/mainnika/mongox-go-driver/mongox/query" |
||||||
|
"github.com/mongodb/mongo-go-driver/mongo" |
||||||
|
"github.com/mongodb/mongo-go-driver/mongo/options" |
||||||
|
) |
||||||
|
|
||||||
|
// LoadOne function loads a first single target document by a query
|
||||||
|
func LoadOne(db *mongox.Database, target interface{}, composed *query.Query) error { |
||||||
|
|
||||||
|
collection := db.GetCollectionOf(target) |
||||||
|
opts := &options.FindOneOptions{} |
||||||
|
|
||||||
|
if composed.Sorter() != nil { |
||||||
|
opts.Sort = composed.Sorter().Sort() |
||||||
|
} |
||||||
|
|
||||||
|
result := collection.FindOne(db.Context(), composed.M(), opts) |
||||||
|
if result.Err() != nil { |
||||||
|
return errors.InternalErrorf("can't create find one result: %s", result.Err()) |
||||||
|
} |
||||||
|
|
||||||
|
err := result.Decode(target) |
||||||
|
if err == mongo.ErrNoDocuments { |
||||||
|
return errors.NotFoundErrorf("%s", err) |
||||||
|
} |
||||||
|
if err != nil { |
||||||
|
return errors.InternalErrorf("can't decode desult: %s", err) |
||||||
|
} |
||||||
|
|
||||||
|
return nil |
||||||
|
} |
@ -0,0 +1,80 @@ |
|||||||
|
package mongox |
||||||
|
|
||||||
|
import ( |
||||||
|
"context" |
||||||
|
"reflect" |
||||||
|
|
||||||
|
"github.com/mainnika/mongox-go-driver/mongox/errors" |
||||||
|
"github.com/mongodb/mongo-go-driver/mongo" |
||||||
|
) |
||||||
|
|
||||||
|
// Database handler
|
||||||
|
type Database struct { |
||||||
|
client *mongo.Client |
||||||
|
dbname string |
||||||
|
ctx context.Context |
||||||
|
} |
||||||
|
|
||||||
|
// NewDatabase function creates new database instance with mongo client and empty context
|
||||||
|
func NewDatabase(client *mongo.Client, dbname string) *Database { |
||||||
|
|
||||||
|
db := &Database{} |
||||||
|
db.client = client |
||||||
|
db.dbname = dbname |
||||||
|
|
||||||
|
return db |
||||||
|
} |
||||||
|
|
||||||
|
// Client function returns a mongo client
|
||||||
|
func (d *Database) Client() *mongo.Client { |
||||||
|
return d.client |
||||||
|
} |
||||||
|
|
||||||
|
// Context function returns a context
|
||||||
|
func (d *Database) Context() context.Context { |
||||||
|
return d.ctx |
||||||
|
} |
||||||
|
|
||||||
|
// Name function returns a database name
|
||||||
|
func (d *Database) Name() string { |
||||||
|
return d.dbname |
||||||
|
} |
||||||
|
|
||||||
|
// New function creates new database context with same client
|
||||||
|
func (d *Database) New(ctx context.Context) *Database { |
||||||
|
|
||||||
|
if ctx != nil { |
||||||
|
ctx = context.Background() |
||||||
|
} |
||||||
|
|
||||||
|
return &Database{ |
||||||
|
client: d.client, |
||||||
|
dbname: d.dbname, |
||||||
|
ctx: ctx, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// GetCollectionOf returns the collection object by the «collection» tag of the given document;
|
||||||
|
// the «collection» tag should exists, e.g.:
|
||||||
|
// type Foobar struct {
|
||||||
|
// base.ObjectID `bson:",inline" json:",inline" collection:"foobars"`
|
||||||
|
// ...
|
||||||
|
// Will panic if there is no «collection» tag
|
||||||
|
func (d *Database) GetCollectionOf(document interface{}) *mongo.Collection { |
||||||
|
|
||||||
|
el := reflect.TypeOf(document).Elem() |
||||||
|
numField := el.NumField() |
||||||
|
|
||||||
|
for i := 0; i < numField; i++ { |
||||||
|
field := el.Field(i) |
||||||
|
tag := field.Tag |
||||||
|
found, ok := tag.Lookup("collection") |
||||||
|
if !ok { |
||||||
|
continue |
||||||
|
} |
||||||
|
|
||||||
|
return d.client.Database(d.dbname).Collection(found) |
||||||
|
} |
||||||
|
|
||||||
|
panic(errors.InternalErrorf("document %v does not have a collection tag", document)) |
||||||
|
} |
@ -0,0 +1,16 @@ |
|||||||
|
package errors |
||||||
|
|
||||||
|
import "fmt" |
||||||
|
|
||||||
|
// InternalError error
|
||||||
|
type InternalError string |
||||||
|
|
||||||
|
// Error message
|
||||||
|
func (ie InternalError) Error() string { |
||||||
|
return fmt.Sprintf("internal error, %s", string(ie)) |
||||||
|
} |
||||||
|
|
||||||
|
// InternalErrorf function creates an instance of InternalError
|
||||||
|
func InternalErrorf(format string, params ...interface{}) error { |
||||||
|
return InternalError(fmt.Sprintf(format, params...)) |
||||||
|
} |
@ -0,0 +1,16 @@ |
|||||||
|
package errors |
||||||
|
|
||||||
|
import "fmt" |
||||||
|
|
||||||
|
// NotFound error
|
||||||
|
type NotFound string |
||||||
|
|
||||||
|
// Error message
|
||||||
|
func (nf NotFound) Error() string { |
||||||
|
return fmt.Sprintf("can not find, %s", string(nf)) |
||||||
|
} |
||||||
|
|
||||||
|
// NotFoundErrorf function creates an instance of BadRequestError
|
||||||
|
func NotFoundErrorf(format string, params ...interface{}) error { |
||||||
|
return NotFound(fmt.Sprintf(format, params...)) |
||||||
|
} |
@ -0,0 +1,53 @@ |
|||||||
|
package query |
||||||
|
|
||||||
|
import ( |
||||||
|
"github.com/mainnika/mongox-go-driver/mongox/errors" |
||||||
|
"github.com/mongodb/mongo-go-driver/bson" |
||||||
|
) |
||||||
|
|
||||||
|
// ComposeQuery is a function to compose filters into a single query
|
||||||
|
func Compose(filters ...interface{}) *Query { |
||||||
|
|
||||||
|
q := &Query{} |
||||||
|
|
||||||
|
for _, f := range filters { |
||||||
|
|
||||||
|
ok := false |
||||||
|
ok = ok || applyBson(q, f) |
||||||
|
ok = ok || applyLimits(q, f) |
||||||
|
|
||||||
|
if !ok { |
||||||
|
panic(errors.InternalErrorf("unknown filter %v", f)) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return q |
||||||
|
} |
||||||
|
|
||||||
|
// applyBson is a fallback for a custom bson.M
|
||||||
|
func applyBson(q *Query, f interface{}) bool { |
||||||
|
|
||||||
|
switch f := f.(type) { |
||||||
|
case bson.M: |
||||||
|
q.And(f) |
||||||
|
default: |
||||||
|
return false |
||||||
|
} |
||||||
|
|
||||||
|
return true |
||||||
|
} |
||||||
|
|
||||||
|
// applyLimits extends query with contol functions
|
||||||
|
func applyLimits(q *Query, f interface{}) bool { |
||||||
|
|
||||||
|
switch f := f.(type) { |
||||||
|
case Limiter: |
||||||
|
q.limiter = f |
||||||
|
case Sorter: |
||||||
|
q.sorter = f |
||||||
|
default: |
||||||
|
return false |
||||||
|
} |
||||||
|
|
||||||
|
return true |
||||||
|
} |
@ -0,0 +1,60 @@ |
|||||||
|
package query |
||||||
|
|
||||||
|
import ( |
||||||
|
"github.com/mongodb/mongo-go-driver/bson" |
||||||
|
|
||||||
|
"reflect" |
||||||
|
) |
||||||
|
|
||||||
|
// Query is an enchanched bson.M map
|
||||||
|
type Query struct { |
||||||
|
m bson.M |
||||||
|
limiter Limiter |
||||||
|
sorter Sorter |
||||||
|
} |
||||||
|
|
||||||
|
// And function pushes the elem query to the $and array of the query
|
||||||
|
func (q *Query) And(elem bson.M) *Query { |
||||||
|
|
||||||
|
if q.m == nil { |
||||||
|
q.m = bson.M{} |
||||||
|
} |
||||||
|
|
||||||
|
queries, exists := q.m["$and"].(bson.A) |
||||||
|
|
||||||
|
if !exists { |
||||||
|
q.m["$and"] = bson.A{elem} |
||||||
|
return q |
||||||
|
} |
||||||
|
|
||||||
|
q.m["$and"] = append(queries, elem) |
||||||
|
|
||||||
|
return q |
||||||
|
} |
||||||
|
|
||||||
|
// Limiter is a limit function for a query
|
||||||
|
func (q *Query) Limiter() Limiter { |
||||||
|
|
||||||
|
return q.limiter |
||||||
|
} |
||||||
|
|
||||||
|
// Sorter is a sort rule for a query
|
||||||
|
func (q *Query) Sorter() Sorter { |
||||||
|
|
||||||
|
return q.sorter |
||||||
|
} |
||||||
|
|
||||||
|
// Empty checks the query for any content
|
||||||
|
func (q *Query) Empty() bool { |
||||||
|
|
||||||
|
qv := reflect.ValueOf(q) |
||||||
|
keys := qv.MapKeys() |
||||||
|
|
||||||
|
return len(keys) == 0 |
||||||
|
} |
||||||
|
|
||||||
|
// M returns underlying query map
|
||||||
|
func (q *Query) M() bson.M { |
||||||
|
|
||||||
|
return q.m |
||||||
|
} |
@ -0,0 +1,20 @@ |
|||||||
|
package query |
||||||
|
|
||||||
|
import ( |
||||||
|
"github.com/mongodb/mongo-go-driver/bson" |
||||||
|
) |
||||||
|
|
||||||
|
// Sorter is a filter to sort the data before query
|
||||||
|
type Sorter interface { |
||||||
|
Sort() bson.M |
||||||
|
} |
||||||
|
|
||||||
|
// Sort is a simple implementations of the Sorter filter
|
||||||
|
type Sort bson.M |
||||||
|
|
||||||
|
var _ Sorter = &Sort{} |
||||||
|
|
||||||
|
// Sort returns a slice of fields which have to be sorted
|
||||||
|
func (f Sort) Sort() bson.M { |
||||||
|
return bson.M(f) |
||||||
|
} |
Loading…
Reference in new issue