Skip to content

Commit bd7689a

Browse files
authored
don't assume id_sort key exists (#5528)
1 parent e87cacc commit bd7689a

File tree

2 files changed

+47
-10
lines changed

2 files changed

+47
-10
lines changed

lib/mongoid/contextual/mongo.rb

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -260,16 +260,16 @@ def find_one_and_delete
260260
#
261261
# @return [ Document ] The first document.
262262
def first(limit_or_opts = nil)
263-
limit = limit_or_opts unless limit_or_opts.is_a?(Hash)
263+
limit, opts = extract_limit_and_opts(limit_or_opts)
264264
if cached? && cache_loaded?
265265
return limit ? documents.first(limit) : documents.first
266266
end
267267
try_numbered_cache(:first, limit) do
268-
if limit_or_opts.try(:key?, :id_sort)
268+
if opts.key?(:id_sort)
269269
Mongoid::Warnings.warn_id_sort_deprecated
270270
end
271271
sorted_view = view
272-
if sort = view.sort || ({ _id: 1 } unless limit_or_opts.try(:fetch, :id_sort) == :none)
272+
if sort = view.sort || ({ _id: 1 } unless opts[:id_sort] == :none)
273273
sorted_view = view.sort(sort)
274274
end
275275
if raw_docs = sorted_view.limit(limit || 1).to_a
@@ -376,12 +376,12 @@ def initialize(criteria)
376376
#
377377
# @return [ Document ] The last document.
378378
def last(limit_or_opts = nil)
379-
limit = limit_or_opts unless limit_or_opts.is_a?(Hash)
379+
limit, opts = extract_limit_and_opts(limit_or_opts)
380380
if cached? && cache_loaded?
381381
return limit ? documents.last(limit) : documents.last
382382
end
383383
res = try_numbered_cache(:last, limit) do
384-
with_inverse_sorting(limit_or_opts) do
384+
with_inverse_sorting(opts) do
385385
if raw_docs = view.limit(limit || 1).to_a
386386
process_raw_docs(raw_docs, limit)
387387
end
@@ -612,6 +612,23 @@ def try_numbered_cache(key, n, &block)
612612
end
613613
end
614614

615+
# Extract the limit and opts from the given argument, so that code
616+
# can operate without having to worry about the current type and
617+
# state of the argument.
618+
#
619+
# @param [ nil | Integer | Hash ] limit_or_opts The value to pull the
620+
# limit and option hash from.
621+
#
622+
# @return [ Array<nil | Integer, Hash> ] A 2-array of the limit and the
623+
# option hash.
624+
def extract_limit_and_opts(limit_or_opts)
625+
case limit_or_opts
626+
when nil, Integer then [ limit_or_opts, {} ]
627+
when Hash then [ nil, limit_or_opts ]
628+
else raise ArgumentError, "expected nil, Integer, or Hash"
629+
end
630+
end
631+
615632
# Update the documents for the provided method.
616633
#
617634
# @api private
@@ -676,10 +693,10 @@ def apply_option(name)
676693
# @example Apply the inverse sorting params to the given block
677694
# context.with_inverse_sorting
678695
def with_inverse_sorting(opts = {})
679-
Mongoid::Warnings.warn_id_sort_deprecated if opts.try(:key?, :id_sort)
696+
Mongoid::Warnings.warn_id_sort_deprecated if opts.key?(:id_sort)
680697

681698
begin
682-
if sort = criteria.options[:sort] || ( { _id: 1 } unless opts.try(:fetch, :id_sort) == :none )
699+
if sort = criteria.options[:sort] || ( { _id: 1 } unless opts[:id_sort] == :none )
683700
@view = view.sort(Hash[sort.map{|k, v| [k, -1*v]}])
684701
end
685702
yield

spec/mongoid/contextual/mongo_spec.rb

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1554,9 +1554,9 @@
15541554
expect(context.send(method)).to eq(depeche_mode)
15551555
end
15561556

1557-
context 'when calling #last' do
1557+
context "when calling ##{method}" do
15581558

1559-
it 'returns the last document, sorted by _id' do
1559+
it 'returns the requested document, sorted by _id' do
15601560
expect(context.send(method)).to eq(depeche_mode)
15611561
expect(context.last).to eq(rolling_stones)
15621562
end
@@ -1571,7 +1571,7 @@
15711571
expect(context.send(method, opts)).to eq(depeche_mode)
15721572
end
15731573

1574-
context 'when calling #last' do
1574+
context "when calling ##{method}" do
15751575

15761576
it 'doesn\'t apply a sort on _id' do
15771577
expect(context.send(method, opts)).to eq(depeche_mode)
@@ -1883,6 +1883,16 @@
18831883
end
18841884
end
18851885

1886+
context "when given an empty hash" do
1887+
let(:context) { described_class.new(criteria) }
1888+
let(:criteria) { Band.criteria }
1889+
let(:docs) { context.send(method, {}) }
1890+
1891+
it "behaves as if limit is nil" do
1892+
expect(docs).to eq(depeche_mode)
1893+
end
1894+
end
1895+
18861896
context "when calling #first then #last" do
18871897

18881898
let(:context) do
@@ -2358,6 +2368,16 @@
23582368
end
23592369
end
23602370
end
2371+
2372+
context "when given an empty hash" do
2373+
let(:context) { described_class.new(criteria) }
2374+
let(:criteria) { Band.criteria }
2375+
let(:docs) { context.last({}) }
2376+
2377+
it "behaves as if limit is nil" do
2378+
expect(docs).to eq(rolling_stones)
2379+
end
2380+
end
23612381
end
23622382

23632383
describe "#initialize" do

0 commit comments

Comments
 (0)