counter cache for user model

This commit is contained in:
Dylan Knutson
2025-03-21 05:24:15 +00:00
parent dab811d784
commit 7d0d94d761
23 changed files with 1389 additions and 21 deletions

View File

@@ -38,4 +38,4 @@
- [ ] fix for IDs that have a dot in them - e.g. https://refurrer.com/users/fa@jakke.
- [ ] Rich inline links to e621 e.g. https://refurrer.com/posts/fa@60070060
- [ ] Find FaPost that have favs recorded but no scan / file, enqueue scan
- [ ] Bunch of posts with empty responses: posts = Domain::Post.joins(files: :log_entry).where(files: { http_log_entries: { response_sha256: BlobFile::EMPTY_FILE_SHA256 }}).limit(10)
- [x] Bunch of posts with empty responses: posts = Domain::Post.joins(files: :log_entry).where(files: { http_log_entries: { response_sha256: BlobFile::EMPTY_FILE_SHA256 }}).limit(10)

View File

@@ -128,6 +128,10 @@ class Domain::E621::Job::ScanUserFavsJob < Domain::E621::Job::Base
end
end
# Use reset_counters to update the counter cache after using upsert_all
Domain::User.reset_counters(user.id, :user_post_favs)
logger.info("[reset user_post_favs counter cache for user: #{user.id}]")
logger.info(
[
"[favs scanned: #{post_ids.size.to_s.bold}]",

View File

@@ -565,7 +565,8 @@ class Domain::Fa::Job::Base < Scraper::JobBase
).returns(T::Boolean)
end
def user_disabled_or_not_found?(user, response)
if response.status_code != 200
# HTTP 400 is returned when the user is not found
if response.status_code != 200 && response.status_code != 400
fatal_error(
"http #{response.status_code}, log entry #{response.log_entry.id}",
)

View File

@@ -98,6 +98,14 @@ class Domain::Fa::Job::FavsJob < Domain::Fa::Job::Base
unique_by: %i[user_id post_id],
)
end
# Use reset_counters to update the counter cache after using upsert_all
Domain::User.reset_counters(user.id, :user_post_favs)
logger.info(
format_tags(
make_tag("reset user_post_favs counter cache for user", user.id),
),
)
end
user.scanned_favs_at = Time.zone.now

View File

@@ -77,6 +77,14 @@ module Domain::Fa::Job
{ user_id: user.id, post_id: post_id }
end,
)
# Use reset_counters to update the counter cache after using insert_all
Domain::User.reset_counters(user.id, :user_post_favs)
logger.info(
format_tags(
make_tag("reset user_post_favs counter cache for user", user.id),
),
)
end
if missing_fav_post_ids.include? recent_fav_post_ids.last
@@ -125,6 +133,25 @@ module Domain::Fa::Job
{ from_id: watcher_id, to_id: user.id }
end,
)
# Use reset_counters to update follows_to for the current user
Domain::User.reset_counters(user.id, :user_user_follows_to)
logger.info(
format_tags(
make_tag(
"reset user_user_follows_to counter cache for user",
user.id,
),
),
)
# Update follows_from counts for watcher users
missing_watcher_ids.each_slice(100) do |batch_ids|
batch_ids.each do |watcher_id|
Domain::User.reset_counters(watcher_id, :user_user_follows_from)
end
end
logger.info("added #{num_missing.to_s.bold} new watchers")
end
@@ -140,22 +167,45 @@ module Domain::Fa::Job
find_or_create_users_by_recent_users(recent_watched)
raise("invariant") unless recent_watched_users.size == recent_watched.size
recent_watched_user_ids = recent_watched_users.map { |m| T.must(m.id) }
known_watched_users =
user.followed_users.where(id: recent_watched_user_ids).to_a
missing_watched_users = recent_watched_users - known_watched_users
known_watched_user_ids =
user.followed_users.where(id: recent_watched_user_ids).pluck(:id)
missing_watched_users =
recent_watched_users.reject do |u|
known_watched_user_ids.include?(u.id)
end
missing_watched_user_ids = missing_watched_users.map { |m| T.must(m.id) }
if missing_watched_users.empty?
if missing_watched_user_ids.empty?
logger.info("no new users watched")
user.scanned_follows_at = Time.current
return
end
num_missing = missing_watched_users.size
num_missing = missing_watched_user_ids.size
Domain::UserUserFollow.insert_all!(
missing_watched_users.map do |watched_user|
{ from_id: user.id, to_id: watched_user.id }
missing_watched_user_ids.map do |watched_user_id|
{ from_id: user.id, to_id: watched_user_id }
end,
)
# Use reset_counters to update follows_from for the current user
Domain::User.reset_counters(user.id, :user_user_follows_from)
logger.info(
format_tags(
make_tag(
"reset user_user_follows_from counter cache for user",
user.id,
),
),
)
# Update follows_to counts for users who were followed
missing_watched_user_ids.each_slice(100) do |batch_ids|
batch_ids.each do |watched_user_id|
Domain::User.reset_counters(watched_user_id, :user_user_follows_to)
end
end
logger.info("added #{num_missing.to_s.bold} new users watched")
last_watched_user = recent_watched_users.last

View File

@@ -154,6 +154,15 @@ class Domain::Fa::Job::UserPageJob < Domain::Fa::Job::Base
faved_posts.map(&:id).compact.map { |post_id| { post_id: } },
unique_by: %i[user_id post_id],
)
# Use reset_counters to update the counter cache after upserting favs
Domain::User.reset_counters(user.id, :user_post_favs)
logger.info(
format_tags(
make_tag("reset user_post_favs counter cache for user", user.id),
),
)
user.scanned_favs_at = Time.current
end
end
@@ -182,10 +191,31 @@ class Domain::Fa::Job::UserPageJob < Domain::Fa::Job::Base
) { |user| user.name = recent_user.name }
end
watched_user_ids = watched_users.map(&:id).compact
user.user_user_follows_from.upsert_all(
watched_users.map(&:id).compact.map { |user_id| { to_id: user_id } },
watched_user_ids.map { |user_id| { to_id: user_id } },
unique_by: %i[from_id to_id],
)
# Use reset_counters to update follows_from for the current user
Domain::User.reset_counters(user.id, :user_user_follows_from)
logger.info(
format_tags(
make_tag(
"reset user_user_follows_from counter cache for user",
user.id,
),
),
)
# Update follows_to counts for users who were followed
watched_user_ids.each_slice(100) do |batch_ids|
batch_ids.each do |watched_user_id|
Domain::User.reset_counters(watched_user_id, :user_user_follows_to)
end
end
user.scanned_follows_at = Time.current
elsif recent_watching.any?
# if there are watchers, find the ones we've already recorded. if
@@ -239,13 +269,31 @@ class Domain::Fa::Job::UserPageJob < Domain::Fa::Job::Base
) { |user| user.name = recent_user.name }
end
watcher_ids = watched_by_users.map(&:id).compact
user.user_user_follows_to.upsert_all(
watched_by_users
.map(&:id)
.compact
.map { |user_id| { from_id: user_id } },
watcher_ids.map { |user_id| { from_id: user_id } },
unique_by: %i[from_id to_id],
)
# Use reset_counters to update follows_to for the current user
Domain::User.reset_counters(user.id, :user_user_follows_to)
logger.info(
format_tags(
make_tag(
"reset user_user_follows_to counter cache for user",
user.id,
),
),
)
# Update follows_from counts for watchers
watcher_ids.each_slice(100) do |batch_ids|
batch_ids.each do |watcher_id|
Domain::User.reset_counters(watcher_id, :user_user_follows_from)
end
end
user.scanned_followed_by_at = Time.current
return
end

