go mod vendor

+ move k8s.io/apimachinery fork from go.work to go.mod
(and include it in vendor)
This commit is contained in:
2022-11-07 00:16:27 +02:00
parent d08bbf250a
commit e45bf4739b
1366 changed files with 469062 additions and 45 deletions

View File

@@ -0,0 +1,199 @@
// Copyright (C) MongoDB, Inc. 2019-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 operation
import (
"context"
"errors"
"go.mongodb.org/mongo-driver/event"
"go.mongodb.org/mongo-driver/mongo/description"
"go.mongodb.org/mongo-driver/mongo/writeconcern"
"go.mongodb.org/mongo-driver/x/bsonx/bsoncore"
"go.mongodb.org/mongo-driver/x/mongo/driver"
"go.mongodb.org/mongo-driver/x/mongo/driver/session"
)
// AbortTransaction performs an abortTransaction operation.
type AbortTransaction struct {
recoveryToken bsoncore.Document
session *session.Client
clock *session.ClusterClock
collection string
monitor *event.CommandMonitor
crypt driver.Crypt
database string
deployment driver.Deployment
selector description.ServerSelector
writeConcern *writeconcern.WriteConcern
retry *driver.RetryMode
serverAPI *driver.ServerAPIOptions
}
// NewAbortTransaction constructs and returns a new AbortTransaction.
func NewAbortTransaction() *AbortTransaction {
return &AbortTransaction{}
}
func (at *AbortTransaction) processResponse(driver.ResponseInfo) error {
var err error
return err
}
// Execute runs this operations and returns an error if the operation did not execute successfully.
func (at *AbortTransaction) Execute(ctx context.Context) error {
if at.deployment == nil {
return errors.New("the AbortTransaction operation must have a Deployment set before Execute can be called")
}
return driver.Operation{
CommandFn: at.command,
ProcessResponseFn: at.processResponse,
RetryMode: at.retry,
Type: driver.Write,
Client: at.session,
Clock: at.clock,
CommandMonitor: at.monitor,
Crypt: at.crypt,
Database: at.database,
Deployment: at.deployment,
Selector: at.selector,
WriteConcern: at.writeConcern,
ServerAPI: at.serverAPI,
}.Execute(ctx)
}
func (at *AbortTransaction) command(dst []byte, desc description.SelectedServer) ([]byte, error) {
dst = bsoncore.AppendInt32Element(dst, "abortTransaction", 1)
if at.recoveryToken != nil {
dst = bsoncore.AppendDocumentElement(dst, "recoveryToken", at.recoveryToken)
}
return dst, nil
}
// RecoveryToken sets the recovery token to use when committing or aborting a sharded transaction.
func (at *AbortTransaction) RecoveryToken(recoveryToken bsoncore.Document) *AbortTransaction {
if at == nil {
at = new(AbortTransaction)
}
at.recoveryToken = recoveryToken
return at
}
// Session sets the session for this operation.
func (at *AbortTransaction) Session(session *session.Client) *AbortTransaction {
if at == nil {
at = new(AbortTransaction)
}
at.session = session
return at
}
// ClusterClock sets the cluster clock for this operation.
func (at *AbortTransaction) ClusterClock(clock *session.ClusterClock) *AbortTransaction {
if at == nil {
at = new(AbortTransaction)
}
at.clock = clock
return at
}
// Collection sets the collection that this command will run against.
func (at *AbortTransaction) Collection(collection string) *AbortTransaction {
if at == nil {
at = new(AbortTransaction)
}
at.collection = collection
return at
}
// CommandMonitor sets the monitor to use for APM events.
func (at *AbortTransaction) CommandMonitor(monitor *event.CommandMonitor) *AbortTransaction {
if at == nil {
at = new(AbortTransaction)
}
at.monitor = monitor
return at
}
// Crypt sets the Crypt object to use for automatic encryption and decryption.
func (at *AbortTransaction) Crypt(crypt driver.Crypt) *AbortTransaction {
if at == nil {
at = new(AbortTransaction)
}
at.crypt = crypt
return at
}
// Database sets the database to run this operation against.
func (at *AbortTransaction) Database(database string) *AbortTransaction {
if at == nil {
at = new(AbortTransaction)
}
at.database = database
return at
}
// Deployment sets the deployment to use for this operation.
func (at *AbortTransaction) Deployment(deployment driver.Deployment) *AbortTransaction {
if at == nil {
at = new(AbortTransaction)
}
at.deployment = deployment
return at
}
// ServerSelector sets the selector used to retrieve a server.
func (at *AbortTransaction) ServerSelector(selector description.ServerSelector) *AbortTransaction {
if at == nil {
at = new(AbortTransaction)
}
at.selector = selector
return at
}
// WriteConcern sets the write concern for this operation.
func (at *AbortTransaction) WriteConcern(writeConcern *writeconcern.WriteConcern) *AbortTransaction {
if at == nil {
at = new(AbortTransaction)
}
at.writeConcern = writeConcern
return at
}
// Retry enables retryable mode for this operation. Retries are handled automatically in driver.Operation.Execute based
// on how the operation is set.
func (at *AbortTransaction) Retry(retry driver.RetryMode) *AbortTransaction {
if at == nil {
at = new(AbortTransaction)
}
at.retry = &retry
return at
}
// ServerAPI sets the server API version for this operation.
func (at *AbortTransaction) ServerAPI(serverAPI *driver.ServerAPIOptions) *AbortTransaction {
if at == nil {
at = new(AbortTransaction)
}
at.serverAPI = serverAPI
return at
}

View File

@@ -0,0 +1,419 @@
// Copyright (C) MongoDB, Inc. 2019-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 operation
import (
"context"
"errors"
"time"
"go.mongodb.org/mongo-driver/bson/bsontype"
"go.mongodb.org/mongo-driver/event"
"go.mongodb.org/mongo-driver/mongo/description"
"go.mongodb.org/mongo-driver/mongo/readconcern"
"go.mongodb.org/mongo-driver/mongo/readpref"
"go.mongodb.org/mongo-driver/mongo/writeconcern"
"go.mongodb.org/mongo-driver/x/bsonx/bsoncore"
"go.mongodb.org/mongo-driver/x/mongo/driver"
"go.mongodb.org/mongo-driver/x/mongo/driver/session"
)
// Aggregate represents an aggregate operation.
type Aggregate struct {
allowDiskUse *bool
batchSize *int32
bypassDocumentValidation *bool
collation bsoncore.Document
comment *string
hint bsoncore.Value
maxTime *time.Duration
pipeline bsoncore.Document
session *session.Client
clock *session.ClusterClock
collection string
monitor *event.CommandMonitor
database string
deployment driver.Deployment
readConcern *readconcern.ReadConcern
readPreference *readpref.ReadPref
retry *driver.RetryMode
selector description.ServerSelector
writeConcern *writeconcern.WriteConcern
crypt driver.Crypt
serverAPI *driver.ServerAPIOptions
let bsoncore.Document
hasOutputStage bool
customOptions map[string]bsoncore.Value
timeout *time.Duration
result driver.CursorResponse
}
// NewAggregate constructs and returns a new Aggregate.
func NewAggregate(pipeline bsoncore.Document) *Aggregate {
return &Aggregate{
pipeline: pipeline,
}
}
// Result returns the result of executing this operation.
func (a *Aggregate) Result(opts driver.CursorOptions) (*driver.BatchCursor, error) {
clientSession := a.session
clock := a.clock
opts.ServerAPI = a.serverAPI
return driver.NewBatchCursor(a.result, clientSession, clock, opts)
}
// ResultCursorResponse returns the underlying CursorResponse result of executing this
// operation.
func (a *Aggregate) ResultCursorResponse() driver.CursorResponse {
return a.result
}
func (a *Aggregate) processResponse(info driver.ResponseInfo) error {
var err error
a.result, err = driver.NewCursorResponse(info)
return err
}
// Execute runs this operations and returns an error if the operation did not execute successfully.
func (a *Aggregate) Execute(ctx context.Context) error {
if a.deployment == nil {
return errors.New("the Aggregate operation must have a Deployment set before Execute can be called")
}
return driver.Operation{
CommandFn: a.command,
ProcessResponseFn: a.processResponse,
Client: a.session,
Clock: a.clock,
CommandMonitor: a.monitor,
Database: a.database,
Deployment: a.deployment,
ReadConcern: a.readConcern,
ReadPreference: a.readPreference,
Type: driver.Read,
RetryMode: a.retry,
Selector: a.selector,
WriteConcern: a.writeConcern,
Crypt: a.crypt,
MinimumWriteConcernWireVersion: 5,
ServerAPI: a.serverAPI,
IsOutputAggregate: a.hasOutputStage,
MaxTime: a.maxTime,
Timeout: a.timeout,
}.Execute(ctx)
}
func (a *Aggregate) command(dst []byte, desc description.SelectedServer) ([]byte, error) {
header := bsoncore.Value{Type: bsontype.String, Data: bsoncore.AppendString(nil, a.collection)}
if a.collection == "" {
header = bsoncore.Value{Type: bsontype.Int32, Data: []byte{0x01, 0x00, 0x00, 0x00}}
}
dst = bsoncore.AppendValueElement(dst, "aggregate", header)
cursorIdx, cursorDoc := bsoncore.AppendDocumentStart(nil)
if a.allowDiskUse != nil {
dst = bsoncore.AppendBooleanElement(dst, "allowDiskUse", *a.allowDiskUse)
}
if a.batchSize != nil {
cursorDoc = bsoncore.AppendInt32Element(cursorDoc, "batchSize", *a.batchSize)
}
if a.bypassDocumentValidation != nil {
dst = bsoncore.AppendBooleanElement(dst, "bypassDocumentValidation", *a.bypassDocumentValidation)
}
if a.collation != nil {
if desc.WireVersion == nil || !desc.WireVersion.Includes(5) {
return nil, errors.New("the 'collation' command parameter requires a minimum server wire version of 5")
}
dst = bsoncore.AppendDocumentElement(dst, "collation", a.collation)
}
if a.comment != nil {
dst = bsoncore.AppendStringElement(dst, "comment", *a.comment)
}
if a.hint.Type != bsontype.Type(0) {
dst = bsoncore.AppendValueElement(dst, "hint", a.hint)
}
if a.pipeline != nil {
dst = bsoncore.AppendArrayElement(dst, "pipeline", a.pipeline)
}
if a.let != nil {
dst = bsoncore.AppendDocumentElement(dst, "let", a.let)
}
for optionName, optionValue := range a.customOptions {
dst = bsoncore.AppendValueElement(dst, optionName, optionValue)
}
cursorDoc, _ = bsoncore.AppendDocumentEnd(cursorDoc, cursorIdx)
dst = bsoncore.AppendDocumentElement(dst, "cursor", cursorDoc)
return dst, nil
}
// AllowDiskUse enables writing to temporary files. When true, aggregation stages can write to the dbPath/_tmp directory.
func (a *Aggregate) AllowDiskUse(allowDiskUse bool) *Aggregate {
if a == nil {
a = new(Aggregate)
}
a.allowDiskUse = &allowDiskUse
return a
}
// BatchSize specifies the number of documents to return in every batch.
func (a *Aggregate) BatchSize(batchSize int32) *Aggregate {
if a == nil {
a = new(Aggregate)
}
a.batchSize = &batchSize
return a
}
// BypassDocumentValidation allows the write to opt-out of document level validation. This only applies when the $out stage is specified.
func (a *Aggregate) BypassDocumentValidation(bypassDocumentValidation bool) *Aggregate {
if a == nil {
a = new(Aggregate)
}
a.bypassDocumentValidation = &bypassDocumentValidation
return a
}
// Collation specifies a collation. This option is only valid for server versions 3.4 and above.
func (a *Aggregate) Collation(collation bsoncore.Document) *Aggregate {
if a == nil {
a = new(Aggregate)
}
a.collation = collation
return a
}
// Comment specifies an arbitrary string to help trace the operation through the database profiler, currentOp, and logs.
func (a *Aggregate) Comment(comment string) *Aggregate {
if a == nil {
a = new(Aggregate)
}
a.comment = &comment
return a
}
// Hint specifies the index to use.
func (a *Aggregate) Hint(hint bsoncore.Value) *Aggregate {
if a == nil {
a = new(Aggregate)
}
a.hint = hint
return a
}
// MaxTime specifies the maximum amount of time to allow the query to run on the server.
func (a *Aggregate) MaxTime(maxTime *time.Duration) *Aggregate {
if a == nil {
a = new(Aggregate)
}
a.maxTime = maxTime
return a
}
// Pipeline determines how data is transformed for an aggregation.
func (a *Aggregate) Pipeline(pipeline bsoncore.Document) *Aggregate {
if a == nil {
a = new(Aggregate)
}
a.pipeline = pipeline
return a
}
// Session sets the session for this operation.
func (a *Aggregate) Session(session *session.Client) *Aggregate {
if a == nil {
a = new(Aggregate)
}
a.session = session
return a
}
// ClusterClock sets the cluster clock for this operation.
func (a *Aggregate) ClusterClock(clock *session.ClusterClock) *Aggregate {
if a == nil {
a = new(Aggregate)
}
a.clock = clock
return a
}
// Collection sets the collection that this command will run against.
func (a *Aggregate) Collection(collection string) *Aggregate {
if a == nil {
a = new(Aggregate)
}
a.collection = collection
return a
}
// CommandMonitor sets the monitor to use for APM events.
func (a *Aggregate) CommandMonitor(monitor *event.CommandMonitor) *Aggregate {
if a == nil {
a = new(Aggregate)
}
a.monitor = monitor
return a
}
// Database sets the database to run this operation against.
func (a *Aggregate) Database(database string) *Aggregate {
if a == nil {
a = new(Aggregate)
}
a.database = database
return a
}
// Deployment sets the deployment to use for this operation.
func (a *Aggregate) Deployment(deployment driver.Deployment) *Aggregate {
if a == nil {
a = new(Aggregate)
}
a.deployment = deployment
return a
}
// ReadConcern specifies the read concern for this operation.
func (a *Aggregate) ReadConcern(readConcern *readconcern.ReadConcern) *Aggregate {
if a == nil {
a = new(Aggregate)
}
a.readConcern = readConcern
return a
}
// ReadPreference set the read preference used with this operation.
func (a *Aggregate) ReadPreference(readPreference *readpref.ReadPref) *Aggregate {
if a == nil {
a = new(Aggregate)
}
a.readPreference = readPreference
return a
}
// ServerSelector sets the selector used to retrieve a server.
func (a *Aggregate) ServerSelector(selector description.ServerSelector) *Aggregate {
if a == nil {
a = new(Aggregate)
}
a.selector = selector
return a
}
// WriteConcern sets the write concern for this operation.
func (a *Aggregate) WriteConcern(writeConcern *writeconcern.WriteConcern) *Aggregate {
if a == nil {
a = new(Aggregate)
}
a.writeConcern = writeConcern
return a
}
// Retry enables retryable writes for this operation. Retries are not handled automatically,
// instead a boolean is returned from Execute and SelectAndExecute that indicates if the
// operation can be retried. Retrying is handled by calling RetryExecute.
func (a *Aggregate) Retry(retry driver.RetryMode) *Aggregate {
if a == nil {
a = new(Aggregate)
}
a.retry = &retry
return a
}
// Crypt sets the Crypt object to use for automatic encryption and decryption.
func (a *Aggregate) Crypt(crypt driver.Crypt) *Aggregate {
if a == nil {
a = new(Aggregate)
}
a.crypt = crypt
return a
}
// ServerAPI sets the server API version for this operation.
func (a *Aggregate) ServerAPI(serverAPI *driver.ServerAPIOptions) *Aggregate {
if a == nil {
a = new(Aggregate)
}
a.serverAPI = serverAPI
return a
}
// Let specifies the let document to use. This option is only valid for server versions 5.0 and above.
func (a *Aggregate) Let(let bsoncore.Document) *Aggregate {
if a == nil {
a = new(Aggregate)
}
a.let = let
return a
}
// HasOutputStage specifies whether the aggregate contains an output stage. Used in determining when to
// append read preference at the operation level.
func (a *Aggregate) HasOutputStage(hos bool) *Aggregate {
if a == nil {
a = new(Aggregate)
}
a.hasOutputStage = hos
return a
}
// CustomOptions specifies extra options to use in the aggregate command.
func (a *Aggregate) CustomOptions(co map[string]bsoncore.Value) *Aggregate {
if a == nil {
a = new(Aggregate)
}
a.customOptions = co
return a
}
// Timeout sets the timeout for this operation.
func (a *Aggregate) Timeout(timeout *time.Duration) *Aggregate {
if a == nil {
a = new(Aggregate)
}
a.timeout = timeout
return a
}

View File

@@ -0,0 +1,220 @@
// Copyright (C) MongoDB, Inc. 2021-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 operation
import (
"context"
"errors"
"time"
"go.mongodb.org/mongo-driver/event"
"go.mongodb.org/mongo-driver/mongo/description"
"go.mongodb.org/mongo-driver/mongo/readconcern"
"go.mongodb.org/mongo-driver/mongo/readpref"
"go.mongodb.org/mongo-driver/x/bsonx/bsoncore"
"go.mongodb.org/mongo-driver/x/mongo/driver"
"go.mongodb.org/mongo-driver/x/mongo/driver/session"
)
// Command is used to run a generic operation.
type Command struct {
command bsoncore.Document
readConcern *readconcern.ReadConcern
database string
deployment driver.Deployment
selector description.ServerSelector
readPreference *readpref.ReadPref
clock *session.ClusterClock
session *session.Client
monitor *event.CommandMonitor
resultResponse bsoncore.Document
resultCursor *driver.BatchCursor
crypt driver.Crypt
serverAPI *driver.ServerAPIOptions
createCursor bool
cursorOpts driver.CursorOptions
timeout *time.Duration
}
// NewCommand constructs and returns a new Command. Once the operation is executed, the result may only be accessed via
// the Result() function.
func NewCommand(command bsoncore.Document) *Command {
return &Command{
command: command,
}
}
// NewCursorCommand constructs a new Command. Once the operation is executed, the server response will be used to
// construct a cursor, which can be accessed via the ResultCursor() function.
func NewCursorCommand(command bsoncore.Document, cursorOpts driver.CursorOptions) *Command {
return &Command{
command: command,
cursorOpts: cursorOpts,
createCursor: true,
}
}
// Result returns the result of executing this operation.
func (c *Command) Result() bsoncore.Document { return c.resultResponse }
// ResultCursor returns the BatchCursor that was constructed using the command response. If the operation was not
// configured to create a cursor (i.e. it was created using NewCommand rather than NewCursorCommand), this function
// will return nil and an error.
func (c *Command) ResultCursor() (*driver.BatchCursor, error) {
if !c.createCursor {
return nil, errors.New("command operation was not configured to create a cursor, but a result cursor was requested")
}
return c.resultCursor, nil
}
// Execute runs this operations and returns an error if the operation did not execute successfully.
func (c *Command) Execute(ctx context.Context) error {
if c.deployment == nil {
return errors.New("the Command operation must have a Deployment set before Execute can be called")
}
return driver.Operation{
CommandFn: func(dst []byte, desc description.SelectedServer) ([]byte, error) {
return append(dst, c.command[4:len(c.command)-1]...), nil
},
ProcessResponseFn: func(info driver.ResponseInfo) error {
c.resultResponse = info.ServerResponse
if c.createCursor {
cursorRes, err := driver.NewCursorResponse(info)
if err != nil {
return err
}
c.resultCursor, err = driver.NewBatchCursor(cursorRes, c.session, c.clock, c.cursorOpts)
return err
}
return nil
},
Client: c.session,
Clock: c.clock,
CommandMonitor: c.monitor,
Database: c.database,
Deployment: c.deployment,
ReadPreference: c.readPreference,
Selector: c.selector,
Crypt: c.crypt,
ServerAPI: c.serverAPI,
Timeout: c.timeout,
}.Execute(ctx)
}
// Session sets the session for this operation.
func (c *Command) Session(session *session.Client) *Command {
if c == nil {
c = new(Command)
}
c.session = session
return c
}
// ClusterClock sets the cluster clock for this operation.
func (c *Command) ClusterClock(clock *session.ClusterClock) *Command {
if c == nil {
c = new(Command)
}
c.clock = clock
return c
}
// CommandMonitor sets the monitor to use for APM events.
func (c *Command) CommandMonitor(monitor *event.CommandMonitor) *Command {
if c == nil {
c = new(Command)
}
c.monitor = monitor
return c
}
// Database sets the database to run this operation against.
func (c *Command) Database(database string) *Command {
if c == nil {
c = new(Command)
}
c.database = database
return c
}
// Deployment sets the deployment to use for this operation.
func (c *Command) Deployment(deployment driver.Deployment) *Command {
if c == nil {
c = new(Command)
}
c.deployment = deployment
return c
}
// ReadConcern specifies the read concern for this operation.
func (c *Command) ReadConcern(readConcern *readconcern.ReadConcern) *Command {
if c == nil {
c = new(Command)
}
c.readConcern = readConcern
return c
}
// ReadPreference set the read preference used with this operation.
func (c *Command) ReadPreference(readPreference *readpref.ReadPref) *Command {
if c == nil {
c = new(Command)
}
c.readPreference = readPreference
return c
}
// ServerSelector sets the selector used to retrieve a server.
func (c *Command) ServerSelector(selector description.ServerSelector) *Command {
if c == nil {
c = new(Command)
}
c.selector = selector
return c
}
// Crypt sets the Crypt object to use for automatic encryption and decryption.
func (c *Command) Crypt(crypt driver.Crypt) *Command {
if c == nil {
c = new(Command)
}
c.crypt = crypt
return c
}
// ServerAPI sets the server API version for this operation.
func (c *Command) ServerAPI(serverAPI *driver.ServerAPIOptions) *Command {
if c == nil {
c = new(Command)
}
c.serverAPI = serverAPI
return c
}
// Timeout sets the timeout for this operation.
func (c *Command) Timeout(timeout *time.Duration) *Command {
if c == nil {
c = new(Command)
}
c.timeout = timeout
return c
}

