require "spec_helper" describe Mongoid::Relations::CounterCache do describe "#reset_counters" do context "when counter is reset" do let(:person) do Person.create do |person| person[:drugs_count] = 3 end end before do person.reset_counters(:drugs) end it "sets the counter to zero" do expect(person.drugs_count).to eq(0) end it "persists the changes" do expect(person.reload.drugs_count).to eq(0) end end context "when reset with invalid name" do let(:person) do Person.create end it "expect to raise an error" do expect { person.reset_counters(:not_exist) }.to raise_error(NoMethodError) end end context "when counter gets messy" do let(:person) do Person.create end let!(:post) do person.posts.create(title: "my first post") end before do Person.update_counters(person.id, :posts_count => 10) person.reload person.reset_counters(:posts) end it "resets to the right value" do expect(person.posts_count).to eq(1) end it "persists the change" do expect(person.reload.posts_count).to eq(1) end end context "when the counter is on a subclass" do let(:subscription) do Subscription.create end let!(:pack) do subscription.packs.create end before do subscription.reset_counters(:packs) end it "resets the appropriate counter" do expect(subscription[:packs_count]).to eq(1) end it "persists the change" do expect(subscription.reload[:packs_count]).to eq(1) end end context 'when there are persistence options set' do let(:subscription) do Subscription.new end before do subscription.with(collection: 'other') do |sub| sub.save sub.packs.create end end it 'applies the persistence options when resetting the counter' do subscription.with(collection: 'other') do |sub| expect(sub.reload[:packs_count]).to eq(1) end end end end describe ".reset_counters" do context "when counter is reset" do let(:person) do Person.create do |person| person[:drugs_count] = 3 end end before do Person.reset_counters person.id, :drugs end it "returns zero" do expect(person.reload.drugs_count).to eq(0) end end context "when counter is reset with wrong id" do it "expect to raise an error" do expect { Person.reset_counters "1", :drugs }.to raise_error(Mongoid::Errors::DocumentNotFound) end end context "when reset with invalid name" do let(:person) do Person.create end it "expect to raise an error" do expect { Person.reset_counters person.id, :not_exist }.to raise_error(NoMethodError) end end context "when counter gets messy" do let(:person) do Person.create end let!(:post) do person.posts.create(title: "my first post") end before do Person.update_counters(person.id, :posts_count => 10) Person.reset_counters(person.id, :posts) end it "resets to the right value" do expect(person.reload.posts_count).to eq(1) end end context "when the counter is on a subclass" do let(:subscription) do Subscription.create end let!(:pack) do subscription.packs.create end before do Subscription.reset_counters(subscription.id, :packs) end it "resets the appropriate counter" do expect(subscription.reload[:packs_count]).to eq(1) end end end describe "#update_counters" do context "when was 3 " do let(:person) do Person.create do |person| person[:drugs_count] = 3 end end context "and update counter with 5" do before do Person.update_counters person.id, :drugs_count => 5 end it "return 8" do expect(person.reload.drugs_count).to eq(8) end end context "and update counter with -5" do before do Person.update_counters person.id, :drugs_count => -5 end it "return -2" do expect(person.reload.drugs_count).to eq(-2) end end end context "when update with 2 and use a string argument" do let(:person) { Person.create } before do Person.update_counters person.id, "drugs_count" => 2 end it "returns 2" do expect(person.reload.drugs_count).to eq(2) end end context "when update more multiple counters" do let(:person) { Person.create } before do Person.update_counters(person.id, :drugs_count => 2, :second_counter => 5) end it "updates drugs_counter" do expect(person.reload.drugs_count).to eq(2) end it "updates second_counter" do expect(person.reload.second_counter).to eq(5) end end end describe "#increment_counter" do let(:person) { Person.create } context "when increment 3 times" do before do 3.times { Person.increment_counter(:drugs_count, person.id) } end it "returns 3" do expect(person.reload.drugs_count).to eq(3) end end context "when increment 3 times using string as argument" do before do 3.times { Person.increment_counter("drugs_count", person.id) } end it "returns 3" do expect(person.reload.drugs_count).to eq(3) end end context 'when there are persistence options set' do let(:person) do Person.new end before do person.with(collection: 'other') do |per| per.save per.drugs.create end end it 'applies the persistence options when resetting the counter' do person.with(collection: 'other') do |per| expect(per.drugs_count).to eq(1) end end end end describe "#decrement_counter" do let(:person) do Person.create do |p| p[:drugs_count] = 3 end end context "when decrement 3 times" do before do 3.times { Person.decrement_counter(:drugs_count, person.id) } end it "returns 0" do expect(person.reload.drugs_count).to eq(0) end end context "when increment 3 times using string as argument" do before do 3.times { Person.decrement_counter("drugs_count", person.id) } end it "returns 0" do expect(person.reload.drugs_count).to eq(0) end end context 'when there are persistence options set' do let(:person) do Person.new end before do person.with(collection: 'other') do |per| per.save drug = per.drugs.create drug.destroy end end it 'applies the persistence options when resetting the counter' do person.with(collection: 'other') do |per| expect(per.reload.drugs_count).to eq(0) end end end end describe "#add_counter_cache_callbacks" do context "when parent is not frozen" do context 'when #destroy is called on the object' do let(:person) do Person.create end let!(:drug) do person.drugs.create end before do drug.destroy end it "updates the counter cache" do expect(person.drugs_count).to eq(0) end end context 'when #create is called on the object' do let(:person) do Person.create { |p| p.drugs += [Drug.create, Drug.create] } end it "updates the counter cache" do expect(person.drugs_count).to eq(2) end end context 'when #update is called on the object' do let(:person1) do Person.create { |p| p.drugs += [Drug.create, Drug.create] } end let(:drug) do person1.drugs.first end let(:person2) do Person.create end before do drug.update_attribute(:person, person2) end it "updates the current counter cache" do expect(drug.person.drugs_count).to eq(1) end it "updates the current counter cache" do expect(person2.drugs_count).to eq(1) end it "updates the original object's counter cache" do expect(person1.reload.drugs_count).to eq(1) end end end context "when parent is frozen" do let(:person) do Person.create end let!(:drug) do person.drugs.create end before do person.destroy drug.destroy end it "before_destroy doesn't update counter cache" do expect(person.drugs_count).to eq(1) end end end end