Skip to content

Commit

Permalink
GODRIVER-3339 Separate Many and One for UpdateOptions and `Dele…
Browse files Browse the repository at this point in the history
…teOptions`
  • Loading branch information
qingyang-hu committed Sep 17, 2024
1 parent 884fb42 commit 3b76520
Show file tree
Hide file tree
Showing 10 changed files with 445 additions and 175 deletions.
18 changes: 9 additions & 9 deletions internal/integration/collection_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -296,7 +296,7 @@ func TestCollection(t *testing.T) {
})
mt.RunOpts("not found with options", mtest.NewOptions().MinServerVersion("3.4"), func(mt *mtest.T) {
initCollection(mt, mt.Coll)
opts := options.Delete().SetCollation(&options.Collation{Locale: "en_US"})
opts := options.DeleteOne().SetCollation(&options.Collation{Locale: "en_US"})
res, err := mt.Coll.DeleteOne(context.Background(), bson.D{{"x", 0}}, opts)
assert.Nil(mt, err, "DeleteOne error: %v", err)
assert.Equal(mt, int64(0), res.DeletedCount, "expected DeletedCount 0, got %v", res.DeletedCount)
Expand Down Expand Up @@ -339,13 +339,13 @@ func TestCollection(t *testing.T) {
})
assert.Nil(mt, err, "CreateOne error: %v", err)

opts := options.Delete().SetHint(bson.M{"x": 1})
opts := options.DeleteOne().SetHint(bson.M{"x": 1})
res, err := mt.Coll.DeleteOne(context.Background(), bson.D{{"x", 1}}, opts)
assert.Nil(mt, err, "DeleteOne error: %v", err)
assert.Equal(mt, int64(1), res.DeletedCount, "expected DeletedCount 1, got %v", res.DeletedCount)
})
mt.RunOpts("multikey map index", mtest.NewOptions().MinServerVersion("4.4"), func(mt *mtest.T) {
opts := options.Delete().SetHint(bson.M{"x": 1, "y": 1})
opts := options.DeleteOne().SetHint(bson.M{"x": 1, "y": 1})
_, err := mt.Coll.DeleteOne(context.Background(), bson.D{{"x", 0}}, opts)
assert.Equal(mt, mongo.ErrMapForOrderedArgument{"hint"}, err, "expected error %v, got %v", mongo.ErrMapForOrderedArgument{"hint"}, err)
})
Expand All @@ -365,7 +365,7 @@ func TestCollection(t *testing.T) {
})
mt.RunOpts("not found with options", mtest.NewOptions().MinServerVersion("3.4"), func(mt *mtest.T) {
initCollection(mt, mt.Coll)
opts := options.Delete().SetCollation(&options.Collation{Locale: "en_US"})
opts := options.DeleteMany().SetCollation(&options.Collation{Locale: "en_US"})
res, err := mt.Coll.DeleteMany(context.Background(), bson.D{{"x", bson.D{{"$lt", 1}}}}, opts)
assert.Nil(mt, err, "DeleteMany error: %v", err)
assert.Equal(mt, int64(0), res.DeletedCount, "expected DeletedCount 0, got %v", res.DeletedCount)
Expand Down Expand Up @@ -408,13 +408,13 @@ func TestCollection(t *testing.T) {
})
assert.Nil(mt, err, "index CreateOne error: %v", err)

opts := options.Delete().SetHint(bson.M{"x": 1})
opts := options.DeleteOne().SetHint(bson.M{"x": 1})
res, err := mt.Coll.DeleteOne(context.Background(), bson.D{{"x", 1}}, opts)
assert.Nil(mt, err, "DeleteOne error: %v", err)
assert.Equal(mt, int64(1), res.DeletedCount, "expected DeletedCount 1, got %v", res.DeletedCount)
})
mt.RunOpts("multikey map index", mtest.NewOptions().MinServerVersion("4.4"), func(mt *mtest.T) {
opts := options.Delete().SetHint(bson.M{"x": 1, "y": 1})
opts := options.DeleteMany().SetHint(bson.M{"x": 1, "y": 1})
_, err := mt.Coll.DeleteMany(context.Background(), bson.D{{"x", 0}}, opts)
assert.Equal(mt, mongo.ErrMapForOrderedArgument{"hint"}, err, "expected error %v, got %v", mongo.ErrMapForOrderedArgument{"hint"}, err)
})
Expand Down Expand Up @@ -451,7 +451,7 @@ func TestCollection(t *testing.T) {
filter := bson.D{{"x", 0}}
update := bson.D{{"$inc", bson.D{{"x", 1}}}}

res, err := mt.Coll.UpdateOne(context.Background(), filter, update, options.Update().SetUpsert(true))
res, err := mt.Coll.UpdateOne(context.Background(), filter, update, options.UpdateOne().SetUpsert(true))
assert.Nil(mt, err, "UpdateOne error: %v", err)
assert.Equal(mt, int64(0), res.MatchedCount, "expected matched count 0, got %v", res.MatchedCount)
assert.Equal(mt, int64(0), res.ModifiedCount, "expected matched count 0, got %v", res.ModifiedCount)
Expand Down Expand Up @@ -570,7 +570,7 @@ func TestCollection(t *testing.T) {
update := bson.D{{"$inc", bson.D{{"x", 1}}}}

id := "blah"
res, err := mt.Coll.UpdateByID(context.Background(), id, update, options.Update().SetUpsert(true))
res, err := mt.Coll.UpdateByID(context.Background(), id, update, options.UpdateOne().SetUpsert(true))
assert.Nil(mt, err, "UpdateByID error: %v", err)
assert.Equal(mt, int64(0), res.MatchedCount, "expected matched count 0, got %v", res.MatchedCount)
assert.Equal(mt, int64(0), res.ModifiedCount, "expected modified count 0, got %v", res.ModifiedCount)
Expand Down Expand Up @@ -633,7 +633,7 @@ func TestCollection(t *testing.T) {
filter := bson.D{{"x", bson.D{{"$lt", 1}}}}
update := bson.D{{"$inc", bson.D{{"x", 1}}}}

res, err := mt.Coll.UpdateMany(context.Background(), filter, update, options.Update().SetUpsert(true))
res, err := mt.Coll.UpdateMany(context.Background(), filter, update, options.UpdateMany().SetUpsert(true))
assert.Nil(mt, err, "UpdateMany error: %v", err)
assert.Equal(mt, int64(0), res.MatchedCount, "expected matched count 0, got %v", res.MatchedCount)
assert.Equal(mt, int64(0), res.ModifiedCount, "expected modified count 0, got %v", res.ModifiedCount)
Expand Down
12 changes: 6 additions & 6 deletions internal/integration/crud_helpers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -801,7 +801,7 @@ func executeDeleteOne(mt *mtest.T, sess *mongo.Session, args bson.Raw) (*mongo.D
mt.Helper()

filter := emptyDoc
opts := options.Delete()
opts := options.DeleteOne()

elems, _ := args.Elements()
for _, elem := range elems {
Expand Down Expand Up @@ -837,7 +837,7 @@ func executeDeleteMany(mt *mtest.T, sess *mongo.Session, args bson.Raw) (*mongo.
mt.Helper()

filter := emptyDoc
opts := options.Delete()
opts := options.DeleteMany()

elems, _ := args.Elements()
for _, elem := range elems {
Expand Down Expand Up @@ -874,7 +874,7 @@ func executeUpdateOne(mt *mtest.T, sess *mongo.Session, args bson.Raw) (*mongo.U

filter := emptyDoc
var update interface{} = emptyDoc
opts := options.Update()
opts := options.UpdateOne()

elems, _ := args.Elements()
for _, elem := range elems {
Expand Down Expand Up @@ -902,7 +902,7 @@ func executeUpdateOne(mt *mtest.T, sess *mongo.Session, args bson.Raw) (*mongo.U
}
}

updateArgs, err := mongoutil.NewOptions[options.UpdateOptions](opts)
updateArgs, err := mongoutil.NewOptions[options.UpdateOneOptions](opts)
require.NoError(mt, err, "failed to construct options from builder")

if updateArgs.Upsert == nil {
Expand All @@ -926,7 +926,7 @@ func executeUpdateMany(mt *mtest.T, sess *mongo.Session, args bson.Raw) (*mongo.

filter := emptyDoc
var update interface{} = emptyDoc
opts := options.Update()
opts := options.UpdateMany()

elems, _ := args.Elements()
for _, elem := range elems {
Expand Down Expand Up @@ -954,7 +954,7 @@ func executeUpdateMany(mt *mtest.T, sess *mongo.Session, args bson.Raw) (*mongo.
}
}

updateArgs, err := mongoutil.NewOptions[options.UpdateOptions](opts)
updateArgs, err := mongoutil.NewOptions[options.UpdateManyOptions](opts)
require.NoError(mt, err, "failed to construct options from builder")

if updateArgs.Upsert == nil {
Expand Down
2 changes: 1 addition & 1 deletion internal/integration/crud_prose_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -296,7 +296,7 @@ func TestHintErrors(t *testing.T) {
mt.Run("UpdateMany", func(mt *mtest.T) {

_, got := mt.Coll.UpdateMany(context.Background(), bson.D{{"a", 1}}, bson.D{{"$inc", bson.D{{"a", 1}}}},
options.Update().SetHint("_id_"))
options.UpdateMany().SetHint("_id_"))
assert.NotNil(mt, got, "expected non-nil error, got nil")
assert.Equal(mt, got, expected, "expected: %v got: %v", expected, got)
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -403,7 +403,7 @@ func executeDeleteOne(ctx context.Context, operation *operation) (*operationResu
}

var filter bson.Raw
opts := options.Delete()
opts := options.DeleteOne()

elems, err := operation.Arguments.Elements()
if err != nil {
Expand Down Expand Up @@ -457,7 +457,7 @@ func executeDeleteMany(ctx context.Context, operation *operation) (*operationRes
}

var filter bson.Raw
opts := options.Delete()
opts := options.DeleteMany()

elems, err := operation.Arguments.Elements()
if err != nil {
Expand Down Expand Up @@ -1316,7 +1316,7 @@ func executeUpdateOne(ctx context.Context, operation *operation) (*operationResu
return nil, err
}

updateArgs, err := createUpdateArguments(operation.Arguments)
updateArgs, err := createUpdateArguments[options.UpdateOneOptions](operation.Arguments)
if err != nil {
return nil, err
}
Expand All @@ -1335,7 +1335,7 @@ func executeUpdateMany(ctx context.Context, operation *operation) (*operationRes
return nil, err
}

updateArgs, err := createUpdateArguments(operation.Arguments)
updateArgs, err := createUpdateArguments[options.UpdateManyOptions](operation.Arguments)
if err != nil {
return nil, err
}
Expand Down
46 changes: 33 additions & 13 deletions internal/integration/unified/crud_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ package unified

import (
"fmt"
"reflect"
"strings"

"go.mongodb.org/mongo-driver/v2/bson"
"go.mongodb.org/mongo-driver/v2/internal/bsonutil"
Expand All @@ -20,65 +22,83 @@ func newMissingArgumentError(arg string) error {
return fmt.Errorf("operation arguments document is missing required field %q", arg)
}

type updateArguments struct {
type updateArguments[Options options.UpdateManyOptions | options.UpdateOneOptions] struct {
filter bson.Raw
update interface{}
opts *options.UpdateOptionsBuilder
opts options.Lister[Options]
}

func createUpdateArguments(args bson.Raw) (*updateArguments, error) {
ua := &updateArguments{
opts: options.Update(),
func createUpdateArguments[Options options.UpdateManyOptions | options.UpdateOneOptions](
args bson.Raw,
) (*updateArguments[Options], error) {
ua := &updateArguments[Options]{}
var builder reflect.Value
switch any((*Options)(nil)).(type) {
case *options.UpdateManyOptions:
builder = reflect.ValueOf(options.UpdateMany())
case *options.UpdateOneOptions:
builder = reflect.ValueOf(options.UpdateOne())
}
var err error

elems, _ := args.Elements()
for _, elem := range elems {
key := elem.Key()
val := elem.Value()

var arg reflect.Value
switch key {
case "arrayFilters":
ua.opts.SetArrayFilters(
arg = reflect.ValueOf(
bsonutil.RawToInterfaces(bsonutil.RawArrayToDocuments(val.Array())...),
)
case "bypassDocumentValidation":
ua.opts.SetBypassDocumentValidation(val.Boolean())
arg = reflect.ValueOf(val.Boolean())
case "collation":
collation, err := createCollation(val.Document())
if err != nil {
return nil, fmt.Errorf("error creating collation: %w", err)
}
ua.opts.SetCollation(collation)
arg = reflect.ValueOf(collation)
case "comment":
ua.opts.SetComment(val)
arg = reflect.ValueOf(val)
case "filter":
ua.filter = val.Document()
case "hint":
hint, err := createHint(val)
if err != nil {
return nil, fmt.Errorf("error creating hint: %w", err)
}
ua.opts.SetHint(hint)
arg = reflect.ValueOf(hint)
case "let":
ua.opts.SetLet(val.Document())
arg = reflect.ValueOf(val.Document())
case "update":
var err error
ua.update, err = createUpdateValue(val)
if err != nil {
return nil, fmt.Errorf("error processing update value: %w", err)
}
case "upsert":
ua.opts.SetUpsert(val.Boolean())
arg = reflect.ValueOf(val.Boolean())
default:
return nil, fmt.Errorf("unrecognized update option %q", key)
}
if arg.IsValid() {
fn := builder.MethodByName(
fmt.Sprintf("Set%s%s", strings.ToUpper(string(key[0])), key[1:]),
)
if !fn.IsValid() {
return nil, fmt.Errorf("unrecognized update option %q", key)
}
fn.Call([]reflect.Value{arg})
}
}
if ua.filter == nil {
return nil, newMissingArgumentError("filter")
}
if ua.update == nil {
return nil, newMissingArgumentError("update")
}
ua.opts = builder.Interface().(options.Lister[Options])

return ua, nil
}
Expand Down
Loading

0 comments on commit 3b76520

Please sign in to comment.