View File

@@ -0,0 +1,201 @@
// Copyright (C) MongoDB, Inc. 2019-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 operation
import (
"context"
"errors"
"time"
"go.mongodb.org/mongo-driver/event"
"go.mongodb.org/mongo-driver/mongo/description"
"go.mongodb.org/mongo-driver/mongo/writeconcern"
"go.mongodb.org/mongo-driver/x/bsonx/bsoncore"
"go.mongodb.org/mongo-driver/x/mongo/driver"
"go.mongodb.org/mongo-driver/x/mongo/driver/session"
)
// CommitTransaction attempts to commit a transaction.
type CommitTransaction struct {
maxTime *time.Duration
recoveryToken bsoncore.Document
session *session.Client
clock *session.ClusterClock
monitor *event.CommandMonitor
crypt driver.Crypt
database string
deployment driver.Deployment
selector description.ServerSelector
writeConcern *writeconcern.WriteConcern
retry *driver.RetryMode
serverAPI *driver.ServerAPIOptions
}
// NewCommitTransaction constructs and returns a new CommitTransaction.
func NewCommitTransaction() *CommitTransaction {
return &CommitTransaction{}
}
func (ct *CommitTransaction) processResponse(driver.ResponseInfo) error {
var err error
return err
}
// Execute runs this operations and returns an error if the operation did not execute successfully.
func (ct *CommitTransaction) Execute(ctx context.Context) error {
if ct.deployment == nil {
return errors.New("the CommitTransaction operation must have a Deployment set before Execute can be called")
}
return driver.Operation{
CommandFn: ct.command,
ProcessResponseFn: ct.processResponse,
RetryMode: ct.retry,
Type: driver.Write,
Client: ct.session,
Clock: ct.clock,
CommandMonitor: ct.monitor,
Crypt: ct.crypt,
Database: ct.database,
Deployment: ct.deployment,
MaxTime: ct.maxTime,
Selector: ct.selector,
WriteConcern: ct.writeConcern,
ServerAPI: ct.serverAPI,
}.Execute(ctx)
}
func (ct *CommitTransaction) command(dst []byte, desc description.SelectedServer) ([]byte, error) {
dst = bsoncore.AppendInt32Element(dst, "commitTransaction", 1)
if ct.recoveryToken != nil {
dst = bsoncore.AppendDocumentElement(dst, "recoveryToken", ct.recoveryToken)
}
return dst, nil
}
// MaxTime specifies the maximum amount of time to allow the query to run on the server.
func (ct *CommitTransaction) MaxTime(maxTime *time.Duration) *CommitTransaction {
if ct == nil {
ct = new(CommitTransaction)
}
ct.maxTime = maxTime
return ct
}
// RecoveryToken sets the recovery token to use when committing or aborting a sharded transaction.
func (ct *CommitTransaction) RecoveryToken(recoveryToken bsoncore.Document) *CommitTransaction {
if ct == nil {
ct = new(CommitTransaction)
}
ct.recoveryToken = recoveryToken
return ct
}
// Session sets the session for this operation.
func (ct *CommitTransaction) Session(session *session.Client) *CommitTransaction {
if ct == nil {
ct = new(CommitTransaction)
}
ct.session = session
return ct
}
// ClusterClock sets the cluster clock for this operation.
func (ct *CommitTransaction) ClusterClock(clock *session.ClusterClock) *CommitTransaction {
if ct == nil {
ct = new(CommitTransaction)
}
ct.clock = clock
return ct
}
// CommandMonitor sets the monitor to use for APM events.
func (ct *CommitTransaction) CommandMonitor(monitor *event.CommandMonitor) *CommitTransaction {
if ct == nil {
ct = new(CommitTransaction)
}
ct.monitor = monitor
return ct
}
// Crypt sets the Crypt object to use for automatic encryption and decryption.
func (ct *CommitTransaction) Crypt(crypt driver.Crypt) *CommitTransaction {
if ct == nil {
ct = new(CommitTransaction)
}
ct.crypt = crypt
return ct
}
// Database sets the database to run this operation against.
func (ct *CommitTransaction) Database(database string) *CommitTransaction {
if ct == nil {
ct = new(CommitTransaction)
}
ct.database = database
return ct
}
// Deployment sets the deployment to use for this operation.
func (ct *CommitTransaction) Deployment(deployment driver.Deployment) *CommitTransaction {
if ct == nil {
ct = new(CommitTransaction)
}
ct.deployment = deployment
return ct
}
// ServerSelector sets the selector used to retrieve a server.
func (ct *CommitTransaction) ServerSelector(selector description.ServerSelector) *CommitTransaction {
if ct == nil {
ct = new(CommitTransaction)
}
ct.selector = selector
return ct
}
// WriteConcern sets the write concern for this operation.
func (ct *CommitTransaction) WriteConcern(writeConcern *writeconcern.WriteConcern) *CommitTransaction {
if ct == nil {
ct = new(CommitTransaction)
}
ct.writeConcern = writeConcern
return ct
}
// Retry enables retryable mode for this operation. Retries are handled automatically in driver.Operation.Execute based
// on how the operation is set.
func (ct *CommitTransaction) Retry(retry driver.RetryMode) *CommitTransaction {
if ct == nil {
ct = new(CommitTransaction)
}
ct.retry = &retry
return ct
}
// ServerAPI sets the server API version for this operation.
func (ct *CommitTransaction) ServerAPI(serverAPI *driver.ServerAPIOptions) *CommitTransaction {
if ct == nil {
ct = new(CommitTransaction)
}
ct.serverAPI = serverAPI
return ct
}

View File

@@ -0,0 +1,311 @@
// Copyright (C) MongoDB, Inc. 2019-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 operation
import (
"context"
"errors"
"fmt"
"time"
"go.mongodb.org/mongo-driver/bson/bsontype"
"go.mongodb.org/mongo-driver/event"
"go.mongodb.org/mongo-driver/mongo/description"
"go.mongodb.org/mongo-driver/mongo/readconcern"
"go.mongodb.org/mongo-driver/mongo/readpref"
"go.mongodb.org/mongo-driver/x/bsonx/bsoncore"
"go.mongodb.org/mongo-driver/x/mongo/driver"
"go.mongodb.org/mongo-driver/x/mongo/driver/session"
)
// Count represents a count operation.
type Count struct {
maxTime *time.Duration
query bsoncore.Document
session *session.Client
clock *session.ClusterClock
collection string
comment bsoncore.Value
monitor *event.CommandMonitor
crypt driver.Crypt
database string
deployment driver.Deployment
readConcern *readconcern.ReadConcern
readPreference *readpref.ReadPref
selector description.ServerSelector
retry *driver.RetryMode
result CountResult
serverAPI *driver.ServerAPIOptions
timeout *time.Duration
}
// CountResult represents a count result returned by the server.
type CountResult struct {
// The number of documents found
N int64
}
func buildCountResult(response bsoncore.Document) (CountResult, error) {
elements, err := response.Elements()
if err != nil {
return CountResult{}, err
}
cr := CountResult{}
for _, element := range elements {
switch element.Key() {
case "n": // for count using original command
var ok bool
cr.N, ok = element.Value().AsInt64OK()
if !ok {
return cr, fmt.Errorf("response field 'n' is type int64, but received BSON type %s",
element.Value().Type)
}
case "cursor": // for count using aggregate with $collStats
firstBatch, err := element.Value().Document().LookupErr("firstBatch")
if err != nil {
return cr, err
}
// get count value from first batch
val := firstBatch.Array().Index(0)
count, err := val.Document().LookupErr("n")
if err != nil {
return cr, err
}
// use count as Int64 for result
var ok bool
cr.N, ok = count.AsInt64OK()
if !ok {
return cr, fmt.Errorf("response field 'n' is type int64, but received BSON type %s",
element.Value().Type)
}
}
}
return cr, nil
}
// NewCount constructs and returns a new Count.
func NewCount() *Count {
return &Count{}
}
// Result returns the result of executing this operation.
func (c *Count) Result() CountResult { return c.result }
func (c *Count) processResponse(info driver.ResponseInfo) error {
var err error
c.result, err = buildCountResult(info.ServerResponse)
return err
}
// Execute runs this operations and returns an error if the operation did not execute successfully.
func (c *Count) Execute(ctx context.Context) error {
if c.deployment == nil {
return errors.New("the Count operation must have a Deployment set before Execute can be called")
}
err := driver.Operation{
CommandFn: c.command,
ProcessResponseFn: c.processResponse,
RetryMode: c.retry,
Type: driver.Read,
Client: c.session,
Clock: c.clock,
CommandMonitor: c.monitor,
Crypt: c.crypt,
Database: c.database,
Deployment: c.deployment,
MaxTime: c.maxTime,
ReadConcern: c.readConcern,
ReadPreference: c.readPreference,
Selector: c.selector,
ServerAPI: c.serverAPI,
Timeout: c.timeout,
}.Execute(ctx)
// Swallow error if NamespaceNotFound(26) is returned from aggregate on non-existent namespace
if err != nil {
dErr, ok := err.(driver.Error)
if ok && dErr.Code == 26 {
err = nil
}
}
return err
}
func (c *Count) command(dst []byte, desc description.SelectedServer) ([]byte, error) {
dst = bsoncore.AppendStringElement(dst, "count", c.collection)
if c.query != nil {
dst = bsoncore.AppendDocumentElement(dst, "query", c.query)
}
if c.comment.Type != bsontype.Type(0) {
dst = bsoncore.AppendValueElement(dst, "comment", c.comment)
}
return dst, nil
}
// MaxTime specifies the maximum amount of time to allow the query to run on the server.
func (c *Count) MaxTime(maxTime *time.Duration) *Count {
if c == nil {
c = new(Count)
}
c.maxTime = maxTime
return c
}
// Query determines what results are returned from find.
func (c *Count) Query(query bsoncore.Document) *Count {
if c == nil {
c = new(Count)
}
c.query = query
return c
}
// Session sets the session for this operation.
func (c *Count) Session(session *session.Client) *Count {
if c == nil {
c = new(Count)
}
c.session = session
return c
}
// ClusterClock sets the cluster clock for this operation.
func (c *Count) ClusterClock(clock *session.ClusterClock) *Count {
if c == nil {
c = new(Count)
}
c.clock = clock
return c
}
// Collection sets the collection that this command will run against.
func (c *Count) Collection(collection string) *Count {
if c == nil {
c = new(Count)
}
c.collection = collection
return c
}
// Comment sets a value to help trace an operation.
func (c *Count) Comment(comment bsoncore.Value) *Count {
if c == nil {
c = new(Count)
}
c.comment = comment
return c
}
// CommandMonitor sets the monitor to use for APM events.
func (c *Count) CommandMonitor(monitor *event.CommandMonitor) *Count {
if c == nil {
c = new(Count)
}
c.monitor = monitor
return c
}
// Crypt sets the Crypt object to use for automatic encryption and decryption.
func (c *Count) Crypt(crypt driver.Crypt) *Count {
if c == nil {
c = new(Count)
}
c.crypt = crypt
return c
}
// Database sets the database to run this operation against.
func (c *Count) Database(database string) *Count {
if c == nil {
c = new(Count)
}
c.database = database
return c
}
// Deployment sets the deployment to use for this operation.
func (c *Count) Deployment(deployment driver.Deployment) *Count {
if c == nil {
c = new(Count)
}
c.deployment = deployment
return c
}
// ReadConcern specifies the read concern for this operation.
func (c *Count) ReadConcern(readConcern *readconcern.ReadConcern) *Count {
if c == nil {
c = new(Count)
}
c.readConcern = readConcern
return c
}
// ReadPreference set the read preference used with this operation.
func (c *Count) ReadPreference(readPreference *readpref.ReadPref) *Count {
if c == nil {
c = new(Count)
}
c.readPreference = readPreference
return c
}
// ServerSelector sets the selector used to retrieve a server.
func (c *Count) ServerSelector(selector description.ServerSelector) *Count {
if c == nil {
c = new(Count)
}
c.selector = selector
return c
}
// Retry enables retryable mode for this operation. Retries are handled automatically in driver.Operation.Execute based
// on how the operation is set.
func (c *Count) Retry(retry driver.RetryMode) *Count {
if c == nil {
c = new(Count)
}
c.retry = &retry
return c
}
// ServerAPI sets the server API version for this operation.
func (c *Count) ServerAPI(serverAPI *driver.ServerAPIOptions) *Count {
if c == nil {
c = new(Count)
}
c.serverAPI = serverAPI
return c
}
// Timeout sets the timeout for this operation.
func (c *Count) Timeout(timeout *time.Duration) *Count {
if c == nil {
c = new(Count)
}
c.timeout = timeout
return c
}

View File

@@ -0,0 +1,402 @@
// Copyright (C) MongoDB, Inc. 2019-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 operation
import (
"context"
"errors"
"go.mongodb.org/mongo-driver/event"
"go.mongodb.org/mongo-driver/mongo/description"
"go.mongodb.org/mongo-driver/mongo/writeconcern"
"go.mongodb.org/mongo-driver/x/bsonx/bsoncore"
"go.mongodb.org/mongo-driver/x/mongo/driver"
"go.mongodb.org/mongo-driver/x/mongo/driver/session"
)
// Create represents a create operation.
type Create struct {
capped *bool
collation bsoncore.Document
changeStreamPreAndPostImages bsoncore.Document
collectionName *string
indexOptionDefaults bsoncore.Document
max *int64
pipeline bsoncore.Document
size *int64
storageEngine bsoncore.Document
validationAction *string
validationLevel *string
validator bsoncore.Document
viewOn *string
session *session.Client
clock *session.ClusterClock
monitor *event.CommandMonitor
crypt driver.Crypt
database string
deployment driver.Deployment
selector description.ServerSelector
writeConcern *writeconcern.WriteConcern
serverAPI *driver.ServerAPIOptions
expireAfterSeconds *int64
timeSeries bsoncore.Document
encryptedFields bsoncore.Document
clusteredIndex bsoncore.Document
}
// NewCreate constructs and returns a new Create.
func NewCreate(collectionName string) *Create {
return &Create{
collectionName: &collectionName,
}
}
func (c *Create) processResponse(driver.ResponseInfo) error {
return nil
}
// Execute runs this operations and returns an error if the operation did not execute successfully.
func (c *Create) Execute(ctx context.Context) error {
if c.deployment == nil {
return errors.New("the Create operation must have a Deployment set before Execute can be called")
}
return driver.Operation{
CommandFn: c.command,
ProcessResponseFn: c.processResponse,
Client: c.session,
Clock: c.clock,
CommandMonitor: c.monitor,
Crypt: c.crypt,
Database: c.database,
Deployment: c.deployment,
Selector: c.selector,
WriteConcern: c.writeConcern,
ServerAPI: c.serverAPI,
}.Execute(ctx)
}
func (c *Create) command(dst []byte, desc description.SelectedServer) ([]byte, error) {
if c.collectionName != nil {
dst = bsoncore.AppendStringElement(dst, "create", *c.collectionName)
}
if c.capped != nil {
dst = bsoncore.AppendBooleanElement(dst, "capped", *c.capped)
}
if c.changeStreamPreAndPostImages != nil {
dst = bsoncore.AppendDocumentElement(dst, "changeStreamPreAndPostImages", c.changeStreamPreAndPostImages)
}
if c.collation != nil {
if desc.WireVersion == nil || !desc.WireVersion.Includes(5) {
return nil, errors.New("the 'collation' command parameter requires a minimum server wire version of 5")
}
dst = bsoncore.AppendDocumentElement(dst, "collation", c.collation)
}
if c.indexOptionDefaults != nil {
dst = bsoncore.AppendDocumentElement(dst, "indexOptionDefaults", c.indexOptionDefaults)
}
if c.max != nil {
dst = bsoncore.AppendInt64Element(dst, "max", *c.max)
}
if c.pipeline != nil {
dst = bsoncore.AppendArrayElement(dst, "pipeline", c.pipeline)
}
if c.size != nil {
dst = bsoncore.AppendInt64Element(dst, "size", *c.size)
}
if c.storageEngine != nil {
dst = bsoncore.AppendDocumentElement(dst, "storageEngine", c.storageEngine)
}
if c.validationAction != nil {
dst = bsoncore.AppendStringElement(dst, "validationAction", *c.validationAction)
}
if c.validationLevel != nil {
dst = bsoncore.AppendStringElement(dst, "validationLevel", *c.validationLevel)
}
if c.validator != nil {
dst = bsoncore.AppendDocumentElement(dst, "validator", c.validator)
}
if c.viewOn != nil {
dst = bsoncore.AppendStringElement(dst, "viewOn", *c.viewOn)
}
if c.expireAfterSeconds != nil {
dst = bsoncore.AppendInt64Element(dst, "expireAfterSeconds", *c.expireAfterSeconds)
}
if c.timeSeries != nil {
dst = bsoncore.AppendDocumentElement(dst, "timeseries", c.timeSeries)
}
if c.encryptedFields != nil {
dst = bsoncore.AppendDocumentElement(dst, "encryptedFields", c.encryptedFields)
}
if c.clusteredIndex != nil {
dst = bsoncore.AppendDocumentElement(dst, "clusteredIndex", c.clusteredIndex)
}
return dst, nil
}
// Capped specifies if the collection is capped.
func (c *Create) Capped(capped bool) *Create {
if c == nil {
c = new(Create)
}
c.capped = &capped
return c
}
// Collation specifies a collation. This option is only valid for server versions 3.4 and above.
func (c *Create) Collation(collation bsoncore.Document) *Create {
if c == nil {
c = new(Create)
}
c.collation = collation
return c
}
// ChangeStreamPreAndPostImages specifies how change streams opened against the collection can return pre-
// and post-images of updated documents. This option is only valid for server versions 6.0 and above.
func (c *Create) ChangeStreamPreAndPostImages(csppi bsoncore.Document) *Create {
if c == nil {
c = new(Create)
}
c.changeStreamPreAndPostImages = csppi
return c
}
// CollectionName specifies the name of the collection to create.
func (c *Create) CollectionName(collectionName string) *Create {
if c == nil {
c = new(Create)
}
c.collectionName = &collectionName
return c
}
// IndexOptionDefaults specifies a default configuration for indexes on the collection.
func (c *Create) IndexOptionDefaults(indexOptionDefaults bsoncore.Document) *Create {
if c == nil {
c = new(Create)
}
c.indexOptionDefaults = indexOptionDefaults
return c
}
// Max specifies the maximum number of documents allowed in a capped collection.
func (c *Create) Max(max int64) *Create {
if c == nil {
c = new(Create)
}
c.max = &max
return c
}
// Pipeline specifies the agggregtion pipeline to be run against the source to create the view.
func (c *Create) Pipeline(pipeline bsoncore.Document) *Create {
if c == nil {
c = new(Create)
}
c.pipeline = pipeline
return c
}
// Size specifies the maximum size in bytes for a capped collection.
func (c *Create) Size(size int64) *Create {
if c == nil {
c = new(Create)
}
c.size = &size
return c
}
// StorageEngine specifies the storage engine to use for the index.
func (c *Create) StorageEngine(storageEngine bsoncore.Document) *Create {
if c == nil {
c = new(Create)
}
c.storageEngine = storageEngine
return c
}
// ValidationAction specifies what should happen if a document being inserted does not pass validation.
func (c *Create) ValidationAction(validationAction string) *Create {
if c == nil {
c = new(Create)
}
c.validationAction = &validationAction
return c
}
// ValidationLevel specifies how strictly the server applies validation rules to existing documents in the collection
// during update operations.
func (c *Create) ValidationLevel(validationLevel string) *Create {
if c == nil {
c = new(Create)
}
c.validationLevel = &validationLevel
return c
}
// Validator specifies validation rules for the collection.
func (c *Create) Validator(validator bsoncore.Document) *Create {
if c == nil {
c = new(Create)
}
c.validator = validator
return c
}
// ViewOn specifies the name of the source collection or view on which the view will be created.
func (c *Create) ViewOn(viewOn string) *Create {
if c == nil {
c = new(Create)
}
c.viewOn = &viewOn
return c
}
// Session sets the session for this operation.
func (c *Create) Session(session *session.Client) *Create {
if c == nil {
c = new(Create)
}
c.session = session
return c
}
// ClusterClock sets the cluster clock for this operation.
func (c *Create) ClusterClock(clock *session.ClusterClock) *Create {
if c == nil {
c = new(Create)
}
c.clock = clock
return c
}
// CommandMonitor sets the monitor to use for APM events.
func (c *Create) CommandMonitor(monitor *event.CommandMonitor) *Create {
if c == nil {
c = new(Create)
}
c.monitor = monitor
return c
}
// Crypt sets the Crypt object to use for automatic encryption and decryption.
func (c *Create) Crypt(crypt driver.Crypt) *Create {
if c == nil {
c = new(Create)
}
c.crypt = crypt
return c
}
// Database sets the database to run this operation against.
func (c *Create) Database(database string) *Create {
if c == nil {
c = new(Create)
}
c.database = database
return c
}
// Deployment sets the deployment to use for this operation.
func (c *Create) Deployment(deployment driver.Deployment) *Create {
if c == nil {
c = new(Create)
}
c.deployment = deployment
return c
}
// ServerSelector sets the selector used to retrieve a server.
func (c *Create) ServerSelector(selector description.ServerSelector) *Create {
if c == nil {
c = new(Create)
}
c.selector = selector
return c
}
// WriteConcern sets the write concern for this operation.
func (c *Create) WriteConcern(writeConcern *writeconcern.WriteConcern) *Create {
if c == nil {
c = new(Create)
}
c.writeConcern = writeConcern
return c
}
// ServerAPI sets the server API version for this operation.
func (c *Create) ServerAPI(serverAPI *driver.ServerAPIOptions) *Create {
if c == nil {
c = new(Create)
}
c.serverAPI = serverAPI
return c
}
// ExpireAfterSeconds sets the seconds to wait before deleting old time-series data.
func (c *Create) ExpireAfterSeconds(eas int64) *Create {
if c == nil {
c = new(Create)
}
c.expireAfterSeconds = &eas
return c
}
// TimeSeries sets the time series options for this operation.
func (c *Create) TimeSeries(timeSeries bsoncore.Document) *Create {
if c == nil {
c = new(Create)
}
c.timeSeries = timeSeries
return c
}
// EncryptedFields sets the EncryptedFields for this operation.
func (c *Create) EncryptedFields(ef bsoncore.Document) *Create {
if c == nil {
c = new(Create)
}
c.encryptedFields = ef
return c
}
// ClusteredIndex sets the ClusteredIndex option for this operation.
func (c *Create) ClusteredIndex(ci bsoncore.Document) *Create {
if c == nil {
c = new(Create)
}
c.clusteredIndex = ci
return c
}

