From 8bd6c4b2ae75007ae3cf87b31f20c0fbbeba74d2 Mon Sep 17 00:00:00 2001 From: Dylan Knutson Date: Wed, 20 Aug 2025 22:10:57 +0000 Subject: [PATCH] migrate e621 favs to own table --- .../domain/e621/job/scan_user_favs_job.rb | 8 +- app/models/domain/post/e621_post.rb | 2 +- app/models/domain/user.rb | 25 +- app/models/domain/user/e621_user.rb | 2 +- app/models/domain/user/fa_user.rb | 6 +- app/models/domain/user_post_fav.rb | 12 + .../user_post_fav/e621_user_post_fav.rb | 7 + .../domain/user_post_fav/fa_user_post_fav.rb | 15 +- ...0820204436_remove_fa_user_post_fav_rows.rb | 12 + ...250820205149_create_user_post_favs_e621.rb | 14 + ...0922_migrate_domain_user_post_favs_e621.rb | 70 + ...ove_idx_domain_user_post_favs_on_fav_id.rb | 21 + ...5340_add_indexes_to_user_post_favs_e621.rb | 33 + db/structure.sql | 60 +- sorbet/rbi/dsl/domain/post/e621_post.rbi | 4 +- sorbet/rbi/dsl/domain/user/e621_user.rbi | 6 +- sorbet/rbi/dsl/domain/user/inkbunny_user.rbi | 2 +- .../user_post_fav/e621_user_post_fav.rbi | 1436 +++++++++++++++++ .../domain/user_post_fav/fa_user_post_fav.rbi | 12 - .../domain/users_controller_spec.rb | 10 +- .../e621/job/scan_user_favs_job_spec.rb | 6 +- spec/models/domain/user_counter_cache_spec.rb | 2 +- 22 files changed, 1710 insertions(+), 55 deletions(-) create mode 100644 app/models/domain/user_post_fav/e621_user_post_fav.rb create mode 100644 db/migrate/20250820204436_remove_fa_user_post_fav_rows.rb create mode 100644 db/migrate/20250820205149_create_user_post_favs_e621.rb create mode 100644 db/migrate/20250820210922_migrate_domain_user_post_favs_e621.rb create mode 100644 db/migrate/20250820212318_remove_idx_domain_user_post_favs_on_fav_id.rb create mode 100644 db/migrate/20250820215340_add_indexes_to_user_post_favs_e621.rb create mode 100644 sorbet/rbi/dsl/domain/user_post_fav/e621_user_post_fav.rbi diff --git a/app/jobs/domain/e621/job/scan_user_favs_job.rb b/app/jobs/domain/e621/job/scan_user_favs_job.rb index da7a468b..ec0805d8 100644 --- a/app/jobs/domain/e621/job/scan_user_favs_job.rb +++ b/app/jobs/domain/e621/job/scan_user_favs_job.rb @@ -121,9 +121,11 @@ class Domain::E621::Job::ScanUserFavsJob < Domain::E621::Job::Base logger.info "upserting #{post_ids.size} favs" post_ids.each_slice(1000) do |slice| ReduxApplicationRecord.transaction do - Domain::UserPostFav.upsert_all( - slice.map { |post_id| { user_id: user.id, post_id: post_id } }, - unique_by: :index_domain_user_post_favs_on_user_id_and_post_id, + Domain::UserPostFav::E621UserPostFav.upsert_all( + slice.map do |post_id| + { user_id: user.id, post_id: post_id, removed: false } + end, + unique_by: %i[user_id post_id], ) end end diff --git a/app/models/domain/post/e621_post.rb b/app/models/domain/post/e621_post.rb index d520c822..f1f618e2 100644 --- a/app/models/domain/post/e621_post.rb +++ b/app/models/domain/post/e621_post.rb @@ -3,7 +3,7 @@ class Domain::Post::E621Post < Domain::Post aux_table :e621 has_single_file! - has_faving_users! Domain::User::E621User + has_faving_users! Domain::User::E621User, Domain::UserPostFav::E621UserPostFav belongs_to_groups! :pools, Domain::PostGroup::E621Pool, Domain::PostGroupJoin::E621PoolJoin diff --git a/app/models/domain/user.rb b/app/models/domain/user.rb index 92459fa6..75675294 100644 --- a/app/models/domain/user.rb +++ b/app/models/domain/user.rb @@ -147,9 +147,30 @@ class Domain::User < ReduxApplicationRecord class_name: klass.name end - sig { params(klass: T.class_of(Domain::Post)).void } - def self.has_faved_posts!(klass) + sig do + params( + klass: T.class_of(Domain::Post), + fav_model_type: T.class_of(Domain::UserPostFav), + fav_model_order: T.untyped, + ).void + end + def self.has_faved_posts!( + klass, + fav_model_type = Domain::UserPostFav, + fav_model_order: nil + ) self.class_has_faved_posts = klass + + has_many :user_post_favs, + -> do + rel = extending(CounterCacheWithFallback[:user_post_favs]) + rel = rel.order(fav_model_order) if fav_model_order + rel + end, + class_name: fav_model_type.name, + inverse_of: :user, + dependent: :destroy + has_many :faved_posts, -> { order(klass.param_order_attribute => :desc) }, through: :user_post_favs, diff --git a/app/models/domain/user/e621_user.rb b/app/models/domain/user/e621_user.rb index e637f342..1424315b 100644 --- a/app/models/domain/user/e621_user.rb +++ b/app/models/domain/user/e621_user.rb @@ -17,7 +17,7 @@ class Domain::User::E621User < Domain::User validates :e621_id, presence: true validates :name, length: { minimum: 1 }, allow_nil: false - has_faved_posts! Domain::Post::E621Post + has_faved_posts! Domain::Post::E621Post, Domain::UserPostFav::E621UserPostFav sig { override.returns([String, Symbol]) } def self.param_prefix_and_attribute diff --git a/app/models/domain/user/fa_user.rb b/app/models/domain/user/fa_user.rb index 80b7a4cd..e9f0d14b 100644 --- a/app/models/domain/user/fa_user.rb +++ b/app/models/domain/user/fa_user.rb @@ -29,7 +29,11 @@ class Domain::User::FaUser < Domain::User has_followed_users! Domain::User::FaUser has_followed_by_users! Domain::User::FaUser has_created_posts! Domain::Post::FaPost - has_faved_posts! Domain::Post::FaPost + has_faved_posts! Domain::Post::FaPost, + Domain::UserPostFav::FaUserPostFav, + fav_model_order: { + fa_fav_id: :desc, + } enum :state, { ok: "ok", account_disabled: "account_disabled", error: "error" }, diff --git a/app/models/domain/user_post_fav.rb b/app/models/domain/user_post_fav.rb index a677ce66..aac42446 100644 --- a/app/models/domain/user_post_fav.rb +++ b/app/models/domain/user_post_fav.rb @@ -16,6 +16,18 @@ class Domain::UserPostFav < ReduxApplicationRecord belongs_to :post, class_name: "Domain::Post", inverse_of: :user_post_favs + sig { params(user_klass: T.class_of(Domain::User), post_klass: T.class_of(Domain::Post)).void } + def self.user_post_fav_relationships(user_klass, post_klass) + belongs_to_with_counter_cache :user, + class_name: user_klass.name, + inverse_of: :user_post_favs, + counter_cache: :user_post_favs_count + + belongs_to :post, + class_name: post_klass.name, + inverse_of: :user_post_favs + end + scope :for_post_type, ->(post_klass) do post_klass = T.cast(post_klass, T.class_of(Domain::Post)) diff --git a/app/models/domain/user_post_fav/e621_user_post_fav.rb b/app/models/domain/user_post_fav/e621_user_post_fav.rb new file mode 100644 index 00000000..39ef11dc --- /dev/null +++ b/app/models/domain/user_post_fav/e621_user_post_fav.rb @@ -0,0 +1,7 @@ +# typed: strict +# frozen_string_literal: true + +class Domain::UserPostFav::E621UserPostFav < Domain::UserPostFav + self.table_name = "domain_user_post_favs_e621" + user_post_fav_relationships Domain::User::E621User, Domain::Post::E621Post +end diff --git a/app/models/domain/user_post_fav/fa_user_post_fav.rb b/app/models/domain/user_post_fav/fa_user_post_fav.rb index 67bf3972..db9be8a5 100644 --- a/app/models/domain/user_post_fav/fa_user_post_fav.rb +++ b/app/models/domain/user_post_fav/fa_user_post_fav.rb @@ -1,24 +1,11 @@ # typed: strict class Domain::UserPostFav::FaUserPostFav < Domain::UserPostFav self.table_name = "domain_user_post_favs_fa" - - belongs_to_with_counter_cache :user, - class_name: "Domain::User::FaUser", - inverse_of: :user_post_favs, - counter_cache: :user_post_favs_count - - belongs_to :post, - class_name: "Domain::Post::FaPost", - inverse_of: :user_post_favs + user_post_fav_relationships Domain::User::FaUser, Domain::Post::FaPost scope :with_explicit_time_and_id, -> { where.not(explicit_time: nil).where.not(fa_fav_id: nil) } - scope :with_inferred_time_and_id, - -> { where.not(inferred_time: nil).where.not(fa_fav_id: nil) } - - scope :with_fa_fav_id, -> { where.not(fa_fav_id: nil) } - validates :fa_fav_id, uniqueness: true, if: :fa_fav_id? before_save :set_inferred_time diff --git a/db/migrate/20250820204436_remove_fa_user_post_fav_rows.rb b/db/migrate/20250820204436_remove_fa_user_post_fav_rows.rb new file mode 100644 index 00000000..bcef153a --- /dev/null +++ b/db/migrate/20250820204436_remove_fa_user_post_fav_rows.rb @@ -0,0 +1,12 @@ +class RemoveFaUserPostFavRows < ActiveRecord::Migration[7.2] + def up + execute <<-SQL + DELETE FROM domain_user_post_favs + WHERE type = 'Domain::UserPostFav::FaUserPostFav_INVALID' + SQL + end + + def down + raise ActiveRecord::IrreversibleMigration + end +end diff --git a/db/migrate/20250820205149_create_user_post_favs_e621.rb b/db/migrate/20250820205149_create_user_post_favs_e621.rb new file mode 100644 index 00000000..069ddb82 --- /dev/null +++ b/db/migrate/20250820205149_create_user_post_favs_e621.rb @@ -0,0 +1,14 @@ +# typed: strict +# frozen_string_literal: true + +class CreateUserPostFavsE621 < ActiveRecord::Migration[7.2] + sig { void } + def change + create_table :domain_user_post_favs_e621, + primary_key: %i[user_id post_id] do |t| + t.bigint :user_id, null: false + t.bigint :post_id, null: false + t.boolean :removed, null: false, default: false + end + end +end diff --git a/db/migrate/20250820210922_migrate_domain_user_post_favs_e621.rb b/db/migrate/20250820210922_migrate_domain_user_post_favs_e621.rb new file mode 100644 index 00000000..7badd746 --- /dev/null +++ b/db/migrate/20250820210922_migrate_domain_user_post_favs_e621.rb @@ -0,0 +1,70 @@ +# typed: strict +# frozen_string_literal: true + +class MigrateDomainUserPostFavsE621 < ActiveRecord::Migration[7.2] + disable_ddl_transaction! + + sig { void } + def up + puts "Getting min/max user id..." + min_user_id = + Domain::User.where(type: "Domain::User::E621User").minimum(:id) + max_user_id = + Domain::User.where(type: "Domain::User::E621User").maximum(:id) + 1 + max_batch_size = 1000 + batch_count = ((max_user_id - min_user_id) / max_batch_size.to_f).ceil + + puts "Migrating #{batch_count} batches..." + shards = + T.cast( + batch_count.times.map do |batch_index| + start_user_id = min_user_id + batch_index * max_batch_size + end_user_id = [start_user_id + max_batch_size, max_user_id].min + + Domain::User.where( + type: "Domain::User::E621User", + id: start_user_id...end_user_id, + ).pluck(:id) + end, + T::Array[T::Array[Integer]], + ) + + num_threads = 4 + pool = + T.let( + Concurrent::FixedThreadPool.new(num_threads), + Concurrent::FixedThreadPool, + ) + shards.each_with_index do |shard, index| + pool.post do + puts "migrate shard #{index + 1} of #{shards.size}: #{shard.minmax.join(" -> ")} (#{shard.size} users)" + migrate_shard(shard) + puts "done: shard #{index + 1} of #{shards.size}: #{shard.minmax.join(" -> ")}" + end + end + + pool.shutdown + pool.wait_for_termination + end + + sig { params(user_ids: T::Array[Integer]).void } + def migrate_shard(user_ids) + ActiveRecord::Base.with_connection do |connection| + connection.execute <<-SQL + INSERT INTO + domain_user_post_favs_e621 ( + user_id, + post_id, + removed + ) + SELECT + user_id, + post_id, + removed + FROM domain_user_post_favs + WHERE user_id IN (#{user_ids.join(", ")}) + ON CONFLICT (user_id, post_id) DO NOTHING + SQL + end + end +end diff --git a/db/migrate/20250820212318_remove_idx_domain_user_post_favs_on_fav_id.rb b/db/migrate/20250820212318_remove_idx_domain_user_post_favs_on_fav_id.rb new file mode 100644 index 00000000..b6eed8f9 --- /dev/null +++ b/db/migrate/20250820212318_remove_idx_domain_user_post_favs_on_fav_id.rb @@ -0,0 +1,21 @@ +class RemoveIdxDomainUserPostFavsOnFavId < ActiveRecord::Migration[7.2] + def up + execute <<-SQL + DROP INDEX index_domain_user_post_favs_on_type_and_user_id; + DROP INDEX idx_domain_user_post_favs_on_fav_id; + SQL + end + + def down + execute <<-SQL + CREATE UNIQUE INDEX idx_domain_user_post_favs_on_fav_id + ON domain_user_post_favs USING btree + (((json_attributes ->> 'fav_id'::text)::integer) ASC NULLS LAST) + WHERE type = 'Domain::UserPostFav::FaUserPostFav_INVALID'::domain_user_post_fav_type; + + CREATE INDEX index_domain_user_post_favs_on_type_and_user_id + ON domain_user_post_favs USING btree + (type ASC NULLS LAST, user_id ASC NULLS LAST); + SQL + end +end diff --git a/db/migrate/20250820215340_add_indexes_to_user_post_favs_e621.rb b/db/migrate/20250820215340_add_indexes_to_user_post_favs_e621.rb new file mode 100644 index 00000000..22e40269 --- /dev/null +++ b/db/migrate/20250820215340_add_indexes_to_user_post_favs_e621.rb @@ -0,0 +1,33 @@ +# typed: strict +# +class AddIndexesToUserPostFavsE621 < ActiveRecord::Migration[7.2] + sig { void } + def change + change_table :domain_user_post_favs_e621 do |t| + t.index %i[post_id user_id] + end + + reversible do |dir| + dir.up do + add_foreign_key :domain_user_post_favs_e621, + :domain_users_e621_aux, + primary_key: :base_table_id, + column: :user_id, + index: false, + name: "fk_domain_user_post_favs_e621_user_id" + add_foreign_key :domain_user_post_favs_e621, + :domain_posts_e621_aux, + primary_key: :base_table_id, + column: :post_id, + index: false, + name: "fk_domain_user_post_favs_e621_post_id" + end + dir.down do + remove_foreign_key :domain_user_post_favs_e621, + name: "fk_domain_user_post_favs_e621_user_id" + remove_foreign_key :domain_user_post_favs_e621, + name: "fk_domain_user_post_favs_e621_post_id" + end + end + end +end diff --git a/db/structure.sql b/db/structure.sql index 93d325c0..7ded30c2 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -1,4 +1,4 @@ -\restrict huxfo3NM6M7Nj4JUdHDWXGq7DoLnw9sDIrV5g3aVIBWghR5vgItCQUJG6cJ3EJf +\restrict fsnJecu1BUZk39yUe5E3zqbZEe6yKihIQHKEWYdhLLHCBtdUoLtB3L0VBXECSF8 -- Dumped from database version 17.6 (Debian 17.6-1.pgdg13+1) -- Dumped by pg_dump version 17.6 (Debian 17.6-1.pgdg12+1) @@ -1972,6 +1972,19 @@ CREATE TABLE public.domain_user_post_favs ( WITH (autovacuum_enabled='true'); +-- +-- Name: domain_user_post_favs_e621; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.domain_user_post_favs_e621 ( + user_id bigint NOT NULL, + post_id bigint NOT NULL, + removed boolean DEFAULT false NOT NULL, + explicit_time timestamp(6) without time zone, + inferred_time timestamp(6) without time zone +); + + -- -- Name: domain_user_post_favs_fa; Type: TABLE; Schema: public; Owner: - -- @@ -3624,6 +3637,14 @@ ALTER TABLE ONLY public.domain_user_job_event_profile_scans ADD CONSTRAINT domain_user_job_event_profile_scans_pkey PRIMARY KEY (id); +-- +-- Name: domain_user_post_favs_e621 domain_user_post_favs_e621_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.domain_user_post_favs_e621 + ADD CONSTRAINT domain_user_post_favs_e621_pkey PRIMARY KEY (user_id, post_id); + + -- -- Name: domain_user_post_favs_fa domain_user_post_favs_fa_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- @@ -3913,13 +3934,6 @@ CREATE UNIQUE INDEX idx_domain_post_groups_on_sofurry_id ON public.domain_post_g CREATE UNIQUE INDEX idx_domain_posts_on_sofurry_id ON public.domain_posts USING btree ((((json_attributes ->> 'sofurry_id'::text))::integer)) WHERE (type = 'Domain::Post::SofurryPost'::public.domain_post_type); --- --- Name: idx_domain_user_post_favs_on_fav_id; Type: INDEX; Schema: public; Owner: - --- - -CREATE UNIQUE INDEX idx_domain_user_post_favs_on_fav_id ON public.domain_user_post_favs USING btree ((((json_attributes ->> 'fav_id'::text))::integer)) WHERE (type = 'Domain::UserPostFav::FaUserPostFav_INVALID'::public.domain_user_post_fav_type); - - -- -- Name: idx_domain_users_e621_on_name_lower; Type: INDEX; Schema: public; Owner: - -- @@ -4732,6 +4746,13 @@ CREATE INDEX index_domain_user_post_fav_user_factors_on_embedding ON public.doma CREATE UNIQUE INDEX index_domain_user_post_fav_user_factors_on_user_id ON public.domain_user_post_fav_user_factors USING btree (user_id); +-- +-- Name: index_domain_user_post_favs_e621_on_post_id_and_user_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_domain_user_post_favs_e621_on_post_id_and_user_id ON public.domain_user_post_favs_e621 USING btree (post_id, user_id); + + -- -- Name: index_domain_user_post_favs_fa_on_fa_fav_id; Type: INDEX; Schema: public; Owner: - -- @@ -5656,6 +5677,22 @@ ALTER INDEX public.index_blob_files_on_sha256 ATTACH PARTITION public.index_blob ALTER INDEX public.index_blob_files_on_sha256 ATTACH PARTITION public.index_blob_files_63_on_sha256; +-- +-- Name: domain_user_post_favs_e621 fk_domain_user_post_favs_e621_post_id; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.domain_user_post_favs_e621 + ADD CONSTRAINT fk_domain_user_post_favs_e621_post_id FOREIGN KEY (post_id) REFERENCES public.domain_posts_e621_aux(base_table_id); + + +-- +-- Name: domain_user_post_favs_e621 fk_domain_user_post_favs_e621_user_id; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.domain_user_post_favs_e621 + ADD CONSTRAINT fk_domain_user_post_favs_e621_user_id FOREIGN KEY (user_id) REFERENCES public.domain_users_e621_aux(base_table_id); + + -- -- Name: domain_user_post_favs_fa fk_domain_user_post_favs_fa_post_id; Type: FK CONSTRAINT; Schema: public; Owner: - -- @@ -6092,11 +6129,16 @@ ALTER TABLE ONLY public.domain_twitter_tweets -- PostgreSQL database dump complete -- -\unrestrict huxfo3NM6M7Nj4JUdHDWXGq7DoLnw9sDIrV5g3aVIBWghR5vgItCQUJG6cJ3EJf +\unrestrict fsnJecu1BUZk39yUe5E3zqbZEe6yKihIQHKEWYdhLLHCBtdUoLtB3L0VBXECSF8 SET search_path TO "$user", public; INSERT INTO "schema_migrations" (version) VALUES +('20250820215340'), +('20250820212318'), +('20250820210922'), +('20250820205149'), +('20250820204436'), ('20250820145726'), ('20250819012459'), ('20250819001506'), diff --git a/sorbet/rbi/dsl/domain/post/e621_post.rbi b/sorbet/rbi/dsl/domain/post/e621_post.rbi index b3e207d8..f3411872 100644 --- a/sorbet/rbi/dsl/domain/post/e621_post.rbi +++ b/sorbet/rbi/dsl/domain/post/e621_post.rbi @@ -719,10 +719,10 @@ class Domain::Post::E621Post # This method is created by ActiveRecord on the `Domain::Post::E621Post` class because it declared `has_many :user_post_favs`. # 🔗 [Rails guide for `has_many` association](https://guides.rubyonrails.org/association_basics.html#the-has-many-association) - sig { returns(::Domain::UserPostFav::PrivateCollectionProxy) } + sig { returns(::Domain::UserPostFav::E621UserPostFav::PrivateCollectionProxy) } def user_post_favs; end - sig { params(value: T::Enumerable[::Domain::UserPostFav]).void } + sig { params(value: T::Enumerable[::Domain::UserPostFav::E621UserPostFav]).void } def user_post_favs=(value); end end diff --git a/sorbet/rbi/dsl/domain/user/e621_user.rbi b/sorbet/rbi/dsl/domain/user/e621_user.rbi index 0c440a1b..ad01362d 100644 --- a/sorbet/rbi/dsl/domain/user/e621_user.rbi +++ b/sorbet/rbi/dsl/domain/user/e621_user.rbi @@ -672,12 +672,12 @@ class Domain::User::E621User sig { params(ids: T::Array[T.untyped]).returns(T::Array[T.untyped]) } def user_post_fav_ids=(ids); end - # This method is created by ActiveRecord on the `Domain::User` class because it declared `has_many :user_post_favs`. + # This method is created by ActiveRecord on the `Domain::User::E621User` class because it declared `has_many :user_post_favs`. # 🔗 [Rails guide for `has_many` association](https://guides.rubyonrails.org/association_basics.html#the-has-many-association) - sig { returns(::Domain::UserPostFav::PrivateCollectionProxy) } + sig { returns(::Domain::UserPostFav::E621UserPostFav::PrivateCollectionProxy) } def user_post_favs; end - sig { params(value: T::Enumerable[::Domain::UserPostFav]).void } + sig { params(value: T::Enumerable[::Domain::UserPostFav::E621UserPostFav]).void } def user_post_favs=(value); end sig { returns(T::Array[T.untyped]) } diff --git a/sorbet/rbi/dsl/domain/user/inkbunny_user.rbi b/sorbet/rbi/dsl/domain/user/inkbunny_user.rbi index 366029ea..f29ee047 100644 --- a/sorbet/rbi/dsl/domain/user/inkbunny_user.rbi +++ b/sorbet/rbi/dsl/domain/user/inkbunny_user.rbi @@ -699,7 +699,7 @@ class Domain::User::InkbunnyUser sig { params(ids: T::Array[T.untyped]).returns(T::Array[T.untyped]) } def user_post_fav_ids=(ids); end - # This method is created by ActiveRecord on the `Domain::User` class because it declared `has_many :user_post_favs`. + # This method is created by ActiveRecord on the `Domain::User::InkbunnyUser` class because it declared `has_many :user_post_favs`. # 🔗 [Rails guide for `has_many` association](https://guides.rubyonrails.org/association_basics.html#the-has-many-association) sig { returns(::Domain::UserPostFav::PrivateCollectionProxy) } def user_post_favs; end diff --git a/sorbet/rbi/dsl/domain/user_post_fav/e621_user_post_fav.rbi b/sorbet/rbi/dsl/domain/user_post_fav/e621_user_post_fav.rbi new file mode 100644 index 00000000..a30cfc58 --- /dev/null +++ b/sorbet/rbi/dsl/domain/user_post_fav/e621_user_post_fav.rbi @@ -0,0 +1,1436 @@ +# typed: true + +# DO NOT EDIT MANUALLY +# This is an autogenerated file for dynamic methods in `Domain::UserPostFav::E621UserPostFav`. +# Please instead update this file by running `bin/tapioca dsl Domain::UserPostFav::E621UserPostFav`. + + +class Domain::UserPostFav::E621UserPostFav + include GeneratedAssociationMethods + include GeneratedAttributeMethods + extend CommonRelationMethods + extend GeneratedRelationMethods + + sig { returns(ColorLogger) } + def logger; end + + private + + sig { returns(NilClass) } + def to_ary; end + + class << self + sig do + params( + name: Symbol, + type: T.any(Symbol, ActiveModel::Type::Value), + options: T.nilable(T::Hash[Symbol, T.untyped]) + ).void + end + def attr_json(name, type, options = nil); end + + sig do + params( + default_container_attribute: T.nilable(Symbol), + bad_cast: T.nilable(Symbol), + unknown_key: T.nilable(Symbol) + ).void + end + def attr_json_config(default_container_attribute: nil, bad_cast: nil, unknown_key: nil); end + + sig { returns(T::Array[Symbol]) } + def attr_json_registry; end + + sig { returns(ColorLogger) } + def logger; end + + sig do + params( + attributes: T.untyped, + block: T.nilable(T.proc.params(object: ::Domain::UserPostFav::E621UserPostFav).void) + ).returns(::Domain::UserPostFav::E621UserPostFav) + end + def new(attributes = nil, &block); end + end + + module CommonRelationMethods + sig do + params( + block: T.nilable(T.proc.params(record: ::Domain::UserPostFav::E621UserPostFav).returns(T.untyped)) + ).returns(T::Boolean) + end + def any?(&block); end + + sig { params(column_name: T.any(String, Symbol)).returns(T.any(Integer, Float, BigDecimal)) } + def average(column_name); end + + sig do + params( + block: T.nilable(T.proc.params(object: ::Domain::UserPostFav::E621UserPostFav).void) + ).returns(::Domain::UserPostFav::E621UserPostFav) + end + sig do + params( + attributes: T::Array[T.untyped], + block: T.nilable(T.proc.params(object: ::Domain::UserPostFav::E621UserPostFav).void) + ).returns(T::Array[::Domain::UserPostFav::E621UserPostFav]) + end + sig do + params( + attributes: T.untyped, + block: T.nilable(T.proc.params(object: ::Domain::UserPostFav::E621UserPostFav).void) + ).returns(::Domain::UserPostFav::E621UserPostFav) + end + def build(attributes = nil, &block); end + + sig { params(operation: Symbol, column_name: T.any(String, Symbol)).returns(T.any(Integer, Float, BigDecimal)) } + def calculate(operation, column_name); end + + sig { params(column_name: T.nilable(T.any(String, Symbol))).returns(Integer) } + sig do + params( + column_name: NilClass, + block: T.proc.params(object: ::Domain::UserPostFav::E621UserPostFav).void + ).returns(Integer) + end + def count(column_name = nil, &block); end + + sig do + params( + block: T.nilable(T.proc.params(object: ::Domain::UserPostFav::E621UserPostFav).void) + ).returns(::Domain::UserPostFav::E621UserPostFav) + end + sig do + params( + attributes: T::Array[T.untyped], + block: T.nilable(T.proc.params(object: ::Domain::UserPostFav::E621UserPostFav).void) + ).returns(T::Array[::Domain::UserPostFav::E621UserPostFav]) + end + sig do + params( + attributes: T.untyped, + block: T.nilable(T.proc.params(object: ::Domain::UserPostFav::E621UserPostFav).void) + ).returns(::Domain::UserPostFav::E621UserPostFav) + end + def create(attributes = nil, &block); end + + sig do + params( + block: T.nilable(T.proc.params(object: ::Domain::UserPostFav::E621UserPostFav).void) + ).returns(::Domain::UserPostFav::E621UserPostFav) + end + sig do + params( + attributes: T::Array[T.untyped], + block: T.nilable(T.proc.params(object: ::Domain::UserPostFav::E621UserPostFav).void) + ).returns(T::Array[::Domain::UserPostFav::E621UserPostFav]) + end + sig do + params( + attributes: T.untyped, + block: T.nilable(T.proc.params(object: ::Domain::UserPostFav::E621UserPostFav).void) + ).returns(::Domain::UserPostFav::E621UserPostFav) + end + def create!(attributes = nil, &block); end + + sig do + params( + attributes: T::Array[T.untyped], + block: T.nilable(T.proc.params(object: ::Domain::UserPostFav::E621UserPostFav).void) + ).returns(T::Array[::Domain::UserPostFav::E621UserPostFav]) + end + sig do + params( + attributes: T.untyped, + block: T.nilable(T.proc.params(object: ::Domain::UserPostFav::E621UserPostFav).void) + ).returns(::Domain::UserPostFav::E621UserPostFav) + end + def create_or_find_by(attributes, &block); end + + sig do + params( + attributes: T::Array[T.untyped], + block: T.nilable(T.proc.params(object: ::Domain::UserPostFav::E621UserPostFav).void) + ).returns(T::Array[::Domain::UserPostFav::E621UserPostFav]) + end + sig do + params( + attributes: T.untyped, + block: T.nilable(T.proc.params(object: ::Domain::UserPostFav::E621UserPostFav).void) + ).returns(::Domain::UserPostFav::E621UserPostFav) + end + def create_or_find_by!(attributes, &block); end + + sig { returns(T::Array[::Domain::UserPostFav::E621UserPostFav]) } + def destroy_all; end + + sig { params(conditions: T.untyped).returns(T::Boolean) } + def exists?(conditions = :none); end + + sig { returns(T.nilable(::Domain::UserPostFav::E621UserPostFav)) } + def fifth; end + + sig { returns(::Domain::UserPostFav::E621UserPostFav) } + def fifth!; end + + sig do + params( + args: T::Array[T.any(String, Symbol, ::ActiveSupport::Multibyte::Chars, T::Boolean, BigDecimal, Numeric, ::ActiveRecord::Type::Binary::Data, ::ActiveRecord::Type::Time::Value, Date, Time, ::ActiveSupport::Duration, T::Class[T.anything])] + ).returns(::Domain::UserPostFav::E621UserPostFav) + end + sig do + params( + args: T::Array[T::Array[T.any(String, Symbol, ::ActiveSupport::Multibyte::Chars, T::Boolean, BigDecimal, Numeric, ::ActiveRecord::Type::Binary::Data, ::ActiveRecord::Type::Time::Value, Date, Time, ::ActiveSupport::Duration, T::Class[T.anything])]] + ).returns(T::Enumerable[::Domain::UserPostFav::E621UserPostFav]) + end + sig do + params( + args: NilClass, + block: T.proc.params(object: ::Domain::UserPostFav::E621UserPostFav).void + ).returns(T.nilable(::Domain::UserPostFav::E621UserPostFav)) + end + def find(args = nil, &block); end + + sig { params(args: T.untyped).returns(T.nilable(::Domain::UserPostFav::E621UserPostFav)) } + def find_by(*args); end + + sig { params(args: T.untyped).returns(::Domain::UserPostFav::E621UserPostFav) } + def find_by!(*args); end + + sig do + params( + start: T.untyped, + finish: T.untyped, + batch_size: Integer, + error_on_ignore: T.untyped, + order: Symbol, + block: T.proc.params(object: ::Domain::UserPostFav::E621UserPostFav).void + ).void + end + sig do + params( + start: T.untyped, + finish: T.untyped, + batch_size: Integer, + error_on_ignore: T.untyped, + order: Symbol + ).returns(T::Enumerator[::Domain::UserPostFav::E621UserPostFav]) + end + def find_each(start: nil, finish: nil, batch_size: 1000, error_on_ignore: nil, order: :asc, &block); end + + sig do + params( + start: T.untyped, + finish: T.untyped, + batch_size: Integer, + error_on_ignore: T.untyped, + order: Symbol, + block: T.proc.params(object: T::Array[::Domain::UserPostFav::E621UserPostFav]).void + ).void + end + sig do + params( + start: T.untyped, + finish: T.untyped, + batch_size: Integer, + error_on_ignore: T.untyped, + order: Symbol + ).returns(T::Enumerator[T::Enumerator[::Domain::UserPostFav::E621UserPostFav]]) + end + def find_in_batches(start: nil, finish: nil, batch_size: 1000, error_on_ignore: nil, order: :asc, &block); end + + sig do + params( + attributes: T::Array[T.untyped], + block: T.nilable(T.proc.params(object: ::Domain::UserPostFav::E621UserPostFav).void) + ).returns(T::Array[::Domain::UserPostFav::E621UserPostFav]) + end + sig do + params( + attributes: T.untyped, + block: T.nilable(T.proc.params(object: ::Domain::UserPostFav::E621UserPostFav).void) + ).returns(::Domain::UserPostFav::E621UserPostFav) + end + def find_or_create_by(attributes, &block); end + + sig do + params( + attributes: T::Array[T.untyped], + block: T.nilable(T.proc.params(object: ::Domain::UserPostFav::E621UserPostFav).void) + ).returns(T::Array[::Domain::UserPostFav::E621UserPostFav]) + end + sig do + params( + attributes: T.untyped, + block: T.nilable(T.proc.params(object: ::Domain::UserPostFav::E621UserPostFav).void) + ).returns(::Domain::UserPostFav::E621UserPostFav) + end + def find_or_create_by!(attributes, &block); end + + sig do + params( + attributes: T::Array[T.untyped], + block: T.nilable(T.proc.params(object: ::Domain::UserPostFav::E621UserPostFav).void) + ).returns(T::Array[::Domain::UserPostFav::E621UserPostFav]) + end + sig do + params( + attributes: T.untyped, + block: T.nilable(T.proc.params(object: ::Domain::UserPostFav::E621UserPostFav).void) + ).returns(::Domain::UserPostFav::E621UserPostFav) + end + def find_or_initialize_by(attributes, &block); end + + sig { params(signed_id: T.untyped, purpose: T.untyped).returns(T.nilable(::Domain::UserPostFav::E621UserPostFav)) } + def find_signed(signed_id, purpose: nil); end + + sig { params(signed_id: T.untyped, purpose: T.untyped).returns(::Domain::UserPostFav::E621UserPostFav) } + def find_signed!(signed_id, purpose: nil); end + + sig { params(arg: T.untyped, args: T.untyped).returns(::Domain::UserPostFav::E621UserPostFav) } + def find_sole_by(arg, *args); end + + sig { returns(T.nilable(::Domain::UserPostFav::E621UserPostFav)) } + sig { params(limit: Integer).returns(T::Array[::Domain::UserPostFav::E621UserPostFav]) } + def first(limit = nil); end + + sig { returns(::Domain::UserPostFav::E621UserPostFav) } + def first!; end + + sig { returns(T.nilable(::Domain::UserPostFav::E621UserPostFav)) } + def forty_two; end + + sig { returns(::Domain::UserPostFav::E621UserPostFav) } + def forty_two!; end + + sig { returns(T.nilable(::Domain::UserPostFav::E621UserPostFav)) } + def fourth; end + + sig { returns(::Domain::UserPostFav::E621UserPostFav) } + def fourth!; end + + sig { returns(Array) } + def ids; end + + sig do + params( + of: Integer, + start: T.untyped, + finish: T.untyped, + load: T.untyped, + error_on_ignore: T.untyped, + order: Symbol, + use_ranges: T.untyped, + block: T.proc.params(object: PrivateRelation).void + ).void + end + sig do + params( + of: Integer, + start: T.untyped, + finish: T.untyped, + load: T.untyped, + error_on_ignore: T.untyped, + order: Symbol, + use_ranges: T.untyped + ).returns(::ActiveRecord::Batches::BatchEnumerator) + end + def in_batches(of: 1000, start: nil, finish: nil, load: false, error_on_ignore: nil, order: :asc, use_ranges: nil, &block); end + + sig { params(record: T.untyped).returns(T::Boolean) } + def include?(record); end + + sig { returns(T.nilable(::Domain::UserPostFav::E621UserPostFav)) } + sig { params(limit: Integer).returns(T::Array[::Domain::UserPostFav::E621UserPostFav]) } + def last(limit = nil); end + + sig { returns(::Domain::UserPostFav::E621UserPostFav) } + def last!; end + + sig do + params( + block: T.nilable(T.proc.params(record: ::Domain::UserPostFav::E621UserPostFav).returns(T.untyped)) + ).returns(T::Boolean) + end + def many?(&block); end + + sig { params(column_name: T.any(String, Symbol)).returns(T.untyped) } + def maximum(column_name); end + + sig { params(record: T.untyped).returns(T::Boolean) } + def member?(record); end + + sig { params(column_name: T.any(String, Symbol)).returns(T.untyped) } + def minimum(column_name); end + + sig do + params( + block: T.nilable(T.proc.params(object: ::Domain::UserPostFav::E621UserPostFav).void) + ).returns(::Domain::UserPostFav::E621UserPostFav) + end + sig do + params( + attributes: T::Array[T.untyped], + block: T.nilable(T.proc.params(object: ::Domain::UserPostFav::E621UserPostFav).void) + ).returns(T::Array[::Domain::UserPostFav::E621UserPostFav]) + end + sig do + params( + attributes: T.untyped, + block: T.nilable(T.proc.params(object: ::Domain::UserPostFav::E621UserPostFav).void) + ).returns(::Domain::UserPostFav::E621UserPostFav) + end + def new(attributes = nil, &block); end + + sig do + params( + block: T.nilable(T.proc.params(record: ::Domain::UserPostFav::E621UserPostFav).returns(T.untyped)) + ).returns(T::Boolean) + end + def none?(&block); end + + sig do + params( + block: T.nilable(T.proc.params(record: ::Domain::UserPostFav::E621UserPostFav).returns(T.untyped)) + ).returns(T::Boolean) + end + def one?(&block); end + + sig { params(column_names: T.untyped).returns(T.untyped) } + def pick(*column_names); end + + sig { params(column_names: T.untyped).returns(T.untyped) } + def pluck(*column_names); end + + sig { returns(T.nilable(::Domain::UserPostFav::E621UserPostFav)) } + def second; end + + sig { returns(::Domain::UserPostFav::E621UserPostFav) } + def second!; end + + sig { returns(T.nilable(::Domain::UserPostFav::E621UserPostFav)) } + def second_to_last; end + + sig { returns(::Domain::UserPostFav::E621UserPostFav) } + def second_to_last!; end + + sig { returns(::Domain::UserPostFav::E621UserPostFav) } + def sole; end + + sig { params(initial_value_or_column: T.untyped).returns(T.any(Integer, Float, BigDecimal)) } + sig do + type_parameters(:U) + .params( + initial_value_or_column: T.nilable(T.type_parameter(:U)), + block: T.proc.params(object: ::Domain::UserPostFav::E621UserPostFav).returns(T.type_parameter(:U)) + ).returns(T.type_parameter(:U)) + end + def sum(initial_value_or_column = nil, &block); end + + sig { returns(T.nilable(::Domain::UserPostFav::E621UserPostFav)) } + sig { params(limit: Integer).returns(T::Array[::Domain::UserPostFav::E621UserPostFav]) } + def take(limit = nil); end + + sig { returns(::Domain::UserPostFav::E621UserPostFav) } + def take!; end + + sig { returns(T.nilable(::Domain::UserPostFav::E621UserPostFav)) } + def third; end + + sig { returns(::Domain::UserPostFav::E621UserPostFav) } + def third!; end + + sig { returns(T.nilable(::Domain::UserPostFav::E621UserPostFav)) } + def third_to_last; end + + sig { returns(::Domain::UserPostFav::E621UserPostFav) } + def third_to_last!; end + end + + module GeneratedAssociationMethods + sig { params(args: T.untyped, blk: T.untyped).returns(::Domain::Post::E621Post) } + def build_post(*args, &blk); end + + sig { params(args: T.untyped, blk: T.untyped).returns(::Domain::User::E621User) } + def build_user(*args, &blk); end + + sig { params(args: T.untyped, blk: T.untyped).returns(::Domain::Post::E621Post) } + def create_post(*args, &blk); end + + sig { params(args: T.untyped, blk: T.untyped).returns(::Domain::Post::E621Post) } + def create_post!(*args, &blk); end + + sig { params(args: T.untyped, blk: T.untyped).returns(::Domain::User::E621User) } + def create_user(*args, &blk); end + + sig { params(args: T.untyped, blk: T.untyped).returns(::Domain::User::E621User) } + def create_user!(*args, &blk); end + + sig { returns(T.nilable(::Domain::Post::E621Post)) } + def post; end + + sig { params(value: T.nilable(::Domain::Post::E621Post)).void } + def post=(value); end + + sig { returns(T::Boolean) } + def post_changed?; end + + sig { returns(T::Boolean) } + def post_previously_changed?; end + + sig { returns(T.nilable(::Domain::Post::E621Post)) } + def reload_post; end + + sig { returns(T.nilable(::Domain::User::E621User)) } + def reload_user; end + + sig { void } + def reset_post; end + + sig { void } + def reset_user; end + + sig { returns(T.nilable(::Domain::User::E621User)) } + def user; end + + sig { params(value: T.nilable(::Domain::User::E621User)).void } + def user=(value); end + + sig { returns(T::Boolean) } + def user_changed?; end + + sig { returns(T::Boolean) } + def user_previously_changed?; end + end + + module GeneratedAssociationRelationMethods + sig { returns(PrivateAssociationRelation) } + def all; end + + sig { params(args: T.untyped, blk: T.untyped).returns(PrivateAssociationRelation) } + def and(*args, &blk); end + + sig { params(args: T.untyped, blk: T.untyped).returns(PrivateAssociationRelation) } + def annotate(*args, &blk); end + + sig { params(args: T.untyped, blk: T.untyped).returns(PrivateAssociationRelation) } + def arel_columns(*args, &blk); end + + sig { params(args: T.untyped, blk: T.untyped).returns(PrivateAssociationRelation) } + def create_with(*args, &blk); end + + sig { params(value: T::Boolean).returns(PrivateAssociationRelation) } + def distinct(value = true); end + + sig { params(args: T.untyped, blk: T.untyped).returns(PrivateAssociationRelation) } + def eager_load(*args, &blk); end + + sig { params(args: T.untyped, blk: T.untyped).returns(PrivateAssociationRelation) } + def except(*args, &blk); end + + sig { params(args: T.untyped, blk: T.untyped).returns(PrivateAssociationRelation) } + def excluding(*args, &blk); end + + sig { params(args: T.untyped, blk: T.untyped).returns(PrivateAssociationRelation) } + def extending(*args, &blk); end + + sig { params(association: Symbol).returns(T::Array[T.untyped]) } + def extract_associated(association); end + + sig { params(args: T.untyped, blk: T.untyped).returns(PrivateAssociationRelation) } + def for_post_type(*args, &blk); end + + sig { params(args: T.untyped, blk: T.untyped).returns(PrivateAssociationRelation) } + def from(*args, &blk); end + + sig { params(args: T.untyped, blk: T.untyped).returns(PrivateAssociationRelationGroupChain) } + def group(*args, &blk); end + + sig { params(args: T.untyped, blk: T.untyped).returns(PrivateAssociationRelation) } + def having(*args, &blk); end + + sig { params(args: T.untyped, blk: T.untyped).returns(PrivateAssociationRelation) } + def in_order_of(*args, &blk); end + + sig { params(args: T.untyped, blk: T.untyped).returns(PrivateAssociationRelation) } + def includes(*args, &blk); end + + sig { params(args: T.untyped, blk: T.untyped).returns(PrivateAssociationRelation) } + def invert_where(*args, &blk); end + + sig { params(args: T.untyped, blk: T.untyped).returns(PrivateAssociationRelation) } + def joins(*args, &blk); end + + sig { params(args: T.untyped, blk: T.untyped).returns(PrivateAssociationRelation) } + def left_joins(*args, &blk); end + + sig { params(args: T.untyped, blk: T.untyped).returns(PrivateAssociationRelation) } + def left_outer_joins(*args, &blk); end + + sig { params(args: T.untyped, blk: T.untyped).returns(PrivateAssociationRelation) } + def limit(*args, &blk); end + + sig { params(args: T.untyped, blk: T.untyped).returns(PrivateAssociationRelation) } + def lock(*args, &blk); end + + sig { params(args: T.untyped, blk: T.untyped).returns(PrivateAssociationRelation) } + def merge(*args, &blk); end + + sig { params(args: T.untyped, blk: T.untyped).returns(PrivateAssociationRelation) } + def none(*args, &blk); end + + sig { params(args: T.untyped, blk: T.untyped).returns(PrivateAssociationRelation) } + def null_relation?(*args, &blk); end + + sig { params(args: T.untyped, blk: T.untyped).returns(PrivateAssociationRelation) } + def offset(*args, &blk); end + + sig { params(args: T.untyped, blk: T.untyped).returns(PrivateAssociationRelation) } + def only(*args, &blk); end + + sig { params(args: T.untyped, blk: T.untyped).returns(PrivateAssociationRelation) } + def optimizer_hints(*args, &blk); end + + sig { params(args: T.untyped, blk: T.untyped).returns(PrivateAssociationRelation) } + def or(*args, &blk); end + + sig { params(args: T.untyped, blk: T.untyped).returns(PrivateAssociationRelation) } + def order(*args, &blk); end + + sig do + params( + num: T.any(Integer, String) + ).returns(T.all(PrivateAssociationRelation, Kaminari::PageScopeMethods, Kaminari::ActiveRecordRelationMethods)) + end + def page(num = nil); end + + sig do + params( + num: Integer + ).returns(T.all(PrivateAssociationRelation, Kaminari::PageScopeMethods, Kaminari::ActiveRecordRelationMethods)) + end + def per(num); end + + sig { params(args: T.untyped, blk: T.untyped).returns(PrivateAssociationRelation) } + def preload(*args, &blk); end + + sig { params(args: T.untyped, blk: T.untyped).returns(PrivateAssociationRelation) } + def readonly(*args, &blk); end + + sig { params(args: T.untyped, blk: T.untyped).returns(PrivateAssociationRelation) } + def references(*args, &blk); end + + sig { params(args: T.untyped, blk: T.untyped).returns(PrivateAssociationRelation) } + def regroup(*args, &blk); end + + sig { params(args: T.untyped, blk: T.untyped).returns(PrivateAssociationRelation) } + def reorder(*args, &blk); end + + sig { params(args: T.untyped, blk: T.untyped).returns(PrivateAssociationRelation) } + def reselect(*args, &blk); end + + sig { params(args: T.untyped, blk: T.untyped).returns(PrivateAssociationRelation) } + def reverse_order(*args, &blk); end + + sig { params(args: T.untyped, blk: T.untyped).returns(PrivateAssociationRelation) } + def rewhere(*args, &blk); end + + sig { params(args: T.untyped).returns(PrivateAssociationRelation) } + sig do + params( + blk: T.proc.params(record: ::Domain::UserPostFav::E621UserPostFav).returns(T::Boolean) + ).returns(T::Array[::Domain::UserPostFav::E621UserPostFav]) + end + def select(*args, &blk); end + + sig { params(args: T.untyped, blk: T.untyped).returns(PrivateAssociationRelation) } + def strict_loading(*args, &blk); end + + sig { params(args: T.untyped, blk: T.untyped).returns(PrivateAssociationRelation) } + def structurally_compatible?(*args, &blk); end + + sig { params(args: T.untyped, blk: T.untyped).returns(PrivateAssociationRelation) } + def uniq!(*args, &blk); end + + sig { params(args: T.untyped, blk: T.untyped).returns(PrivateAssociationRelation) } + def unscope(*args, &blk); end + + sig { returns(PrivateAssociationRelationWhereChain) } + sig { params(args: T.untyped).returns(PrivateAssociationRelation) } + def where(*args); end + + sig { params(args: T.untyped, blk: T.untyped).returns(PrivateAssociationRelation) } + def with(*args, &blk); end + + sig { params(args: T.untyped, blk: T.untyped).returns(PrivateAssociationRelation) } + def with_recursive(*args, &blk); end + + sig { params(args: T.untyped, blk: T.untyped).returns(PrivateAssociationRelation) } + def without(*args, &blk); end + + sig do + returns(T.all(PrivateAssociationRelation, Kaminari::PageScopeMethods, Kaminari::ActiveRecordRelationMethods)) + end + def without_count; end + end + + module GeneratedAttributeMethods + sig { returns(T.nilable(::ActiveSupport::TimeWithZone)) } + def explicit_time; end + + sig { params(value: T.nilable(::ActiveSupport::TimeWithZone)).returns(T.nilable(::ActiveSupport::TimeWithZone)) } + def explicit_time=(value); end + + sig { returns(T::Boolean) } + def explicit_time?; end + + sig { returns(T.nilable(::ActiveSupport::TimeWithZone)) } + def explicit_time_before_last_save; end + + sig { returns(T.untyped) } + def explicit_time_before_type_cast; end + + sig { returns(T::Boolean) } + def explicit_time_came_from_user?; end + + sig { returns(T.nilable([T.nilable(::ActiveSupport::TimeWithZone), T.nilable(::ActiveSupport::TimeWithZone)])) } + def explicit_time_change; end + + sig { returns(T.nilable([T.nilable(::ActiveSupport::TimeWithZone), T.nilable(::ActiveSupport::TimeWithZone)])) } + def explicit_time_change_to_be_saved; end + + sig do + params( + from: T.nilable(::ActiveSupport::TimeWithZone), + to: T.nilable(::ActiveSupport::TimeWithZone) + ).returns(T::Boolean) + end + def explicit_time_changed?(from: T.unsafe(nil), to: T.unsafe(nil)); end + + sig { returns(T.nilable(::ActiveSupport::TimeWithZone)) } + def explicit_time_in_database; end + + sig { returns(T.nilable([T.nilable(::ActiveSupport::TimeWithZone), T.nilable(::ActiveSupport::TimeWithZone)])) } + def explicit_time_previous_change; end + + sig do + params( + from: T.nilable(::ActiveSupport::TimeWithZone), + to: T.nilable(::ActiveSupport::TimeWithZone) + ).returns(T::Boolean) + end + def explicit_time_previously_changed?(from: T.unsafe(nil), to: T.unsafe(nil)); end + + sig { returns(T.nilable(::ActiveSupport::TimeWithZone)) } + def explicit_time_previously_was; end + + sig { returns(T.nilable(::ActiveSupport::TimeWithZone)) } + def explicit_time_was; end + + sig { void } + def explicit_time_will_change!; end + + sig { returns([T.nilable(::Integer), T.nilable(::Integer)]) } + def id; end + + sig do + params( + value: [T.nilable(::Integer), T.nilable(::Integer)] + ).returns([T.nilable(::Integer), T.nilable(::Integer)]) + end + def id=(value); end + + sig { returns(T::Boolean) } + def id?; end + + sig { returns(T.nilable([T.nilable(::Integer), T.nilable(::Integer)])) } + def id_before_last_save; end + + sig { returns(T.untyped) } + def id_before_type_cast; end + + sig { returns(T::Boolean) } + def id_came_from_user?; end + + sig do + returns(T.nilable([[T.nilable(::Integer), T.nilable(::Integer)], [T.nilable(::Integer), T.nilable(::Integer)]])) + end + def id_change; end + + sig do + returns(T.nilable([[T.nilable(::Integer), T.nilable(::Integer)], [T.nilable(::Integer), T.nilable(::Integer)]])) + end + def id_change_to_be_saved; end + + sig do + params( + from: [T.nilable(::Integer), T.nilable(::Integer)], + to: [T.nilable(::Integer), T.nilable(::Integer)] + ).returns(T::Boolean) + end + def id_changed?(from: T.unsafe(nil), to: T.unsafe(nil)); end + + sig { returns(T.nilable([T.nilable(::Integer), T.nilable(::Integer)])) } + def id_in_database; end + + sig do + returns(T.nilable([[T.nilable(::Integer), T.nilable(::Integer)], [T.nilable(::Integer), T.nilable(::Integer)]])) + end + def id_previous_change; end + + sig do + params( + from: [T.nilable(::Integer), T.nilable(::Integer)], + to: [T.nilable(::Integer), T.nilable(::Integer)] + ).returns(T::Boolean) + end + def id_previously_changed?(from: T.unsafe(nil), to: T.unsafe(nil)); end + + sig { returns(T.nilable([T.nilable(::Integer), T.nilable(::Integer)])) } + def id_previously_was; end + + sig { returns(T.nilable([T.nilable(::Integer), T.nilable(::Integer)])) } + def id_was; end + + sig { void } + def id_will_change!; end + + sig { returns(T.nilable(::ActiveSupport::TimeWithZone)) } + def inferred_time; end + + sig { params(value: T.nilable(::ActiveSupport::TimeWithZone)).returns(T.nilable(::ActiveSupport::TimeWithZone)) } + def inferred_time=(value); end + + sig { returns(T::Boolean) } + def inferred_time?; end + + sig { returns(T.nilable(::ActiveSupport::TimeWithZone)) } + def inferred_time_before_last_save; end + + sig { returns(T.untyped) } + def inferred_time_before_type_cast; end + + sig { returns(T::Boolean) } + def inferred_time_came_from_user?; end + + sig { returns(T.nilable([T.nilable(::ActiveSupport::TimeWithZone), T.nilable(::ActiveSupport::TimeWithZone)])) } + def inferred_time_change; end + + sig { returns(T.nilable([T.nilable(::ActiveSupport::TimeWithZone), T.nilable(::ActiveSupport::TimeWithZone)])) } + def inferred_time_change_to_be_saved; end + + sig do + params( + from: T.nilable(::ActiveSupport::TimeWithZone), + to: T.nilable(::ActiveSupport::TimeWithZone) + ).returns(T::Boolean) + end + def inferred_time_changed?(from: T.unsafe(nil), to: T.unsafe(nil)); end + + sig { returns(T.nilable(::ActiveSupport::TimeWithZone)) } + def inferred_time_in_database; end + + sig { returns(T.nilable([T.nilable(::ActiveSupport::TimeWithZone), T.nilable(::ActiveSupport::TimeWithZone)])) } + def inferred_time_previous_change; end + + sig do + params( + from: T.nilable(::ActiveSupport::TimeWithZone), + to: T.nilable(::ActiveSupport::TimeWithZone) + ).returns(T::Boolean) + end + def inferred_time_previously_changed?(from: T.unsafe(nil), to: T.unsafe(nil)); end + + sig { returns(T.nilable(::ActiveSupport::TimeWithZone)) } + def inferred_time_previously_was; end + + sig { returns(T.nilable(::ActiveSupport::TimeWithZone)) } + def inferred_time_was; end + + sig { void } + def inferred_time_will_change!; end + + sig { returns(T.nilable(::Integer)) } + def post_id; end + + sig { params(value: T.nilable(::Integer)).returns(T.nilable(::Integer)) } + def post_id=(value); end + + sig { returns(T::Boolean) } + def post_id?; end + + sig { returns(T.nilable(::Integer)) } + def post_id_before_last_save; end + + sig { returns(T.untyped) } + def post_id_before_type_cast; end + + sig { returns(T::Boolean) } + def post_id_came_from_user?; end + + sig { returns(T.nilable([T.nilable(::Integer), T.nilable(::Integer)])) } + def post_id_change; end + + sig { returns(T.nilable([T.nilable(::Integer), T.nilable(::Integer)])) } + def post_id_change_to_be_saved; end + + sig { params(from: T.nilable(::Integer), to: T.nilable(::Integer)).returns(T::Boolean) } + def post_id_changed?(from: T.unsafe(nil), to: T.unsafe(nil)); end + + sig { returns(T.nilable(::Integer)) } + def post_id_in_database; end + + sig { returns(T.nilable([T.nilable(::Integer), T.nilable(::Integer)])) } + def post_id_previous_change; end + + sig { params(from: T.nilable(::Integer), to: T.nilable(::Integer)).returns(T::Boolean) } + def post_id_previously_changed?(from: T.unsafe(nil), to: T.unsafe(nil)); end + + sig { returns(T.nilable(::Integer)) } + def post_id_previously_was; end + + sig { returns(T.nilable(::Integer)) } + def post_id_was; end + + sig { void } + def post_id_will_change!; end + + sig { returns(T.nilable(T::Boolean)) } + def removed; end + + sig { params(value: T.nilable(T::Boolean)).returns(T.nilable(T::Boolean)) } + def removed=(value); end + + sig { returns(T::Boolean) } + def removed?; end + + sig { returns(T.nilable(T::Boolean)) } + def removed_before_last_save; end + + sig { returns(T.untyped) } + def removed_before_type_cast; end + + sig { returns(T::Boolean) } + def removed_came_from_user?; end + + sig { returns(T.nilable([T.nilable(T::Boolean), T.nilable(T::Boolean)])) } + def removed_change; end + + sig { returns(T.nilable([T.nilable(T::Boolean), T.nilable(T::Boolean)])) } + def removed_change_to_be_saved; end + + sig { params(from: T.nilable(T::Boolean), to: T.nilable(T::Boolean)).returns(T::Boolean) } + def removed_changed?(from: T.unsafe(nil), to: T.unsafe(nil)); end + + sig { returns(T.nilable(T::Boolean)) } + def removed_in_database; end + + sig { returns(T.nilable([T.nilable(T::Boolean), T.nilable(T::Boolean)])) } + def removed_previous_change; end + + sig { params(from: T.nilable(T::Boolean), to: T.nilable(T::Boolean)).returns(T::Boolean) } + def removed_previously_changed?(from: T.unsafe(nil), to: T.unsafe(nil)); end + + sig { returns(T.nilable(T::Boolean)) } + def removed_previously_was; end + + sig { returns(T.nilable(T::Boolean)) } + def removed_was; end + + sig { void } + def removed_will_change!; end + + sig { void } + def restore_explicit_time!; end + + sig { void } + def restore_id!; end + + sig { void } + def restore_inferred_time!; end + + sig { void } + def restore_post_id!; end + + sig { void } + def restore_removed!; end + + sig { void } + def restore_user_id!; end + + sig { returns(T.nilable([T.nilable(::ActiveSupport::TimeWithZone), T.nilable(::ActiveSupport::TimeWithZone)])) } + def saved_change_to_explicit_time; end + + sig { returns(T::Boolean) } + def saved_change_to_explicit_time?; end + + sig do + returns(T.nilable([[T.nilable(::Integer), T.nilable(::Integer)], [T.nilable(::Integer), T.nilable(::Integer)]])) + end + def saved_change_to_id; end + + sig { returns(T::Boolean) } + def saved_change_to_id?; end + + sig { returns(T.nilable([T.nilable(::ActiveSupport::TimeWithZone), T.nilable(::ActiveSupport::TimeWithZone)])) } + def saved_change_to_inferred_time; end + + sig { returns(T::Boolean) } + def saved_change_to_inferred_time?; end + + sig { returns(T.nilable([T.nilable(::Integer), T.nilable(::Integer)])) } + def saved_change_to_post_id; end + + sig { returns(T::Boolean) } + def saved_change_to_post_id?; end + + sig { returns(T.nilable([T.nilable(T::Boolean), T.nilable(T::Boolean)])) } + def saved_change_to_removed; end + + sig { returns(T::Boolean) } + def saved_change_to_removed?; end + + sig { returns(T.nilable([T.nilable(::Integer), T.nilable(::Integer)])) } + def saved_change_to_user_id; end + + sig { returns(T::Boolean) } + def saved_change_to_user_id?; end + + sig { returns(T.nilable(::Integer)) } + def user_id; end + + sig { params(value: T.nilable(::Integer)).returns(T.nilable(::Integer)) } + def user_id=(value); end + + sig { returns(T::Boolean) } + def user_id?; end + + sig { returns(T.nilable(::Integer)) } + def user_id_before_last_save; end + + sig { returns(T.untyped) } + def user_id_before_type_cast; end + + sig { returns(T::Boolean) } + def user_id_came_from_user?; end + + sig { returns(T.nilable([T.nilable(::Integer), T.nilable(::Integer)])) } + def user_id_change; end + + sig { returns(T.nilable([T.nilable(::Integer), T.nilable(::Integer)])) } + def user_id_change_to_be_saved; end + + sig { params(from: T.nilable(::Integer), to: T.nilable(::Integer)).returns(T::Boolean) } + def user_id_changed?(from: T.unsafe(nil), to: T.unsafe(nil)); end + + sig { returns(T.nilable(::Integer)) } + def user_id_in_database; end + + sig { returns(T.nilable([T.nilable(::Integer), T.nilable(::Integer)])) } + def user_id_previous_change; end + + sig { params(from: T.nilable(::Integer), to: T.nilable(::Integer)).returns(T::Boolean) } + def user_id_previously_changed?(from: T.unsafe(nil), to: T.unsafe(nil)); end + + sig { returns(T.nilable(::Integer)) } + def user_id_previously_was; end + + sig { returns(T.nilable(::Integer)) } + def user_id_was; end + + sig { void } + def user_id_will_change!; end + + sig { returns(T::Boolean) } + def will_save_change_to_explicit_time?; end + + sig { returns(T::Boolean) } + def will_save_change_to_id?; end + + sig { returns(T::Boolean) } + def will_save_change_to_inferred_time?; end + + sig { returns(T::Boolean) } + def will_save_change_to_post_id?; end + + sig { returns(T::Boolean) } + def will_save_change_to_removed?; end + + sig { returns(T::Boolean) } + def will_save_change_to_user_id?; end + end + + module GeneratedRelationMethods + sig { returns(PrivateRelation) } + def all; end + + sig { params(args: T.untyped, blk: T.untyped).returns(PrivateRelation) } + def and(*args, &blk); end + + sig { params(args: T.untyped, blk: T.untyped).returns(PrivateRelation) } + def annotate(*args, &blk); end + + sig { params(args: T.untyped, blk: T.untyped).returns(PrivateRelation) } + def arel_columns(*args, &blk); end + + sig { params(args: T.untyped, blk: T.untyped).returns(PrivateRelation) } + def create_with(*args, &blk); end + + sig { params(value: T::Boolean).returns(PrivateRelation) } + def distinct(value = true); end + + sig { params(args: T.untyped, blk: T.untyped).returns(PrivateRelation) } + def eager_load(*args, &blk); end + + sig { params(args: T.untyped, blk: T.untyped).returns(PrivateRelation) } + def except(*args, &blk); end + + sig { params(args: T.untyped, blk: T.untyped).returns(PrivateRelation) } + def excluding(*args, &blk); end + + sig { params(args: T.untyped, blk: T.untyped).returns(PrivateRelation) } + def extending(*args, &blk); end + + sig { params(association: Symbol).returns(T::Array[T.untyped]) } + def extract_associated(association); end + + sig { params(args: T.untyped, blk: T.untyped).returns(PrivateRelation) } + def for_post_type(*args, &blk); end + + sig { params(args: T.untyped, blk: T.untyped).returns(PrivateRelation) } + def from(*args, &blk); end + + sig { params(args: T.untyped, blk: T.untyped).returns(PrivateRelationGroupChain) } + def group(*args, &blk); end + + sig { params(args: T.untyped, blk: T.untyped).returns(PrivateRelation) } + def having(*args, &blk); end + + sig { params(args: T.untyped, blk: T.untyped).returns(PrivateRelation) } + def in_order_of(*args, &blk); end + + sig { params(args: T.untyped, blk: T.untyped).returns(PrivateRelation) } + def includes(*args, &blk); end + + sig { params(args: T.untyped, blk: T.untyped).returns(PrivateRelation) } + def invert_where(*args, &blk); end + + sig { params(args: T.untyped, blk: T.untyped).returns(PrivateRelation) } + def joins(*args, &blk); end + + sig { params(args: T.untyped, blk: T.untyped).returns(PrivateRelation) } + def left_joins(*args, &blk); end + + sig { params(args: T.untyped, blk: T.untyped).returns(PrivateRelation) } + def left_outer_joins(*args, &blk); end + + sig { params(args: T.untyped, blk: T.untyped).returns(PrivateRelation) } + def limit(*args, &blk); end + + sig { params(args: T.untyped, blk: T.untyped).returns(PrivateRelation) } + def lock(*args, &blk); end + + sig { params(args: T.untyped, blk: T.untyped).returns(PrivateRelation) } + def merge(*args, &blk); end + + sig { params(args: T.untyped, blk: T.untyped).returns(PrivateRelation) } + def none(*args, &blk); end + + sig { params(args: T.untyped, blk: T.untyped).returns(PrivateRelation) } + def null_relation?(*args, &blk); end + + sig { params(args: T.untyped, blk: T.untyped).returns(PrivateRelation) } + def offset(*args, &blk); end + + sig { params(args: T.untyped, blk: T.untyped).returns(PrivateRelation) } + def only(*args, &blk); end + + sig { params(args: T.untyped, blk: T.untyped).returns(PrivateRelation) } + def optimizer_hints(*args, &blk); end + + sig { params(args: T.untyped, blk: T.untyped).returns(PrivateRelation) } + def or(*args, &blk); end + + sig { params(args: T.untyped, blk: T.untyped).returns(PrivateRelation) } + def order(*args, &blk); end + + sig do + params( + num: T.any(Integer, String) + ).returns(T.all(PrivateRelation, Kaminari::PageScopeMethods, Kaminari::ActiveRecordRelationMethods)) + end + def page(num = nil); end + + sig do + params( + num: Integer + ).returns(T.all(PrivateRelation, Kaminari::PageScopeMethods, Kaminari::ActiveRecordRelationMethods)) + end + def per(num); end + + sig { params(args: T.untyped, blk: T.untyped).returns(PrivateRelation) } + def preload(*args, &blk); end + + sig { params(args: T.untyped, blk: T.untyped).returns(PrivateRelation) } + def readonly(*args, &blk); end + + sig { params(args: T.untyped, blk: T.untyped).returns(PrivateRelation) } + def references(*args, &blk); end + + sig { params(args: T.untyped, blk: T.untyped).returns(PrivateRelation) } + def regroup(*args, &blk); end + + sig { params(args: T.untyped, blk: T.untyped).returns(PrivateRelation) } + def reorder(*args, &blk); end + + sig { params(args: T.untyped, blk: T.untyped).returns(PrivateRelation) } + def reselect(*args, &blk); end + + sig { params(args: T.untyped, blk: T.untyped).returns(PrivateRelation) } + def reverse_order(*args, &blk); end + + sig { params(args: T.untyped, blk: T.untyped).returns(PrivateRelation) } + def rewhere(*args, &blk); end + + sig { params(args: T.untyped).returns(PrivateRelation) } + sig do + params( + blk: T.proc.params(record: ::Domain::UserPostFav::E621UserPostFav).returns(T::Boolean) + ).returns(T::Array[::Domain::UserPostFav::E621UserPostFav]) + end + def select(*args, &blk); end + + sig { params(args: T.untyped, blk: T.untyped).returns(PrivateRelation) } + def strict_loading(*args, &blk); end + + sig { params(args: T.untyped, blk: T.untyped).returns(PrivateRelation) } + def structurally_compatible?(*args, &blk); end + + sig { params(args: T.untyped, blk: T.untyped).returns(PrivateRelation) } + def uniq!(*args, &blk); end + + sig { params(args: T.untyped, blk: T.untyped).returns(PrivateRelation) } + def unscope(*args, &blk); end + + sig { returns(PrivateRelationWhereChain) } + sig { params(args: T.untyped).returns(PrivateRelation) } + def where(*args); end + + sig { params(args: T.untyped, blk: T.untyped).returns(PrivateRelation) } + def with(*args, &blk); end + + sig { params(args: T.untyped, blk: T.untyped).returns(PrivateRelation) } + def with_recursive(*args, &blk); end + + sig { params(args: T.untyped, blk: T.untyped).returns(PrivateRelation) } + def without(*args, &blk); end + + sig { returns(T.all(PrivateRelation, Kaminari::PageScopeMethods, Kaminari::ActiveRecordRelationMethods)) } + def without_count; end + end + + class PrivateAssociationRelation < ::ActiveRecord::AssociationRelation + include CommonRelationMethods + include GeneratedAssociationRelationMethods + + Elem = type_member { { fixed: ::Domain::UserPostFav::E621UserPostFav } } + + sig { returns(T::Array[::Domain::UserPostFav::E621UserPostFav]) } + def to_a; end + + sig { returns(T::Array[::Domain::UserPostFav::E621UserPostFav]) } + def to_ary; end + end + + class PrivateAssociationRelationGroupChain < PrivateAssociationRelation + Elem = type_member { { fixed: ::Domain::UserPostFav::E621UserPostFav } } + + sig { params(column_name: T.any(String, Symbol)).returns(T::Hash[T.untyped, T.any(Integer, Float, BigDecimal)]) } + def average(column_name); end + + sig do + params( + operation: Symbol, + column_name: T.any(String, Symbol) + ).returns(T::Hash[T.untyped, T.any(Integer, Float, BigDecimal)]) + end + def calculate(operation, column_name); end + + sig { params(column_name: T.untyped).returns(T::Hash[T.untyped, Integer]) } + def count(column_name = nil); end + + sig { params(args: T.untyped, blk: T.untyped).returns(T.self_type) } + def having(*args, &blk); end + + sig { params(column_name: T.any(String, Symbol)).returns(T::Hash[T.untyped, T.untyped]) } + def maximum(column_name); end + + sig { params(column_name: T.any(String, Symbol)).returns(T::Hash[T.untyped, T.untyped]) } + def minimum(column_name); end + + sig do + params( + column_name: T.nilable(T.any(String, Symbol)), + block: T.nilable(T.proc.params(record: T.untyped).returns(T.untyped)) + ).returns(T::Hash[T.untyped, T.any(Integer, Float, BigDecimal)]) + end + def size(column_name = nil, &block); end + + sig do + params( + column_name: T.nilable(T.any(String, Symbol)), + block: T.nilable(T.proc.params(record: T.untyped).returns(T.untyped)) + ).returns(T::Hash[T.untyped, T.any(Integer, Float, BigDecimal)]) + end + def sum(column_name = nil, &block); end + end + + class PrivateAssociationRelationWhereChain + Elem = type_member { { fixed: ::Domain::UserPostFav::E621UserPostFav } } + + sig { params(args: T.untyped).returns(PrivateAssociationRelation) } + def associated(*args); end + + sig { params(args: T.untyped).returns(PrivateAssociationRelation) } + def missing(*args); end + + sig { params(opts: T.untyped, rest: T.untyped).returns(PrivateAssociationRelation) } + def not(opts, *rest); end + end + + class PrivateCollectionProxy < ::ActiveRecord::Associations::CollectionProxy + include CommonRelationMethods + include GeneratedAssociationRelationMethods + + Elem = type_member { { fixed: ::Domain::UserPostFav::E621UserPostFav } } + + sig do + params( + records: T.any(::Domain::UserPostFav::E621UserPostFav, T::Enumerable[T.any(::Domain::UserPostFav::E621UserPostFav, T::Enumerable[::Domain::UserPostFav::E621UserPostFav])]) + ).returns(PrivateCollectionProxy) + end + def <<(*records); end + + sig do + params( + records: T.any(::Domain::UserPostFav::E621UserPostFav, T::Enumerable[T.any(::Domain::UserPostFav::E621UserPostFav, T::Enumerable[::Domain::UserPostFav::E621UserPostFav])]) + ).returns(PrivateCollectionProxy) + end + def append(*records); end + + sig { returns(PrivateCollectionProxy) } + def clear; end + + sig do + params( + records: T.any(::Domain::UserPostFav::E621UserPostFav, T::Enumerable[T.any(::Domain::UserPostFav::E621UserPostFav, T::Enumerable[::Domain::UserPostFav::E621UserPostFav])]) + ).returns(PrivateCollectionProxy) + end + def concat(*records); end + + sig { returns(T::Array[::Domain::UserPostFav::E621UserPostFav]) } + def load_target; end + + sig do + params( + records: T.any(::Domain::UserPostFav::E621UserPostFav, T::Enumerable[T.any(::Domain::UserPostFav::E621UserPostFav, T::Enumerable[::Domain::UserPostFav::E621UserPostFav])]) + ).returns(PrivateCollectionProxy) + end + def prepend(*records); end + + sig do + params( + records: T.any(::Domain::UserPostFav::E621UserPostFav, T::Enumerable[T.any(::Domain::UserPostFav::E621UserPostFav, T::Enumerable[::Domain::UserPostFav::E621UserPostFav])]) + ).returns(PrivateCollectionProxy) + end + def push(*records); end + + sig do + params( + other_array: T.any(::Domain::UserPostFav::E621UserPostFav, T::Enumerable[T.any(::Domain::UserPostFav::E621UserPostFav, T::Enumerable[::Domain::UserPostFav::E621UserPostFav])]) + ).returns(T::Array[::Domain::UserPostFav::E621UserPostFav]) + end + def replace(other_array); end + + sig { returns(PrivateAssociationRelation) } + def scope; end + + sig { returns(T::Array[::Domain::UserPostFav::E621UserPostFav]) } + def target; end + + sig { returns(T::Array[::Domain::UserPostFav::E621UserPostFav]) } + def to_a; end + + sig { returns(T::Array[::Domain::UserPostFav::E621UserPostFav]) } + def to_ary; end + end + + class PrivateRelation < ::ActiveRecord::Relation + include CommonRelationMethods + include GeneratedRelationMethods + + Elem = type_member { { fixed: ::Domain::UserPostFav::E621UserPostFav } } + + sig { returns(T::Array[::Domain::UserPostFav::E621UserPostFav]) } + def to_a; end + + sig { returns(T::Array[::Domain::UserPostFav::E621UserPostFav]) } + def to_ary; end + end + + class PrivateRelationGroupChain < PrivateRelation + Elem = type_member { { fixed: ::Domain::UserPostFav::E621UserPostFav } } + + sig { params(column_name: T.any(String, Symbol)).returns(T::Hash[T.untyped, T.any(Integer, Float, BigDecimal)]) } + def average(column_name); end + + sig do + params( + operation: Symbol, + column_name: T.any(String, Symbol) + ).returns(T::Hash[T.untyped, T.any(Integer, Float, BigDecimal)]) + end + def calculate(operation, column_name); end + + sig { params(column_name: T.untyped).returns(T::Hash[T.untyped, Integer]) } + def count(column_name = nil); end + + sig { params(args: T.untyped, blk: T.untyped).returns(T.self_type) } + def having(*args, &blk); end + + sig { params(column_name: T.any(String, Symbol)).returns(T::Hash[T.untyped, T.untyped]) } + def maximum(column_name); end + + sig { params(column_name: T.any(String, Symbol)).returns(T::Hash[T.untyped, T.untyped]) } + def minimum(column_name); end + + sig do + params( + column_name: T.nilable(T.any(String, Symbol)), + block: T.nilable(T.proc.params(record: T.untyped).returns(T.untyped)) + ).returns(T::Hash[T.untyped, T.any(Integer, Float, BigDecimal)]) + end + def size(column_name = nil, &block); end + + sig do + params( + column_name: T.nilable(T.any(String, Symbol)), + block: T.nilable(T.proc.params(record: T.untyped).returns(T.untyped)) + ).returns(T::Hash[T.untyped, T.any(Integer, Float, BigDecimal)]) + end + def sum(column_name = nil, &block); end + end + + class PrivateRelationWhereChain + Elem = type_member { { fixed: ::Domain::UserPostFav::E621UserPostFav } } + + sig { params(args: T.untyped).returns(PrivateRelation) } + def associated(*args); end + + sig { params(args: T.untyped).returns(PrivateRelation) } + def missing(*args); end + + sig { params(opts: T.untyped, rest: T.untyped).returns(PrivateRelation) } + def not(opts, *rest); end + end +end diff --git a/sorbet/rbi/dsl/domain/user_post_fav/fa_user_post_fav.rbi b/sorbet/rbi/dsl/domain/user_post_fav/fa_user_post_fav.rbi index 264c3825..3f1f3b96 100644 --- a/sorbet/rbi/dsl/domain/user_post_fav/fa_user_post_fav.rbi +++ b/sorbet/rbi/dsl/domain/user_post_fav/fa_user_post_fav.rbi @@ -665,12 +665,6 @@ class Domain::UserPostFav::FaUserPostFav sig { params(args: T.untyped, blk: T.untyped).returns(PrivateAssociationRelation) } def with_explicit_time_and_id(*args, &blk); end - sig { params(args: T.untyped, blk: T.untyped).returns(PrivateAssociationRelation) } - def with_fa_fav_id(*args, &blk); end - - sig { params(args: T.untyped, blk: T.untyped).returns(PrivateAssociationRelation) } - def with_inferred_time_and_id(*args, &blk); end - sig { params(args: T.untyped, blk: T.untyped).returns(PrivateAssociationRelation) } def with_recursive(*args, &blk); end @@ -1288,12 +1282,6 @@ class Domain::UserPostFav::FaUserPostFav sig { params(args: T.untyped, blk: T.untyped).returns(PrivateRelation) } def with_explicit_time_and_id(*args, &blk); end - sig { params(args: T.untyped, blk: T.untyped).returns(PrivateRelation) } - def with_fa_fav_id(*args, &blk); end - - sig { params(args: T.untyped, blk: T.untyped).returns(PrivateRelation) } - def with_inferred_time_and_id(*args, &blk); end - sig { params(args: T.untyped, blk: T.untyped).returns(PrivateRelation) } def with_recursive(*args, &blk); end diff --git a/spec/controllers/domain/users_controller_spec.rb b/spec/controllers/domain/users_controller_spec.rb index 825e9db7..9622988e 100644 --- a/spec/controllers/domain/users_controller_spec.rb +++ b/spec/controllers/domain/users_controller_spec.rb @@ -221,8 +221,14 @@ RSpec.describe Domain::UsersController, type: :controller do def setup_faving_users # Create E621-specific user-post-fav relationships - Domain::UserPostFav.create!(user: faving_user1, post: domain_post) - Domain::UserPostFav.create!(user: faving_user2, post: domain_post) + Domain::UserPostFav::E621UserPostFav.create!( + user: faving_user1, + post: domain_post, + ) + Domain::UserPostFav::E621UserPostFav.create!( + user: faving_user2, + post: domain_post, + ) end include_examples "users_faving_post action for post type", diff --git a/spec/jobs/domain/e621/job/scan_user_favs_job_spec.rb b/spec/jobs/domain/e621/job/scan_user_favs_job_spec.rb index e1b88b57..116d0c7d 100644 --- a/spec/jobs/domain/e621/job/scan_user_favs_job_spec.rb +++ b/spec/jobs/domain/e621/job/scan_user_favs_job_spec.rb @@ -39,7 +39,7 @@ RSpec.describe Domain::E621::Job::ScanUserFavsJob do expect(Domain::Post::E621Post.pluck(:e621_id)).to match_array( [5_212_363, 5_214_461, 5_306_537, 2_518_409, 5_129_881], ) - expect(Domain::UserPostFav.count).to eq(5) + expect(Domain::UserPostFav::E621UserPostFav.count).to eq(5) post5212363 = Domain::Post::E621Post.find_by(e621_id: 5_212_363) expect(post5212363).to be_present @@ -63,7 +63,7 @@ RSpec.describe Domain::E621::Job::ScanUserFavsJob do ) # Verify fav relationship - fav = Domain::UserPostFav.find_by(user: user, post: post) + fav = Domain::UserPostFav::E621UserPostFav.find_by(user: user, post: post) expect(fav).to be_present end @@ -137,7 +137,7 @@ RSpec.describe Domain::E621::Job::ScanUserFavsJob do it "does not create any favs" do expect { perform_now({ user: user }) }.not_to change( - Domain::UserPostFav, + Domain::UserPostFav::E621UserPostFav, :count, ) end diff --git a/spec/models/domain/user_counter_cache_spec.rb b/spec/models/domain/user_counter_cache_spec.rb index 16c11e12..8ad74844 100644 --- a/spec/models/domain/user_counter_cache_spec.rb +++ b/spec/models/domain/user_counter_cache_spec.rb @@ -159,7 +159,7 @@ RSpec.describe "Domain::User counter caches", type: :model do user.reload expect(user.user_post_favs_count).to be_nil - expect(user.user_post_favs.size).to eq(0) + 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