Skip to content

RUBY-3520 Sort option for updateOne and replaceOne #2938

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 3 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions lib/mongo/bulk_write/transformable.rb
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ module Transformable
d['upsert'] = true if doc[:upsert]
d[Operation::COLLATION] = doc[:collation] if doc[:collation]
d['hint'] = doc[:hint] if doc[:hint]
d['sort'] = doc[:sort] if doc[:sort]
end
}

Expand Down Expand Up @@ -130,6 +131,7 @@ module Transformable
d[Operation::COLLATION] = doc[:collation] if doc[:collation]
d[Operation::ARRAY_FILTERS] = doc[:array_filters] if doc[:array_filters]
d['hint'] = doc[:hint] if doc[:hint]
d['sort'] = doc[:sort] if doc[:sort]
end
}

Expand Down
10 changes: 10 additions & 0 deletions lib/mongo/collection.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1049,6 +1049,11 @@ def parallel_scan(cursor_count, options = {})
# May be specified as a Hash (e.g. { _id: 1 }) or a String (e.g. "_id_").
# @option options [ Hash ] :let Mapping of variables to use in the command.
# See the server documentation for details.
# @option opts [ Hash ] :sort Specifies which document the operation
# replaces if the query matches multiple documents. The first document
# matched by the sort order will be replaced.
# This option is only supported by servers >= 8.0. Older servers will
# report an error for using this option.
#
# @return [ Result ] The response from the database.
#
Expand Down Expand Up @@ -1115,6 +1120,11 @@ def update_many(filter, update, options = {})
# May be specified as a Hash (e.g. { _id: 1 }) or a String (e.g. "_id_").
# @option options [ Hash ] :let Mapping of variables to use in the command.
# See the server documentation for details.
# @option opts [ Hash ] :sort Specifies which document the operation
# updates if the query matches multiple documents. The first document
# matched by the sort order will be updated.
# This option is only supported by servers >= 8.0. Older servers will
# report an error for using this option.
#
# @return [ Result ] The response from the database.
#
Expand Down
12 changes: 12 additions & 0 deletions lib/mongo/collection/view/writable.rb
Original file line number Diff line number Diff line change
Expand Up @@ -389,6 +389,11 @@ def delete_one(opts = {})
# @option opts [ true, false ] :upsert Whether to upsert if the
# document doesn't exist.
# Can be :w => Integer, :fsync => Boolean, :j => Boolean.
# @option opts [ Hash ] :sort Specifies which document the operation
# replaces if the query matches multiple documents. The first document
# matched by the sort order will be replaced.
# This option is only supported by servers >= 8.0. Older servers will
# report an error for using this option.
#
# @return [ Result ] The response from the database.
#
Expand All @@ -410,6 +415,7 @@ def replace_one(replacement, opts = {})
Operation::U => replacement,
hint: opts[:hint],
collation: opts[:collation] || opts['collation'] || collation,
sort: opts[:sort] || opts['sort'],
}.compact
if opts[:upsert]
update_doc['upsert'] = true
Expand Down Expand Up @@ -549,6 +555,11 @@ def update_many(spec, opts = {})
# document doesn't exist.
# @option opts [ Hash ] :write_concern The write concern options.
# Can be :w => Integer, :fsync => Boolean, :j => Boolean.
# @option opts [ Hash ] :sort Specifies which document the operation
# updates if the query matches multiple documents. The first document
# matched by the sort order will be updated.
# This option is only supported by servers >= 8.0. Older servers will
# report an error for using this option.
#
# @return [ Result ] The response from the database.
#
Expand All @@ -570,6 +581,7 @@ def update_one(spec, opts = {})
Operation::U => spec,
hint: opts[:hint],
collation: opts[:collation] || opts['collation'] || collation,
sort: opts[:sort] || opts['sort'],
}.compact
if opts[:upsert]
update_doc['upsert'] = true
Expand Down
9 changes: 7 additions & 2 deletions spec/runners/unified/crud_operations.rb
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,8 @@ def update_one(op)
hint: args.use('hint'),
upsert: args.use('upsert'),
timeout_ms: args.use('timeoutMS'),
max_time_ms: args.use('maxTimeMS')
max_time_ms: args.use('maxTimeMS'),
sort: args.use('sort')
}
if session = args.use('session')
opts[:session] = entities.get(:session, session)
Expand Down Expand Up @@ -228,7 +229,8 @@ def replace_one(op)
let: args.use('let'),
hint: args.use('hint'),
timeout_ms: args.use('timeoutMS'),
max_time_ms: args.use('maxTimeMS')
max_time_ms: args.use('maxTimeMS'),
sort: args.use('sort'),
)
end
end
Expand Down Expand Up @@ -358,6 +360,9 @@ def convert_bulk_write_spec(spec)
else
raise NotImplementedError, "Unknown operation #{op}"
end
if %w[ updateOne replaceOne ].include?(op)
out[:sort] = spec.use('sort') if spec.key?('sort')
end
unless spec.empty?
raise NotImplementedError, "Unhandled keys: #{spec}"
end
Expand Down
94 changes: 94 additions & 0 deletions spec/spec_tests/data/crud_unified/bulkWrite-replaceOne-sort.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
description: BulkWrite replaceOne-sort