View File

@@ -0,0 +1,278 @@
// Copyright (C) MongoDB, Inc. 2019-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 operation
import (
"context"
"errors"
"fmt"
"time"
"go.mongodb.org/mongo-driver/bson/bsontype"
"go.mongodb.org/mongo-driver/event"
"go.mongodb.org/mongo-driver/mongo/description"
"go.mongodb.org/mongo-driver/mongo/writeconcern"
"go.mongodb.org/mongo-driver/x/bsonx/bsoncore"
"go.mongodb.org/mongo-driver/x/mongo/driver"
"go.mongodb.org/mongo-driver/x/mongo/driver/session"
)
// CreateIndexes performs a createIndexes operation.
type CreateIndexes struct {
commitQuorum bsoncore.Value
indexes bsoncore.Document
maxTime *time.Duration
session *session.Client
clock *session.ClusterClock
collection string
monitor *event.CommandMonitor
crypt driver.Crypt
database string
deployment driver.Deployment
selector description.ServerSelector
writeConcern *writeconcern.WriteConcern
result CreateIndexesResult
serverAPI *driver.ServerAPIOptions
timeout *time.Duration
}
// CreateIndexesResult represents a createIndexes result returned by the server.
type CreateIndexesResult struct {
// If the collection was created automatically.
CreatedCollectionAutomatically bool
// The number of indexes existing after this command.
IndexesAfter int32
// The number of indexes existing before this command.
IndexesBefore int32
}
func buildCreateIndexesResult(response bsoncore.Document) (CreateIndexesResult, error) {
elements, err := response.Elements()
if err != nil {
return CreateIndexesResult{}, err
}
cir := CreateIndexesResult{}
for _, element := range elements {
switch element.Key() {
case "createdCollectionAutomatically":
var ok bool
cir.CreatedCollectionAutomatically, ok = element.Value().BooleanOK()
if !ok {
return cir, fmt.Errorf("response field 'createdCollectionAutomatically' is type bool, but received BSON type %s", element.Value().Type)
}
case "indexesAfter":
var ok bool
cir.IndexesAfter, ok = element.Value().AsInt32OK()
if !ok {
return cir, fmt.Errorf("response field 'indexesAfter' is type int32, but received BSON type %s", element.Value().Type)
}
case "indexesBefore":
var ok bool
cir.IndexesBefore, ok = element.Value().AsInt32OK()
if !ok {
return cir, fmt.Errorf("response field 'indexesBefore' is type int32, but received BSON type %s", element.Value().Type)
}
}
}
return cir, nil
}
// NewCreateIndexes constructs and returns a new CreateIndexes.
func NewCreateIndexes(indexes bsoncore.Document) *CreateIndexes {
return &CreateIndexes{
indexes: indexes,
}
}
// Result returns the result of executing this operation.
func (ci *CreateIndexes) Result() CreateIndexesResult { return ci.result }
func (ci *CreateIndexes) processResponse(info driver.ResponseInfo) error {
var err error
ci.result, err = buildCreateIndexesResult(info.ServerResponse)
return err
}
// Execute runs this operations and returns an error if the operation did not execute successfully.
func (ci *CreateIndexes) Execute(ctx context.Context) error {
if ci.deployment == nil {
return errors.New("the CreateIndexes operation must have a Deployment set before Execute can be called")
}
return driver.Operation{
CommandFn: ci.command,
ProcessResponseFn: ci.processResponse,
Client: ci.session,
Clock: ci.clock,
CommandMonitor: ci.monitor,
Crypt: ci.crypt,
Database: ci.database,
Deployment: ci.deployment,
MaxTime: ci.maxTime,
Selector: ci.selector,
WriteConcern: ci.writeConcern,
ServerAPI: ci.serverAPI,
Timeout: ci.timeout,
}.Execute(ctx)
}
func (ci *CreateIndexes) command(dst []byte, desc description.SelectedServer) ([]byte, error) {
dst = bsoncore.AppendStringElement(dst, "createIndexes", ci.collection)
if ci.commitQuorum.Type != bsontype.Type(0) {
if desc.WireVersion == nil || !desc.WireVersion.Includes(9) {
return nil, errors.New("the 'commitQuorum' command parameter requires a minimum server wire version of 9")
}
dst = bsoncore.AppendValueElement(dst, "commitQuorum", ci.commitQuorum)
}
if ci.indexes != nil {
dst = bsoncore.AppendArrayElement(dst, "indexes", ci.indexes)
}
return dst, nil
}
// CommitQuorum specifies the number of data-bearing members of a replica set, including the primary, that must
// complete the index builds successfully before the primary marks the indexes as ready. This should either be a
// string or int32 value.
func (ci *CreateIndexes) CommitQuorum(commitQuorum bsoncore.Value) *CreateIndexes {
if ci == nil {
ci = new(CreateIndexes)
}
ci.commitQuorum = commitQuorum
return ci
}
// Indexes specifies an array containing index specification documents for the indexes being created.
func (ci *CreateIndexes) Indexes(indexes bsoncore.Document) *CreateIndexes {
if ci == nil {
ci = new(CreateIndexes)
}
ci.indexes = indexes
return ci
}
// MaxTime specifies the maximum amount of time to allow the query to run on the server.
func (ci *CreateIndexes) MaxTime(maxTime *time.Duration) *CreateIndexes {
if ci == nil {
ci = new(CreateIndexes)
}
ci.maxTime = maxTime
return ci
}
// Session sets the session for this operation.
func (ci *CreateIndexes) Session(session *session.Client) *CreateIndexes {
if ci == nil {
ci = new(CreateIndexes)
}
ci.session = session
return ci
}
// ClusterClock sets the cluster clock for this operation.
func (ci *CreateIndexes) ClusterClock(clock *session.ClusterClock) *CreateIndexes {
if ci == nil {
ci = new(CreateIndexes)
}
ci.clock = clock
return ci
}
// Collection sets the collection that this command will run against.
func (ci *CreateIndexes) Collection(collection string) *CreateIndexes {
if ci == nil {
ci = new(CreateIndexes)
}
ci.collection = collection
return ci
}
// CommandMonitor sets the monitor to use for APM events.
func (ci *CreateIndexes) CommandMonitor(monitor *event.CommandMonitor) *CreateIndexes {
if ci == nil {
ci = new(CreateIndexes)
}
ci.monitor = monitor
return ci
}
// Crypt sets the Crypt object to use for automatic encryption and decryption.
func (ci *CreateIndexes) Crypt(crypt driver.Crypt) *CreateIndexes {
if ci == nil {
ci = new(CreateIndexes)
}
ci.crypt = crypt
return ci
}
// Database sets the database to run this operation against.
func (ci *CreateIndexes) Database(database string) *CreateIndexes {
if ci == nil {
ci = new(CreateIndexes)
}
ci.database = database
return ci
}
// Deployment sets the deployment to use for this operation.
func (ci *CreateIndexes) Deployment(deployment driver.Deployment) *CreateIndexes {
if ci == nil {
ci = new(CreateIndexes)
}
ci.deployment = deployment
return ci
}
// ServerSelector sets the selector used to retrieve a server.
func (ci *CreateIndexes) ServerSelector(selector description.ServerSelector) *CreateIndexes {
if ci == nil {
ci = new(CreateIndexes)
}
ci.selector = selector
return ci
}
// WriteConcern sets the write concern for this operation.
func (ci *CreateIndexes) WriteConcern(writeConcern *writeconcern.WriteConcern) *CreateIndexes {
if ci == nil {
ci = new(CreateIndexes)
}
ci.writeConcern = writeConcern
return ci
}
// ServerAPI sets the server API version for this operation.
func (ci *CreateIndexes) ServerAPI(serverAPI *driver.ServerAPIOptions) *CreateIndexes {
if ci == nil {
ci = new(CreateIndexes)
}
ci.serverAPI = serverAPI
return ci
}
// Timeout sets the timeout for this operation.
func (ci *CreateIndexes) Timeout(timeout *time.Duration) *CreateIndexes {
if ci == nil {
ci = new(CreateIndexes)
}
ci.timeout = timeout
return ci
}

View File

@@ -0,0 +1,314 @@
// Copyright (C) MongoDB, Inc. 2019-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 operation
import (
"context"
"errors"
"fmt"
"time"
"go.mongodb.org/mongo-driver/bson/bsontype"
"go.mongodb.org/mongo-driver/event"
"go.mongodb.org/mongo-driver/mongo/description"
"go.mongodb.org/mongo-driver/mongo/writeconcern"
"go.mongodb.org/mongo-driver/x/bsonx/bsoncore"
"go.mongodb.org/mongo-driver/x/mongo/driver"
"go.mongodb.org/mongo-driver/x/mongo/driver/session"
)
// Delete performs a delete operation
type Delete struct {
comment bsoncore.Value
deletes []bsoncore.Document
ordered *bool
session *session.Client
clock *session.ClusterClock
collection string
monitor *event.CommandMonitor
crypt driver.Crypt
database string
deployment driver.Deployment
selector description.ServerSelector
writeConcern *writeconcern.WriteConcern
retry *driver.RetryMode
hint *bool
result DeleteResult
serverAPI *driver.ServerAPIOptions
let bsoncore.Document
timeout *time.Duration
}
// DeleteResult represents a delete result returned by the server.
type DeleteResult struct {
// Number of documents successfully deleted.
N int64
}
func buildDeleteResult(response bsoncore.Document) (DeleteResult, error) {
elements, err := response.Elements()
if err != nil {
return DeleteResult{}, err
}
dr := DeleteResult{}
for _, element := range elements {
switch element.Key() {
case "n":
var ok bool
dr.N, ok = element.Value().AsInt64OK()
if !ok {
return dr, fmt.Errorf("response field 'n' is type int32 or int64, but received BSON type %s", element.Value().Type)
}
}
}
return dr, nil
}
// NewDelete constructs and returns a new Delete.
func NewDelete(deletes ...bsoncore.Document) *Delete {
return &Delete{
deletes: deletes,
}
}
// Result returns the result of executing this operation.
func (d *Delete) Result() DeleteResult { return d.result }
func (d *Delete) processResponse(info driver.ResponseInfo) error {
dr, err := buildDeleteResult(info.ServerResponse)
d.result.N += dr.N
return err
}
// Execute runs this operations and returns an error if the operation did not execute successfully.
func (d *Delete) Execute(ctx context.Context) error {
if d.deployment == nil {
return errors.New("the Delete operation must have a Deployment set before Execute can be called")
}
batches := &driver.Batches{
Identifier: "deletes",
Documents: d.deletes,
Ordered: d.ordered,
}
return driver.Operation{
CommandFn: d.command,
ProcessResponseFn: d.processResponse,
Batches: batches,
RetryMode: d.retry,
Type: driver.Write,
Client: d.session,
Clock: d.clock,
CommandMonitor: d.monitor,
Crypt: d.crypt,
Database: d.database,
Deployment: d.deployment,
Selector: d.selector,
WriteConcern: d.writeConcern,
ServerAPI: d.serverAPI,
Timeout: d.timeout,
}.Execute(ctx)
}
func (d *Delete) command(dst []byte, desc description.SelectedServer) ([]byte, error) {
dst = bsoncore.AppendStringElement(dst, "delete", d.collection)
if d.comment.Type != bsontype.Type(0) {
dst = bsoncore.AppendValueElement(dst, "comment", d.comment)
}
if d.ordered != nil {
dst = bsoncore.AppendBooleanElement(dst, "ordered", *d.ordered)
}
if d.hint != nil && *d.hint {
if desc.WireVersion == nil || !desc.WireVersion.Includes(5) {
return nil, errors.New("the 'hint' command parameter requires a minimum server wire version of 5")
}
if !d.writeConcern.Acknowledged() {
return nil, errUnacknowledgedHint
}
}
if d.let != nil {
dst = bsoncore.AppendDocumentElement(dst, "let", d.let)
}
return dst, nil
}
// Deletes adds documents to this operation that will be used to determine what documents to delete when this operation
// is executed. These documents should have the form {q: <query>, limit: <integer limit>, collation: <document>}. The
// collation field is optional. If limit is 0, there will be no limit on the number of documents deleted.
func (d *Delete) Deletes(deletes ...bsoncore.Document) *Delete {
if d == nil {
d = new(Delete)
}
d.deletes = deletes
return d
}
// Ordered sets ordered. If true, when a write fails, the operation will return the error, when
// false write failures do not stop execution of the operation.
func (d *Delete) Ordered(ordered bool) *Delete {
if d == nil {
d = new(Delete)
}
d.ordered = &ordered
return d
}
// Session sets the session for this operation.
func (d *Delete) Session(session *session.Client) *Delete {
if d == nil {
d = new(Delete)
}
d.session = session
return d
}
// ClusterClock sets the cluster clock for this operation.
func (d *Delete) ClusterClock(clock *session.ClusterClock) *Delete {
if d == nil {
d = new(Delete)
}
d.clock = clock
return d
}
// Collection sets the collection that this command will run against.
func (d *Delete) Collection(collection string) *Delete {
if d == nil {
d = new(Delete)
}
d.collection = collection
return d
}
// Comment sets a value to help trace an operation.
func (d *Delete) Comment(comment bsoncore.Value) *Delete {
if d == nil {
d = new(Delete)
}
d.comment = comment
return d
}
// CommandMonitor sets the monitor to use for APM events.
func (d *Delete) CommandMonitor(monitor *event.CommandMonitor) *Delete {
if d == nil {
d = new(Delete)
}
d.monitor = monitor
return d
}
// Crypt sets the Crypt object to use for automatic encryption and decryption.
func (d *Delete) Crypt(crypt driver.Crypt) *Delete {
if d == nil {
d = new(Delete)
}
d.crypt = crypt
return d
}
// Database sets the database to run this operation against.
func (d *Delete) Database(database string) *Delete {
if d == nil {
d = new(Delete)
}
d.database = database
return d
}
// Deployment sets the deployment to use for this operation.
func (d *Delete) Deployment(deployment driver.Deployment) *Delete {
if d == nil {
d = new(Delete)
}
d.deployment = deployment
return d
}
// ServerSelector sets the selector used to retrieve a server.
func (d *Delete) ServerSelector(selector description.ServerSelector) *Delete {
if d == nil {
d = new(Delete)
}
d.selector = selector
return d
}
// WriteConcern sets the write concern for this operation.
func (d *Delete) WriteConcern(writeConcern *writeconcern.WriteConcern) *Delete {
if d == nil {
d = new(Delete)
}
d.writeConcern = writeConcern
return d
}
// Retry enables retryable mode for this operation. Retries are handled automatically in driver.Operation.Execute based
// on how the operation is set.
func (d *Delete) Retry(retry driver.RetryMode) *Delete {
if d == nil {
d = new(Delete)
}
d.retry = &retry
return d
}
// Hint is a flag to indicate that the update document contains a hint. Hint is only supported by
// servers >= 4.4. Older servers >= 3.4 will report an error for using the hint option. For servers <
// 3.4, the driver will return an error if the hint option is used.
func (d *Delete) Hint(hint bool) *Delete {
if d == nil {
d = new(Delete)
}
d.hint = &hint
return d
}
// ServerAPI sets the server API version for this operation.
func (d *Delete) ServerAPI(serverAPI *driver.ServerAPIOptions) *Delete {
if d == nil {
d = new(Delete)
}
d.serverAPI = serverAPI
return d
}
// Let specifies the let document to use. This option is only valid for server versions 5.0 and above.
func (d *Delete) Let(let bsoncore.Document) *Delete {
if d == nil {
d = new(Delete)
}
d.let = let
return d
}
// Timeout sets the timeout for this operation.
func (d *Delete) Timeout(timeout *time.Duration) *Delete {
if d == nil {
d = new(Delete)
}
d.timeout = timeout
return d
}

View File

