# typed: false require "rails_helper" RSpec.describe "Domain::User counter caches", type: :model do let(:user) { create(:domain_user_fa_user) } let(:post) { create(:domain_post_fa_post) } describe "user_post_creations_count" do it "increments when a post creation is added" do expect { Domain::UserPostCreation.create!(user: user, post: post) }.to change { user.reload.user_post_creations.size }.from(0).to(1) end it "decrements when a post creation is removed" do creation = Domain::UserPostCreation.create!(user: user, post: post) expect { creation.destroy }.to change { user.reload.user_post_creations.size }.from(1).to(0) end it "provides direct access to the counts" do posts = create_list(:domain_post_fa_post, 3) posts.each { |p| Domain::UserPostCreation.create!(user: user, post: p) } # Counter in database should be updated automatically expect(user.reload.user_post_creations.size).to eq(3) # Calling the method should use the cached value expect(user.user_post_creations.size).to eq(3) end it "resets to the correct count" do posts = create_list(:domain_post_fa_post, 3) posts.each { |p| Domain::UserPostCreation.create!(user: user, post: p) } # Manually set to wrong value user.update_column(:user_post_creations_count, 0) expect(user.read_attribute(:user_post_creations_count)).to eq(0) # Reset counter Domain::User.reset_counters(user.id, :user_post_creations) expect(user.reload.user_post_creations_count).to eq(3) end end describe "user_post_favs_count" do it "increments when a post fav is added" do expect { Domain::UserPostFav.create!(user: user, post: post) }.to change { user.reload.user_post_favs.size }.from(0).to(1) end it "decrements when a post fav is removed" do fav = Domain::UserPostFav.create!(user: user, post: post) expect { fav.destroy }.to change { user.reload.user_post_favs.size }.from( 1, ).to(0) end it "provides direct access to the counts" do posts = create_list(:domain_post_fa_post, 3) posts.each { |p| Domain::UserPostFav.create!(user: user, post: p) } # Counter in database should be updated automatically expect(user.reload.user_post_favs.size).to eq(3) # Calling the method should use the cached value expect(user.user_post_favs.size).to eq(3) end end describe "user_user_follows_from_count" do let(:other_user) { create(:domain_user_fa_user) } it "increments when a follow is added" do expect { Domain::UserUserFollow.create!(from: user, to: other_user) }.to change { user.reload.user_user_follows_from.size }.from(0).to(1) end it "decrements when a follow is removed" do follow = Domain::UserUserFollow.create!(from: user, to: other_user) expect { follow.destroy }.to change { user.reload.user_user_follows_from.size }.from(1).to(0) end it "provides direct access to the counts" do users = create_list(:domain_user_fa_user, 3) users.each { |u| Domain::UserUserFollow.create!(from: user, to: u) } # Counter in database should be updated automatically expect(user.reload.user_user_follows_from.size).to eq(3) # Calling the method should use the cached value expect(user.user_user_follows_from.size).to eq(3) end end describe "user_user_follows_to_count" do let(:other_user) { create(:domain_user_fa_user) } it "increments when a follow is added" do expect { Domain::UserUserFollow.create!(from: other_user, to: user) }.to change { user.reload.user_user_follows_to.size }.from(0).to(1) end it "decrements when a follow is removed" do follow = Domain::UserUserFollow.create!(from: other_user, to: user) expect { follow.destroy }.to change { user.reload.user_user_follows_to.size }.from(1).to(0) end it "provides direct access to the counts" do users = create_list(:domain_user_fa_user, 3) users.each { |u| Domain::UserUserFollow.create!(from: u, to: user) } # Counter in database should be updated automatically expect(user.reload.user_user_follows_to.size).to eq(3) # Calling the method should use the cached value expect(user.user_user_follows_to.size).to eq(3) end end describe "counter cache consistency" do it "maintains separate counts for creations and favs" do # Create 2 posts and fav 3 posts created_posts = create_list(:domain_post_fa_post, 2) faved_posts = create_list(:domain_post_fa_post, 3) created_posts.each do |p| Domain::UserPostCreation.create!(user: user, post: p) end faved_posts.each { |p| Domain::UserPostFav.create!(user: user, post: p) } user.reload expect(user.user_post_creations_count).to eq(2) expect(user.user_post_favs_count).to eq(3) end end it "falls back to sql COUNT when the counter cache is not set" do user = create(:domain_user_fa_user) post = create(:domain_post_fa_post, creator: user) # creation of a post should update the counter cache user.reload expect(user.user_post_creations_count).to eq(1) expect(user.user_post_favs_count).to be_nil # insert a fav without updating the counter cache, so the counter cache is nil Domain::UserPostFav::FaUserPostFav.insert_all!( [{ user_id: user.id, post_id: post.id }], ) user.reload expect(user.user_post_favs_count).to be_nil expect(user.user_post_favs.size).to eq(1) expect(user.user_post_favs.count).to eq(1) # recompute the value of the counter cache Domain::User.reset_counters(user.id, :user_post_favs) user.reload expect(user.user_post_favs_count).to eq(1) expect(user.user_post_favs.size).to eq(1) expect(user.user_post_favs.count).to eq(1) end it "sets the right value when there was already an existing model" do user = create(:domain_user_fa_user) # create a post as if it was there prior to the counter cache existing create(:domain_post_fa_post, creator: user) user.update_column(:user_post_creations_count, nil) user.reload user = Domain::User.find(user.id) expect(user.user_post_creations_count).to eq(nil) expect(user.user_post_creations.length).to eq(1) expect(user.user_post_creations.count).to eq(1) # create a second post create(:domain_post_fa_post, creator: user) user.reload expect(user.user_post_creations_count).to eq(2) expect(user.user_post_creations.size).to eq(2) expect(user.user_post_creations.length).to eq(2) expect(user.user_post_creations.count).to eq(2) # and a third to test incrementing create(:domain_post_fa_post, creator: user) user.reload expect(user.user_post_creations.count).to eq(3) expect(user.user_post_creations_count).to eq(3) expect(user.user_post_creations.length).to eq(3) expect(user.user_post_creations.size).to eq(3) end it "works with user_user_follows" do user = create(:domain_user_fa_user) other_user_1 = create(:domain_user_fa_user) other_user_2 = create(:domain_user_fa_user) [user, other_user_1, other_user_2].each do |u| expect(u.user_user_follows_from_count).to be_nil expect(u.user_user_follows_from.size).to eq(0) expect(u.user_user_follows_to_count).to be_nil expect(u.user_user_follows_to.size).to eq(0) end Domain::UserUserFollow.create!(from: user, to: other_user_1) user.reload expect(user.user_user_follows_from_count).to eq(1) expect(user.user_user_follows_from.size).to eq(1) expect(other_user_1.user_user_follows_to_count).to eq(1) expect(other_user_1.user_user_follows_to.size).to eq(1) Domain::UserUserFollow.create!(from: user, to: other_user_2) user.reload expect(user.user_user_follows_from_count).to eq(2) expect(user.user_user_follows_from.size).to eq(2) Domain::UserUserFollow.create!(from: other_user_1, to: user) user.reload expect(user.user_user_follows_to_count).to eq(1) expect(user.user_user_follows_to.size).to eq(1) end end