Skip to content

Commit 9dd4bcd

Browse files
authored
GODRIVER-3285 Allow update to supply sort option. (#1797)
1 parent b6131e4 commit 9dd4bcd

16 files changed

+1420
-3
lines changed

internal/integration/unified/bulkwrite_helpers.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,8 @@ 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+
uom.SetSort(val.Document())
105107
case "upsert":
106108
uom.SetUpsert(val.Boolean())
107109
default:
@@ -249,6 +251,8 @@ func createBulkWriteModel(rawModel bson.Raw) (mongo.WriteModel, error) {
249251
return nil, fmt.Errorf("error creating hint: %w", err)
250252
}
251253
rom.SetHint(hint)
254+
case "sort":
255+
rom.SetSort(val.Document())
252256
case "replacement":
253257
replacement = val.Document()
254258
case "upsert":

internal/integration/unified/collection_operation_execution.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1293,6 +1293,8 @@ func executeReplaceOne(ctx context.Context, operation *operation) (*operationRes
12931293
return nil, fmt.Errorf("error creating hint: %w", err)
12941294
}
12951295
opts.SetHint(hint)
1296+
case "sort":
1297+
opts.SetSort(val.Document())
12961298
case "replacement":
12971299
replacement = val.Document()
12981300
case "upsert":

internal/integration/unified/crud_helpers.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,8 @@ func createUpdateOneArguments(args bson.Raw) (*updateArguments, *options.UpdateO
123123
}
124124
case "upsert":
125125
opts.SetUpsert(val.Boolean())
126+
case "sort":
127+
opts.SetSort(val.Document())
126128
default:
127129
return nil, nil, fmt.Errorf("unrecognized update option %q", key)
128130
}

