seba-365 - implemented dep
Change-Id: Ia6226d50e7615935a0c8876809a687427ff88c22
diff --git a/vendor/github.com/mongodb/mongo-go-driver/mongo/batch_cursor.go b/vendor/github.com/mongodb/mongo-go-driver/mongo/batch_cursor.go
new file mode 100644
index 0000000..a7ce0b5
--- /dev/null
+++ b/vendor/github.com/mongodb/mongo-go-driver/mongo/batch_cursor.go
@@ -0,0 +1,30 @@
+package mongo
+
+import (
+ "context"
+)
+
+// batchCursor is the interface implemented by types that can provide batches of document results.
+// The Cursor type is built on top of this type.
+type batchCursor interface {
+ // ID returns the ID of the cursor.
+ ID() int64
+
+ // Next returns true if there is a batch available.
+ Next(context.Context) bool
+
+ // Batch appends the current batch of documents to dst. RequiredBytes can be used to determine
+ // the length of the current batch of documents.
+ //
+ // If there is no batch available, this method should do nothing.
+ Batch(dst []byte) []byte
+
+ // RequiredBytes returns the number of bytes required fo rthe current batch.
+ RequiredBytes() int
+
+ // Err returns the last error encountered.
+ Err() error
+
+ // Close closes the cursor.
+ Close(context.Context) error
+}
diff --git a/vendor/github.com/mongodb/mongo-go-driver/mongo/bulk_write.go b/vendor/github.com/mongodb/mongo-go-driver/mongo/bulk_write.go
new file mode 100644
index 0000000..f086189
--- /dev/null
+++ b/vendor/github.com/mongodb/mongo-go-driver/mongo/bulk_write.go
@@ -0,0 +1,341 @@
+// Copyright (C) MongoDB, Inc. 2017-present.
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+
+package mongo
+
+import (
+ "github.com/mongodb/mongo-go-driver/mongo/options"
+ "github.com/mongodb/mongo-go-driver/x/mongo/driver"
+)
+
+// WriteModel is the interface satisfied by all models for bulk writes.
+type WriteModel interface {
+ convertModel() driver.WriteModel
+}
+
+// InsertOneModel is the write model for insert operations.
+type InsertOneModel struct {
+ Document interface{}
+}
+
+// NewInsertOneModel creates a new InsertOneModel.
+func NewInsertOneModel() *InsertOneModel {
+ return &InsertOneModel{}
+}
+
+// SetDocument sets the BSON document for the InsertOneModel.
+func (iom *InsertOneModel) SetDocument(doc interface{}) *InsertOneModel {
+ iom.Document = doc
+ return iom
+}
+
+func (iom *InsertOneModel) convertModel() driver.WriteModel {
+ return driver.InsertOneModel{
+ Document: iom.Document,
+ }
+}
+
+// DeleteOneModel is the write model for delete operations.
+type DeleteOneModel struct {
+ Filter interface{}
+ Collation *options.Collation
+}
+
+// NewDeleteOneModel creates a new DeleteOneModel.
+func NewDeleteOneModel() *DeleteOneModel {
+ return &DeleteOneModel{}
+}
+
+// SetFilter sets the filter for the DeleteOneModel.
+func (dom *DeleteOneModel) SetFilter(filter interface{}) *DeleteOneModel {
+ dom.Filter = filter
+ return dom
+}
+
+// SetCollation sets the collation for the DeleteOneModel.
+func (dom *DeleteOneModel) SetCollation(collation *options.Collation) *DeleteOneModel {
+ dom.Collation = collation
+ return dom
+}
+
+func (dom *DeleteOneModel) convertModel() driver.WriteModel {
+ return driver.DeleteOneModel{
+ Collation: dom.Collation,
+ Filter: dom.Filter,
+ }
+}
+
+// DeleteManyModel is the write model for deleteMany operations.
+type DeleteManyModel struct {
+ Filter interface{}
+ Collation *options.Collation
+}
+
+// NewDeleteManyModel creates a new DeleteManyModel.
+func NewDeleteManyModel() *DeleteManyModel {
+ return &DeleteManyModel{}
+}
+
+// SetFilter sets the filter for the DeleteManyModel.
+func (dmm *DeleteManyModel) SetFilter(filter interface{}) *DeleteManyModel {
+ dmm.Filter = filter
+ return dmm
+}
+
+// SetCollation sets the collation for the DeleteManyModel.
+func (dmm *DeleteManyModel) SetCollation(collation *options.Collation) *DeleteManyModel {
+ dmm.Collation = collation
+ return dmm
+}
+
+func (dmm *DeleteManyModel) convertModel() driver.WriteModel {
+ return driver.DeleteManyModel{
+ Collation: dmm.Collation,
+ Filter: dmm.Filter,
+ }
+}
+
+// ReplaceOneModel is the write model for replace operations.
+type ReplaceOneModel struct {
+ Collation *options.Collation
+ Upsert *bool
+ Filter interface{}
+ Replacement interface{}
+}
+
+// NewReplaceOneModel creates a new ReplaceOneModel.
+func NewReplaceOneModel() *ReplaceOneModel {
+ return &ReplaceOneModel{}
+}
+
+// SetFilter sets the filter for the ReplaceOneModel.
+func (rom *ReplaceOneModel) SetFilter(filter interface{}) *ReplaceOneModel {
+ rom.Filter = filter
+ return rom
+}
+
+// SetReplacement sets the replacement document for the ReplaceOneModel.
+func (rom *ReplaceOneModel) SetReplacement(rep interface{}) *ReplaceOneModel {
+ rom.Replacement = rep
+ return rom
+}
+
+// SetCollation sets the collation for the ReplaceOneModel.
+func (rom *ReplaceOneModel) SetCollation(collation *options.Collation) *ReplaceOneModel {
+ rom.Collation = collation
+ return rom
+}
+
+// SetUpsert specifies if a new document should be created if no document matches the query.
+func (rom *ReplaceOneModel) SetUpsert(upsert bool) *ReplaceOneModel {
+ rom.Upsert = &upsert
+ return rom
+}
+
+func (rom *ReplaceOneModel) convertModel() driver.WriteModel {
+ um := driver.UpdateModel{
+ Collation: rom.Collation,
+ }
+ if rom.Upsert != nil {
+ um.Upsert = *rom.Upsert
+ um.UpsertSet = true
+ }
+
+ return driver.ReplaceOneModel{
+ UpdateModel: um,
+ Filter: rom.Filter,
+ Replacement: rom.Replacement,
+ }
+}
+
+// UpdateOneModel is the write model for update operations.
+type UpdateOneModel struct {
+ Collation *options.Collation
+ Upsert *bool
+ Filter interface{}
+ Update interface{}
+ ArrayFilters *options.ArrayFilters
+}
+
+// NewUpdateOneModel creates a new UpdateOneModel.
+func NewUpdateOneModel() *UpdateOneModel {
+ return &UpdateOneModel{}
+}
+
+// SetFilter sets the filter for the UpdateOneModel.
+func (uom *UpdateOneModel) SetFilter(filter interface{}) *UpdateOneModel {
+ uom.Filter = filter
+ return uom
+}
+
+// SetUpdate sets the update document for the UpdateOneModel.
+func (uom *UpdateOneModel) SetUpdate(update interface{}) *UpdateOneModel {
+ uom.Update = update
+ return uom
+}
+
+// SetArrayFilters specifies a set of filters specifying to which array elements an update should apply.
+func (uom *UpdateOneModel) SetArrayFilters(filters options.ArrayFilters) *UpdateOneModel {
+ uom.ArrayFilters = &filters
+ return uom
+}
+
+// SetCollation sets the collation for the UpdateOneModel.
+func (uom *UpdateOneModel) SetCollation(collation *options.Collation) *UpdateOneModel {
+ uom.Collation = collation
+ return uom
+}
+
+// SetUpsert specifies if a new document should be created if no document matches the query.
+func (uom *UpdateOneModel) SetUpsert(upsert bool) *UpdateOneModel {
+ uom.Upsert = &upsert
+ return uom
+}
+
+func (uom *UpdateOneModel) convertModel() driver.WriteModel {
+ um := driver.UpdateModel{
+ Collation: uom.Collation,
+ }
+ if uom.Upsert != nil {
+ um.Upsert = *uom.Upsert
+ um.UpsertSet = true
+ }
+
+ converted := driver.UpdateOneModel{
+ UpdateModel: um,
+ Filter: uom.Filter,
+ Update: uom.Update,
+ }
+ if uom.ArrayFilters != nil {
+ converted.ArrayFilters = *uom.ArrayFilters
+ converted.ArrayFiltersSet = true
+ }
+
+ return converted
+}
+
+// UpdateManyModel is the write model for updateMany operations.
+type UpdateManyModel struct {
+ Collation *options.Collation
+ Upsert *bool
+ Filter interface{}
+ Update interface{}
+ ArrayFilters *options.ArrayFilters
+}
+
+// NewUpdateManyModel creates a new UpdateManyModel.
+func NewUpdateManyModel() *UpdateManyModel {
+ return &UpdateManyModel{}
+}
+
+// SetFilter sets the filter for the UpdateManyModel.
+func (umm *UpdateManyModel) SetFilter(filter interface{}) *UpdateManyModel {
+ umm.Filter = filter
+ return umm
+}
+
+// SetUpdate sets the update document for the UpdateManyModel.
+func (umm *UpdateManyModel) SetUpdate(update interface{}) *UpdateManyModel {
+ umm.Update = update
+ return umm
+}
+
+// SetArrayFilters specifies a set of filters specifying to which array elements an update should apply.
+func (umm *UpdateManyModel) SetArrayFilters(filters options.ArrayFilters) *UpdateManyModel {
+ umm.ArrayFilters = &filters
+ return umm
+}
+
+// SetCollation sets the collation for the UpdateManyModel.
+func (umm *UpdateManyModel) SetCollation(collation *options.Collation) *UpdateManyModel {
+ umm.Collation = collation
+ return umm
+}
+
+// SetUpsert specifies if a new document should be created if no document matches the query.
+func (umm *UpdateManyModel) SetUpsert(upsert bool) *UpdateManyModel {
+ umm.Upsert = &upsert
+ return umm
+}
+
+func (umm *UpdateManyModel) convertModel() driver.WriteModel {
+ um := driver.UpdateModel{
+ Collation: umm.Collation,
+ }
+ if umm.Upsert != nil {
+ um.Upsert = *umm.Upsert
+ um.UpsertSet = true
+ }
+
+ converted := driver.UpdateManyModel{
+ UpdateModel: um,
+ Filter: umm.Filter,
+ Update: umm.Update,
+ }
+ if umm.ArrayFilters != nil {
+ converted.ArrayFilters = *umm.ArrayFilters
+ converted.ArrayFiltersSet = true
+ }
+
+ return converted
+}
+
+func dispatchToMongoModel(model driver.WriteModel) WriteModel {
+ switch conv := model.(type) {
+ case driver.InsertOneModel:
+ return &InsertOneModel{
+ Document: conv.Document,
+ }
+ case driver.DeleteOneModel:
+ return &DeleteOneModel{
+ Filter: conv.Filter,
+ Collation: conv.Collation,
+ }
+ case driver.DeleteManyModel:
+ return &DeleteManyModel{
+ Filter: conv.Filter,
+ Collation: conv.Collation,
+ }
+ case driver.ReplaceOneModel:
+ rom := &ReplaceOneModel{
+ Filter: conv.Filter,
+ Replacement: conv.Replacement,
+ Collation: conv.Collation,
+ }
+ if conv.UpsertSet {
+ rom.Upsert = &conv.Upsert
+ }
+ return rom
+ case driver.UpdateOneModel:
+ uom := &UpdateOneModel{
+ Filter: conv.Filter,
+ Update: conv.Update,
+ Collation: conv.Collation,
+ }
+ if conv.UpsertSet {
+ uom.Upsert = &conv.Upsert
+ }
+ if conv.ArrayFiltersSet {
+ uom.ArrayFilters = &conv.ArrayFilters
+ }
+ return uom
+ case driver.UpdateManyModel:
+ umm := &UpdateManyModel{
+ Filter: conv.Filter,
+ Update: conv.Update,
+ Collation: conv.Collation,
+ }
+ if conv.UpsertSet {
+ umm.Upsert = &conv.Upsert
+ }
+ if conv.ArrayFiltersSet {
+ umm.ArrayFilters = &conv.ArrayFilters
+ }
+ return umm
+ }
+
+ return nil
+}
diff --git a/vendor/github.com/mongodb/mongo-go-driver/mongo/change_stream.go b/vendor/github.com/mongodb/mongo-go-driver/mongo/change_stream.go
new file mode 100644
index 0000000..5330117
--- /dev/null
+++ b/vendor/github.com/mongodb/mongo-go-driver/mongo/change_stream.go
@@ -0,0 +1,508 @@
+// Copyright (C) MongoDB, Inc. 2017-present.
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+
+package mongo
+
+import (
+ "context"
+ "errors"
+ "time"
+
+ "github.com/mongodb/mongo-go-driver/bson"
+ "github.com/mongodb/mongo-go-driver/bson/bsoncodec"
+ "github.com/mongodb/mongo-go-driver/mongo/options"
+ "github.com/mongodb/mongo-go-driver/mongo/readconcern"
+ "github.com/mongodb/mongo-go-driver/mongo/readpref"
+ "github.com/mongodb/mongo-go-driver/x/bsonx"
+ "github.com/mongodb/mongo-go-driver/x/bsonx/bsoncore"
+ "github.com/mongodb/mongo-go-driver/x/mongo/driver"
+ "github.com/mongodb/mongo-go-driver/x/mongo/driver/session"
+ "github.com/mongodb/mongo-go-driver/x/network/command"
+ "github.com/mongodb/mongo-go-driver/x/network/description"
+)
+
+const errorInterrupted int32 = 11601
+const errorCappedPositionLost int32 = 136
+const errorCursorKilled int32 = 237
+
+// ErrMissingResumeToken indicates that a change stream notification from the server did not
+// contain a resume token.
+var ErrMissingResumeToken = errors.New("cannot provide resume functionality when the resume token is missing")
+
+// ErrNilCursor indicates that the cursor for the change stream is nil.
+var ErrNilCursor = errors.New("cursor is nil")
+
+// ChangeStream instances iterate a stream of change documents. Each document can be decoded via the
+// Decode method. Resume tokens should be retrieved via the ResumeToken method and can be stored to
+// resume the change stream at a specific point in time.
+//
+// A typical usage of the ChangeStream type would be:
+type ChangeStream struct {
+ // Current is the BSON bytes of the current change document. This property is only valid until
+ // the next call to Next or Close. If continued access is required to the bson.Raw, you must
+ // make a copy of it.
+ Current bson.Raw
+
+ cmd bsonx.Doc // aggregate command to run to create stream and rebuild cursor
+ pipeline bsonx.Arr
+ options *options.ChangeStreamOptions
+ coll *Collection
+ db *Database
+ ns command.Namespace
+ cursor *Cursor
+ cursorOpts bsonx.Doc
+
+ resumeToken bsonx.Doc
+ err error
+ streamType StreamType
+ client *Client
+ sess Session
+ readPref *readpref.ReadPref
+ readConcern *readconcern.ReadConcern
+ registry *bsoncodec.Registry
+}
+
+func (cs *ChangeStream) replaceOptions(desc description.SelectedServer) {
+ // if cs has not received any changes and resumeAfter not specified and max wire version >= 7, run known agg cmd
+ // with startAtOperationTime set to startAtOperationTime provided by user or saved from initial agg
+ // must not send resumeAfter key
+
+ // else: run known agg cmd with resumeAfter set to last known resumeToken
+ // must not set startAtOperationTime (remove if originally in cmd)
+
+ if cs.options.ResumeAfter == nil && desc.WireVersion.Max >= 7 && cs.resumeToken == nil {
+ cs.options.SetStartAtOperationTime(cs.sess.OperationTime())
+ } else {
+ if cs.resumeToken == nil {
+ return // restart stream without the resume token
+ }
+
+ cs.options.SetResumeAfter(cs.resumeToken)
+ // remove startAtOperationTime
+ cs.options.SetStartAtOperationTime(nil)
+ }
+}
+
+// Create options docs for the pipeline and cursor
+func createCmdDocs(csType StreamType, opts *options.ChangeStreamOptions, registry *bsoncodec.Registry) (bsonx.Doc,
+ bsonx.Doc, bsonx.Doc, error) {
+
+ pipelineDoc := bsonx.Doc{}
+ cursorDoc := bsonx.Doc{}
+ optsDoc := bsonx.Doc{}
+
+ if csType == ClientStream {
+ pipelineDoc = pipelineDoc.Append("allChangesForCluster", bsonx.Boolean(true))
+ }
+
+ if opts.BatchSize != nil {
+ cursorDoc = cursorDoc.Append("batchSize", bsonx.Int32(*opts.BatchSize))
+ }
+ if opts.Collation != nil {
+ optsDoc = optsDoc.Append("collation", bsonx.Document(opts.Collation.ToDocument()))
+ }
+ if opts.FullDocument != nil {
+ pipelineDoc = pipelineDoc.Append("fullDocument", bsonx.String(string(*opts.FullDocument)))
+ }
+ if opts.MaxAwaitTime != nil {
+ ms := int64(time.Duration(*opts.MaxAwaitTime) / time.Millisecond)
+ pipelineDoc = pipelineDoc.Append("maxAwaitTimeMS", bsonx.Int64(ms))
+ }
+ if opts.ResumeAfter != nil {
+ rt, err := transformDocument(registry, opts.ResumeAfter)
+ if err != nil {
+ return nil, nil, nil, err
+ }
+
+ pipelineDoc = pipelineDoc.Append("resumeAfter", bsonx.Document(rt))
+ }
+ if opts.StartAtOperationTime != nil {
+ pipelineDoc = pipelineDoc.Append("startAtOperationTime",
+ bsonx.Timestamp(opts.StartAtOperationTime.T, opts.StartAtOperationTime.I))
+ }
+
+ return pipelineDoc, cursorDoc, optsDoc, nil
+}
+
+func getSession(ctx context.Context, client *Client) (Session, error) {
+ sess := sessionFromContext(ctx)
+ if err := client.ValidSession(sess); err != nil {
+ return nil, err
+ }
+
+ var mongoSess Session
+ if sess != nil {
+ mongoSess = &sessionImpl{
+ Client: sess,
+ }
+ } else {
+ // create implicit session because it will be needed
+ newSess, err := session.NewClientSession(client.topology.SessionPool, client.id, session.Implicit)
+ if err != nil {
+ return nil, err
+ }
+
+ mongoSess = &sessionImpl{
+ Client: newSess,
+ }
+ }
+
+ return mongoSess, nil
+}
+
+func parseOptions(csType StreamType, opts *options.ChangeStreamOptions, registry *bsoncodec.Registry) (bsonx.Doc,
+ bsonx.Doc, bsonx.Doc, error) {
+
+ if opts.FullDocument == nil {
+ opts = opts.SetFullDocument(options.Default)
+ }
+
+ pipelineDoc, cursorDoc, optsDoc, err := createCmdDocs(csType, opts, registry)
+ if err != nil {
+ return nil, nil, nil, err
+ }
+
+ return pipelineDoc, cursorDoc, optsDoc, nil
+}
+
+func (cs *ChangeStream) runCommand(ctx context.Context, replaceOptions bool) error {
+ ss, err := cs.client.topology.SelectServer(ctx, cs.db.writeSelector)
+ if err != nil {
+ return err
+ }
+
+ desc := ss.Description()
+ conn, err := ss.Connection(ctx)
+ if err != nil {
+ return err
+ }
+ defer conn.Close()
+
+ if replaceOptions {
+ cs.replaceOptions(desc)
+ optionsDoc, _, _, err := createCmdDocs(cs.streamType, cs.options, cs.registry)
+ if err != nil {
+ return err
+ }
+
+ changeStreamDoc := bsonx.Doc{
+ {"$changeStream", bsonx.Document(optionsDoc)},
+ }
+ cs.pipeline[0] = bsonx.Document(changeStreamDoc)
+ cs.cmd.Set("pipeline", bsonx.Array(cs.pipeline))
+ }
+
+ readCmd := command.Read{
+ DB: cs.db.name,
+ Command: cs.cmd,
+ Session: cs.sess.(*sessionImpl).Client,
+ Clock: cs.client.clock,
+ ReadPref: cs.readPref,
+ ReadConcern: cs.readConcern,
+ }
+
+ rdr, err := readCmd.RoundTrip(ctx, desc, conn)
+ if err != nil {
+ cs.sess.EndSession(ctx)
+ return err
+ }
+
+ batchCursor, err := driver.NewBatchCursor(bsoncore.Document(rdr), readCmd.Session, readCmd.Clock, ss.Server)
+ if err != nil {
+ cs.sess.EndSession(ctx)
+ return err
+ }
+ cursor, err := newCursor(batchCursor, cs.registry)
+ if err != nil {
+ cs.sess.EndSession(ctx)
+ return err
+ }
+ cs.cursor = cursor
+
+ cursorValue, err := rdr.LookupErr("cursor")
+ if err != nil {
+ return err
+ }
+ cursorDoc := cursorValue.Document()
+ cs.ns = command.ParseNamespace(cursorDoc.Lookup("ns").StringValue())
+
+ return nil
+}
+
+func newChangeStream(ctx context.Context, coll *Collection, pipeline interface{},
+ opts ...*options.ChangeStreamOptions) (*ChangeStream, error) {
+
+ pipelineArr, err := transformAggregatePipeline(coll.registry, pipeline)
+ if err != nil {
+ return nil, err
+ }
+
+ csOpts := options.MergeChangeStreamOptions(opts...)
+ pipelineDoc, cursorDoc, optsDoc, err := parseOptions(CollectionStream, csOpts, coll.registry)
+ if err != nil {
+ return nil, err
+ }
+ sess, err := getSession(ctx, coll.client)
+ if err != nil {
+ return nil, err
+ }
+
+ csDoc := bsonx.Document(bsonx.Doc{
+ {"$changeStream", bsonx.Document(pipelineDoc)},
+ })
+ pipelineArr = append(bsonx.Arr{csDoc}, pipelineArr...)
+
+ cmd := bsonx.Doc{
+ {"aggregate", bsonx.String(coll.name)},
+ {"pipeline", bsonx.Array(pipelineArr)},
+ {"cursor", bsonx.Document(cursorDoc)},
+ }
+ cmd = append(cmd, optsDoc...)
+
+ cs := &ChangeStream{
+ client: coll.client,
+ sess: sess,
+ cmd: cmd,
+ pipeline: pipelineArr,
+ coll: coll,
+ db: coll.db,
+ streamType: CollectionStream,
+ readPref: coll.readPreference,
+ readConcern: coll.readConcern,
+ options: csOpts,
+ registry: coll.registry,
+ cursorOpts: cursorDoc,
+ }
+
+ err = cs.runCommand(ctx, false)
+ if err != nil {
+ return nil, err
+ }
+
+ return cs, nil
+}
+
+func newDbChangeStream(ctx context.Context, db *Database, pipeline interface{},
+ opts ...*options.ChangeStreamOptions) (*ChangeStream, error) {
+
+ pipelineArr, err := transformAggregatePipeline(db.registry, pipeline)
+ if err != nil {
+ return nil, err
+ }
+
+ csOpts := options.MergeChangeStreamOptions(opts...)
+ pipelineDoc, cursorDoc, optsDoc, err := parseOptions(DatabaseStream, csOpts, db.registry)
+ if err != nil {
+ return nil, err
+ }
+ sess, err := getSession(ctx, db.client)
+ if err != nil {
+ return nil, err
+ }
+
+ csDoc := bsonx.Document(bsonx.Doc{
+ {"$changeStream", bsonx.Document(pipelineDoc)},
+ })
+ pipelineArr = append(bsonx.Arr{csDoc}, pipelineArr...)
+
+ cmd := bsonx.Doc{
+ {"aggregate", bsonx.Int32(1)},
+ {"pipeline", bsonx.Array(pipelineArr)},
+ {"cursor", bsonx.Document(cursorDoc)},
+ }
+ cmd = append(cmd, optsDoc...)
+
+ cs := &ChangeStream{
+ client: db.client,
+ db: db,
+ sess: sess,
+ cmd: cmd,
+ pipeline: pipelineArr,
+ streamType: DatabaseStream,
+ readPref: db.readPreference,
+ readConcern: db.readConcern,
+ options: csOpts,
+ registry: db.registry,
+ cursorOpts: cursorDoc,
+ }
+
+ err = cs.runCommand(ctx, false)
+ if err != nil {
+ return nil, err
+ }
+
+ return cs, nil
+}
+
+func newClientChangeStream(ctx context.Context, client *Client, pipeline interface{},
+ opts ...*options.ChangeStreamOptions) (*ChangeStream, error) {
+
+ pipelineArr, err := transformAggregatePipeline(client.registry, pipeline)
+ if err != nil {
+ return nil, err
+ }
+
+ csOpts := options.MergeChangeStreamOptions(opts...)
+ pipelineDoc, cursorDoc, optsDoc, err := parseOptions(ClientStream, csOpts, client.registry)
+ if err != nil {
+ return nil, err
+ }
+ sess, err := getSession(ctx, client)
+ if err != nil {
+ return nil, err
+ }
+
+ csDoc := bsonx.Document(bsonx.Doc{
+ {"$changeStream", bsonx.Document(pipelineDoc)},
+ })
+ pipelineArr = append(bsonx.Arr{csDoc}, pipelineArr...)
+
+ cmd := bsonx.Doc{
+ {"aggregate", bsonx.Int32(1)},
+ {"pipeline", bsonx.Array(pipelineArr)},
+ {"cursor", bsonx.Document(cursorDoc)},
+ }
+ cmd = append(cmd, optsDoc...)
+
+ cs := &ChangeStream{
+ client: client,
+ db: client.Database("admin"),
+ sess: sess,
+ cmd: cmd,
+ pipeline: pipelineArr,
+ streamType: ClientStream,
+ readPref: client.readPreference,
+ readConcern: client.readConcern,
+ options: csOpts,
+ registry: client.registry,
+ cursorOpts: cursorDoc,
+ }
+
+ err = cs.runCommand(ctx, false)
+ if err != nil {
+ return nil, err
+ }
+
+ return cs, nil
+}
+
+func (cs *ChangeStream) storeResumeToken() error {
+ idVal, err := cs.cursor.Current.LookupErr("_id")
+ if err != nil {
+ _ = cs.Close(context.Background())
+ return ErrMissingResumeToken
+ }
+
+ var idDoc bson.Raw
+ idDoc, ok := idVal.DocumentOK()
+ if !ok {
+ _ = cs.Close(context.Background())
+ return ErrMissingResumeToken
+ }
+ tokenDoc, err := bsonx.ReadDoc(idDoc)
+ if err != nil {
+ _ = cs.Close(context.Background())
+ return ErrMissingResumeToken
+ }
+
+ cs.resumeToken = tokenDoc
+ return nil
+}
+
+// ID returns the cursor ID for this change stream.
+func (cs *ChangeStream) ID() int64 {
+ if cs.cursor == nil {
+ return 0
+ }
+
+ return cs.cursor.ID()
+}
+
+// Next gets the next result from this change stream. Returns true if there were no errors and the next
+// result is available for decoding.
+func (cs *ChangeStream) Next(ctx context.Context) bool {
+ // execute in a loop to retry resume-able errors and advance the underlying cursor
+ for {
+ if cs.cursor == nil {
+ return false
+ }
+
+ if cs.cursor.Next(ctx) {
+ err := cs.storeResumeToken()
+ if err != nil {
+ cs.err = err
+ return false
+ }
+
+ cs.Current = cs.cursor.Current
+ return true
+ }
+
+ err := cs.cursor.Err()
+ if err == nil {
+ return false
+ }
+
+ switch t := err.(type) {
+ case command.Error:
+ if t.Code == errorInterrupted || t.Code == errorCappedPositionLost || t.Code == errorCursorKilled {
+ return false
+ }
+ }
+
+ killCursors := command.KillCursors{
+ NS: cs.ns,
+ IDs: []int64{cs.ID()},
+ }
+
+ _, _ = driver.KillCursors(ctx, killCursors, cs.client.topology, cs.db.writeSelector)
+ cs.err = cs.runCommand(ctx, true)
+ if cs.err != nil {
+ return false
+ }
+ }
+}
+
+// Decode will decode the current document into val.
+func (cs *ChangeStream) Decode(out interface{}) error {
+ if cs.cursor == nil {
+ return ErrNilCursor
+ }
+
+ return bson.UnmarshalWithRegistry(cs.registry, cs.Current, out)
+}
+
+// Err returns the current error.
+func (cs *ChangeStream) Err() error {
+ if cs.err != nil {
+ return cs.err
+ }
+ if cs.cursor == nil {
+ return nil
+ }
+
+ return cs.cursor.Err()
+}
+
+// Close closes this cursor.
+func (cs *ChangeStream) Close(ctx context.Context) error {
+ if cs.cursor == nil {
+ return nil // cursor is already closed
+ }
+
+ return cs.cursor.Close(ctx)
+}
+
+// StreamType represents the type of a change stream.
+type StreamType uint8
+
+// These constants represent valid change stream types. A change stream can be initialized over a collection, all
+// collections in a database, or over a whole client.
+const (
+ CollectionStream StreamType = iota
+ DatabaseStream
+ ClientStream
+)
diff --git a/vendor/github.com/mongodb/mongo-go-driver/mongo/client.go b/vendor/github.com/mongodb/mongo-go-driver/mongo/client.go
new file mode 100644
index 0000000..7984bc0
--- /dev/null
+++ b/vendor/github.com/mongodb/mongo-go-driver/mongo/client.go
@@ -0,0 +1,454 @@
+// Copyright (C) MongoDB, Inc. 2017-present.
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+
+package mongo
+
+import (
+ "context"
+ "time"
+
+ "github.com/mongodb/mongo-go-driver/bson"
+ "github.com/mongodb/mongo-go-driver/bson/bsoncodec"
+ "github.com/mongodb/mongo-go-driver/mongo/options"
+ "github.com/mongodb/mongo-go-driver/mongo/readconcern"
+ "github.com/mongodb/mongo-go-driver/mongo/readpref"
+ "github.com/mongodb/mongo-go-driver/mongo/writeconcern"
+ "github.com/mongodb/mongo-go-driver/tag"
+ "github.com/mongodb/mongo-go-driver/x/mongo/driver"
+ "github.com/mongodb/mongo-go-driver/x/mongo/driver/session"
+ "github.com/mongodb/mongo-go-driver/x/mongo/driver/topology"
+ "github.com/mongodb/mongo-go-driver/x/mongo/driver/uuid"
+ "github.com/mongodb/mongo-go-driver/x/network/command"
+ "github.com/mongodb/mongo-go-driver/x/network/connstring"
+ "github.com/mongodb/mongo-go-driver/x/network/description"
+)
+
+const defaultLocalThreshold = 15 * time.Millisecond
+
+// Client performs operations on a given topology.
+type Client struct {
+ id uuid.UUID
+ topologyOptions []topology.Option
+ topology *topology.Topology
+ connString connstring.ConnString
+ localThreshold time.Duration
+ retryWrites bool
+ clock *session.ClusterClock
+ readPreference *readpref.ReadPref
+ readConcern *readconcern.ReadConcern
+ writeConcern *writeconcern.WriteConcern
+ registry *bsoncodec.Registry
+ marshaller BSONAppender
+}
+
+// Connect creates a new Client and then initializes it using the Connect method.
+func Connect(ctx context.Context, uri string, opts ...*options.ClientOptions) (*Client, error) {
+ c, err := NewClientWithOptions(uri, opts...)
+ if err != nil {
+ return nil, err
+ }
+ err = c.Connect(ctx)
+ if err != nil {
+ return nil, err
+ }
+ return c, nil
+}
+
+// NewClient creates a new client to connect to a cluster specified by the uri.
+func NewClient(uri string) (*Client, error) {
+ cs, err := connstring.Parse(uri)
+ if err != nil {
+ return nil, err
+ }
+
+ return newClient(cs)
+}
+
+// NewClientWithOptions creates a new client to connect to to a cluster specified by the connection
+// string and the options manually passed in. If the same option is configured in both the
+// connection string and the manual options, the manual option will be ignored.
+func NewClientWithOptions(uri string, opts ...*options.ClientOptions) (*Client, error) {
+ cs, err := connstring.Parse(uri)
+ if err != nil {
+ return nil, err
+ }
+
+ return newClient(cs, opts...)
+}
+
+// Connect initializes the Client by starting background monitoring goroutines.
+// This method must be called before a Client can be used.
+func (c *Client) Connect(ctx context.Context) error {
+ err := c.topology.Connect(ctx)
+ if err != nil {
+ return replaceTopologyErr(err)
+ }
+
+ return nil
+
+}
+
+// Disconnect closes sockets to the topology referenced by this Client. It will
+// shut down any monitoring goroutines, close the idle connection pool, and will
+// wait until all the in use connections have been returned to the connection
+// pool and closed before returning. If the context expires via cancellation,
+// deadline, or timeout before the in use connections have returned, the in use
+// connections will be closed, resulting in the failure of any in flight read
+// or write operations. If this method returns with no errors, all connections
+// associated with this Client have been closed.
+func (c *Client) Disconnect(ctx context.Context) error {
+ c.endSessions(ctx)
+ return replaceTopologyErr(c.topology.Disconnect(ctx))
+}
+
+// Ping verifies that the client can connect to the topology.
+// If readPreference is nil then will use the client's default read
+// preference.
+func (c *Client) Ping(ctx context.Context, rp *readpref.ReadPref) error {
+ if ctx == nil {
+ ctx = context.Background()
+ }
+
+ if rp == nil {
+ rp = c.readPreference
+ }
+
+ _, err := c.topology.SelectServer(ctx, description.ReadPrefSelector(rp))
+ return replaceTopologyErr(err)
+}
+
+// StartSession starts a new session.
+func (c *Client) StartSession(opts ...*options.SessionOptions) (Session, error) {
+ if c.topology.SessionPool == nil {
+ return nil, ErrClientDisconnected
+ }
+
+ sopts := options.MergeSessionOptions(opts...)
+ coreOpts := &session.ClientOptions{
+ DefaultReadConcern: c.readConcern,
+ DefaultReadPreference: c.readPreference,
+ DefaultWriteConcern: c.writeConcern,
+ }
+ if sopts.CausalConsistency != nil {
+ coreOpts.CausalConsistency = sopts.CausalConsistency
+ }
+ if sopts.DefaultReadConcern != nil {
+ coreOpts.DefaultReadConcern = sopts.DefaultReadConcern
+ }
+ if sopts.DefaultWriteConcern != nil {
+ coreOpts.DefaultWriteConcern = sopts.DefaultWriteConcern
+ }
+ if sopts.DefaultReadPreference != nil {
+ coreOpts.DefaultReadPreference = sopts.DefaultReadPreference
+ }
+
+ sess, err := session.NewClientSession(c.topology.SessionPool, c.id, session.Explicit, coreOpts)
+ if err != nil {
+ return nil, replaceTopologyErr(err)
+ }
+
+ sess.RetryWrite = c.retryWrites
+
+ return &sessionImpl{
+ Client: sess,
+ topo: c.topology,
+ }, nil
+}
+
+func (c *Client) endSessions(ctx context.Context) {
+ if c.topology.SessionPool == nil {
+ return
+ }
+ cmd := command.EndSessions{
+ Clock: c.clock,
+ SessionIDs: c.topology.SessionPool.IDSlice(),
+ }
+
+ _, _ = driver.EndSessions(ctx, cmd, c.topology, description.ReadPrefSelector(readpref.PrimaryPreferred()))
+}
+
+func newClient(cs connstring.ConnString, opts ...*options.ClientOptions) (*Client, error) {
+ clientOpt := options.MergeClientOptions(cs, opts...)
+
+ client := &Client{
+ topologyOptions: clientOpt.TopologyOptions,
+ connString: clientOpt.ConnString,
+ localThreshold: defaultLocalThreshold,
+ readPreference: clientOpt.ReadPreference,
+ readConcern: clientOpt.ReadConcern,
+ writeConcern: clientOpt.WriteConcern,
+ registry: clientOpt.Registry,
+ }
+
+ if client.connString.RetryWritesSet {
+ client.retryWrites = client.connString.RetryWrites
+ }
+ if clientOpt.RetryWrites != nil {
+ client.retryWrites = *clientOpt.RetryWrites
+ }
+
+ clientID, err := uuid.New()
+ if err != nil {
+ return nil, err
+ }
+ client.id = clientID
+
+ topts := append(
+ client.topologyOptions,
+ topology.WithConnString(func(connstring.ConnString) connstring.ConnString { return client.connString }),
+ topology.WithServerOptions(func(opts ...topology.ServerOption) []topology.ServerOption {
+ return append(opts, topology.WithClock(func(clock *session.ClusterClock) *session.ClusterClock {
+ return client.clock
+ }), topology.WithRegistry(func(registry *bsoncodec.Registry) *bsoncodec.Registry {
+ return client.registry
+ }))
+ }),
+ )
+ topo, err := topology.New(topts...)
+ if err != nil {
+ return nil, replaceTopologyErr(err)
+ }
+ client.topology = topo
+ client.clock = &session.ClusterClock{}
+
+ if client.readConcern == nil {
+ client.readConcern = readConcernFromConnString(&client.connString)
+
+ if client.readConcern == nil {
+ // no read concern in conn string
+ client.readConcern = readconcern.New()
+ }
+ }
+
+ if client.writeConcern == nil {
+ client.writeConcern = writeConcernFromConnString(&client.connString)
+ }
+ if client.readPreference == nil {
+ rp, err := readPreferenceFromConnString(&client.connString)
+ if err != nil {
+ return nil, err
+ }
+ if rp != nil {
+ client.readPreference = rp
+ } else {
+ client.readPreference = readpref.Primary()
+ }
+ }
+
+ if client.registry == nil {
+ client.registry = bson.DefaultRegistry
+ }
+ return client, nil
+}
+
+func readConcernFromConnString(cs *connstring.ConnString) *readconcern.ReadConcern {
+ if len(cs.ReadConcernLevel) == 0 {
+ return nil
+ }
+
+ rc := &readconcern.ReadConcern{}
+ readconcern.Level(cs.ReadConcernLevel)(rc)
+
+ return rc
+}
+
+func writeConcernFromConnString(cs *connstring.ConnString) *writeconcern.WriteConcern {
+ var wc *writeconcern.WriteConcern
+
+ if len(cs.WString) > 0 {
+ if wc == nil {
+ wc = writeconcern.New()
+ }
+
+ writeconcern.WTagSet(cs.WString)(wc)
+ } else if cs.WNumberSet {
+ if wc == nil {
+ wc = writeconcern.New()
+ }
+
+ writeconcern.W(cs.WNumber)(wc)
+ }
+
+ if cs.JSet {
+ if wc == nil {
+ wc = writeconcern.New()
+ }
+
+ writeconcern.J(cs.J)(wc)
+ }
+
+ if cs.WTimeoutSet {
+ if wc == nil {
+ wc = writeconcern.New()
+ }
+
+ writeconcern.WTimeout(cs.WTimeout)(wc)
+ }
+
+ return wc
+}
+
+func readPreferenceFromConnString(cs *connstring.ConnString) (*readpref.ReadPref, error) {
+ var rp *readpref.ReadPref
+ var err error
+ options := make([]readpref.Option, 0, 1)
+
+ tagSets := tag.NewTagSetsFromMaps(cs.ReadPreferenceTagSets)
+ if len(tagSets) > 0 {
+ options = append(options, readpref.WithTagSets(tagSets...))
+ }
+
+ if cs.MaxStaleness != 0 {
+ options = append(options, readpref.WithMaxStaleness(cs.MaxStaleness))
+ }
+
+ if len(cs.ReadPreference) > 0 {
+ if rp == nil {
+ mode, _ := readpref.ModeFromString(cs.ReadPreference)
+ rp, err = readpref.New(mode, options...)
+ if err != nil {
+ return nil, err
+ }
+ }
+ }
+
+ return rp, nil
+}
+
+// ValidSession returns an error if the session doesn't belong to the client
+func (c *Client) ValidSession(sess *session.Client) error {
+ if sess != nil && !uuid.Equal(sess.ClientID, c.id) {
+ return ErrWrongClient
+ }
+ return nil
+}
+
+// Database returns a handle for a given database.
+func (c *Client) Database(name string, opts ...*options.DatabaseOptions) *Database {
+ return newDatabase(c, name, opts...)
+}
+
+// ConnectionString returns the connection string of the cluster the client is connected to.
+func (c *Client) ConnectionString() string {
+ return c.connString.Original
+}
+
+// ListDatabases returns a ListDatabasesResult.
+func (c *Client) ListDatabases(ctx context.Context, filter interface{}, opts ...*options.ListDatabasesOptions) (ListDatabasesResult, error) {
+ if ctx == nil {
+ ctx = context.Background()
+ }
+
+ sess := sessionFromContext(ctx)
+
+ err := c.ValidSession(sess)
+ if err != nil {
+ return ListDatabasesResult{}, err
+ }
+
+ f, err := transformDocument(c.registry, filter)
+ if err != nil {
+ return ListDatabasesResult{}, err
+ }
+
+ cmd := command.ListDatabases{
+ Filter: f,
+ Session: sess,
+ Clock: c.clock,
+ }
+
+ readSelector := description.CompositeSelector([]description.ServerSelector{
+ description.ReadPrefSelector(readpref.Primary()),
+ description.LatencySelector(c.localThreshold),
+ })
+ res, err := driver.ListDatabases(
+ ctx, cmd,
+ c.topology,
+ readSelector,
+ c.id,
+ c.topology.SessionPool,
+ opts...,
+ )
+ if err != nil {
+ return ListDatabasesResult{}, replaceTopologyErr(err)
+ }
+
+ return (ListDatabasesResult{}).fromResult(res), nil
+}
+
+// ListDatabaseNames returns a slice containing the names of all of the databases on the server.
+func (c *Client) ListDatabaseNames(ctx context.Context, filter interface{}, opts ...*options.ListDatabasesOptions) ([]string, error) {
+ opts = append(opts, options.ListDatabases().SetNameOnly(true))
+
+ res, err := c.ListDatabases(ctx, filter, opts...)
+ if err != nil {
+ return nil, err
+ }
+
+ names := make([]string, 0)
+ for _, spec := range res.Databases {
+ names = append(names, spec.Name)
+ }
+
+ return names, nil
+}
+
+// WithSession allows a user to start a session themselves and manage
+// its lifetime. The only way to provide a session to a CRUD method is
+// to invoke that CRUD method with the mongo.SessionContext within the
+// closure. The mongo.SessionContext can be used as a regular context,
+// so methods like context.WithDeadline and context.WithTimeout are
+// supported.
+//
+// If the context.Context already has a mongo.Session attached, that
+// mongo.Session will be replaced with the one provided.
+//
+// Errors returned from the closure are transparently returned from
+// this function.
+func WithSession(ctx context.Context, sess Session, fn func(SessionContext) error) error {
+ return fn(contextWithSession(ctx, sess))
+}
+
+// UseSession creates a default session, that is only valid for the
+// lifetime of the closure. No cleanup outside of closing the session
+// is done upon exiting the closure. This means that an outstanding
+// transaction will be aborted, even if the closure returns an error.
+//
+// If ctx already contains a mongo.Session, that mongo.Session will be
+// replaced with the newly created mongo.Session.
+//
+// Errors returned from the closure are transparently returned from
+// this method.
+func (c *Client) UseSession(ctx context.Context, fn func(SessionContext) error) error {
+ return c.UseSessionWithOptions(ctx, options.Session(), fn)
+}
+
+// UseSessionWithOptions works like UseSession but allows the caller
+// to specify the options used to create the session.
+func (c *Client) UseSessionWithOptions(ctx context.Context, opts *options.SessionOptions, fn func(SessionContext) error) error {
+ defaultSess, err := c.StartSession(opts)
+ if err != nil {
+ return err
+ }
+
+ defer defaultSess.EndSession(ctx)
+
+ sessCtx := sessionContext{
+ Context: context.WithValue(ctx, sessionKey{}, defaultSess),
+ Session: defaultSess,
+ }
+
+ return fn(sessCtx)
+}
+
+// Watch returns a change stream cursor used to receive information of changes to the client. This method is preferred
+// to running a raw aggregation with a $changeStream stage because it supports resumability in the case of some errors.
+// The client must have read concern majority or no read concern for a change stream to be created successfully.
+func (c *Client) Watch(ctx context.Context, pipeline interface{},
+ opts ...*options.ChangeStreamOptions) (*ChangeStream, error) {
+
+ return newClientChangeStream(ctx, c, pipeline, opts...)
+}
diff --git a/vendor/github.com/mongodb/mongo-go-driver/mongo/collection.go b/vendor/github.com/mongodb/mongo-go-driver/mongo/collection.go
new file mode 100644
index 0000000..fb16775
--- /dev/null
+++ b/vendor/github.com/mongodb/mongo-go-driver/mongo/collection.go
@@ -0,0 +1,1298 @@
+// Copyright (C) MongoDB, Inc. 2017-present.
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+
+package mongo
+
+import (
+ "context"
+ "errors"
+ "strings"
+
+ "github.com/mongodb/mongo-go-driver/bson/bsoncodec"
+ "github.com/mongodb/mongo-go-driver/mongo/options"
+ "github.com/mongodb/mongo-go-driver/mongo/readconcern"
+ "github.com/mongodb/mongo-go-driver/mongo/readpref"
+ "github.com/mongodb/mongo-go-driver/mongo/writeconcern"
+ "github.com/mongodb/mongo-go-driver/x/bsonx"
+ "github.com/mongodb/mongo-go-driver/x/mongo/driver"
+ "github.com/mongodb/mongo-go-driver/x/mongo/driver/session"
+ "github.com/mongodb/mongo-go-driver/x/network/command"
+ "github.com/mongodb/mongo-go-driver/x/network/description"
+)
+
+// Collection performs operations on a given collection.
+type Collection struct {
+ client *Client
+ db *Database
+ name string
+ readConcern *readconcern.ReadConcern
+ writeConcern *writeconcern.WriteConcern
+ readPreference *readpref.ReadPref
+ readSelector description.ServerSelector
+ writeSelector description.ServerSelector
+ registry *bsoncodec.Registry
+}
+
+func newCollection(db *Database, name string, opts ...*options.CollectionOptions) *Collection {
+ collOpt := options.MergeCollectionOptions(opts...)
+
+ rc := db.readConcern
+ if collOpt.ReadConcern != nil {
+ rc = collOpt.ReadConcern
+ }
+
+ wc := db.writeConcern
+ if collOpt.WriteConcern != nil {
+ wc = collOpt.WriteConcern
+ }
+
+ rp := db.readPreference
+ if collOpt.ReadPreference != nil {
+ rp = collOpt.ReadPreference
+ }
+
+ reg := db.registry
+ if collOpt.Registry != nil {
+ reg = collOpt.Registry
+ }
+
+ readSelector := description.CompositeSelector([]description.ServerSelector{
+ description.ReadPrefSelector(rp),
+ description.LatencySelector(db.client.localThreshold),
+ })
+
+ writeSelector := description.CompositeSelector([]description.ServerSelector{
+ description.WriteSelector(),
+ description.LatencySelector(db.client.localThreshold),
+ })
+
+ coll := &Collection{
+ client: db.client,
+ db: db,
+ name: name,
+ readPreference: rp,
+ readConcern: rc,
+ writeConcern: wc,
+ readSelector: readSelector,
+ writeSelector: writeSelector,
+ registry: reg,
+ }
+
+ return coll
+}
+
+func (coll *Collection) copy() *Collection {
+ return &Collection{
+ client: coll.client,
+ db: coll.db,
+ name: coll.name,
+ readConcern: coll.readConcern,
+ writeConcern: coll.writeConcern,
+ readPreference: coll.readPreference,
+ readSelector: coll.readSelector,
+ writeSelector: coll.writeSelector,
+ registry: coll.registry,
+ }
+}
+
+// Clone creates a copy of this collection with updated options, if any are given.
+func (coll *Collection) Clone(opts ...*options.CollectionOptions) (*Collection, error) {
+ copyColl := coll.copy()
+ optsColl := options.MergeCollectionOptions(opts...)
+
+ if optsColl.ReadConcern != nil {
+ copyColl.readConcern = optsColl.ReadConcern
+ }
+
+ if optsColl.WriteConcern != nil {
+ copyColl.writeConcern = optsColl.WriteConcern
+ }
+
+ if optsColl.ReadPreference != nil {
+ copyColl.readPreference = optsColl.ReadPreference
+ }
+
+ if optsColl.Registry != nil {
+ copyColl.registry = optsColl.Registry
+ }
+
+ copyColl.readSelector = description.CompositeSelector([]description.ServerSelector{
+ description.ReadPrefSelector(copyColl.readPreference),
+ description.LatencySelector(copyColl.client.localThreshold),
+ })
+
+ return copyColl, nil
+}
+
+// Name provides access to the name of the collection.
+func (coll *Collection) Name() string {
+ return coll.name
+}
+
+// namespace returns the namespace of the collection.
+func (coll *Collection) namespace() command.Namespace {
+ return command.NewNamespace(coll.db.name, coll.name)
+}
+
+// Database provides access to the database that contains the collection.
+func (coll *Collection) Database() *Database {
+ return coll.db
+}
+
+// BulkWrite performs a bulk write operation.
+//
+// See https://docs.mongodb.com/manual/core/bulk-write-operations/.
+func (coll *Collection) BulkWrite(ctx context.Context, models []WriteModel,
+ opts ...*options.BulkWriteOptions) (*BulkWriteResult, error) {
+
+ if len(models) == 0 {
+ return nil, ErrEmptySlice
+ }
+
+ if ctx == nil {
+ ctx = context.Background()
+ }
+
+ sess := sessionFromContext(ctx)
+
+ err := coll.client.ValidSession(sess)
+ if err != nil {
+ return nil, err
+ }
+
+ dispatchModels := make([]driver.WriteModel, len(models))
+ for i, model := range models {
+ if model == nil {
+ return nil, ErrNilDocument
+ }
+ dispatchModels[i] = model.convertModel()
+ }
+
+ res, err := driver.BulkWrite(
+ ctx,
+ coll.namespace(),
+ dispatchModels,
+ coll.client.topology,
+ coll.writeSelector,
+ coll.client.id,
+ coll.client.topology.SessionPool,
+ coll.client.retryWrites,
+ sess,
+ coll.writeConcern,
+ coll.client.clock,
+ coll.registry,
+ opts...,
+ )
+
+ if err != nil {
+ if conv, ok := err.(driver.BulkWriteException); ok {
+ return &BulkWriteResult{}, BulkWriteException{
+ WriteConcernError: convertWriteConcernError(conv.WriteConcernError),
+ WriteErrors: convertBulkWriteErrors(conv.WriteErrors),
+ }
+ }
+
+ return &BulkWriteResult{}, replaceTopologyErr(err)
+ }
+
+ return &BulkWriteResult{
+ InsertedCount: res.InsertedCount,
+ MatchedCount: res.MatchedCount,
+ ModifiedCount: res.ModifiedCount,
+ DeletedCount: res.DeletedCount,
+ UpsertedCount: res.UpsertedCount,
+ UpsertedIDs: res.UpsertedIDs,
+ }, nil
+}
+
+// InsertOne inserts a single document into the collection.
+func (coll *Collection) InsertOne(ctx context.Context, document interface{},
+ opts ...*options.InsertOneOptions) (*InsertOneResult, error) {
+
+ if ctx == nil {
+ ctx = context.Background()
+ }
+
+ doc, insertedID, err := transformAndEnsureID(coll.registry, document)
+ if err != nil {
+ return nil, err
+ }
+
+ sess := sessionFromContext(ctx)
+
+ err = coll.client.ValidSession(sess)
+ if err != nil {
+ return nil, err
+ }
+
+ wc := coll.writeConcern
+ if sess != nil && sess.TransactionRunning() {
+ wc = nil
+ }
+ oldns := coll.namespace()
+ cmd := command.Insert{
+ NS: command.Namespace{DB: oldns.DB, Collection: oldns.Collection},
+ Docs: []bsonx.Doc{doc},
+ WriteConcern: wc,
+ Session: sess,
+ Clock: coll.client.clock,
+ }
+
+ // convert to InsertManyOptions so these can be argued to dispatch.Insert
+ insertOpts := make([]*options.InsertManyOptions, len(opts))
+ for i, opt := range opts {
+ insertOpts[i] = options.InsertMany()
+ insertOpts[i].BypassDocumentValidation = opt.BypassDocumentValidation
+ }
+
+ res, err := driver.Insert(
+ ctx, cmd,
+ coll.client.topology,
+ coll.writeSelector,
+ coll.client.id,
+ coll.client.topology.SessionPool,
+ coll.client.retryWrites,
+ insertOpts...,
+ )
+
+ rr, err := processWriteError(res.WriteConcernError, res.WriteErrors, err)
+ if rr&rrOne == 0 {
+ return nil, err
+ }
+
+ return &InsertOneResult{InsertedID: insertedID}, err
+}
+
+// InsertMany inserts the provided documents.
+func (coll *Collection) InsertMany(ctx context.Context, documents []interface{},
+ opts ...*options.InsertManyOptions) (*InsertManyResult, error) {
+
+ if ctx == nil {
+ ctx = context.Background()
+ }
+
+ if len(documents) == 0 {
+ return nil, ErrEmptySlice
+ }
+
+ result := make([]interface{}, len(documents))
+ docs := make([]bsonx.Doc, len(documents))
+
+ for i, doc := range documents {
+ if doc == nil {
+ return nil, ErrNilDocument
+ }
+ bdoc, insertedID, err := transformAndEnsureID(coll.registry, doc)
+ if err != nil {
+ return nil, err
+ }
+
+ docs[i] = bdoc
+ result[i] = insertedID
+ }
+
+ sess := sessionFromContext(ctx)
+
+ err := coll.client.ValidSession(sess)
+ if err != nil {
+ return nil, err
+ }
+
+ wc := coll.writeConcern
+ if sess != nil && sess.TransactionRunning() {
+ wc = nil
+ }
+
+ oldns := coll.namespace()
+ cmd := command.Insert{
+ NS: command.Namespace{DB: oldns.DB, Collection: oldns.Collection},
+ Docs: docs,
+ WriteConcern: wc,
+ Session: sess,
+ Clock: coll.client.clock,
+ }
+
+ res, err := driver.Insert(
+ ctx, cmd,
+ coll.client.topology,
+ coll.writeSelector,
+ coll.client.id,
+ coll.client.topology.SessionPool,
+ coll.client.retryWrites,
+ opts...,
+ )
+
+ switch err {
+ case nil:
+ case command.ErrUnacknowledgedWrite:
+ return &InsertManyResult{InsertedIDs: result}, ErrUnacknowledgedWrite
+ default:
+ return nil, replaceTopologyErr(err)
+ }
+ if len(res.WriteErrors) > 0 || res.WriteConcernError != nil {
+ bwErrors := make([]BulkWriteError, 0, len(res.WriteErrors))
+ for _, we := range res.WriteErrors {
+ bwErrors = append(bwErrors, BulkWriteError{
+ WriteError{
+ Index: we.Index,
+ Code: we.Code,
+ Message: we.ErrMsg,
+ },
+ nil,
+ })
+ }
+
+ err = BulkWriteException{
+ WriteErrors: bwErrors,
+ WriteConcernError: convertWriteConcernError(res.WriteConcernError),
+ }
+ }
+
+ return &InsertManyResult{InsertedIDs: result}, err
+}
+
+// DeleteOne deletes a single document from the collection.
+func (coll *Collection) DeleteOne(ctx context.Context, filter interface{},
+ opts ...*options.DeleteOptions) (*DeleteResult, error) {
+
+ if ctx == nil {
+ ctx = context.Background()
+ }
+
+ f, err := transformDocument(coll.registry, filter)
+ if err != nil {
+ return nil, err
+ }
+ deleteDocs := []bsonx.Doc{
+ {
+ {"q", bsonx.Document(f)},
+ {"limit", bsonx.Int32(1)},
+ },
+ }
+
+ sess := sessionFromContext(ctx)
+
+ err = coll.client.ValidSession(sess)
+ if err != nil {
+ return nil, err
+ }
+
+ wc := coll.writeConcern
+ if sess != nil && sess.TransactionRunning() {
+ wc = nil
+ }
+
+ oldns := coll.namespace()
+ cmd := command.Delete{
+ NS: command.Namespace{DB: oldns.DB, Collection: oldns.Collection},
+ Deletes: deleteDocs,
+ WriteConcern: wc,
+ Session: sess,
+ Clock: coll.client.clock,
+ }
+
+ res, err := driver.Delete(
+ ctx, cmd,
+ coll.client.topology,
+ coll.writeSelector,
+ coll.client.id,
+ coll.client.topology.SessionPool,
+ coll.client.retryWrites,
+ opts...,
+ )
+
+ rr, err := processWriteError(res.WriteConcernError, res.WriteErrors, err)
+ if rr&rrOne == 0 {
+ return nil, err
+ }
+ return &DeleteResult{DeletedCount: int64(res.N)}, err
+}
+
+// DeleteMany deletes multiple documents from the collection.
+func (coll *Collection) DeleteMany(ctx context.Context, filter interface{},
+ opts ...*options.DeleteOptions) (*DeleteResult, error) {
+
+ if ctx == nil {
+ ctx = context.Background()
+ }
+
+ f, err := transformDocument(coll.registry, filter)
+ if err != nil {
+ return nil, err
+ }
+ deleteDocs := []bsonx.Doc{{{"q", bsonx.Document(f)}, {"limit", bsonx.Int32(0)}}}
+
+ sess := sessionFromContext(ctx)
+
+ err = coll.client.ValidSession(sess)
+ if err != nil {
+ return nil, err
+ }
+
+ wc := coll.writeConcern
+ if sess != nil && sess.TransactionRunning() {
+ wc = nil
+ }
+
+ oldns := coll.namespace()
+ cmd := command.Delete{
+ NS: command.Namespace{DB: oldns.DB, Collection: oldns.Collection},
+ Deletes: deleteDocs,
+ WriteConcern: wc,
+ Session: sess,
+ Clock: coll.client.clock,
+ }
+
+ res, err := driver.Delete(
+ ctx, cmd,
+ coll.client.topology,
+ coll.writeSelector,
+ coll.client.id,
+ coll.client.topology.SessionPool,
+ false,
+ opts...,
+ )
+
+ rr, err := processWriteError(res.WriteConcernError, res.WriteErrors, err)
+ if rr&rrMany == 0 {
+ return nil, err
+ }
+ return &DeleteResult{DeletedCount: int64(res.N)}, err
+}
+
+func (coll *Collection) updateOrReplaceOne(ctx context.Context, filter,
+ update bsonx.Doc, sess *session.Client, opts ...*options.UpdateOptions) (*UpdateResult, error) {
+
+ // TODO: should session be taken from ctx or left as argument?
+ if ctx == nil {
+ ctx = context.Background()
+ }
+
+ updateDocs := []bsonx.Doc{
+ {
+ {"q", bsonx.Document(filter)},
+ {"u", bsonx.Document(update)},
+ {"multi", bsonx.Boolean(false)},
+ },
+ }
+
+ wc := coll.writeConcern
+ if sess != nil && sess.TransactionRunning() {
+ wc = nil
+ }
+
+ oldns := coll.namespace()
+ cmd := command.Update{
+ NS: command.Namespace{DB: oldns.DB, Collection: oldns.Collection},
+ Docs: updateDocs,
+ WriteConcern: wc,
+ Session: sess,
+ Clock: coll.client.clock,
+ }
+
+ r, err := driver.Update(
+ ctx, cmd,
+ coll.client.topology,
+ coll.writeSelector,
+ coll.client.id,
+ coll.client.topology.SessionPool,
+ coll.client.retryWrites,
+ opts...,
+ )
+ if err != nil && err != command.ErrUnacknowledgedWrite {
+ return nil, replaceTopologyErr(err)
+ }
+
+ res := &UpdateResult{
+ MatchedCount: r.MatchedCount,
+ ModifiedCount: r.ModifiedCount,
+ UpsertedCount: int64(len(r.Upserted)),
+ }
+ if len(r.Upserted) > 0 {
+ res.UpsertedID = r.Upserted[0].ID
+ res.MatchedCount--
+ }
+
+ rr, err := processWriteError(r.WriteConcernError, r.WriteErrors, err)
+ if rr&rrOne == 0 {
+ return nil, err
+ }
+ return res, err
+}
+
+// UpdateOne updates a single document in the collection.
+func (coll *Collection) UpdateOne(ctx context.Context, filter interface{}, update interface{},
+ opts ...*options.UpdateOptions) (*UpdateResult, error) {
+
+ if ctx == nil {
+ ctx = context.Background()
+ }
+
+ f, err := transformDocument(coll.registry, filter)
+ if err != nil {
+ return nil, err
+ }
+
+ u, err := transformDocument(coll.registry, update)
+ if err != nil {
+ return nil, err
+ }
+
+ if err := ensureDollarKey(u); err != nil {
+ return nil, err
+ }
+
+ sess := sessionFromContext(ctx)
+
+ err = coll.client.ValidSession(sess)
+ if err != nil {
+ return nil, err
+ }
+
+ return coll.updateOrReplaceOne(ctx, f, u, sess, opts...)
+}
+
+// UpdateMany updates multiple documents in the collection.
+func (coll *Collection) UpdateMany(ctx context.Context, filter interface{}, update interface{},
+ opts ...*options.UpdateOptions) (*UpdateResult, error) {
+
+ if ctx == nil {
+ ctx = context.Background()
+ }
+
+ f, err := transformDocument(coll.registry, filter)
+ if err != nil {
+ return nil, err
+ }
+
+ u, err := transformDocument(coll.registry, update)
+ if err != nil {
+ return nil, err
+ }
+
+ if err = ensureDollarKey(u); err != nil {
+ return nil, err
+ }
+
+ updateDocs := []bsonx.Doc{
+ {
+ {"q", bsonx.Document(f)},
+ {"u", bsonx.Document(u)},
+ {"multi", bsonx.Boolean(true)},
+ },
+ }
+
+ sess := sessionFromContext(ctx)
+
+ err = coll.client.ValidSession(sess)
+ if err != nil {
+ return nil, err
+ }
+
+ wc := coll.writeConcern
+ if sess != nil && sess.TransactionRunning() {
+ wc = nil
+ }
+
+ oldns := coll.namespace()
+ cmd := command.Update{
+ NS: command.Namespace{DB: oldns.DB, Collection: oldns.Collection},
+ Docs: updateDocs,
+ WriteConcern: wc,
+ Session: sess,
+ Clock: coll.client.clock,
+ }
+
+ r, err := driver.Update(
+ ctx, cmd,
+ coll.client.topology,
+ coll.writeSelector,
+ coll.client.id,
+ coll.client.topology.SessionPool,
+ false,
+ opts...,
+ )
+ if err != nil && err != command.ErrUnacknowledgedWrite {
+ return nil, replaceTopologyErr(err)
+ }
+ res := &UpdateResult{
+ MatchedCount: r.MatchedCount,
+ ModifiedCount: r.ModifiedCount,
+ UpsertedCount: int64(len(r.Upserted)),
+ }
+ // TODO(skriptble): Is this correct? Do we only return the first upserted ID for an UpdateMany?
+ if len(r.Upserted) > 0 {
+ res.UpsertedID = r.Upserted[0].ID
+ res.MatchedCount--
+ }
+
+ rr, err := processWriteError(r.WriteConcernError, r.WriteErrors, err)
+ if rr&rrMany == 0 {
+ return nil, err
+ }
+ return res, err
+}
+
+// ReplaceOne replaces a single document in the collection.
+func (coll *Collection) ReplaceOne(ctx context.Context, filter interface{},
+ replacement interface{}, opts ...*options.ReplaceOptions) (*UpdateResult, error) {
+
+ if ctx == nil {
+ ctx = context.Background()
+ }
+
+ f, err := transformDocument(coll.registry, filter)
+ if err != nil {
+ return nil, err
+ }
+
+ r, err := transformDocument(coll.registry, replacement)
+ if err != nil {
+ return nil, err
+ }
+
+ if len(r) > 0 && strings.HasPrefix(r[0].Key, "$") {
+ return nil, errors.New("replacement document cannot contains keys beginning with '$")
+ }
+
+ sess := sessionFromContext(ctx)
+
+ err = coll.client.ValidSession(sess)
+ if err != nil {
+ return nil, err
+ }
+
+ updateOptions := make([]*options.UpdateOptions, 0, len(opts))
+ for _, opt := range opts {
+ uOpts := options.Update()
+ uOpts.BypassDocumentValidation = opt.BypassDocumentValidation
+ uOpts.Collation = opt.Collation
+ uOpts.Upsert = opt.Upsert
+ updateOptions = append(updateOptions, uOpts)
+ }
+
+ return coll.updateOrReplaceOne(ctx, f, r, sess, updateOptions...)
+}
+
+// Aggregate runs an aggregation framework pipeline.
+//
+// See https://docs.mongodb.com/manual/aggregation/.
+func (coll *Collection) Aggregate(ctx context.Context, pipeline interface{},
+ opts ...*options.AggregateOptions) (*Cursor, error) {
+
+ if ctx == nil {
+ ctx = context.Background()
+ }
+
+ pipelineArr, err := transformAggregatePipeline(coll.registry, pipeline)
+ if err != nil {
+ return nil, err
+ }
+
+ aggOpts := options.MergeAggregateOptions(opts...)
+
+ sess := sessionFromContext(ctx)
+
+ err = coll.client.ValidSession(sess)
+ if err != nil {
+ return nil, err
+ }
+
+ wc := coll.writeConcern
+ if sess != nil && sess.TransactionRunning() {
+ wc = nil
+ }
+
+ rc := coll.readConcern
+ if sess != nil && (sess.TransactionInProgress()) {
+ rc = nil
+ }
+
+ oldns := coll.namespace()
+ cmd := command.Aggregate{
+ NS: command.Namespace{DB: oldns.DB, Collection: oldns.Collection},
+ Pipeline: pipelineArr,
+ ReadPref: coll.readPreference,
+ WriteConcern: wc,
+ ReadConcern: rc,
+ Session: sess,
+ Clock: coll.client.clock,
+ }
+
+ batchCursor, err := driver.Aggregate(
+ ctx, cmd,
+ coll.client.topology,
+ coll.readSelector,
+ coll.writeSelector,
+ coll.client.id,
+ coll.client.topology.SessionPool,
+ coll.registry,
+ aggOpts,
+ )
+ if err != nil {
+ return nil, replaceTopologyErr(err)
+ }
+
+ cursor, err := newCursor(batchCursor, coll.registry)
+ return cursor, replaceTopologyErr(err)
+}
+
+// Count gets the number of documents matching the filter.
+func (coll *Collection) Count(ctx context.Context, filter interface{},
+ opts ...*options.CountOptions) (int64, error) {
+
+ if ctx == nil {
+ ctx = context.Background()
+ }
+
+ f, err := transformDocument(coll.registry, filter)
+ if err != nil {
+ return 0, err
+ }
+
+ sess := sessionFromContext(ctx)
+
+ err = coll.client.ValidSession(sess)
+ if err != nil {
+ return 0, err
+ }
+
+ rc := coll.readConcern
+ if sess != nil && (sess.TransactionInProgress()) {
+ rc = nil
+ }
+
+ oldns := coll.namespace()
+ cmd := command.Count{
+ NS: command.Namespace{DB: oldns.DB, Collection: oldns.Collection},
+ Query: f,
+ ReadPref: coll.readPreference,
+ ReadConcern: rc,
+ Session: sess,
+ Clock: coll.client.clock,
+ }
+
+ count, err := driver.Count(
+ ctx, cmd,
+ coll.client.topology,
+ coll.readSelector,
+ coll.client.id,
+ coll.client.topology.SessionPool,
+ coll.registry,
+ opts...,
+ )
+
+ return count, replaceTopologyErr(err)
+}
+
+// CountDocuments gets the number of documents matching the filter.
+func (coll *Collection) CountDocuments(ctx context.Context, filter interface{},
+ opts ...*options.CountOptions) (int64, error) {
+
+ if ctx == nil {
+ ctx = context.Background()
+ }
+
+ countOpts := options.MergeCountOptions(opts...)
+
+ pipelineArr, err := countDocumentsAggregatePipeline(coll.registry, filter, countOpts)
+ if err != nil {
+ return 0, err
+ }
+
+ sess := sessionFromContext(ctx)
+
+ err = coll.client.ValidSession(sess)
+ if err != nil {
+ return 0, err
+ }
+
+ rc := coll.readConcern
+ if sess != nil && (sess.TransactionInProgress()) {
+ rc = nil
+ }
+
+ oldns := coll.namespace()
+ cmd := command.CountDocuments{
+ NS: command.Namespace{DB: oldns.DB, Collection: oldns.Collection},
+ Pipeline: pipelineArr,
+ ReadPref: coll.readPreference,
+ ReadConcern: rc,
+ Session: sess,
+ Clock: coll.client.clock,
+ }
+
+ count, err := driver.CountDocuments(
+ ctx, cmd,
+ coll.client.topology,
+ coll.readSelector,
+ coll.client.id,
+ coll.client.topology.SessionPool,
+ coll.registry,
+ countOpts,
+ )
+
+ return count, replaceTopologyErr(err)
+}
+
+// EstimatedDocumentCount gets an estimate of the count of documents in a collection using collection metadata.
+func (coll *Collection) EstimatedDocumentCount(ctx context.Context,
+ opts ...*options.EstimatedDocumentCountOptions) (int64, error) {
+
+ if ctx == nil {
+ ctx = context.Background()
+ }
+
+ sess := sessionFromContext(ctx)
+
+ err := coll.client.ValidSession(sess)
+ if err != nil {
+ return 0, err
+ }
+
+ rc := coll.readConcern
+ if sess != nil && (sess.TransactionInProgress()) {
+ rc = nil
+ }
+
+ oldns := coll.namespace()
+ cmd := command.Count{
+ NS: command.Namespace{DB: oldns.DB, Collection: oldns.Collection},
+ Query: bsonx.Doc{},
+ ReadPref: coll.readPreference,
+ ReadConcern: rc,
+ Session: sess,
+ Clock: coll.client.clock,
+ }
+
+ countOpts := options.Count()
+ if len(opts) >= 1 {
+ countOpts = countOpts.SetMaxTime(*opts[len(opts)-1].MaxTime)
+ }
+
+ count, err := driver.Count(
+ ctx, cmd,
+ coll.client.topology,
+ coll.readSelector,
+ coll.client.id,
+ coll.client.topology.SessionPool,
+ coll.registry,
+ countOpts,
+ )
+
+ return count, replaceTopologyErr(err)
+}
+
+// Distinct finds the distinct values for a specified field across a single
+// collection.
+func (coll *Collection) Distinct(ctx context.Context, fieldName string, filter interface{},
+ opts ...*options.DistinctOptions) ([]interface{}, error) {
+
+ if ctx == nil {
+ ctx = context.Background()
+ }
+
+ f, err := transformDocument(coll.registry, filter)
+ if err != nil {
+ return nil, err
+ }
+
+ sess := sessionFromContext(ctx)
+
+ err = coll.client.ValidSession(sess)
+ if err != nil {
+ return nil, err
+ }
+
+ rc := coll.readConcern
+ if sess != nil && (sess.TransactionInProgress()) {
+ rc = nil
+ }
+
+ oldns := coll.namespace()
+ cmd := command.Distinct{
+ NS: command.Namespace{DB: oldns.DB, Collection: oldns.Collection},
+ Field: fieldName,
+ Query: f,
+ ReadPref: coll.readPreference,
+ ReadConcern: rc,
+ Session: sess,
+ Clock: coll.client.clock,
+ }
+
+ res, err := driver.Distinct(
+ ctx, cmd,
+ coll.client.topology,
+ coll.readSelector,
+ coll.client.id,
+ coll.client.topology.SessionPool,
+ opts...,
+ )
+ if err != nil {
+ return nil, replaceTopologyErr(err)
+ }
+
+ return res.Values, nil
+}
+
+// Find finds the documents matching a model.
+func (coll *Collection) Find(ctx context.Context, filter interface{},
+ opts ...*options.FindOptions) (*Cursor, error) {
+
+ if ctx == nil {
+ ctx = context.Background()
+ }
+
+ f, err := transformDocument(coll.registry, filter)
+ if err != nil {
+ return nil, err
+ }
+
+ sess := sessionFromContext(ctx)
+
+ err = coll.client.ValidSession(sess)
+ if err != nil {
+ return nil, err
+ }
+
+ rc := coll.readConcern
+ if sess != nil && (sess.TransactionInProgress()) {
+ rc = nil
+ }
+
+ oldns := coll.namespace()
+ cmd := command.Find{
+ NS: command.Namespace{DB: oldns.DB, Collection: oldns.Collection},
+ Filter: f,
+ ReadPref: coll.readPreference,
+ ReadConcern: rc,
+ Session: sess,
+ Clock: coll.client.clock,
+ }
+
+ batchCursor, err := driver.Find(
+ ctx, cmd,
+ coll.client.topology,
+ coll.readSelector,
+ coll.client.id,
+ coll.client.topology.SessionPool,
+ coll.registry,
+ opts...,
+ )
+ if err != nil {
+ return nil, replaceTopologyErr(err)
+ }
+
+ cursor, err := newCursor(batchCursor, coll.registry)
+ return cursor, replaceTopologyErr(err)
+}
+
+// FindOne returns up to one document that matches the model.
+func (coll *Collection) FindOne(ctx context.Context, filter interface{},
+ opts ...*options.FindOneOptions) *SingleResult {
+
+ if ctx == nil {
+ ctx = context.Background()
+ }
+
+ f, err := transformDocument(coll.registry, filter)
+ if err != nil {
+ return &SingleResult{err: err}
+ }
+
+ sess := sessionFromContext(ctx)
+
+ err = coll.client.ValidSession(sess)
+ if err != nil {
+ return &SingleResult{err: err}
+ }
+
+ rc := coll.readConcern
+ if sess != nil && (sess.TransactionInProgress()) {
+ rc = nil
+ }
+
+ oldns := coll.namespace()
+ cmd := command.Find{
+ NS: command.Namespace{DB: oldns.DB, Collection: oldns.Collection},
+ Filter: f,
+ ReadPref: coll.readPreference,
+ ReadConcern: rc,
+ Session: sess,
+ Clock: coll.client.clock,
+ }
+
+ findOpts := make([]*options.FindOptions, len(opts))
+ for i, opt := range opts {
+ findOpts[i] = &options.FindOptions{
+ AllowPartialResults: opt.AllowPartialResults,
+ BatchSize: opt.BatchSize,
+ Collation: opt.Collation,
+ Comment: opt.Comment,
+ CursorType: opt.CursorType,
+ Hint: opt.Hint,
+ Max: opt.Max,
+ MaxAwaitTime: opt.MaxAwaitTime,
+ Min: opt.Min,
+ NoCursorTimeout: opt.NoCursorTimeout,
+ OplogReplay: opt.OplogReplay,
+ Projection: opt.Projection,
+ ReturnKey: opt.ReturnKey,
+ ShowRecordID: opt.ShowRecordID,
+ Skip: opt.Skip,
+ Snapshot: opt.Snapshot,
+ Sort: opt.Sort,
+ }
+ }
+
+ batchCursor, err := driver.Find(
+ ctx, cmd,
+ coll.client.topology,
+ coll.readSelector,
+ coll.client.id,
+ coll.client.topology.SessionPool,
+ coll.registry,
+ findOpts...,
+ )
+ if err != nil {
+ return &SingleResult{err: replaceTopologyErr(err)}
+ }
+
+ cursor, err := newCursor(batchCursor, coll.registry)
+ return &SingleResult{cur: cursor, reg: coll.registry, err: replaceTopologyErr(err)}
+}
+
+// FindOneAndDelete find a single document and deletes it, returning the
+// original in result.
+func (coll *Collection) FindOneAndDelete(ctx context.Context, filter interface{},
+ opts ...*options.FindOneAndDeleteOptions) *SingleResult {
+
+ if ctx == nil {
+ ctx = context.Background()
+ }
+
+ f, err := transformDocument(coll.registry, filter)
+ if err != nil {
+ return &SingleResult{err: err}
+ }
+
+ sess := sessionFromContext(ctx)
+
+ err = coll.client.ValidSession(sess)
+ if err != nil {
+ return &SingleResult{err: err}
+ }
+
+ oldns := coll.namespace()
+ wc := coll.writeConcern
+ if sess != nil && sess.TransactionRunning() {
+ wc = nil
+ }
+
+ cmd := command.FindOneAndDelete{
+ NS: command.Namespace{DB: oldns.DB, Collection: oldns.Collection},
+ Query: f,
+ WriteConcern: wc,
+ Session: sess,
+ Clock: coll.client.clock,
+ }
+
+ res, err := driver.FindOneAndDelete(
+ ctx, cmd,
+ coll.client.topology,
+ coll.writeSelector,
+ coll.client.id,
+ coll.client.topology.SessionPool,
+ coll.client.retryWrites,
+ coll.registry,
+ opts...,
+ )
+ if err != nil {
+ return &SingleResult{err: replaceTopologyErr(err)}
+ }
+
+ return &SingleResult{rdr: res.Value, reg: coll.registry}
+}
+
+// FindOneAndReplace finds a single document and replaces it, returning either
+// the original or the replaced document.
+func (coll *Collection) FindOneAndReplace(ctx context.Context, filter interface{},
+ replacement interface{}, opts ...*options.FindOneAndReplaceOptions) *SingleResult {
+
+ if ctx == nil {
+ ctx = context.Background()
+ }
+
+ f, err := transformDocument(coll.registry, filter)
+ if err != nil {
+ return &SingleResult{err: err}
+ }
+
+ r, err := transformDocument(coll.registry, replacement)
+ if err != nil {
+ return &SingleResult{err: err}
+ }
+
+ if len(r) > 0 && strings.HasPrefix(r[0].Key, "$") {
+ return &SingleResult{err: errors.New("replacement document cannot contains keys beginning with '$")}
+ }
+
+ sess := sessionFromContext(ctx)
+
+ err = coll.client.ValidSession(sess)
+ if err != nil {
+ return &SingleResult{err: err}
+ }
+
+ wc := coll.writeConcern
+ if sess != nil && sess.TransactionRunning() {
+ wc = nil
+ }
+
+ oldns := coll.namespace()
+ cmd := command.FindOneAndReplace{
+ NS: command.Namespace{DB: oldns.DB, Collection: oldns.Collection},
+ Query: f,
+ Replacement: r,
+ WriteConcern: wc,
+ Session: sess,
+ Clock: coll.client.clock,
+ }
+
+ res, err := driver.FindOneAndReplace(
+ ctx, cmd,
+ coll.client.topology,
+ coll.writeSelector,
+ coll.client.id,
+ coll.client.topology.SessionPool,
+ coll.client.retryWrites,
+ coll.registry,
+ opts...,
+ )
+ if err != nil {
+ return &SingleResult{err: replaceTopologyErr(err)}
+ }
+
+ return &SingleResult{rdr: res.Value, reg: coll.registry}
+}
+
+// FindOneAndUpdate finds a single document and updates it, returning either
+// the original or the updated.
+func (coll *Collection) FindOneAndUpdate(ctx context.Context, filter interface{},
+ update interface{}, opts ...*options.FindOneAndUpdateOptions) *SingleResult {
+
+ if ctx == nil {
+ ctx = context.Background()
+ }
+
+ f, err := transformDocument(coll.registry, filter)
+ if err != nil {
+ return &SingleResult{err: err}
+ }
+
+ u, err := transformDocument(coll.registry, update)
+ if err != nil {
+ return &SingleResult{err: err}
+ }
+
+ err = ensureDollarKey(u)
+ if err != nil {
+ return &SingleResult{
+ err: err,
+ }
+ }
+
+ sess := sessionFromContext(ctx)
+
+ err = coll.client.ValidSession(sess)
+ if err != nil {
+ return &SingleResult{err: err}
+ }
+
+ wc := coll.writeConcern
+ if sess != nil && sess.TransactionRunning() {
+ wc = nil
+ }
+
+ oldns := coll.namespace()
+ cmd := command.FindOneAndUpdate{
+ NS: command.Namespace{DB: oldns.DB, Collection: oldns.Collection},
+ Query: f,
+ Update: u,
+ WriteConcern: wc,
+ Session: sess,
+ Clock: coll.client.clock,
+ }
+
+ res, err := driver.FindOneAndUpdate(
+ ctx, cmd,
+ coll.client.topology,
+ coll.writeSelector,
+ coll.client.id,
+ coll.client.topology.SessionPool,
+ coll.client.retryWrites,
+ coll.registry,
+ opts...,
+ )
+ if err != nil {
+ return &SingleResult{err: replaceTopologyErr(err)}
+ }
+
+ return &SingleResult{rdr: res.Value, reg: coll.registry}
+}
+
+// Watch returns a change stream cursor used to receive notifications of changes to the collection.
+//
+// This method is preferred to running a raw aggregation with a $changeStream stage because it
+// supports resumability in the case of some errors. The collection must have read concern majority or no read concern
+// for a change stream to be created successfully.
+func (coll *Collection) Watch(ctx context.Context, pipeline interface{},
+ opts ...*options.ChangeStreamOptions) (*ChangeStream, error) {
+ return newChangeStream(ctx, coll, pipeline, opts...)
+}
+
+// Indexes returns the index view for this collection.
+func (coll *Collection) Indexes() IndexView {
+ return IndexView{coll: coll}
+}
+
+// Drop drops this collection from database.
+func (coll *Collection) Drop(ctx context.Context) error {
+ if ctx == nil {
+ ctx = context.Background()
+ }
+
+ sess := sessionFromContext(ctx)
+
+ err := coll.client.ValidSession(sess)
+ if err != nil {
+ return err
+ }
+
+ wc := coll.writeConcern
+ if sess != nil && sess.TransactionRunning() {
+ wc = nil
+ }
+
+ cmd := command.DropCollection{
+ DB: coll.db.name,
+ Collection: coll.name,
+ WriteConcern: wc,
+ Session: sess,
+ Clock: coll.client.clock,
+ }
+ _, err = driver.DropCollection(
+ ctx, cmd,
+ coll.client.topology,
+ coll.writeSelector,
+ coll.client.id,
+ coll.client.topology.SessionPool,
+ )
+ if err != nil && !command.IsNotFound(err) {
+ return replaceTopologyErr(err)
+ }
+ return nil
+}
diff --git a/vendor/github.com/mongodb/mongo-go-driver/mongo/cursor.go b/vendor/github.com/mongodb/mongo-go-driver/mongo/cursor.go
new file mode 100644
index 0000000..a9dc13d
--- /dev/null
+++ b/vendor/github.com/mongodb/mongo-go-driver/mongo/cursor.go
@@ -0,0 +1,137 @@
+// Copyright (C) MongoDB, Inc. 2017-present.
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+
+package mongo
+
+import (
+ "context"
+ "errors"
+
+ "github.com/mongodb/mongo-go-driver/bson"
+ "github.com/mongodb/mongo-go-driver/bson/bsoncodec"
+ "github.com/mongodb/mongo-go-driver/x/mongo/driver"
+)
+
+// Cursor is used to iterate a stream of documents. Each document is decoded into the result
+// according to the rules of the bson package.
+//
+// A typical usage of the Cursor type would be:
+//
+// var cur *Cursor
+// ctx := context.Background()
+// defer cur.Close(ctx)
+//
+// for cur.Next(ctx) {
+// elem := &bson.D{}
+// if err := cur.Decode(elem); err != nil {
+// log.Fatal(err)
+// }
+//
+// // do something with elem....
+// }
+//
+// if err := cur.Err(); err != nil {
+// log.Fatal(err)
+// }
+//
+type Cursor struct {
+ // Current is the BSON bytes of the current document. This property is only valid until the next
+ // call to Next or Close. If continued access is required to the bson.Raw, you must make a copy
+ // of it.
+ Current bson.Raw
+
+ bc batchCursor
+ pos int
+ batch []byte
+ registry *bsoncodec.Registry
+
+ err error
+}
+
+func newCursor(bc batchCursor, registry *bsoncodec.Registry) (*Cursor, error) {
+ if registry == nil {
+ registry = bson.DefaultRegistry
+ }
+ if bc == nil {
+ return nil, errors.New("batch cursor must not be nil")
+ }
+ return &Cursor{bc: bc, pos: 0, batch: make([]byte, 0, 256), registry: registry}, nil
+}
+
+func newEmptyCursor() *Cursor {
+ return &Cursor{bc: driver.NewEmptyBatchCursor()}
+}
+
+// ID returns the ID of this cursor.
+func (c *Cursor) ID() int64 { return c.bc.ID() }
+
+func (c *Cursor) advanceCurrentDocument() bool {
+ if len(c.batch[c.pos:]) < 4 {
+ c.err = errors.New("could not read next document: insufficient bytes")
+ return false
+ }
+ length := (int(c.batch[c.pos]) | int(c.batch[c.pos+1])<<8 | int(c.batch[c.pos+2])<<16 | int(c.batch[c.pos+3])<<24)
+ if len(c.batch[c.pos:]) < length {
+ c.err = errors.New("could not read next document: insufficient bytes")
+ return false
+ }
+ if len(c.Current) > 4 {
+ c.Current[0], c.Current[1], c.Current[2], c.Current[3] = 0x00, 0x00, 0x00, 0x00 // Invalidate the current document
+ }
+ c.Current = c.batch[c.pos : c.pos+length]
+ c.pos += length
+ return true
+}
+
+// Next gets the next result from this cursor. Returns true if there were no errors and the next
+// result is available for decoding.
+func (c *Cursor) Next(ctx context.Context) bool {
+ if ctx == nil {
+ ctx = context.Background()
+ }
+ if c.pos < len(c.batch) {
+ return c.advanceCurrentDocument()
+ }
+
+ // clear the batch
+ c.batch = c.batch[:0]
+ c.pos = 0
+ c.Current = c.Current[:0]
+
+ // call the Next method in a loop until at least one document is returned in the next batch or
+ // the context times out.
+ for len(c.batch) == 0 {
+ // If we don't have a next batch
+ if !c.bc.Next(ctx) {
+ // Do we have an error? If so we return false.
+ c.err = c.bc.Err()
+ if c.err != nil {
+ return false
+ }
+ // Is the cursor ID zero?
+ if c.bc.ID() == 0 {
+ return false
+ }
+ // empty batch, but cursor is still valid, so continue.
+ continue
+ }
+
+ c.batch = c.bc.Batch(c.batch[:0])
+ }
+
+ return c.advanceCurrentDocument()
+}
+
+// Decode will decode the current document into val.
+func (c *Cursor) Decode(val interface{}) error {
+ return bson.UnmarshalWithRegistry(c.registry, c.Current, val)
+}
+
+// Err returns the current error.
+func (c *Cursor) Err() error { return c.err }
+
+// Close closes this cursor.
+func (c *Cursor) Close(ctx context.Context) error { return c.bc.Close(ctx) }
diff --git a/vendor/github.com/mongodb/mongo-go-driver/mongo/database.go b/vendor/github.com/mongodb/mongo-go-driver/mongo/database.go
new file mode 100644
index 0000000..9575e06
--- /dev/null
+++ b/vendor/github.com/mongodb/mongo-go-driver/mongo/database.go
@@ -0,0 +1,282 @@
+// Copyright (C) MongoDB, Inc. 2017-present.
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+
+package mongo
+
+import (
+ "context"
+
+ "github.com/mongodb/mongo-go-driver/bson/bsoncodec"
+ "github.com/mongodb/mongo-go-driver/mongo/options"
+ "github.com/mongodb/mongo-go-driver/mongo/readconcern"
+ "github.com/mongodb/mongo-go-driver/mongo/readpref"
+ "github.com/mongodb/mongo-go-driver/mongo/writeconcern"
+ "github.com/mongodb/mongo-go-driver/x/mongo/driver"
+ "github.com/mongodb/mongo-go-driver/x/network/command"
+ "github.com/mongodb/mongo-go-driver/x/network/description"
+)
+
+// Database performs operations on a given database.
+type Database struct {
+ client *Client
+ name string
+ readConcern *readconcern.ReadConcern
+ writeConcern *writeconcern.WriteConcern
+ readPreference *readpref.ReadPref
+ readSelector description.ServerSelector
+ writeSelector description.ServerSelector
+ registry *bsoncodec.Registry
+}
+
+func newDatabase(client *Client, name string, opts ...*options.DatabaseOptions) *Database {
+ dbOpt := options.MergeDatabaseOptions(opts...)
+
+ rc := client.readConcern
+ if dbOpt.ReadConcern != nil {
+ rc = dbOpt.ReadConcern
+ }
+
+ rp := client.readPreference
+ if dbOpt.ReadPreference != nil {
+ rp = dbOpt.ReadPreference
+ }
+
+ wc := client.writeConcern
+ if dbOpt.WriteConcern != nil {
+ wc = dbOpt.WriteConcern
+ }
+
+ db := &Database{
+ client: client,
+ name: name,
+ readPreference: rp,
+ readConcern: rc,
+ writeConcern: wc,
+ registry: client.registry,
+ }
+
+ db.readSelector = description.CompositeSelector([]description.ServerSelector{
+ description.ReadPrefSelector(db.readPreference),
+ description.LatencySelector(db.client.localThreshold),
+ })
+
+ db.writeSelector = description.CompositeSelector([]description.ServerSelector{
+ description.WriteSelector(),
+ description.LatencySelector(db.client.localThreshold),
+ })
+
+ return db
+}
+
+// Client returns the Client the database was created from.
+func (db *Database) Client() *Client {
+ return db.client
+}
+
+// Name returns the name of the database.
+func (db *Database) Name() string {
+ return db.name
+}
+
+// Collection gets a handle for a given collection in the database.
+func (db *Database) Collection(name string, opts ...*options.CollectionOptions) *Collection {
+ return newCollection(db, name, opts...)
+}
+
+func (db *Database) processRunCommand(ctx context.Context, cmd interface{}, opts ...*options.RunCmdOptions) (command.Read,
+ description.ServerSelector, error) {
+
+ if ctx == nil {
+ ctx = context.Background()
+ }
+
+ sess := sessionFromContext(ctx)
+ runCmd := options.MergeRunCmdOptions(opts...)
+
+ if err := db.client.ValidSession(sess); err != nil {
+ return command.Read{}, nil, err
+ }
+
+ rp := runCmd.ReadPreference
+ if rp == nil {
+ if sess != nil && sess.TransactionRunning() {
+ rp = sess.CurrentRp // override with transaction read pref if specified
+ }
+ if rp == nil {
+ rp = readpref.Primary() // set to primary if nothing specified in options
+ }
+ }
+
+ runCmdDoc, err := transformDocument(db.registry, cmd)
+ if err != nil {
+ return command.Read{}, nil, err
+ }
+
+ readSelect := description.CompositeSelector([]description.ServerSelector{
+ description.ReadPrefSelector(rp),
+ description.LatencySelector(db.client.localThreshold),
+ })
+
+ return command.Read{
+ DB: db.Name(),
+ Command: runCmdDoc,
+ ReadPref: rp,
+ Session: sess,
+ Clock: db.client.clock,
+ }, readSelect, nil
+}
+
+// RunCommand runs a command on the database. A user can supply a custom
+// context to this method, or nil to default to context.Background().
+func (db *Database) RunCommand(ctx context.Context, runCommand interface{}, opts ...*options.RunCmdOptions) *SingleResult {
+ if ctx == nil {
+ ctx = context.Background()
+ }
+
+ readCmd, readSelect, err := db.processRunCommand(ctx, runCommand, opts...)
+ if err != nil {
+ return &SingleResult{err: err}
+ }
+
+ doc, err := driver.Read(ctx,
+ readCmd,
+ db.client.topology,
+ readSelect,
+ db.client.id,
+ db.client.topology.SessionPool,
+ )
+
+ return &SingleResult{err: replaceTopologyErr(err), rdr: doc, reg: db.registry}
+}
+
+// RunCommandCursor runs a command on the database and returns a cursor over the resulting reader. A user can supply
+// a custom context to this method, or nil to default to context.Background().
+func (db *Database) RunCommandCursor(ctx context.Context, runCommand interface{}, opts ...*options.RunCmdOptions) (*Cursor, error) {
+ if ctx == nil {
+ ctx = context.Background()
+ }
+
+ readCmd, readSelect, err := db.processRunCommand(ctx, runCommand, opts...)
+ if err != nil {
+ return nil, err
+ }
+
+ batchCursor, err := driver.ReadCursor(
+ ctx,
+ readCmd,
+ db.client.topology,
+ readSelect,
+ db.client.id,
+ db.client.topology.SessionPool,
+ )
+ if err != nil {
+ return nil, replaceTopologyErr(err)
+ }
+
+ cursor, err := newCursor(batchCursor, db.registry)
+ return cursor, replaceTopologyErr(err)
+}
+
+// Drop drops this database from mongodb.
+func (db *Database) Drop(ctx context.Context) error {
+ if ctx == nil {
+ ctx = context.Background()
+ }
+
+ sess := sessionFromContext(ctx)
+
+ err := db.client.ValidSession(sess)
+ if err != nil {
+ return err
+ }
+
+ cmd := command.DropDatabase{
+ DB: db.name,
+ Session: sess,
+ Clock: db.client.clock,
+ }
+ _, err = driver.DropDatabase(
+ ctx, cmd,
+ db.client.topology,
+ db.writeSelector,
+ db.client.id,
+ db.client.topology.SessionPool,
+ )
+ if err != nil && !command.IsNotFound(err) {
+ return replaceTopologyErr(err)
+ }
+ return nil
+}
+
+// ListCollections list collections from mongodb database.
+func (db *Database) ListCollections(ctx context.Context, filter interface{}, opts ...*options.ListCollectionsOptions) (*Cursor, error) {
+ if ctx == nil {
+ ctx = context.Background()
+ }
+
+ sess := sessionFromContext(ctx)
+
+ err := db.client.ValidSession(sess)
+ if err != nil {
+ return nil, err
+ }
+
+ filterDoc, err := transformDocument(db.registry, filter)
+ if err != nil {
+ return nil, err
+ }
+
+ cmd := command.ListCollections{
+ DB: db.name,
+ Filter: filterDoc,
+ ReadPref: readpref.Primary(), // list collections must be run on a primary by default
+ Session: sess,
+ Clock: db.client.clock,
+ }
+
+ readSelector := description.CompositeSelector([]description.ServerSelector{
+ description.ReadPrefSelector(readpref.Primary()),
+ description.LatencySelector(db.client.localThreshold),
+ })
+ batchCursor, err := driver.ListCollections(
+ ctx, cmd,
+ db.client.topology,
+ readSelector,
+ db.client.id,
+ db.client.topology.SessionPool,
+ opts...,
+ )
+ if err != nil {
+ return nil, replaceTopologyErr(err)
+ }
+
+ cursor, err := newCursor(batchCursor, db.registry)
+ return cursor, replaceTopologyErr(err)
+}
+
+// ReadConcern returns the read concern of this database.
+func (db *Database) ReadConcern() *readconcern.ReadConcern {
+ return db.readConcern
+}
+
+// ReadPreference returns the read preference of this database.
+func (db *Database) ReadPreference() *readpref.ReadPref {
+ return db.readPreference
+}
+
+// WriteConcern returns the write concern of this database.
+func (db *Database) WriteConcern() *writeconcern.WriteConcern {
+ return db.writeConcern
+}
+
+// Watch returns a change stream cursor used to receive information of changes to the database. This method is preferred
+// to running a raw aggregation with a $changeStream stage because it supports resumability in the case of some errors.
+// The database must have read concern majority or no read concern for a change stream to be created successfully.
+func (db *Database) Watch(ctx context.Context, pipeline interface{},
+ opts ...*options.ChangeStreamOptions) (*ChangeStream, error) {
+
+ return newDbChangeStream(ctx, db, pipeline, opts...)
+}
diff --git a/vendor/github.com/mongodb/mongo-go-driver/mongo/doc.go b/vendor/github.com/mongodb/mongo-go-driver/mongo/doc.go
new file mode 100644
index 0000000..4f7f819
--- /dev/null
+++ b/vendor/github.com/mongodb/mongo-go-driver/mongo/doc.go
@@ -0,0 +1,60 @@
+// Copyright (C) MongoDB, Inc. 2017-present.
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+
+// NOTE: This documentation should be kept in line with the Example* test functions.
+
+// Package mongo provides a MongoDB Driver API for Go.
+//
+// Basic usage of the driver starts with creating a Client from a connection
+// string. To do so, call the NewClient and Connect functions:
+//
+// client, err := NewClient("mongodb://foo:bar@localhost:27017")
+// if err != nil { return err }
+// ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second)
+// defer cancel()
+// err = client.Connect(ctx)
+// if err != nil { return err }
+//
+// This will create a new client and start monitoring the MongoDB server on localhost.
+// The Database and Collection types can be used to access the database:
+//
+// collection := client.Database("baz").Collection("qux")
+//
+// A Collection can be used to query the database or insert documents:
+//
+// res, err := collection.InsertOne(context.Background(), bson.M{"hello": "world"})
+// if err != nil { return err }
+// id := res.InsertedID
+//
+// Several methods return a cursor, which can be used like this:
+//
+// cur, err := collection.Find(context.Background(), bson.D{})
+// if err != nil { log.Fatal(err) }
+// defer cur.Close(context.Background())
+// for cur.Next(context.Background()) {
+// raw, err := cur.DecodeBytes()
+// if err != nil { log.Fatal(err) }
+// // do something with elem....
+// }
+// if err := cur.Err(); err != nil {
+// return err
+// }
+//
+// Methods that only return a single document will return a *SingleResult, which works
+// like a *sql.Row:
+//
+// result := struct{
+// Foo string
+// Bar int32
+// }{}
+// filter := bson.D{{"hello", "world"}}
+// err := collection.FindOne(context.Background(), filter).Decode(&result)
+// if err != nil { return err }
+// // do something with result...
+//
+// Additional examples can be found under the examples directory in the driver's repository and
+// on the MongoDB website.
+package mongo
diff --git a/vendor/github.com/mongodb/mongo-go-driver/mongo/errors.go b/vendor/github.com/mongodb/mongo-go-driver/mongo/errors.go
new file mode 100644
index 0000000..3505bcc
--- /dev/null
+++ b/vendor/github.com/mongodb/mongo-go-driver/mongo/errors.go
@@ -0,0 +1,186 @@
+// Copyright (C) MongoDB, Inc. 2017-present.
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+
+package mongo
+
+import (
+ "bytes"
+ "errors"
+ "fmt"
+
+ "github.com/mongodb/mongo-go-driver/bson"
+ "github.com/mongodb/mongo-go-driver/x/mongo/driver"
+ "github.com/mongodb/mongo-go-driver/x/mongo/driver/topology"
+ "github.com/mongodb/mongo-go-driver/x/network/command"
+ "github.com/mongodb/mongo-go-driver/x/network/result"
+)
+
+// ErrUnacknowledgedWrite is returned from functions that have an unacknowledged
+// write concern.
+var ErrUnacknowledgedWrite = errors.New("unacknowledged write")
+
+// ErrClientDisconnected is returned when a user attempts to call a method on a
+// disconnected client
+var ErrClientDisconnected = errors.New("client is disconnected")
+
+// ErrNilDocument is returned when a user attempts to pass a nil document or filter
+// to a function where the field is required.
+var ErrNilDocument = errors.New("document is nil")
+
+// ErrEmptySlice is returned when a user attempts to pass an empty slice as input
+// to a function wehere the field is required.
+var ErrEmptySlice = errors.New("must provide at least one element in input slice")
+
+func replaceTopologyErr(err error) error {
+ if err == topology.ErrTopologyClosed {
+ return ErrClientDisconnected
+ }
+ return err
+}
+
+// WriteError is a non-write concern failure that occurred as a result of a write
+// operation.
+type WriteError struct {
+ Index int
+ Code int
+ Message string
+}
+
+func (we WriteError) Error() string { return we.Message }
+
+// WriteErrors is a group of non-write concern failures that occurred as a result
+// of a write operation.
+type WriteErrors []WriteError
+
+func (we WriteErrors) Error() string {
+ var buf bytes.Buffer
+ fmt.Fprint(&buf, "write errors: [")
+ for idx, err := range we {
+ if idx != 0 {
+ fmt.Fprintf(&buf, ", ")
+ }
+ fmt.Fprintf(&buf, "{%s}", err)
+ }
+ fmt.Fprint(&buf, "]")
+ return buf.String()
+}
+
+func writeErrorsFromResult(rwes []result.WriteError) WriteErrors {
+ wes := make(WriteErrors, 0, len(rwes))
+ for _, err := range rwes {
+ wes = append(wes, WriteError{Index: err.Index, Code: err.Code, Message: err.ErrMsg})
+ }
+ return wes
+}
+
+// WriteConcernError is a write concern failure that occurred as a result of a
+// write operation.
+type WriteConcernError struct {
+ Code int
+ Message string
+ Details bson.Raw
+}
+
+func (wce WriteConcernError) Error() string { return wce.Message }
+
+// WriteException is an error for a non-bulk write operation.
+type WriteException struct {
+ WriteConcernError *WriteConcernError
+ WriteErrors WriteErrors
+}
+
+func (mwe WriteException) Error() string {
+ var buf bytes.Buffer
+ fmt.Fprint(&buf, "multiple write errors: [")
+ fmt.Fprintf(&buf, "{%s}, ", mwe.WriteErrors)
+ fmt.Fprintf(&buf, "{%s}]", mwe.WriteConcernError)
+ return buf.String()
+}
+
+func convertBulkWriteErrors(errors []driver.BulkWriteError) []BulkWriteError {
+ bwErrors := make([]BulkWriteError, 0, len(errors))
+ for _, err := range errors {
+ bwErrors = append(bwErrors, BulkWriteError{
+ WriteError{
+ Index: err.Index,
+ Code: err.Code,
+ Message: err.ErrMsg,
+ },
+ dispatchToMongoModel(err.Model),
+ })
+ }
+
+ return bwErrors
+}
+
+func convertWriteConcernError(wce *result.WriteConcernError) *WriteConcernError {
+ if wce == nil {
+ return nil
+ }
+
+ return &WriteConcernError{Code: wce.Code, Message: wce.ErrMsg, Details: wce.ErrInfo}
+}
+
+// BulkWriteError is an error for one operation in a bulk write.
+type BulkWriteError struct {
+ WriteError
+ Request WriteModel
+}
+
+func (bwe BulkWriteError) Error() string {
+ var buf bytes.Buffer
+ fmt.Fprintf(&buf, "{%s}", bwe.WriteError)
+ return buf.String()
+}
+
+// BulkWriteException is an error for a bulk write operation.
+type BulkWriteException struct {
+ WriteConcernError *WriteConcernError
+ WriteErrors []BulkWriteError
+}
+
+func (bwe BulkWriteException) Error() string {
+ var buf bytes.Buffer
+ fmt.Fprint(&buf, "bulk write error: [")
+ fmt.Fprintf(&buf, "{%s}, ", bwe.WriteErrors)
+ fmt.Fprintf(&buf, "{%s}]", bwe.WriteConcernError)
+ return buf.String()
+}
+
+// returnResult is used to determine if a function calling processWriteError should return
+// the result or return nil. Since the processWriteError function is used by many different
+// methods, both *One and *Many, we need a way to differentiate if the method should return
+// the result and the error.
+type returnResult int
+
+const (
+ rrNone returnResult = 1 << iota // None means do not return the result ever.
+ rrOne // One means return the result if this was called by a *One method.
+ rrMany // Many means return the result is this was called by a *Many method.
+
+ rrAll returnResult = rrOne | rrMany // All means always return the result.
+)
+
+// processWriteError handles processing the result of a write operation. If the retrunResult matches
+// the calling method's type, it should return the result object in addition to the error.
+// This function will wrap the errors from other packages and return them as errors from this package.
+//
+// WriteConcernError will be returned over WriteErrors if both are present.
+func processWriteError(wce *result.WriteConcernError, wes []result.WriteError, err error) (returnResult, error) {
+ switch {
+ case err == command.ErrUnacknowledgedWrite:
+ return rrAll, ErrUnacknowledgedWrite
+ case err != nil:
+ return rrNone, replaceTopologyErr(err)
+ case wce != nil || len(wes) > 0:
+ return rrMany, WriteException{
+ WriteConcernError: convertWriteConcernError(wce),
+ WriteErrors: writeErrorsFromResult(wes),
+ }
+ default:
+ return rrAll, nil
+ }
+}
diff --git a/vendor/github.com/mongodb/mongo-go-driver/mongo/index_options_builder.go b/vendor/github.com/mongodb/mongo-go-driver/mongo/index_options_builder.go
new file mode 100644
index 0000000..abc1514
--- /dev/null
+++ b/vendor/github.com/mongodb/mongo-go-driver/mongo/index_options_builder.go
@@ -0,0 +1,134 @@
+// Copyright (C) MongoDB, Inc. 2017-present.
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+
+package mongo
+
+import (
+ "github.com/mongodb/mongo-go-driver/bson"
+)
+
+// IndexOptionsBuilder constructs a BSON document for index options
+type IndexOptionsBuilder struct {
+ document bson.D
+}
+
+// NewIndexOptionsBuilder creates a new instance of IndexOptionsBuilder
+func NewIndexOptionsBuilder() *IndexOptionsBuilder {
+ return &IndexOptionsBuilder{}
+}
+
+// Background sets the background option
+func (iob *IndexOptionsBuilder) Background(background bool) *IndexOptionsBuilder {
+ iob.document = append(iob.document, bson.E{"background", background})
+ return iob
+}
+
+// ExpireAfterSeconds sets the expireAfterSeconds option
+func (iob *IndexOptionsBuilder) ExpireAfterSeconds(expireAfterSeconds int32) *IndexOptionsBuilder {
+ iob.document = append(iob.document, bson.E{"expireAfterSeconds", expireAfterSeconds})
+ return iob
+}
+
+// Name sets the name option
+func (iob *IndexOptionsBuilder) Name(name string) *IndexOptionsBuilder {
+ iob.document = append(iob.document, bson.E{"name", name})
+ return iob
+}
+
+// Sparse sets the sparse option
+func (iob *IndexOptionsBuilder) Sparse(sparse bool) *IndexOptionsBuilder {
+ iob.document = append(iob.document, bson.E{"sparse", sparse})
+ return iob
+}
+
+// StorageEngine sets the storageEngine option
+func (iob *IndexOptionsBuilder) StorageEngine(storageEngine interface{}) *IndexOptionsBuilder {
+ iob.document = append(iob.document, bson.E{"storageEngine", storageEngine})
+ return iob
+}
+
+// Unique sets the unique option
+func (iob *IndexOptionsBuilder) Unique(unique bool) *IndexOptionsBuilder {
+ iob.document = append(iob.document, bson.E{"unique", unique})
+ return iob
+}
+
+// Version sets the version option
+func (iob *IndexOptionsBuilder) Version(version int32) *IndexOptionsBuilder {
+ iob.document = append(iob.document, bson.E{"v", version})
+ return iob
+}
+
+// DefaultLanguage sets the defaultLanguage option
+func (iob *IndexOptionsBuilder) DefaultLanguage(defaultLanguage string) *IndexOptionsBuilder {
+ iob.document = append(iob.document, bson.E{"default_language", defaultLanguage})
+ return iob
+}
+
+// LanguageOverride sets the languageOverride option
+func (iob *IndexOptionsBuilder) LanguageOverride(languageOverride string) *IndexOptionsBuilder {
+ iob.document = append(iob.document, bson.E{"language_override", languageOverride})
+ return iob
+}
+
+// TextVersion sets the textVersion option
+func (iob *IndexOptionsBuilder) TextVersion(textVersion int32) *IndexOptionsBuilder {
+ iob.document = append(iob.document, bson.E{"textIndexVersion", textVersion})
+ return iob
+}
+
+// Weights sets the weights option
+func (iob *IndexOptionsBuilder) Weights(weights interface{}) *IndexOptionsBuilder {
+ iob.document = append(iob.document, bson.E{"weights", weights})
+ return iob
+}
+
+// SphereVersion sets the sphereVersion option
+func (iob *IndexOptionsBuilder) SphereVersion(sphereVersion int32) *IndexOptionsBuilder {
+ iob.document = append(iob.document, bson.E{"2dsphereIndexVersion", sphereVersion})
+ return iob
+}
+
+// Bits sets the bits option
+func (iob *IndexOptionsBuilder) Bits(bits int32) *IndexOptionsBuilder {
+ iob.document = append(iob.document, bson.E{"bits", bits})
+ return iob
+}
+
+// Max sets the max option
+func (iob *IndexOptionsBuilder) Max(max float64) *IndexOptionsBuilder {
+ iob.document = append(iob.document, bson.E{"max", max})
+ return iob
+}
+
+// Min sets the min option
+func (iob *IndexOptionsBuilder) Min(min float64) *IndexOptionsBuilder {
+ iob.document = append(iob.document, bson.E{"min", min})
+ return iob
+}
+
+// BucketSize sets the bucketSize option
+func (iob *IndexOptionsBuilder) BucketSize(bucketSize int32) *IndexOptionsBuilder {
+ iob.document = append(iob.document, bson.E{"bucketSize", bucketSize})
+ return iob
+}
+
+// PartialFilterExpression sets the partialFilterExpression option
+func (iob *IndexOptionsBuilder) PartialFilterExpression(partialFilterExpression interface{}) *IndexOptionsBuilder {
+ iob.document = append(iob.document, bson.E{"partialFilterExpression", partialFilterExpression})
+ return iob
+}
+
+// Collation sets the collation option
+func (iob *IndexOptionsBuilder) Collation(collation interface{}) *IndexOptionsBuilder {
+ iob.document = append(iob.document, bson.E{"collation", collation})
+ return iob
+}
+
+// Build returns the BSON document from the builder
+func (iob *IndexOptionsBuilder) Build() bson.D {
+ return iob.document
+}
diff --git a/vendor/github.com/mongodb/mongo-go-driver/mongo/index_view.go b/vendor/github.com/mongodb/mongo-go-driver/mongo/index_view.go
new file mode 100644
index 0000000..1ff8d49
--- /dev/null
+++ b/vendor/github.com/mongodb/mongo-go-driver/mongo/index_view.go
@@ -0,0 +1,343 @@
+// Copyright (C) MongoDB, Inc. 2017-present.
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+
+package mongo
+
+import (
+ "bytes"
+ "context"
+ "errors"
+ "fmt"
+
+ "github.com/mongodb/mongo-go-driver/bson"
+ "github.com/mongodb/mongo-go-driver/bson/bsoncodec"
+ "github.com/mongodb/mongo-go-driver/bson/bsontype"
+ "github.com/mongodb/mongo-go-driver/mongo/options"
+ "github.com/mongodb/mongo-go-driver/mongo/readpref"
+ "github.com/mongodb/mongo-go-driver/x/bsonx"
+ "github.com/mongodb/mongo-go-driver/x/mongo/driver"
+ "github.com/mongodb/mongo-go-driver/x/network/command"
+ "github.com/mongodb/mongo-go-driver/x/network/description"
+)
+
+// ErrInvalidIndexValue indicates that the index Keys document has a value that isn't either a number or a string.
+var ErrInvalidIndexValue = errors.New("invalid index value")
+
+// ErrNonStringIndexName indicates that the index name specified in the options is not a string.
+var ErrNonStringIndexName = errors.New("index name must be a string")
+
+// ErrMultipleIndexDrop indicates that multiple indexes would be dropped from a call to IndexView.DropOne.
+var ErrMultipleIndexDrop = errors.New("multiple indexes would be dropped")
+
+// IndexView is used to create, drop, and list indexes on a given collection.
+type IndexView struct {
+ coll *Collection
+}
+
+// IndexModel contains information about an index.
+type IndexModel struct {
+ Keys interface{}
+ Options *options.IndexOptions
+}
+
+// List returns a cursor iterating over all the indexes in the collection.
+func (iv IndexView) List(ctx context.Context, opts ...*options.ListIndexesOptions) (*Cursor, error) {
+ sess := sessionFromContext(ctx)
+
+ err := iv.coll.client.ValidSession(sess)
+ if err != nil {
+ return nil, err
+ }
+
+ listCmd := command.ListIndexes{
+ NS: iv.coll.namespace(),
+ Session: sess,
+ Clock: iv.coll.client.clock,
+ }
+
+ readSelector := description.CompositeSelector([]description.ServerSelector{
+ description.ReadPrefSelector(readpref.Primary()),
+ description.LatencySelector(iv.coll.client.localThreshold),
+ })
+ batchCursor, err := driver.ListIndexes(
+ ctx, listCmd,
+ iv.coll.client.topology,
+ readSelector,
+ iv.coll.client.id,
+ iv.coll.client.topology.SessionPool,
+ opts...,
+ )
+ if err != nil {
+ if err == command.ErrEmptyCursor {
+ return newEmptyCursor(), nil
+ }
+ return nil, replaceTopologyErr(err)
+ }
+
+ cursor, err := newCursor(batchCursor, iv.coll.registry)
+ return cursor, replaceTopologyErr(err)
+}
+
+// CreateOne creates a single index in the collection specified by the model.
+func (iv IndexView) CreateOne(ctx context.Context, model IndexModel, opts ...*options.CreateIndexesOptions) (string, error) {
+ names, err := iv.CreateMany(ctx, []IndexModel{model}, opts...)
+ if err != nil {
+ return "", err
+ }
+
+ return names[0], nil
+}
+
+// CreateMany creates multiple indexes in the collection specified by the models. The names of the
+// creates indexes are returned.
+func (iv IndexView) CreateMany(ctx context.Context, models []IndexModel, opts ...*options.CreateIndexesOptions) ([]string, error) {
+ names := make([]string, 0, len(models))
+ indexes := bsonx.Arr{}
+
+ for _, model := range models {
+ if model.Keys == nil {
+ return nil, fmt.Errorf("index model keys cannot be nil")
+ }
+
+ name, err := getOrGenerateIndexName(iv.coll.registry, model)
+ if err != nil {
+ return nil, err
+ }
+
+ names = append(names, name)
+
+ keys, err := transformDocument(iv.coll.registry, model.Keys)
+ if err != nil {
+ return nil, err
+ }
+ index := bsonx.Doc{{"key", bsonx.Document(keys)}}
+ if model.Options != nil {
+ optsDoc, err := iv.createOptionsDoc(model.Options)
+ if err != nil {
+ return nil, err
+ }
+
+ index = append(index, optsDoc...)
+ }
+ index = index.Set("name", bsonx.String(name))
+
+ indexes = append(indexes, bsonx.Document(index))
+ }
+
+ sess := sessionFromContext(ctx)
+
+ err := iv.coll.client.ValidSession(sess)
+ if err != nil {
+ return nil, err
+ }
+
+ cmd := command.CreateIndexes{
+ NS: iv.coll.namespace(),
+ Indexes: indexes,
+ Session: sess,
+ Clock: iv.coll.client.clock,
+ }
+
+ _, err = driver.CreateIndexes(
+ ctx, cmd,
+ iv.coll.client.topology,
+ iv.coll.writeSelector,
+ iv.coll.client.id,
+ iv.coll.client.topology.SessionPool,
+ opts...,
+ )
+ if err != nil {
+ return nil, err
+ }
+
+ return names, nil
+}
+
+func (iv IndexView) createOptionsDoc(opts *options.IndexOptions) (bsonx.Doc, error) {
+ optsDoc := bsonx.Doc{}
+ if opts.Background != nil {
+ optsDoc = append(optsDoc, bsonx.Elem{"background", bsonx.Boolean(*opts.Background)})
+ }
+ if opts.ExpireAfterSeconds != nil {
+ optsDoc = append(optsDoc, bsonx.Elem{"expireAfterSeconds", bsonx.Int32(*opts.ExpireAfterSeconds)})
+ }
+ if opts.Name != nil {
+ optsDoc = append(optsDoc, bsonx.Elem{"name", bsonx.String(*opts.Name)})
+ }
+ if opts.Sparse != nil {
+ optsDoc = append(optsDoc, bsonx.Elem{"sparse", bsonx.Boolean(*opts.Sparse)})
+ }
+ if opts.StorageEngine != nil {
+ doc, err := transformDocument(iv.coll.registry, opts.StorageEngine)
+ if err != nil {
+ return nil, err
+ }
+
+ optsDoc = append(optsDoc, bsonx.Elem{"storageEngine", bsonx.Document(doc)})
+ }
+ if opts.Unique != nil {
+ optsDoc = append(optsDoc, bsonx.Elem{"unique", bsonx.Boolean(*opts.Unique)})
+ }
+ if opts.Version != nil {
+ optsDoc = append(optsDoc, bsonx.Elem{"v", bsonx.Int32(*opts.Version)})
+ }
+ if opts.DefaultLanguage != nil {
+ optsDoc = append(optsDoc, bsonx.Elem{"default_language", bsonx.String(*opts.DefaultLanguage)})
+ }
+ if opts.LanguageOverride != nil {
+ optsDoc = append(optsDoc, bsonx.Elem{"language_override", bsonx.String(*opts.LanguageOverride)})
+ }
+ if opts.TextVersion != nil {
+ optsDoc = append(optsDoc, bsonx.Elem{"textIndexVersion", bsonx.Int32(*opts.TextVersion)})
+ }
+ if opts.Weights != nil {
+ weightsDoc, err := transformDocument(iv.coll.registry, opts.Weights)
+ if err != nil {
+ return nil, err
+ }
+
+ optsDoc = append(optsDoc, bsonx.Elem{"weights", bsonx.Document(weightsDoc)})
+ }
+ if opts.SphereVersion != nil {
+ optsDoc = append(optsDoc, bsonx.Elem{"2dsphereIndexVersion", bsonx.Int32(*opts.SphereVersion)})
+ }
+ if opts.Bits != nil {
+ optsDoc = append(optsDoc, bsonx.Elem{"bits", bsonx.Int32(*opts.Bits)})
+ }
+ if opts.Max != nil {
+ optsDoc = append(optsDoc, bsonx.Elem{"max", bsonx.Double(*opts.Max)})
+ }
+ if opts.Min != nil {
+ optsDoc = append(optsDoc, bsonx.Elem{"min", bsonx.Double(*opts.Min)})
+ }
+ if opts.BucketSize != nil {
+ optsDoc = append(optsDoc, bsonx.Elem{"bucketSize", bsonx.Int32(*opts.BucketSize)})
+ }
+ if opts.PartialFilterExpression != nil {
+ doc, err := transformDocument(iv.coll.registry, opts.PartialFilterExpression)
+ if err != nil {
+ return nil, err
+ }
+
+ optsDoc = append(optsDoc, bsonx.Elem{"partialFilterExpression", bsonx.Document(doc)})
+ }
+ if opts.Collation != nil {
+ doc := opts.Collation.ToDocument()
+ optsDoc = append(optsDoc, bsonx.Elem{"collation", bsonx.Document(doc)})
+ }
+
+ return optsDoc, nil
+}
+
+// DropOne drops the index with the given name from the collection.
+func (iv IndexView) DropOne(ctx context.Context, name string, opts ...*options.DropIndexesOptions) (bson.Raw, error) {
+ if name == "*" {
+ return nil, ErrMultipleIndexDrop
+ }
+
+ sess := sessionFromContext(ctx)
+
+ err := iv.coll.client.ValidSession(sess)
+ if err != nil {
+ return nil, err
+ }
+
+ cmd := command.DropIndexes{
+ NS: iv.coll.namespace(),
+ Index: name,
+ Session: sess,
+ Clock: iv.coll.client.clock,
+ }
+
+ return driver.DropIndexes(
+ ctx, cmd,
+ iv.coll.client.topology,
+ iv.coll.writeSelector,
+ iv.coll.client.id,
+ iv.coll.client.topology.SessionPool,
+ opts...,
+ )
+}
+
+// DropAll drops all indexes in the collection.
+func (iv IndexView) DropAll(ctx context.Context, opts ...*options.DropIndexesOptions) (bson.Raw, error) {
+ sess := sessionFromContext(ctx)
+
+ err := iv.coll.client.ValidSession(sess)
+ if err != nil {
+ return nil, err
+ }
+
+ cmd := command.DropIndexes{
+ NS: iv.coll.namespace(),
+ Index: "*",
+ Session: sess,
+ Clock: iv.coll.client.clock,
+ }
+
+ return driver.DropIndexes(
+ ctx, cmd,
+ iv.coll.client.topology,
+ iv.coll.writeSelector,
+ iv.coll.client.id,
+ iv.coll.client.topology.SessionPool,
+ opts...,
+ )
+}
+
+func getOrGenerateIndexName(registry *bsoncodec.Registry, model IndexModel) (string, error) {
+ if model.Options != nil && model.Options.Name != nil {
+ return *model.Options.Name, nil
+ }
+
+ name := bytes.NewBufferString("")
+ first := true
+
+ keys, err := transformDocument(registry, model.Keys)
+ if err != nil {
+ return "", err
+ }
+ for _, elem := range keys {
+ if !first {
+ _, err := name.WriteRune('_')
+ if err != nil {
+ return "", err
+ }
+ }
+
+ _, err := name.WriteString(elem.Key)
+ if err != nil {
+ return "", err
+ }
+
+ _, err = name.WriteRune('_')
+ if err != nil {
+ return "", err
+ }
+
+ var value string
+
+ switch elem.Value.Type() {
+ case bsontype.Int32:
+ value = fmt.Sprintf("%d", elem.Value.Int32())
+ case bsontype.Int64:
+ value = fmt.Sprintf("%d", elem.Value.Int64())
+ case bsontype.String:
+ value = elem.Value.StringValue()
+ default:
+ return "", ErrInvalidIndexValue
+ }
+
+ _, err = name.WriteString(value)
+ if err != nil {
+ return "", err
+ }
+
+ first = false
+ }
+
+ return name.String(), nil
+}
diff --git a/vendor/github.com/mongodb/mongo-go-driver/mongo/mongo.go b/vendor/github.com/mongodb/mongo-go-driver/mongo/mongo.go
new file mode 100644
index 0000000..9757d9b
--- /dev/null
+++ b/vendor/github.com/mongodb/mongo-go-driver/mongo/mongo.go
@@ -0,0 +1,242 @@
+// Copyright (C) MongoDB, Inc. 2017-present.
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+
+package mongo
+
+import (
+ "context"
+ "errors"
+ "fmt"
+ "net"
+ "reflect"
+ "strings"
+
+ "github.com/mongodb/mongo-go-driver/mongo/options"
+ "github.com/mongodb/mongo-go-driver/x/bsonx"
+
+ "github.com/mongodb/mongo-go-driver/bson"
+ "github.com/mongodb/mongo-go-driver/bson/bsoncodec"
+ "github.com/mongodb/mongo-go-driver/bson/bsontype"
+ "github.com/mongodb/mongo-go-driver/bson/primitive"
+)
+
+// Dialer is used to make network connections.
+type Dialer interface {
+ DialContext(ctx context.Context, network, address string) (net.Conn, error)
+}
+
+// BSONAppender is an interface implemented by types that can marshal a
+// provided type into BSON bytes and append those bytes to the provided []byte.
+// The AppendBSON can return a non-nil error and non-nil []byte. The AppendBSON
+// method may also write incomplete BSON to the []byte.
+type BSONAppender interface {
+ AppendBSON([]byte, interface{}) ([]byte, error)
+}
+
+// BSONAppenderFunc is an adapter function that allows any function that
+// satisfies the AppendBSON method signature to be used where a BSONAppender is
+// used.
+type BSONAppenderFunc func([]byte, interface{}) ([]byte, error)
+
+// AppendBSON implements the BSONAppender interface
+func (baf BSONAppenderFunc) AppendBSON(dst []byte, val interface{}) ([]byte, error) {
+ return baf(dst, val)
+}
+
+// MarshalError is returned when attempting to transform a value into a document
+// results in an error.
+type MarshalError struct {
+ Value interface{}
+ Err error
+}
+
+// Error implements the error interface.
+func (me MarshalError) Error() string {
+ return fmt.Sprintf("cannot transform type %s to a *bsonx.Document", reflect.TypeOf(me.Value))
+}
+
+// Pipeline is a type that makes creating aggregation pipelines easier. It is a
+// helper and is intended for serializing to BSON.
+//
+// Example usage:
+//
+// mongo.Pipeline{
+// {{"$group", bson.D{{"_id", "$state"}, {"totalPop", bson.D{{"$sum", "$pop"}}}}}},
+// {{"$match", bson.D{{"totalPop", bson.D{{"$gte", 10*1000*1000}}}}}},
+// }
+//
+type Pipeline []bson.D
+
+// transformAndEnsureID is a hack that makes it easy to get a RawValue as the _id value. This will
+// be removed when we switch from using bsonx to bsoncore for the driver package.
+func transformAndEnsureID(registry *bsoncodec.Registry, val interface{}) (bsonx.Doc, interface{}, error) {
+ // TODO: performance is going to be pretty bad for bsonx.Doc here since we turn it into a []byte
+ // only to turn it back into a bsonx.Doc. We can fix this post beta1 when we refactor the driver
+ // package to use bsoncore.Document instead of bsonx.Doc.
+ if registry == nil {
+ registry = bson.NewRegistryBuilder().Build()
+ }
+ switch tt := val.(type) {
+ case nil:
+ return nil, nil, ErrNilDocument
+ case bsonx.Doc:
+ val = tt.Copy()
+ case []byte:
+ // Slight optimization so we'll just use MarshalBSON and not go through the codec machinery.
+ val = bson.Raw(tt)
+ }
+
+ // TODO(skriptble): Use a pool of these instead.
+ buf := make([]byte, 0, 256)
+ b, err := bson.MarshalAppendWithRegistry(registry, buf, val)
+ if err != nil {
+ return nil, nil, MarshalError{Value: val, Err: err}
+ }
+
+ d, err := bsonx.ReadDoc(b)
+ if err != nil {
+ return nil, nil, err
+ }
+
+ var id interface{}
+
+ idx := d.IndexOf("_id")
+ var idElem bsonx.Elem
+ switch idx {
+ case -1:
+ idElem = bsonx.Elem{"_id", bsonx.ObjectID(primitive.NewObjectID())}
+ d = append(d, bsonx.Elem{})
+ copy(d[1:], d)
+ d[0] = idElem
+ default:
+ idElem = d[idx]
+ copy(d[1:idx+1], d[0:idx])
+ d[0] = idElem
+ }
+
+ t, data, err := idElem.Value.MarshalAppendBSONValue(buf[:0])
+ if err != nil {
+ return nil, nil, err
+ }
+
+ err = bson.RawValue{Type: t, Value: data}.UnmarshalWithRegistry(registry, &id)
+ if err != nil {
+ return nil, nil, err
+ }
+
+ return d, id, nil
+}
+
+func transformDocument(registry *bsoncodec.Registry, val interface{}) (bsonx.Doc, error) {
+ if registry == nil {
+ registry = bson.NewRegistryBuilder().Build()
+ }
+ if val == nil {
+ return nil, ErrNilDocument
+ }
+ if doc, ok := val.(bsonx.Doc); ok {
+ return doc.Copy(), nil
+ }
+ if bs, ok := val.([]byte); ok {
+ // Slight optimization so we'll just use MarshalBSON and not go through the codec machinery.
+ val = bson.Raw(bs)
+ }
+
+ // TODO(skriptble): Use a pool of these instead.
+ buf := make([]byte, 0, 256)
+ b, err := bson.MarshalAppendWithRegistry(registry, buf[:0], val)
+ if err != nil {
+ return nil, MarshalError{Value: val, Err: err}
+ }
+ return bsonx.ReadDoc(b)
+}
+
+func ensureID(d bsonx.Doc) (bsonx.Doc, interface{}) {
+ var id interface{}
+
+ elem, err := d.LookupElementErr("_id")
+ switch err.(type) {
+ case nil:
+ id = elem
+ default:
+ oid := primitive.NewObjectID()
+ d = append(d, bsonx.Elem{"_id", bsonx.ObjectID(oid)})
+ id = oid
+ }
+ return d, id
+}
+
+func ensureDollarKey(doc bsonx.Doc) error {
+ if len(doc) == 0 {
+ return errors.New("update document must have at least one element")
+ }
+ if !strings.HasPrefix(doc[0].Key, "$") {
+ return errors.New("update document must contain key beginning with '$'")
+ }
+ return nil
+}
+
+func transformAggregatePipeline(registry *bsoncodec.Registry, pipeline interface{}) (bsonx.Arr, error) {
+ pipelineArr := bsonx.Arr{}
+ switch t := pipeline.(type) {
+ case bsoncodec.ValueMarshaler:
+ btype, val, err := t.MarshalBSONValue()
+ if err != nil {
+ return nil, err
+ }
+ if btype != bsontype.Array {
+ return nil, fmt.Errorf("ValueMarshaler returned a %v, but was expecting %v", btype, bsontype.Array)
+ }
+ err = pipelineArr.UnmarshalBSONValue(btype, val)
+ if err != nil {
+ return nil, err
+ }
+ default:
+ val := reflect.ValueOf(t)
+ if !val.IsValid() || (val.Kind() != reflect.Slice && val.Kind() != reflect.Array) {
+ return nil, fmt.Errorf("can only transform slices and arrays into aggregation pipelines, but got %v", val.Kind())
+ }
+ for idx := 0; idx < val.Len(); idx++ {
+ elem, err := transformDocument(registry, val.Index(idx).Interface())
+ if err != nil {
+ return nil, err
+ }
+ pipelineArr = append(pipelineArr, bsonx.Document(elem))
+ }
+ }
+
+ return pipelineArr, nil
+}
+
+// Build the aggregation pipeline for the CountDocument command.
+func countDocumentsAggregatePipeline(registry *bsoncodec.Registry, filter interface{}, opts *options.CountOptions) (bsonx.Arr, error) {
+ pipeline := bsonx.Arr{}
+ filterDoc, err := transformDocument(registry, filter)
+
+ if err != nil {
+ return nil, err
+ }
+ pipeline = append(pipeline, bsonx.Document(bsonx.Doc{{"$match", bsonx.Document(filterDoc)}}))
+
+ if opts != nil {
+ if opts.Skip != nil {
+ pipeline = append(pipeline, bsonx.Document(bsonx.Doc{{"$skip", bsonx.Int64(*opts.Skip)}}))
+ }
+ if opts.Limit != nil {
+ pipeline = append(pipeline, bsonx.Document(bsonx.Doc{{"$limit", bsonx.Int64(*opts.Limit)}}))
+ }
+ }
+
+ pipeline = append(pipeline, bsonx.Document(bsonx.Doc{
+ {"$group", bsonx.Document(bsonx.Doc{
+ {"_id", bsonx.Null()},
+ {"n", bsonx.Document(bsonx.Doc{{"$sum", bsonx.Int32(1)}})},
+ })},
+ },
+ ))
+
+ return pipeline, nil
+}
diff --git a/vendor/github.com/mongodb/mongo-go-driver/mongo/options/aggregateoptions.go b/vendor/github.com/mongodb/mongo-go-driver/mongo/options/aggregateoptions.go
new file mode 100644
index 0000000..3700d84
--- /dev/null
+++ b/vendor/github.com/mongodb/mongo-go-driver/mongo/options/aggregateoptions.go
@@ -0,0 +1,119 @@
+// Copyright (C) MongoDB, Inc. 2017-present.
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+
+package options
+
+import "time"
+
+// AggregateOptions represents all possible options to the aggregate() function
+type AggregateOptions struct {
+ AllowDiskUse *bool // Enables writing to temporary files. When set to true, aggregation stages can write data to the _tmp subdirectory in the dbPath directory
+ BatchSize *int32 // The number of documents to return per batch
+ BypassDocumentValidation *bool // If true, allows the write to opt-out of document level validation. This only applies when the $out stage is specified
+ Collation *Collation // Specifies a collation
+ MaxTime *time.Duration // The maximum amount of time to allow the query to run
+ MaxAwaitTime *time.Duration // The maximum amount of time for the server to wait on new documents to satisfy a tailable cursor query
+ Comment *string // Enables users to specify an arbitrary string to help trace the operation through the database profiler, currentOp and logs.
+ Hint interface{} // The index to use for the aggregation. The hint does not apply to $lookup and $graphLookup stages
+}
+
+// Aggregate returns a pointer to a new AggregateOptions
+func Aggregate() *AggregateOptions {
+ return &AggregateOptions{}
+}
+
+// SetAllowDiskUse enables writing to temporary files. When set to true,
+// aggregation stages can write data to the _tmp subdirectory in the
+// dbPath directory
+func (ao *AggregateOptions) SetAllowDiskUse(b bool) *AggregateOptions {
+ ao.AllowDiskUse = &b
+ return ao
+}
+
+// SetBatchSize specifies the number of documents to return per batch
+func (ao *AggregateOptions) SetBatchSize(i int32) *AggregateOptions {
+ ao.BatchSize = &i
+ return ao
+}
+
+// SetBypassDocumentValidation allows the write to opt-out of document level
+// validation. This only applies when the $out stage is specified
+// Valid for server versions >= 3.2. For servers < 3.2, this option is ignored.
+func (ao *AggregateOptions) SetBypassDocumentValidation(b bool) *AggregateOptions {
+ ao.BypassDocumentValidation = &b
+ return ao
+}
+
+// SetCollation specifies a collation.
+// Valid for server versions >= 3.4
+func (ao *AggregateOptions) SetCollation(c *Collation) *AggregateOptions {
+ ao.Collation = c
+ return ao
+}
+
+// SetMaxTime specifies the maximum amount of time to allow the query to run
+func (ao *AggregateOptions) SetMaxTime(d time.Duration) *AggregateOptions {
+ ao.MaxTime = &d
+ return ao
+}
+
+// SetMaxAwaitTime specifies the maximum amount of time for the server to
+// wait on new documents to satisfy a tailable cursor query
+// For servers < 3.2, this option is ignored
+func (ao *AggregateOptions) SetMaxAwaitTime(d time.Duration) *AggregateOptions {
+ ao.MaxAwaitTime = &d
+ return ao
+}
+
+// SetComment enables users to specify an arbitrary string to help trace the
+// operation through the database profiler, currentOp and logs.
+func (ao *AggregateOptions) SetComment(s string) *AggregateOptions {
+ ao.Comment = &s
+ return ao
+}
+
+// SetHint specifies the index to use for the aggregation. The hint does not
+// apply to $lookup and $graphLookup stages
+func (ao *AggregateOptions) SetHint(h interface{}) *AggregateOptions {
+ ao.Hint = h
+ return ao
+}
+
+// MergeAggregateOptions combines the argued AggregateOptions into a single AggregateOptions in a last-one-wins fashion
+func MergeAggregateOptions(opts ...*AggregateOptions) *AggregateOptions {
+ aggOpts := Aggregate()
+ for _, ao := range opts {
+ if ao == nil {
+ continue
+ }
+ if ao.AllowDiskUse != nil {
+ aggOpts.AllowDiskUse = ao.AllowDiskUse
+ }
+ if ao.BatchSize != nil {
+ aggOpts.BatchSize = ao.BatchSize
+ }
+ if ao.BypassDocumentValidation != nil {
+ aggOpts.BypassDocumentValidation = ao.BypassDocumentValidation
+ }
+ if ao.Collation != nil {
+ aggOpts.Collation = ao.Collation
+ }
+ if ao.MaxTime != nil {
+ aggOpts.MaxTime = ao.MaxTime
+ }
+ if ao.MaxAwaitTime != nil {
+ aggOpts.MaxAwaitTime = ao.MaxAwaitTime
+ }
+ if ao.Comment != nil {
+ aggOpts.Comment = ao.Comment
+ }
+ if ao.Hint != nil {
+ aggOpts.Hint = ao.Hint
+ }
+ }
+
+ return aggOpts
+}
diff --git a/vendor/github.com/mongodb/mongo-go-driver/mongo/options/bulkwriteoptions.go b/vendor/github.com/mongodb/mongo-go-driver/mongo/options/bulkwriteoptions.go
new file mode 100644
index 0000000..86282fa
--- /dev/null
+++ b/vendor/github.com/mongodb/mongo-go-driver/mongo/options/bulkwriteoptions.go
@@ -0,0 +1,55 @@
+// Copyright (C) MongoDB, Inc. 2017-present.
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+
+package options
+
+// DefaultOrdered is the default order for a BulkWriteOptions struct created from BulkWrite.
+var DefaultOrdered = true
+
+// BulkWriteOptions represent all possible options for a bulkWrite operation.
+type BulkWriteOptions struct {
+ BypassDocumentValidation *bool // If true, allows the write to opt out of document-level validation.
+ Ordered *bool // If true, when a write fails, return without performing remaining writes. Defaults to true.
+}
+
+// BulkWrite creates a new *BulkWriteOptions
+func BulkWrite() *BulkWriteOptions {
+ return &BulkWriteOptions{
+ Ordered: &DefaultOrdered,
+ }
+}
+
+// SetOrdered configures the ordered option. If true, when a write fails, the function will return without attempting
+// remaining writes. Defaults to true.
+func (b *BulkWriteOptions) SetOrdered(ordered bool) *BulkWriteOptions {
+ b.Ordered = &ordered
+ return b
+}
+
+// SetBypassDocumentValidation specifies if the write should opt out of document-level validation.
+// Valid for server versions >= 3.2. For servers < 3.2, this option is ignored.
+func (b *BulkWriteOptions) SetBypassDocumentValidation(bypass bool) *BulkWriteOptions {
+ b.BypassDocumentValidation = &bypass
+ return b
+}
+
+// MergeBulkWriteOptions combines the given *BulkWriteOptions into a single *BulkWriteOptions in a last one wins fashion.
+func MergeBulkWriteOptions(opts ...*BulkWriteOptions) *BulkWriteOptions {
+ b := BulkWrite()
+ for _, opt := range opts {
+ if opt == nil {
+ continue
+ }
+ if opt.Ordered != nil {
+ b.Ordered = opt.Ordered
+ }
+ if opt.BypassDocumentValidation != nil {
+ b.BypassDocumentValidation = opt.BypassDocumentValidation
+ }
+ }
+
+ return b
+}
diff --git a/vendor/github.com/mongodb/mongo-go-driver/mongo/options/changestreamoptions.go b/vendor/github.com/mongodb/mongo-go-driver/mongo/options/changestreamoptions.go
new file mode 100644
index 0000000..c8776ac
--- /dev/null
+++ b/vendor/github.com/mongodb/mongo-go-driver/mongo/options/changestreamoptions.go
@@ -0,0 +1,97 @@
+// Copyright (C) MongoDB, Inc. 2017-present.
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+
+package options
+
+import (
+ "github.com/mongodb/mongo-go-driver/bson/primitive"
+ "time"
+)
+
+// ChangeStreamOptions represents all possible options to a change stream
+type ChangeStreamOptions struct {
+ BatchSize *int32 // The number of documents to return per batch
+ Collation *Collation // Specifies a collation
+ FullDocument *FullDocument // When set to ‘updateLookup’, the change notification for partial updates will include both a delta describing the changes to the document, as well as a copy of the entire document that was changed from some time after the change occurred.
+ MaxAwaitTime *time.Duration // The maximum amount of time for the server to wait on new documents to satisfy a change stream query
+ ResumeAfter interface{} // Specifies the logical starting point for the new change stream
+ StartAtOperationTime *primitive.Timestamp // Ensures that a change stream will only provide changes that occurred after a timestamp.
+}
+
+// ChangeStream returns a pointer to a new ChangeStreamOptions
+func ChangeStream() *ChangeStreamOptions {
+ return &ChangeStreamOptions{}
+}
+
+// SetBatchSize specifies the number of documents to return per batch
+func (cso *ChangeStreamOptions) SetBatchSize(i int32) *ChangeStreamOptions {
+ cso.BatchSize = &i
+ return cso
+}
+
+// SetCollation specifies a collation
+func (cso *ChangeStreamOptions) SetCollation(c Collation) *ChangeStreamOptions {
+ cso.Collation = &c
+ return cso
+}
+
+// SetFullDocument specifies the fullDocument option.
+// When set to ‘updateLookup’, the change notification for partial updates will
+// include both a delta describing the changes to the document, as well as a
+// copy of the entire document that was changed from some time after the change
+// occurred.
+func (cso *ChangeStreamOptions) SetFullDocument(fd FullDocument) *ChangeStreamOptions {
+ cso.FullDocument = &fd
+ return cso
+}
+
+// SetMaxAwaitTime specifies the maximum amount of time for the server to wait on new documents to satisfy a change stream query
+func (cso *ChangeStreamOptions) SetMaxAwaitTime(d time.Duration) *ChangeStreamOptions {
+ cso.MaxAwaitTime = &d
+ return cso
+}
+
+// SetResumeAfter specifies the logical starting point for the new change stream
+func (cso *ChangeStreamOptions) SetResumeAfter(rt interface{}) *ChangeStreamOptions {
+ cso.ResumeAfter = rt
+ return cso
+}
+
+// SetStartAtOperationTime ensures that a change stream will only provide changes that occurred after a specified timestamp.
+func (cso *ChangeStreamOptions) SetStartAtOperationTime(t *primitive.Timestamp) *ChangeStreamOptions {
+ cso.StartAtOperationTime = t
+ return cso
+}
+
+// MergeChangeStreamOptions combines the argued ChangeStreamOptions into a single ChangeStreamOptions in a last-one-wins fashion
+func MergeChangeStreamOptions(opts ...*ChangeStreamOptions) *ChangeStreamOptions {
+ csOpts := ChangeStream()
+ for _, cso := range opts {
+ if cso == nil {
+ continue
+ }
+ if cso.BatchSize != nil {
+ csOpts.BatchSize = cso.BatchSize
+ }
+ if cso.Collation != nil {
+ csOpts.Collation = cso.Collation
+ }
+ if cso.FullDocument != nil {
+ csOpts.FullDocument = cso.FullDocument
+ }
+ if cso.MaxAwaitTime != nil {
+ csOpts.MaxAwaitTime = cso.MaxAwaitTime
+ }
+ if cso.ResumeAfter != nil {
+ csOpts.ResumeAfter = cso.ResumeAfter
+ }
+ if cso.StartAtOperationTime != nil {
+ csOpts.StartAtOperationTime = cso.StartAtOperationTime
+ }
+ }
+
+ return csOpts
+}
diff --git a/vendor/github.com/mongodb/mongo-go-driver/mongo/options/clientoptions.go b/vendor/github.com/mongodb/mongo-go-driver/mongo/options/clientoptions.go
new file mode 100644
index 0000000..e09a9c1
--- /dev/null
+++ b/vendor/github.com/mongodb/mongo-go-driver/mongo/options/clientoptions.go
@@ -0,0 +1,424 @@
+// Copyright (C) MongoDB, Inc. 2017-present.
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+
+package options
+
+import (
+ "context"
+ "net"
+ "time"
+
+ "github.com/mongodb/mongo-go-driver/bson/bsoncodec"
+ "github.com/mongodb/mongo-go-driver/event"
+ "github.com/mongodb/mongo-go-driver/mongo/readconcern"
+ "github.com/mongodb/mongo-go-driver/mongo/readpref"
+ "github.com/mongodb/mongo-go-driver/mongo/writeconcern"
+ "github.com/mongodb/mongo-go-driver/x/mongo/driver/topology"
+ "github.com/mongodb/mongo-go-driver/x/network/connection"
+ "github.com/mongodb/mongo-go-driver/x/network/connstring"
+)
+
+// ContextDialer makes new network connections
+type ContextDialer interface {
+ DialContext(ctx context.Context, network, address string) (net.Conn, error)
+}
+
+// SSLOpt holds client SSL options.
+//
+// Enabled indicates whether SSL should be enabled.
+//
+// ClientCertificateKeyFile specifies the file containing the client certificate and private key
+// used for authentication.
+//
+// ClientCertificateKeyPassword provides a callback that returns a password used for decrypting the
+// private key of a PEM file (if one is provided).
+//
+// Insecure indicates whether to skip the verification of the server certificate and hostname.
+//
+// CaFile specifies the file containing the certificate authority used for SSL connections.
+type SSLOpt struct {
+ Enabled bool
+ ClientCertificateKeyFile string
+ ClientCertificateKeyPassword func() string
+ Insecure bool
+ CaFile string
+}
+
+// Credential holds auth options.
+//
+// AuthMechanism indicates the mechanism to use for authentication.
+// Supported values include "SCRAM-SHA-256", "SCRAM-SHA-1", "MONGODB-CR", "PLAIN", "GSSAPI", and "MONGODB-X509".
+//
+// AuthMechanismProperties specifies additional configuration options which may be used by certain
+// authentication mechanisms.
+//
+// AuthSource specifies the database to authenticate against.
+//
+// Username specifies the username that will be authenticated.
+//
+// Password specifies the password used for authentication.
+type Credential struct {
+ AuthMechanism string
+ AuthMechanismProperties map[string]string
+ AuthSource string
+ Username string
+ Password string
+}
+
+// ClientOptions represents all possbile options to configure a client.
+type ClientOptions struct {
+ TopologyOptions []topology.Option
+ ConnString connstring.ConnString
+ RetryWrites *bool
+ ReadPreference *readpref.ReadPref
+ ReadConcern *readconcern.ReadConcern
+ WriteConcern *writeconcern.WriteConcern
+ Registry *bsoncodec.Registry
+}
+
+// Client creates a new ClientOptions instance.
+func Client() *ClientOptions {
+ return &ClientOptions{
+ TopologyOptions: make([]topology.Option, 0),
+ }
+}
+
+// SetAppName specifies the client application name. This value is used by MongoDB when it logs
+// connection information and profile information, such as slow queries.
+func (c *ClientOptions) SetAppName(s string) *ClientOptions {
+ c.ConnString.AppName = s
+
+ return c
+}
+
+// SetAuth sets the authentication options.
+func (c *ClientOptions) SetAuth(auth Credential) *ClientOptions {
+ c.ConnString.AuthMechanism = auth.AuthMechanism
+ c.ConnString.AuthMechanismProperties = auth.AuthMechanismProperties
+ c.ConnString.AuthSource = auth.AuthSource
+ c.ConnString.Username = auth.Username
+ c.ConnString.Password = auth.Password
+
+ return c
+}
+
+// SetConnectTimeout specifies the timeout for an initial connection to a server.
+// If a custom Dialer is used, this method won't be set and the user is
+// responsible for setting the ConnectTimeout for connections on the dialer
+// themselves.
+func (c *ClientOptions) SetConnectTimeout(d time.Duration) *ClientOptions {
+ c.ConnString.ConnectTimeout = d
+ c.ConnString.ConnectTimeoutSet = true
+
+ return c
+}
+
+// SetDialer specifies a custom dialer used to dial new connections to a server.
+// If a custom dialer is not set, a net.Dialer with a 300 second keepalive time will be used by default.
+func (c *ClientOptions) SetDialer(d ContextDialer) *ClientOptions {
+ c.TopologyOptions = append(
+ c.TopologyOptions,
+ topology.WithServerOptions(func(opts ...topology.ServerOption) []topology.ServerOption {
+ return append(
+ opts,
+ topology.WithConnectionOptions(func(opts ...connection.Option) []connection.Option {
+ return append(
+ opts,
+ connection.WithDialer(func(connection.Dialer) connection.Dialer {
+ return d
+ }),
+ )
+ }),
+ )
+ }),
+ )
+
+ return c
+}
+
+// SetMonitor specifies a command monitor used to see commands for a client.
+func (c *ClientOptions) SetMonitor(m *event.CommandMonitor) *ClientOptions {
+ c.TopologyOptions = append(
+ c.TopologyOptions,
+ topology.WithServerOptions(func(opts ...topology.ServerOption) []topology.ServerOption {
+ return append(
+ opts,
+ topology.WithConnectionOptions(func(opts ...connection.Option) []connection.Option {
+ return append(
+ opts,
+ connection.WithMonitor(func(*event.CommandMonitor) *event.CommandMonitor {
+ return m
+ }),
+ )
+ }),
+ )
+ }),
+ )
+
+ return c
+}
+
+// SetHeartbeatInterval specifies the interval to wait between server monitoring checks.
+func (c *ClientOptions) SetHeartbeatInterval(d time.Duration) *ClientOptions {
+ c.ConnString.HeartbeatInterval = d
+ c.ConnString.HeartbeatIntervalSet = true
+
+ return c
+}
+
+// SetHosts specifies the initial list of addresses from which to discover the rest of the cluster.
+func (c *ClientOptions) SetHosts(s []string) *ClientOptions {
+ c.ConnString.Hosts = s
+
+ return c
+}
+
+// SetLocalThreshold specifies how far to distribute queries, beyond the server with the fastest
+// round-trip time. If a server's roundtrip time is more than LocalThreshold slower than the
+// the fastest, the driver will not send queries to that server.
+func (c *ClientOptions) SetLocalThreshold(d time.Duration) *ClientOptions {
+ c.ConnString.LocalThreshold = d
+ c.ConnString.LocalThresholdSet = true
+
+ return c
+}
+
+// SetMaxConnIdleTime specifies the maximum number of milliseconds that a connection can remain idle
+// in a connection pool before being removed and closed.
+func (c *ClientOptions) SetMaxConnIdleTime(d time.Duration) *ClientOptions {
+ c.ConnString.MaxConnIdleTime = d
+ c.ConnString.MaxConnIdleTimeSet = true
+
+ return c
+}
+
+// SetMaxPoolSize specifies the max size of a server's connection pool.
+func (c *ClientOptions) SetMaxPoolSize(u uint16) *ClientOptions {
+ c.ConnString.MaxPoolSize = u
+ c.ConnString.MaxPoolSizeSet = true
+
+ return c
+}
+
+// SetReadConcern specifies the read concern.
+func (c *ClientOptions) SetReadConcern(rc *readconcern.ReadConcern) *ClientOptions {
+ c.ReadConcern = rc
+
+ return c
+}
+
+// SetReadPreference specifies the read preference.
+func (c *ClientOptions) SetReadPreference(rp *readpref.ReadPref) *ClientOptions {
+ c.ReadPreference = rp
+
+ return c
+}
+
+// SetRegistry specifies the bsoncodec.Registry.
+func (c *ClientOptions) SetRegistry(registry *bsoncodec.Registry) *ClientOptions {
+ c.Registry = registry
+
+ // add registry to the server options so that it will be used for the cursors built by this client
+ c.TopologyOptions = append(
+ c.TopologyOptions,
+ topology.WithServerOptions(func(opts ...topology.ServerOption) []topology.ServerOption {
+ return append(
+ opts,
+ topology.WithRegistry(func(*bsoncodec.Registry) *bsoncodec.Registry {
+ return registry
+ }),
+ )
+ }),
+ )
+
+ return c
+}
+
+// SetReplicaSet specifies the name of the replica set of the cluster.
+func (c *ClientOptions) SetReplicaSet(s string) *ClientOptions {
+ c.ConnString.ReplicaSet = s
+
+ return c
+}
+
+// SetRetryWrites specifies whether the client has retryable writes enabled.
+func (c *ClientOptions) SetRetryWrites(b bool) *ClientOptions {
+ c.RetryWrites = &b
+
+ return c
+}
+
+// SetServerSelectionTimeout specifies a timeout in milliseconds to block for server selection.
+func (c *ClientOptions) SetServerSelectionTimeout(d time.Duration) *ClientOptions {
+ c.ConnString.ServerSelectionTimeout = d
+ c.ConnString.ServerSelectionTimeoutSet = true
+
+ return c
+}
+
+// SetSingle specifies whether the driver should connect directly to the server instead of
+// auto-discovering other servers in the cluster.
+func (c *ClientOptions) SetSingle(b bool) *ClientOptions {
+ if b {
+ c.ConnString.Connect = connstring.SingleConnect
+ } else {
+ c.ConnString.Connect = connstring.AutoConnect
+ }
+ c.ConnString.ConnectSet = true
+
+ return c
+}
+
+// SetSocketTimeout specifies the time in milliseconds to attempt to send or receive on a socket
+// before the attempt times out.
+func (c *ClientOptions) SetSocketTimeout(d time.Duration) *ClientOptions {
+ c.ConnString.SocketTimeout = d
+ c.ConnString.SocketTimeoutSet = true
+
+ return c
+}
+
+// SetSSL sets SSL options.
+func (c *ClientOptions) SetSSL(ssl *SSLOpt) *ClientOptions {
+ c.ConnString.SSL = ssl.Enabled
+ c.ConnString.SSLSet = true
+
+ if ssl.ClientCertificateKeyFile != "" {
+ c.ConnString.SSLClientCertificateKeyFile = ssl.ClientCertificateKeyFile
+ c.ConnString.SSLClientCertificateKeyFileSet = true
+ }
+
+ if ssl.ClientCertificateKeyPassword != nil {
+ c.ConnString.SSLClientCertificateKeyPassword = ssl.ClientCertificateKeyPassword
+ c.ConnString.SSLClientCertificateKeyPasswordSet = true
+ }
+
+ c.ConnString.SSLInsecure = ssl.Insecure
+ c.ConnString.SSLInsecureSet = true
+
+ if ssl.CaFile != "" {
+ c.ConnString.SSLCaFile = ssl.CaFile
+ c.ConnString.SSLCaFileSet = true
+ }
+
+ return c
+}
+
+// SetWriteConcern sets the write concern.
+func (c *ClientOptions) SetWriteConcern(wc *writeconcern.WriteConcern) *ClientOptions {
+ c.WriteConcern = wc
+
+ return c
+}
+
+// MergeClientOptions combines the given connstring and *ClientOptions into a single *ClientOptions in a last one wins
+// fashion. The given connstring will be used for the default options, which can be overwritten using the given
+// *ClientOptions.
+func MergeClientOptions(cs connstring.ConnString, opts ...*ClientOptions) *ClientOptions {
+ c := Client()
+ c.ConnString = cs
+
+ for _, opt := range opts {
+ if opt == nil {
+ continue
+ }
+ c.TopologyOptions = append(c.TopologyOptions, opt.TopologyOptions...)
+
+ if an := opt.ConnString.AppName; an != "" {
+ c.ConnString.AppName = an
+ }
+ if am := opt.ConnString.AuthMechanism; len(am) != 0 {
+ c.ConnString.AuthMechanism = am
+ }
+ if amp := opt.ConnString.AuthMechanismProperties; amp != nil {
+ c.ConnString.AuthMechanismProperties = amp
+ }
+ if as := opt.ConnString.AuthSource; len(as) != 0 {
+ c.ConnString.AuthSource = as
+ }
+ if u := opt.ConnString.Username; len(u) != 0 {
+ c.ConnString.Username = u
+ }
+ if p := opt.ConnString.Password; len(p) != 0 {
+ c.ConnString.Password = p
+ }
+ if opt.ConnString.ConnectTimeoutSet {
+ c.ConnString.ConnectTimeoutSet = true
+ c.ConnString.ConnectTimeout = opt.ConnString.ConnectTimeout
+ }
+ if opt.ConnString.HeartbeatIntervalSet {
+ c.ConnString.HeartbeatIntervalSet = true
+ c.ConnString.HeartbeatInterval = opt.ConnString.HeartbeatInterval
+ }
+ if h := opt.ConnString.Hosts; h != nil {
+ c.ConnString.Hosts = h
+ }
+ if opt.ConnString.LocalThresholdSet {
+ c.ConnString.LocalThresholdSet = true
+ c.ConnString.LocalThreshold = opt.ConnString.LocalThreshold
+ }
+ if opt.ConnString.MaxConnIdleTimeSet {
+ c.ConnString.MaxConnIdleTimeSet = true
+ c.ConnString.MaxConnIdleTime = opt.ConnString.MaxConnIdleTime
+ }
+ if opt.ConnString.MaxPoolSizeSet {
+ c.ConnString.MaxPoolSizeSet = true
+ c.ConnString.MaxPoolSize = opt.ConnString.MaxPoolSize
+ }
+ if opt.ReadConcern != nil {
+ c.ReadConcern = opt.ReadConcern
+ }
+ if opt.ReadPreference != nil {
+ c.ReadPreference = opt.ReadPreference
+ }
+ if opt.Registry != nil {
+ c.Registry = opt.Registry
+ }
+ if rs := opt.ConnString.ReplicaSet; rs != "" {
+ c.ConnString.ReplicaSet = rs
+ }
+ if opt.RetryWrites != nil {
+ c.RetryWrites = opt.RetryWrites
+ }
+ if opt.ConnString.ServerSelectionTimeoutSet {
+ c.ConnString.ServerSelectionTimeoutSet = true
+ c.ConnString.ServerSelectionTimeout = opt.ConnString.ServerSelectionTimeout
+ }
+ if opt.ConnString.ConnectSet {
+ c.ConnString.ConnectSet = true
+ c.ConnString.Connect = opt.ConnString.Connect
+ }
+ if opt.ConnString.SocketTimeoutSet {
+ c.ConnString.SocketTimeoutSet = true
+ c.ConnString.SocketTimeout = opt.ConnString.SocketTimeout
+ }
+ if opt.ConnString.SSLSet {
+ c.ConnString.SSLSet = true
+ c.ConnString.SSL = opt.ConnString.SSL
+ }
+ if opt.ConnString.SSLClientCertificateKeyFileSet {
+ c.ConnString.SSLClientCertificateKeyFileSet = true
+ c.ConnString.SSLClientCertificateKeyFile = opt.ConnString.SSLClientCertificateKeyFile
+ }
+ if opt.ConnString.SSLClientCertificateKeyPasswordSet {
+ c.ConnString.SSLClientCertificateKeyPasswordSet = true
+ c.ConnString.SSLClientCertificateKeyPassword = opt.ConnString.SSLClientCertificateKeyPassword
+ }
+ if opt.ConnString.SSLInsecureSet {
+ c.ConnString.SSLInsecureSet = true
+ c.ConnString.SSLInsecure = opt.ConnString.SSLInsecure
+ }
+ if opt.ConnString.SSLCaFileSet {
+ c.ConnString.SSLCaFileSet = true
+ c.ConnString.SSLCaFile = opt.ConnString.SSLCaFile
+ }
+ if opt.WriteConcern != nil {
+ c.WriteConcern = opt.WriteConcern
+ }
+ }
+
+ return c
+}
diff --git a/vendor/github.com/mongodb/mongo-go-driver/mongo/options/collectionoptions.go b/vendor/github.com/mongodb/mongo-go-driver/mongo/options/collectionoptions.go
new file mode 100644
index 0000000..3415505
--- /dev/null
+++ b/vendor/github.com/mongodb/mongo-go-driver/mongo/options/collectionoptions.go
@@ -0,0 +1,77 @@
+// Copyright (C) MongoDB, Inc. 2017-present.
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+
+package options
+
+import (
+ "github.com/mongodb/mongo-go-driver/bson/bsoncodec"
+ "github.com/mongodb/mongo-go-driver/mongo/readconcern"
+ "github.com/mongodb/mongo-go-driver/mongo/readpref"
+ "github.com/mongodb/mongo-go-driver/mongo/writeconcern"
+)
+
+// CollectionOptions represent all possible options to configure a Collection.
+type CollectionOptions struct {
+ ReadConcern *readconcern.ReadConcern // The read concern for operations in the collection.
+ WriteConcern *writeconcern.WriteConcern // The write concern for operations in the collection.
+ ReadPreference *readpref.ReadPref // The read preference for operations in the collection.
+ Registry *bsoncodec.Registry // The registry to be used to construct BSON encoders and decoders for the collection.
+}
+
+// Collection creates a new CollectionOptions instance
+func Collection() *CollectionOptions {
+ return &CollectionOptions{}
+}
+
+// SetReadConcern sets the read concern for the collection.
+func (c *CollectionOptions) SetReadConcern(rc *readconcern.ReadConcern) *CollectionOptions {
+ c.ReadConcern = rc
+ return c
+}
+
+// SetWriteConcern sets the write concern for the collection.
+func (c *CollectionOptions) SetWriteConcern(wc *writeconcern.WriteConcern) *CollectionOptions {
+ c.WriteConcern = wc
+ return c
+}
+
+// SetReadPreference sets the read preference for the collection.
+func (c *CollectionOptions) SetReadPreference(rp *readpref.ReadPref) *CollectionOptions {
+ c.ReadPreference = rp
+ return c
+}
+
+// SetRegistry sets the bsoncodec Registry for the collection.
+func (c *CollectionOptions) SetRegistry(r *bsoncodec.Registry) *CollectionOptions {
+ c.Registry = r
+ return c
+}
+
+// MergeCollectionOptions combines the *CollectionOptions arguments into a single *CollectionOptions in a last one wins
+// fashion.
+func MergeCollectionOptions(opts ...*CollectionOptions) *CollectionOptions {
+ c := Collection()
+
+ for _, opt := range opts {
+ if opt == nil {
+ continue
+ }
+ if opt.ReadConcern != nil {
+ c.ReadConcern = opt.ReadConcern
+ }
+ if opt.WriteConcern != nil {
+ c.WriteConcern = opt.WriteConcern
+ }
+ if opt.ReadPreference != nil {
+ c.ReadPreference = opt.ReadPreference
+ }
+ if opt.Registry != nil {
+ c.Registry = opt.Registry
+ }
+ }
+
+ return c
+}
diff --git a/vendor/github.com/mongodb/mongo-go-driver/mongo/options/countoptions.go b/vendor/github.com/mongodb/mongo-go-driver/mongo/options/countoptions.go
new file mode 100644
index 0000000..be3baab
--- /dev/null
+++ b/vendor/github.com/mongodb/mongo-go-driver/mongo/options/countoptions.go
@@ -0,0 +1,81 @@
+// Copyright (C) MongoDB, Inc. 2017-present.
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+
+package options
+
+import "time"
+
+// CountOptions represents all possible options to the count() function
+type CountOptions struct {
+ Collation *Collation // Specifies a collation
+ Hint interface{} // The index to use
+ Limit *int64 // The maximum number of documents to count
+ MaxTime *time.Duration // The maximum amount of time to allow the operation to run
+ Skip *int64 // The number of documents to skip before counting
+}
+
+// Count returns a pointer to a new CountOptions
+func Count() *CountOptions {
+ return &CountOptions{}
+}
+
+// SetCollation specifies a collation
+// Valid for server versions >= 3.4
+func (co *CountOptions) SetCollation(c *Collation) *CountOptions {
+ co.Collation = c
+ return co
+}
+
+// SetHint specifies the index to use
+func (co *CountOptions) SetHint(h interface{}) *CountOptions {
+ co.Hint = h
+ return co
+}
+
+// SetLimit specifies the maximum number of documents to count
+func (co *CountOptions) SetLimit(i int64) *CountOptions {
+ co.Limit = &i
+ return co
+}
+
+// SetMaxTime specifies the maximum amount of time to allow the operation to run
+func (co *CountOptions) SetMaxTime(d time.Duration) *CountOptions {
+ co.MaxTime = &d
+ return co
+}
+
+// SetSkip specifies the number of documents to skip before counting
+func (co *CountOptions) SetSkip(i int64) *CountOptions {
+ co.Skip = &i
+ return co
+}
+
+// MergeCountOptions combines the argued CountOptions into a single CountOptions in a last-one-wins fashion
+func MergeCountOptions(opts ...*CountOptions) *CountOptions {
+ countOpts := Count()
+ for _, co := range opts {
+ if co == nil {
+ continue
+ }
+ if co.Collation != nil {
+ countOpts.Collation = co.Collation
+ }
+ if co.Hint != nil {
+ countOpts.Hint = co.Hint
+ }
+ if co.Limit != nil {
+ countOpts.Limit = co.Limit
+ }
+ if co.MaxTime != nil {
+ countOpts.MaxTime = co.MaxTime
+ }
+ if co.Skip != nil {
+ countOpts.Skip = co.Skip
+ }
+ }
+
+ return countOpts
+}
diff --git a/vendor/github.com/mongodb/mongo-go-driver/mongo/options/dboptions.go b/vendor/github.com/mongodb/mongo-go-driver/mongo/options/dboptions.go
new file mode 100644
index 0000000..989cb13
--- /dev/null
+++ b/vendor/github.com/mongodb/mongo-go-driver/mongo/options/dboptions.go
@@ -0,0 +1,77 @@
+// Copyright (C) MongoDB, Inc. 2017-present.
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+
+package options
+
+import (
+ "github.com/mongodb/mongo-go-driver/bson/bsoncodec"
+ "github.com/mongodb/mongo-go-driver/mongo/readconcern"
+ "github.com/mongodb/mongo-go-driver/mongo/readpref"
+ "github.com/mongodb/mongo-go-driver/mongo/writeconcern"
+)
+
+// DatabaseOptions represent all possible options to configure a Database.
+type DatabaseOptions struct {
+ ReadConcern *readconcern.ReadConcern // The read concern for operations in the database.
+ WriteConcern *writeconcern.WriteConcern // The write concern for operations in the database.
+ ReadPreference *readpref.ReadPref // The read preference for operations in the database.
+ Registry *bsoncodec.Registry // The registry to be used to construct BSON encoders and decoders for the database.
+}
+
+// Database creates a new DatabaseOptions instance
+func Database() *DatabaseOptions {
+ return &DatabaseOptions{}
+}
+
+// SetReadConcern sets the read concern for the database.
+func (d *DatabaseOptions) SetReadConcern(rc *readconcern.ReadConcern) *DatabaseOptions {
+ d.ReadConcern = rc
+ return d
+}
+
+// SetWriteConcern sets the write concern for the database.
+func (d *DatabaseOptions) SetWriteConcern(wc *writeconcern.WriteConcern) *DatabaseOptions {
+ d.WriteConcern = wc
+ return d
+}
+
+// SetReadPreference sets the read preference for the database.
+func (d *DatabaseOptions) SetReadPreference(rp *readpref.ReadPref) *DatabaseOptions {
+ d.ReadPreference = rp
+ return d
+}
+
+// SetRegistry sets the bsoncodec Registry for the database.
+func (d *DatabaseOptions) SetRegistry(r *bsoncodec.Registry) *DatabaseOptions {
+ d.Registry = r
+ return d
+}
+
+// MergeDatabaseOptions combines the *DatabaseOptions arguments into a single *DatabaseOptions in a last one wins
+// fashion.
+func MergeDatabaseOptions(opts ...*DatabaseOptions) *DatabaseOptions {
+ d := Database()
+
+ for _, opt := range opts {
+ if opt == nil {
+ continue
+ }
+ if opt.ReadConcern != nil {
+ d.ReadConcern = opt.ReadConcern
+ }
+ if opt.WriteConcern != nil {
+ d.WriteConcern = opt.WriteConcern
+ }
+ if opt.ReadPreference != nil {
+ d.ReadPreference = opt.ReadPreference
+ }
+ if opt.Registry != nil {
+ d.Registry = opt.Registry
+ }
+ }
+
+ return d
+}
diff --git a/vendor/github.com/mongodb/mongo-go-driver/mongo/options/deleteoptions.go b/vendor/github.com/mongodb/mongo-go-driver/mongo/options/deleteoptions.go
new file mode 100644
index 0000000..919d6b8
--- /dev/null
+++ b/vendor/github.com/mongodb/mongo-go-driver/mongo/options/deleteoptions.go
@@ -0,0 +1,39 @@
+// Copyright (C) MongoDB, Inc. 2017-present.
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+
+package options
+
+// DeleteOptions represents all possible options to the deleteOne() and deleteMany() functions
+type DeleteOptions struct {
+ Collation *Collation // Specifies a collation
+}
+
+// Delete returns a pointer to a new DeleteOptions
+func Delete() *DeleteOptions {
+ return &DeleteOptions{}
+}
+
+// SetCollation specifies a collation
+// Valid for servers >= 3.4.
+func (do *DeleteOptions) SetCollation(c *Collation) *DeleteOptions {
+ do.Collation = c
+ return do
+}
+
+// MergeDeleteOptions combines the argued DeleteOptions into a single DeleteOptions in a last-one-wins fashion
+func MergeDeleteOptions(opts ...*DeleteOptions) *DeleteOptions {
+ dOpts := Delete()
+ for _, do := range opts {
+ if do == nil {
+ continue
+ }
+ if do.Collation != nil {
+ dOpts.Collation = do.Collation
+ }
+ }
+
+ return dOpts
+}
diff --git a/vendor/github.com/mongodb/mongo-go-driver/mongo/options/distinctoptions.go b/vendor/github.com/mongodb/mongo-go-driver/mongo/options/distinctoptions.go
new file mode 100644
index 0000000..3b3f588
--- /dev/null
+++ b/vendor/github.com/mongodb/mongo-go-driver/mongo/options/distinctoptions.go
@@ -0,0 +1,51 @@
+// Copyright (C) MongoDB, Inc. 2017-present.
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+
+package options
+
+import "time"
+
+// DistinctOptions represents all possible options to the distinct() function
+type DistinctOptions struct {
+ Collation *Collation // Specifies a collation
+ MaxTime *time.Duration // The maximum amount of time to allow the operation to run
+}
+
+// Distinct returns a pointer to a new DistinctOptions
+func Distinct() *DistinctOptions {
+ return &DistinctOptions{}
+}
+
+// SetCollation specifies a collation
+// Valid for server versions >= 3.4
+func (do *DistinctOptions) SetCollation(c *Collation) *DistinctOptions {
+ do.Collation = c
+ return do
+}
+
+// SetMaxTime specifies the maximum amount of time to allow the operation to run
+func (do *DistinctOptions) SetMaxTime(d time.Duration) *DistinctOptions {
+ do.MaxTime = &d
+ return do
+}
+
+// MergeDistinctOptions combines the argued DistinctOptions into a single DistinctOptions in a last-one-wins fashion
+func MergeDistinctOptions(opts ...*DistinctOptions) *DistinctOptions {
+ distinctOpts := Distinct()
+ for _, do := range opts {
+ if do == nil {
+ continue
+ }
+ if do.Collation != nil {
+ distinctOpts.Collation = do.Collation
+ }
+ if do.MaxTime != nil {
+ distinctOpts.MaxTime = do.MaxTime
+ }
+ }
+
+ return distinctOpts
+}
diff --git a/vendor/github.com/mongodb/mongo-go-driver/mongo/options/estimatedcountoptions.go b/vendor/github.com/mongodb/mongo-go-driver/mongo/options/estimatedcountoptions.go
new file mode 100644
index 0000000..f43bb9f
--- /dev/null
+++ b/vendor/github.com/mongodb/mongo-go-driver/mongo/options/estimatedcountoptions.go
@@ -0,0 +1,42 @@
+// Copyright (C) MongoDB, Inc. 2017-present.
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+
+package options
+
+import "time"
+
+// EstimatedDocumentCountOptions represents all possible options to the estimatedDocumentCount() function
+type EstimatedDocumentCountOptions struct {
+ MaxTime *time.Duration // The maximum amount of time to allow the operation to run
+}
+
+// EstimatedDocumentCount returns a pointer to a new EstimatedDocumentCountOptions
+func EstimatedDocumentCount() *EstimatedDocumentCountOptions {
+ return &EstimatedDocumentCountOptions{}
+}
+
+// SetMaxTime specifies the maximum amount of time to allow the operation to run
+func (eco *EstimatedDocumentCountOptions) SetMaxTime(d time.Duration) *EstimatedDocumentCountOptions {
+ eco.MaxTime = &d
+ return eco
+}
+
+// MergeEstimatedDocumentCountOptions combines the given *EstimatedDocumentCountOptions into a single
+// *EstimatedDocumentCountOptions in a last one wins fashion.
+func MergeEstimatedDocumentCountOptions(opts ...*EstimatedDocumentCountOptions) *EstimatedDocumentCountOptions {
+ e := EstimatedDocumentCount()
+ for _, opt := range opts {
+ if opt == nil {
+ continue
+ }
+
+ if opt.MaxTime != nil {
+ e.MaxTime = opt.MaxTime
+ }
+ }
+
+ return e
+}
diff --git a/vendor/github.com/mongodb/mongo-go-driver/mongo/options/findoptions.go b/vendor/github.com/mongodb/mongo-go-driver/mongo/options/findoptions.go
new file mode 100644
index 0000000..4ba6133
--- /dev/null
+++ b/vendor/github.com/mongodb/mongo-go-driver/mongo/options/findoptions.go
@@ -0,0 +1,693 @@
+// Copyright (C) MongoDB, Inc. 2017-present.
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+
+package options
+
+import (
+ "time"
+)
+
+// FindOptions represent all possible options to the find() function.
+type FindOptions struct {
+ AllowPartialResults *bool // If true, allows partial results to be returned if some shards are down.
+ BatchSize *int32 // Specifies the number of documents to return in every batch.
+ Collation *Collation // Specifies a collation to be used
+ Comment *string // Specifies a string to help trace the operation through the database.
+ CursorType *CursorType // Specifies the type of cursor to use
+ Hint interface{} // Specifies the index to use.
+ Limit *int64 // Sets a limit on the number of results to return.
+ Max interface{} // Sets an exclusive upper bound for a specific index
+ MaxAwaitTime *time.Duration // Specifies the maximum amount of time for the server to wait on new documents.
+ MaxTime *time.Duration // Specifies the maximum amount of time to allow the query to run.
+ Min interface{} // Specifies the inclusive lower bound for a specific index.
+ NoCursorTimeout *bool // If true, prevents cursors from timing out after an inactivity period.
+ OplogReplay *bool // Adds an option for internal use only and should not be set.
+ Projection interface{} // Limits the fields returned for all documents.
+ ReturnKey *bool // If true, only returns index keys for all result documents.
+ ShowRecordID *bool // If true, a $recordId field with the record identifier will be added to the returned documents.
+ Skip *int64 // Specifies the number of documents to skip before returning
+ Snapshot *bool // If true, prevents the cursor from returning a document more than once because of an intervening write operation.
+ Sort interface{} // Specifies the order in which to return results.
+}
+
+// Find creates a new FindOptions instance.
+func Find() *FindOptions {
+ return &FindOptions{}
+}
+
+// SetAllowPartialResults sets whether partial results can be returned if some shards are down.
+// For server versions < 3.2, this defaults to false.
+func (f *FindOptions) SetAllowPartialResults(b bool) *FindOptions {
+ f.AllowPartialResults = &b
+ return f
+}
+
+// SetBatchSize sets the number of documents to return in each batch.
+func (f *FindOptions) SetBatchSize(i int32) *FindOptions {
+ f.BatchSize = &i
+ return f
+}
+
+// SetCollation specifies a Collation to use for the Find operation.
+// Valid for server versions >= 3.4
+func (f *FindOptions) SetCollation(collation *Collation) *FindOptions {
+ f.Collation = collation
+ return f
+}
+
+// SetComment specifies a string to help trace the operation through the database.
+func (f *FindOptions) SetComment(comment string) *FindOptions {
+ f.Comment = &comment
+ return f
+}
+
+// SetCursorType specifes the type of cursor to use.
+func (f *FindOptions) SetCursorType(ct CursorType) *FindOptions {
+ f.CursorType = &ct
+ return f
+}
+
+// SetHint specifies the index to use.
+func (f *FindOptions) SetHint(hint interface{}) *FindOptions {
+ f.Hint = hint
+ return f
+}
+
+// SetLimit specifies a limit on the number of results.
+// A negative limit implies that only 1 batch should be returned.
+func (f *FindOptions) SetLimit(i int64) *FindOptions {
+ f.Limit = &i
+ return f
+}
+
+// SetMax specifies an exclusive upper bound for a specific index.
+func (f *FindOptions) SetMax(max interface{}) *FindOptions {
+ f.Max = max
+ return f
+}
+
+// SetMaxAwaitTime specifies the max amount of time for the server to wait on new documents.
+// If the cursor type is not TailableAwait, this option is ignored.
+// For server versions < 3.2, this option is ignored.
+func (f *FindOptions) SetMaxAwaitTime(d time.Duration) *FindOptions {
+ f.MaxAwaitTime = &d
+ return f
+}
+
+// SetMaxTime specifies the max time to allow the query to run.
+func (f *FindOptions) SetMaxTime(d time.Duration) *FindOptions {
+ f.MaxTime = &d
+ return f
+}
+
+// SetMin specifies the inclusive lower bound for a specific index.
+func (f *FindOptions) SetMin(min interface{}) *FindOptions {
+ f.Min = min
+ return f
+}
+
+// SetNoCursorTimeout specifies whether or not cursors should time out after a period of inactivity.
+// For server versions < 3.2, this defaults to false.
+func (f *FindOptions) SetNoCursorTimeout(b bool) *FindOptions {
+ f.NoCursorTimeout = &b
+ return f
+}
+
+// SetOplogReplay adds an option for internal use only and should not be set.
+// For server versions < 3.2, this defaults to false.
+func (f *FindOptions) SetOplogReplay(b bool) *FindOptions {
+ f.OplogReplay = &b
+ return f
+}
+
+// SetProjection adds an option to limit the fields returned for all documents.
+func (f *FindOptions) SetProjection(projection interface{}) *FindOptions {
+ f.Projection = projection
+ return f
+}
+
+// SetReturnKey adds an option to only return index keys for all result documents.
+func (f *FindOptions) SetReturnKey(b bool) *FindOptions {
+ f.ReturnKey = &b
+ return f
+}
+
+// SetShowRecordID adds an option to determine whether to return the record identifier for each document.
+// If true, a $recordId field will be added to each returned document.
+func (f *FindOptions) SetShowRecordID(b bool) *FindOptions {
+ f.ShowRecordID = &b
+ return f
+}
+
+// SetSkip specifies the number of documents to skip before returning.
+// For server versions < 3.2, this defaults to 0.
+func (f *FindOptions) SetSkip(i int64) *FindOptions {
+ f.Skip = &i
+ return f
+}
+
+// SetSnapshot prevents the cursor from returning a document more than once because of an intervening write operation.
+func (f *FindOptions) SetSnapshot(b bool) *FindOptions {
+ f.Snapshot = &b
+ return f
+}
+
+// SetSort specifies the order in which to return documents.
+func (f *FindOptions) SetSort(sort interface{}) *FindOptions {
+ f.Sort = sort
+ return f
+}
+
+// MergeFindOptions combines the argued FindOptions into a single FindOptions in a last-one-wins fashion
+func MergeFindOptions(opts ...*FindOptions) *FindOptions {
+ fo := Find()
+ for _, opt := range opts {
+ if opt == nil {
+ continue
+ }
+ if opt.AllowPartialResults != nil {
+ fo.AllowPartialResults = opt.AllowPartialResults
+ }
+ if opt.BatchSize != nil {
+ fo.BatchSize = opt.BatchSize
+ }
+ if opt.Collation != nil {
+ fo.Collation = opt.Collation
+ }
+ if opt.Comment != nil {
+ fo.Comment = opt.Comment
+ }
+ if opt.CursorType != nil {
+ fo.CursorType = opt.CursorType
+ }
+ if opt.Hint != nil {
+ fo.Hint = opt.Hint
+ }
+ if opt.Limit != nil {
+ fo.Limit = opt.Limit
+ }
+ if opt.Max != nil {
+ fo.Max = opt.Max
+ }
+ if opt.MaxAwaitTime != nil {
+ fo.MaxAwaitTime = opt.MaxAwaitTime
+ }
+ if opt.MaxTime != nil {
+ fo.MaxTime = opt.MaxTime
+ }
+ if opt.Min != nil {
+ fo.Min = opt.Min
+ }
+ if opt.NoCursorTimeout != nil {
+ fo.NoCursorTimeout = opt.NoCursorTimeout
+ }
+ if opt.OplogReplay != nil {
+ fo.OplogReplay = opt.OplogReplay
+ }
+ if opt.Projection != nil {
+ fo.Projection = opt.Projection
+ }
+ if opt.ReturnKey != nil {
+ fo.ReturnKey = opt.ReturnKey
+ }
+ if opt.ShowRecordID != nil {
+ fo.ShowRecordID = opt.ShowRecordID
+ }
+ if opt.Skip != nil {
+ fo.Skip = opt.Skip
+ }
+ if opt.Snapshot != nil {
+ fo.Snapshot = opt.Snapshot
+ }
+ if opt.Sort != nil {
+ fo.Sort = opt.Sort
+ }
+ }
+
+ return fo
+}
+
+// FindOneOptions represent all possible options to the findOne() function.
+type FindOneOptions struct {
+ AllowPartialResults *bool // If true, allows partial results to be returned if some shards are down.
+ BatchSize *int32 // Specifies the number of documents to return in every batch.
+ Collation *Collation // Specifies a collation to be used
+ Comment *string // Specifies a string to help trace the operation through the database.
+ CursorType *CursorType // Specifies the type of cursor to use
+ Hint interface{} // Specifies the index to use.
+ Max interface{} // Sets an exclusive upper bound for a specific index
+ MaxAwaitTime *time.Duration // Specifies the maximum amount of time for the server to wait on new documents.
+ MaxTime *time.Duration // Specifies the maximum amount of time to allow the query to run.
+ Min interface{} // Specifies the inclusive lower bound for a specific index.
+ NoCursorTimeout *bool // If true, prevents cursors from timing out after an inactivity period.
+ OplogReplay *bool // Adds an option for internal use only and should not be set.
+ Projection interface{} // Limits the fields returned for all documents.
+ ReturnKey *bool // If true, only returns index keys for all result documents.
+ ShowRecordID *bool // If true, a $recordId field with the record identifier will be added to the returned documents.
+ Skip *int64 // Specifies the number of documents to skip before returning
+ Snapshot *bool // If true, prevents the cursor from returning a document more than once because of an intervening write operation.
+ Sort interface{} // Specifies the order in which to return results.
+}
+
+// FindOne creates a new FindOneOptions instance.
+func FindOne() *FindOneOptions {
+ return &FindOneOptions{}
+}
+
+// SetAllowPartialResults sets whether partial results can be returned if some shards are down.
+func (f *FindOneOptions) SetAllowPartialResults(b bool) *FindOneOptions {
+ f.AllowPartialResults = &b
+ return f
+}
+
+// SetBatchSize sets the number of documents to return in each batch.
+func (f *FindOneOptions) SetBatchSize(i int32) *FindOneOptions {
+ f.BatchSize = &i
+ return f
+}
+
+// SetCollation specifies a Collation to use for the Find operation.
+func (f *FindOneOptions) SetCollation(collation *Collation) *FindOneOptions {
+ f.Collation = collation
+ return f
+}
+
+// SetComment specifies a string to help trace the operation through the database.
+func (f *FindOneOptions) SetComment(comment string) *FindOneOptions {
+ f.Comment = &comment
+ return f
+}
+
+// SetCursorType specifes the type of cursor to use.
+func (f *FindOneOptions) SetCursorType(ct CursorType) *FindOneOptions {
+ f.CursorType = &ct
+ return f
+}
+
+// SetHint specifies the index to use.
+func (f *FindOneOptions) SetHint(hint interface{}) *FindOneOptions {
+ f.Hint = hint
+ return f
+}
+
+// SetMax specifies an exclusive upper bound for a specific index.
+func (f *FindOneOptions) SetMax(max interface{}) *FindOneOptions {
+ f.Max = max
+ return f
+}
+
+// SetMaxAwaitTime specifies the max amount of time for the server to wait on new documents.
+// For server versions < 3.2, this option is ignored.
+func (f *FindOneOptions) SetMaxAwaitTime(d time.Duration) *FindOneOptions {
+ f.MaxAwaitTime = &d
+ return f
+}
+
+// SetMaxTime specifies the max time to allow the query to run.
+func (f *FindOneOptions) SetMaxTime(d time.Duration) *FindOneOptions {
+ f.MaxTime = &d
+ return f
+}
+
+// SetMin specifies the inclusive lower bound for a specific index.
+func (f *FindOneOptions) SetMin(min interface{}) *FindOneOptions {
+ f.Min = min
+ return f
+}
+
+// SetNoCursorTimeout specifies whether or not cursors should time out after a period of inactivity.
+func (f *FindOneOptions) SetNoCursorTimeout(b bool) *FindOneOptions {
+ f.NoCursorTimeout = &b
+ return f
+}
+
+// SetOplogReplay adds an option for internal use only and should not be set.
+func (f *FindOneOptions) SetOplogReplay(b bool) *FindOneOptions {
+ f.OplogReplay = &b
+ return f
+}
+
+// SetProjection adds an option to limit the fields returned for all documents.
+func (f *FindOneOptions) SetProjection(projection interface{}) *FindOneOptions {
+ f.Projection = projection
+ return f
+}
+
+// SetReturnKey adds an option to only return index keys for all result documents.
+func (f *FindOneOptions) SetReturnKey(b bool) *FindOneOptions {
+ f.ReturnKey = &b
+ return f
+}
+
+// SetShowRecordID adds an option to determine whether to return the record identifier for each document.
+// If true, a $recordId field will be added to each returned document.
+func (f *FindOneOptions) SetShowRecordID(b bool) *FindOneOptions {
+ f.ShowRecordID = &b
+ return f
+}
+
+// SetSkip specifies the number of documents to skip before returning.
+func (f *FindOneOptions) SetSkip(i int64) *FindOneOptions {
+ f.Skip = &i
+ return f
+}
+
+// SetSnapshot prevents the cursor from returning a document more than once because of an intervening write operation.
+func (f *FindOneOptions) SetSnapshot(b bool) *FindOneOptions {
+ f.Snapshot = &b
+ return f
+}
+
+// SetSort specifies the order in which to return documents.
+func (f *FindOneOptions) SetSort(sort interface{}) *FindOneOptions {
+ f.Sort = sort
+ return f
+}
+
+// MergeFindOneOptions combines the argued FindOneOptions into a single FindOneOptions in a last-one-wins fashion
+func MergeFindOneOptions(opts ...*FindOneOptions) *FindOneOptions {
+ fo := FindOne()
+ for _, opt := range opts {
+ if opt == nil {
+ continue
+ }
+ if opt.AllowPartialResults != nil {
+ fo.AllowPartialResults = opt.AllowPartialResults
+ }
+ if opt.BatchSize != nil {
+ fo.BatchSize = opt.BatchSize
+ }
+ if opt.Collation != nil {
+ fo.Collation = opt.Collation
+ }
+ if opt.Comment != nil {
+ fo.Comment = opt.Comment
+ }
+ if opt.CursorType != nil {
+ fo.CursorType = opt.CursorType
+ }
+ if opt.Hint != nil {
+ fo.Hint = opt.Hint
+ }
+ if opt.Max != nil {
+ fo.Max = opt.Max
+ }
+ if opt.MaxAwaitTime != nil {
+ fo.MaxAwaitTime = opt.MaxAwaitTime
+ }
+ if opt.MaxTime != nil {
+ fo.MaxTime = opt.MaxTime
+ }
+ if opt.Min != nil {
+ fo.Min = opt.Min
+ }
+ if opt.NoCursorTimeout != nil {
+ fo.NoCursorTimeout = opt.NoCursorTimeout
+ }
+ if opt.OplogReplay != nil {
+ fo.OplogReplay = opt.OplogReplay
+ }
+ if opt.Projection != nil {
+ fo.Projection = opt.Projection
+ }
+ if opt.ReturnKey != nil {
+ fo.ReturnKey = opt.ReturnKey
+ }
+ if opt.ShowRecordID != nil {
+ fo.ShowRecordID = opt.ShowRecordID
+ }
+ if opt.Skip != nil {
+ fo.Skip = opt.Skip
+ }
+ if opt.Snapshot != nil {
+ fo.Snapshot = opt.Snapshot
+ }
+ if opt.Sort != nil {
+ fo.Sort = opt.Sort
+ }
+ }
+
+ return fo
+}
+
+// FindOneAndReplaceOptions represent all possible options to the findOne() function.
+type FindOneAndReplaceOptions struct {
+ BypassDocumentValidation *bool // If true, allows the write to opt out of document-level validation.
+ Collation *Collation // Specifies a collation to be used
+ MaxTime *time.Duration // Specifies the maximum amount of time to allow the query to run.
+ Projection interface{} // Limits the fields returned for all documents.
+ ReturnDocument *ReturnDocument // Specifies whether the original or updated document should be returned.
+ Sort interface{} // Specifies the order in which to return results.
+ Upsert *bool // If true, creates a a new document if no document matches the query.
+}
+
+// FindOneAndReplace creates a new FindOneAndReplaceOptions instance.
+func FindOneAndReplace() *FindOneAndReplaceOptions {
+ return &FindOneAndReplaceOptions{}
+}
+
+// SetBypassDocumentValidation specifies whether or not the write should opt out of document-level validation.
+// Valid for server versions >= 3.2. For servers < 3.2, this option is ignored.
+func (f *FindOneAndReplaceOptions) SetBypassDocumentValidation(b bool) *FindOneAndReplaceOptions {
+ f.BypassDocumentValidation = &b
+ return f
+}
+
+// SetCollation specifies a Collation to use for the Find operation.
+func (f *FindOneAndReplaceOptions) SetCollation(collation *Collation) *FindOneAndReplaceOptions {
+ f.Collation = collation
+ return f
+}
+
+// SetMaxTime specifies the max time to allow the query to run.
+func (f *FindOneAndReplaceOptions) SetMaxTime(d time.Duration) *FindOneAndReplaceOptions {
+ f.MaxTime = &d
+ return f
+}
+
+// SetProjection adds an option to limit the fields returned for all documents.
+func (f *FindOneAndReplaceOptions) SetProjection(projection interface{}) *FindOneAndReplaceOptions {
+ f.Projection = projection
+ return f
+}
+
+// SetReturnDocument specifies whether the original or updated document should be returned.
+// If set to Before, the original document will be returned. If set to After, the updated document
+// will be returned.
+func (f *FindOneAndReplaceOptions) SetReturnDocument(rd ReturnDocument) *FindOneAndReplaceOptions {
+ f.ReturnDocument = &rd
+ return f
+}
+
+// SetSort specifies the order in which to return documents.
+func (f *FindOneAndReplaceOptions) SetSort(sort interface{}) *FindOneAndReplaceOptions {
+ f.Sort = sort
+ return f
+}
+
+// SetUpsert specifies if a new document should be created if no document matches the query.
+func (f *FindOneAndReplaceOptions) SetUpsert(b bool) *FindOneAndReplaceOptions {
+ f.Upsert = &b
+ return f
+}
+
+// MergeFindOneAndReplaceOptions combines the argued FindOneAndReplaceOptions into a single FindOneAndReplaceOptions in a last-one-wins fashion
+func MergeFindOneAndReplaceOptions(opts ...*FindOneAndReplaceOptions) *FindOneAndReplaceOptions {
+ fo := FindOneAndReplace()
+ for _, opt := range opts {
+ if opt == nil {
+ continue
+ }
+ if opt.BypassDocumentValidation != nil {
+ fo.BypassDocumentValidation = opt.BypassDocumentValidation
+ }
+ if opt.Collation != nil {
+ fo.Collation = opt.Collation
+ }
+ if opt.MaxTime != nil {
+ fo.MaxTime = opt.MaxTime
+ }
+ if opt.Projection != nil {
+ fo.Projection = opt.Projection
+ }
+ if opt.ReturnDocument != nil {
+ fo.ReturnDocument = opt.ReturnDocument
+ }
+ if opt.Sort != nil {
+ fo.Sort = opt.Sort
+ }
+ if opt.Upsert != nil {
+ fo.Upsert = opt.Upsert
+ }
+ }
+
+ return fo
+}
+
+// FindOneAndUpdateOptions represent all possible options to the findOne() function.
+type FindOneAndUpdateOptions struct {
+ ArrayFilters *ArrayFilters // A set of filters specifying to which array elements an update should apply.
+ BypassDocumentValidation *bool // If true, allows the write to opt out of document-level validation.
+ Collation *Collation // Specifies a collation to be used
+ MaxTime *time.Duration // Specifies the maximum amount of time to allow the query to run.
+ Projection interface{} // Limits the fields returned for all documents.
+ ReturnDocument *ReturnDocument // Specifies whether the original or updated document should be returned.
+ Sort interface{} // Specifies the order in which to return results.
+ Upsert *bool // If true, creates a a new document if no document matches the query.
+}
+
+// FindOneAndUpdate creates a new FindOneAndUpdateOptions instance.
+func FindOneAndUpdate() *FindOneAndUpdateOptions {
+ return &FindOneAndUpdateOptions{}
+}
+
+// SetBypassDocumentValidation sets filters that specify to which array elements an update should apply.
+func (f *FindOneAndUpdateOptions) SetBypassDocumentValidation(b bool) *FindOneAndUpdateOptions {
+ f.BypassDocumentValidation = &b
+ return f
+}
+
+// SetArrayFilters specifies a set of filters, which
+func (f *FindOneAndUpdateOptions) SetArrayFilters(filters ArrayFilters) *FindOneAndUpdateOptions {
+ f.ArrayFilters = &filters
+ return f
+}
+
+// SetCollation specifies a Collation to use for the Find operation.
+func (f *FindOneAndUpdateOptions) SetCollation(collation *Collation) *FindOneAndUpdateOptions {
+ f.Collation = collation
+ return f
+}
+
+// SetMaxTime specifies the max time to allow the query to run.
+func (f *FindOneAndUpdateOptions) SetMaxTime(d time.Duration) *FindOneAndUpdateOptions {
+ f.MaxTime = &d
+ return f
+}
+
+// SetProjection adds an option to limit the fields returned for all documents.
+func (f *FindOneAndUpdateOptions) SetProjection(projection interface{}) *FindOneAndUpdateOptions {
+ f.Projection = projection
+ return f
+}
+
+// SetReturnDocument specifies whether the original or updated document should be returned.
+// If set to Before, the original document will be returned. If set to After, the updated document
+// will be returned.
+func (f *FindOneAndUpdateOptions) SetReturnDocument(rd ReturnDocument) *FindOneAndUpdateOptions {
+ f.ReturnDocument = &rd
+ return f
+}
+
+// SetSort specifies the order in which to return documents.
+func (f *FindOneAndUpdateOptions) SetSort(sort interface{}) *FindOneAndUpdateOptions {
+ f.Sort = sort
+ return f
+}
+
+// SetUpsert specifies if a new document should be created if no document matches the query.
+func (f *FindOneAndUpdateOptions) SetUpsert(b bool) *FindOneAndUpdateOptions {
+ f.Upsert = &b
+ return f
+}
+
+// MergeFindOneAndUpdateOptions combines the argued FindOneAndUpdateOptions into a single FindOneAndUpdateOptions in a last-one-wins fashion
+func MergeFindOneAndUpdateOptions(opts ...*FindOneAndUpdateOptions) *FindOneAndUpdateOptions {
+ fo := FindOneAndUpdate()
+ for _, opt := range opts {
+ if opt == nil {
+ continue
+ }
+ if opt.ArrayFilters != nil {
+ fo.ArrayFilters = opt.ArrayFilters
+ }
+ if opt.BypassDocumentValidation != nil {
+ fo.BypassDocumentValidation = opt.BypassDocumentValidation
+ }
+ if opt.Collation != nil {
+ fo.Collation = opt.Collation
+ }
+ if opt.MaxTime != nil {
+ fo.MaxTime = opt.MaxTime
+ }
+ if opt.Projection != nil {
+ fo.Projection = opt.Projection
+ }
+ if opt.ReturnDocument != nil {
+ fo.ReturnDocument = opt.ReturnDocument
+ }
+ if opt.Sort != nil {
+ fo.Sort = opt.Sort
+ }
+ if opt.Upsert != nil {
+ fo.Upsert = opt.Upsert
+ }
+ }
+
+ return fo
+}
+
+// FindOneAndDeleteOptions represent all possible options to the findOne() function.
+type FindOneAndDeleteOptions struct {
+ Collation *Collation // Specifies a collation to be used
+ MaxTime *time.Duration // Specifies the maximum amount of time to allow the query to run.
+ Projection interface{} // Limits the fields returned for all documents.
+ Sort interface{} // Specifies the order in which to return results.
+}
+
+// FindOneAndDelete creates a new FindOneAndDeleteOptions instance.
+func FindOneAndDelete() *FindOneAndDeleteOptions {
+ return &FindOneAndDeleteOptions{}
+}
+
+// SetCollation specifies a Collation to use for the Find operation.
+// Valid for server versions >= 3.4
+func (f *FindOneAndDeleteOptions) SetCollation(collation *Collation) *FindOneAndDeleteOptions {
+ f.Collation = collation
+ return f
+}
+
+// SetMaxTime specifies the max time to allow the query to run.
+func (f *FindOneAndDeleteOptions) SetMaxTime(d time.Duration) *FindOneAndDeleteOptions {
+ f.MaxTime = &d
+ return f
+}
+
+// SetProjection adds an option to limit the fields returned for all documents.
+func (f *FindOneAndDeleteOptions) SetProjection(projection interface{}) *FindOneAndDeleteOptions {
+ f.Projection = projection
+ return f
+}
+
+// SetSort specifies the order in which to return documents.
+func (f *FindOneAndDeleteOptions) SetSort(sort interface{}) *FindOneAndDeleteOptions {
+ f.Sort = sort
+ return f
+}
+
+// MergeFindOneAndDeleteOptions combines the argued FindOneAndDeleteOptions into a single FindOneAndDeleteOptions in a last-one-wins fashion
+func MergeFindOneAndDeleteOptions(opts ...*FindOneAndDeleteOptions) *FindOneAndDeleteOptions {
+ fo := FindOneAndDelete()
+ for _, opt := range opts {
+ if opt == nil {
+ continue
+ }
+ if opt.Collation != nil {
+ fo.Collation = opt.Collation
+ }
+ if opt.MaxTime != nil {
+ fo.MaxTime = opt.MaxTime
+ }
+ if opt.Projection != nil {
+ fo.Projection = opt.Projection
+ }
+ if opt.Sort != nil {
+ fo.Sort = opt.Sort
+ }
+ }
+
+ return fo
+}
diff --git a/vendor/github.com/mongodb/mongo-go-driver/mongo/options/gridfsoptions.go b/vendor/github.com/mongodb/mongo-go-driver/mongo/options/gridfsoptions.go
new file mode 100644
index 0000000..232a1c8
--- /dev/null
+++ b/vendor/github.com/mongodb/mongo-go-driver/mongo/options/gridfsoptions.go
@@ -0,0 +1,268 @@
+// Copyright (C) MongoDB, Inc. 2017-present.
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+
+package options
+
+import (
+ "time"
+
+ "github.com/mongodb/mongo-go-driver/mongo/readconcern"
+ "github.com/mongodb/mongo-go-driver/mongo/readpref"
+ "github.com/mongodb/mongo-go-driver/mongo/writeconcern"
+ "github.com/mongodb/mongo-go-driver/x/bsonx"
+)
+
+// DefaultName is the default name for a GridFS bucket.
+var DefaultName = "fs"
+
+// DefaultChunkSize is the default size of each file chunk in bytes.
+var DefaultChunkSize int32 = 255 * 1000
+
+// DefaultRevision is the default revision number for a download by name operation.
+var DefaultRevision int32 = -1
+
+// BucketOptions represents all possible options to configure a GridFS bucket.
+type BucketOptions struct {
+ Name *string // The bucket name. Defaults to "fs".
+ ChunkSizeBytes *int32 // The chunk size in bytes. Defaults to 255KB.
+ WriteConcern *writeconcern.WriteConcern // The write concern for the bucket. Defaults to the write concern of the database.
+ ReadConcern *readconcern.ReadConcern // The read concern for the bucket. Defaults to the read concern of the database.
+ ReadPreference *readpref.ReadPref // The read preference for the bucket. Defaults to the read preference of the database.
+}
+
+// GridFSBucket creates a new *BucketOptions
+func GridFSBucket() *BucketOptions {
+ return &BucketOptions{
+ Name: &DefaultName,
+ ChunkSizeBytes: &DefaultChunkSize,
+ }
+}
+
+// SetName sets the name for the bucket. Defaults to "fs" if not set.
+func (b *BucketOptions) SetName(name string) *BucketOptions {
+ b.Name = &name
+ return b
+}
+
+// SetChunkSizeBytes sets the chunk size in bytes for the bucket. Defaults to 255KB if not set.
+func (b *BucketOptions) SetChunkSizeBytes(i int32) *BucketOptions {
+ b.ChunkSizeBytes = &i
+ return b
+}
+
+// SetWriteConcern sets the write concern for the bucket.
+func (b *BucketOptions) SetWriteConcern(wc *writeconcern.WriteConcern) *BucketOptions {
+ b.WriteConcern = wc
+ return b
+}
+
+// SetReadConcern sets the read concern for the bucket.
+func (b *BucketOptions) SetReadConcern(rc *readconcern.ReadConcern) *BucketOptions {
+ b.ReadConcern = rc
+ return b
+}
+
+// SetReadPreference sets the read preference for the bucket.
+func (b *BucketOptions) SetReadPreference(rp *readpref.ReadPref) *BucketOptions {
+ b.ReadPreference = rp
+ return b
+}
+
+// MergeBucketOptions combines the given *BucketOptions into a single *BucketOptions.
+// If the name or chunk size is not set in any of the given *BucketOptions, the resulting *BucketOptions will have
+// name "fs" and chunk size 255KB.
+func MergeBucketOptions(opts ...*BucketOptions) *BucketOptions {
+ b := GridFSBucket()
+
+ for _, opt := range opts {
+ if opt == nil {
+ continue
+ }
+ if opt.Name != nil {
+ b.Name = opt.Name
+ }
+ if opt.ChunkSizeBytes != nil {
+ b.ChunkSizeBytes = opt.ChunkSizeBytes
+ }
+ if opt.WriteConcern != nil {
+ b.WriteConcern = opt.WriteConcern
+ }
+ if opt.ReadConcern != nil {
+ b.ReadConcern = opt.ReadConcern
+ }
+ if opt.ReadPreference != nil {
+ b.ReadPreference = opt.ReadPreference
+ }
+ }
+
+ return b
+}
+
+// UploadOptions represents all possible options for a GridFS upload operation.
+type UploadOptions struct {
+ ChunkSizeBytes *int32 // Chunk size in bytes. Defaults to the chunk size of the bucket.
+ Metadata bsonx.Doc // User data for the 'metadata' field of the files collection document.
+}
+
+// GridFSUpload creates a new *UploadOptions
+func GridFSUpload() *UploadOptions {
+ return &UploadOptions{}
+}
+
+// SetChunkSizeBytes sets the chunk size in bytes for the upload. Defaults to 255KB if not set.
+func (u *UploadOptions) SetChunkSizeBytes(i int32) *UploadOptions {
+ u.ChunkSizeBytes = &i
+ return u
+}
+
+// SetMetadata specfies the metadata for the upload.
+func (u *UploadOptions) SetMetadata(doc bsonx.Doc) *UploadOptions {
+ u.Metadata = doc
+ return u
+}
+
+// MergeUploadOptions combines the given *UploadOptions into a single *UploadOptions.
+// If the chunk size is not set in any of the given *UploadOptions, the resulting *UploadOptions will have chunk size
+// 255KB.
+func MergeUploadOptions(opts ...*UploadOptions) *UploadOptions {
+ u := GridFSUpload()
+
+ for _, opt := range opts {
+ if opt == nil {
+ continue
+ }
+ if opt.ChunkSizeBytes != nil {
+ u.ChunkSizeBytes = opt.ChunkSizeBytes
+ }
+ if opt.Metadata != nil {
+ u.Metadata = opt.Metadata
+ }
+ }
+
+ return u
+}
+
+// NameOptions represents all options that can be used for a GridFS download by name operation.
+type NameOptions struct {
+ Revision *int32 // Which revision (documents with the same filename and different uploadDate). Defaults to -1 (the most recent revision).
+}
+
+// GridFSName creates a new *NameOptions
+func GridFSName() *NameOptions {
+ return &NameOptions{}
+}
+
+// SetRevision specifies which revision of the file to retrieve. Defaults to -1.
+// * Revision numbers are defined as follows:
+// * 0 = the original stored file
+// * 1 = the first revision
+// * 2 = the second revision
+// * etc…
+// * -2 = the second most recent revision
+// * -1 = the most recent revision
+func (n *NameOptions) SetRevision(r int32) *NameOptions {
+ n.Revision = &r
+ return n
+}
+
+// MergeNameOptions combines the given *NameOptions into a single *NameOptions in a last one wins fashion.
+func MergeNameOptions(opts ...*NameOptions) *NameOptions {
+ n := GridFSName()
+ n.Revision = &DefaultRevision
+
+ for _, opt := range opts {
+ if opt == nil {
+ continue
+ }
+ if opt.Revision != nil {
+ n.Revision = opt.Revision
+ }
+ }
+
+ return n
+}
+
+// GridFSFindOptions represents all options for a GridFS find operation.
+type GridFSFindOptions struct {
+ BatchSize *int32
+ Limit *int32
+ MaxTime *time.Duration
+ NoCursorTimeout *bool
+ Skip *int32
+ Sort interface{}
+}
+
+// GridFSFind creates a new GridFSFindOptions instance.
+func GridFSFind() *GridFSFindOptions {
+ return &GridFSFindOptions{}
+}
+
+// SetBatchSize sets the number of documents to return in each batch.
+func (f *GridFSFindOptions) SetBatchSize(i int32) *GridFSFindOptions {
+ f.BatchSize = &i
+ return f
+}
+
+// SetLimit specifies a limit on the number of results.
+// A negative limit implies that only 1 batch should be returned.
+func (f *GridFSFindOptions) SetLimit(i int32) *GridFSFindOptions {
+ f.Limit = &i
+ return f
+}
+
+// SetMaxTime specifies the max time to allow the query to run.
+func (f *GridFSFindOptions) SetMaxTime(d time.Duration) *GridFSFindOptions {
+ f.MaxTime = &d
+ return f
+}
+
+// SetNoCursorTimeout specifies whether or not cursors should time out after a period of inactivity.
+func (f *GridFSFindOptions) SetNoCursorTimeout(b bool) *GridFSFindOptions {
+ f.NoCursorTimeout = &b
+ return f
+}
+
+// SetSkip specifies the number of documents to skip before returning.
+func (f *GridFSFindOptions) SetSkip(i int32) *GridFSFindOptions {
+ f.Skip = &i
+ return f
+}
+
+// SetSort specifies the order in which to return documents.
+func (f *GridFSFindOptions) SetSort(sort interface{}) *GridFSFindOptions {
+ f.Sort = sort
+ return f
+}
+
+// MergeGridFSFindOptions combines the argued GridFSFindOptions into a single GridFSFindOptions in a last-one-wins fashion
+func MergeGridFSFindOptions(opts ...*GridFSFindOptions) *GridFSFindOptions {
+ fo := GridFSFind()
+ for _, opt := range opts {
+ if opt == nil {
+ continue
+ }
+ if opt.BatchSize != nil {
+ fo.BatchSize = opt.BatchSize
+ }
+ if opt.Limit != nil {
+ fo.Limit = opt.Limit
+ }
+ if opt.MaxTime != nil {
+ fo.MaxTime = opt.MaxTime
+ }
+ if opt.NoCursorTimeout != nil {
+ fo.NoCursorTimeout = opt.NoCursorTimeout
+ }
+ if opt.Skip != nil {
+ fo.Skip = opt.Skip
+ }
+ if opt.Sort != nil {
+ fo.Sort = opt.Sort
+ }
+ }
+
+ return fo
+}
diff --git a/vendor/github.com/mongodb/mongo-go-driver/mongo/options/indexoptions.go b/vendor/github.com/mongodb/mongo-go-driver/mongo/options/indexoptions.go
new file mode 100644
index 0000000..2fda698
--- /dev/null
+++ b/vendor/github.com/mongodb/mongo-go-driver/mongo/options/indexoptions.go
@@ -0,0 +1,326 @@
+// Copyright (C) MongoDB, Inc. 2017-present.
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+
+package options
+
+import (
+ "time"
+)
+
+// CreateIndexesOptions represents all possible options for the create() function.
+type CreateIndexesOptions struct {
+ MaxTime *time.Duration // The maximum amount of time to allow the query to run.
+}
+
+// CreateIndexes creates a new CreateIndexesOptions instance.
+func CreateIndexes() *CreateIndexesOptions {
+ return &CreateIndexesOptions{}
+}
+
+// SetMaxTime specifies the maximum amount of time to allow the query to run.
+func (c *CreateIndexesOptions) SetMaxTime(d time.Duration) *CreateIndexesOptions {
+ c.MaxTime = &d
+ return c
+}
+
+// MergeCreateIndexesOptions combines the given *CreateIndexesOptions into a single *CreateIndexesOptions in a last one
+// wins fashion.
+func MergeCreateIndexesOptions(opts ...*CreateIndexesOptions) *CreateIndexesOptions {
+ c := CreateIndexes()
+ for _, opt := range opts {
+ if opt == nil {
+ continue
+ }
+ if opt.MaxTime != nil {
+ c.MaxTime = opt.MaxTime
+ }
+ }
+
+ return c
+}
+
+// DropIndexesOptions represents all possible options for the create() function.
+type DropIndexesOptions struct {
+ MaxTime *time.Duration
+}
+
+// DropIndexes creates a new DropIndexesOptions instance.
+func DropIndexes() *DropIndexesOptions {
+ return &DropIndexesOptions{}
+}
+
+// SetMaxTime specifies the maximum amount of time to allow the query to run.
+func (d *DropIndexesOptions) SetMaxTime(duration time.Duration) *DropIndexesOptions {
+ d.MaxTime = &duration
+ return d
+}
+
+// MergeDropIndexesOptions combines the given *DropIndexesOptions into a single *DropIndexesOptions in a last one
+// wins fashion.
+func MergeDropIndexesOptions(opts ...*DropIndexesOptions) *DropIndexesOptions {
+ c := DropIndexes()
+ for _, opt := range opts {
+ if opt == nil {
+ continue
+ }
+ if opt.MaxTime != nil {
+ c.MaxTime = opt.MaxTime
+ }
+ }
+
+ return c
+}
+
+// ListIndexesOptions represents all possible options for the create() function.
+type ListIndexesOptions struct {
+ BatchSize *int32
+ MaxTime *time.Duration
+}
+
+// ListIndexes creates a new ListIndexesOptions instance.
+func ListIndexes() *ListIndexesOptions {
+ return &ListIndexesOptions{}
+}
+
+// SetBatchSize specifies the number of documents to return in every batch.
+func (l *ListIndexesOptions) SetBatchSize(i int32) *ListIndexesOptions {
+ l.BatchSize = &i
+ return l
+}
+
+// SetMaxTime specifies the maximum amount of time to allow the query to run.
+func (l *ListIndexesOptions) SetMaxTime(d time.Duration) *ListIndexesOptions {
+ l.MaxTime = &d
+ return l
+}
+
+// MergeListIndexesOptions combines the given *ListIndexesOptions into a single *ListIndexesOptions in a last one
+// wins fashion.
+func MergeListIndexesOptions(opts ...*ListIndexesOptions) *ListIndexesOptions {
+ c := ListIndexes()
+ for _, opt := range opts {
+ if opt == nil {
+ continue
+ }
+ if opt.MaxTime != nil {
+ c.MaxTime = opt.MaxTime
+ }
+ }
+
+ return c
+}
+
+// IndexOptions represents all possible options to configure a new index.
+type IndexOptions struct {
+ Background *bool
+ ExpireAfterSeconds *int32
+ Name *string
+ Sparse *bool
+ StorageEngine interface{}
+ Unique *bool
+ Version *int32
+ DefaultLanguage *string
+ LanguageOverride *string
+ TextVersion *int32
+ Weights interface{}
+ SphereVersion *int32
+ Bits *int32
+ Max *float64
+ Min *float64
+ BucketSize *int32
+ PartialFilterExpression interface{}
+ Collation *Collation
+}
+
+// Index creates a new *IndexOptions
+func Index() *IndexOptions {
+ return &IndexOptions{}
+}
+
+// SetBackground sets the background option. If true, the server will create the index in the background and not block
+// other tasks
+func (i *IndexOptions) SetBackground(background bool) *IndexOptions {
+ i.Background = &background
+ return i
+}
+
+// SetExpireAfterSeconds specifies the number of seconds for a document to remain in a collection.
+func (i *IndexOptions) SetExpireAfterSeconds(seconds int32) *IndexOptions {
+ i.ExpireAfterSeconds = &seconds
+ return i
+}
+
+// SetName specifies a name for the index.
+// If not set, a name will be generated in the format "[field]_[direction]".
+// If multiple indexes are created for the same key pattern with different collations, a name must be provided to avoid
+// ambiguity.
+func (i *IndexOptions) SetName(name string) *IndexOptions {
+ i.Name = &name
+ return i
+}
+
+// SetSparse sets the sparse option.
+// If true, the index will only reference documents with the specified field in the index.
+func (i *IndexOptions) SetSparse(sparse bool) *IndexOptions {
+ i.Sparse = &sparse
+ return i
+}
+
+// SetStorageEngine specifies the storage engine to use.
+// Valid for server versions >= 3.0
+func (i *IndexOptions) SetStorageEngine(engine interface{}) *IndexOptions {
+ i.StorageEngine = engine
+ return i
+}
+
+// SetUnique forces the index to be unique.
+func (i *IndexOptions) SetUnique(unique bool) *IndexOptions {
+ i.Unique = &unique
+ return i
+}
+
+// SetVersion specifies the index version number, either 0 or 1.
+func (i *IndexOptions) SetVersion(version int32) *IndexOptions {
+ i.Version = &version
+ return i
+}
+
+// SetDefaultLanguage specifies the default language for text indexes.
+// If not set, this will default to english.
+func (i *IndexOptions) SetDefaultLanguage(language string) *IndexOptions {
+ i.DefaultLanguage = &language
+ return i
+}
+
+// SetLanguageOverride specifies the field in the document to override the language.
+func (i *IndexOptions) SetLanguageOverride(override string) *IndexOptions {
+ i.LanguageOverride = &override
+ return i
+}
+
+// SetTextVersion specifies the text index version number.
+// MongoDB version 2.4 can only support version 1.
+// MongoDB versions 2.6 and higher can support versions 1 or 2.
+func (i *IndexOptions) SetTextVersion(version int32) *IndexOptions {
+ i.TextVersion = &version
+ return i
+}
+
+// SetWeights specifies fields in the index and their corresponding weight values.
+func (i *IndexOptions) SetWeights(weights interface{}) *IndexOptions {
+ i.Weights = weights
+ return i
+}
+
+// SetSphereVersion specifies the 2dsphere index version number.
+// MongoDB version 2.4 can only support version 1.
+// MongoDB versions 2.6 and higher can support versions 1 or 2.
+func (i *IndexOptions) SetSphereVersion(version int32) *IndexOptions {
+ i.SphereVersion = &version
+ return i
+}
+
+// SetBits specifies the precision of the stored geo hash in the 2d index, from 1 to 32.
+func (i *IndexOptions) SetBits(bits int32) *IndexOptions {
+ i.Bits = &bits
+ return i
+}
+
+// SetMax specifies the maximum boundary for latitude and longitude in the 2d index.
+func (i *IndexOptions) SetMax(max float64) *IndexOptions {
+ i.Max = &max
+ return i
+}
+
+// SetMin specifies the minimum boundary for latitude and longitude in the 2d index.
+func (i *IndexOptions) SetMin(min float64) *IndexOptions {
+ i.Min = &min
+ return i
+}
+
+// SetBucketSize specifies number of units within which to group the location values in a geo haystack index.
+func (i *IndexOptions) SetBucketSize(bucketSize int32) *IndexOptions {
+ i.BucketSize = &bucketSize
+ return i
+}
+
+// SetPartialFilterExpression specifies a filter for use in a partial index. Only documents that match the filter
+// expression are included in the index.
+func (i *IndexOptions) SetPartialFilterExpression(expression interface{}) *IndexOptions {
+ i.PartialFilterExpression = expression
+ return i
+}
+
+// SetCollation specifies a Collation to use for the operation.
+// Valid for server versions >= 3.4
+func (i *IndexOptions) SetCollation(collation *Collation) *IndexOptions {
+ i.Collation = collation
+ return i
+}
+
+// MergeIndexOptions combines the given *IndexOptions into a single *IndexOptions in a last one wins fashion.
+func MergeIndexOptions(opts ...*IndexOptions) *IndexOptions {
+ i := Index()
+
+ for _, opt := range opts {
+ if opt.Background != nil {
+ i.Background = opt.Background
+ }
+ if opt.ExpireAfterSeconds != nil {
+ i.ExpireAfterSeconds = opt.ExpireAfterSeconds
+ }
+ if opt.Name != nil {
+ i.Name = opt.Name
+ }
+ if opt.Sparse != nil {
+ i.Sparse = opt.Sparse
+ }
+ if opt.StorageEngine != nil {
+ i.StorageEngine = opt.StorageEngine
+ }
+ if opt.Unique != nil {
+ i.Unique = opt.Unique
+ }
+ if opt.Version != nil {
+ i.Version = opt.Version
+ }
+ if opt.DefaultLanguage != nil {
+ i.DefaultLanguage = opt.DefaultLanguage
+ }
+ if opt.LanguageOverride != nil {
+ i.LanguageOverride = opt.LanguageOverride
+ }
+ if opt.TextVersion != nil {
+ i.TextVersion = opt.TextVersion
+ }
+ if opt.Weights != nil {
+ i.Weights = opt.Weights
+ }
+ if opt.SphereVersion != nil {
+ i.SphereVersion = opt.SphereVersion
+ }
+ if opt.Bits != nil {
+ i.Bits = opt.Bits
+ }
+ if opt.Max != nil {
+ i.Max = opt.Max
+ }
+ if opt.Min != nil {
+ i.Min = opt.Min
+ }
+ if opt.BucketSize != nil {
+ i.BucketSize = opt.BucketSize
+ }
+ if opt.PartialFilterExpression != nil {
+ i.PartialFilterExpression = opt.PartialFilterExpression
+ }
+ if opt.Collation != nil {
+ i.Collation = opt.Collation
+ }
+ }
+
+ return i
+}
diff --git a/vendor/github.com/mongodb/mongo-go-driver/mongo/options/insertoptions.go b/vendor/github.com/mongodb/mongo-go-driver/mongo/options/insertoptions.go
new file mode 100644
index 0000000..064ede3
--- /dev/null
+++ b/vendor/github.com/mongodb/mongo-go-driver/mongo/options/insertoptions.go
@@ -0,0 +1,84 @@
+// Copyright (C) MongoDB, Inc. 2017-present.
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+
+package options
+
+// InsertOneOptions represents all possible options to the insertOne()
+type InsertOneOptions struct {
+ BypassDocumentValidation *bool // If true, allows the write to opt-out of document level validation
+}
+
+// InsertOne returns a pointer to a new InsertOneOptions
+func InsertOne() *InsertOneOptions {
+ return &InsertOneOptions{}
+}
+
+// SetBypassDocumentValidation allows the write to opt-out of document level validation.
+// Valid for server versions >= 3.2. For servers < 3.2, this option is ignored.
+func (ioo *InsertOneOptions) SetBypassDocumentValidation(b bool) *InsertOneOptions {
+ ioo.BypassDocumentValidation = &b
+ return ioo
+}
+
+// MergeInsertOneOptions combines the argued InsertOneOptions into a single InsertOneOptions in a last-one-wins fashion
+func MergeInsertOneOptions(opts ...*InsertOneOptions) *InsertOneOptions {
+ ioOpts := InsertOne()
+ for _, ioo := range opts {
+ if ioo == nil {
+ continue
+ }
+ if ioo.BypassDocumentValidation != nil {
+ ioOpts.BypassDocumentValidation = ioo.BypassDocumentValidation
+ }
+ }
+
+ return ioOpts
+}
+
+// InsertManyOptions represents all possible options to the insertMany()
+type InsertManyOptions struct {
+ BypassDocumentValidation *bool // If true, allows the write to opt-out of document level validation
+ Ordered *bool // If true, when an insert fails, return without performing the remaining inserts. Defaults to true.
+}
+
+// InsertMany returns a pointer to a new InsertManyOptions
+func InsertMany() *InsertManyOptions {
+ return &InsertManyOptions{
+ Ordered: &DefaultOrdered,
+ }
+}
+
+// SetBypassDocumentValidation allows the write to opt-out of document level validation.
+// Valid for server versions >= 3.2. For servers < 3.2, this option is ignored.
+func (imo *InsertManyOptions) SetBypassDocumentValidation(b bool) *InsertManyOptions {
+ imo.BypassDocumentValidation = &b
+ return imo
+}
+
+// SetOrdered configures the ordered option. If true, when a write fails, the function will return without attempting
+// remaining writes. Defaults to true.
+func (imo *InsertManyOptions) SetOrdered(b bool) *InsertManyOptions {
+ imo.Ordered = &b
+ return imo
+}
+
+// MergeInsertManyOptions combines the argued InsertManyOptions into a single InsertManyOptions in a last-one-wins fashion
+func MergeInsertManyOptions(opts ...*InsertManyOptions) *InsertManyOptions {
+ imOpts := InsertMany()
+ for _, imo := range opts {
+ if imo == nil {
+ continue
+ }
+ if imo.BypassDocumentValidation != nil {
+ imOpts.BypassDocumentValidation = imo.BypassDocumentValidation
+ }
+ if imo.Ordered != nil {
+ imOpts.Ordered = imo.Ordered
+ }
+ }
+
+ return imOpts
+}
diff --git a/vendor/github.com/mongodb/mongo-go-driver/mongo/options/listcollectionsoptions.go b/vendor/github.com/mongodb/mongo-go-driver/mongo/options/listcollectionsoptions.go
new file mode 100644
index 0000000..e44ad4a
--- /dev/null
+++ b/vendor/github.com/mongodb/mongo-go-driver/mongo/options/listcollectionsoptions.go
@@ -0,0 +1,39 @@
+// Copyright (C) MongoDB, Inc. 2017-present.
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+
+package options
+
+// ListCollectionsOptions represents all possible options for a listCollections command.
+type ListCollectionsOptions struct {
+ NameOnly *bool // If true, only the collection names will be returned.
+}
+
+// ListCollections creates a new *ListCollectionsOptions
+func ListCollections() *ListCollectionsOptions {
+ return &ListCollectionsOptions{}
+}
+
+// SetNameOnly specifies whether to return only the collection names.
+func (lc *ListCollectionsOptions) SetNameOnly(b bool) *ListCollectionsOptions {
+ lc.NameOnly = &b
+ return lc
+}
+
+// MergeListCollectionsOptions combines the given *ListCollectionsOptions into a single *ListCollectionsOptions in a
+// last one wins fashion.
+func MergeListCollectionsOptions(opts ...*ListCollectionsOptions) *ListCollectionsOptions {
+ lc := ListCollections()
+ for _, opt := range opts {
+ if opt == nil {
+ continue
+ }
+ if opt.NameOnly != nil {
+ lc.NameOnly = opt.NameOnly
+ }
+ }
+
+ return lc
+}
diff --git a/vendor/github.com/mongodb/mongo-go-driver/mongo/options/listdatabasesoptions.go b/vendor/github.com/mongodb/mongo-go-driver/mongo/options/listdatabasesoptions.go
new file mode 100644
index 0000000..5efb6e8
--- /dev/null
+++ b/vendor/github.com/mongodb/mongo-go-driver/mongo/options/listdatabasesoptions.go
@@ -0,0 +1,39 @@
+// Copyright (C) MongoDB, Inc. 2017-present.
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+
+package options
+
+// ListDatabasesOptions represents all possible options for a listDatabases command.
+type ListDatabasesOptions struct {
+ NameOnly *bool // If true, only the database names will be returned.
+}
+
+// ListDatabases creates a new *ListDatabasesOptions
+func ListDatabases() *ListDatabasesOptions {
+ return &ListDatabasesOptions{}
+}
+
+// SetNameOnly specifies whether to return only the database names.
+func (ld *ListDatabasesOptions) SetNameOnly(b bool) *ListDatabasesOptions {
+ ld.NameOnly = &b
+ return ld
+}
+
+// MergeListDatabasesOptions combines the given *ListDatabasesOptions into a single *ListDatabasesOptions in a last one
+// wins fashion.
+func MergeListDatabasesOptions(opts ...*ListDatabasesOptions) *ListDatabasesOptions {
+ ld := ListDatabases()
+ for _, opt := range opts {
+ if opts == nil {
+ continue
+ }
+ if opt.NameOnly != nil {
+ ld.NameOnly = opt.NameOnly
+ }
+ }
+
+ return ld
+}
diff --git a/vendor/github.com/mongodb/mongo-go-driver/mongo/options/mongooptions.go b/vendor/github.com/mongodb/mongo-go-driver/mongo/options/mongooptions.go
new file mode 100644
index 0000000..22f383b
--- /dev/null
+++ b/vendor/github.com/mongodb/mongo-go-driver/mongo/options/mongooptions.go
@@ -0,0 +1,163 @@
+// Copyright (C) MongoDB, Inc. 2017-present.
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+
+package options
+
+import (
+ "fmt"
+ "reflect"
+
+ "github.com/mongodb/mongo-go-driver/bson"
+ "github.com/mongodb/mongo-go-driver/bson/bsoncodec"
+ "github.com/mongodb/mongo-go-driver/x/bsonx"
+)
+
+// Collation allows users to specify language-specific rules for string comparison, such as
+// rules for lettercase and accent marks.
+type Collation struct {
+ Locale string `bson:",omitempty"` // The locale
+ CaseLevel bool `bson:",omitempty"` // The case level
+ CaseFirst string `bson:",omitempty"` // The case ordering
+ Strength int `bson:",omitempty"` // The number of comparision levels to use
+ NumericOrdering bool `bson:",omitempty"` // Whether to order numbers based on numerical order and not collation order
+ Alternate string `bson:",omitempty"` // Whether spaces and punctuation are considered base characters
+ MaxVariable string `bson:",omitempty"` // Which characters are affected by alternate: "shifted"
+ Normalization bool `bson:",omitempty"` // Causes text to be normalized into Unicode NFD
+ Backwards bool `bson:",omitempty"` // Causes secondary differences to be considered in reverse order, as it is done in the French language
+}
+
+// ToDocument converts the Collation to a *bsonx.Document
+func (co *Collation) ToDocument() bsonx.Doc {
+ doc := bsonx.Doc{}
+ if co.Locale != "" {
+ doc = append(doc, bsonx.Elem{"locale", bsonx.String(co.Locale)})
+ }
+ if co.CaseLevel {
+ doc = append(doc, bsonx.Elem{"caseLevel", bsonx.Boolean(true)})
+ }
+ if co.CaseFirst != "" {
+ doc = append(doc, bsonx.Elem{"caseFirst", bsonx.String(co.CaseFirst)})
+ }
+ if co.Strength != 0 {
+ doc = append(doc, bsonx.Elem{"strength", bsonx.Int32(int32(co.Strength))})
+ }
+ if co.NumericOrdering {
+ doc = append(doc, bsonx.Elem{"numericOrdering", bsonx.Boolean(true)})
+ }
+ if co.Alternate != "" {
+ doc = append(doc, bsonx.Elem{"alternate", bsonx.String(co.Alternate)})
+ }
+ if co.MaxVariable != "" {
+ doc = append(doc, bsonx.Elem{"maxVariable", bsonx.String(co.MaxVariable)})
+ }
+ if co.Normalization {
+ doc = append(doc, bsonx.Elem{"normalization", bsonx.Boolean(co.Normalization)})
+ }
+ if co.Backwards {
+ doc = append(doc, bsonx.Elem{"backwards", bsonx.Boolean(true)})
+ }
+ return doc
+}
+
+// CursorType specifies whether a cursor should close when the last data is retrieved. See
+// NonTailable, Tailable, and TailableAwait.
+type CursorType int8
+
+const (
+ // NonTailable specifies that a cursor should close after retrieving the last data.
+ NonTailable CursorType = iota
+ // Tailable specifies that a cursor should not close when the last data is retrieved and can be resumed later.
+ Tailable
+ // TailableAwait specifies that a cursor should not close when the last data is retrieved and
+ // that it should block for a certain amount of time for new data before returning no data.
+ TailableAwait
+)
+
+// ReturnDocument specifies whether a findAndUpdate operation should return the document as it was
+// before the update or as it is after the update.
+type ReturnDocument int8
+
+const (
+ // Before specifies that findAndUpdate should return the document as it was before the update.
+ Before ReturnDocument = iota
+ // After specifies that findAndUpdate should return the document as it is after the update.
+ After
+)
+
+// FullDocument specifies whether a change stream should include a copy of the entire document that was changed from
+// some time after the change occurred.
+type FullDocument string
+
+const (
+ // Default does not include a document copy
+ Default FullDocument = "default"
+ // UpdateLookup includes a delta describing the changes to the document and a copy of the entire document that
+ // was changed
+ UpdateLookup FullDocument = "updateLookup"
+)
+
+// ArrayFilters is used to hold filters for the array filters CRUD option. If a registry is nil, bson.DefaultRegistry
+// will be used when converting the filter interfaces to BSON.
+type ArrayFilters struct {
+ Registry *bsoncodec.Registry // The registry to use for converting filters. Defaults to bson.DefaultRegistry.
+ Filters []interface{} // The filters to apply
+}
+
+// ToArray builds a bsonx.Arr from the provided ArrayFilters.
+func (af *ArrayFilters) ToArray() (bsonx.Arr, error) {
+ docs := make([]bsonx.Doc, 0, len(af.Filters))
+ for _, f := range af.Filters {
+ d, err := transformDocument(af.Registry, f)
+ if err != nil {
+ return nil, err
+ }
+ docs = append(docs, d)
+ }
+
+ arr := bsonx.Arr{}
+ for _, doc := range docs {
+ arr = append(arr, bsonx.Document(doc))
+ }
+
+ return arr, nil
+}
+
+// MarshalError is returned when attempting to transform a value into a document
+// results in an error.
+type MarshalError struct {
+ Value interface{}
+ Err error
+}
+
+// Error implements the error interface.
+func (me MarshalError) Error() string {
+ return fmt.Sprintf("cannot transform type %s to a *bsonx.Document", reflect.TypeOf(me.Value))
+}
+
+var defaultRegistry = bson.DefaultRegistry
+
+func transformDocument(registry *bsoncodec.Registry, val interface{}) (bsonx.Doc, error) {
+ if val == nil {
+ return bsonx.Doc{}, nil
+ }
+ reg := defaultRegistry
+ if registry != nil {
+ reg = registry
+ }
+
+ if bs, ok := val.([]byte); ok {
+ // Slight optimization so we'll just use MarshalBSON and not go through the codec machinery.
+ val = bson.Raw(bs)
+ }
+
+ // TODO(skriptble): Use a pool of these instead.
+ buf := make([]byte, 0, 256)
+ b, err := bson.MarshalAppendWithRegistry(reg, buf, val)
+ if err != nil {
+ return nil, MarshalError{Value: val, Err: err}
+ }
+ return bsonx.ReadDoc(b)
+}
diff --git a/vendor/github.com/mongodb/mongo-go-driver/mongo/options/replaceoptions.go b/vendor/github.com/mongodb/mongo-go-driver/mongo/options/replaceoptions.go
new file mode 100644
index 0000000..7a8c2ba
--- /dev/null
+++ b/vendor/github.com/mongodb/mongo-go-driver/mongo/options/replaceoptions.go
@@ -0,0 +1,60 @@
+// Copyright (C) MongoDB, Inc. 2017-present.
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+
+package options
+
+// ReplaceOptions represents all possible options to the replaceOne() function
+type ReplaceOptions struct {
+ BypassDocumentValidation *bool // If true, allows the write to opt-out of document level validation
+ Collation *Collation // Specifies a collation
+ Upsert *bool // When true, creates a new document if no document matches the query
+}
+
+// Replace returns a pointer to a new ReplaceOptions
+func Replace() *ReplaceOptions {
+ return &ReplaceOptions{}
+}
+
+// SetBypassDocumentValidation allows the write to opt-out of document level validation.
+// Valid for server versions >= 3.2. For servers < 3.2, this option is ignored.
+func (ro *ReplaceOptions) SetBypassDocumentValidation(b bool) *ReplaceOptions {
+ ro.BypassDocumentValidation = &b
+ return ro
+}
+
+// SetCollation specifies a collation.
+// Valid for servers >= 3.4
+func (ro *ReplaceOptions) SetCollation(c *Collation) *ReplaceOptions {
+ ro.Collation = c
+ return ro
+}
+
+// SetUpsert allows the creation of a new document if not document matches the query
+func (ro *ReplaceOptions) SetUpsert(b bool) *ReplaceOptions {
+ ro.Upsert = &b
+ return ro
+}
+
+// MergeReplaceOptions combines the argued ReplaceOptions into a single ReplaceOptions in a last-one-wins fashion
+func MergeReplaceOptions(opts ...*ReplaceOptions) *ReplaceOptions {
+ rOpts := Replace()
+ for _, ro := range opts {
+ if ro == nil {
+ continue
+ }
+ if ro.BypassDocumentValidation != nil {
+ rOpts.BypassDocumentValidation = ro.BypassDocumentValidation
+ }
+ if ro.Collation != nil {
+ rOpts.Collation = ro.Collation
+ }
+ if ro.Upsert != nil {
+ rOpts.Upsert = ro.Upsert
+ }
+ }
+
+ return rOpts
+}
diff --git a/vendor/github.com/mongodb/mongo-go-driver/mongo/options/runcmdoptions.go b/vendor/github.com/mongodb/mongo-go-driver/mongo/options/runcmdoptions.go
new file mode 100644
index 0000000..c7c696d
--- /dev/null
+++ b/vendor/github.com/mongodb/mongo-go-driver/mongo/options/runcmdoptions.go
@@ -0,0 +1,40 @@
+// Copyright (C) MongoDB, Inc. 2017-present.
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+
+package options
+
+import "github.com/mongodb/mongo-go-driver/mongo/readpref"
+
+// RunCmdOptions represents all possible options for a runCommand operation.
+type RunCmdOptions struct {
+ ReadPreference *readpref.ReadPref // The read preference for the operation.
+}
+
+// RunCmd creates a new *RunCmdOptions
+func RunCmd() *RunCmdOptions {
+ return &RunCmdOptions{}
+}
+
+// SetReadPreference sets the read preference for the operation.
+func (rc *RunCmdOptions) SetReadPreference(rp *readpref.ReadPref) *RunCmdOptions {
+ rc.ReadPreference = rp
+ return rc
+}
+
+// MergeRunCmdOptions combines the given *RunCmdOptions into one *RunCmdOptions in a last one wins fashion.
+func MergeRunCmdOptions(opts ...*RunCmdOptions) *RunCmdOptions {
+ rc := RunCmd()
+ for _, opt := range opts {
+ if opt == nil {
+ continue
+ }
+ if opt.ReadPreference != nil {
+ rc.ReadPreference = opt.ReadPreference
+ }
+ }
+
+ return rc
+}
diff --git a/vendor/github.com/mongodb/mongo-go-driver/mongo/options/sessionoptions.go b/vendor/github.com/mongodb/mongo-go-driver/mongo/options/sessionoptions.go
new file mode 100644
index 0000000..ffe45e6
--- /dev/null
+++ b/vendor/github.com/mongodb/mongo-go-driver/mongo/options/sessionoptions.go
@@ -0,0 +1,79 @@
+// Copyright (C) MongoDB, Inc. 2017-present.
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+
+package options
+
+import (
+ "github.com/mongodb/mongo-go-driver/mongo/readconcern"
+ "github.com/mongodb/mongo-go-driver/mongo/readpref"
+ "github.com/mongodb/mongo-go-driver/mongo/writeconcern"
+)
+
+// DefaultCausalConsistency is the default value for the CausalConsistency option.
+var DefaultCausalConsistency = true
+
+// SessionOptions represents all possible options for creating a new session.
+type SessionOptions struct {
+ CausalConsistency *bool // Specifies if reads should be causally consistent. Defaults to true.
+ DefaultReadConcern *readconcern.ReadConcern // The default read concern for transactions started in the session.
+ DefaultReadPreference *readpref.ReadPref // The default read preference for transactions started in the session.
+ DefaultWriteConcern *writeconcern.WriteConcern // The default write concern for transactions started in the session.
+}
+
+// Session creates a new *SessionOptions
+func Session() *SessionOptions {
+ return &SessionOptions{
+ CausalConsistency: &DefaultCausalConsistency,
+ }
+}
+
+// SetCausalConsistency specifies if a session should be causally consistent. Defaults to true.
+func (s *SessionOptions) SetCausalConsistency(b bool) *SessionOptions {
+ s.CausalConsistency = &b
+ return s
+}
+
+// SetDefaultReadConcern sets the default read concern for transactions started in a session.
+func (s *SessionOptions) SetDefaultReadConcern(rc *readconcern.ReadConcern) *SessionOptions {
+ s.DefaultReadConcern = rc
+ return s
+}
+
+// SetDefaultReadPreference sets the default read preference for transactions started in a session.
+func (s *SessionOptions) SetDefaultReadPreference(rp *readpref.ReadPref) *SessionOptions {
+ s.DefaultReadPreference = rp
+ return s
+}
+
+// SetDefaultWriteConcern sets the default write concern for transactions started in a session.
+func (s *SessionOptions) SetDefaultWriteConcern(wc *writeconcern.WriteConcern) *SessionOptions {
+ s.DefaultWriteConcern = wc
+ return s
+}
+
+// MergeSessionOptions combines the given *SessionOptions into a single *SessionOptions in a last one wins fashion.
+func MergeSessionOptions(opts ...*SessionOptions) *SessionOptions {
+ s := Session()
+ for _, opt := range opts {
+ if opt == nil {
+ continue
+ }
+ if opt.CausalConsistency != nil {
+ s.CausalConsistency = opt.CausalConsistency
+ }
+ if opt.DefaultReadConcern != nil {
+ s.DefaultReadConcern = opt.DefaultReadConcern
+ }
+ if opt.DefaultReadPreference != nil {
+ s.DefaultReadPreference = opt.DefaultReadPreference
+ }
+ if opt.DefaultWriteConcern != nil {
+ s.DefaultWriteConcern = opt.DefaultWriteConcern
+ }
+ }
+
+ return s
+}
diff --git a/vendor/github.com/mongodb/mongo-go-driver/mongo/options/transactionoptions.go b/vendor/github.com/mongodb/mongo-go-driver/mongo/options/transactionoptions.go
new file mode 100644
index 0000000..5aec1b9
--- /dev/null
+++ b/vendor/github.com/mongodb/mongo-go-driver/mongo/options/transactionoptions.go
@@ -0,0 +1,65 @@
+// Copyright (C) MongoDB, Inc. 2017-present.
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+
+package options
+
+import (
+ "github.com/mongodb/mongo-go-driver/mongo/readconcern"
+ "github.com/mongodb/mongo-go-driver/mongo/readpref"
+ "github.com/mongodb/mongo-go-driver/mongo/writeconcern"
+)
+
+// TransactionOptions represents all possible options for starting a transaction.
+type TransactionOptions struct {
+ ReadConcern *readconcern.ReadConcern // The read concern for the transaction. Defaults to the session's read concern.
+ ReadPreference *readpref.ReadPref // The read preference for the transaction. Defaults to the session's read preference.
+ WriteConcern *writeconcern.WriteConcern // The write concern for the transaction. Defaults to the session's write concern.
+}
+
+// Transaction creates a new *TransactionOptions
+func Transaction() *TransactionOptions {
+ return &TransactionOptions{}
+}
+
+// SetReadConcern sets the read concern for the transaction.
+func (t *TransactionOptions) SetReadConcern(rc *readconcern.ReadConcern) *TransactionOptions {
+ t.ReadConcern = rc
+ return t
+}
+
+// SetReadPreference sets the read preference for the transaction.
+func (t *TransactionOptions) SetReadPreference(rp *readpref.ReadPref) *TransactionOptions {
+ t.ReadPreference = rp
+ return t
+}
+
+// SetWriteConcern sets the write concern for the transaction.
+func (t *TransactionOptions) SetWriteConcern(wc *writeconcern.WriteConcern) *TransactionOptions {
+ t.WriteConcern = wc
+ return t
+}
+
+// MergeTransactionOptions combines the given *TransactionOptions into a single *TransactionOptions in a last one wins
+// fashion.
+func MergeTransactionOptions(opts ...*TransactionOptions) *TransactionOptions {
+ t := Transaction()
+ for _, opt := range opts {
+ if opt == nil {
+ continue
+ }
+ if opt.ReadConcern != nil {
+ t.ReadConcern = opt.ReadConcern
+ }
+ if opt.ReadPreference != nil {
+ t.ReadPreference = opt.ReadPreference
+ }
+ if opt.WriteConcern != nil {
+ t.WriteConcern = opt.WriteConcern
+ }
+ }
+
+ return t
+}
diff --git a/vendor/github.com/mongodb/mongo-go-driver/mongo/options/updateoptions.go b/vendor/github.com/mongodb/mongo-go-driver/mongo/options/updateoptions.go
new file mode 100644
index 0000000..468ccda
--- /dev/null
+++ b/vendor/github.com/mongodb/mongo-go-driver/mongo/options/updateoptions.go
@@ -0,0 +1,71 @@
+// Copyright (C) MongoDB, Inc. 2017-present.
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+
+package options
+
+// UpdateOptions represents all possible options to the updateOne() and updateMany() functions
+type UpdateOptions struct {
+ ArrayFilters *ArrayFilters // A set of filters specifying to which array elements an update should apply
+ BypassDocumentValidation *bool // If true, allows the write to opt-out of document level validation
+ Collation *Collation // Specifies a collation
+ Upsert *bool // When true, creates a new document if no document matches the query
+}
+
+// Update returns a pointer to a new UpdateOptions
+func Update() *UpdateOptions {
+ return &UpdateOptions{}
+}
+
+// SetArrayFilters specifies a set of filters specifying to which array elements an update should apply
+// Valid for server versions >= 3.6.
+func (uo *UpdateOptions) SetArrayFilters(af ArrayFilters) *UpdateOptions {
+ uo.ArrayFilters = &af
+ return uo
+}
+
+// SetBypassDocumentValidation allows the write to opt-out of document level validation.
+// Valid for server versions >= 3.2. For servers < 3.2, this option is ignored.
+func (uo *UpdateOptions) SetBypassDocumentValidation(b bool) *UpdateOptions {
+ uo.BypassDocumentValidation = &b
+ return uo
+}
+
+// SetCollation specifies a collation.
+// Valid for server versions >= 3.4.
+func (uo *UpdateOptions) SetCollation(c *Collation) *UpdateOptions {
+ uo.Collation = c
+ return uo
+}
+
+// SetUpsert allows the creation of a new document if not document matches the query
+func (uo *UpdateOptions) SetUpsert(b bool) *UpdateOptions {
+ uo.Upsert = &b
+ return uo
+}
+
+// MergeUpdateOptions combines the argued UpdateOptions into a single UpdateOptions in a last-one-wins fashion
+func MergeUpdateOptions(opts ...*UpdateOptions) *UpdateOptions {
+ uOpts := Update()
+ for _, uo := range opts {
+ if uo == nil {
+ continue
+ }
+ if uo.ArrayFilters != nil {
+ uOpts.ArrayFilters = uo.ArrayFilters
+ }
+ if uo.BypassDocumentValidation != nil {
+ uOpts.BypassDocumentValidation = uo.BypassDocumentValidation
+ }
+ if uo.Collation != nil {
+ uOpts.Collation = uo.Collation
+ }
+ if uo.Upsert != nil {
+ uOpts.Upsert = uo.Upsert
+ }
+ }
+
+ return uOpts
+}
diff --git a/vendor/github.com/mongodb/mongo-go-driver/mongo/readconcern/readconcern.go b/vendor/github.com/mongodb/mongo-go-driver/mongo/readconcern/readconcern.go
new file mode 100644
index 0000000..c185fff
--- /dev/null
+++ b/vendor/github.com/mongodb/mongo-go-driver/mongo/readconcern/readconcern.go
@@ -0,0 +1,77 @@
+// Copyright (C) MongoDB, Inc. 2017-present.
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+
+package readconcern
+
+import (
+ "github.com/mongodb/mongo-go-driver/bson/bsontype"
+ "github.com/mongodb/mongo-go-driver/x/bsonx/bsoncore"
+)
+
+// ReadConcern for replica sets and replica set shards determines which data to return from a query.
+type ReadConcern struct {
+ level string
+}
+
+// Option is an option to provide when creating a ReadConcern.
+type Option func(concern *ReadConcern)
+
+// Level creates an option that sets the level of a ReadConcern.
+func Level(level string) Option {
+ return func(concern *ReadConcern) {
+ concern.level = level
+ }
+}
+
+// Local specifies that the query should return the instance’s most recent data.
+func Local() *ReadConcern {
+ return New(Level("local"))
+}
+
+// Majority specifies that the query should return the instance’s most recent data acknowledged as
+// having been written to a majority of members in the replica set.
+func Majority() *ReadConcern {
+ return New(Level("majority"))
+}
+
+// Linearizable specifies that the query should return data that reflects all successful writes
+// issued with a write concern of "majority" and acknowledged prior to the start of the read operation.
+func Linearizable() *ReadConcern {
+ return New(Level("linearizable"))
+}
+
+// Available specifies that the query should return data from the instance with no guarantee
+// that the data has been written to a majority of the replica set members (i.e. may be rolled back).
+func Available() *ReadConcern {
+ return New(Level("available"))
+}
+
+// Snapshot is only available for operations within multi-document transactions.
+func Snapshot() *ReadConcern {
+ return New(Level("snapshot"))
+}
+
+// New constructs a new read concern from the given string.
+func New(options ...Option) *ReadConcern {
+ concern := &ReadConcern{}
+
+ for _, option := range options {
+ option(concern)
+ }
+
+ return concern
+}
+
+// MarshalBSONValue implements the bson.ValueMarshaler interface.
+func (rc *ReadConcern) MarshalBSONValue() (bsontype.Type, []byte, error) {
+ var elems []byte
+
+ if len(rc.level) > 0 {
+ elems = bsoncore.AppendStringElement(elems, "level", rc.level)
+ }
+
+ return bsontype.EmbeddedDocument, bsoncore.BuildDocument(nil, elems), nil
+}
diff --git a/vendor/github.com/mongodb/mongo-go-driver/mongo/readpref/mode.go b/vendor/github.com/mongodb/mongo-go-driver/mongo/readpref/mode.go
new file mode 100644
index 0000000..e7030c6
--- /dev/null
+++ b/vendor/github.com/mongodb/mongo-go-driver/mongo/readpref/mode.go
@@ -0,0 +1,56 @@
+// Copyright (C) MongoDB, Inc. 2017-present.
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+
+package readpref
+
+import (
+ "fmt"
+ "strings"
+)
+
+// Mode indicates the user's preference on reads.
+type Mode uint8
+
+// Mode constants
+const (
+ _ Mode = iota
+ // PrimaryMode indicates that only a primary is
+ // considered for reading. This is the default
+ // mode.
+ PrimaryMode
+ // PrimaryPreferredMode indicates that if a primary
+ // is available, use it; otherwise, eligible
+ // secondaries will be considered.
+ PrimaryPreferredMode
+ // SecondaryMode indicates that only secondaries
+ // should be considered.
+ SecondaryMode
+ // SecondaryPreferredMode indicates that only secondaries
+ // should be considered when one is available. If none
+ // are available, then a primary will be considered.
+ SecondaryPreferredMode
+ // NearestMode indicates that all primaries and secondaries
+ // will be considered.
+ NearestMode
+)
+
+// ModeFromString returns a mode corresponding to
+// mode.
+func ModeFromString(mode string) (Mode, error) {
+ switch strings.ToLower(mode) {
+ case "primary":
+ return PrimaryMode, nil
+ case "primarypreferred":
+ return PrimaryPreferredMode, nil
+ case "secondary":
+ return SecondaryMode, nil
+ case "secondarypreferred":
+ return SecondaryPreferredMode, nil
+ case "nearest":
+ return NearestMode, nil
+ }
+ return Mode(0), fmt.Errorf("unknown read preference %v", mode)
+}
diff --git a/vendor/github.com/mongodb/mongo-go-driver/mongo/readpref/options.go b/vendor/github.com/mongodb/mongo-go-driver/mongo/readpref/options.go
new file mode 100644
index 0000000..a81cf3e
--- /dev/null
+++ b/vendor/github.com/mongodb/mongo-go-driver/mongo/readpref/options.go
@@ -0,0 +1,60 @@
+// Copyright (C) MongoDB, Inc. 2017-present.
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+
+package readpref
+
+import (
+ "errors"
+ "time"
+
+ "github.com/mongodb/mongo-go-driver/tag"
+)
+
+// ErrInvalidTagSet indicates that an invalid set of tags was specified.
+var ErrInvalidTagSet = errors.New("an even number of tags must be specified")
+
+// Option configures a read preference
+type Option func(*ReadPref) error
+
+// WithMaxStaleness sets the maximum staleness a
+// server is allowed.
+func WithMaxStaleness(ms time.Duration) Option {
+ return func(rp *ReadPref) error {
+ rp.maxStaleness = ms
+ rp.maxStalenessSet = true
+ return nil
+ }
+}
+
+// WithTags sets a single tag set used to match
+// a server. The last call to WithTags or WithTagSets
+// overrides all previous calls to either method.
+func WithTags(tags ...string) Option {
+ return func(rp *ReadPref) error {
+ length := len(tags)
+ if length < 2 || length%2 != 0 {
+ return ErrInvalidTagSet
+ }
+
+ tagset := make(tag.Set, 0, length/2)
+
+ for i := 1; i < length; i += 2 {
+ tagset = append(tagset, tag.Tag{Name: tags[i-1], Value: tags[i]})
+ }
+
+ return WithTagSets(tagset)(rp)
+ }
+}
+
+// WithTagSets sets the tag sets used to match
+// a server. The last call to WithTags or WithTagSets
+// overrides all previous calls to either method.
+func WithTagSets(tagSets ...tag.Set) Option {
+ return func(rp *ReadPref) error {
+ rp.tagSets = tagSets
+ return nil
+ }
+}
diff --git a/vendor/github.com/mongodb/mongo-go-driver/mongo/readpref/readpref.go b/vendor/github.com/mongodb/mongo-go-driver/mongo/readpref/readpref.go
new file mode 100644
index 0000000..0d624ff
--- /dev/null
+++ b/vendor/github.com/mongodb/mongo-go-driver/mongo/readpref/readpref.go
@@ -0,0 +1,99 @@
+// Copyright (C) MongoDB, Inc. 2017-present.
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+
+package readpref
+
+import (
+ "errors"
+ "time"
+
+ "github.com/mongodb/mongo-go-driver/tag"
+)
+
+var (
+ errInvalidReadPreference = errors.New("can not specify tags or max staleness on primary")
+)
+
+var primary = ReadPref{mode: PrimaryMode}
+
+// Primary constructs a read preference with a PrimaryMode.
+func Primary() *ReadPref {
+ return &primary
+}
+
+// PrimaryPreferred constructs a read preference with a PrimaryPreferredMode.
+func PrimaryPreferred(opts ...Option) *ReadPref {
+ // New only returns an error with a mode of Primary
+ rp, _ := New(PrimaryPreferredMode, opts...)
+ return rp
+}
+
+// SecondaryPreferred constructs a read preference with a SecondaryPreferredMode.
+func SecondaryPreferred(opts ...Option) *ReadPref {
+ // New only returns an error with a mode of Primary
+ rp, _ := New(SecondaryPreferredMode, opts...)
+ return rp
+}
+
+// Secondary constructs a read preference with a SecondaryMode.
+func Secondary(opts ...Option) *ReadPref {
+ // New only returns an error with a mode of Primary
+ rp, _ := New(SecondaryMode, opts...)
+ return rp
+}
+
+// Nearest constructs a read preference with a NearestMode.
+func Nearest(opts ...Option) *ReadPref {
+ // New only returns an error with a mode of Primary
+ rp, _ := New(NearestMode, opts...)
+ return rp
+}
+
+// New creates a new ReadPref.
+func New(mode Mode, opts ...Option) (*ReadPref, error) {
+ rp := &ReadPref{
+ mode: mode,
+ }
+
+ if mode == PrimaryMode && len(opts) != 0 {
+ return nil, errInvalidReadPreference
+ }
+
+ for _, opt := range opts {
+ err := opt(rp)
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ return rp, nil
+}
+
+// ReadPref determines which servers are considered suitable for read operations.
+type ReadPref struct {
+ maxStaleness time.Duration
+ maxStalenessSet bool
+ mode Mode
+ tagSets []tag.Set
+}
+
+// MaxStaleness is the maximum amount of time to allow
+// a server to be considered eligible for selection. The
+// second return value indicates if this value has been set.
+func (r *ReadPref) MaxStaleness() (time.Duration, bool) {
+ return r.maxStaleness, r.maxStalenessSet
+}
+
+// Mode indicates the mode of the read preference.
+func (r *ReadPref) Mode() Mode {
+ return r.mode
+}
+
+// TagSets are multiple tag sets indicating
+// which servers should be considered.
+func (r *ReadPref) TagSets() []tag.Set {
+ return r.tagSets
+}
diff --git a/vendor/github.com/mongodb/mongo-go-driver/mongo/results.go b/vendor/github.com/mongodb/mongo-go-driver/mongo/results.go
new file mode 100644
index 0000000..b4bcd02
--- /dev/null
+++ b/vendor/github.com/mongodb/mongo-go-driver/mongo/results.go
@@ -0,0 +1,139 @@
+// Copyright (C) MongoDB, Inc. 2017-present.
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+
+package mongo
+
+import (
+ "fmt"
+
+ "github.com/mongodb/mongo-go-driver/bson"
+ "github.com/mongodb/mongo-go-driver/x/network/result"
+)
+
+// BulkWriteResult holds the result of a bulk write operation.
+type BulkWriteResult struct {
+ InsertedCount int64
+ MatchedCount int64
+ ModifiedCount int64
+ DeletedCount int64
+ UpsertedCount int64
+ UpsertedIDs map[int64]interface{}
+}
+
+// InsertOneResult is a result of an InsertOne operation.
+//
+// InsertedID will be a Go type that corresponds to a BSON type.
+type InsertOneResult struct {
+ // The identifier that was inserted.
+ InsertedID interface{}
+}
+
+// InsertManyResult is a result of an InsertMany operation.
+type InsertManyResult struct {
+ // Maps the indexes of inserted documents to their _id fields.
+ InsertedIDs []interface{}
+}
+
+// DeleteResult is a result of an DeleteOne operation.
+type DeleteResult struct {
+ // The number of documents that were deleted.
+ DeletedCount int64 `bson:"n"`
+}
+
+// ListDatabasesResult is a result of a ListDatabases operation. Each specification
+// is a description of the datbases on the server.
+type ListDatabasesResult struct {
+ Databases []DatabaseSpecification
+ TotalSize int64
+}
+
+func (ldr ListDatabasesResult) fromResult(res result.ListDatabases) ListDatabasesResult {
+ ldr.Databases = make([]DatabaseSpecification, 0, len(res.Databases))
+ for _, spec := range res.Databases {
+ ldr.Databases = append(
+ ldr.Databases,
+ DatabaseSpecification{Name: spec.Name, SizeOnDisk: spec.SizeOnDisk, Empty: spec.Empty},
+ )
+ }
+ ldr.TotalSize = res.TotalSize
+ return ldr
+}
+
+// DatabaseSpecification is the information for a single database returned
+// from a ListDatabases operation.
+type DatabaseSpecification struct {
+ Name string
+ SizeOnDisk int64
+ Empty bool
+}
+
+// UpdateResult is a result of an update operation.
+//
+// UpsertedID will be a Go type that corresponds to a BSON type.
+type UpdateResult struct {
+ // The number of documents that matched the filter.
+ MatchedCount int64
+ // The number of documents that were modified.
+ ModifiedCount int64
+ // The number of documents that were upserted.
+ UpsertedCount int64
+ // The identifier of the inserted document if an upsert took place.
+ UpsertedID interface{}
+}
+
+// UnmarshalBSON implements the bson.Unmarshaler interface.
+func (result *UpdateResult) UnmarshalBSON(b []byte) error {
+ elems, err := bson.Raw(b).Elements()
+ if err != nil {
+ return err
+ }
+
+ for _, elem := range elems {
+ switch elem.Key() {
+ case "n":
+ switch elem.Value().Type {
+ case bson.TypeInt32:
+ result.MatchedCount = int64(elem.Value().Int32())
+ case bson.TypeInt64:
+ result.MatchedCount = elem.Value().Int64()
+ default:
+ return fmt.Errorf("Received invalid type for n, should be Int32 or Int64, received %s", elem.Value().Type)
+ }
+ case "nModified":
+ switch elem.Value().Type {
+ case bson.TypeInt32:
+ result.ModifiedCount = int64(elem.Value().Int32())
+ case bson.TypeInt64:
+ result.ModifiedCount = elem.Value().Int64()
+ default:
+ return fmt.Errorf("Received invalid type for nModified, should be Int32 or Int64, received %s", elem.Value().Type)
+ }
+ case "upserted":
+ switch elem.Value().Type {
+ case bson.TypeArray:
+ e, err := elem.Value().Array().IndexErr(0)
+ if err != nil {
+ break
+ }
+ if e.Value().Type != bson.TypeEmbeddedDocument {
+ break
+ }
+ var d struct {
+ ID interface{} `bson:"_id"`
+ }
+ err = bson.Unmarshal(e.Value().Document(), &d)
+ if err != nil {
+ return err
+ }
+ result.UpsertedID = d.ID
+ default:
+ return fmt.Errorf("Received invalid type for upserted, should be Array, received %s", elem.Value().Type)
+ }
+ }
+ }
+
+ return nil
+}
diff --git a/vendor/github.com/mongodb/mongo-go-driver/mongo/session.go b/vendor/github.com/mongodb/mongo-go-driver/mongo/session.go
new file mode 100644
index 0000000..381714d
--- /dev/null
+++ b/vendor/github.com/mongodb/mongo-go-driver/mongo/session.go
@@ -0,0 +1,181 @@
+// Copyright (C) MongoDB, Inc. 2017-present.
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+
+package mongo
+
+import (
+ "context"
+ "errors"
+
+ "github.com/mongodb/mongo-go-driver/bson"
+ "github.com/mongodb/mongo-go-driver/bson/primitive"
+ "github.com/mongodb/mongo-go-driver/mongo/options"
+ "github.com/mongodb/mongo-go-driver/x/mongo/driver"
+ "github.com/mongodb/mongo-go-driver/x/mongo/driver/session"
+ "github.com/mongodb/mongo-go-driver/x/mongo/driver/topology"
+ "github.com/mongodb/mongo-go-driver/x/network/command"
+ "github.com/mongodb/mongo-go-driver/x/network/description"
+)
+
+// ErrWrongClient is returned when a user attempts to pass in a session created by a different client than
+// the method call is using.
+var ErrWrongClient = errors.New("session was not created by this client")
+
+// SessionContext is a hybrid interface. It combines a context.Context with
+// a mongo.Session. This type can be used as a regular context.Context or
+// Session type. It is not goroutine safe and should not be used in multiple goroutines concurrently.
+type SessionContext interface {
+ context.Context
+ Session
+}
+
+type sessionContext struct {
+ context.Context
+ Session
+}
+
+type sessionKey struct {
+}
+
+// Session is the interface that represents a sequential set of operations executed.
+// Instances of this interface can be used to use transactions against the server
+// and to enable causally consistent behavior for applications.
+type Session interface {
+ EndSession(context.Context)
+ StartTransaction(...*options.TransactionOptions) error
+ AbortTransaction(context.Context) error
+ CommitTransaction(context.Context) error
+ ClusterTime() bson.Raw
+ AdvanceClusterTime(bson.Raw) error
+ OperationTime() *primitive.Timestamp
+ AdvanceOperationTime(*primitive.Timestamp) error
+ session()
+}
+
+// sessionImpl represents a set of sequential operations executed by an application that are related in some way.
+type sessionImpl struct {
+ *session.Client
+ topo *topology.Topology
+ didCommitAfterStart bool // true if commit was called after start with no other operations
+}
+
+// EndSession ends the session.
+func (s *sessionImpl) EndSession(ctx context.Context) {
+ if s.TransactionInProgress() {
+ // ignore all errors aborting during an end session
+ _ = s.AbortTransaction(ctx)
+ }
+ s.Client.EndSession()
+}
+
+// StartTransaction starts a transaction for this session.
+func (s *sessionImpl) StartTransaction(opts ...*options.TransactionOptions) error {
+ err := s.CheckStartTransaction()
+ if err != nil {
+ return err
+ }
+
+ s.didCommitAfterStart = false
+
+ topts := options.MergeTransactionOptions(opts...)
+ coreOpts := &session.TransactionOptions{
+ ReadConcern: topts.ReadConcern,
+ ReadPreference: topts.ReadPreference,
+ WriteConcern: topts.WriteConcern,
+ }
+
+ return s.Client.StartTransaction(coreOpts)
+}
+
+// AbortTransaction aborts the session's transaction, returning any errors and error codes
+func (s *sessionImpl) AbortTransaction(ctx context.Context) error {
+ err := s.CheckAbortTransaction()
+ if err != nil {
+ return err
+ }
+
+ cmd := command.AbortTransaction{
+ Session: s.Client,
+ }
+
+ s.Aborting = true
+ _, err = driver.AbortTransaction(ctx, cmd, s.topo, description.WriteSelector())
+
+ _ = s.Client.AbortTransaction()
+ return err
+}
+
+// CommitTransaction commits the sesson's transaction.
+func (s *sessionImpl) CommitTransaction(ctx context.Context) error {
+ err := s.CheckCommitTransaction()
+ if err != nil {
+ return err
+ }
+
+ // Do not run the commit command if the transaction is in started state
+ if s.TransactionStarting() || s.didCommitAfterStart {
+ s.didCommitAfterStart = true
+ return s.Client.CommitTransaction()
+ }
+
+ if s.Client.TransactionCommitted() {
+ s.RetryingCommit = true
+ }
+
+ cmd := command.CommitTransaction{
+ Session: s.Client,
+ }
+
+ // Hack to ensure that session stays in committed state
+ if s.TransactionCommitted() {
+ s.Committing = true
+ defer func() {
+ s.Committing = false
+ }()
+ }
+ _, err = driver.CommitTransaction(ctx, cmd, s.topo, description.WriteSelector())
+ if err == nil {
+ return s.Client.CommitTransaction()
+ }
+ return err
+}
+
+func (s *sessionImpl) ClusterTime() bson.Raw {
+ return s.Client.ClusterTime
+}
+
+func (s *sessionImpl) AdvanceClusterTime(d bson.Raw) error {
+ return s.Client.AdvanceClusterTime(d)
+}
+
+func (s *sessionImpl) OperationTime() *primitive.Timestamp {
+ return s.Client.OperationTime
+}
+
+func (s *sessionImpl) AdvanceOperationTime(ts *primitive.Timestamp) error {
+ return s.Client.AdvanceOperationTime(ts)
+}
+
+func (*sessionImpl) session() {
+}
+
+// sessionFromContext checks for a sessionImpl in the argued context and returns the session if it
+// exists
+func sessionFromContext(ctx context.Context) *session.Client {
+ s := ctx.Value(sessionKey{})
+ if ses, ok := s.(*sessionImpl); ses != nil && ok {
+ return ses.Client
+ }
+
+ return nil
+}
+
+func contextWithSession(ctx context.Context, sess Session) SessionContext {
+ return &sessionContext{
+ Context: context.WithValue(ctx, sessionKey{}, sess),
+ Session: sess,
+ }
+}
diff --git a/vendor/github.com/mongodb/mongo-go-driver/mongo/single_result.go b/vendor/github.com/mongodb/mongo-go-driver/mongo/single_result.go
new file mode 100644
index 0000000..9a929db
--- /dev/null
+++ b/vendor/github.com/mongodb/mongo-go-driver/mongo/single_result.go
@@ -0,0 +1,93 @@
+// Copyright (C) MongoDB, Inc. 2017-present.
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+
+package mongo
+
+import (
+ "context"
+ "errors"
+
+ "github.com/mongodb/mongo-go-driver/bson"
+ "github.com/mongodb/mongo-go-driver/bson/bsoncodec"
+)
+
+// ErrNoDocuments is returned by Decode when an operation that returns a
+// SingleResult doesn't return any documents.
+var ErrNoDocuments = errors.New("mongo: no documents in result")
+
+// SingleResult represents a single document returned from an operation. If
+// the operation returned an error, the Err method of SingleResult will
+// return that error.
+type SingleResult struct {
+ err error
+ cur *Cursor
+ rdr bson.Raw
+ reg *bsoncodec.Registry
+}
+
+// Decode will attempt to decode the first document into v. If there was an
+// error from the operation that created this SingleResult then the error
+// will be returned. If there were no returned documents, ErrNoDocuments is
+// returned.
+func (sr *SingleResult) Decode(v interface{}) error {
+ if sr.err != nil {
+ return sr.err
+ }
+ if sr.reg == nil {
+ return bson.ErrNilRegistry
+ }
+ switch {
+ case sr.rdr != nil:
+ if v == nil {
+ return nil
+ }
+ return bson.UnmarshalWithRegistry(sr.reg, sr.rdr, v)
+ case sr.cur != nil:
+ defer sr.cur.Close(context.TODO())
+ if !sr.cur.Next(context.TODO()) {
+ if err := sr.cur.Err(); err != nil {
+ return err
+ }
+ return ErrNoDocuments
+ }
+ if v == nil {
+ return nil
+ }
+ return sr.cur.Decode(v)
+ }
+
+ return ErrNoDocuments
+}
+
+// DecodeBytes will return a copy of the document as a bson.Raw. If there was an
+// error from the operation that created this SingleResult then the error
+// will be returned. If there were no returned documents, ErrNoDocuments is
+// returned.
+func (sr *SingleResult) DecodeBytes() (bson.Raw, error) {
+ switch {
+ case sr.err != nil:
+ return nil, sr.err
+ case sr.rdr != nil:
+ return sr.rdr, nil
+ case sr.cur != nil:
+ defer sr.cur.Close(context.TODO())
+ if !sr.cur.Next(context.TODO()) {
+ if err := sr.cur.Err(); err != nil {
+ return nil, err
+ }
+ return nil, ErrNoDocuments
+ }
+ return sr.cur.Current, nil
+ }
+
+ return nil, ErrNoDocuments
+}
+
+// Err will return the error from the operation that created this SingleResult.
+// If there was no error, nil is returned.
+func (sr *SingleResult) Err() error {
+ return sr.err
+}
diff --git a/vendor/github.com/mongodb/mongo-go-driver/mongo/util.go b/vendor/github.com/mongodb/mongo-go-driver/mongo/util.go
new file mode 100644
index 0000000..270fa24
--- /dev/null
+++ b/vendor/github.com/mongodb/mongo-go-driver/mongo/util.go
@@ -0,0 +1,7 @@
+// Copyright (C) MongoDB, Inc. 2017-present.
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+
+package mongo
diff --git a/vendor/github.com/mongodb/mongo-go-driver/mongo/writeconcern/writeconcern.go b/vendor/github.com/mongodb/mongo-go-driver/mongo/writeconcern/writeconcern.go
new file mode 100644
index 0000000..234ba19
--- /dev/null
+++ b/vendor/github.com/mongodb/mongo-go-driver/mongo/writeconcern/writeconcern.go
@@ -0,0 +1,186 @@
+// Copyright (C) MongoDB, Inc. 2017-present.
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+
+package writeconcern
+
+import (
+ "errors"
+ "time"
+
+ "github.com/mongodb/mongo-go-driver/bson"
+ "github.com/mongodb/mongo-go-driver/bson/bsontype"
+ "github.com/mongodb/mongo-go-driver/x/bsonx/bsoncore"
+)
+
+// ErrInconsistent indicates that an inconsistent write concern was specified.
+var ErrInconsistent = errors.New("a write concern cannot have both w=0 and j=true")
+
+// ErrEmptyWriteConcern indicates that a write concern has no fields set.
+var ErrEmptyWriteConcern = errors.New("a write concern must have at least one field set")
+
+// ErrNegativeW indicates that a negative integer `w` field was specified.
+var ErrNegativeW = errors.New("write concern `w` field cannot be a negative number")
+
+// ErrNegativeWTimeout indicates that a negative WTimeout was specified.
+var ErrNegativeWTimeout = errors.New("write concern `wtimeout` field cannot be negative")
+
+// WriteConcern describes the level of acknowledgement requested from MongoDB for write operations
+// to a standalone mongod or to replica sets or to sharded clusters.
+type WriteConcern struct {
+ w interface{}
+ j bool
+ wTimeout time.Duration
+}
+
+// Option is an option to provide when creating a ReadConcern.
+type Option func(concern *WriteConcern)
+
+// New constructs a new WriteConcern.
+func New(options ...Option) *WriteConcern {
+ concern := &WriteConcern{}
+
+ for _, option := range options {
+ option(concern)
+ }
+
+ return concern
+}
+
+// W requests acknowledgement that write operations propagate to the specified number of mongod
+// instances.
+func W(w int) Option {
+ return func(concern *WriteConcern) {
+ concern.w = w
+ }
+}
+
+// WMajority requests acknowledgement that write operations propagate to the majority of mongod
+// instances.
+func WMajority() Option {
+ return func(concern *WriteConcern) {
+ concern.w = "majority"
+ }
+}
+
+// WTagSet requests acknowledgement that write operations propagate to the specified mongod
+// instance.
+func WTagSet(tag string) Option {
+ return func(concern *WriteConcern) {
+ concern.w = tag
+ }
+}
+
+// J requests acknowledgement from MongoDB that write operations are written to
+// the journal.
+func J(j bool) Option {
+ return func(concern *WriteConcern) {
+ concern.j = j
+ }
+}
+
+// WTimeout specifies specifies a time limit for the write concern.
+func WTimeout(d time.Duration) Option {
+ return func(concern *WriteConcern) {
+ concern.wTimeout = d
+ }
+}
+
+// MarshalBSONValue implements the bson.ValueMarshaler interface.
+func (wc *WriteConcern) MarshalBSONValue() (bsontype.Type, []byte, error) {
+ if !wc.IsValid() {
+ return bsontype.Type(0), nil, ErrInconsistent
+ }
+
+ var elems []byte
+
+ if wc.w != nil {
+ switch t := wc.w.(type) {
+ case int:
+ if t < 0 {
+ return bsontype.Type(0), nil, ErrNegativeW
+ }
+
+ elems = bsoncore.AppendInt32Element(elems, "w", int32(t))
+ case string:
+ elems = bsoncore.AppendStringElement(elems, "w", string(t))
+ }
+ }
+
+ if wc.j {
+ elems = bsoncore.AppendBooleanElement(elems, "j", wc.j)
+ }
+
+ if wc.wTimeout < 0 {
+ return bsontype.Type(0), nil, ErrNegativeWTimeout
+ }
+
+ if wc.wTimeout != 0 {
+ elems = bsoncore.AppendInt64Element(elems, "wtimeout", int64(wc.wTimeout/time.Millisecond))
+ }
+
+ if len(elems) == 0 {
+ return bsontype.Type(0), nil, ErrEmptyWriteConcern
+ }
+ return bsontype.EmbeddedDocument, bsoncore.BuildDocument(nil, elems), nil
+}
+
+// AcknowledgedValue returns true if a BSON RawValue for a write concern represents an acknowledged write concern.
+// The element's value must be a document representing a write concern.
+func AcknowledgedValue(rawv bson.RawValue) bool {
+ doc, ok := bsoncore.Value{Type: rawv.Type, Data: rawv.Value}.DocumentOK()
+ if !ok {
+ return false
+ }
+
+ val, err := doc.LookupErr("w")
+ if err != nil {
+ // key w not found --> acknowledged
+ return true
+ }
+
+ i32, ok := val.Int32OK()
+ if !ok {
+ return false
+ }
+ return i32 != 0
+}
+
+// Acknowledged indicates whether or not a write with the given write concern will be acknowledged.
+func (wc *WriteConcern) Acknowledged() bool {
+ if wc == nil || wc.j {
+ return true
+ }
+
+ switch v := wc.w.(type) {
+ case int:
+ if v == 0 {
+ return false
+ }
+ }
+
+ return true
+}
+
+// IsValid checks whether the write concern is invalid.
+func (wc *WriteConcern) IsValid() bool {
+ if !wc.j {
+ return true
+ }
+
+ switch v := wc.w.(type) {
+ case int:
+ if v == 0 {
+ return false
+ }
+ }
+
+ return true
+}
+
+// AckWrite returns true if a write concern represents an acknowledged write
+func AckWrite(wc *WriteConcern) bool {
+ return wc == nil || wc.Acknowledged()
+}