@@ -0,0 +1,311 @@
// Copyright (C) MongoDB, Inc. 2019-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 operation
import (
"context"
"errors"
"time"
"go.mongodb.org/mongo-driver/bson/bsontype"
"go.mongodb.org/mongo-driver/event"
"go.mongodb.org/mongo-driver/mongo/description"
"go.mongodb.org/mongo-driver/mongo/readconcern"
"go.mongodb.org/mongo-driver/mongo/readpref"
"go.mongodb.org/mongo-driver/x/bsonx/bsoncore"
"go.mongodb.org/mongo-driver/x/mongo/driver"
"go.mongodb.org/mongo-driver/x/mongo/driver/session"
)
// Distinct performs a distinct operation.
type Distinct struct {
collation bsoncore.Document
key *string
maxTime *time.Duration
query bsoncore.Document
session *session.Client
clock *session.ClusterClock
collection string
comment bsoncore.Value
monitor *event.CommandMonitor
crypt driver.Crypt
database string
deployment driver.Deployment
readConcern *readconcern.ReadConcern
readPreference *readpref.ReadPref
selector description.ServerSelector
retry *driver.RetryMode
result DistinctResult
serverAPI *driver.ServerAPIOptions
timeout *time.Duration
}
// DistinctResult represents a distinct result returned by the server.
type DistinctResult struct {
// The distinct values for the field.
Values bsoncore.Value
}
func buildDistinctResult(response bsoncore.Document) (DistinctResult, error) {
elements, err := response.Elements()
if err != nil {
return DistinctResult{}, err
}
dr := DistinctResult{}
for _, element := range elements {
switch element.Key() {
case "values":
dr.Values = element.Value()
}
}
return dr, nil
}
// NewDistinct constructs and returns a new Distinct.
func NewDistinct(key string, query bsoncore.Document) *Distinct {
return &Distinct{
key: &key,
query: query,
}
}
// Result returns the result of executing this operation.
func (d *Distinct) Result() DistinctResult { return d.result }
func (d *Distinct) processResponse(info driver.ResponseInfo) error {
var err error
d.result, err = buildDistinctResult(info.ServerResponse)
return err
}
// Execute runs this operations and returns an error if the operation did not execute successfully.
func (d *Distinct) Execute(ctx context.Context) error {
if d.deployment == nil {
return errors.New("the Distinct operation must have a Deployment set before Execute can be called")
}
return driver.Operation{
CommandFn: d.command,
ProcessResponseFn: d.processResponse,
RetryMode: d.retry,
Type: driver.Read,
Client: d.session,
Clock: d.clock,
CommandMonitor: d.monitor,
Crypt: d.crypt,
Database: d.database,
Deployment: d.deployment,
MaxTime: d.maxTime,
ReadConcern: d.readConcern,
ReadPreference: d.readPreference,
Selector: d.selector,
ServerAPI: d.serverAPI,
Timeout: d.timeout,
}.Execute(ctx)
}
func (d *Distinct) command(dst []byte, desc description.SelectedServer) ([]byte, error) {
dst = bsoncore.AppendStringElement(dst, "distinct", d.collection)
if d.collation != nil {
if desc.WireVersion == nil || !desc.WireVersion.Includes(5) {
return nil, errors.New("the 'collation' command parameter requires a minimum server wire version of 5")
}
dst = bsoncore.AppendDocumentElement(dst, "collation", d.collation)
}
if d.comment.Type != bsontype.Type(0) {
dst = bsoncore.AppendValueElement(dst, "comment", d.comment)
}
if d.key != nil {
dst = bsoncore.AppendStringElement(dst, "key", *d.key)
}
if d.query != nil {
dst = bsoncore.AppendDocumentElement(dst, "query", d.query)
}
return dst, nil
}
// Collation specifies a collation to be used.
func (d *Distinct) Collation(collation bsoncore.Document) *Distinct {
if d == nil {
d = new(Distinct)
}
d.collation = collation
return d
}
// Key specifies which field to return distinct values for.
func (d *Distinct) Key(key string) *Distinct {
if d == nil {
d = new(Distinct)
}
d.key = &key
return d
}
// MaxTime specifies the maximum amount of time to allow the query to run on the server.
func (d *Distinct) MaxTime(maxTime *time.Duration) *Distinct {
if d == nil {
d = new(Distinct)
}
d.maxTime = maxTime
return d
}
// Query specifies which documents to return distinct values from.
func (d *Distinct) Query(query bsoncore.Document) *Distinct {
if d == nil {
d = new(Distinct)
}
d.query = query
return d
}
// Session sets the session for this operation.
func (d *Distinct) Session(session *session.Client) *Distinct {
if d == nil {
d = new(Distinct)
}
d.session = session
return d
}
// ClusterClock sets the cluster clock for this operation.
func (d *Distinct) ClusterClock(clock *session.ClusterClock) *Distinct {
if d == nil {
d = new(Distinct)
}
d.clock = clock
return d
}
// Collection sets the collection that this command will run against.
func (d *Distinct) Collection(collection string) *Distinct {
if d == nil {
d = new(Distinct)
}
d.collection = collection
return d
}
// Comment sets a value to help trace an operation.
func (d *Distinct) Comment(comment bsoncore.Value) *Distinct {
if d == nil {
d = new(Distinct)
}
d.comment = comment
return d
}
// CommandMonitor sets the monitor to use for APM events.
func (d *Distinct) CommandMonitor(monitor *event.CommandMonitor) *Distinct {
if d == nil {
d = new(Distinct)
}
d.monitor = monitor
return d
}
// Crypt sets the Crypt object to use for automatic encryption and decryption.
func (d *Distinct) Crypt(crypt driver.Crypt) *Distinct {
if d == nil {
d = new(Distinct)
}
d.crypt = crypt
return d
}
// Database sets the database to run this operation against.
func (d *Distinct) Database(database string) *Distinct {
if d == nil {
d = new(Distinct)
}
d.database = database
return d
}
// Deployment sets the deployment to use for this operation.
func (d *Distinct) Deployment(deployment driver.Deployment) *Distinct {
if d == nil {
d = new(Distinct)
}
d.deployment = deployment
return d
}
// ReadConcern specifies the read concern for this operation.
func (d *Distinct) ReadConcern(readConcern *readconcern.ReadConcern) *Distinct {
if d == nil {
d = new(Distinct)
}
d.readConcern = readConcern
return d
}
// ReadPreference set the read preference used with this operation.
func (d *Distinct) ReadPreference(readPreference *readpref.ReadPref) *Distinct {
if d == nil {
d = new(Distinct)
}
d.readPreference = readPreference
return d
}
// ServerSelector sets the selector used to retrieve a server.
func (d *Distinct) ServerSelector(selector description.ServerSelector) *Distinct {
if d == nil {
d = new(Distinct)
}
d.selector = selector
return d
}
// Retry enables retryable mode for this operation. Retries are handled automatically in driver.Operation.Execute based
// on how the operation is set.
func (d *Distinct) Retry(retry driver.RetryMode) *Distinct {
if d == nil {
d = new(Distinct)
}
d.retry = &retry
return d
}
// ServerAPI sets the server API version for this operation.
func (d *Distinct) ServerAPI(serverAPI *driver.ServerAPIOptions) *Distinct {
if d == nil {
d = new(Distinct)
}
d.serverAPI = serverAPI
return d
}
// Timeout sets the timeout for this operation.
func (d *Distinct) Timeout(timeout *time.Duration) *Distinct {
if d == nil {
d = new(Distinct)
}
d.timeout = timeout
return d
}

View File

@@ -0,0 +1,222 @@
// Copyright (C) MongoDB, Inc. 2019-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 operation
import (
"context"
"errors"
"fmt"
"time"
"go.mongodb.org/mongo-driver/event"
"go.mongodb.org/mongo-driver/mongo/description"
"go.mongodb.org/mongo-driver/mongo/writeconcern"
"go.mongodb.org/mongo-driver/x/bsonx/bsoncore"
"go.mongodb.org/mongo-driver/x/mongo/driver"
"go.mongodb.org/mongo-driver/x/mongo/driver/session"
)
// DropCollection performs a drop operation.
type DropCollection struct {
session *session.Client
clock *session.ClusterClock
collection string
monitor *event.CommandMonitor
crypt driver.Crypt
database string
deployment driver.Deployment
selector description.ServerSelector
writeConcern *writeconcern.WriteConcern
result DropCollectionResult
serverAPI *driver.ServerAPIOptions
timeout *time.Duration
}
// DropCollectionResult represents a dropCollection result returned by the server.
type DropCollectionResult struct {
// The number of indexes in the dropped collection.
NIndexesWas int32
// The namespace of the dropped collection.
Ns string
}
func buildDropCollectionResult(response bsoncore.Document) (DropCollectionResult, error) {
elements, err := response.Elements()
if err != nil {
return DropCollectionResult{}, err
}
dcr := DropCollectionResult{}
for _, element := range elements {
switch element.Key() {
case "nIndexesWas":
var ok bool
dcr.NIndexesWas, ok = element.Value().AsInt32OK()
if !ok {
return dcr, fmt.Errorf("response field 'nIndexesWas' is type int32, but received BSON type %s", element.Value().Type)
}
case "ns":
var ok bool
dcr.Ns, ok = element.Value().StringValueOK()
if !ok {
return dcr, fmt.Errorf("response field 'ns' is type string, but received BSON type %s", element.Value().Type)
}
}
}
return dcr, nil
}
// NewDropCollection constructs and returns a new DropCollection.
func NewDropCollection() *DropCollection {
return &DropCollection{}
}
// Result returns the result of executing this operation.
func (dc *DropCollection) Result() DropCollectionResult { return dc.result }
func (dc *DropCollection) processResponse(info driver.ResponseInfo) error {
var err error
dc.result, err = buildDropCollectionResult(info.ServerResponse)
return err
}
// Execute runs this operations and returns an error if the operation did not execute successfully.
func (dc *DropCollection) Execute(ctx context.Context) error {
if dc.deployment == nil {
return errors.New("the DropCollection operation must have a Deployment set before Execute can be called")
}
return driver.Operation{
CommandFn: dc.command,
ProcessResponseFn: dc.processResponse,
Client: dc.session,
Clock: dc.clock,
CommandMonitor: dc.monitor,
Crypt: dc.crypt,
Database: dc.database,
Deployment: dc.deployment,
Selector: dc.selector,
WriteConcern: dc.writeConcern,
ServerAPI: dc.serverAPI,
Timeout: dc.timeout,
}.Execute(ctx)
}
func (dc *DropCollection) command(dst []byte, desc description.SelectedServer) ([]byte, error) {
dst = bsoncore.AppendStringElement(dst, "drop", dc.collection)
return dst, nil
}
// Session sets the session for this operation.
func (dc *DropCollection) Session(session *session.Client) *DropCollection {
if dc == nil {
dc = new(DropCollection)
}
dc.session = session
return dc
}
// ClusterClock sets the cluster clock for this operation.
func (dc *DropCollection) ClusterClock(clock *session.ClusterClock) *DropCollection {
if dc == nil {
dc = new(DropCollection)
}
dc.clock = clock
return dc
}
// Collection sets the collection that this command will run against.
func (dc *DropCollection) Collection(collection string) *DropCollection {
if dc == nil {
dc = new(DropCollection)
}
dc.collection = collection
return dc
}
// CommandMonitor sets the monitor to use for APM events.
func (dc *DropCollection) CommandMonitor(monitor *event.CommandMonitor) *DropCollection {
if dc == nil {
dc = new(DropCollection)
}
dc.monitor = monitor
return dc
}
// Crypt sets the Crypt object to use for automatic encryption and decryption.
func (dc *DropCollection) Crypt(crypt driver.Crypt) *DropCollection {
if dc == nil {
dc = new(DropCollection)
}
dc.crypt = crypt
return dc
}
// Database sets the database to run this operation against.
func (dc *DropCollection) Database(database string) *DropCollection {
if dc == nil {
dc = new(DropCollection)
}
dc.database = database
return dc
}
// Deployment sets the deployment to use for this operation.
func (dc *DropCollection) Deployment(deployment driver.Deployment) *DropCollection {
if dc == nil {
dc = new(DropCollection)
}
dc.deployment = deployment
return dc
}
// ServerSelector sets the selector used to retrieve a server.
func (dc *DropCollection) ServerSelector(selector description.ServerSelector) *DropCollection {
if dc == nil {
dc = new(DropCollection)
}
dc.selector = selector
return dc
}
// WriteConcern sets the write concern for this operation.
func (dc *DropCollection) WriteConcern(writeConcern *writeconcern.WriteConcern) *DropCollection {
if dc == nil {
dc = new(DropCollection)
}
dc.writeConcern = writeConcern
return dc
}
// ServerAPI sets the server API version for this operation.
func (dc *DropCollection) ServerAPI(serverAPI *driver.ServerAPIOptions) *DropCollection {
if dc == nil {
dc = new(DropCollection)
}
dc.serverAPI = serverAPI
return dc
}
// Timeout sets the timeout for this operation.
func (dc *DropCollection) Timeout(timeout *time.Duration) *DropCollection {
if dc == nil {
dc = new(DropCollection)
}
dc.timeout = timeout
return dc
}

View File

@@ -0,0 +1,154 @@
// Copyright (C) MongoDB, Inc. 2019-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 operation
import (
"context"
"errors"
"go.mongodb.org/mongo-driver/event"
"go.mongodb.org/mongo-driver/mongo/description"
"go.mongodb.org/mongo-driver/mongo/writeconcern"
"go.mongodb.org/mongo-driver/x/bsonx/bsoncore"
"go.mongodb.org/mongo-driver/x/mongo/driver"
"go.mongodb.org/mongo-driver/x/mongo/driver/session"
)
// DropDatabase performs a dropDatabase operation
type DropDatabase struct {
session *session.Client
clock *session.ClusterClock
monitor *event.CommandMonitor
crypt driver.Crypt
database string
deployment driver.Deployment
selector description.ServerSelector
writeConcern *writeconcern.WriteConcern
serverAPI *driver.ServerAPIOptions
}
// NewDropDatabase constructs and returns a new DropDatabase.
func NewDropDatabase() *DropDatabase {
return &DropDatabase{}
}
// Execute runs this operations and returns an error if the operation did not execute successfully.
func (dd *DropDatabase) Execute(ctx context.Context) error {
if dd.deployment == nil {
return errors.New("the DropDatabase operation must have a Deployment set before Execute can be called")
}
return driver.Operation{
CommandFn: dd.command,
Client: dd.session,
Clock: dd.clock,
CommandMonitor: dd.monitor,
Crypt: dd.crypt,
Database: dd.database,
Deployment: dd.deployment,
Selector: dd.selector,
WriteConcern: dd.writeConcern,
ServerAPI: dd.serverAPI,
}.Execute(ctx)
}
func (dd *DropDatabase) command(dst []byte, desc description.SelectedServer) ([]byte, error) {
dst = bsoncore.AppendInt32Element(dst, "dropDatabase", 1)
return dst, nil
}
// Session sets the session for this operation.
func (dd *DropDatabase) Session(session *session.Client) *DropDatabase {
if dd == nil {
dd = new(DropDatabase)
}
dd.session = session
return dd
}
// ClusterClock sets the cluster clock for this operation.
func (dd *DropDatabase) ClusterClock(clock *session.ClusterClock) *DropDatabase {
if dd == nil {
dd = new(DropDatabase)
}
dd.clock = clock
return dd
}
// CommandMonitor sets the monitor to use for APM events.
func (dd *DropDatabase) CommandMonitor(monitor *event.CommandMonitor) *DropDatabase {
if dd == nil {
dd = new(DropDatabase)
}
dd.monitor = monitor
return dd
}
// Crypt sets the Crypt object to use for automatic encryption and decryption.
func (dd *DropDatabase) Crypt(crypt driver.Crypt) *DropDatabase {
if dd == nil {
dd = new(DropDatabase)
}
dd.crypt = crypt
return dd
}
// Database sets the database to run this operation against.
func (dd *DropDatabase) Database(database string) *DropDatabase {
if dd == nil {
dd = new(DropDatabase)
}
dd.database = database
return dd
}
// Deployment sets the deployment to use for this operation.
func (dd *DropDatabase) Deployment(deployment driver.Deployment) *DropDatabase {
if dd == nil {
dd = new(DropDatabase)
}
dd.deployment = deployment
return dd
}
// ServerSelector sets the selector used to retrieve a server.
func (dd *DropDatabase) ServerSelector(selector description.ServerSelector) *DropDatabase {
if dd == nil {
dd = new(DropDatabase)
}
dd.selector = selector
return dd
}
// WriteConcern sets the write concern for this operation.
func (dd *DropDatabase) WriteConcern(writeConcern *writeconcern.WriteConcern) *DropDatabase {
if dd == nil {
dd = new(DropDatabase)
}
dd.writeConcern = writeConcern
return dd
}
// ServerAPI sets the server API version for this operation.
func (dd *DropDatabase) ServerAPI(serverAPI *driver.ServerAPIOptions) *DropDatabase {
if dd == nil {
dd = new(DropDatabase)
}
dd.serverAPI = serverAPI
return dd
}

View File

@@ -0,0 +1,242 @@
// Copyright (C) MongoDB, Inc. 2019-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 operation
import (
"context"
"errors"
"fmt"
"time"
"go.mongodb.org/mongo-driver/event"
"go.mongodb.org/mongo-driver/mongo/description"
"go.mongodb.org/mongo-driver/mongo/writeconcern"
"go.mongodb.org/mongo-driver/x/bsonx/bsoncore"
"go.mongodb.org/mongo-driver/x/mongo/driver"
"go.mongodb.org/mongo-driver/x/mongo/driver/session"
)
// DropIndexes performs an dropIndexes operation.
type DropIndexes struct {
index *string
maxTime *time.Duration
session *session.Client
clock *session.ClusterClock
collection string
monitor *event.CommandMonitor
crypt driver.Crypt
database string
deployment driver.Deployment
selector description.ServerSelector
writeConcern *writeconcern.WriteConcern
result DropIndexesResult
serverAPI *driver.ServerAPIOptions
timeout *time.Duration
}
// DropIndexesResult represents a dropIndexes result returned by the server.
type DropIndexesResult struct {
// Number of indexes that existed before the drop was executed.
NIndexesWas int32
}
func buildDropIndexesResult(response bsoncore.Document) (DropIndexesResult, error) {
elements, err := response.Elements()
if err != nil {
return DropIndexesResult{}, err
}
dir := DropIndexesResult{}
for _, element := range elements {
switch element.Key() {
case "nIndexesWas":
var ok bool
dir.NIndexesWas, ok = element.Value().AsInt32OK()
if !ok {
return dir, fmt.Errorf("response field 'nIndexesWas' is type int32, but received BSON type %s", element.Value().Type)
}
}
}
return dir, nil
}
// NewDropIndexes constructs and returns a new DropIndexes.
func NewDropIndexes(index string) *DropIndexes {
return &DropIndexes{
index: &index,
}
}
// Result returns the result of executing this operation.
func (di *DropIndexes) Result() DropIndexesResult { return di.result }
func (di *DropIndexes) processResponse(info driver.ResponseInfo) error {
var err error
di.result, err = buildDropIndexesResult(info.ServerResponse)
return err
}
// Execute runs this operations and returns an error if the operation did not execute successfully.
func (di *DropIndexes) Execute(ctx context.Context) error {
if di.deployment == nil {
return errors.New("the DropIndexes operation must have a Deployment set before Execute can be called")
}
return driver.Operation{
CommandFn: di.command,
ProcessResponseFn: di.processResponse,
Client: di.session,
Clock: di.clock,
CommandMonitor: di.monitor,
Crypt: di.crypt,
Database: di.database,
Deployment: di.deployment,
MaxTime: di.maxTime,
Selector: di.selector,
WriteConcern: di.writeConcern,
ServerAPI: di.serverAPI,
Timeout: di.timeout,
}.Execute(ctx)
}
func (di *DropIndexes) command(dst []byte, desc description.SelectedServer) ([]byte, error) {
dst = bsoncore.AppendStringElement(dst, "dropIndexes", di.collection)
if di.index != nil {
dst = bsoncore.AppendStringElement(dst, "index", *di.index)
}
return dst, nil
}
// Index specifies the name of the index to drop. If '*' is specified, all indexes will be dropped.
func (di *DropIndexes) Index(index string) *DropIndexes {
if di == nil {
di = new(DropIndexes)
}
di.index = &index
return di
}
// MaxTime specifies the maximum amount of time to allow the query to run on the server.
func (di *DropIndexes) MaxTime(maxTime *time.Duration) *DropIndexes {
if di == nil {
di = new(DropIndexes)
}
di.maxTime = maxTime
return di
}
// Session sets the session for this operation.
func (di *DropIndexes) Session(session *session.Client) *DropIndexes {
if di == nil {
di = new(DropIndexes)
}
di.session = session
return di
}
// ClusterClock sets the cluster clock for this operation.
func (di *DropIndexes) ClusterClock(clock *session.ClusterClock) *DropIndexes {
if di == nil {
di = new(DropIndexes)
}
di.clock = clock
return di
}
// Collection sets the collection that this command will run against.
func (di *DropIndexes) Collection(collection string) *DropIndexes {
if di == nil {
di = new(DropIndexes)
}
di.collection = collection
return di
}
// CommandMonitor sets the monitor to use for APM events.
func (di *DropIndexes) CommandMonitor(monitor *event.CommandMonitor) *DropIndexes {
if di == nil {
di = new(DropIndexes)
}
di.monitor = monitor
return di
}
// Crypt sets the Crypt object to use for automatic encryption and decryption.
func (di *DropIndexes) Crypt(crypt driver.Crypt) *DropIndexes {
if di == nil {
di = new(DropIndexes)
}
di.crypt = crypt
return di
}
// Database sets the database to run this operation against.
func (di *DropIndexes) Database(database string) *DropIndexes {
if di == nil {
di = new(DropIndexes)
}
di.database = database
return di
}
// Deployment sets the deployment to use for this operation.
func (di *DropIndexes) Deployment(deployment driver.Deployment) *DropIndexes {
if di == nil {
di = new(DropIndexes)
}
di.deployment = deployment
return di
}
// ServerSelector sets the selector used to retrieve a server.
func (di *DropIndexes) ServerSelector(selector description.ServerSelector) *DropIndexes {
if di == nil {
di = new(DropIndexes)
}
di.selector = selector
return di
}
// WriteConcern sets the write concern for this operation.
func (di *DropIndexes) WriteConcern(writeConcern *writeconcern.WriteConcern) *DropIndexes {
if di == nil {
di = new(DropIndexes)
}
di.writeConcern = writeConcern
return di
}
// ServerAPI sets the server API version for this operation.
func (di *DropIndexes) ServerAPI(serverAPI *driver.ServerAPIOptions) *DropIndexes {
if di == nil {
di = new(DropIndexes)
}
di.serverAPI = serverAPI
return di
}
// Timeout sets the timeout for this operation.
func (di *DropIndexes) Timeout(timeout *time.Duration) *DropIndexes {
if di == nil {
di = new(DropIndexes)
}
di.timeout = timeout
return di
}

