From 5cefa4282f70ce3e0ccc1fd2f258be9226dd484e Mon Sep 17 00:00:00 2001 From: Timothy Kim Date: Mon, 1 Jul 2024 12:24:15 -0400 Subject: [PATCH] GODRIVER-2701 PR Changes --- mongo/index_view.go | 65 ++++++++++++------- mongo/integration/index_view_test.go | 10 +-- mongo/integration/main.go | 41 ++++++++++++ x/mongo/driver/operation/drop_indexes.go | 82 +++++++++++++----------- 4 files changed, 131 insertions(+), 67 deletions(-) diff --git a/mongo/index_view.go b/mongo/index_view.go index 6e12fa18d7..85a4154c56 100644 --- a/mongo/index_view.go +++ b/mongo/index_view.go @@ -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") @@ -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() } @@ -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: }. The "nIndexesWas" field in the response contains the number of // indexes that existed prior to the drop. @@ -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 diff --git a/mongo/integration/index_view_test.go b/mongo/integration/index_view_test.go index 84beb78bb7..9a08621363 100644 --- a/mongo/integration/index_view_test.go +++ b/mongo/integration/index_view_test.go @@ -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()) diff --git a/mongo/integration/main.go b/mongo/integration/main.go index 16e89d3263..c104a38a2a 100644 --- a/mongo/integration/main.go +++ b/mongo/integration/main.go @@ -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) + } +} diff --git a/x/mongo/driver/operation/drop_indexes.go b/x/mongo/driver/operation/drop_indexes.go index 0c3d459707..8e52ad1b26 100644 --- a/x/mongo/driver/operation/drop_indexes.go +++ b/x/mongo/driver/operation/drop_indexes.go @@ -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 @@ -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") } @@ -105,28 +104,33 @@ 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 @@ -134,9 +138,9 @@ func (di *DropIndexes) MaxTime(maxTime *time.Duration) *DropIndexes { } // 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 @@ -144,9 +148,9 @@ func (di *DropIndexes) Session(session *session.Client) *DropIndexes { } // 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 @@ -154,9 +158,9 @@ func (di *DropIndexes) ClusterClock(clock *session.ClusterClock) *DropIndexes { } // 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 @@ -164,9 +168,9 @@ func (di *DropIndexes) Collection(collection string) *DropIndexes { } // 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 @@ -174,9 +178,9 @@ func (di *DropIndexes) CommandMonitor(monitor *event.CommandMonitor) *DropIndexe } // 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 @@ -184,9 +188,9 @@ func (di *DropIndexes) Crypt(crypt driver.Crypt) *DropIndexes { } // 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 @@ -194,9 +198,9 @@ func (di *DropIndexes) Database(database string) *DropIndexes { } // 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 @@ -204,9 +208,9 @@ func (di *DropIndexes) Deployment(deployment driver.Deployment) *DropIndexes { } // 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 @@ -214,9 +218,9 @@ func (di *DropIndexes) ServerSelector(selector description.ServerSelector) *Drop } // 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 @@ -224,9 +228,9 @@ func (di *DropIndexes) WriteConcern(writeConcern *writeconcern.WriteConcern) *Dr } // 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 @@ -234,9 +238,9 @@ func (di *DropIndexes) ServerAPI(serverAPI *driver.ServerAPIOptions) *DropIndexe } // 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