Skip to content

Commit 78fb959

Browse files
authored
MONGOID-5608 allow using #exists? with args on relations (#5736)
* MONGOID-5608 allow using `#exists?` with args on relations * simplify * test the nil/false and _id matching paths, too
1 parent 512e165 commit 78fb959

File tree

4 files changed

+106
-5
lines changed

4 files changed

+106
-5
lines changed

lib/mongoid/association/embedded/embeds_many/proxy.rb

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -292,9 +292,24 @@ def destroy_all(conditions = {})
292292
# @example Are there persisted documents?
293293
# person.posts.exists?
294294
#
295-
# @return [ true | false ] True is persisted documents exist, false if not.
296-
def exists?
297-
_target.any?(&:persisted?)
295+
# @param [ :none | nil | false | Hash | Object ] id_or_conditions
296+
# When :none (the default), returns true if any persisted
297+
# documents exist in the association. When nil or false, this
298+
# will always return false. When a Hash is given, this queries
299+
# the documents in the association for those that match the given
300+
# conditions, and returns true if any match which have been
301+
# persisted. Any other argument is interpreted as an id, and
302+
# queries for the existence of persisted documents in the
303+
# association with a matching _id.
304+
#
305+
# @return [ true | false ] True if persisted documents exist, false if not.
306+
def exists?(id_or_conditions = :none)
307+
case id_or_conditions
308+
when :none then _target.any?(&:persisted?)
309+
when nil, false then false
310+
when Hash then where(id_or_conditions).any?(&:persisted?)
311+
else where(_id: id_or_conditions).any?(&:persisted?)
312+
end
298313
end
299314

300315
# Finds a document in this association through several different

lib/mongoid/association/referenced/has_many/proxy.rb

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -217,9 +217,18 @@ def each(&block)
217217
# @example Are there persisted documents?
218218
# person.posts.exists?
219219
#
220+
# @param [ :none | nil | false | Hash | Object ] id_or_conditions
221+
# When :none (the default), returns true if any persisted
222+
# documents exist in the association. When nil or false, this
223+
# will always return false. When a Hash is given, this queries
224+
# the documents in the association for those that match the given
225+
# conditions, and returns true if any match. Any other argument is
226+
# interpreted as an id, and queries for the existence of documents
227+
# in the association with a matching _id.
228+
#
220229
# @return [ true | false ] True is persisted documents exist, false if not.
221-
def exists?
222-
criteria.exists?
230+
def exists?(id_or_conditions = :none)
231+
criteria.exists?(id_or_conditions)
223232
end
224233

225234
# Find the matching document on the association, either based on id or

spec/mongoid/association/embedded/embeds_many/proxy_spec.rb

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2311,9 +2311,37 @@ class TrackingIdValidationHistory
23112311
person.addresses.create!(street: "Bond St")
23122312
end
23132313

2314+
let(:address) { person.addresses.first }
2315+
23142316
it "returns true" do
23152317
expect(person.addresses.exists?).to be true
23162318
end
2319+
2320+
context 'when given specifying conditions' do
2321+
context 'when the record exists in the association' do
2322+
it 'returns true by condition' do
2323+
expect(person.addresses.exists?(street: 'Bond St')).to be true
2324+
end
2325+
2326+
it 'returns true by id' do
2327+
expect(person.addresses.exists?(address._id)).to be true
2328+
end
2329+
2330+
it 'returns false when given false' do
2331+
expect(person.addresses.exists?(false)).to be false
2332+
end
2333+
2334+
it 'returns false when given nil' do
2335+
expect(person.addresses.exists?(nil)).to be false
2336+
end
2337+
end
2338+
2339+
context 'when the record does not exist in the association' do
2340+
it 'returns false' do
2341+
expect(person.addresses.exists?(street: 'Garfield Ave')).to be false
2342+
end
2343+
end
2344+
end
23172345
end
23182346

23192347
context "when no documents exist in the database" do
@@ -2325,6 +2353,13 @@ class TrackingIdValidationHistory
23252353
it "returns false" do
23262354
expect(person.addresses.exists?).to be false
23272355
end
2356+
2357+
context 'when given specifying conditions' do
2358+
it 'returns false' do
2359+
expect(person.addresses.exists?(street: 'Hyde Park Dr')).to be false
2360+
expect(person.addresses.exists?(street: 'Garfield Ave')).to be false
2361+
end
2362+
end
23282363
end
23292364
end
23302365

spec/mongoid/association/referenced/has_many/proxy_spec.rb

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1924,6 +1924,42 @@ def with_transaction_via(model, &block)
19241924
expect_query(1) { expect(person.posts.exists?).to be true }
19251925
end
19261926
end
1927+
1928+
context 'when invoked with specifying conditions' do
1929+
let(:other_person) { Person.create! }
1930+
let(:post) { person.posts.first }
1931+
1932+
before do
1933+
person.posts.create title: 'bumfuzzle'
1934+
other_person.posts.create title: 'bumbershoot'
1935+
end
1936+
1937+
context 'when the conditions match an associated record' do
1938+
it 'detects its existence by condition' do
1939+
expect(person.posts.exists?(title: 'bumfuzzle')).to be true
1940+
expect(other_person.posts.exists?(title: 'bumbershoot')).to be true
1941+
end
1942+
1943+
it 'detects its existence by id' do
1944+
expect(person.posts.exists?(post._id)).to be true
1945+
end
1946+
1947+
it 'returns false when given false' do
1948+
expect(person.posts.exists?(false)).to be false
1949+
end
1950+
1951+
it 'returns false when given nil' do
1952+
expect(person.posts.exists?(nil)).to be false
1953+
end
1954+
end
1955+
1956+
context 'when the conditions match an unassociated record' do
1957+
it 'does not detect its existence' do
1958+
expect(person.posts.exists?(title: 'bumbershoot')).to be false
1959+
expect(other_person.posts.exists?(title: 'bumfuzzle')).to be false
1960+
end
1961+
end
1962+
end
19271963
end
19281964

19291965
context 'when documents exist in application but not in database' do
@@ -1972,6 +2008,12 @@ def with_transaction_via(model, &block)
19722008
expect_query(1) { expect(person.posts.exists?).to be false }
19732009
end
19742010
end
2011+
2012+
context 'when invoked with specifying conditions' do
2013+
it 'returns false' do
2014+
expect(person.posts.exists?(title: 'hullaballoo')).to be false
2015+
end
2016+
end
19752017
end
19762018
end
19772019

0 commit comments

Comments
 (0)