View File

@@ -0,0 +1,161 @@
// Copyright (C) MongoDB, Inc. 2019-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 operation
import (
"context"
"errors"
"go.mongodb.org/mongo-driver/event"
"go.mongodb.org/mongo-driver/mongo/description"
"go.mongodb.org/mongo-driver/x/bsonx/bsoncore"
"go.mongodb.org/mongo-driver/x/mongo/driver"
"go.mongodb.org/mongo-driver/x/mongo/driver/session"
)
// EndSessions performs an endSessions operation.
type EndSessions struct {
sessionIDs bsoncore.Document
session *session.Client
clock *session.ClusterClock
monitor *event.CommandMonitor
crypt driver.Crypt
database string
deployment driver.Deployment
selector description.ServerSelector
serverAPI *driver.ServerAPIOptions
}
// NewEndSessions constructs and returns a new EndSessions.
func NewEndSessions(sessionIDs bsoncore.Document) *EndSessions {
return &EndSessions{
sessionIDs: sessionIDs,
}
}
func (es *EndSessions) processResponse(driver.ResponseInfo) error {
var err error
return err
}
// Execute runs this operations and returns an error if the operation did not execute successfully.
func (es *EndSessions) Execute(ctx context.Context) error {
if es.deployment == nil {
return errors.New("the EndSessions operation must have a Deployment set before Execute can be called")
}
return driver.Operation{
CommandFn: es.command,
ProcessResponseFn: es.processResponse,
Client: es.session,
Clock: es.clock,
CommandMonitor: es.monitor,
Crypt: es.crypt,
Database: es.database,
Deployment: es.deployment,
Selector: es.selector,
ServerAPI: es.serverAPI,
}.Execute(ctx)
}
func (es *EndSessions) command(dst []byte, desc description.SelectedServer) ([]byte, error) {
if es.sessionIDs != nil {
dst = bsoncore.AppendArrayElement(dst, "endSessions", es.sessionIDs)
}
return dst, nil
}
// SessionIDs specifies the sessions to be expired.
func (es *EndSessions) SessionIDs(sessionIDs bsoncore.Document) *EndSessions {
if es == nil {
es = new(EndSessions)
}
es.sessionIDs = sessionIDs
return es
}
// Session sets the session for this operation.
func (es *EndSessions) Session(session *session.Client) *EndSessions {
if es == nil {
es = new(EndSessions)
}
es.session = session
return es
}
// ClusterClock sets the cluster clock for this operation.
func (es *EndSessions) ClusterClock(clock *session.ClusterClock) *EndSessions {
if es == nil {
es = new(EndSessions)
}
es.clock = clock
return es
}
// CommandMonitor sets the monitor to use for APM events.
func (es *EndSessions) CommandMonitor(monitor *event.CommandMonitor) *EndSessions {
if es == nil {
es = new(EndSessions)
}
es.monitor = monitor
return es
}
// Crypt sets the Crypt object to use for automatic encryption and decryption.
func (es *EndSessions) Crypt(crypt driver.Crypt) *EndSessions {
if es == nil {
es = new(EndSessions)
}
es.crypt = crypt
return es
}
// Database sets the database to run this operation against.
func (es *EndSessions) Database(database string) *EndSessions {
if es == nil {
es = new(EndSessions)
}
es.database = database
return es
}
// Deployment sets the deployment to use for this operation.
func (es *EndSessions) Deployment(deployment driver.Deployment) *EndSessions {
if es == nil {
es = new(EndSessions)
}
es.deployment = deployment
return es
}
// ServerSelector sets the selector used to retrieve a server.
func (es *EndSessions) ServerSelector(selector description.ServerSelector) *EndSessions {
if es == nil {
es = new(EndSessions)
}
es.selector = selector
return es
}
// ServerAPI sets the server API version for this operation.
func (es *EndSessions) ServerAPI(serverAPI *driver.ServerAPIOptions) *EndSessions {
if es == nil {
es = new(EndSessions)
}
es.serverAPI = serverAPI
return es
}

View File

@@ -0,0 +1,13 @@
// 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 operation
import "errors"
var (
errUnacknowledgedHint = errors.New("the 'hint' command parameter cannot be used with unacknowledged writes")
)

View File

@@ -0,0 +1,548 @@
// Copyright (C) MongoDB, Inc. 2019-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 operation
import (
"context"
"errors"
"time"
"go.mongodb.org/mongo-driver/bson/bsontype"
"go.mongodb.org/mongo-driver/event"
"go.mongodb.org/mongo-driver/mongo/description"
"go.mongodb.org/mongo-driver/mongo/readconcern"
"go.mongodb.org/mongo-driver/mongo/readpref"
"go.mongodb.org/mongo-driver/x/bsonx/bsoncore"
"go.mongodb.org/mongo-driver/x/mongo/driver"
"go.mongodb.org/mongo-driver/x/mongo/driver/session"
)
// Find performs a find operation.
type Find struct {
allowDiskUse *bool
allowPartialResults *bool
awaitData *bool
batchSize *int32
collation bsoncore.Document
comment *string
filter bsoncore.Document
hint bsoncore.Value
let bsoncore.Document
limit *int64
max bsoncore.Document
maxTime *time.Duration
min bsoncore.Document
noCursorTimeout *bool
oplogReplay *bool
projection bsoncore.Document
returnKey *bool
showRecordID *bool
singleBatch *bool
skip *int64
snapshot *bool
sort bsoncore.Document
tailable *bool
session *session.Client
clock *session.ClusterClock
collection string
monitor *event.CommandMonitor
crypt driver.Crypt
database string
deployment driver.Deployment
readConcern *readconcern.ReadConcern
readPreference *readpref.ReadPref
selector description.ServerSelector
retry *driver.RetryMode
result driver.CursorResponse
serverAPI *driver.ServerAPIOptions
timeout *time.Duration
}
// NewFind constructs and returns a new Find.
func NewFind(filter bsoncore.Document) *Find {
return &Find{
filter: filter,
}
}
// Result returns the result of executing this operation.
func (f *Find) Result(opts driver.CursorOptions) (*driver.BatchCursor, error) {
opts.ServerAPI = f.serverAPI
return driver.NewBatchCursor(f.result, f.session, f.clock, opts)
}
func (f *Find) processResponse(info driver.ResponseInfo) error {
var err error
f.result, err = driver.NewCursorResponse(info)
return err
}
// Execute runs this operations and returns an error if the operation did not execute successfully.
func (f *Find) Execute(ctx context.Context) error {
if f.deployment == nil {
return errors.New("the Find operation must have a Deployment set before Execute can be called")
}
return driver.Operation{
CommandFn: f.command,
ProcessResponseFn: f.processResponse,
RetryMode: f.retry,
Type: driver.Read,
Client: f.session,
Clock: f.clock,
CommandMonitor: f.monitor,
Crypt: f.crypt,
Database: f.database,
Deployment: f.deployment,
MaxTime: f.maxTime,
ReadConcern: f.readConcern,
ReadPreference: f.readPreference,
Selector: f.selector,
Legacy: driver.LegacyFind,
ServerAPI: f.serverAPI,
Timeout: f.timeout,
}.Execute(ctx)
}
func (f *Find) command(dst []byte, desc description.SelectedServer) ([]byte, error) {
dst = bsoncore.AppendStringElement(dst, "find", f.collection)
if f.allowDiskUse != nil {
if desc.WireVersion == nil || !desc.WireVersion.Includes(4) {
return nil, errors.New("the 'allowDiskUse' command parameter requires a minimum server wire version of 4")
}
dst = bsoncore.AppendBooleanElement(dst, "allowDiskUse", *f.allowDiskUse)
}
if f.allowPartialResults != nil {
dst = bsoncore.AppendBooleanElement(dst, "allowPartialResults", *f.allowPartialResults)
}
if f.awaitData != nil {
dst = bsoncore.AppendBooleanElement(dst, "awaitData", *f.awaitData)
}
if f.batchSize != nil {
dst = bsoncore.AppendInt32Element(dst, "batchSize", *f.batchSize)
}
if f.collation != nil {
if desc.WireVersion == nil || !desc.WireVersion.Includes(5) {
return nil, errors.New("the 'collation' command parameter requires a minimum server wire version of 5")
}
dst = bsoncore.AppendDocumentElement(dst, "collation", f.collation)
}
if f.comment != nil {
dst = bsoncore.AppendStringElement(dst, "comment", *f.comment)
}
if f.filter != nil {
dst = bsoncore.AppendDocumentElement(dst, "filter", f.filter)
}
if f.hint.Type != bsontype.Type(0) {
dst = bsoncore.AppendValueElement(dst, "hint", f.hint)
}
if f.let != nil {
dst = bsoncore.AppendDocumentElement(dst, "let", f.let)
}
if f.limit != nil {
dst = bsoncore.AppendInt64Element(dst, "limit", *f.limit)
}
if f.max != nil {
dst = bsoncore.AppendDocumentElement(dst, "max", f.max)
}
if f.min != nil {
dst = bsoncore.AppendDocumentElement(dst, "min", f.min)
}
if f.noCursorTimeout != nil {
dst = bsoncore.AppendBooleanElement(dst, "noCursorTimeout", *f.noCursorTimeout)
}
if f.oplogReplay != nil {
dst = bsoncore.AppendBooleanElement(dst, "oplogReplay", *f.oplogReplay)
}
if f.projection != nil {
dst = bsoncore.AppendDocumentElement(dst, "projection", f.projection)
}
if f.returnKey != nil {
dst = bsoncore.AppendBooleanElement(dst, "returnKey", *f.returnKey)
}
if f.showRecordID != nil {
dst = bsoncore.AppendBooleanElement(dst, "showRecordId", *f.showRecordID)
}
if f.singleBatch != nil {
dst = bsoncore.AppendBooleanElement(dst, "singleBatch", *f.singleBatch)
}
if f.skip != nil {
dst = bsoncore.AppendInt64Element(dst, "skip", *f.skip)
}
if f.snapshot != nil {
dst = bsoncore.AppendBooleanElement(dst, "snapshot", *f.snapshot)
}
if f.sort != nil {
dst = bsoncore.AppendDocumentElement(dst, "sort", f.sort)
}
if f.tailable != nil {
dst = bsoncore.AppendBooleanElement(dst, "tailable", *f.tailable)
}
return dst, nil
}
// AllowDiskUse when true allows temporary data to be written to disk during the find command."
func (f *Find) AllowDiskUse(allowDiskUse bool) *Find {
if f == nil {
f = new(Find)
}
f.allowDiskUse = &allowDiskUse
return f
}
// AllowPartialResults when true allows partial results to be returned if some shards are down.
func (f *Find) AllowPartialResults(allowPartialResults bool) *Find {
if f == nil {
f = new(Find)
}
f.allowPartialResults = &allowPartialResults
return f
}
// AwaitData when true makes a cursor block before returning when no data is available.
func (f *Find) AwaitData(awaitData bool) *Find {
if f == nil {
f = new(Find)
}
f.awaitData = &awaitData
return f
}
// BatchSize specifies the number of documents to return in every batch.
func (f *Find) BatchSize(batchSize int32) *Find {
if f == nil {
f = new(Find)
}
f.batchSize = &batchSize
return f
}
// Collation specifies a collation to be used.
func (f *Find) Collation(collation bsoncore.Document) *Find {
if f == nil {
f = new(Find)
}
f.collation = collation
return f
}
// Comment sets a string to help trace an operation.
func (f *Find) Comment(comment string) *Find {
if f == nil {
f = new(Find)
}
f.comment = &comment
return f
}
// Filter determines what results are returned from find.
func (f *Find) Filter(filter bsoncore.Document) *Find {
if f == nil {
f = new(Find)
}
f.filter = filter
return f
}
// Hint specifies the index to use.
func (f *Find) Hint(hint bsoncore.Value) *Find {
if f == nil {
f = new(Find)
}
f.hint = hint
return f
}
// Let specifies the let document to use. This option is only valid for server versions 5.0 and above.
func (f *Find) Let(let bsoncore.Document) *Find {
if f == nil {
f = new(Find)
}
f.let = let
return f
}
// Limit sets a limit on the number of documents to return.
func (f *Find) Limit(limit int64) *Find {
if f == nil {
f = new(Find)
}
f.limit = &limit
return f
}
// Max sets an exclusive upper bound for a specific index.
func (f *Find) Max(max bsoncore.Document) *Find {
if f == nil {
f = new(Find)
}
f.max = max
return f
}
// MaxTime specifies the maximum amount of time to allow the query to run on the server.
func (f *Find) MaxTime(maxTime *time.Duration) *Find {
if f == nil {
f = new(Find)
}
f.maxTime = maxTime
return f
}
// Min sets an inclusive lower bound for a specific index.
func (f *Find) Min(min bsoncore.Document) *Find {
if f == nil {
f = new(Find)
}
f.min = min
return f
}
// NoCursorTimeout when true prevents cursor from timing out after an inactivity period.
func (f *Find) NoCursorTimeout(noCursorTimeout bool) *Find {
if f == nil {
f = new(Find)
}
f.noCursorTimeout = &noCursorTimeout
return f
}
// OplogReplay when true replays a replica set's oplog.
func (f *Find) OplogReplay(oplogReplay bool) *Find {
if f == nil {
f = new(Find)
}
f.oplogReplay = &oplogReplay
return f
}
// Projection limits the fields returned for all documents.
func (f *Find) Projection(projection bsoncore.Document) *Find {
if f == nil {
f = new(Find)
}
f.projection = projection
return f
}
// ReturnKey when true returns index keys for all result documents.
func (f *Find) ReturnKey(returnKey bool) *Find {
if f == nil {
f = new(Find)
}
f.returnKey = &returnKey
return f
}
// ShowRecordID when true adds a $recordId field with the record identifier to returned documents.
func (f *Find) ShowRecordID(showRecordID bool) *Find {
if f == nil {
f = new(Find)
}
f.showRecordID = &showRecordID
return f
}
// SingleBatch specifies whether the results should be returned in a single batch.
func (f *Find) SingleBatch(singleBatch bool) *Find {
if f == nil {
f = new(Find)
}
f.singleBatch = &singleBatch
return f
}
// Skip specifies the number of documents to skip before returning.
func (f *Find) Skip(skip int64) *Find {
if f == nil {
f = new(Find)
}
f.skip = &skip
return f
}
// Snapshot prevents the cursor from returning a document more than once because of an intervening write operation.
func (f *Find) Snapshot(snapshot bool) *Find {
if f == nil {
f = new(Find)
}
f.snapshot = &snapshot
return f
}
// Sort specifies the order in which to return results.
func (f *Find) Sort(sort bsoncore.Document) *Find {
if f == nil {
f = new(Find)
}
f.sort = sort
return f
}
// Tailable keeps a cursor open and resumable after the last data has been retrieved.
func (f *Find) Tailable(tailable bool) *Find {
if f == nil {
f = new(Find)
}
f.tailable = &tailable
return f
}
// Session sets the session for this operation.
func (f *Find) Session(session *session.Client) *Find {
if f == nil {
f = new(Find)
}
f.session = session
return f
}
// ClusterClock sets the cluster clock for this operation.
func (f *Find) ClusterClock(clock *session.ClusterClock) *Find {
if f == nil {
f = new(Find)
}
f.clock = clock
return f
}
// Collection sets the collection that this command will run against.
func (f *Find) Collection(collection string) *Find {
if f == nil {
f = new(Find)
}
f.collection = collection
return f
}
// CommandMonitor sets the monitor to use for APM events.
func (f *Find) CommandMonitor(monitor *event.CommandMonitor) *Find {
if f == nil {
f = new(Find)
}
f.monitor = monitor
return f
}
// Crypt sets the Crypt object to use for automatic encryption and decryption.
func (f *Find) Crypt(crypt driver.Crypt) *Find {
if f == nil {
f = new(Find)
}
f.crypt = crypt
return f
}
// Database sets the database to run this operation against.
func (f *Find) Database(database string) *Find {
if f == nil {
f = new(Find)
}
f.database = database
return f
}
// Deployment sets the deployment to use for this operation.
func (f *Find) Deployment(deployment driver.Deployment) *Find {
if f == nil {
f = new(Find)
}
f.deployment = deployment
return f
}
// ReadConcern specifies the read concern for this operation.
func (f *Find) ReadConcern(readConcern *readconcern.ReadConcern) *Find {
if f == nil {
f = new(Find)
}
f.readConcern = readConcern
return f
}
// ReadPreference set the read preference used with this operation.
func (f *Find) ReadPreference(readPreference *readpref.ReadPref) *Find {
if f == nil {
f = new(Find)
}
f.readPreference = readPreference
return f
}
// ServerSelector sets the selector used to retrieve a server.
func (f *Find) ServerSelector(selector description.ServerSelector) *Find {
if f == nil {
f = new(Find)
}
f.selector = selector
return f
}
// Retry enables retryable mode for this operation. Retries are handled automatically in driver.Operation.Execute based
// on how the operation is set.
func (f *Find) Retry(retry driver.RetryMode) *Find {
if f == nil {
f = new(Find)
}
f.retry = &retry
return f
}
// ServerAPI sets the server API version for this operation.
func (f *Find) ServerAPI(serverAPI *driver.ServerAPIOptions) *Find {
if f == nil {
f = new(Find)
}
f.serverAPI = serverAPI
return f
}
// Timeout sets the timeout for this operation.
func (f *Find) Timeout(timeout *time.Duration) *Find {
if f == nil {
f = new(Find)
}
f.timeout = timeout
return f
}

View File