schemaVersion: "1.0"

createEntities:
- client:
id: &client0 client0
observeEvents: [ commandStartedEvent, commandSucceededEvent ]
- database:
id: &database0 database0
client: *client0
databaseName: &database0Name crud-tests
- collection:
id: &collection0 collection0
database: *database0
collectionName: &collection0Name coll0

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

tests:
- description: BulkWrite replaceOne with sort option
runOnRequirements:
- minServerVersion: "8.0"
operations:
- object: *collection0
name: bulkWrite
arguments:
requests:
- replaceOne:
filter: { _id: { $gt: 1 } }
sort: { _id: -1 }
replacement: { x: 1 }
expectEvents:
- client: *client0
events:
- commandStartedEvent:
command:
update: *collection0Name
updates:
- q: { _id: { $gt: 1 } }
u: { x: 1 }
sort: { _id: -1 }
multi: { $$unsetOrMatches: false }
upsert: { $$unsetOrMatches: false }
- commandSucceededEvent:
reply: { ok: 1, n: 1 }
commandName: update
outcome:
- collectionName: *collection0Name
databaseName: *database0Name
documents:
- { _id: 1, x: 11 }
- { _id: 2, x: 22 }
- { _id: 3, x: 1 }

- description: BulkWrite replaceOne with sort option unsupported (server-side error)
runOnRequirements:
- maxServerVersion: "7.99"
operations:
- object: *collection0
name: bulkWrite
arguments:
requests:
- replaceOne:
filter: { _id: { $gt: 1 } }
sort: { _id: -1 }
replacement: { x: 1 }
expectError:
isClientError: false
expectEvents:
- client: *client0
events:
- commandStartedEvent:
command:
update: *collection0Name
updates:
- q: { _id: { $gt: 1 } }
u: { x: 1 }
sort: { _id: -1 }
multi: { $$unsetOrMatches: false }
upsert: { $$unsetOrMatches: false }
outcome:
- collectionName: *collection0Name
databaseName: *database0Name
documents:
- { _id: 1, x: 11 }
- { _id: 2, x: 22 }
- { _id: 3, x: 33 }
94 changes: 94 additions & 0 deletions spec/spec_tests/data/crud_unified/bulkWrite-updateOne-sort.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
description: BulkWrite updateOne-sort

schemaVersion: "1.0"

createEntities:
- client:
id: &client0 client0
observeEvents: [ commandStartedEvent, commandSucceededEvent ]
- database:
id: &database0 database0
client: *client0
databaseName: &database0Name crud-tests
- collection:
id: &collection0 collection0
database: *database0
collectionName: &collection0Name coll0

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

