Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
qingyang-hu committed Aug 23, 2024
1 parent 8dc4e78 commit 2bdacda
Show file tree
Hide file tree
Showing 10 changed files with 445 additions and 1 deletion.
9 changes: 8 additions & 1 deletion mongo/collection.go
Original file line number Diff line number Diff line change
Expand Up @@ -598,7 +598,13 @@ func (coll *Collection) updateOrReplace(ctx context.Context, filter bsoncore.Doc
}
op = op.Let(let)
}

if !multi && uo.Sort != nil {
sort, err := marshal(uo.Sort, coll.bsonOpts, coll.registry)
if err != nil {
return nil, err
}
op = op.Sort(sort)
}
if uo.BypassDocumentValidation != nil && *uo.BypassDocumentValidation {
op = op.BypassDocumentValidation(*uo.BypassDocumentValidation)
}
Expand Down Expand Up @@ -759,6 +765,7 @@ func (coll *Collection) ReplaceOne(ctx context.Context, filter interface{},
uOpts.Upsert = opt.Upsert
uOpts.Hint = opt.Hint
uOpts.Let = opt.Let
uOpts.Sort = opt.Sort
uOpts.Comment = opt.Comment
updateOptions = append(updateOptions, uOpts)
}
Expand Down
20 changes: 20 additions & 0 deletions mongo/integration/crud_helpers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,20 @@ func createHint(mt *mtest.T, val bson.RawValue) interface{} {
return hint
}

// create a sort document from a bson.RawValue
func createSort(mt *mtest.T, val bson.RawValue) interface{} {
mt.Helper()

var sort interface{}
switch val.Type {
case bsontype.EmbeddedDocument:
sort = val.Document()
default:
mt.Fatalf("unrecognized sort value type: %s\n", val.Type)
}
return sort
}

