Skip to content

Commit

Permalink
MONGOID-5608 allow using #exists? with args on relations (#5736)
Browse files Browse the repository at this point in the history
* MONGOID-5608 allow using `#exists?` with args on relations

* simplify

* test the nil/false and _id matching paths, too
  • Loading branch information
jamis authored Nov 2, 2023
1 parent 512e165 commit 78fb959
Show file tree
Hide file tree
Showing 4 changed files with 106 additions and 5 deletions.
21 changes: 18 additions & 3 deletions lib/mongoid/association/embedded/embeds_many/proxy.rb
Original file line number Diff line number Diff line change
Expand Up @@ -292,9 +292,24 @@ def destroy_all(conditions = {})
# @example Are there persisted documents?
# person.posts.exists?
#
# @return [ true | false ] True is persisted documents exist, false if not.
def exists?
_target.any?(&:persisted?)
# @param [ :none | nil | false | Hash | Object ] id_or_conditions
# When :none (the default), returns true if any persisted
# documents exist in the association. When nil or false, this
# will always return false. When a Hash is given, this queries
# the documents in the association for those that match the given
# conditions, and returns true if any match which have been
# persisted. Any other argument is interpreted as an id, and
# queries for the existence of persisted documents in the
# association with a matching _id.
#
# @return [ true | false ] True if persisted documents exist, false if not.
def exists?(id_or_conditions = :none)
case id_or_conditions
when :none then _target.any?(&:persisted?)
when nil, false then false
when Hash then where(id_or_conditions).any?(&:persisted?)
else where(_id: id_or_conditions).any?(&:persisted?)
end
end

# Finds a document in this association through several different
Expand Down
13 changes: 11 additions & 2 deletions lib/mongoid/association/referenced/has_many/proxy.rb
Original file line number Diff line number Diff line change
Expand Up @@ -217,9 +217,18 @@ def each(&block)
# @example Are there persisted documents?
# person.posts.exists?
#
# @param [ :none | nil | false | Hash | Object ] id_or_conditions
# When :none (the default), returns true if any persisted
# documents exist in the association. When nil or false, this
# will always return false. When a Hash is given, this queries
# the documents in the association for those that match the given
# conditions, and returns true if any match. Any other argument is
# interpreted as an id, and queries for the existence of documents
# in the association with a matching _id.
#
# @return [ true | false ] True is persisted documents exist, false if not.
def exists?
criteria.exists?
def exists?(id_or_conditions = :none)
criteria.exists?(id_or_conditions)
end

# Find the matching document on the association, either based on id or
Expand Down
35 changes: 35 additions & 0 deletions spec/mongoid/association/embedded/embeds_many/proxy_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2311,9 +2311,37 @@ class TrackingIdValidationHistory
person.addresses.create!(street: "Bond St")
end

let(:address) { person.addresses.first }

it "returns true" do
expect(person.addresses.exists?).to be true
end

context 'when given specifying conditions' do
context 'when the record exists in the association' do
it 'returns true by condition' do
expect(person.addresses.exists?(street: 'Bond St')).to be true
end

it 'returns true by id' do
expect(person.addresses.exists?(address._id)).to be true
end

it 'returns false when given false' do
expect(person.addresses.exists?(false)).to be false
end

it 'returns false when given nil' do
expect(person.addresses.exists?(nil)).to be false
end
end

context 'when the record does not exist in the association' do
it 'returns false' do
expect(person.addresses.exists?(street: 'Garfield Ave')).to be false
end
end
end
end

context "when no documents exist in the database" do
Expand All @@ -2325,6 +2353,13 @@ class TrackingIdValidationHistory
it "returns false" do
expect(person.addresses.exists?).to be false
end

context 'when given specifying conditions' do
it 'returns false' do
expect(person.addresses.exists?(street: 'Hyde Park Dr')).to be false
expect(person.addresses.exists?(street: 'Garfield Ave')).to be false
end
end
end
end

Expand Down
42 changes: 42 additions & 0 deletions spec/mongoid/association/referenced/has_many/proxy_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1924,6 +1924,42 @@ def with_transaction_via(model, &block)
expect_query(1) { expect(person.posts.exists?).to be true }
end
end

context 'when invoked with specifying conditions' do
let(:other_person) { Person.create! }
let(:post) { person.posts.first }

before do
person.posts.create title: 'bumfuzzle'
other_person.posts.create title: 'bumbershoot'
end

context 'when the conditions match an associated record' do
it 'detects its existence by condition' do
expect(person.posts.exists?(title: 'bumfuzzle')).to be true
expect(other_person.posts.exists?(title: 'bumbershoot')).to be true
end

it 'detects its existence by id' do
expect(person.posts.exists?(post._id)).to be true
end

it 'returns false when given false' do
expect(person.posts.exists?(false)).to be false
end

it 'returns false when given nil' do
expect(person.posts.exists?(nil)).to be false
end
end

context 'when the conditions match an unassociated record' do
it 'does not detect its existence' do
expect(person.posts.exists?(title: 'bumbershoot')).to be false
expect(other_person.posts.exists?(title: 'bumfuzzle')).to be false
end
end
end
end

context 'when documents exist in application but not in database' do
Expand Down Expand Up @@ -1972,6 +2008,12 @@ def with_transaction_via(model, &block)
expect_query(1) { expect(person.posts.exists?).to be false }
end
end

context 'when invoked with specifying conditions' do
it 'returns false' do
expect(person.posts.exists?(title: 'hullaballoo')).to be false
end
end
end
end

Expand Down

0 comments on commit 78fb959

Please sign in to comment.