tests:
- description: BulkWrite updateOne with sort option
runOnRequirements:
- minServerVersion: "8.0"
operations:
- object: *collection0
name: bulkWrite
arguments:
requests:
- updateOne:
filter: { _id: { $gt: 1 } }
sort: { _id: -1 }
update: [ $set: { x: 1 } ]
expectEvents:
- client: *client0
events:
- commandStartedEvent:
command:
update: *collection0Name
updates:
- q: { _id: { $gt: 1 } }
u: [ $set: { x: 1 } ]
sort: { _id: -1 }
multi: { $$unsetOrMatches: false }
upsert: { $$unsetOrMatches: false }
- commandSucceededEvent:
reply: { ok: 1, n: 1 }
commandName: update
outcome:
- collectionName: *collection0Name
databaseName: *database0Name
documents:
- { _id: 1, x: 11 }
- { _id: 2, x: 22 }
- { _id: 3, x: 1 }

- description: BulkWrite updateOne with sort option unsupported (server-side error)
runOnRequirements:
- maxServerVersion: "7.99"
operations:
- object: *collection0
name: bulkWrite
arguments:
requests:
- updateOne:
filter: { _id: { $gt: 1 } }
sort: { _id: -1 }
update: [ $set: { x: 1 } ]
expectError:
isClientError: false
expectEvents:
- client: *client0
events:
- commandStartedEvent:
command:
update: *collection0Name
updates:
- q: { _id: { $gt: 1 } }
u: [ $set: { x: 1 } ]
sort: { _id: -1 }
multi: { $$unsetOrMatches: false }
upsert: { $$unsetOrMatches: false }
outcome:
- collectionName: *collection0Name
databaseName: *database0Name
documents:
- { _id: 1, x: 11 }
- { _id: 2, x: 22 }
- { _id: 3, x: 33 }
94 changes: 94 additions & 0 deletions spec/spec_tests/data/crud_unified/replaceOne-sort.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
description: replaceOne-sort

schemaVersion: "1.0"

createEntities:
- client:
id: &client0 client0
observeEvents: [ commandStartedEvent, commandSucceededEvent ]
- database:
id: &database0 database0
client: *client0
databaseName: &database0Name crud-tests
- collection:
id: &collection0 collection0
database: *database0
collectionName: &collection0Name coll0

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

tests:
- description: ReplaceOne with sort option
runOnRequirements:
- minServerVersion: "8.0"
operations:
- name: replaceOne
object: *collection0
arguments:
filter: { _id: { $gt: 1 } }
sort: { _id: -1 }
replacement: { x: 1 }
expectResult:
matchedCount: 1
modifiedCount: 1
upsertedCount: 0
expectEvents:
- client: *client0
events:
- commandStartedEvent:
command:
update: *collection0Name
updates:
- q: { _id: { $gt: 1 } }
u: { x: 1 }
sort: { _id: -1 }
multi: { $$unsetOrMatches: false }
upsert: { $$unsetOrMatches: false }
- commandSucceededEvent:
reply: { ok: 1, n: 1 }
commandName: update
outcome:
- collectionName: *collection0Name
databaseName: *database0Name
documents:
- { _id: 1, x: 11 }
- { _id: 2, x: 22 }
- { _id: 3, x: 1 }

- description: replaceOne with sort option unsupported (server-side error)
runOnRequirements:
- maxServerVersion: "7.99"
operations:
- name: replaceOne
object: *collection0
arguments:
filter: { _id: { $gt: 1 } }
sort: { _id: -1 }
replacement: { x: 1 }
expectError:
isClientError: false
expectEvents:
- client: *client0
events:
- commandStartedEvent:
command:
update: *collection0Name
updates:
- q: { _id: { $gt: 1 } }
u: { x: 1 }
sort: { _id: -1 }
multi: { $$unsetOrMatches: false }
upsert: { $$unsetOrMatches: false }
outcome:
- collectionName: *collection0Name
databaseName: *database0Name
documents:
- { _id: 1, x: 11 }
- { _id: 2, x: 22 }
- { _id: 3, x: 33 }
Loading