Skip to content

Commit

Permalink
GODRIVER-2701 PR Changes
Browse files Browse the repository at this point in the history
  • Loading branch information
timothy-kim-mongo committed Jul 1, 2024
1 parent 7e5f157 commit 5cefa42
Show file tree
Hide file tree
Showing 4 changed files with 131 additions and 67 deletions.
65 changes: 41 additions & 24 deletions mongo/index_view.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ import (
"go.mongodb.org/mongo-driver/x/mongo/driver/session"
)

// ErrInvalidSearchParam is returned if the search param in dropIndex was not a valid key or name
var ErrInvalidSearchParam = errors.New("invalid search param")
// ErrInvalidIndexType is returned if an invalid index type is inputted.
var ErrInvalidIndexType = errors.New("invalid index type")

// ErrInvalidKeyValue is returned if there is invalid key value
var ErrInvalidKeyValue = errors.New("invalid key value")
Expand Down Expand Up @@ -373,7 +373,7 @@ func (iv IndexView) createOptionsDoc(opts *options.IndexOptions) (bsoncore.Docum
return optsDoc, nil
}

func (iv IndexView) drop(ctx context.Context, name string, opts ...*options.DropIndexesOptions) (bson.Raw, error) {
func (iv IndexView) drop(ctx context.Context, index any, opts ...*options.DropIndexesOptions) (bson.Raw, error) {
if ctx == nil {
ctx = context.Background()
}
Expand Down Expand Up @@ -403,34 +403,46 @@ func (iv IndexView) drop(ctx context.Context, name string, opts ...*options.Drop

// TODO(GODRIVER-3038): This operation should pass CSE to the DropIndexes
// Crypt setter to be applied to the operation.
op := operation.NewDropIndexes(name).
Session(sess).WriteConcern(wc).CommandMonitor(iv.coll.client.monitor).
ServerSelector(selector).ClusterClock(iv.coll.client.clock).
Database(iv.coll.db.name).Collection(iv.coll.name).
Deployment(iv.coll.client.deployment).ServerAPI(iv.coll.client.serverAPI).
Timeout(iv.coll.client.timeout).MaxTime(dio.MaxTime)

err = op.Execute(ctx)
if err != nil {
return nil, replaceErrors(err)
var results operation.DropIndexesResult

switch indexVal := index.(type) {
case string:
// Convert index to string
op := operation.NewDropIndexes(indexVal).Session(sess).WriteConcern(wc).CommandMonitor(iv.coll.client.monitor).
ServerSelector(selector).ClusterClock(iv.coll.client.clock).
Database(iv.coll.db.name).Collection(iv.coll.name).
Deployment(iv.coll.client.deployment).ServerAPI(iv.coll.client.serverAPI).
Timeout(iv.coll.client.timeout).MaxTime(dio.MaxTime)
err = op.Execute(ctx)
if err != nil {
return nil, replaceErrors(err)
}
results = op.Result()
case bsoncore.Document:
// Convert index to bsoncore.Document
op := operation.NewDropIndexes(indexVal).Session(sess).WriteConcern(wc).CommandMonitor(iv.coll.client.monitor).
ServerSelector(selector).ClusterClock(iv.coll.client.clock).
Database(iv.coll.db.name).Collection(iv.coll.name).
Deployment(iv.coll.client.deployment).ServerAPI(iv.coll.client.serverAPI).
Timeout(iv.coll.client.timeout).MaxTime(dio.MaxTime)
err = op.Execute(ctx)
if err != nil {
return nil, replaceErrors(err)
}
results = op.Result()
default:
// Handle unexpected type
return nil, ErrInvalidIndexType
}

// TODO: it's weird to return a bson.Raw here because we have to convert the result back to BSON
ridx, res := bsoncore.AppendDocumentStart(nil)
res = bsoncore.AppendInt32Element(res, "nIndexesWas", op.Result().NIndexesWas)
res = bsoncore.AppendInt32Element(res, "nIndexesWas", results.NIndexesWas)
res, _ = bsoncore.AppendDocumentEnd(res, ridx)
return res, nil
}

func (iv IndexView) dropFromKeys(ctx context.Context, keySpecDocument bsoncore.Document, opts ...*options.DropIndexesOptions) (bson.Raw, error) {
model := IndexModel{nil, nil}
name, err := getOrGenerateIndexName(keySpecDocument, model)
if err != nil {
return nil, ErrInvalidKeyValue
}
return iv.drop(ctx, name, opts...)
}

// DropOne executes a dropIndexes operation to drop an index on the collection. If the operation succeeds, this returns
// a BSON document in the form {nIndexesWas: <int32>}. The "nIndexesWas" field in the response contains the number of
// indexes that existed prior to the drop.
Expand All @@ -455,8 +467,13 @@ func (iv IndexView) DropOne(ctx context.Context, name string, opts ...*options.D
// indexes that existed prior to the drop.
//
// The key parameter should be the keySpecDocument of the index to drop.
func (iv IndexView) DropKeyOne(ctx context.Context, key bsoncore.Document, opts ...*options.DropIndexesOptions) (bson.Raw, error) {
return iv.dropFromKeys(ctx, key, opts...)
func (iv IndexView) DropKeyOne(ctx context.Context, keySpecDocument interface{}, opts ...*options.DropIndexesOptions) (bson.Raw, error) {
doc, err := marshal(keySpecDocument, iv.coll.bsonOpts, iv.coll.registry)
if err != nil {
return nil, err
}

return iv.drop(ctx, doc, opts...)
}

// DropAll executes a dropIndexes operation to drop all indexes on the collection. If the operation succeeds, this
Expand Down
10 changes: 6 additions & 4 deletions mongo/integration/index_view_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -614,16 +614,18 @@ func TestIndexView(t *testing.T) {
Keys: bson.Raw(bsoncore.NewDocumentBuilder().AppendInt32("_id", 1).Build()),
},
{
Keys: bson.Raw(bsoncore.NewDocumentBuilder().AppendInt32("foo", -1).Build()),
Keys: bson.Raw(bsoncore.NewDocumentBuilder().AppendInt32("username", 1).Build()),
Options: options.Index().SetUnique(true).SetName("myidx"),
},
})

key := bson.Raw(bsoncore.NewDocumentBuilder().AppendInt32("foo", -1).Build())

key := map[string]interface{}{
"username": 1,
}
assert.Nil(mt, err, "CreateMany error: %v", err)
assert.Equal(mt, 2, len(indexNames), "expected 2 index names, got %v", len(indexNames))

_, err = iv.DropKeyOne(context.Background(), bsoncore.Document(key))
_, err = iv.DropKeyOne(context.Background(), key)
assert.Nil(mt, err, "DropOne error: %v", err)

cursor, err := iv.List(context.Background())
Expand Down
41 changes: 41 additions & 0 deletions mongo/integration/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,44 @@ package integration
//
// go build go.mongodb.org/mongo-driver/mongo/integration: build constraints exclude all Go files in ./go.mongodb.org/mongo-driver/mongo/integration
//

import (
"context"
"log"

"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
"go.mongodb.org/mongo-driver/x/bsonx/bsoncore"
)

func main() {
opts := options.Client().ApplyURI("mongodb://localhost:27017")

client, err := mongo.Connect(context.Background(), opts)
if err != nil {
log.Fatalf("failed to create connection: %v", err)
}

defer client.Disconnect(context.Background())

database := client.Database("appdb")
uc := database.Collection("users")

indexModel := mongo.IndexModel{
Keys: bson.M{"username": 1},
Options: options.Index().SetUnique(true).SetName("myidx"),
}

_, err = uc.Indexes().CreateOne(context.TODO(), indexModel)
if err != nil {
log.Fatal(err)
}

print("hi")
// Drop index if it exists
_, err = uc.Indexes().DropKeyOne(context.Background(), bsoncore.Document(bson.Raw(bsoncore.NewDocumentBuilder().AppendInt32("username", 1).Build())))
if err != nil {
log.Fatalf("failed to drop index: %v", err)
}
}
82 changes: 43 additions & 39 deletions x/mongo/driver/operation/drop_indexes.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ import (
)

// DropIndexes performs an dropIndexes operation.
type DropIndexes struct {
index *string
type DropIndexes[T string | bsoncore.Document] struct {
index T
maxTime *time.Duration
session *session.Client
clock *session.ClusterClock
Expand Down Expand Up @@ -64,24 +64,23 @@ func buildDropIndexesResult(response bsoncore.Document) (DropIndexesResult, erro
return dir, nil
}

// NewDropIndexes constructs and returns a new DropIndexes.
func NewDropIndexes(index string) *DropIndexes {
return &DropIndexes{
index: &index,
func NewDropIndexes[T string | bsoncore.Document](index T) *DropIndexes[T] {
return &DropIndexes[T]{
index: index,
}
}

// Result returns the result of executing this operation.
func (di *DropIndexes) Result() DropIndexesResult { return di.result }
func (di *DropIndexes[T]) Result() DropIndexesResult { return di.result }

func (di *DropIndexes) processResponse(info driver.ResponseInfo) error {
func (di *DropIndexes[T]) 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 {
func (di *DropIndexes[T]) 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")
}
Expand All @@ -105,138 +104,143 @@ func (di *DropIndexes) Execute(ctx context.Context) error {

}

func (di *DropIndexes) command(dst []byte, _ description.SelectedServer) ([]byte, error) {
func (di *DropIndexes[T]) command(dst []byte, _ description.SelectedServer) ([]byte, error) {
dst = bsoncore.AppendStringElement(dst, "dropIndexes", di.collection)
if di.index != nil {
dst = bsoncore.AppendStringElement(dst, "index", *di.index)

switch any(di.index).(type) {
case string:
dst = bsoncore.AppendStringElement(dst, "index", string(di.index))
case bsoncore.Document:
dst = bsoncore.AppendDocumentElement(dst, "index", bsoncore.Document(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 {
func (di *DropIndexes[T]) Index(index T) *DropIndexes[T] {
if di == nil {
di = new(DropIndexes)
di = new(DropIndexes[T])
}

di.index = &index
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 {
func (di *DropIndexes[T]) MaxTime(maxTime *time.Duration) *DropIndexes[T] {
if di == nil {
di = new(DropIndexes)
di = new(DropIndexes[T])
}

di.maxTime = maxTime
return di
}

// Session sets the session for this operation.
func (di *DropIndexes) Session(session *session.Client) *DropIndexes {
func (di *DropIndexes[T]) Session(session *session.Client) *DropIndexes[T] {
if di == nil {
di = new(DropIndexes)
di = new(DropIndexes[T])
}

di.session = session
return di
}

// ClusterClock sets the cluster clock for this operation.
func (di *DropIndexes) ClusterClock(clock *session.ClusterClock) *DropIndexes {
func (di *DropIndexes[T]) ClusterClock(clock *session.ClusterClock) *DropIndexes[T] {
if di == nil {
di = new(DropIndexes)
di = new(DropIndexes[T])
}

di.clock = clock
return di
}

// Collection sets the collection that this command will run against.
func (di *DropIndexes) Collection(collection string) *DropIndexes {
func (di *DropIndexes[T]) Collection(collection string) *DropIndexes[T] {
if di == nil {
di = new(DropIndexes)
di = new(DropIndexes[T])
}

di.collection = collection
return di
}

// CommandMonitor sets the monitor to use for APM events.
func (di *DropIndexes) CommandMonitor(monitor *event.CommandMonitor) *DropIndexes {
func (di *DropIndexes[T]) CommandMonitor(monitor *event.CommandMonitor) *DropIndexes[T] {
if di == nil {
di = new(DropIndexes)
di = new(DropIndexes[T])
}

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 {
func (di *DropIndexes[T]) Crypt(crypt driver.Crypt) *DropIndexes[T] {
if di == nil {
di = new(DropIndexes)
di = new(DropIndexes[T])
}

di.crypt = crypt
return di
}

// Database sets the database to run this operation against.
func (di *DropIndexes) Database(database string) *DropIndexes {
func (di *DropIndexes[T]) Database(database string) *DropIndexes[T] {
if di == nil {
di = new(DropIndexes)
di = new(DropIndexes[T])
}

di.database = database
return di
}

// Deployment sets the deployment to use for this operation.
func (di *DropIndexes) Deployment(deployment driver.Deployment) *DropIndexes {
func (di *DropIndexes[T]) Deployment(deployment driver.Deployment) *DropIndexes[T] {
if di == nil {
di = new(DropIndexes)
di = new(DropIndexes[T])
}

di.deployment = deployment
return di
}

// ServerSelector sets the selector used to retrieve a server.
func (di *DropIndexes) ServerSelector(selector description.ServerSelector) *DropIndexes {
func (di *DropIndexes[T]) ServerSelector(selector description.ServerSelector) *DropIndexes[T] {
if di == nil {
di = new(DropIndexes)
di = new(DropIndexes[T])
}

di.selector = selector
return di
}

// WriteConcern sets the write concern for this operation.
func (di *DropIndexes) WriteConcern(writeConcern *writeconcern.WriteConcern) *DropIndexes {
func (di *DropIndexes[T]) WriteConcern(writeConcern *writeconcern.WriteConcern) *DropIndexes[T] {
if di == nil {
di = new(DropIndexes)
di = new(DropIndexes[T])
}

di.writeConcern = writeConcern
return di
}

// ServerAPI sets the server API version for this operation.
func (di *DropIndexes) ServerAPI(serverAPI *driver.ServerAPIOptions) *DropIndexes {
func (di *DropIndexes[T]) ServerAPI(serverAPI *driver.ServerAPIOptions) *DropIndexes[T] {
if di == nil {
di = new(DropIndexes)
di = new(DropIndexes[T])
}

di.serverAPI = serverAPI
return di
}

// Timeout sets the timeout for this operation.
func (di *DropIndexes) Timeout(timeout *time.Duration) *DropIndexes {
func (di *DropIndexes[T]) Timeout(timeout *time.Duration) *DropIndexes[T] {
if di == nil {
di = new(DropIndexes)
di = new(DropIndexes[T])
}

di.timeout = timeout
Expand Down

0 comments on commit 5cefa42

Please sign in to comment.