@@ -0,0 +1,477 @@
// Copyright (C) MongoDB, Inc. 2019-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 operation
import (
"context"
"errors"
"fmt"
"time"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/bsontype"
"go.mongodb.org/mongo-driver/event"
"go.mongodb.org/mongo-driver/mongo/description"
"go.mongodb.org/mongo-driver/mongo/writeconcern"
"go.mongodb.org/mongo-driver/x/bsonx/bsoncore"
"go.mongodb.org/mongo-driver/x/mongo/driver"
"go.mongodb.org/mongo-driver/x/mongo/driver/session"
)
// FindAndModify performs a findAndModify operation.
type FindAndModify struct {
arrayFilters bsoncore.Document
bypassDocumentValidation *bool
collation bsoncore.Document
comment bsoncore.Value
fields bsoncore.Document
maxTime *time.Duration
newDocument *bool
query bsoncore.Document
remove *bool
sort bsoncore.Document
update bsoncore.Value
upsert *bool
session *session.Client
clock *session.ClusterClock
collection string
monitor *event.CommandMonitor
database string
deployment driver.Deployment
selector description.ServerSelector
writeConcern *writeconcern.WriteConcern
retry *driver.RetryMode
crypt driver.Crypt
hint bsoncore.Value
serverAPI *driver.ServerAPIOptions
let bsoncore.Document
timeout *time.Duration
result FindAndModifyResult
}
// LastErrorObject represents information about updates and upserts returned by the server.
type LastErrorObject struct {
// True if an update modified an existing document
UpdatedExisting bool
// Object ID of the upserted document.
Upserted interface{}
}
// FindAndModifyResult represents a findAndModify result returned by the server.
type FindAndModifyResult struct {
// Either the old or modified document, depending on the value of the new parameter.
Value bsoncore.Document
// Contains information about updates and upserts.
LastErrorObject LastErrorObject
}
func buildFindAndModifyResult(response bsoncore.Document) (FindAndModifyResult, error) {
elements, err := response.Elements()
if err != nil {
return FindAndModifyResult{}, err
}
famr := FindAndModifyResult{}
for _, element := range elements {
switch element.Key() {
case "value":
var ok bool
famr.Value, ok = element.Value().DocumentOK()
// The 'value' field returned by a FindAndModify can be null in the case that no document was found.
if element.Value().Type != bsontype.Null && !ok {
return famr, fmt.Errorf("response field 'value' is type document or null, but received BSON type %s", element.Value().Type)
}
case "lastErrorObject":
valDoc, ok := element.Value().DocumentOK()
if !ok {
return famr, fmt.Errorf("response field 'lastErrorObject' is type document, but received BSON type %s", element.Value().Type)
}
var leo LastErrorObject
if err = bson.Unmarshal(valDoc, &leo); err != nil {
return famr, err
}
famr.LastErrorObject = leo
}
}
return famr, nil
}
// NewFindAndModify constructs and returns a new FindAndModify.
func NewFindAndModify(query bsoncore.Document) *FindAndModify {
return &FindAndModify{
query: query,
}
}
// Result returns the result of executing this operation.
func (fam *FindAndModify) Result() FindAndModifyResult { return fam.result }
func (fam *FindAndModify) processResponse(info driver.ResponseInfo) error {
var err error
fam.result, err = buildFindAndModifyResult(info.ServerResponse)
return err
}
// Execute runs this operations and returns an error if the operation did not execute successfully.
func (fam *FindAndModify) Execute(ctx context.Context) error {
if fam.deployment == nil {
return errors.New("the FindAndModify operation must have a Deployment set before Execute can be called")
}
return driver.Operation{
CommandFn: fam.command,
ProcessResponseFn: fam.processResponse,
RetryMode: fam.retry,
Type: driver.Write,
Client: fam.session,
Clock: fam.clock,
CommandMonitor: fam.monitor,
Database: fam.database,
Deployment: fam.deployment,
MaxTime: fam.maxTime,
Selector: fam.selector,
WriteConcern: fam.writeConcern,
Crypt: fam.crypt,
ServerAPI: fam.serverAPI,
Timeout: fam.timeout,
}.Execute(ctx)
}
func (fam *FindAndModify) command(dst []byte, desc description.SelectedServer) ([]byte, error) {
dst = bsoncore.AppendStringElement(dst, "findAndModify", fam.collection)
if fam.arrayFilters != nil {
if desc.WireVersion == nil || !desc.WireVersion.Includes(6) {
return nil, errors.New("the 'arrayFilters' command parameter requires a minimum server wire version of 6")
}
dst = bsoncore.AppendArrayElement(dst, "arrayFilters", fam.arrayFilters)
}
if fam.bypassDocumentValidation != nil {
dst = bsoncore.AppendBooleanElement(dst, "bypassDocumentValidation", *fam.bypassDocumentValidation)
}
if fam.collation != nil {
if desc.WireVersion == nil || !desc.WireVersion.Includes(5) {
return nil, errors.New("the 'collation' command parameter requires a minimum server wire version of 5")
}
dst = bsoncore.AppendDocumentElement(dst, "collation", fam.collation)
}
if fam.comment.Type != bsontype.Type(0) {
dst = bsoncore.AppendValueElement(dst, "comment", fam.comment)
}
if fam.fields != nil {
dst = bsoncore.AppendDocumentElement(dst, "fields", fam.fields)
}
if fam.newDocument != nil {
dst = bsoncore.AppendBooleanElement(dst, "new", *fam.newDocument)
}
if fam.query != nil {
dst = bsoncore.AppendDocumentElement(dst, "query", fam.query)
}
if fam.remove != nil {
dst = bsoncore.AppendBooleanElement(dst, "remove", *fam.remove)
}
if fam.sort != nil {
dst = bsoncore.AppendDocumentElement(dst, "sort", fam.sort)
}
if fam.update.Data != nil {
dst = bsoncore.AppendValueElement(dst, "update", fam.update)
}
if fam.upsert != nil {
dst = bsoncore.AppendBooleanElement(dst, "upsert", *fam.upsert)
}
if fam.hint.Type != bsontype.Type(0) {
if desc.WireVersion == nil || !desc.WireVersion.Includes(8) {
return nil, errors.New("the 'hint' command parameter requires a minimum server wire version of 8")
}
if !fam.writeConcern.Acknowledged() {
return nil, errUnacknowledgedHint
}
dst = bsoncore.AppendValueElement(dst, "hint", fam.hint)
}
if fam.let != nil {
dst = bsoncore.AppendDocumentElement(dst, "let", fam.let)
}
return dst, nil
}
// ArrayFilters specifies an array of filter documents that determines which array elements to modify for an update operation on an array field.
func (fam *FindAndModify) ArrayFilters(arrayFilters bsoncore.Document) *FindAndModify {
if fam == nil {
fam = new(FindAndModify)
}
fam.arrayFilters = arrayFilters
return fam
}
// BypassDocumentValidation specifies if document validation can be skipped when executing the operation.
func (fam *FindAndModify) BypassDocumentValidation(bypassDocumentValidation bool) *FindAndModify {
if fam == nil {
fam = new(FindAndModify)
}
fam.bypassDocumentValidation = &bypassDocumentValidation
return fam
}
// Collation specifies a collation to be used.
func (fam *FindAndModify) Collation(collation bsoncore.Document) *FindAndModify {
if fam == nil {
fam = new(FindAndModify)
}
fam.collation = collation
return fam
}
// Comment sets a value to help trace an operation.
func (fam *FindAndModify) Comment(comment bsoncore.Value) *FindAndModify {
if fam == nil {
fam = new(FindAndModify)
}
fam.comment = comment
return fam
}
// Fields specifies a subset of fields to return.
func (fam *FindAndModify) Fields(fields bsoncore.Document) *FindAndModify {
if fam == nil {
fam = new(FindAndModify)
}
fam.fields = fields
return fam
}
// MaxTime specifies the maximum amount of time to allow the operation to run on the server.
func (fam *FindAndModify) MaxTime(maxTime *time.Duration) *FindAndModify {
if fam == nil {
fam = new(FindAndModify)
}
fam.maxTime = maxTime
return fam
}
// NewDocument specifies whether to return the modified document or the original. Defaults to false (return original).
func (fam *FindAndModify) NewDocument(newDocument bool) *FindAndModify {
if fam == nil {
fam = new(FindAndModify)
}
fam.newDocument = &newDocument
return fam
}
// Query specifies the selection criteria for the modification.
func (fam *FindAndModify) Query(query bsoncore.Document) *FindAndModify {
if fam == nil {
fam = new(FindAndModify)
}
fam.query = query
return fam
}
// Remove specifies that the matched document should be removed. Defaults to false.
func (fam *FindAndModify) Remove(remove bool) *FindAndModify {
if fam == nil {
fam = new(FindAndModify)
}
fam.remove = &remove
return fam
}
// Sort determines which document the operation modifies if the query matches multiple documents.The first document matched by the sort order will be modified.
func (fam *FindAndModify) Sort(sort bsoncore.Document) *FindAndModify {
if fam == nil {
fam = new(FindAndModify)
}
fam.sort = sort
return fam
}
// Update specifies the update document to perform on the matched document.
func (fam *FindAndModify) Update(update bsoncore.Value) *FindAndModify {
if fam == nil {
fam = new(FindAndModify)
}
fam.update = update
return fam
}
// Upsert specifies whether or not to create a new document if no documents match the query when doing an update. Defaults to false.
func (fam *FindAndModify) Upsert(upsert bool) *FindAndModify {
if fam == nil {
fam = new(FindAndModify)
}
fam.upsert = &upsert
return fam
}
// Session sets the session for this operation.
func (fam *FindAndModify) Session(session *session.Client) *FindAndModify {
if fam == nil {
fam = new(FindAndModify)
}
fam.session = session
return fam
}
// ClusterClock sets the cluster clock for this operation.
func (fam *FindAndModify) ClusterClock(clock *session.ClusterClock) *FindAndModify {
if fam == nil {
fam = new(FindAndModify)
}
fam.clock = clock
return fam
}
// Collection sets the collection that this command will run against.
func (fam *FindAndModify) Collection(collection string) *FindAndModify {
if fam == nil {
fam = new(FindAndModify)
}
fam.collection = collection
return fam
}
// CommandMonitor sets the monitor to use for APM events.
func (fam *FindAndModify) CommandMonitor(monitor *event.CommandMonitor) *FindAndModify {
if fam == nil {
fam = new(FindAndModify)
}
fam.monitor = monitor
return fam
}
// Database sets the database to run this operation against.
func (fam *FindAndModify) Database(database string) *FindAndModify {
if fam == nil {
fam = new(FindAndModify)
}
fam.database = database
return fam
}
// Deployment sets the deployment to use for this operation.
func (fam *FindAndModify) Deployment(deployment driver.Deployment) *FindAndModify {
if fam == nil {
fam = new(FindAndModify)
}
fam.deployment = deployment
return fam
}
// ServerSelector sets the selector used to retrieve a server.
func (fam *FindAndModify) ServerSelector(selector description.ServerSelector) *FindAndModify {
if fam == nil {
fam = new(FindAndModify)
}
fam.selector = selector
return fam
}
// WriteConcern sets the write concern for this operation.
func (fam *FindAndModify) WriteConcern(writeConcern *writeconcern.WriteConcern) *FindAndModify {
if fam == nil {
fam = new(FindAndModify)
}
fam.writeConcern = writeConcern
return fam
}
// Retry enables retryable writes for this operation. Retries are not handled automatically,
// instead a boolean is returned from Execute and SelectAndExecute that indicates if the
// operation can be retried. Retrying is handled by calling RetryExecute.
func (fam *FindAndModify) Retry(retry driver.RetryMode) *FindAndModify {
if fam == nil {
fam = new(FindAndModify)
}
fam.retry = &retry
return fam
}
// Crypt sets the Crypt object to use for automatic encryption and decryption.
func (fam *FindAndModify) Crypt(crypt driver.Crypt) *FindAndModify {
if fam == nil {
fam = new(FindAndModify)
}
fam.crypt = crypt
return fam
}
// Hint specifies the index to use.
func (fam *FindAndModify) Hint(hint bsoncore.Value) *FindAndModify {
if fam == nil {
fam = new(FindAndModify)
}
fam.hint = hint
return fam
}
// ServerAPI sets the server API version for this operation.
func (fam *FindAndModify) ServerAPI(serverAPI *driver.ServerAPIOptions) *FindAndModify {
if fam == nil {
fam = new(FindAndModify)
}
fam.serverAPI = serverAPI
return fam
}
// Let specifies the let document to use. This option is only valid for server versions 5.0 and above.
func (fam *FindAndModify) Let(let bsoncore.Document) *FindAndModify {
if fam == nil {
fam = new(FindAndModify)
}
fam.let = let
return fam
}
// Timeout sets the timeout for this operation.
func (fam *FindAndModify) Timeout(timeout *time.Duration) *FindAndModify {
if fam == nil {
fam = new(FindAndModify)
}
fam.timeout = timeout
return fam
}

View File

@@ -0,0 +1,258 @@
// Copyright (C) MongoDB, Inc. 2021-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 operation
import (
"context"
"errors"
"runtime"
"strconv"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/internal"
"go.mongodb.org/mongo-driver/mongo/address"
"go.mongodb.org/mongo-driver/mongo/description"
"go.mongodb.org/mongo-driver/version"
"go.mongodb.org/mongo-driver/x/bsonx/bsoncore"
"go.mongodb.org/mongo-driver/x/mongo/driver"
"go.mongodb.org/mongo-driver/x/mongo/driver/session"
)
// Hello is used to run the handshake operation.
type Hello struct {
appname string
compressors []string
saslSupportedMechs string
d driver.Deployment
clock *session.ClusterClock
speculativeAuth bsoncore.Document
topologyVersion *description.TopologyVersion
maxAwaitTimeMS *int64
serverAPI *driver.ServerAPIOptions
loadBalanced bool
res bsoncore.Document
}
var _ driver.Handshaker = (*Hello)(nil)
// NewHello constructs a Hello.
func NewHello() *Hello { return &Hello{} }
// AppName sets the application name in the client metadata sent in this operation.
func (h *Hello) AppName(appname string) *Hello {
h.appname = appname
return h
}
// ClusterClock sets the cluster clock for this operation.
func (h *Hello) ClusterClock(clock *session.ClusterClock) *Hello {
if h == nil {
h = new(Hello)
}
h.clock = clock
return h
}
// Compressors sets the compressors that can be used.
func (h *Hello) Compressors(compressors []string) *Hello {
h.compressors = compressors
return h
}
// SASLSupportedMechs retrieves the supported SASL mechanism for the given user when this operation
// is run.
func (h *Hello) SASLSupportedMechs(username string) *Hello {
h.saslSupportedMechs = username
return h
}
// Deployment sets the Deployment for this operation.
func (h *Hello) Deployment(d driver.Deployment) *Hello {
h.d = d
return h
}
// SpeculativeAuthenticate sets the document to be used for speculative authentication.
func (h *Hello) SpeculativeAuthenticate(doc bsoncore.Document) *Hello {
h.speculativeAuth = doc
return h
}
// TopologyVersion sets the TopologyVersion to be used for heartbeats.
func (h *Hello) TopologyVersion(tv *description.TopologyVersion) *Hello {
h.topologyVersion = tv
return h
}
// MaxAwaitTimeMS sets the maximum time for the server to wait for topology changes during a heartbeat.
func (h *Hello) MaxAwaitTimeMS(awaitTime int64) *Hello {
h.maxAwaitTimeMS = &awaitTime
return h
}
// ServerAPI sets the server API version for this operation.
func (h *Hello) ServerAPI(serverAPI *driver.ServerAPIOptions) *Hello {
h.serverAPI = serverAPI
return h
}
// LoadBalanced specifies whether or not this operation is being sent over a connection to a load balanced cluster.
func (h *Hello) LoadBalanced(lb bool) *Hello {
h.loadBalanced = lb
return h
}
// Result returns the result of executing this operation.
func (h *Hello) Result(addr address.Address) description.Server {
return description.NewServer(addr, bson.Raw(h.res))
}
// handshakeCommand appends all necessary command fields as well as client metadata, SASL supported mechs, and compression.
func (h *Hello) handshakeCommand(dst []byte, desc description.SelectedServer) ([]byte, error) {
dst, err := h.command(dst, desc)
if err != nil {
return dst, err
}
if h.saslSupportedMechs != "" {
dst = bsoncore.AppendStringElement(dst, "saslSupportedMechs", h.saslSupportedMechs)
}
if h.speculativeAuth != nil {
dst = bsoncore.AppendDocumentElement(dst, "speculativeAuthenticate", h.speculativeAuth)
}
var idx int32
idx, dst = bsoncore.AppendArrayElementStart(dst, "compression")
for i, compressor := range h.compressors {
dst = bsoncore.AppendStringElement(dst, strconv.Itoa(i), compressor)
}
dst, _ = bsoncore.AppendArrayEnd(dst, idx)
// append client metadata
idx, dst = bsoncore.AppendDocumentElementStart(dst, "client")
didx, dst := bsoncore.AppendDocumentElementStart(dst, "driver")
dst = bsoncore.AppendStringElement(dst, "name", "mongo-go-driver")
dst = bsoncore.AppendStringElement(dst, "version", version.Driver)
dst, _ = bsoncore.AppendDocumentEnd(dst, didx)
didx, dst = bsoncore.AppendDocumentElementStart(dst, "os")
dst = bsoncore.AppendStringElement(dst, "type", runtime.GOOS)
dst = bsoncore.AppendStringElement(dst, "architecture", runtime.GOARCH)
dst, _ = bsoncore.AppendDocumentEnd(dst, didx)
dst = bsoncore.AppendStringElement(dst, "platform", runtime.Version())
if h.appname != "" {
didx, dst = bsoncore.AppendDocumentElementStart(dst, "application")
dst = bsoncore.AppendStringElement(dst, "name", h.appname)
dst, _ = bsoncore.AppendDocumentEnd(dst, didx)
}
dst, _ = bsoncore.AppendDocumentEnd(dst, idx)
return dst, nil
}
// command appends all necessary command fields.
func (h *Hello) command(dst []byte, desc description.SelectedServer) ([]byte, error) {
// Use "hello" if topology is LoadBalanced, API version is declared or server
// has responded with "helloOk". Otherwise, use legacy hello.
if desc.Kind == description.LoadBalanced || h.serverAPI != nil || desc.Server.HelloOK {
dst = bsoncore.AppendInt32Element(dst, "hello", 1)
} else {
dst = bsoncore.AppendInt32Element(dst, internal.LegacyHello, 1)
}
dst = bsoncore.AppendBooleanElement(dst, "helloOk", true)
if tv := h.topologyVersion; tv != nil {
var tvIdx int32
tvIdx, dst = bsoncore.AppendDocumentElementStart(dst, "topologyVersion")
dst = bsoncore.AppendObjectIDElement(dst, "processId", tv.ProcessID)
dst = bsoncore.AppendInt64Element(dst, "counter", tv.Counter)
dst, _ = bsoncore.AppendDocumentEnd(dst, tvIdx)
}
if h.maxAwaitTimeMS != nil {
dst = bsoncore.AppendInt64Element(dst, "maxAwaitTimeMS", *h.maxAwaitTimeMS)
}
if h.loadBalanced {
// The loadBalanced parameter should only be added if it's true. We should never explicitly send
// loadBalanced=false per the load balancing spec.
dst = bsoncore.AppendBooleanElement(dst, "loadBalanced", true)
}
return dst, nil
}
// Execute runs this operation.
func (h *Hello) Execute(ctx context.Context) error {
if h.d == nil {
return errors.New("a Hello must have a Deployment set before Execute can be called")
}
return h.createOperation().Execute(ctx)
}
// StreamResponse gets the next streaming Hello response from the server.
func (h *Hello) StreamResponse(ctx context.Context, conn driver.StreamerConnection) error {
return h.createOperation().ExecuteExhaust(ctx, conn)
}
func (h *Hello) createOperation() driver.Operation {
return driver.Operation{
Clock: h.clock,
CommandFn: h.command,
Database: "admin",
Deployment: h.d,
ProcessResponseFn: func(info driver.ResponseInfo) error {
h.res = info.ServerResponse
return nil
},
ServerAPI: h.serverAPI,
}
}
// GetHandshakeInformation performs the MongoDB handshake for the provided connection and returns the relevant
// information about the server. This function implements the driver.Handshaker interface.
func (h *Hello) GetHandshakeInformation(ctx context.Context, _ address.Address, c driver.Connection) (driver.HandshakeInformation, error) {
err := driver.Operation{
Clock: h.clock,
CommandFn: h.handshakeCommand,
Deployment: driver.SingleConnectionDeployment{c},
Database: "admin",
ProcessResponseFn: func(info driver.ResponseInfo) error {
h.res = info.ServerResponse
return nil
},
ServerAPI: h.serverAPI,
}.Execute(ctx)
if err != nil {
return driver.HandshakeInformation{}, err
}
info := driver.HandshakeInformation{
Description: h.Result(c.Address()),
}
if speculativeAuthenticate, ok := h.res.Lookup("speculativeAuthenticate").DocumentOK(); ok {
info.SpeculativeAuthenticate = speculativeAuthenticate
}
if serverConnectionID, ok := h.res.Lookup("connectionId").Int32OK(); ok {
info.ServerConnectionID = &serverConnectionID
}
// Cast to bson.Raw to lookup saslSupportedMechs to avoid converting from bsoncore.Value to bson.RawValue for the
// StringSliceFromRawValue call.
if saslSupportedMechs, lookupErr := bson.Raw(h.res).LookupErr("saslSupportedMechs"); lookupErr == nil {
info.SaslSupportedMechs, err = internal.StringSliceFromRawValue("saslSupportedMechs", saslSupportedMechs)
}
return info, err
}
// FinishHandshake implements the Handshaker interface. This is a no-op function because a non-authenticated connection
// does not do anything besides the initial Hello for a handshake.
func (h *Hello) FinishHandshake(context.Context, driver.Connection) error {
return nil
}

