Files
redux-scraper/spec/models/domain/user_counter_cache_spec.rb
2025-08-20 22:10:57 +00:00

234 lines
8.1 KiB
Ruby

# 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