Skip to content
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

MONGOID-5608 allow using #exists? with args on relations #5736

Merged
merged 3 commits into from
Nov 2, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
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
18 changes: 16 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,23 @@ 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)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not:

delegate :exists?, to: :criteria

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That would work, too. In general I'm not a fan of that style. It tends to stymie investigation into execution flow, at least for me. I'll think about it, though.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

case id_or_conditions
when :none then criteria.exists?
when nil, false then false
when Hash then criteria.where(id_or_conditions).exists?
else criteria.where(_id: id_or_conditions).exists?
end
jamis marked this conversation as resolved.
Show resolved Hide resolved
end

# Find the matching document on the association, either based on id or
Expand Down
21 changes: 21 additions & 0 deletions spec/mongoid/association/embedded/embeds_many/proxy_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2314,6 +2314,20 @@ class TrackingIdValidationHistory
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' do
expect(person.addresses.exists?(street: 'Bond St')).to be true
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 +2339,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
29 changes: 29 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,29 @@ 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! }

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' do
expect(person.posts.exists?(title: 'bumfuzzle')).to be true
expect(other_person.posts.exists?(title: 'bumbershoot')).to be true
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 +1995,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
Loading