mongo/bulk_write.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -340,6 +340,7 @@ func (bw *bulkWrite) runUpdate(ctx context.Context, batch bulkWriteBatch) (opera
340340
filter: converted.Filter,
341341
update: converted.Replacement,
342342
hint: converted.Hint,
343+
sort: converted.Sort,
343344
collation: converted.Collation,
344345
upsert: converted.Upsert,
345346
}.marshal(bw.collection.bsonOpts, bw.collection.registry)
@@ -349,6 +350,7 @@ func (bw *bulkWrite) runUpdate(ctx context.Context, batch bulkWriteBatch) (opera
349350
filter: converted.Filter,
350351
update: converted.Update,
351352
hint: converted.Hint,
353+
sort: converted.Sort,
352354
arrayFilters: converted.ArrayFilters,
353355
collation: converted.Collation,
354356
upsert: converted.Upsert,
@@ -420,6 +422,7 @@ type updateDoc struct {
420422
filter interface{}
421423
update interface{}
422424
hint interface{}
425+
sort interface{}
423426
arrayFilters []interface{}
424427
collation *options.Collation
425428
upsert *bool
@@ -446,6 +449,16 @@ func (doc updateDoc) marshal(bsonOpts *options.BSONOptions, registry *bson.Regis
446449
if doc.multi {
447450
updateDoc = bsoncore.AppendBooleanElement(updateDoc, "multi", doc.multi)
448451
}
452+
if doc.sort != nil {
453+
if isUnorderedMap(doc.sort) {
454+
return nil, ErrMapForOrderedArgument{"sort"}
455+
}
456+
s, err := marshal(doc.sort, bsonOpts, registry)
457+
if err != nil {
458+
return nil, err
459+
}
460+
updateDoc = bsoncore.AppendDocumentElement(updateDoc, "sort", s)
461+
}
449462

450463
if doc.arrayFilters != nil {
451464
reg := registry

mongo/bulk_write_models.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@ type ReplaceOneModel struct {
125125
Filter interface{}
126126
Replacement interface{}
127127
Hint interface{}
128+
Sort interface{}
128129
}
129130

130131
// NewReplaceOneModel creates a new ReplaceOneModel.
@@ -173,6 +174,14 @@ func (rom *ReplaceOneModel) SetUpsert(upsert bool) *ReplaceOneModel {
173174
return rom
174175
}
175176

177+
// SetSort specifies which document the operation replaces if the query matches multiple documents. The first document
178+
// matched by the sort order will be replaced. This option is only valid for MongoDB versions >= 8.0. The driver will
179+
// return an error if the sort parameter is a multi-key map. The default value is nil.
180+
func (rom *ReplaceOneModel) SetSort(sort interface{}) *ReplaceOneModel {
181+
rom.Sort = sort
182+
return rom
183+
}
184+
176185
func (*ReplaceOneModel) writeModel() {}
177186

178187
// UpdateOneModel is used to update at most one document in a BulkWrite operation.
@@ -183,6 +192,7 @@ type UpdateOneModel struct {
183192
Update interface{}
184193
ArrayFilters []interface{}
185194
Hint interface{}
195+
Sort interface{}
186196
}
187197

188198
// NewUpdateOneModel creates a new UpdateOneModel.
@@ -238,6 +248,14 @@ func (uom *UpdateOneModel) SetUpsert(upsert bool) *UpdateOneModel {
238248
return uom
239249
}
240250

251+
// SetSort specifies which document the operation updates if the query matches multiple documents. The first document
252+
// matched by the sort order will be updated. This option is only valid for MongoDB versions >= 8.0. The driver will
253+
// return an error if the sort parameter is a multi-key map. The default value is nil.
254+
func (uom *UpdateOneModel) SetSort(sort interface{}) *UpdateOneModel {
255+
uom.Sort = sort
256+
return uom
257+
}
258+
241259
func (*UpdateOneModel) writeModel() {}
242260

243261
// UpdateManyModel is used to update multiple documents in a BulkWrite operation.

mongo/collection.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -610,6 +610,7 @@ func (coll *Collection) updateOrReplace(
610610
multi bool,
611611
expectedRr returnResult,
612612
checkDollarKey bool,
613+
sort interface{},
613614
args *options.UpdateManyOptions,
614615
) (*UpdateResult, error) {
615616

@@ -623,6 +624,7 @@ func (coll *Collection) updateOrReplace(
623624
filter: filter,
624625
update: update,
625626
hint: args.Hint,
627+
sort: sort,
626628
arrayFilters: args.ArrayFilters,
627629
collation: args.Collation,
628630
upsert: args.Upsert,
@@ -775,7 +777,7 @@ func (coll *Collection) UpdateOne(
775777
Let: args.Let,
776778
}
777779

778-
return coll.updateOrReplace(ctx, f, update, false, rrOne, true, updateOptions)
780+
return coll.updateOrReplace(ctx, f, update, false, rrOne, true, args.Sort, updateOptions)
779781
}
780782

781783
// UpdateMany executes an update command to update documents in the collection.
@@ -811,7 +813,7 @@ func (coll *Collection) UpdateMany(
811813
return nil, fmt.Errorf("failed to construct options from builder: %w", err)
812814
}
813815

814-
return coll.updateOrReplace(ctx, f, update, true, rrMany, true, args)
816+
return coll.updateOrReplace(ctx, f, update, true, rrMany, true, nil, args)
815817
}
816818

817819
// ReplaceOne executes an update command to replace at most one document in the collection.
@@ -865,7 +867,7 @@ func (coll *Collection) ReplaceOne(
865867
Comment: args.Comment,
866868
}
867869

868-
return coll.updateOrReplace(ctx, f, r, false, rrOne, false, updateOptions)
870+
return coll.updateOrReplace(ctx, f, r, false, rrOne, false, args.Sort, updateOptions)
869871
}
870872

871873
// Aggregate executes an aggregate command against the collection and returns a cursor over the resulting documents.

mongo/options/replaceoptions.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ type ReplaceOptions struct {
1717
Hint interface{}
1818
Upsert *bool
1919
Let interface{}
20+
Sort interface{}
2021
}
2122

2223
// ReplaceOptionsBuilder contains options to configure replace operations. Each
@@ -122,3 +123,18 @@ func (ro *ReplaceOptionsBuilder) SetLet(l interface{}) *ReplaceOptionsBuilder {
122123

123124
return ro
124125
}
126+
127+
// SetSort sets the value for the Sort field. Specifies a document specifying which document should
128+
// be replaced if the filter used by the operation matches multiple documents in the collection. If
129+
// set, the first document in the sorted order will be replaced. This option is only valid for MongoDB
130+
// versions >= 8.0. The driver will return an error if the sort parameter is a multi-key map. The
131+
// default value is nil.
132+
func (ro *ReplaceOptionsBuilder) SetSort(s interface{}) *ReplaceOptionsBuilder {
133+
ro.Opts = append(ro.Opts, func(opts *ReplaceOptions) error {
134+
opts.Sort = s
135+
136+
return nil
137+
})
138+
139+
return ro
140+
}

mongo/options/updateoptions.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ type UpdateOneOptions struct {
1818
Hint interface{}
1919
Upsert *bool
2020
Let interface{}
21+
Sort interface{}
2122
}
2223

2324
// UpdateOneOptionsBuilder contains options to configure UpdateOne operations.
@@ -137,6 +138,21 @@ func (uo *UpdateOneOptionsBuilder) SetLet(l interface{}) *UpdateOneOptionsBuilde
137138
return uo
138139
}
139140

141+
// SetSort sets the value for the Sort field. Specifies a document specifying which document should
142+
// be updated if the filter used by the operation matches multiple documents in the collection. If
143+
// set, the first document in the sorted order will be updated. This option is only valid for MongoDB
144+
// versions >= 8.0. The driver will return an error if the sort parameter is a multi-key map. The
145+
// default value is nil.
146+
func (uo *UpdateOneOptionsBuilder) SetSort(s interface{}) *UpdateOneOptionsBuilder {
147+
uo.Opts = append(uo.Opts, func(opts *UpdateOneOptions) error {
148+
opts.Sort = s
149+
150+
return nil
151+
})
152+
153+
return uo
154+
}
155+
140156
// UpdateManyOptions represents arguments that can be used to configure UpdateMany
141157
// operations.
142158
//

0 commit comments

Comments
 (0)