mirror of
https://github.com/mainnika/mongox-go-driver.git
synced 2026-05-22 15:53:36 +00:00
Basic stuff, loadOne
This commit is contained in:
@@ -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)
|
||||
}
|
||||
Reference in New Issue
Block a user