View File

@@ -0,0 +1,293 @@
// Copyright (C) MongoDB, Inc. 2019-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 operation
import (
"context"
"errors"
"fmt"
"time"
"go.mongodb.org/mongo-driver/bson/bsontype"
"go.mongodb.org/mongo-driver/event"
"go.mongodb.org/mongo-driver/mongo/description"
"go.mongodb.org/mongo-driver/mongo/writeconcern"
"go.mongodb.org/mongo-driver/x/bsonx/bsoncore"
"go.mongodb.org/mongo-driver/x/mongo/driver"
"go.mongodb.org/mongo-driver/x/mongo/driver/session"
)
// Insert performs an insert operation.
type Insert struct {
bypassDocumentValidation *bool
comment bsoncore.Value
documents []bsoncore.Document
ordered *bool
session *session.Client
clock *session.ClusterClock
collection string
monitor *event.CommandMonitor
crypt driver.Crypt
database string
deployment driver.Deployment
selector description.ServerSelector
writeConcern *writeconcern.WriteConcern
retry *driver.RetryMode
result InsertResult
serverAPI *driver.ServerAPIOptions
timeout *time.Duration
}
// InsertResult represents an insert result returned by the server.
type InsertResult struct {
// Number of documents successfully inserted.
N int64
}
func buildInsertResult(response bsoncore.Document) (InsertResult, error) {
elements, err := response.Elements()
if err != nil {
return InsertResult{}, err
}
ir := InsertResult{}
for _, element := range elements {
switch element.Key() {
case "n":
var ok bool
ir.N, ok = element.Value().AsInt64OK()
if !ok {
return ir, fmt.Errorf("response field 'n' is type int32 or int64, but received BSON type %s", element.Value().Type)
}
}
}
return ir, nil
}
// NewInsert constructs and returns a new Insert.
func NewInsert(documents ...bsoncore.Document) *Insert {
return &Insert{
documents: documents,
}
}
// Result returns the result of executing this operation.
func (i *Insert) Result() InsertResult { return i.result }
func (i *Insert) processResponse(info driver.ResponseInfo) error {
ir, err := buildInsertResult(info.ServerResponse)
i.result.N += ir.N
return err
}
// Execute runs this operations and returns an error if the operation did not execute successfully.
func (i *Insert) Execute(ctx context.Context) error {
if i.deployment == nil {
return errors.New("the Insert operation must have a Deployment set before Execute can be called")
}
batches := &driver.Batches{
Identifier: "documents",
Documents: i.documents,
Ordered: i.ordered,
}
return driver.Operation{
CommandFn: i.command,
ProcessResponseFn: i.processResponse,
Batches: batches,
RetryMode: i.retry,
Type: driver.Write,
Client: i.session,
Clock: i.clock,
CommandMonitor: i.monitor,
Crypt: i.crypt,
Database: i.database,
Deployment: i.deployment,
Selector: i.selector,
WriteConcern: i.writeConcern,
ServerAPI: i.serverAPI,
Timeout: i.timeout,
}.Execute(ctx)
}
func (i *Insert) command(dst []byte, desc description.SelectedServer) ([]byte, error) {
dst = bsoncore.AppendStringElement(dst, "insert", i.collection)
if i.bypassDocumentValidation != nil && (desc.WireVersion != nil && desc.WireVersion.Includes(4)) {
dst = bsoncore.AppendBooleanElement(dst, "bypassDocumentValidation", *i.bypassDocumentValidation)
}
if i.comment.Type != bsontype.Type(0) {
dst = bsoncore.AppendValueElement(dst, "comment", i.comment)
}
if i.ordered != nil {
dst = bsoncore.AppendBooleanElement(dst, "ordered", *i.ordered)
}
return dst, nil
}
// BypassDocumentValidation allows the operation to opt-out of document level validation. Valid
// for server versions >= 3.2. For servers < 3.2, this setting is ignored.
func (i *Insert) BypassDocumentValidation(bypassDocumentValidation bool) *Insert {
if i == nil {
i = new(Insert)
}
i.bypassDocumentValidation = &bypassDocumentValidation
return i
}
// Comment sets a value to help trace an operation.
func (i *Insert) Comment(comment bsoncore.Value) *Insert {
if i == nil {
i = new(Insert)
}
i.comment = comment
return i
}
// Documents adds documents to this operation that will be inserted when this operation is
// executed.
func (i *Insert) Documents(documents ...bsoncore.Document) *Insert {
if i == nil {
i = new(Insert)
}
i.documents = documents
return i
}
// Ordered sets ordered. If true, when a write fails, the operation will return the error, when
// false write failures do not stop execution of the operation.
func (i *Insert) Ordered(ordered bool) *Insert {
if i == nil {
i = new(Insert)
}
i.ordered = &ordered
return i
}
// Session sets the session for this operation.
func (i *Insert) Session(session *session.Client) *Insert {
if i == nil {
i = new(Insert)
}
i.session = session
return i
}
// ClusterClock sets the cluster clock for this operation.
func (i *Insert) ClusterClock(clock *session.ClusterClock) *Insert {
if i == nil {
i = new(Insert)
}
i.clock = clock
return i
}
// Collection sets the collection that this command will run against.
func (i *Insert) Collection(collection string) *Insert {
if i == nil {
i = new(Insert)
}
i.collection = collection
return i
}
// CommandMonitor sets the monitor to use for APM events.
func (i *Insert) CommandMonitor(monitor *event.CommandMonitor) *Insert {
if i == nil {
i = new(Insert)
}
i.monitor = monitor
return i
}
// Crypt sets the Crypt object to use for automatic encryption and decryption.
func (i *Insert) Crypt(crypt driver.Crypt) *Insert {
if i == nil {
i = new(Insert)
}
i.crypt = crypt
return i
}
// Database sets the database to run this operation against.
func (i *Insert) Database(database string) *Insert {
if i == nil {
i = new(Insert)
}
i.database = database
return i
}
// Deployment sets the deployment to use for this operation.
func (i *Insert) Deployment(deployment driver.Deployment) *Insert {
if i == nil {
i = new(Insert)
}
i.deployment = deployment
return i
}
// ServerSelector sets the selector used to retrieve a server.
func (i *Insert) ServerSelector(selector description.ServerSelector) *Insert {
if i == nil {
i = new(Insert)
}
i.selector = selector
return i
}
// WriteConcern sets the write concern for this operation.
func (i *Insert) WriteConcern(writeConcern *writeconcern.WriteConcern) *Insert {
if i == nil {
i = new(Insert)
}
i.writeConcern = writeConcern
return i
}
// Retry enables retryable mode for this operation. Retries are handled automatically in driver.Operation.Execute based
// on how the operation is set.
func (i *Insert) Retry(retry driver.RetryMode) *Insert {
if i == nil {
i = new(Insert)
}
i.retry = &retry
return i
}
// ServerAPI sets the server API version for this operation.
func (i *Insert) ServerAPI(serverAPI *driver.ServerAPIOptions) *Insert {
if i == nil {
i = new(Insert)
}
i.serverAPI = serverAPI
return i
}
// Timeout sets the timeout for this operation.
func (i *Insert) Timeout(timeout *time.Duration) *Insert {
if i == nil {
i = new(Insert)
}
i.timeout = timeout
return i
}

View File

@@ -0,0 +1,327 @@
// Copyright (C) MongoDB, Inc. 2019-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 operation
import (
"context"
"errors"
"fmt"
"time"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/event"
"go.mongodb.org/mongo-driver/mongo/description"
"go.mongodb.org/mongo-driver/mongo/readpref"
"go.mongodb.org/mongo-driver/x/bsonx/bsoncore"
"go.mongodb.org/mongo-driver/x/mongo/driver"
"go.mongodb.org/mongo-driver/x/mongo/driver/session"
)
// ListDatabases performs a listDatabases operation.
type ListDatabases struct {
filter bsoncore.Document
authorizedDatabases *bool
nameOnly *bool
session *session.Client
clock *session.ClusterClock
monitor *event.CommandMonitor
database string
deployment driver.Deployment
readPreference *readpref.ReadPref
retry *driver.RetryMode
selector description.ServerSelector
crypt driver.Crypt
serverAPI *driver.ServerAPIOptions
timeout *time.Duration
result ListDatabasesResult
}
// ListDatabasesResult represents a listDatabases result returned by the server.
type ListDatabasesResult struct {
// An array of documents, one document for each database
Databases []databaseRecord
// The sum of the size of all the database files on disk in bytes.
TotalSize int64
}
type databaseRecord struct {
Name string
SizeOnDisk int64 `bson:"sizeOnDisk"`
Empty bool
}
func buildListDatabasesResult(response bsoncore.Document) (ListDatabasesResult, error) {
elements, err := response.Elements()
if err != nil {
return ListDatabasesResult{}, err
}
ir := ListDatabasesResult{}
for _, element := range elements {
switch element.Key() {
case "totalSize":
var ok bool
ir.TotalSize, ok = element.Value().AsInt64OK()
if !ok {
return ir, fmt.Errorf("response field 'totalSize' is type int64, but received BSON type %s: %s", element.Value().Type, element.Value())
}
case "databases":
arr, ok := element.Value().ArrayOK()
if !ok {
return ir, fmt.Errorf("response field 'databases' is type array, but received BSON type %s", element.Value().Type)
}
var tmp bsoncore.Document
err := bson.Unmarshal(arr, &tmp)
if err != nil {
return ir, err
}
records, err := tmp.Elements()
if err != nil {
return ir, err
}
ir.Databases = make([]databaseRecord, len(records))
for i, val := range records {
valueDoc, ok := val.Value().DocumentOK()
if !ok {
return ir, fmt.Errorf("'databases' element is type document, but received BSON type %s", val.Value().Type)
}
elems, err := valueDoc.Elements()
if err != nil {
return ir, err
}
for _, elem := range elems {
switch elem.Key() {
case "name":
ir.Databases[i].Name, ok = elem.Value().StringValueOK()
if !ok {
return ir, fmt.Errorf("response field 'name' is type string, but received BSON type %s", elem.Value().Type)
}
case "sizeOnDisk":
ir.Databases[i].SizeOnDisk, ok = elem.Value().AsInt64OK()
if !ok {
return ir, fmt.Errorf("response field 'sizeOnDisk' is type int64, but received BSON type %s", elem.Value().Type)
}
case "empty":
ir.Databases[i].Empty, ok = elem.Value().BooleanOK()
if !ok {
return ir, fmt.Errorf("response field 'empty' is type bool, but received BSON type %s", elem.Value().Type)
}
}
}
}
}
}
return ir, nil
}
// NewListDatabases constructs and returns a new ListDatabases.
func NewListDatabases(filter bsoncore.Document) *ListDatabases {
return &ListDatabases{
filter: filter,
}
}
// Result returns the result of executing this operation.
func (ld *ListDatabases) Result() ListDatabasesResult { return ld.result }
func (ld *ListDatabases) processResponse(info driver.ResponseInfo) error {
var err error
ld.result, err = buildListDatabasesResult(info.ServerResponse)
return err
}
// Execute runs this operations and returns an error if the operation did not execute successfully.
func (ld *ListDatabases) Execute(ctx context.Context) error {
if ld.deployment == nil {
return errors.New("the ListDatabases operation must have a Deployment set before Execute can be called")
}
return driver.Operation{
CommandFn: ld.command,
ProcessResponseFn: ld.processResponse,
Client: ld.session,
Clock: ld.clock,
CommandMonitor: ld.monitor,
Database: ld.database,
Deployment: ld.deployment,
ReadPreference: ld.readPreference,
RetryMode: ld.retry,
Type: driver.Read,
Selector: ld.selector,
Crypt: ld.crypt,
ServerAPI: ld.serverAPI,
Timeout: ld.timeout,
}.Execute(ctx)
}
func (ld *ListDatabases) command(dst []byte, desc description.SelectedServer) ([]byte, error) {
dst = bsoncore.AppendInt32Element(dst, "listDatabases", 1)
if ld.filter != nil {
dst = bsoncore.AppendDocumentElement(dst, "filter", ld.filter)
}
if ld.nameOnly != nil {
dst = bsoncore.AppendBooleanElement(dst, "nameOnly", *ld.nameOnly)
}
if ld.authorizedDatabases != nil {
dst = bsoncore.AppendBooleanElement(dst, "authorizedDatabases", *ld.authorizedDatabases)
}
return dst, nil
}
// Filter determines what results are returned from listDatabases.
func (ld *ListDatabases) Filter(filter bsoncore.Document) *ListDatabases {
if ld == nil {
ld = new(ListDatabases)
}
ld.filter = filter
return ld
}
// NameOnly specifies whether to only return database names.
func (ld *ListDatabases) NameOnly(nameOnly bool) *ListDatabases {
if ld == nil {
ld = new(ListDatabases)
}
ld.nameOnly = &nameOnly
return ld
}
// AuthorizedDatabases specifies whether to only return databases which the user is authorized to use."
func (ld *ListDatabases) AuthorizedDatabases(authorizedDatabases bool) *ListDatabases {
if ld == nil {
ld = new(ListDatabases)
}
ld.authorizedDatabases = &authorizedDatabases
return ld
}
// Session sets the session for this operation.
func (ld *ListDatabases) Session(session *session.Client) *ListDatabases {
if ld == nil {
ld = new(ListDatabases)
}
ld.session = session
return ld
}
// ClusterClock sets the cluster clock for this operation.
func (ld *ListDatabases) ClusterClock(clock *session.ClusterClock) *ListDatabases {
if ld == nil {
ld = new(ListDatabases)
}
ld.clock = clock
return ld
}
// CommandMonitor sets the monitor to use for APM events.
func (ld *ListDatabases) CommandMonitor(monitor *event.CommandMonitor) *ListDatabases {
if ld == nil {
ld = new(ListDatabases)
}
ld.monitor = monitor
return ld
}
// Database sets the database to run this operation against.
func (ld *ListDatabases) Database(database string) *ListDatabases {
if ld == nil {
ld = new(ListDatabases)
}
ld.database = database
return ld
}
// Deployment sets the deployment to use for this operation.
func (ld *ListDatabases) Deployment(deployment driver.Deployment) *ListDatabases {
if ld == nil {
ld = new(ListDatabases)
}
ld.deployment = deployment
return ld
}
// ReadPreference set the read preference used with this operation.
func (ld *ListDatabases) ReadPreference(readPreference *readpref.ReadPref) *ListDatabases {
if ld == nil {
ld = new(ListDatabases)
}
ld.readPreference = readPreference
return ld
}
// ServerSelector sets the selector used to retrieve a server.
func (ld *ListDatabases) ServerSelector(selector description.ServerSelector) *ListDatabases {
if ld == nil {
ld = new(ListDatabases)
}
ld.selector = selector
return ld
}
// Retry enables retryable mode for this operation. Retries are handled automatically in driver.Operation.Execute based
// on how the operation is set.
func (ld *ListDatabases) Retry(retry driver.RetryMode) *ListDatabases {
if ld == nil {
ld = new(ListDatabases)
}
ld.retry = &retry
return ld
}
// Crypt sets the Crypt object to use for automatic encryption and decryption.
func (ld *ListDatabases) Crypt(crypt driver.Crypt) *ListDatabases {
if ld == nil {
ld = new(ListDatabases)
}
ld.crypt = crypt
return ld
}
// ServerAPI sets the server API version for this operation.
func (ld *ListDatabases) ServerAPI(serverAPI *driver.ServerAPIOptions) *ListDatabases {
if ld == nil {
ld = new(ListDatabases)
}
ld.serverAPI = serverAPI
return ld
}
// Timeout sets the timeout for this operation.
func (ld *ListDatabases) Timeout(timeout *time.Duration) *ListDatabases {
if ld == nil {
ld = new(ListDatabases)
}
ld.timeout = timeout
return ld
}

View File

