Skip to content

Commit

Permalink
Mongoid::Paranoia should respect unscoped and scoped. Fixes #1064
Browse files Browse the repository at this point in the history
  • Loading branch information
durran committed Jul 31, 2011
1 parent 73a3503 commit 84702e9
Show file tree
Hide file tree
Showing 3 changed files with 144 additions and 50 deletions.
14 changes: 13 additions & 1 deletion CHANGELOG.rdoc
Expand Up @@ -2,7 +2,16 @@

For instructions on upgrading to newer versions, visit {mongoid.org}[http://mongoid.org/docs/upgrading.html].

== 2.1.0 (unreleased)
== 2.1.1

* #1021, #719 Many to many relations dont trigger extra database queries when
pushing new documents.

* #607 Calling create on large associations does not load the entire relation.

* #1064 Mongoid::Paranoia should respect unscoped and scoped.

== 2.1.0

=== Major Changes

Expand All @@ -26,6 +35,9 @@ For instructions on upgrading to newer versions, visit {mongoid.org}[http://mong
* :autosave => true on relational associations now saves on update as well as
create.

* Mongoid now has an identity map for simple find by id queries. See the
website for documentation.

=== New Features

* #1067 Fields now accept a :versioned attribute to be able to disable what
Expand Down
5 changes: 3 additions & 2 deletions lib/mongoid/paranoia.rb
Expand Up @@ -56,6 +56,7 @@ def remove(options = {})
#
# @example Is the document destroyed?
# person.destroyed?

#
# @return [ true, false ] If the document is destroyed.
def destroyed?
Expand Down Expand Up @@ -83,8 +84,8 @@ module ClassMethods #:nodoc:
# @param [ Array ] args The arguments.
#
# @return [ Criteria ] The paranoid compliant criteria.
def criteria(*args)
super.where(:deleted_at.exists => false)
def criteria(embedded = false, scoped = true)
scoped ? super.where(:deleted_at.exists => false) : super
end

# Find deleted documents
Expand Down
175 changes: 128 additions & 47 deletions spec/unit/mongoid/paranoia_spec.rb
Expand Up @@ -3,140 +3,221 @@
describe Mongoid::Paranoia do

let(:collection) do
stub.quacks_like(Mongoid::Collection.allocate)
stub
end

let(:command) do
stub.quacks_like(Mongoid::Persistence::Operations::Remove.allocate)
stub
end

let(:remove_klass) do
Mongoid::Persistence::Operations::Remove
end

describe "#delete!" do

before do
@post = ParanoidPost.new
let(:post) do
ParanoidPost.new
end

it "removes the document from the database" do
Mongoid::Persistence::Operations::Remove.expects(:new).with(@post, {}).returns(command)
remove_klass.expects(:new).with(post, {}).returns(command)
command.expects(:persist).returns(true)
@post.delete!
post.delete!
end

it "sets destroyed to true" do
Mongoid::Persistence::Operations::Remove.expects(:new).with(@post, {}).returns(command)
remove_klass.expects(:new).with(post, {}).returns(command)
command.expects(:persist).returns(true)
@post.delete!
@post.destroyed?.should == true
post.delete!
post.should be_destroyed
end
end

describe "#destroyed?" do

context "when the document was marked as deleted" do

before do
@post = ParanoidPost.new
@post.deleted_at = Time.now
let(:post) do
ParanoidPost.new(:deleted_at => Time.now)
end

it "returns true" do
@post.destroyed?.should == true
post.should be_destroyed
end
end

context "when the document was not marked as deleted" do

before do
@post = ParanoidPost.new
let(:post) do
ParanoidPost.new
end

it "returns true" do
@post.destroyed?.should == false
it "returns false" do
post.should_not be_destroyed
end
end
end

describe "#destroy" do

let(:post) do
ParanoidPost.new
end

let!(:time) do
Time.now
end

before do
@post = ParanoidPost.new
@post.expects(:collection).returns(collection)
@time = Time.now
Time.stubs(:now).returns(@time)
post.expects(:collection).returns(collection)
Time.stubs(:now).returns(time)
end

it "sets the deleted_at flag in the database" do
it "updates the document in the datadase" do
collection.expects(:update).with(
{ :_id => @post.id }, { "$set" => { :deleted_at => @time } }
{ :_id => post.id }, { "$set" => { :deleted_at => time } }
).returns(true)
@post.destroy
post.destroy
end

it "sets the deleted flag" do
collection.expects(:update).with(
{ :_id => @post.id }, { "$set" => { :deleted_at => @time } }
{ :_id => post.id }, { "$set" => { :deleted_at => time } }
).returns(true)
@post.destroy
@post.destroyed?.should == true
post.destroy
post.should be_destroyed
end
end

describe "#remove" do

let(:post) do
ParanoidPost.new
end

let!(:time) do
Time.now
end

before do
@post = ParanoidPost.new
@post.expects(:collection).returns(collection)
@time = Time.now
Time.stubs(:now).returns(@time)
post.expects(:collection).returns(collection)
Time.stubs(:now).returns(time)
end

it "sets the deleted_at flag in the database" do
collection.expects(:update).with(
{ :_id => @post.id }, { "$set" => { :deleted_at => @time } }
{ :_id => post.id }, { "$set" => { :deleted_at => time } }
).returns(true)
@post.remove
post.remove
end

it "sets the deleted flag" do
collection.expects(:update).with(
{ :_id => @post.id }, { "$set" => { :deleted_at => @time } }
{ :_id => post.id }, { "$set" => { :deleted_at => time } }
).returns(true)
@post.remove
@post.destroyed?.should == true
post.remove
post.should be_destroyed
end
end

describe "#restore" do

let(:post) do
ParanoidPost.new
end

let!(:time) do
Time.now
end

before do
@post = ParanoidPost.new(:deleted_at => Time.now)
@post.expects(:collection).returns(collection)
@time = Time.now
Time.stubs(:now).returns(@time)
post.expects(:collection).returns(collection)
Time.stubs(:now).returns(time)
end

it "removes the deleted_at flag from the database" do
collection.expects(:update).with(
{ :_id => @post.id }, { "$unset" => { :deleted_at => true } }
{ :_id => post.id }, { "$unset" => { :deleted_at => true } }
).returns(true)
@post.restore
post.restore
end

it "removes the deleted flag" do
collection.expects(:update).with(
{ :_id => @post.id }, { "$unset" => { :deleted_at => true } }
{ :_id => post.id }, { "$unset" => { :deleted_at => true } }
).returns(true)
@post.restore
@post.destroyed?.should == false
post.restore
post.should_not be_destroyed
end
end

describe ".criteria" do

it "passes along all arguments to super" do
ParanoidPost.criteria(false, true)
context "when setting embedded to true" do

let(:criteria) do
ParanoidPost.criteria(true, true)
end

it "returns an embedded criteria" do
criteria.embedded.should be_true
end
end

context "when setting embedded to false" do

let(:criteria) do
ParanoidPost.criteria(false, true)
end

it "returns an root criteria" do
criteria.embedded.should be_false
end
end

context "when setting scoped to true" do

let(:criteria) do
ParanoidPost.criteria(false, true)
end

it "returns a scoped criteria" do
criteria.selector.should eq({ :deleted_at => { "$exists" => false }})
end
end

context "when setting scoped to false" do

let(:criteria) do
ParanoidPost.criteria(false, false)
end

it "returns an scoped criteria" do
criteria.selector.should eq({})
end
end
end

describe ".scoped" do

let(:scoped) do
ParanoidPost.scoped
end

it "returns a scoped criteria" do
scoped.selector.should eq({ :deleted_at => { "$exists" => false }})
end
end

describe ".unscoped" do

let(:unscoped) do
ParanoidPost.unscoped
end

it "returns an unscoped criteria" do
unscoped.selector.should eq({})
end
end
end

0 comments on commit 84702e9

Please sign in to comment.