// returns true if err is a mongo.CommandError containing a code that is expected from a killAllSessions command.
func isExpectedKillAllSessionsError(err error) bool {
cmdErr, ok := err.(mongo.CommandError)
Expand Down Expand Up @@ -890,6 +904,8 @@ func executeUpdateOne(mt *mtest.T, sess mongo.Session, args bson.Raw) (*mongo.Up
opts = opts.SetCollation(createCollation(mt, val.Document()))
case "hint":
opts = opts.SetHint(createHint(mt, val))
case "sort":
opts = opts.SetSort(createSort(mt, val))
case "session":
default:
mt.Fatalf("unrecognized updateOne option: %v", key)
Expand Down Expand Up @@ -938,6 +954,8 @@ func executeUpdateMany(mt *mtest.T, sess mongo.Session, args bson.Raw) (*mongo.U
opts = opts.SetCollation(createCollation(mt, val.Document()))
case "hint":
opts = opts.SetHint(createHint(mt, val))
case "sort":
opts = opts.SetSort(createSort(mt, val))
case "session":
default:
mt.Fatalf("unrecognized updateMany option: %v", key)
Expand Down Expand Up @@ -982,6 +1000,8 @@ func executeReplaceOne(mt *mtest.T, sess mongo.Session, args bson.Raw) (*mongo.U
opts = opts.SetCollation(createCollation(mt, val.Document()))
case "hint":
opts = opts.SetHint(createHint(mt, val))
case "sort":
opts = opts.SetSort(createSort(mt, val))
case "session":
default:
mt.Fatalf("unrecognized replaceOne option: %v", key)
Expand Down
2 changes: 2 additions & 0 deletions mongo/integration/unified/crud_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ func createUpdateArguments(args bson.Raw) (*updateArguments, error) {
ua.opts.SetHint(hint)
case "let":
ua.opts.SetLet(val.Document())
case "sort":
ua.opts.SetSort(val.Document())
case "update":
ua.update, err = createUpdateValue(val)
if err != nil {
Expand Down
15 changes: 15 additions & 0 deletions mongo/options/replaceoptions.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,12 @@ type ReplaceOptions struct {
// Values must be constant or closed expressions that do not reference document fields. Parameters can then be
// accessed as variables in an aggregate expression context (e.g. "$$var").
Let interface{}

// A document specifying which document should be replaced if the filter used by the operation matches multiple
// documents in the collection. If set, the first document in the sorted order will be updated. This option is
// only valid for MongoDB versions >= 8.0. The driver will return an error if the sort parameter is a multi-key
// map. The default value is nil.
Sort interface{}
}

// Replace creates a new ReplaceOptions instance.
Expand Down Expand Up @@ -83,6 +89,12 @@ func (ro *ReplaceOptions) SetLet(l interface{}) *ReplaceOptions {
return ro
}

// SetSort sets the value for the Sort field.
func (ro *ReplaceOptions) SetSort(s interface{}) *ReplaceOptions {
ro.Sort = s
return ro
}

// MergeReplaceOptions combines the given ReplaceOptions instances into a single ReplaceOptions in a last-one-wins
// fashion.
//
Expand Down Expand Up @@ -112,6 +124,9 @@ func MergeReplaceOptions(opts ...*ReplaceOptions) *ReplaceOptions {
if ro.Let != nil {
rOpts.Let = ro.Let
}
if ro.Sort != nil {
rOpts.Sort = ro.Sort
}
}

return rOpts
Expand Down
15 changes: 15 additions & 0 deletions mongo/options/updateoptions.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,12 @@ type UpdateOptions struct {
// Values must be constant or closed expressions that do not reference document fields. Parameters can then be
// accessed as variables in an aggregate expression context (e.g. "$$var").
Let interface{}

// A document specifying which document should be updated if the filter used by the operation matches multiple
// documents in the collection. If set, the first document in the sorted order will be updated. This option is
// only valid for MongoDB versions >= 8.0. The driver will return an error if the sort parameter is a multi-key
// map. The default value is nil.
Sort interface{}
}

// Update creates a new UpdateOptions instance.
Expand Down Expand Up @@ -94,6 +100,12 @@ func (uo *UpdateOptions) SetLet(l interface{}) *UpdateOptions {
return uo
}

// SetSort sets the value for the Sort field.
func (uo *UpdateOptions) SetSort(s interface{}) *UpdateOptions {
uo.Sort = s
return uo
}

// MergeUpdateOptions combines the given UpdateOptions instances into a single UpdateOptions in a last-one-wins fashion.
//
// Deprecated: Merging options structs will not be supported in Go Driver 2.0. Users should create a
Expand Down Expand Up @@ -125,6 +137,9 @@ func MergeUpdateOptions(opts ...*UpdateOptions) *UpdateOptions {
if uo.Let != nil {
uOpts.Let = uo.Let
}
if uo.Sort != nil {
uOpts.Sort = uo.Sort
}
}

return uOpts
Expand Down
125 changes: 125 additions & 0 deletions testdata/command-monitoring/updateMany-sort.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
{
"description": "updateMany",
"schemaVersion": "1.0",
"runOnRequirements": [
{
"minServerVersion": "8.0"
}
],
"createEntities": [
{
"client": {
"id": "client",
"observeEvents": [
"commandStartedEvent",
"commandSucceededEvent",
"commandFailedEvent"
]
}
},
{
"database": {
"id": "database",
"client": "client",
"databaseName": "command-monitoring-tests"
}
},
{
"collection": {
"id": "collection",
"database": "database",
"collectionName": "test"
}
}
],
"initialData": [
{
"collectionName": "test",
"databaseName": "command-monitoring-tests",
"documents": [
{
"_id": 1,
"x": 11
},
{
"_id": 2,
"x": 22
},
{
"_id": 3,
"x": 33
}
]
}
],
"tests": [
{
"description": "A successful updateMany with sort",
"operations": [
{
"name": "updateMany",
"object": "collection",
"arguments": {
"filter": {
"_id": {
"$gt": 1
}
},
"sort": {
"_id": -1
},
"update": {
"$inc": {
"x": 1
}
}
}
}
],
"expectEvents": [
{
"client": "client",
"events": [
{
"commandStartedEvent": {
"command": {
"update": "test",
"updates": [
{
"q": {
"_id": {
"$gt": 1
}
},
"u": {
"$inc": {
"x": 1
}
},
"upsert": {
"$$unsetOrMatches": false
},
"multi": true
}
],
"ordered": true
},
"commandName": "update",
"databaseName": "command-monitoring-tests"
}
},
{
"commandSucceededEvent": {
"reply": {
"ok": 1,
"n": 2
},
"commandName": "update"
}
}
]
}
]
}
]
}
57 changes: 57 additions & 0 deletions testdata/command-monitoring/updateMany-sort.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
description: "updateMany"

schemaVersion: "1.0"

runOnRequirements:
- minServerVersion: "8.0"

createEntities:
- client:
id: &client client
observeEvents:
- commandStartedEvent
- commandSucceededEvent
- commandFailedEvent
- database:
id: &database database
client: *client
databaseName: &databaseName command-monitoring-tests
- collection:
id: &collection collection
database: *database
collectionName: &collectionName test

initialData:
- collectionName: *collectionName
databaseName: *databaseName
documents:
- { _id: 1, x: 11 }
- { _id: 2, x: 22 }
- { _id: 3, x: 33 }

tests:
- description: "A successful updateMany with sort"
operations:
- name: updateMany
object: *collection
arguments:
filter: { _id: { $gt: 1 } }
sort: { _id: -1 }
update: { $inc: { x: 1 } }
expectEvents:
- client: *client
events:
- commandStartedEvent:
command:
update: *collectionName
updates:
- q: { _id: { $gt: 1 } }
u: { $inc: { x: 1 } }
upsert: { $$unsetOrMatches: false }
multi: true
ordered: true
commandName: update
databaseName: *databaseName
- commandSucceededEvent:
reply: { ok: 1, n: 2 }
commandName: update
Loading

0 comments on commit 2bdacda

Please sign in to comment.