View File

@@ -1,6 +1,7 @@
# typed: strict
class Domain::PostFileThumbnailJob < Scraper::JobBase
queue_as :thumbnails
discard_on Vips::Error
sig { override.returns(Symbol) }
def self.http_factory_method

View File

@@ -931,6 +931,12 @@ class Domain::MigrateToDomain
ON CONFLICT (user_id, post_id) DO NOTHING
SQL
# Use reset_counters to update the counter cache after inserting favs
Domain::User.reset_counters(user.id, :user_post_favs)
logger.info(
"Reset user_post_favs counter cache for user #{user.name} (ID: #{user.id})",
)
if user.faved_posts.count != old_user.fav_posts.count
logger.error(
"favs mismatch for #{user.name}: (#{user.faved_posts.count} != #{old_user.fav_posts.count})",
@@ -962,6 +968,22 @@ class Domain::MigrateToDomain
)
end
# Use reset_counters to update follows_from for the current user
Domain::User.reset_counters(user.id, :user_user_follows_from)
logger.info(
"Reset user_user_follows_from counter cache for user #{user.name} (ID: #{user.id})",
)
# Update follows_to counts for users who were followed
new_user_ids.each_slice(1000) do |batch_ids|
batch_ids.each do |user_id|
Domain::User.reset_counters(user_id, :user_user_follows_to)
end
end
logger.info(
"Reset user_user_follows_to counter cache for #{new_user_ids.size} followed users",
)
if new_user_ids.size != old_user.follows.count
logger.error(
"followers mismatch for #{user.name}: (#{user.followed_users.count} != #{old_user.follows.count})",
@@ -987,6 +1009,12 @@ class Domain::MigrateToDomain
)
end
# Use reset_counters to update the counter cache after upserting favs
Domain::User.reset_counters(new_user.id, :user_post_favs)
logger.info(
"Reset user_post_favs counter cache for user #{new_user.name} (ID: #{new_user.id})",
)
if new_user.faved_posts.count != old_user.faved_posts.count
logger.error(
"favs mismatch for #{new_user.name}: (#{new_user.faved_posts.count} != #{old_user.faved_posts.count})",

View File

@@ -17,6 +17,27 @@ class Domain::User < ReduxApplicationRecord
:class_has_followed_by_users,
:due_at_timestamp_fields
# Counter cache methods with fallbacks
sig { returns(Integer) }
def user_post_creations_count
super || user_post_creations.count
end
sig { returns(Integer) }
def user_post_favs_count
super || user_post_favs.count
end
sig { returns(Integer) }
def user_user_follows_from_count
super || user_user_follows_from.count
end
sig { returns(Integer) }
def user_user_follows_to_count
super || user_user_follows_to.count
end
sig(:final) { returns(T::Boolean) }
def has_created_posts?
class_has_created_posts.present?

View File

@@ -10,5 +10,6 @@ class Domain::UserPostCreation < ReduxApplicationRecord
inverse_of: :user_post_creations
belongs_to :user,
class_name: "::Domain::User",
inverse_of: :user_post_creations
inverse_of: :user_post_creations,
counter_cache: true
end

View File

@@ -3,7 +3,10 @@ class Domain::UserPostFav < ReduxApplicationRecord
self.table_name = "domain_user_post_favs"
self.primary_key = %i[user_id post_id]
belongs_to :user, class_name: "Domain::User", inverse_of: :user_post_favs
belongs_to :user,
class_name: "Domain::User",
inverse_of: :user_post_favs,
counter_cache: true
belongs_to :post, class_name: "Domain::Post", inverse_of: :user_post_favs
scope :for_post_type,

View File

@@ -2,6 +2,10 @@ class Domain::UserUserFollow < ReduxApplicationRecord
self.table_name = "domain_user_user_follows"
self.primary_key = %i[from_id to_id]
belongs_to :from, class_name: "Domain::User"
belongs_to :to, class_name: "Domain::User"
belongs_to :from,
class_name: "Domain::User",
counter_cache: :user_user_follows_from_count
belongs_to :to,
class_name: "Domain::User",
counter_cache: :user_user_follows_to_count
end

View File

@@ -0,0 +1,31 @@
class AddUserCountersToDomainUsers < ActiveRecord::Migration[7.2]
def up
add_column :domain_users,
:user_post_creations_count,
:integer,
default: nil,
null: true
add_column :domain_users,
:user_post_favs_count,
:integer,
default: nil,
null: true
add_column :domain_users,
:user_user_follows_from_count,
:integer,
default: nil,
null: true
add_column :domain_users,
:user_user_follows_to_count,
:integer,
default: nil,
null: true
end
def down
remove_column :domain_users, :user_post_creations_count
remove_column :domain_users, :user_post_favs_count
remove_column :domain_users, :user_user_follows_from_count
remove_column :domain_users, :user_user_follows_to_count
end
end

View File

@@ -3160,7 +3160,11 @@ CREATE TABLE public.domain_users (
type public.domain_user_type NOT NULL,
json_attributes jsonb DEFAULT '{}'::jsonb,
created_at timestamp(6) without time zone NOT NULL,
updated_at timestamp(6) without time zone NOT NULL
updated_at timestamp(6) without time zone NOT NULL,
user_post_creations_count integer,
user_post_favs_count integer,
user_user_follows_from_count integer,
user_user_follows_to_count integer
);
@@ -8910,6 +8914,7 @@ ALTER TABLE ONLY public.domain_twitter_tweets
SET search_path TO "$user", public;
INSERT INTO "schema_migrations" (version) VALUES
('20250321050628'),
('20250310001341'),
('20250310001005'),
('20250306021628'),

79
lib/tasks/counters.rake Normal file
View File

@@ -0,0 +1,79 @@
namespace :counters do
# Generic counter reset helper that works with any model
def reset_model_counters(model_class, counter_names, batch_size: 1000)
counter_names = Array(counter_names)
model_name = model_class.name.demodulize.underscore
counter_desc =
counter_names
.map { |n| n.to_s.sub("#{model_name}_", "").sub("user_", "") }
.join(" and ")
total = model_class.count
puts "Resetting #{counter_desc} counter cache for #{total} #{model_name.pluralize}..."
pb = ProgressBar.create(total: total, format: "%t: %c/%C %B %p%% %a %e")
model_class
.pluck(:id)
.each_slice(batch_size) do |ids|
model_class.transaction do
ids.each do |id|
model_class.reset_counters(id, *counter_names)
pb.increment
end
end
end
puts "Done!"
end
namespace :domain do
namespace :user do
def reset_user_counters(counter_names)
reset_model_counters(Domain::User, counter_names)
end
desc "Reset all user counter caches"
task all: :environment do
reset_user_counters(
%i[
user_post_creations
user_post_favs
user_user_follows_from
user_user_follows_to
],
)
end
desc "Reset post-related counter caches only (creations and favs)"
task posts: :environment do
reset_user_counters(%i[user_post_creations user_post_favs])
end
desc "Reset follow-related counter caches only (follows_from and follows_to)"
task follows: :environment do
reset_user_counters(%i[user_user_follows_from user_user_follows_to])
end
desc "Reset user_post_creations_count counter cache"
task user_post_creations_count: :environment do
reset_user_counters(:user_post_creations)
end
desc "Reset user_post_favs_count counter cache"
task user_post_favs_count: :environment do
reset_user_counters(:user_post_favs)
end
desc "Reset user_user_follows_from_count counter cache"
task user_user_follows_from_count: :environment do
reset_user_counters(:user_user_follows_from)
end
desc "Reset user_user_follows_to_count counter cache"
task user_user_follows_to_count: :environment do
reset_user_counters(:user_user_follows_to)
end
end
end
end

View File

@@ -70,6 +70,9 @@ namespace :blob_file do
puts "error saving blob file #{sha256_hex}: #{e}"
end
end
rescue => e
puts "error migrating blob entry: #{missing_sha256s.map { |sha256| HexUtil.bin2hex(sha256) }}"
raise e
end
num_migrated
end

View File

@@ -1006,6 +1006,18 @@ class Domain::User
sig { void }
def restore_updated_at!; end
sig { void }
def restore_user_post_creations_count!; end
sig { void }
def restore_user_post_favs_count!; end
sig { void }
def restore_user_user_follows_from_count!; end
sig { void }
def restore_user_user_follows_to_count!; end
sig { returns(T.nilable([T.nilable(::ActiveSupport::TimeWithZone), T.nilable(::ActiveSupport::TimeWithZone)])) }
def saved_change_to_created_at; end
@@ -1048,6 +1060,30 @@ class Domain::User
sig { returns(T::Boolean) }
def saved_change_to_updated_at?; end
sig { returns(T.nilable([T.nilable(::Integer), T.nilable(::Integer)])) }
def saved_change_to_user_post_creations_count; end
sig { returns(T::Boolean) }
def saved_change_to_user_post_creations_count?; end
sig { returns(T.nilable([T.nilable(::Integer), T.nilable(::Integer)])) }
def saved_change_to_user_post_favs_count; end
sig { returns(T::Boolean) }
def saved_change_to_user_post_favs_count?; end
sig { returns(T.nilable([T.nilable(::Integer), T.nilable(::Integer)])) }
def saved_change_to_user_user_follows_from_count; end
sig { returns(T::Boolean) }
def saved_change_to_user_user_follows_from_count?; end
sig { returns(T.nilable([T.nilable(::Integer), T.nilable(::Integer)])) }
def saved_change_to_user_user_follows_to_count; end
sig { returns(T::Boolean) }
def saved_change_to_user_user_follows_to_count?; end
sig { returns(T.untyped) }
def type; end
@@ -1148,6 +1184,186 @@ class Domain::User
sig { void }
def updated_at_will_change!; end
sig { returns(T.nilable(::Integer)) }
def user_post_creations_count; end
sig { params(value: T.nilable(::Integer)).returns(T.nilable(::Integer)) }
def user_post_creations_count=(value); end
sig { returns(T::Boolean) }
def user_post_creations_count?; end
sig { returns(T.nilable(::Integer)) }
def user_post_creations_count_before_last_save; end
sig { returns(T.untyped) }
def user_post_creations_count_before_type_cast; end
sig { returns(T::Boolean) }
def user_post_creations_count_came_from_user?; end
sig { returns(T.nilable([T.nilable(::Integer), T.nilable(::Integer)])) }
def user_post_creations_count_change; end
sig { returns(T.nilable([T.nilable(::Integer), T.nilable(::Integer)])) }
def user_post_creations_count_change_to_be_saved; end
sig { params(from: T.nilable(::Integer), to: T.nilable(::Integer)).returns(T::Boolean) }
def user_post_creations_count_changed?(from: T.unsafe(nil), to: T.unsafe(nil)); end
sig { returns(T.nilable(::Integer)) }
def user_post_creations_count_in_database; end
sig { returns(T.nilable([T.nilable(::Integer), T.nilable(::Integer)])) }
def user_post_creations_count_previous_change; end
sig { params(from: T.nilable(::Integer), to: T.nilable(::Integer)).returns(T::Boolean) }
def user_post_creations_count_previously_changed?(from: T.unsafe(nil), to: T.unsafe(nil)); end
sig { returns(T.nilable(::Integer)) }
def user_post_creations_count_previously_was; end
sig { returns(T.nilable(::Integer)) }
def user_post_creations_count_was; end
sig { void }
def user_post_creations_count_will_change!; end
sig { returns(T.nilable(::Integer)) }
def user_post_favs_count; end
sig { params(value: T.nilable(::Integer)).returns(T.nilable(::Integer)) }
def user_post_favs_count=(value); end
sig { returns(T::Boolean) }
def user_post_favs_count?; end
sig { returns(T.nilable(::Integer)) }
def user_post_favs_count_before_last_save; end
sig { returns(T.untyped) }
def user_post_favs_count_before_type_cast; end
sig { returns(T::Boolean) }
def user_post_favs_count_came_from_user?; end
sig { returns(T.nilable([T.nilable(::Integer), T.nilable(::Integer)])) }
def user_post_favs_count_change; end
sig { returns(T.nilable([T.nilable(::Integer), T.nilable(::Integer)])) }
def user_post_favs_count_change_to_be_saved; end
sig { params(from: T.nilable(::Integer), to: T.nilable(::Integer)).returns(T::Boolean) }
def user_post_favs_count_changed?(from: T.unsafe(nil), to: T.unsafe(nil)); end
sig { returns(T.nilable(::Integer)) }
def user_post_favs_count_in_database; end
sig { returns(T.nilable([T.nilable(::Integer), T.nilable(::Integer)])) }
def user_post_favs_count_previous_change; end
sig { params(from: T.nilable(::Integer), to: T.nilable(::Integer)).returns(T::Boolean) }
def user_post_favs_count_previously_changed?(from: T.unsafe(nil), to: T.unsafe(nil)); end
sig { returns(T.nilable(::Integer)) }
def user_post_favs_count_previously_was; end
sig { returns(T.nilable(::Integer)) }
def user_post_favs_count_was; end
sig { void }
def user_post_favs_count_will_change!; end
sig { returns(T.nilable(::Integer)) }
def user_user_follows_from_count; end
sig { params(value: T.nilable(::Integer)).returns(T.nilable(::Integer)) }
def user_user_follows_from_count=(value); end
sig { returns(T::Boolean) }
def user_user_follows_from_count?; end
sig { returns(T.nilable(::Integer)) }
def user_user_follows_from_count_before_last_save; end
sig { returns(T.untyped) }
def user_user_follows_from_count_before_type_cast; end
sig { returns(T::Boolean) }
def user_user_follows_from_count_came_from_user?; end
sig { returns(T.nilable([T.nilable(::Integer), T.nilable(::Integer)])) }
def user_user_follows_from_count_change; end
sig { returns(T.nilable([T.nilable(::Integer), T.nilable(::Integer)])) }
def user_user_follows_from_count_change_to_be_saved; end
sig { params(from: T.nilable(::Integer), to: T.nilable(::Integer)).returns(T::Boolean) }
def user_user_follows_from_count_changed?(from: T.unsafe(nil), to: T.unsafe(nil)); end
sig { returns(T.nilable(::Integer)) }
def user_user_follows_from_count_in_database; end
sig { returns(T.nilable([T.nilable(::Integer), T.nilable(::Integer)])) }
def user_user_follows_from_count_previous_change; end
sig { params(from: T.nilable(::Integer), to: T.nilable(::Integer)).returns(T::Boolean) }
def user_user_follows_from_count_previously_changed?(from: T.unsafe(nil), to: T.unsafe(nil)); end
sig { returns(T.nilable(::Integer)) }
def user_user_follows_from_count_previously_was; end
sig { returns(T.nilable(::Integer)) }
def user_user_follows_from_count_was; end
sig { void }
def user_user_follows_from_count_will_change!; end
sig { returns(T.nilable(::Integer)) }
def user_user_follows_to_count; end
sig { params(value: T.nilable(::Integer)).returns(T.nilable(::Integer)) }
def user_user_follows_to_count=(value); end
sig { returns(T::Boolean) }
def user_user_follows_to_count?; end
sig { returns(T.nilable(::Integer)) }
def user_user_follows_to_count_before_last_save; end
sig { returns(T.untyped) }
def user_user_follows_to_count_before_type_cast; end
sig { returns(T::Boolean) }
def user_user_follows_to_count_came_from_user?; end
sig { returns(T.nilable([T.nilable(::Integer), T.nilable(::Integer)])) }
def user_user_follows_to_count_change; end
sig { returns(T.nilable([T.nilable(::Integer), T.nilable(::Integer)])) }
def user_user_follows_to_count_change_to_be_saved; end
sig { params(from: T.nilable(::Integer), to: T.nilable(::Integer)).returns(T::Boolean) }
def user_user_follows_to_count_changed?(from: T.unsafe(nil), to: T.unsafe(nil)); end
sig { returns(T.nilable(::Integer)) }
def user_user_follows_to_count_in_database; end
sig { returns(T.nilable([T.nilable(::Integer), T.nilable(::Integer)])) }
def user_user_follows_to_count_previous_change; end
sig { params(from: T.nilable(::Integer), to: T.nilable(::Integer)).returns(T::Boolean) }
def user_user_follows_to_count_previously_changed?(from: T.unsafe(nil), to: T.unsafe(nil)); end
sig { returns(T.nilable(::Integer)) }
def user_user_follows_to_count_previously_was; end
sig { returns(T.nilable(::Integer)) }
def user_user_follows_to_count_was; end
sig { void }
def user_user_follows_to_count_will_change!; end
sig { returns(T::Boolean) }
def will_save_change_to_created_at?; end
@@ -1168,6 +1384,18 @@ class Domain::User
sig { returns(T::Boolean) }
def will_save_change_to_updated_at?; end
sig { returns(T::Boolean) }
def will_save_change_to_user_post_creations_count?; end
sig { returns(T::Boolean) }
def will_save_change_to_user_post_favs_count?; end
sig { returns(T::Boolean) }
def will_save_change_to_user_user_follows_from_count?; end
sig { returns(T::Boolean) }
def will_save_change_to_user_user_follows_to_count?; end
end
module GeneratedRelationMethods

View File

@@ -1341,6 +1341,18 @@ class Domain::User::E621User
sig { void }
def restore_updated_at!; end
sig { void }
def restore_user_post_creations_count!; end
sig { void }
def restore_user_post_favs_count!; end
sig { void }
def restore_user_user_follows_from_count!; end
sig { void }
def restore_user_user_follows_to_count!; end
sig { returns(T.nilable([T.nilable(::ActiveSupport::TimeWithZone), T.nilable(::ActiveSupport::TimeWithZone)])) }
def saved_change_to_created_at; end
@@ -1425,6 +1437,30 @@ class Domain::User::E621User
sig { returns(T::Boolean) }
def saved_change_to_updated_at?; end
sig { returns(T.nilable([T.nilable(::Integer), T.nilable(::Integer)])) }
def saved_change_to_user_post_creations_count; end
sig { returns(T::Boolean) }
def saved_change_to_user_post_creations_count?; end
sig { returns(T.nilable([T.nilable(::Integer), T.nilable(::Integer)])) }
def saved_change_to_user_post_favs_count; end
sig { returns(T::Boolean) }
def saved_change_to_user_post_favs_count?; end
sig { returns(T.nilable([T.nilable(::Integer), T.nilable(::Integer)])) }
def saved_change_to_user_user_follows_from_count; end
sig { returns(T::Boolean) }
def saved_change_to_user_user_follows_from_count?; end
sig { returns(T.nilable([T.nilable(::Integer), T.nilable(::Integer)])) }
def saved_change_to_user_user_follows_to_count; end
sig { returns(T::Boolean) }
def saved_change_to_user_user_follows_to_count?; end
sig { returns(T.nilable(::ActiveSupport::TimeWithZone)) }
def scanned_favs_at; end
@@ -1635,6 +1671,186 @@ class Domain::User::E621User
sig { void }
def updated_at_will_change!; end
sig { returns(T.nilable(::Integer)) }
def user_post_creations_count; end
sig { params(value: T.nilable(::Integer)).returns(T.nilable(::Integer)) }
def user_post_creations_count=(value); end
sig { returns(T::Boolean) }
def user_post_creations_count?; end
sig { returns(T.nilable(::Integer)) }
def user_post_creations_count_before_last_save; end
sig { returns(T.untyped) }
def user_post_creations_count_before_type_cast; end
sig { returns(T::Boolean) }
def user_post_creations_count_came_from_user?; end
sig { returns(T.nilable([T.nilable(::Integer), T.nilable(::Integer)])) }
def user_post_creations_count_change; end
sig { returns(T.nilable([T.nilable(::Integer), T.nilable(::Integer)])) }
def user_post_creations_count_change_to_be_saved; end
sig { params(from: T.nilable(::Integer), to: T.nilable(::Integer)).returns(T::Boolean) }
def user_post_creations_count_changed?(from: T.unsafe(nil), to: T.unsafe(nil)); end
sig { returns(T.nilable(::Integer)) }
def user_post_creations_count_in_database; end
sig { returns(T.nilable([T.nilable(::Integer), T.nilable(::Integer)])) }
def user_post_creations_count_previous_change; end
sig { params(from: T.nilable(::Integer), to: T.nilable(::Integer)).returns(T::Boolean) }
def user_post_creations_count_previously_changed?(from: T.unsafe(nil), to: T.unsafe(nil)); end
sig { returns(T.nilable(::Integer)) }
def user_post_creations_count_previously_was; end
sig { returns(T.nilable(::Integer)) }
def user_post_creations_count_was; end
sig { void }
def user_post_creations_count_will_change!; end
sig { returns(T.nilable(::Integer)) }
def user_post_favs_count; end
sig { params(value: T.nilable(::Integer)).returns(T.nilable(::Integer)) }
def user_post_favs_count=(value); end
sig { returns(T::Boolean) }
def user_post_favs_count?; end
sig { returns(T.nilable(::Integer)) }
def user_post_favs_count_before_last_save; end
sig { returns(T.untyped) }
def user_post_favs_count_before_type_cast; end
sig { returns(T::Boolean) }
def user_post_favs_count_came_from_user?; end
sig { returns(T.nilable([T.nilable(::Integer), T.nilable(::Integer)])) }
def user_post_favs_count_change; end
sig { returns(T.nilable([T.nilable(::Integer), T.nilable(::Integer)])) }
def user_post_favs_count_change_to_be_saved; end
sig { params(from: T.nilable(::Integer), to: T.nilable(::Integer)).returns(T::Boolean) }
def user_post_favs_count_changed?(from: T.unsafe(nil), to: T.unsafe(nil)); end
sig { returns(T.nilable(::Integer)) }
def user_post_favs_count_in_database; end
sig { returns(T.nilable([T.nilable(::Integer), T.nilable(::Integer)])) }
def user_post_favs_count_previous_change; end
sig { params(from: T.nilable(::Integer), to: T.nilable(::Integer)).returns(T::Boolean) }
def user_post_favs_count_previously_changed?(from: T.unsafe(nil), to: T.unsafe(nil)); end
sig { returns(T.nilable(::Integer)) }
def user_post_favs_count_previously_was; end
sig { returns(T.nilable(::Integer)) }
def user_post_favs_count_was; end
sig { void }
def user_post_favs_count_will_change!; end
sig { returns(T.nilable(::Integer)) }
def user_user_follows_from_count; end
sig { params(value: T.nilable(::Integer)).returns(T.nilable(::Integer)) }
def user_user_follows_from_count=(value); end
sig { returns(T::Boolean) }
def user_user_follows_from_count?; end
sig { returns(T.nilable(::Integer)) }
def user_user_follows_from_count_before_last_save; end
sig { returns(T.untyped) }
def user_user_follows_from_count_before_type_cast; end
sig { returns(T::Boolean) }
def user_user_follows_from_count_came_from_user?; end
sig { returns(T.nilable([T.nilable(::Integer), T.nilable(::Integer)])) }
def user_user_follows_from_count_change; end
sig { returns(T.nilable([T.nilable(::Integer), T.nilable(::Integer)])) }
def user_user_follows_from_count_change_to_be_saved; end
sig { params(from: T.nilable(::Integer), to: T.nilable(::Integer)).returns(T::Boolean) }
def user_user_follows_from_count_changed?(from: T.unsafe(nil), to: T.unsafe(nil)); end
sig { returns(T.nilable(::Integer)) }
def user_user_follows_from_count_in_database; end
sig { returns(T.nilable([T.nilable(::Integer), T.nilable(::Integer)])) }
def user_user_follows_from_count_previous_change; end
sig { params(from: T.nilable(::Integer), to: T.nilable(::Integer)).returns(T::Boolean) }
def user_user_follows_from_count_previously_changed?(from: T.unsafe(nil), to: T.unsafe(nil)); end
sig { returns(T.nilable(::Integer)) }
def user_user_follows_from_count_previously_was; end
sig { returns(T.nilable(::Integer)) }
def user_user_follows_from_count_was; end
sig { void }
def user_user_follows_from_count_will_change!; end
sig { returns(T.nilable(::Integer)) }
def user_user_follows_to_count; end
sig { params(value: T.nilable(::Integer)).returns(T.nilable(::Integer)) }
def user_user_follows_to_count=(value); end
sig { returns(T::Boolean) }
def user_user_follows_to_count?; end
sig { returns(T.nilable(::Integer)) }
def user_user_follows_to_count_before_last_save; end
sig { returns(T.untyped) }
def user_user_follows_to_count_before_type_cast; end
sig { returns(T::Boolean) }
def user_user_follows_to_count_came_from_user?; end
sig { returns(T.nilable([T.nilable(::Integer), T.nilable(::Integer)])) }
def user_user_follows_to_count_change; end
sig { returns(T.nilable([T.nilable(::Integer), T.nilable(::Integer)])) }
def user_user_follows_to_count_change_to_be_saved; end
sig { params(from: T.nilable(::Integer), to: T.nilable(::Integer)).returns(T::Boolean) }
def user_user_follows_to_count_changed?(from: T.unsafe(nil), to: T.unsafe(nil)); end
sig { returns(T.nilable(::Integer)) }
def user_user_follows_to_count_in_database; end
sig { returns(T.nilable([T.nilable(::Integer), T.nilable(::Integer)])) }
def user_user_follows_to_count_previous_change; end
sig { params(from: T.nilable(::Integer), to: T.nilable(::Integer)).returns(T::Boolean) }
def user_user_follows_to_count_previously_changed?(from: T.unsafe(nil), to: T.unsafe(nil)); end
sig { returns(T.nilable(::Integer)) }
def user_user_follows_to_count_previously_was; end
sig { returns(T.nilable(::Integer)) }
def user_user_follows_to_count_was; end
sig { void }
def user_user_follows_to_count_will_change!; end
sig { returns(T::Boolean) }
def will_save_change_to_created_at?; end
@@ -1676,6 +1892,18 @@ class Domain::User::E621User
sig { returns(T::Boolean) }
def will_save_change_to_updated_at?; end
sig { returns(T::Boolean) }
def will_save_change_to_user_post_creations_count?; end
sig { returns(T::Boolean) }
def will_save_change_to_user_post_favs_count?; end
sig { returns(T::Boolean) }
def will_save_change_to_user_user_follows_from_count?; end
sig { returns(T::Boolean) }
def will_save_change_to_user_user_follows_to_count?; end
end
module GeneratedRelationMethods

View File

@@ -2156,6 +2156,18 @@ class Domain::User::FaUser
sig { void }
def restore_url_name!; end
sig { void }
def restore_user_post_creations_count!; end
sig { void }
def restore_user_post_favs_count!; end
sig { void }
def restore_user_user_follows_from_count!; end
sig { void }
def restore_user_user_follows_to_count!; end
sig { returns(T.nilable([T.nilable(::String), T.nilable(::String)])) }
def saved_change_to_account_status; end
@@ -2366,6 +2378,30 @@ class Domain::User::FaUser
sig { returns(T::Boolean) }
def saved_change_to_url_name?; end
sig { returns(T.nilable([T.nilable(::Integer), T.nilable(::Integer)])) }
def saved_change_to_user_post_creations_count; end
sig { returns(T::Boolean) }
def saved_change_to_user_post_creations_count?; end
sig { returns(T.nilable([T.nilable(::Integer), T.nilable(::Integer)])) }
def saved_change_to_user_post_favs_count; end
sig { returns(T::Boolean) }
def saved_change_to_user_post_favs_count?; end
sig { returns(T.nilable([T.nilable(::Integer), T.nilable(::Integer)])) }
def saved_change_to_user_user_follows_from_count; end
sig { returns(T::Boolean) }
def saved_change_to_user_user_follows_from_count?; end
sig { returns(T.nilable([T.nilable(::Integer), T.nilable(::Integer)])) }
def saved_change_to_user_user_follows_to_count; end
sig { returns(T::Boolean) }
def saved_change_to_user_user_follows_to_count?; end
sig { returns(T.nilable(::ActiveSupport::TimeWithZone)) }
def scanned_favs_at; end
@@ -2896,6 +2932,186 @@ class Domain::User::FaUser
sig { void }
def url_name_will_change!; end
sig { returns(T.nilable(::Integer)) }
def user_post_creations_count; end
sig { params(value: T.nilable(::Integer)).returns(T.nilable(::Integer)) }
def user_post_creations_count=(value); end
sig { returns(T::Boolean) }
def user_post_creations_count?; end
sig { returns(T.nilable(::Integer)) }
def user_post_creations_count_before_last_save; end
sig { returns(T.untyped) }
def user_post_creations_count_before_type_cast; end
sig { returns(T::Boolean) }
def user_post_creations_count_came_from_user?; end
sig { returns(T.nilable([T.nilable(::Integer), T.nilable(::Integer)])) }
def user_post_creations_count_change; end
sig { returns(T.nilable([T.nilable(::Integer), T.nilable(::Integer)])) }
def user_post_creations_count_change_to_be_saved; end
sig { params(from: T.nilable(::Integer), to: T.nilable(::Integer)).returns(T::Boolean) }
def user_post_creations_count_changed?(from: T.unsafe(nil), to: T.unsafe(nil)); end
sig { returns(T.nilable(::Integer)) }
def user_post_creations_count_in_database; end
sig { returns(T.nilable([T.nilable(::Integer), T.nilable(::Integer)])) }
def user_post_creations_count_previous_change; end
sig { params(from: T.nilable(::Integer), to: T.nilable(::Integer)).returns(T::Boolean) }
def user_post_creations_count_previously_changed?(from: T.unsafe(nil), to: T.unsafe(nil)); end
sig { returns(T.nilable(::Integer)) }
def user_post_creations_count_previously_was; end
sig { returns(T.nilable(::Integer)) }
def user_post_creations_count_was; end
sig { void }
def user_post_creations_count_will_change!; end
sig { returns(T.nilable(::Integer)) }
def user_post_favs_count; end
sig { params(value: T.nilable(::Integer)).returns(T.nilable(::Integer)) }
def user_post_favs_count=(value); end
sig { returns(T::Boolean) }
def user_post_favs_count?; end
sig { returns(T.nilable(::Integer)) }
def user_post_favs_count_before_last_save; end
sig { returns(T.untyped) }
def user_post_favs_count_before_type_cast; end
sig { returns(T::Boolean) }
def user_post_favs_count_came_from_user?; end
sig { returns(T.nilable([T.nilable(::Integer), T.nilable(::Integer)])) }
def user_post_favs_count_change; end
sig { returns(T.nilable([T.nilable(::Integer), T.nilable(::Integer)])) }
def user_post_favs_count_change_to_be_saved; end
sig { params(from: T.nilable(::Integer), to: T.nilable(::Integer)).returns(T::Boolean) }
def user_post_favs_count_changed?(from: T.unsafe(nil), to: T.unsafe(nil)); end
sig { returns(T.nilable(::Integer)) }
def user_post_favs_count_in_database; end
sig { returns(T.nilable([T.nilable(::Integer), T.nilable(::Integer)])) }
def user_post_favs_count_previous_change; end
sig { params(from: T.nilable(::Integer), to: T.nilable(::Integer)).returns(T::Boolean) }
def user_post_favs_count_previously_changed?(from: T.unsafe(nil), to: T.unsafe(nil)); end
sig { returns(T.nilable(::Integer)) }
def user_post_favs_count_previously_was; end
sig { returns(T.nilable(::Integer)) }
def user_post_favs_count_was; end
sig { void }
def user_post_favs_count_will_change!; end
sig { returns(T.nilable(::Integer)) }
def user_user_follows_from_count; end
sig { params(value: T.nilable(::Integer)).returns(T.nilable(::Integer)) }
def user_user_follows_from_count=(value); end
sig { returns(T::Boolean) }
def user_user_follows_from_count?; end
sig { returns(T.nilable(::Integer)) }
def user_user_follows_from_count_before_last_save; end
sig { returns(T.untyped) }
def user_user_follows_from_count_before_type_cast; end
sig { returns(T::Boolean) }
def user_user_follows_from_count_came_from_user?; end
sig { returns(T.nilable([T.nilable(::Integer), T.nilable(::Integer)])) }
def user_user_follows_from_count_change; end
sig { returns(T.nilable([T.nilable(::Integer), T.nilable(::Integer)])) }
def user_user_follows_from_count_change_to_be_saved; end
sig { params(from: T.nilable(::Integer), to: T.nilable(::Integer)).returns(T::Boolean) }
def user_user_follows_from_count_changed?(from: T.unsafe(nil), to: T.unsafe(nil)); end
sig { returns(T.nilable(::Integer)) }
def user_user_follows_from_count_in_database; end
sig { returns(T.nilable([T.nilable(::Integer), T.nilable(::Integer)])) }
def user_user_follows_from_count_previous_change; end
sig { params(from: T.nilable(::Integer), to: T.nilable(::Integer)).returns(T::Boolean) }
def user_user_follows_from_count_previously_changed?(from: T.unsafe(nil), to: T.unsafe(nil)); end
sig { returns(T.nilable(::Integer)) }
def user_user_follows_from_count_previously_was; end
sig { returns(T.nilable(::Integer)) }
def user_user_follows_from_count_was; end
sig { void }
def user_user_follows_from_count_will_change!; end
sig { returns(T.nilable(::Integer)) }
def user_user_follows_to_count; end
sig { params(value: T.nilable(::Integer)).returns(T.nilable(::Integer)) }
def user_user_follows_to_count=(value); end
sig { returns(T::Boolean) }
def user_user_follows_to_count?; end
sig { returns(T.nilable(::Integer)) }
def user_user_follows_to_count_before_last_save; end
sig { returns(T.untyped) }
def user_user_follows_to_count_before_type_cast; end
sig { returns(T::Boolean) }
def user_user_follows_to_count_came_from_user?; end
sig { returns(T.nilable([T.nilable(::Integer), T.nilable(::Integer)])) }
def user_user_follows_to_count_change; end
sig { returns(T.nilable([T.nilable(::Integer), T.nilable(::Integer)])) }
def user_user_follows_to_count_change_to_be_saved; end
sig { params(from: T.nilable(::Integer), to: T.nilable(::Integer)).returns(T::Boolean) }
def user_user_follows_to_count_changed?(from: T.unsafe(nil), to: T.unsafe(nil)); end
sig { returns(T.nilable(::Integer)) }
def user_user_follows_to_count_in_database; end
sig { returns(T.nilable([T.nilable(::Integer), T.nilable(::Integer)])) }
def user_user_follows_to_count_previous_change; end
sig { params(from: T.nilable(::Integer), to: T.nilable(::Integer)).returns(T::Boolean) }
def user_user_follows_to_count_previously_changed?(from: T.unsafe(nil), to: T.unsafe(nil)); end
sig { returns(T.nilable(::Integer)) }
def user_user_follows_to_count_previously_was; end
sig { returns(T.nilable(::Integer)) }
def user_user_follows_to_count_was; end
sig { void }
def user_user_follows_to_count_will_change!; end
sig { returns(T::Boolean) }
def will_save_change_to_account_status?; end
@@ -3000,6 +3216,18 @@ class Domain::User::FaUser
sig { returns(T::Boolean) }
def will_save_change_to_url_name?; end
sig { returns(T::Boolean) }
def will_save_change_to_user_post_creations_count?; end
sig { returns(T::Boolean) }
def will_save_change_to_user_post_favs_count?; end
sig { returns(T::Boolean) }
def will_save_change_to_user_user_follows_from_count?; end
sig { returns(T::Boolean) }
def will_save_change_to_user_user_follows_to_count?; end
end
module GeneratedRelationMethods

View File

@@ -1298,6 +1298,18 @@ class Domain::User::InkbunnyUser
sig { void }
def restore_updated_at!; end
sig { void }
def restore_user_post_creations_count!; end
sig { void }
def restore_user_post_favs_count!; end
sig { void }
def restore_user_user_follows_from_count!; end
sig { void }
def restore_user_user_follows_to_count!; end
sig { returns(T.nilable([T.nilable(::ActiveSupport::TimeWithZone), T.nilable(::ActiveSupport::TimeWithZone)])) }
def saved_change_to_created_at; end
@@ -1382,6 +1394,30 @@ class Domain::User::InkbunnyUser
sig { returns(T::Boolean) }
def saved_change_to_updated_at?; end
sig { returns(T.nilable([T.nilable(::Integer), T.nilable(::Integer)])) }
def saved_change_to_user_post_creations_count; end
sig { returns(T::Boolean) }
def saved_change_to_user_post_creations_count?; end
sig { returns(T.nilable([T.nilable(::Integer), T.nilable(::Integer)])) }
def saved_change_to_user_post_favs_count; end
sig { returns(T::Boolean) }
def saved_change_to_user_post_favs_count?; end
sig { returns(T.nilable([T.nilable(::Integer), T.nilable(::Integer)])) }
def saved_change_to_user_user_follows_from_count; end
sig { returns(T::Boolean) }
def saved_change_to_user_user_follows_from_count?; end
sig { returns(T.nilable([T.nilable(::Integer), T.nilable(::Integer)])) }
def saved_change_to_user_user_follows_to_count; end
sig { returns(T::Boolean) }
def saved_change_to_user_user_follows_to_count?; end
sig { returns(T.nilable(::ActiveSupport::TimeWithZone)) }
def scanned_gallery_at; end
@@ -1627,6 +1663,186 @@ class Domain::User::InkbunnyUser
sig { void }
def updated_at_will_change!; end
sig { returns(T.nilable(::Integer)) }
def user_post_creations_count; end
sig { params(value: T.nilable(::Integer)).returns(T.nilable(::Integer)) }
def user_post_creations_count=(value); end
sig { returns(T::Boolean) }
def user_post_creations_count?; end
sig { returns(T.nilable(::Integer)) }
def user_post_creations_count_before_last_save; end
sig { returns(T.untyped) }
def user_post_creations_count_before_type_cast; end
sig { returns(T::Boolean) }
def user_post_creations_count_came_from_user?; end
sig { returns(T.nilable([T.nilable(::Integer), T.nilable(::Integer)])) }
def user_post_creations_count_change; end
sig { returns(T.nilable([T.nilable(::Integer), T.nilable(::Integer)])) }
def user_post_creations_count_change_to_be_saved; end
sig { params(from: T.nilable(::Integer), to: T.nilable(::Integer)).returns(T::Boolean) }
def user_post_creations_count_changed?(from: T.unsafe(nil), to: T.unsafe(nil)); end
sig { returns(T.nilable(::Integer)) }
def user_post_creations_count_in_database; end
sig { returns(T.nilable([T.nilable(::Integer), T.nilable(::Integer)])) }
def user_post_creations_count_previous_change; end
sig { params(from: T.nilable(::Integer), to: T.nilable(::Integer)).returns(T::Boolean) }
def user_post_creations_count_previously_changed?(from: T.unsafe(nil), to: T.unsafe(nil)); end
sig { returns(T.nilable(::Integer)) }
def user_post_creations_count_previously_was; end
sig { returns(T.nilable(::Integer)) }
def user_post_creations_count_was; end
sig { void }
def user_post_creations_count_will_change!; end
sig { returns(T.nilable(::Integer)) }
def user_post_favs_count; end
sig { params(value: T.nilable(::Integer)).returns(T.nilable(::Integer)) }
def user_post_favs_count=(value); end
sig { returns(T::Boolean) }
def user_post_favs_count?; end
sig { returns(T.nilable(::Integer)) }
def user_post_favs_count_before_last_save; end
sig { returns(T.untyped) }
def user_post_favs_count_before_type_cast; end
sig { returns(T::Boolean) }
def user_post_favs_count_came_from_user?; end
sig { returns(T.nilable([T.nilable(::Integer), T.nilable(::Integer)])) }
def user_post_favs_count_change; end
sig { returns(T.nilable([T.nilable(::Integer), T.nilable(::Integer)])) }
def user_post_favs_count_change_to_be_saved; end
sig { params(from: T.nilable(::Integer), to: T.nilable(::Integer)).returns(T::Boolean) }
def user_post_favs_count_changed?(from: T.unsafe(nil), to: T.unsafe(nil)); end
sig { returns(T.nilable(::Integer)) }
def user_post_favs_count_in_database; end
sig { returns(T.nilable([T.nilable(::Integer), T.nilable(::Integer)])) }
def user_post_favs_count_previous_change; end
sig { params(from: T.nilable(::Integer), to: T.nilable(::Integer)).returns(T::Boolean) }
def user_post_favs_count_previously_changed?(from: T.unsafe(nil), to: T.unsafe(nil)); end
sig { returns(T.nilable(::Integer)) }
def user_post_favs_count_previously_was; end
sig { returns(T.nilable(::Integer)) }
def user_post_favs_count_was; end
sig { void }
def user_post_favs_count_will_change!; end
sig { returns(T.nilable(::Integer)) }
def user_user_follows_from_count; end
sig { params(value: T.nilable(::Integer)).returns(T.nilable(::Integer)) }
def user_user_follows_from_count=(value); end
sig { returns(T::Boolean) }
def user_user_follows_from_count?; end
sig { returns(T.nilable(::Integer)) }
def user_user_follows_from_count_before_last_save; end
sig { returns(T.untyped) }
def user_user_follows_from_count_before_type_cast; end
sig { returns(T::Boolean) }
def user_user_follows_from_count_came_from_user?; end
sig { returns(T.nilable([T.nilable(::Integer), T.nilable(::Integer)])) }
def user_user_follows_from_count_change; end
sig { returns(T.nilable([T.nilable(::Integer), T.nilable(::Integer)])) }
def user_user_follows_from_count_change_to_be_saved; end
sig { params(from: T.nilable(::Integer), to: T.nilable(::Integer)).returns(T::Boolean) }
def user_user_follows_from_count_changed?(from: T.unsafe(nil), to: T.unsafe(nil)); end
sig { returns(T.nilable(::Integer)) }
def user_user_follows_from_count_in_database; end
sig { returns(T.nilable([T.nilable(::Integer), T.nilable(::Integer)])) }
def user_user_follows_from_count_previous_change; end
sig { params(from: T.nilable(::Integer), to: T.nilable(::Integer)).returns(T::Boolean) }
def user_user_follows_from_count_previously_changed?(from: T.unsafe(nil), to: T.unsafe(nil)); end
sig { returns(T.nilable(::Integer)) }
def user_user_follows_from_count_previously_was; end
sig { returns(T.nilable(::Integer)) }
def user_user_follows_from_count_was; end
sig { void }
def user_user_follows_from_count_will_change!; end
sig { returns(T.nilable(::Integer)) }
def user_user_follows_to_count; end
sig { params(value: T.nilable(::Integer)).returns(T.nilable(::Integer)) }
def user_user_follows_to_count=(value); end
sig { returns(T::Boolean) }
def user_user_follows_to_count?; end
sig { returns(T.nilable(::Integer)) }
def user_user_follows_to_count_before_last_save; end
sig { returns(T.untyped) }
def user_user_follows_to_count_before_type_cast; end
sig { returns(T::Boolean) }
def user_user_follows_to_count_came_from_user?; end
sig { returns(T.nilable([T.nilable(::Integer), T.nilable(::Integer)])) }
def user_user_follows_to_count_change; end
sig { returns(T.nilable([T.nilable(::Integer), T.nilable(::Integer)])) }
def user_user_follows_to_count_change_to_be_saved; end
sig { params(from: T.nilable(::Integer), to: T.nilable(::Integer)).returns(T::Boolean) }
def user_user_follows_to_count_changed?(from: T.unsafe(nil), to: T.unsafe(nil)); end
sig { returns(T.nilable(::Integer)) }
def user_user_follows_to_count_in_database; end
sig { returns(T.nilable([T.nilable(::Integer), T.nilable(::Integer)])) }
def user_user_follows_to_count_previous_change; end
sig { params(from: T.nilable(::Integer), to: T.nilable(::Integer)).returns(T::Boolean) }
def user_user_follows_to_count_previously_changed?(from: T.unsafe(nil), to: T.unsafe(nil)); end
sig { returns(T.nilable(::Integer)) }
def user_user_follows_to_count_previously_was; end
sig { returns(T.nilable(::Integer)) }
def user_user_follows_to_count_was; end
sig { void }
def user_user_follows_to_count_will_change!; end
sig { returns(T::Boolean) }
def will_save_change_to_created_at?; end
@@ -1668,6 +1884,18 @@ class Domain::User::InkbunnyUser
sig { returns(T::Boolean) }
def will_save_change_to_updated_at?; end
sig { returns(T::Boolean) }
def will_save_change_to_user_post_creations_count?; end
sig { returns(T::Boolean) }
def will_save_change_to_user_post_favs_count?; end
sig { returns(T::Boolean) }
def will_save_change_to_user_user_follows_from_count?; end
sig { returns(T::Boolean) }
def will_save_change_to_user_user_follows_to_count?; end
end
module GeneratedRelationMethods

View File

@@ -0,0 +1,16 @@
# typed: true
# DO NOT EDIT MANUALLY
# This is an autogenerated file for dynamic methods in `Scraper::GenericHttpClientConfig`.
# Please instead update this file by running `bin/tapioca dsl Scraper::GenericHttpClientConfig`.
class Scraper::GenericHttpClientConfig
sig { returns(ColorLogger) }
def logger; end
class << self
sig { returns(ColorLogger) }
def logger; end
end
end

View File

@@ -826,12 +826,12 @@ describe Domain::Fa::Job::UserPageJob do
end
end
context "user not found" do
shared_examples "user not found" do |status_code|
let(:client_mock_config) do
[
{
uri: "https://www.furaffinity.net/user/onefatpokemon/",
status_code: 200,
status_code:,
content_type: "text/html",
contents:
SpecUtil.read_fixture_file(
@@ -855,4 +855,12 @@ describe Domain::Fa::Job::UserPageJob do
expect(user.state).to eq("error")
end
end
context "user not found with 200 status code" do
include_examples "user not found", 200
end
context "user not found with 400 status code" do
include_examples "user not found", 400
end
end

View File

@@ -0,0 +1,145 @@
# 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_count }.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_count
}.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_count).to eq(3)
# Calling the method should use the cached value
expect(user.user_post_creations_count).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_count
}.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_count
}.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_count).to eq(3)
# Calling the method should use the cached value
expect(user.user_post_favs_count).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_count }.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_count
}.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_count).to eq(3)
# Calling the method should use the cached value
expect(user.user_user_follows_from_count).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_count }.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_count
}.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_count).to eq(3)
# Calling the method should use the cached value
expect(user.user_user_follows_to_count).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
end