@@ -0,0 +1,266 @@
// Copyright (C) MongoDB, Inc. 2019-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 operation
import (
"context"
"errors"
"time"
"go.mongodb.org/mongo-driver/event"
"go.mongodb.org/mongo-driver/mongo/description"
"go.mongodb.org/mongo-driver/mongo/readpref"
"go.mongodb.org/mongo-driver/x/bsonx/bsoncore"
"go.mongodb.org/mongo-driver/x/mongo/driver"
"go.mongodb.org/mongo-driver/x/mongo/driver/session"
)
// ListCollections performs a listCollections operation.
type ListCollections struct {
filter bsoncore.Document
nameOnly *bool
authorizedCollections *bool
session *session.Client
clock *session.ClusterClock
monitor *event.CommandMonitor
crypt driver.Crypt
database string
deployment driver.Deployment
readPreference *readpref.ReadPref
selector description.ServerSelector
retry *driver.RetryMode
result driver.CursorResponse
batchSize *int32
serverAPI *driver.ServerAPIOptions
timeout *time.Duration
}
// NewListCollections constructs and returns a new ListCollections.
func NewListCollections(filter bsoncore.Document) *ListCollections {
return &ListCollections{
filter: filter,
}
}
// Result returns the result of executing this operation.
func (lc *ListCollections) Result(opts driver.CursorOptions) (*driver.ListCollectionsBatchCursor, error) {
opts.ServerAPI = lc.serverAPI
bc, err := driver.NewBatchCursor(lc.result, lc.session, lc.clock, opts)
if err != nil {
return nil, err
}
desc := lc.result.Desc
if desc.WireVersion == nil || desc.WireVersion.Max < 3 {
return driver.NewLegacyListCollectionsBatchCursor(bc)
}
return driver.NewListCollectionsBatchCursor(bc)
}
func (lc *ListCollections) processResponse(info driver.ResponseInfo) error {
var err error
lc.result, err = driver.NewCursorResponse(info)
return err
}
// Execute runs this operations and returns an error if the operation did not execute successfully.
func (lc *ListCollections) Execute(ctx context.Context) error {
if lc.deployment == nil {
return errors.New("the ListCollections operation must have a Deployment set before Execute can be called")
}
return driver.Operation{
CommandFn: lc.command,
ProcessResponseFn: lc.processResponse,
RetryMode: lc.retry,
Type: driver.Read,
Client: lc.session,
Clock: lc.clock,
CommandMonitor: lc.monitor,
Crypt: lc.crypt,
Database: lc.database,
Deployment: lc.deployment,
ReadPreference: lc.readPreference,
Selector: lc.selector,
Legacy: driver.LegacyListCollections,
ServerAPI: lc.serverAPI,
Timeout: lc.timeout,
}.Execute(ctx)
}
func (lc *ListCollections) command(dst []byte, desc description.SelectedServer) ([]byte, error) {
dst = bsoncore.AppendInt32Element(dst, "listCollections", 1)
if lc.filter != nil {
dst = bsoncore.AppendDocumentElement(dst, "filter", lc.filter)
}
if lc.nameOnly != nil {
dst = bsoncore.AppendBooleanElement(dst, "nameOnly", *lc.nameOnly)
}
if lc.authorizedCollections != nil {
dst = bsoncore.AppendBooleanElement(dst, "authorizedCollections", *lc.authorizedCollections)
}
cursorDoc := bsoncore.NewDocumentBuilder()
if lc.batchSize != nil {
cursorDoc.AppendInt32("batchSize", *lc.batchSize)
}
dst = bsoncore.AppendDocumentElement(dst, "cursor", cursorDoc.Build())
return dst, nil
}
// Filter determines what results are returned from listCollections.
func (lc *ListCollections) Filter(filter bsoncore.Document) *ListCollections {
if lc == nil {
lc = new(ListCollections)
}
lc.filter = filter
return lc
}
// NameOnly specifies whether to only return collection names.
func (lc *ListCollections) NameOnly(nameOnly bool) *ListCollections {
if lc == nil {
lc = new(ListCollections)
}
lc.nameOnly = &nameOnly
return lc
}
// AuthorizedCollections specifies whether to only return collections the user
// is authorized to use.
func (lc *ListCollections) AuthorizedCollections(authorizedCollections bool) *ListCollections {
if lc == nil {
lc = new(ListCollections)
}
lc.authorizedCollections = &authorizedCollections
return lc
}
// Session sets the session for this operation.
func (lc *ListCollections) Session(session *session.Client) *ListCollections {
if lc == nil {
lc = new(ListCollections)
}
lc.session = session
return lc
}
// ClusterClock sets the cluster clock for this operation.
func (lc *ListCollections) ClusterClock(clock *session.ClusterClock) *ListCollections {
if lc == nil {
lc = new(ListCollections)
}
lc.clock = clock
return lc
}
// CommandMonitor sets the monitor to use for APM events.
func (lc *ListCollections) CommandMonitor(monitor *event.CommandMonitor) *ListCollections {
if lc == nil {
lc = new(ListCollections)
}
lc.monitor = monitor
return lc
}
// Crypt sets the Crypt object to use for automatic encryption and decryption.
func (lc *ListCollections) Crypt(crypt driver.Crypt) *ListCollections {
if lc == nil {
lc = new(ListCollections)
}
lc.crypt = crypt
return lc
}
// Database sets the database to run this operation against.
func (lc *ListCollections) Database(database string) *ListCollections {
if lc == nil {
lc = new(ListCollections)
}
lc.database = database
return lc
}
// Deployment sets the deployment to use for this operation.
func (lc *ListCollections) Deployment(deployment driver.Deployment) *ListCollections {
if lc == nil {
lc = new(ListCollections)
}
lc.deployment = deployment
return lc
}
// ReadPreference set the read preference used with this operation.
func (lc *ListCollections) ReadPreference(readPreference *readpref.ReadPref) *ListCollections {
if lc == nil {
lc = new(ListCollections)
}
lc.readPreference = readPreference
return lc
}
// ServerSelector sets the selector used to retrieve a server.
func (lc *ListCollections) ServerSelector(selector description.ServerSelector) *ListCollections {
if lc == nil {
lc = new(ListCollections)
}
lc.selector = selector
return lc
}
// Retry enables retryable mode for this operation. Retries are handled automatically in driver.Operation.Execute based
// on how the operation is set.
func (lc *ListCollections) Retry(retry driver.RetryMode) *ListCollections {
if lc == nil {
lc = new(ListCollections)
}
lc.retry = &retry
return lc
}
// BatchSize specifies the number of documents to return in every batch.
func (lc *ListCollections) BatchSize(batchSize int32) *ListCollections {
if lc == nil {
lc = new(ListCollections)
}
lc.batchSize = &batchSize
return lc
}
// ServerAPI sets the server API version for this operation.
func (lc *ListCollections) ServerAPI(serverAPI *driver.ServerAPIOptions) *ListCollections {
if lc == nil {
lc = new(ListCollections)
}
lc.serverAPI = serverAPI
return lc
}
// Timeout sets the timeout for this operation.
func (lc *ListCollections) Timeout(timeout *time.Duration) *ListCollections {
if lc == nil {
lc = new(ListCollections)
}
lc.timeout = timeout
return lc
}

View File

@@ -0,0 +1,233 @@
// Copyright (C) MongoDB, Inc. 2019-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 operation
import (
"context"
"errors"
"time"
"go.mongodb.org/mongo-driver/event"
"go.mongodb.org/mongo-driver/mongo/description"
"go.mongodb.org/mongo-driver/x/bsonx/bsoncore"
"go.mongodb.org/mongo-driver/x/mongo/driver"
"go.mongodb.org/mongo-driver/x/mongo/driver/session"
)
// ListIndexes performs a listIndexes operation.
type ListIndexes struct {
batchSize *int32
maxTime *time.Duration
session *session.Client
clock *session.ClusterClock
collection string
monitor *event.CommandMonitor
database string
deployment driver.Deployment
selector description.ServerSelector
retry *driver.RetryMode
crypt driver.Crypt
serverAPI *driver.ServerAPIOptions
timeout *time.Duration
result driver.CursorResponse
}
// NewListIndexes constructs and returns a new ListIndexes.
func NewListIndexes() *ListIndexes {
return &ListIndexes{}
}
// Result returns the result of executing this operation.
func (li *ListIndexes) Result(opts driver.CursorOptions) (*driver.BatchCursor, error) {
clientSession := li.session
clock := li.clock
opts.ServerAPI = li.serverAPI
return driver.NewBatchCursor(li.result, clientSession, clock, opts)
}
func (li *ListIndexes) processResponse(info driver.ResponseInfo) error {
var err error
li.result, err = driver.NewCursorResponse(info)
return err
}
// Execute runs this operations and returns an error if the operation did not execute successfully.
func (li *ListIndexes) Execute(ctx context.Context) error {
if li.deployment == nil {
return errors.New("the ListIndexes operation must have a Deployment set before Execute can be called")
}
return driver.Operation{
CommandFn: li.command,
ProcessResponseFn: li.processResponse,
Client: li.session,
Clock: li.clock,
CommandMonitor: li.monitor,
Database: li.database,
Deployment: li.deployment,
MaxTime: li.maxTime,
Selector: li.selector,
Crypt: li.crypt,
Legacy: driver.LegacyListIndexes,
RetryMode: li.retry,
Type: driver.Read,
ServerAPI: li.serverAPI,
Timeout: li.timeout,
}.Execute(ctx)
}
func (li *ListIndexes) command(dst []byte, desc description.SelectedServer) ([]byte, error) {
dst = bsoncore.AppendStringElement(dst, "listIndexes", li.collection)
cursorIdx, cursorDoc := bsoncore.AppendDocumentStart(nil)
if li.batchSize != nil {
cursorDoc = bsoncore.AppendInt32Element(cursorDoc, "batchSize", *li.batchSize)
}
cursorDoc, _ = bsoncore.AppendDocumentEnd(cursorDoc, cursorIdx)
dst = bsoncore.AppendDocumentElement(dst, "cursor", cursorDoc)
return dst, nil
}
// BatchSize specifies the number of documents to return in every batch.
func (li *ListIndexes) BatchSize(batchSize int32) *ListIndexes {
if li == nil {
li = new(ListIndexes)
}
li.batchSize = &batchSize
return li
}
// MaxTime specifies the maximum amount of time to allow the query to run on the server.
func (li *ListIndexes) MaxTime(maxTime *time.Duration) *ListIndexes {
if li == nil {
li = new(ListIndexes)
}
li.maxTime = maxTime
return li
}
// Session sets the session for this operation.
func (li *ListIndexes) Session(session *session.Client) *ListIndexes {
if li == nil {
li = new(ListIndexes)
}
li.session = session
return li
}
// ClusterClock sets the cluster clock for this operation.
func (li *ListIndexes) ClusterClock(clock *session.ClusterClock) *ListIndexes {
if li == nil {
li = new(ListIndexes)
}
li.clock = clock
return li
}
// Collection sets the collection that this command will run against.
func (li *ListIndexes) Collection(collection string) *ListIndexes {
if li == nil {
li = new(ListIndexes)
}
li.collection = collection
return li
}
// CommandMonitor sets the monitor to use for APM events.
func (li *ListIndexes) CommandMonitor(monitor *event.CommandMonitor) *ListIndexes {
if li == nil {
li = new(ListIndexes)
}
li.monitor = monitor
return li
}
// Database sets the database to run this operation against.
func (li *ListIndexes) Database(database string) *ListIndexes {
if li == nil {
li = new(ListIndexes)
}
li.database = database
return li
}
// Deployment sets the deployment to use for this operation.
func (li *ListIndexes) Deployment(deployment driver.Deployment) *ListIndexes {
if li == nil {
li = new(ListIndexes)
}
li.deployment = deployment
return li
}
// ServerSelector sets the selector used to retrieve a server.
func (li *ListIndexes) ServerSelector(selector description.ServerSelector) *ListIndexes {
if li == nil {
li = new(ListIndexes)
}
li.selector = selector
return li
}
// Retry enables retryable mode for this operation. Retries are handled automatically in driver.Operation.Execute based
// on how the operation is set.
func (li *ListIndexes) Retry(retry driver.RetryMode) *ListIndexes {
if li == nil {
li = new(ListIndexes)
}
li.retry = &retry
return li
}
// Crypt sets the Crypt object to use for automatic encryption and decryption.
func (li *ListIndexes) Crypt(crypt driver.Crypt) *ListIndexes {
if li == nil {
li = new(ListIndexes)
}
li.crypt = crypt
return li
}
// ServerAPI sets the server API version for this operation.
func (li *ListIndexes) ServerAPI(serverAPI *driver.ServerAPIOptions) *ListIndexes {
if li == nil {
li = new(ListIndexes)
}
li.serverAPI = serverAPI
return li
}
// Timeout sets the timeout for this operation.
func (li *ListIndexes) Timeout(timeout *time.Duration) *ListIndexes {
if li == nil {
li = new(ListIndexes)
}
li.timeout = timeout
return li
}

View File

@@ -0,0 +1,401 @@
// Copyright (C) MongoDB, Inc. 2019-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 operation
import (
"context"
"errors"
"fmt"
"time"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/bsontype"
"go.mongodb.org/mongo-driver/event"
"go.mongodb.org/mongo-driver/mongo/description"
"go.mongodb.org/mongo-driver/mongo/writeconcern"
"go.mongodb.org/mongo-driver/x/bsonx/bsoncore"
"go.mongodb.org/mongo-driver/x/mongo/driver"
"go.mongodb.org/mongo-driver/x/mongo/driver/session"
)
// Update performs an update operation.
type Update struct {
bypassDocumentValidation *bool
comment bsoncore.Value
ordered *bool
updates []bsoncore.Document
session *session.Client
clock *session.ClusterClock
collection string
monitor *event.CommandMonitor
database string
deployment driver.Deployment
hint *bool
arrayFilters *bool
selector description.ServerSelector
writeConcern *writeconcern.WriteConcern
retry *driver.RetryMode
result UpdateResult
crypt driver.Crypt
serverAPI *driver.ServerAPIOptions
let bsoncore.Document
timeout *time.Duration
}
// Upsert contains the information for an upsert in an Update operation.
type Upsert struct {
Index int64
ID interface{} `bson:"_id"`
}
// UpdateResult contains information for the result of an Update operation.
type UpdateResult struct {
// Number of documents matched.
N int64
// Number of documents modified.
NModified int64
// Information about upserted documents.
Upserted []Upsert
}
func buildUpdateResult(response bsoncore.Document) (UpdateResult, error) {
elements, err := response.Elements()
if err != nil {
return UpdateResult{}, err
}
ur := UpdateResult{}
for _, element := range elements {
switch element.Key() {
case "nModified":
var ok bool
ur.NModified, ok = element.Value().AsInt64OK()
if !ok {
return ur, fmt.Errorf("response field 'nModified' is type int32 or int64, but received BSON type %s", element.Value().Type)
}
case "n":
var ok bool
ur.N, ok = element.Value().AsInt64OK()
if !ok {
return ur, fmt.Errorf("response field 'n' is type int32 or int64, but received BSON type %s", element.Value().Type)
}
case "upserted":
arr, ok := element.Value().ArrayOK()
if !ok {
return ur, fmt.Errorf("response field 'upserted' is type array, but received BSON type %s", element.Value().Type)
}
var values []bsoncore.Value
values, err = arr.Values()
if err != nil {
break
}
for _, val := range values {
valDoc, ok := val.DocumentOK()
if !ok {
return ur, fmt.Errorf("upserted value is type document, but received BSON type %s", val.Type)
}
var upsert Upsert
if err = bson.Unmarshal(valDoc, &upsert); err != nil {
return ur, err
}
ur.Upserted = append(ur.Upserted, upsert)
}
}
}
return ur, nil
}
// NewUpdate constructs and returns a new Update.
func NewUpdate(updates ...bsoncore.Document) *Update {
return &Update{
updates: updates,
}
}
// Result returns the result of executing this operation.
func (u *Update) Result() UpdateResult { return u.result }
func (u *Update) processResponse(info driver.ResponseInfo) error {
ur, err := buildUpdateResult(info.ServerResponse)
u.result.N += ur.N
u.result.NModified += ur.NModified
if info.CurrentIndex > 0 {
for ind := range ur.Upserted {
ur.Upserted[ind].Index += int64(info.CurrentIndex)
}
}
u.result.Upserted = append(u.result.Upserted, ur.Upserted...)
return err
}
// Execute runs this operations and returns an error if the operation did not execute successfully.
func (u *Update) Execute(ctx context.Context) error {
if u.deployment == nil {
return errors.New("the Update operation must have a Deployment set before Execute can be called")
}
batches := &driver.Batches{
Identifier: "updates",
Documents: u.updates,
Ordered: u.ordered,
}
return driver.Operation{
CommandFn: u.command,
ProcessResponseFn: u.processResponse,
Batches: batches,
RetryMode: u.retry,
Type: driver.Write,
Client: u.session,
Clock: u.clock,
CommandMonitor: u.monitor,
Database: u.database,
Deployment: u.deployment,
Selector: u.selector,
WriteConcern: u.writeConcern,
Crypt: u.crypt,
ServerAPI: u.serverAPI,
Timeout: u.timeout,
}.Execute(ctx)
}
func (u *Update) command(dst []byte, desc description.SelectedServer) ([]byte, error) {
dst = bsoncore.AppendStringElement(dst, "update", u.collection)
if u.bypassDocumentValidation != nil &&
(desc.WireVersion != nil && desc.WireVersion.Includes(4)) {
dst = bsoncore.AppendBooleanElement(dst, "bypassDocumentValidation", *u.bypassDocumentValidation)
}
if u.comment.Type != bsontype.Type(0) {
dst = bsoncore.AppendValueElement(dst, "comment", u.comment)
}
if u.ordered != nil {
dst = bsoncore.AppendBooleanElement(dst, "ordered", *u.ordered)
}
if u.hint != nil && *u.hint {
if desc.WireVersion == nil || !desc.WireVersion.Includes(5) {
return nil, errors.New("the 'hint' command parameter requires a minimum server wire version of 5")
}
if !u.writeConcern.Acknowledged() {
return nil, errUnacknowledgedHint
}
}
if u.arrayFilters != nil && *u.arrayFilters {
if desc.WireVersion == nil || !desc.WireVersion.Includes(6) {
return nil, errors.New("the 'arrayFilters' command parameter requires a minimum server wire version of 6")
}
}
if u.let != nil {
dst = bsoncore.AppendDocumentElement(dst, "let", u.let)
}
return dst, nil
}
// BypassDocumentValidation allows the operation to opt-out of document level validation. Valid
// for server versions >= 3.2. For servers < 3.2, this setting is ignored.
func (u *Update) BypassDocumentValidation(bypassDocumentValidation bool) *Update {
if u == nil {
u = new(Update)
}
u.bypassDocumentValidation = &bypassDocumentValidation
return u
}
// Hint is a flag to indicate that the update document contains a hint. Hint is only supported by
// servers >= 4.2. Older servers >= 3.4 will report an error for using the hint option. For servers <
// 3.4, the driver will return an error if the hint option is used.
func (u *Update) Hint(hint bool) *Update {
if u == nil {
u = new(Update)
}
u.hint = &hint
return u
}
// ArrayFilters is a flag to indicate that the update document contains an arrayFilters field. This option is only
// supported on server versions 3.6 and higher. For servers < 3.6, the driver will return an error.
func (u *Update) ArrayFilters(arrayFilters bool) *Update {
if u == nil {
u = new(Update)
}
u.arrayFilters = &arrayFilters
return u
}
// Ordered sets ordered. If true, when a write fails, the operation will return the error, when
// false write failures do not stop execution of the operation.
func (u *Update) Ordered(ordered bool) *Update {
if u == nil {
u = new(Update)
}
u.ordered = &ordered
return u
}
// Updates specifies an array of update statements to perform when this operation is executed.
// Each update document must have the following structure:
// {q: <query>, u: <update>, multi: <boolean>, collation: Optional<Document>, arrayFitlers: Optional<Array>, hint: Optional<string/Document>}.
func (u *Update) Updates(updates ...bsoncore.Document) *Update {
if u == nil {
u = new(Update)
}
u.updates = updates
return u
}
// Session sets the session for this operation.
func (u *Update) Session(session *session.Client) *Update {
if u == nil {
u = new(Update)
}
u.session = session
return u
}
// ClusterClock sets the cluster clock for this operation.
func (u *Update) ClusterClock(clock *session.ClusterClock) *Update {
if u == nil {
u = new(Update)
}
u.clock = clock
return u
}
// Collection sets the collection that this command will run against.
func (u *Update) Collection(collection string) *Update {
if u == nil {
u = new(Update)
}
u.collection = collection
return u
}
// CommandMonitor sets the monitor to use for APM events.
func (u *Update) CommandMonitor(monitor *event.CommandMonitor) *Update {
if u == nil {
u = new(Update)
}
u.monitor = monitor
return u
}
// Comment sets a value to help trace an operation.
func (u *Update) Comment(comment bsoncore.Value) *Update {
if u == nil {
u = new(Update)
}
u.comment = comment
return u
}
// Database sets the database to run this operation against.
func (u *Update) Database(database string) *Update {
if u == nil {
u = new(Update)
}
u.database = database
return u
}
// Deployment sets the deployment to use for this operation.
func (u *Update) Deployment(deployment driver.Deployment) *Update {
if u == nil {
u = new(Update)
}
u.deployment = deployment
return u
}
// ServerSelector sets the selector used to retrieve a server.
func (u *Update) ServerSelector(selector description.ServerSelector) *Update {
if u == nil {
u = new(Update)
}
u.selector = selector
return u
}
// WriteConcern sets the write concern for this operation.
func (u *Update) WriteConcern(writeConcern *writeconcern.WriteConcern) *Update {
if u == nil {
u = new(Update)
}
u.writeConcern = writeConcern
return u
}
// Retry enables retryable writes for this operation. Retries are not handled automatically,
// instead a boolean is returned from Execute and SelectAndExecute that indicates if the
// operation can be retried. Retrying is handled by calling RetryExecute.
func (u *Update) Retry(retry driver.RetryMode) *Update {
if u == nil {
u = new(Update)
}
u.retry = &retry
return u
}
// Crypt sets the Crypt object to use for automatic encryption and decryption.
func (u *Update) Crypt(crypt driver.Crypt) *Update {
if u == nil {
u = new(Update)
}
u.crypt = crypt
return u
}
// ServerAPI sets the server API version for this operation.
func (u *Update) ServerAPI(serverAPI *driver.ServerAPIOptions) *Update {
if u == nil {
u = new(Update)
}
u.serverAPI = serverAPI
return u
}
// Let specifies the let document to use. This option is only valid for server versions 5.0 and above.
func (u *Update) Let(let bsoncore.Document) *Update {
if u == nil {
u = new(Update)
}
u.let = let
return u
}
// Timeout sets the timeout for this operation.
func (u *Update) Timeout(timeout *time.Duration) *Update {
if u == nil {
u = new(Update)
}
u.timeout = timeout
return u
}