Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Fix performance of cascading delete. Fixes #1994.

  • Loading branch information...
commit 357cba5ccf40fa733c846c695b9a949328881bbd 1 parent deeadf0
@durran durran authored
View
3  CHANGELOG.md
@@ -7,6 +7,9 @@ For instructions on upgrading to newer versions, visit
### Resolved Issues
+* \#1994 `dependent: :delete` only hits the database once now for one to
+ many and many to many relations instead of once for each document.
+
* \#1976 Don't execute eager load queries when base query is empty.
* \#1953 Uniqueness validation now works on localized fields.
View
12 lib/mongoid/relations/cascading/delete.rb
@@ -27,8 +27,18 @@ def initialize(document, metadata)
#
# @example Perform the cascading delete.
# strategy.cascade
+ #
+ # @since 2.0.0
def cascade
- Array.wrap(relation).each { |doc| doc.delete } if relation
+ if relation
+ if relation.cascades.empty?
+ safety = Threaded.safety_options
+ relation.clear
+ Threaded.safety_options = safety
+ else
+ ::Array.wrap(relation).each { |doc| doc.delete }
+ end
+ end
end
end
end
View
12 lib/mongoid/relations/one.rb
@@ -6,6 +6,18 @@ module Relations #:nodoc:
# behaviour or those proxies.
class One < Proxy
+ # Clear this relation - same as calling #delete on the document.
+ #
+ # @example Clear the relation.
+ # relation.clear
+ #
+ # @return [ true, false ] If the delete suceeded.
+ #
+ # @since 3.0.0
+ def clear
+ target.delete
+ end
+
# Get all the documents in the relation that are loaded into memory.
#
# @example Get the in memory documents.
View
4 spec/app/models/home.rb
@@ -0,0 +1,4 @@
+class Home
+ include Mongoid::Document
+ belongs_to :person
+end
View
1  spec/app/models/person.rb
@@ -107,6 +107,7 @@ def extension
has_many :drugs, :autosave => true, :validate => false
has_one :account, :autosave => true, :validate => false
has_one :cat, :dependent => :nullify
+ has_one :home, :dependent => :delete, :validate => false
has_and_belongs_to_many \
:administrated_events,
View
100 spec/unit/mongoid/relations/cascading/delete_spec.rb
@@ -3,44 +3,98 @@
describe Mongoid::Relations::Cascading::Delete do
let(:person) do
- Person.new
+ Person.create
end
- let(:metadata) do
- stub(:name => :posts)
- end
+ describe "#cascade" do
- let(:strategy) do
- described_class.new(person, metadata)
- end
+ context "when cascading a has one" do
- describe "#cascade" do
+ context "when the relation exists" do
- let(:post) do
- stub
- end
+ let!(:home) do
+ person.create_home
+ end
- context "when the documents exist" do
+ before do
+ person.delete
+ end
- before do
- person.expects(:posts).returns([ post ])
+ it "deletes the relation" do
+ home.should be_destroyed
+ end
+
+ it "persists the deletion" do
+ expect {
+ home.reload
+ }.to raise_error(Mongoid::Errors::DocumentNotFound)
+ end
end
- it "deletes all documents in the relation" do
- post.expects(:delete)
- strategy.cascade
+ context "when the relation does not exist" do
+
+ before do
+ person.delete
+ end
+
+ it "deletes the base document" do
+ person.should be_destroyed
+ end
end
end
+ end
+
+ context "when cascading a has many" do
- context "when no documents exist" do
+ context "when the relation has documents" do
- before do
- person.expects(:posts).returns([])
+ let!(:post_one) do
+ person.posts.create(:title => "one")
end
- it "does not delete anything" do
- post.expects(:delete).never
- strategy.cascade
+ let!(:post_two) do
+ person.posts.create(:title => "two")
+ end
+
+ context "when the documents are in memory" do
+
+ before do
+ post_one.expects(:delete).never
+ post_two.expects(:delete).never
+ person.delete
+ end
+
+ it "deletes the first document" do
+ post_one.should be_destroyed
+ end
+
+ it "deletes the second document" do
+ post_two.should be_destroyed
+ end
+
+ it "unbinds the first document" do
+ post_one.person.should be_nil
+ end
+
+ it "unbinds the second document" do
+ post_two.person.should be_nil
+ end
+
+ it "removes the documents from the relation" do
+ person.posts.should be_empty
+ end
+
+ it "persists the first deletion" do
+ expect {
+ post_one.reload
+ }.to raise_error(Mongoid::Errors::DocumentNotFound)
+ end
+
+ it "persists the second deletion" do
+ expect {
+ post_two.reload
+ }.to raise_error(Mongoid::Errors::DocumentNotFound)
+ end
end
end
end
Please sign in to comment.
Something went wrong with that request. Please try again.