Domain::Users::InkbunnyUser aux table migration

This commit is contained in:
Dylan Knutson
2025-07-18 19:44:27 +00:00
parent 0c5f6e84cb
commit ca7315c8ae
11 changed files with 264 additions and 62 deletions

View File

@@ -36,7 +36,7 @@ PATH
GIT
remote: ssh://git@git.dy.mk:2221/dymk/has_aux_table.git
revision: 26ad0e3ea3f72ce0a66e36b13e09627e0d2ed99e
revision: ea33ffbb11b14989fa2ca0eae69c18a4cea2266d
branch: main
specs:
has_aux_table (0.1.0)

View File

@@ -378,7 +378,7 @@ module Domain::PostsHelper
find_proc: ->(_, match, _) do
if user =
Domain::User::InkbunnyUser.where(
"lower(json_attributes->>'name') = lower(?)",
"name = lower(?)",
match[1],
).first
SourceResult.new(

View File

@@ -106,10 +106,25 @@ module AttrJsonRecordAliases
extend T::Helpers
extend ActiveSupport::Concern
abstract!
included { include AttrJson::Record }
requires_ancestor { ActiveRecord::Base }
included do
include AttrJson::Record
original_write_attribute = instance_method(:write_attribute)
define_method(:write_attribute) do |name, value|
T.bind(self, AttrJsonRecordAliases)
klass = T.cast(self.class, T.class_of(ActiveRecord::Base))
ret = original_write_attribute.bind(self).call(name, value)
if attribute_def = ImplHelper.get_json_attr_def(klass, name)
public_send(attribute_def.container_attribute)[
attribute_def.store_key
] = read_attribute(name)
end
ret
end
end
sig { params(attributes: T::Hash[Symbol, T.untyped]).returns(T.untyped) }
def update_json_columns(attributes)
klass = T.cast(self.class, T.class_of(ActiveRecord::Base))
@@ -121,19 +136,6 @@ module AttrJsonRecordAliases
SQL
end
sig { params(name: T.untyped, value: T.untyped).returns(T.untyped) }
def write_attribute(name, value)
klass = T.cast(self.class, T.class_of(ActiveRecord::Base))
ret = super(name, value)
if attribute_def = ImplHelper.get_json_attr_def(klass, name)
public_send(attribute_def.container_attribute)[
attribute_def.store_key
] = read_attribute(name)
end
ret
end
module ImplHelper
extend T::Sig

View File

@@ -7,6 +7,7 @@ class Domain::User < ReduxApplicationRecord
include HasDescriptionHtmlForView
include HasTimestampsWithDueAt
include HasDomainType
include HasAuxTable
self.table_name = "domain_users"
abstract!

View File

@@ -1,12 +1,6 @@
# typed: strict
class Domain::User::InkbunnyUser < Domain::User
attr_json :ib_id, :integer
attr_json :name, :string
attr_json :state, :string
attr_json :scanned_gallery_at, ActiveModelUtcTimeValue.new
attr_json :deep_update_log_entry_id, :integer
attr_json :shallow_update_log_entry_id, :integer
attr_json :ib_detail_raw, ActiveModel::Type::Value.new
aux_table :inkbunny
belongs_to :deep_update_log_entry,
class_name: "::HttpLogEntry",

View File

@@ -0,0 +1,51 @@
# typed: strict
# frozen_string_literal: true
class AddAuxTablesForDomainUsersIbUsers < ActiveRecord::Migration[7.2]
extend T::Sig
sig { void }
def change
mirai_tablespace!
create_aux_table :domain_users, :inkbunny do |t|
t.integer :ib_id, null: false, index: true
t.string :name, null: false, index: true
t.string :state, null: false
t.timestamp :scanned_gallery_at
t.references :deep_update_log_entry,
foreign_key: {
to_table: :http_log_entries,
}
t.references :shallow_update_log_entry,
foreign_key: {
to_table: :http_log_entries,
}
t.column :ib_detail_raw, :jsonb, default: {}
end
up_only { execute <<-SQL }
INSERT INTO domain_users_inkbunny_aux (
base_table_id,
ib_id,
name,
state,
scanned_gallery_at,
deep_update_log_entry_id,
shallow_update_log_entry_id,
ib_detail_raw
)
SELECT
id as base_table_id,
(json_attributes->>'ib_id')::integer as ib_id,
(json_attributes->>'name')::text as name,
(json_attributes->>'state')::text as state,
(json_attributes->>'scanned_gallery_at')::timestamp as scanned_gallery_at,
(json_attributes->>'deep_update_log_entry_id')::integer as deep_update_log_entry_id,
(json_attributes->>'shallow_update_log_entry_id')::integer as shallow_update_log_entry_id,
(json_attributes->>'ib_detail_raw')::jsonb as ib_detail_raw
FROM domain_users
WHERE type = 'Domain::User::InkbunnyUser'
SQL
end
end

View File

@@ -3312,6 +3312,41 @@ CREATE SEQUENCE public.domain_users_id_seq
ALTER SEQUENCE public.domain_users_id_seq OWNED BY public.domain_users.id;
--
-- Name: domain_users_inkbunny_aux; Type: TABLE; Schema: public; Owner: -; Tablespace: mirai
--
CREATE TABLE public.domain_users_inkbunny_aux (
base_table_id bigint NOT NULL,
ib_id integer NOT NULL,
name character varying NOT NULL,
state character varying NOT NULL,
scanned_gallery_at timestamp without time zone,
deep_update_log_entry_id bigint,
shallow_update_log_entry_id bigint,
ib_detail_raw jsonb DEFAULT '{}'::jsonb
);
--
-- Name: domain_users_inkbunny_aux_base_table_id_seq; Type: SEQUENCE; Schema: public; Owner: -
--
CREATE SEQUENCE public.domain_users_inkbunny_aux_base_table_id_seq
START WITH 1
INCREMENT BY 1
NO MINVALUE
NO MAXVALUE
CACHE 1;
--
-- Name: domain_users_inkbunny_aux_base_table_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
--
ALTER SEQUENCE public.domain_users_inkbunny_aux_base_table_id_seq OWNED BY public.domain_users_inkbunny_aux.base_table_id;
SET default_tablespace = '';
--
@@ -4934,6 +4969,13 @@ ALTER TABLE ONLY public.domain_user_search_names ALTER COLUMN id SET DEFAULT nex
ALTER TABLE ONLY public.domain_users ALTER COLUMN id SET DEFAULT nextval('public.domain_users_id_seq'::regclass);
--
-- Name: domain_users_inkbunny_aux base_table_id; Type: DEFAULT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.domain_users_inkbunny_aux ALTER COLUMN base_table_id SET DEFAULT nextval('public.domain_users_inkbunny_aux_base_table_id_seq'::regclass);
--
-- Name: global_states id; Type: DEFAULT; Schema: public; Owner: -
--
@@ -5766,6 +5808,14 @@ ALTER TABLE ONLY public.domain_user_search_names
ADD CONSTRAINT domain_user_search_names_pkey PRIMARY KEY (id);
--
-- Name: domain_users_inkbunny_aux domain_users_inkbunny_aux_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: mirai
--
ALTER TABLE ONLY public.domain_users_inkbunny_aux
ADD CONSTRAINT domain_users_inkbunny_aux_pkey PRIMARY KEY (base_table_id);
--
-- Name: domain_users domain_users_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: mirai
--
@@ -7700,6 +7750,41 @@ CREATE UNIQUE INDEX index_domain_user_user_follows_on_from_id_and_to_id ON publi
CREATE INDEX index_domain_user_user_follows_on_to_id_and_from_id ON public.domain_user_user_follows USING btree (to_id, from_id);
--
-- Name: index_domain_users_inkbunny_aux_on_base_table_id; Type: INDEX; Schema: public; Owner: -; Tablespace: mirai
--
CREATE INDEX index_domain_users_inkbunny_aux_on_base_table_id ON public.domain_users_inkbunny_aux USING btree (base_table_id);
--
-- Name: index_domain_users_inkbunny_aux_on_deep_update_log_entry_id; Type: INDEX; Schema: public; Owner: -; Tablespace: mirai
--
CREATE INDEX index_domain_users_inkbunny_aux_on_deep_update_log_entry_id ON public.domain_users_inkbunny_aux USING btree (deep_update_log_entry_id);
--
-- Name: index_domain_users_inkbunny_aux_on_ib_id; Type: INDEX; Schema: public; Owner: -; Tablespace: mirai
--
CREATE INDEX index_domain_users_inkbunny_aux_on_ib_id ON public.domain_users_inkbunny_aux USING btree (ib_id);
--
-- Name: index_domain_users_inkbunny_aux_on_name; Type: INDEX; Schema: public; Owner: -; Tablespace: mirai
--
CREATE INDEX index_domain_users_inkbunny_aux_on_name ON public.domain_users_inkbunny_aux USING btree (name);
--
-- Name: index_domain_users_inkbunny_aux_on_shallow_update_log_entry_id; Type: INDEX; Schema: public; Owner: -; Tablespace: mirai
--
CREATE INDEX index_domain_users_inkbunny_aux_on_shallow_update_log_entry_id ON public.domain_users_inkbunny_aux USING btree (shallow_update_log_entry_id);
--
-- Name: index_domain_users_on_type; Type: INDEX; Schema: public; Owner: -; Tablespace: mirai
--
@@ -8962,6 +9047,14 @@ ALTER TABLE ONLY public.domain_fa_follows
ADD CONSTRAINT fk_rails_175679b7a2 FOREIGN KEY (followed_id) REFERENCES public.domain_fa_users(id);
--
-- Name: domain_users_inkbunny_aux fk_rails_205f95e7f6; Type: FK CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.domain_users_inkbunny_aux
ADD CONSTRAINT fk_rails_205f95e7f6 FOREIGN KEY (shallow_update_log_entry_id) REFERENCES public.http_log_entries(id);
--
-- Name: domain_post_group_joins fk_rails_22154fb920; Type: FK CONSTRAINT; Schema: public; Owner: -
--
@@ -8994,6 +9087,14 @@ ALTER TABLE ONLY public.domain_fa_user_avatars
ADD CONSTRAINT fk_rails_2a03f31297 FOREIGN KEY (log_entry_id) REFERENCES public.http_log_entries(id);
--
-- Name: domain_users_inkbunny_aux fk_rails_304ea0307f; Type: FK CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.domain_users_inkbunny_aux
ADD CONSTRAINT fk_rails_304ea0307f FOREIGN KEY (base_table_id) REFERENCES public.domain_users(id);
--
-- Name: domain_inkbunny_files fk_rails_31a33e433e; Type: FK CONSTRAINT; Schema: public; Owner: -
--
@@ -9194,6 +9295,14 @@ ALTER TABLE ONLY public.domain_post_files_inkbunny_aux
ADD CONSTRAINT fk_rails_b4f96e5241 FOREIGN KEY (base_table_id) REFERENCES public.domain_post_files(id);
--
-- Name: domain_users_inkbunny_aux fk_rails_c2d597dcc4; Type: FK CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.domain_users_inkbunny_aux
ADD CONSTRAINT fk_rails_c2d597dcc4 FOREIGN KEY (deep_update_log_entry_id) REFERENCES public.http_log_entries(id);
--
-- Name: domain_inkbunny_posts fk_rails_c2d9f4b382; Type: FK CONSTRAINT; Schema: public; Owner: -
--
@@ -9329,6 +9438,7 @@ ALTER TABLE ONLY public.domain_twitter_tweets
SET search_path TO "$user", public;
INSERT INTO "schema_migrations" (version) VALUES
('20250718165332'),
('20250718162608'),
('20250717204152'),
('20250716164417'),

View File

@@ -5,7 +5,7 @@
# Please instead update this file by running `bin/tapioca gem has_aux_table`.
# source://has_aux_table//lib/has_aux_table/migration_extensions.rb#58
# source://has_aux_table//lib/has_aux_table/migration_extensions.rb#119
class ActiveRecord::Migration
include ::HasAuxTable::MigrationExtensions
@@ -256,33 +256,41 @@ class HasAuxTable::AuxTableConfig < ::T::Struct
end
end
# source://has_aux_table//lib/has_aux_table/migration_extensions.rb#5
class HasAuxTable::BaseTableDefinition
# @return [BaseTableDefinition] a new instance of BaseTableDefinition
#
# source://has_aux_table//lib/has_aux_table/migration_extensions.rb#8
def initialize(schema, base_table_name, inner); end
# @abstract Subclasses must implement the `abstract` methods below.
#
# source://has_aux_table//lib/has_aux_table/migration_extensions.rb#16
module HasAuxTable::AuxTableDefinition
abstract!
# source://has_aux_table//lib/has_aux_table/migration_extensions.rb#14
# source://has_aux_table//lib/has_aux_table/migration_extensions.rb#28
sig { params(aux_name: ::Symbol, options: T::Hash[::Symbol, T.untyped], block: T.untyped).void }
def create_aux(aux_name, **options, &block); end
# source://activesupport/7.2.2.1/lib/active_support/delegation.rb#187
def method_missing(method, *_arg1, **_arg2, &_arg3); end
protected
private
# Returns the value of attribute inner.
# @abstract
#
# source://has_aux_table//lib/has_aux_table/migration_extensions.rb#20
def inner; end
# source://has_aux_table//lib/has_aux_table/migration_extensions.rb#39
sig { abstract.returns(::Symbol) }
def aux_base_table_name; end
# source://activesupport/7.2.2.1/lib/active_support/delegation.rb#179
def respond_to_missing?(name, include_private = T.unsafe(nil)); end
# Returns the value of attribute schema.
# @abstract
#
# source://has_aux_table//lib/has_aux_table/migration_extensions.rb#20
# source://has_aux_table//lib/has_aux_table/migration_extensions.rb#35
sig { abstract.returns(::ActiveRecord::Schema) }
def schema; end
class << self
# source://has_aux_table//lib/has_aux_table/migration_extensions.rb#49
sig do
params(
table_definition: T.any(::ActiveRecord::ConnectionAdapters::Table, ::ActiveRecord::ConnectionAdapters::TableDefinition),
schema: ::HasAuxTable::MigrationExtensions,
aux_base_table_name: ::Symbol
).returns(T.all(::HasAuxTable::AuxTableDefinition, T.any(::ActiveRecord::ConnectionAdapters::Table, ::ActiveRecord::ConnectionAdapters::TableDefinition)))
end
def augment(table_definition, schema, aux_base_table_name); end
end
end
# source://has_aux_table//lib/has_aux_table.rb#31
@@ -299,17 +307,17 @@ module HasAuxTable::ClassMethods
private
# source://has_aux_table//lib/has_aux_table.rb#198
# source://has_aux_table//lib/has_aux_table.rb#199
sig { params(load_schema_method: ::Method, config: ::HasAuxTable::AuxTableConfig).void }
def aux_config_load_schema!(load_schema_method, config); end
# source://has_aux_table//lib/has_aux_table.rb#318
# source://has_aux_table//lib/has_aux_table.rb#342
sig { params(aux_table_name: ::Symbol, main_columns: T::Array[::String], aux_columns: T::Array[::String]).void }
def check_for_overlapping_columns!(aux_table_name, main_columns, aux_columns); end
# Generate auxiliary model class dynamically
#
# source://has_aux_table//lib/has_aux_table.rb#73
# source://has_aux_table//lib/has_aux_table.rb#74
sig do
params(
aux_name: ::Symbol,
@@ -319,33 +327,37 @@ module HasAuxTable::ClassMethods
end
def generate_aux_config(aux_name, foreign_key: T.unsafe(nil), primary_key: T.unsafe(nil)); end
# source://has_aux_table//lib/has_aux_table.rb#232
# source://has_aux_table//lib/has_aux_table.rb#233
sig { params(config: ::HasAuxTable::AuxTableConfig).void }
def setup_attribute_getter_setter_hooks!(config); end
# source://has_aux_table//lib/has_aux_table.rb#141
# source://has_aux_table//lib/has_aux_table.rb#142
sig { params(config: ::HasAuxTable::AuxTableConfig).void }
def setup_attribute_types_hook!(config); end
# source://has_aux_table//lib/has_aux_table.rb#300
# source://has_aux_table//lib/has_aux_table.rb#324
sig { params(config: ::HasAuxTable::AuxTableConfig).void }
def setup_attributes_hook!(config); end
# source://has_aux_table//lib/has_aux_table.rb#254
# source://has_aux_table//lib/has_aux_table.rb#271
sig { params(config: ::HasAuxTable::AuxTableConfig).void }
def setup_changed_hook!(config); end
# source://has_aux_table//lib/has_aux_table.rb#255
sig { params(config: ::HasAuxTable::AuxTableConfig).void }
def setup_initialize_hook!(config); end
# Hook into schema loading to generate attribute accessors when schema is loaded
#
# source://has_aux_table//lib/has_aux_table.rb#182
# source://has_aux_table//lib/has_aux_table.rb#183
sig { params(config: ::HasAuxTable::AuxTableConfig).void }
def setup_load_schema_hook!(config); end
# source://has_aux_table//lib/has_aux_table.rb#282
# source://has_aux_table//lib/has_aux_table.rb#306
sig { params(config: ::HasAuxTable::AuxTableConfig).void }
def setup_reload_hook!(config); end
# source://has_aux_table//lib/has_aux_table.rb#265
# source://has_aux_table//lib/has_aux_table.rb#289
sig { params(config: ::HasAuxTable::AuxTableConfig).void }
def setup_save_hook!(config); end
end
@@ -353,18 +365,41 @@ end
# source://has_aux_table//lib/has_aux_table/key_type.rb#5
HasAuxTable::KeyType = T.type_alias { T.any(::String, ::Symbol, T::Array[T.any(::String, ::Symbol)]) }
# source://has_aux_table//lib/has_aux_table/migration_extensions.rb#23
# source://has_aux_table//lib/has_aux_table/migration_extensions.rb#59
module HasAuxTable::MigrationExtensions
requires_ancestor { ActiveRecord::Migration }
# source://has_aux_table//lib/has_aux_table/migration_extensions.rb#36
def change_base_table(name, **options); end
# source://has_aux_table//lib/has_aux_table/migration_extensions.rb#87
sig do
params(
name: ::Symbol,
options: T::Hash[::Symbol, T.untyped],
block: T.proc.params(table_definition: T.all(::HasAuxTable::AuxTableDefinition, T.any(::ActiveRecord::ConnectionAdapters::Table, ::ActiveRecord::ConnectionAdapters::TableDefinition))).void
).void
end
def change_base_table(name, **options, &block); end
# source://has_aux_table//lib/has_aux_table/migration_extensions.rb#42
def create_aux_table(base_table, name, **options); end
# source://has_aux_table//lib/has_aux_table/migration_extensions.rb#102
sig do
params(
base_table: ::Symbol,
name: ::Symbol,
options: T::Hash[::Symbol, T.untyped],
block: T.proc.params(table_definition: T.all(::HasAuxTable::AuxTableDefinition, T.any(::ActiveRecord::ConnectionAdapters::Table, ::ActiveRecord::ConnectionAdapters::TableDefinition))).void
).void
end
def create_aux_table(base_table, name, **options, &block); end
# source://has_aux_table//lib/has_aux_table/migration_extensions.rb#28
def create_base_table(name, type: T.unsafe(nil), **options); end
# source://has_aux_table//lib/has_aux_table/migration_extensions.rb#72
sig do
params(
name: ::Symbol,
type: ::Symbol,
options: T::Hash[::Symbol, T.untyped],
block: T.proc.params(table_definition: T.all(::HasAuxTable::AuxTableDefinition, T.any(::ActiveRecord::ConnectionAdapters::Table, ::ActiveRecord::ConnectionAdapters::TableDefinition))).void
).void
end
def create_base_table(name, type: T.unsafe(nil), **options, &block); end
end
# source://has_aux_table//lib/has_aux_table/aux_table_config.rb#5
@@ -436,6 +471,12 @@ end
# source://has_aux_table//lib/has_aux_table/relation_extensions.rb#7
HasAuxTable::RelationExtensions::Util = HasAuxTable::Util
# source://has_aux_table//lib/has_aux_table/migration_extensions.rb#5
HasAuxTable::TableDefinition = T.type_alias { T.any(::ActiveRecord::ConnectionAdapters::Table, ::ActiveRecord::ConnectionAdapters::TableDefinition) }
# source://has_aux_table//lib/has_aux_table/migration_extensions.rb#13
HasAuxTable::TableDefinitionWithAux = T.type_alias { T.all(::HasAuxTable::AuxTableDefinition, T.any(::ActiveRecord::ConnectionAdapters::Table, ::ActiveRecord::ConnectionAdapters::TableDefinition)) }
# source://has_aux_table//lib/has_aux_table/util.rb#5
module HasAuxTable::Util
class << self

View File

@@ -107,6 +107,7 @@ RSpec.describe Domain::PostsHelper, type: :helper do
].each do |url|
it "returns a link to inkbunny user for #{url}" do
user = create(:domain_user_inkbunny_user, name: "artistone")
# binding.pry
expect(url).to eq_link_for_source(model: user, title: "artistone")
end
end

View File

@@ -126,7 +126,8 @@ RSpec.describe Domain::Inkbunny::Job::UserGalleryJob do
end
let(:args) { { user: user, caused_by_entry: nil } }
it "correctly handles posts with a null last_file_update_datetime" do
it "correctly handles posts with a null last_file_update_datetime",
quiet: false do
expect { perform_now(args) }.to(
change(Domain::Post::InkbunnyPost, :count).by(1),
)

View File

@@ -11,6 +11,7 @@ RSpec::Matchers.define :eq_link_for_source do |model:, title:|
failure_message do |actual_url|
actual = helper.link_for_source(actual_url)
if actual.nil?
binding.pry
"link for source was nil for url #{actual_url}"
elsif actual.model != model
"expected model #{model.to_gid.uri.to_s} to be #{actual.model.to_gid.uri.to_s} for url #{actual_url}"