Skip to content

Commit 8533d0a

Browse files
committed
GODRIVER-3285 [v2]Allow update to supply sort option.
1 parent 7910023 commit 8533d0a

20 files changed

+1744
-133
lines changed

internal/integration/collection_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -451,7 +451,7 @@ func TestCollection(t *testing.T) {
451451
filter := bson.D{{"x", 0}}
452452
update := bson.D{{"$inc", bson.D{{"x", 1}}}}
453453

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

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

636-
res, err := mt.Coll.UpdateMany(context.Background(), filter, update, options.Update().SetUpsert(true))
636+
res, err := mt.Coll.UpdateMany(context.Background(), filter, update, options.UpdateMany().SetUpsert(true))
637637
assert.Nil(mt, err, "UpdateMany error: %v", err)
638638
assert.Equal(mt, int64(0), res.MatchedCount, "expected matched count 0, got %v", res.MatchedCount)
639639
assert.Equal(mt, int64(0), res.ModifiedCount, "expected modified count 0, got %v", res.ModifiedCount)

internal/integration/crud_helpers_test.go

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,20 @@ func createHint(mt *mtest.T, val bson.RawValue) interface{} {
7979
return hint
8080
}
8181

82+
// create a sort document from a bson.RawValue
83+
func createSort(mt *mtest.T, val bson.RawValue) interface{} {
84+
mt.Helper()
85+
86+
var sort interface{}
87+
switch val.Type {
88+
case bson.TypeEmbeddedDocument:
89+
sort = val.Document()
90+
default:
91+
mt.Fatalf("unrecognized sort value type: %s\n", val.Type)
92+
}
93+
return sort
94+
}
95+
8296
// returns true if err is a mongo.CommandError containing a code that is expected from a killAllSessions command.
8397
func isExpectedKillAllSessionsError(err error) bool {
8498
cmdErr, ok := err.(mongo.CommandError)
@@ -874,7 +888,7 @@ func executeUpdateOne(mt *mtest.T, sess *mongo.Session, args bson.Raw) (*mongo.U
874888

875889
filter := emptyDoc
876890
var update interface{} = emptyDoc
877-
opts := options.Update()
891+
opts := options.UpdateOne()
878892

879893
elems, _ := args.Elements()
880894
for _, elem := range elems {
@@ -902,7 +916,7 @@ func executeUpdateOne(mt *mtest.T, sess *mongo.Session, args bson.Raw) (*mongo.U
902916
}
903917
}
904918

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

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

927941
filter := emptyDoc
928942
var update interface{} = emptyDoc
929-
opts := options.Update()
943+
opts := options.UpdateMany()
930944

931945
elems, _ := args.Elements()
932946
for _, elem := range elems {
@@ -954,7 +968,7 @@ func executeUpdateMany(mt *mtest.T, sess *mongo.Session, args bson.Raw) (*mongo.
954968
}
955969
}
956970

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

960974
if updateArgs.Upsert == nil {

internal/integration/crud_prose_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -296,7 +296,7 @@ func TestHintErrors(t *testing.T) {
296296
mt.Run("UpdateMany", func(mt *mtest.T) {
297297

298298
_, got := mt.Coll.UpdateMany(context.Background(), bson.D{{"a", 1}}, bson.D{{"$inc", bson.D{{"a", 1}}}},
299-
options.Update().SetHint("_id_"))
299+
options.UpdateMany().SetHint("_id_"))
300300
assert.NotNil(mt, got, "expected non-nil error, got nil")
301301
assert.Equal(mt, got, expected, "expected: %v got: %v", expected, got)
302302
})

internal/integration/unified/bulkwrite_helpers.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,12 @@ func createBulkWriteModel(rawModel bson.Raw) (mongo.WriteModel, error) {
102102
if err != nil {
103103
return nil, fmt.Errorf("error creating update: %w", err)
104104
}
105+
case "sort":
106+
sort, err := createSort(val)
107+
if err != nil {
108+
return nil, fmt.Errorf("error creating sort: %w", err)
109+
}
110+
uom.SetSort(sort)
105111
case "upsert":
106112
uom.SetUpsert(val.Boolean())
107113
default:
@@ -249,6 +255,12 @@ func createBulkWriteModel(rawModel bson.Raw) (mongo.WriteModel, error) {
249255
return nil, fmt.Errorf("error creating hint: %w", err)
250256
}
251257
rom.SetHint(hint)
258+
case "sort":
259+
sort, err := createSort(val)
260+
if err != nil {
261+
return nil, fmt.Errorf("error creating sort: %w", err)
262+
}
263+
rom.SetSort(sort)
252264
case "replacement":
253265
replacement = val.Document()
254266
case "upsert":

internal/integration/unified/collection_operation_execution.go

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1291,6 +1291,12 @@ func executeReplaceOne(ctx context.Context, operation *operation) (*operationRes
12911291
return nil, fmt.Errorf("error creating hint: %w", err)
12921292
}
12931293
opts.SetHint(hint)
1294+
case "sort":
1295+
sort, err := createSort(val)
1296+
if err != nil {
1297+
return nil, fmt.Errorf("error creating sort: %w", err)
1298+
}
1299+
opts.SetSort(sort)
12941300
case "replacement":
12951301
replacement = val.Document()
12961302
case "upsert":
@@ -1316,7 +1322,7 @@ func executeUpdateOne(ctx context.Context, operation *operation) (*operationResu
13161322
return nil, err
13171323
}
13181324

1319-
updateArgs, err := createUpdateArguments(operation.Arguments)
1325+
updateArgs, err := createUpdateArguments[options.UpdateOneOptions](operation.Arguments)
13201326
if err != nil {
13211327
return nil, err
13221328
}
@@ -1335,7 +1341,7 @@ func executeUpdateMany(ctx context.Context, operation *operation) (*operationRes
13351341
return nil, err
13361342
}
13371343

1338-
updateArgs, err := createUpdateArguments(operation.Arguments)
1344+
updateArgs, err := createUpdateArguments[options.UpdateManyOptions](operation.Arguments)
13391345
if err != nil {
13401346
return nil, err
13411347
}

internal/integration/unified/crud_helpers.go

Lines changed: 44 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ package unified
88

99
import (
1010
"fmt"
11+
"reflect"
12+
"strings"
1113

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

23-
type updateArguments struct {
25+
type updateArguments[Options options.UpdateManyOptions | options.UpdateOneOptions] struct {
2426
filter bson.Raw
2527
update interface{}
26-
opts *options.UpdateOptionsBuilder
28+
opts options.Lister[Options]
2729
}
2830

29-
func createUpdateArguments(args bson.Raw) (*updateArguments, error) {
30-
ua := &updateArguments{
31-
opts: options.Update(),
31+
func createUpdateArguments[Options options.UpdateManyOptions | options.UpdateOneOptions](args bson.Raw) (*updateArguments[Options], error) {
32+
ua := &updateArguments[Options]{}
33+
var builder reflect.Value
34+
switch any((*Options)(nil)).(type) {
35+
case *options.UpdateManyOptions:
36+
builder = reflect.ValueOf(options.UpdateMany())
37+
case *options.UpdateOneOptions:
38+
builder = reflect.ValueOf(options.UpdateOne())
3239
}
33-
var err error
3440

3541
elems, _ := args.Elements()
3642
for _, elem := range elems {
3743
key := elem.Key()
3844
val := elem.Value()
3945

46+
var arg reflect.Value
4047
switch key {
4148
case "arrayFilters":
42-
ua.opts.SetArrayFilters(
49+
arg = reflect.ValueOf(
4350
bsonutil.RawToInterfaces(bsonutil.RawArrayToDocuments(val.Array())...),
4451
)
4552
case "bypassDocumentValidation":
46-
ua.opts.SetBypassDocumentValidation(val.Boolean())
53+
arg = reflect.ValueOf(val.Boolean())
4754
case "collation":
4855
collation, err := createCollation(val.Document())
4956
if err != nil {
5057
return nil, fmt.Errorf("error creating collation: %w", err)
5158
}
52-
ua.opts.SetCollation(collation)
59+
arg = reflect.ValueOf(collation)
5360
case "comment":
54-
ua.opts.SetComment(val)
61+
arg = reflect.ValueOf(val)
5562
case "filter":
5663
ua.filter = val.Document()
5764
case "hint":
5865
hint, err := createHint(val)
5966
if err != nil {
6067
return nil, fmt.Errorf("error creating hint: %w", err)
6168
}
62-
ua.opts.SetHint(hint)
63-
case "let":
64-
ua.opts.SetLet(val.Document())
69+
arg = reflect.ValueOf(hint)
70+
case "let", "sort":
71+
arg = reflect.ValueOf(val.Document())
6572
case "update":
73+
var err error
6674
ua.update, err = createUpdateValue(val)
6775
if err != nil {
6876
return nil, fmt.Errorf("error processing update value: %w", err)
6977
}
7078
case "upsert":
71-
ua.opts.SetUpsert(val.Boolean())
79+
arg = reflect.ValueOf(val.Boolean())
7280
default:
7381
return nil, fmt.Errorf("unrecognized update option %q", key)
7482
}
83+
if arg.IsValid() {
84+
fn := builder.MethodByName(
85+
fmt.Sprintf("Set%s%s", strings.ToUpper(string(key[0])), key[1:]),
86+
)
87+
if !fn.IsValid() {
88+
return nil, fmt.Errorf("unrecognized update option %q", key)
89+
}
90+
fn.Call([]reflect.Value{arg})
91+
}
7592
}
7693
if ua.filter == nil {
7794
return nil, newMissingArgumentError("filter")
7895
}
7996
if ua.update == nil {
8097
return nil, newMissingArgumentError("update")
8198
}
99+
ua.opts = builder.Interface().(options.Lister[Options])
82100

83101
return ua, nil
84102
}
@@ -158,3 +176,15 @@ func createHint(val bson.RawValue) (interface{}, error) {
158176
}
159177
return hint, nil
160178
}
179+
180+
func createSort(val bson.RawValue) (interface{}, error) {
181+
var sort interface{}
182+
183+
switch val.Type {
184+
case bson.TypeEmbeddedDocument:
185+
sort = val.Document()
186+
default:
187+
return nil, fmt.Errorf("unrecognized sort value type %s", val.Type)
188+
}
189+
return sort, nil
190+
}

0 commit comments

Comments
 (0)