diff --git a/CHANGELOG.md b/CHANGELOG.md index 3cfeac6..765b32e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,16 @@ * ... +## 0.5.0 2025-07-09 + +### Added +* Introduced `:meta_tables_after_main` option as a more flexible replacement for `:indexes_after_tables`. + This option places indexes and deferrable constraints after their respective `CREATE TABLE` statements. + +### Deprecated +* `:indexes_after_tables` is now deprecated and will be removed in version 1.0.0. + Please migrate to the new `:meta_tables_after_main` option. + ## 0.4.3 2024-09-22 * Fix additional regexp warnings from "rake test". [#50](https://github.com/lfittl/activerecord-clean-db-structure/pull/50) diff --git a/Gemfile.lock b/Gemfile.lock index 120629b..74eb902 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,7 +1,7 @@ PATH remote: . specs: - activerecord-clean-db-structure (0.4.3) + activerecord-clean-db-structure (0.5.0) activerecord (>= 4.2) GEM diff --git a/README.md b/README.md index 561782b..82bef06 100644 --- a/README.md +++ b/README.md @@ -40,13 +40,13 @@ end ## Other options -### indexes_after_tables +### meta_tables_after_main -You can optionally have indexes following the respective tables setting `indexes_after_tables`: +You can optionally place indexes and constraints (limited to deferrable ones) after the main tables by setting meta_tables_after_main: ```ruby Rails.application.configure do - config.activerecord_clean_db_structure.indexes_after_tables = true + config.activerecord_clean_db_structure.meta_tables_after_main = true end ``` @@ -61,6 +61,7 @@ CREATE TABLE public.users ( CREATE INDEX index_users_on_tentant_id ON public.users USING btree (tenant_id); CREATE UNIQUE INDEX index_users_on_email ON public.users USING btree (email); +ALTER TABLE public.users ADD CONSTRAINT unique_tenant UNIQUE (tenant_id) DEFERRABLE INITIALLY DEFERRED; ``` ### order_column_definitions diff --git a/lib/activerecord-clean-db-structure/clean_dump.rb b/lib/activerecord-clean-db-structure/clean_dump.rb index f95d71a..3c92a43 100644 --- a/lib/activerecord-clean-db-structure/clean_dump.rb +++ b/lib/activerecord-clean-db-structure/clean_dump.rb @@ -128,17 +128,34 @@ def clean_options dump.gsub!(/^(INSERT INTO schema_migrations .*)\n\n/, "\\1\n") end - if options[:indexes_after_tables] == true - # Extract indexes, remove comments and place them just after the respective tables + # TODO: Remove support for :indexes_after_tables in version 1.0.0 + if options[:indexes_after_tables] + warn "[DEPRECATION] The :indexes_after_tables option is deprecated and will be removed in version 1.0.0. Use :meta_tables_after_main instead." + end + + if options[:indexes_after_tables] || options[:meta_tables_after_main] + # Extract indexes indexes = dump .scan(/^CREATE.+INDEX.+ON.+\n/) .group_by { |line| line.scan(/\b\w+\.\w+\b/).first } .transform_values(&:join) + # Extract deferrable constraints + deferrable_constraints = + dump + .scan(/^ALTER.+TABLE.+ONLY.+\n.+DEFERRABLE.+\n/) + .group_by { |line| line.scan(/\b\w+\.\w+\b/).first } + .transform_values(&:join) + + # Remove indexes and deferrable constraints from the dump dump.gsub!(/^CREATE( UNIQUE)? INDEX \w+ ON .+\n+/, '') dump.gsub!(/^-- Name: \w+; Type: INDEX; Schema: \w+\n+/, '') - indexes.each do |table, indexes_for_table| + + dump.gsub!(/^-- Name.+\n\nALTER.+TABLE.+ONLY.+\n.+DEFERRABLE.+\n+/, '') + + indexes_and_constraints = indexes.merge(deferrable_constraints) { |_, v1, v2| v1 + v2 } + indexes_and_constraints.each do |table, indexes_for_table| dump.gsub!(/^(CREATE TABLE #{table}\b(:?[^;\n]*\n)+\);*\n(?:.*);*)/) { $1 + "\n\n" + indexes_for_table } end end diff --git a/lib/activerecord-clean-db-structure/version.rb b/lib/activerecord-clean-db-structure/version.rb index 8ec9986..2a5c468 100644 --- a/lib/activerecord-clean-db-structure/version.rb +++ b/lib/activerecord-clean-db-structure/version.rb @@ -1,3 +1,3 @@ module ActiveRecordCleanDbStructure - VERSION = '0.4.3' + VERSION = '0.5.0' end diff --git a/test/clean_dump_test.rb b/test/clean_dump_test.rb index 9d72c2b..605f2f6 100644 --- a/test/clean_dump_test.rb +++ b/test/clean_dump_test.rb @@ -17,8 +17,8 @@ def test_order_schema_migrations_values assert_cleans_dump "data/input.sql", "expectations/order_schema_migrations_values.sql", order_schema_migrations_values: true end - def test_indexes_after_tables - assert_cleans_dump "data/input.sql", "expectations/indexes_after_tables.sql", indexes_after_tables: true + def test_meta_tables_after_main + assert_cleans_dump "data/input.sql", "expectations/meta_tables_after_main.sql", meta_tables_after_main: true end def test_keep_extensions_all diff --git a/test/data/input.sql b/test/data/input.sql index 61b2a18..94b2e57 100644 --- a/test/data/input.sql +++ b/test/data/input.sql @@ -113,6 +113,11 @@ ALTER TABLE ONLY public.ar_internal_metadata ALTER TABLE ONLY public.delayed_jobs ADD CONSTRAINT delayed_jobs_pkey PRIMARY KEY (id); +-- +-- Name: unique_locked_by_locked_at; Type: CONSTRAINT +-- +ALTER TABLE ONLY public.delayed_jobs + ADD CONSTRAINT unique_locked_by_locked_at UNIQUE (locked_by, locked_at) DEFERRABLE INITIALLY DEFERRED; -- -- Name: schema_migrations schema_migrations_pkey; Type: CONSTRAINT; Schema: public; Owner: - diff --git a/test/expectations/default_props.sql b/test/expectations/default_props.sql index 185e3d5..7675446 100644 --- a/test/expectations/default_props.sql +++ b/test/expectations/default_props.sql @@ -46,6 +46,11 @@ CREATE TABLE public.schema_migrations ( ALTER TABLE ONLY public.ar_internal_metadata ADD CONSTRAINT ar_internal_metadata_pkey PRIMARY KEY (key); +-- Name: unique_locked_by_locked_at; Type: CONSTRAINT + +ALTER TABLE ONLY public.delayed_jobs + ADD CONSTRAINT unique_locked_by_locked_at UNIQUE (locked_by, locked_at) DEFERRABLE INITIALLY DEFERRED; + ALTER TABLE ONLY public.schema_migrations ADD CONSTRAINT schema_migrations_pkey PRIMARY KEY (version); diff --git a/test/expectations/ignore_ids.sql b/test/expectations/ignore_ids.sql index 4aa2f89..74eb50d 100644 --- a/test/expectations/ignore_ids.sql +++ b/test/expectations/ignore_ids.sql @@ -70,6 +70,11 @@ ALTER TABLE ONLY public.ar_internal_metadata ALTER TABLE ONLY public.delayed_jobs ADD CONSTRAINT delayed_jobs_pkey PRIMARY KEY (id); +-- Name: unique_locked_by_locked_at; Type: CONSTRAINT + +ALTER TABLE ONLY public.delayed_jobs + ADD CONSTRAINT unique_locked_by_locked_at UNIQUE (locked_by, locked_at) DEFERRABLE INITIALLY DEFERRED; + -- Name: schema_migrations schema_migrations_pkey; Type: CONSTRAINT ALTER TABLE ONLY public.schema_migrations diff --git a/test/expectations/keep_extensions_all.sql b/test/expectations/keep_extensions_all.sql index 296e54d..298943e 100644 --- a/test/expectations/keep_extensions_all.sql +++ b/test/expectations/keep_extensions_all.sql @@ -52,6 +52,11 @@ CREATE TABLE public.schema_migrations ( ALTER TABLE ONLY public.ar_internal_metadata ADD CONSTRAINT ar_internal_metadata_pkey PRIMARY KEY (key); +-- Name: unique_locked_by_locked_at; Type: CONSTRAINT + +ALTER TABLE ONLY public.delayed_jobs + ADD CONSTRAINT unique_locked_by_locked_at UNIQUE (locked_by, locked_at) DEFERRABLE INITIALLY DEFERRED; + ALTER TABLE ONLY public.schema_migrations ADD CONSTRAINT schema_migrations_pkey PRIMARY KEY (version); diff --git a/test/expectations/indexes_after_tables.sql b/test/expectations/meta_tables_after_main.sql similarity index 93% rename from test/expectations/indexes_after_tables.sql rename to test/expectations/meta_tables_after_main.sql index a354946..c2c4367 100644 --- a/test/expectations/indexes_after_tables.sql +++ b/test/expectations/meta_tables_after_main.sql @@ -40,6 +40,8 @@ WITH (fillfactor='85'); CREATE INDEX index_delayed_jobs_on_locked_by ON public.delayed_jobs USING btree (locked_by); CREATE INDEX index_delayed_jobs_on_queue ON public.delayed_jobs USING btree (queue); CREATE INDEX index_delayed_jobs_on_run_at ON public.delayed_jobs USING btree (run_at) WHERE (locked_at IS NULL); +ALTER TABLE ONLY public.delayed_jobs + ADD CONSTRAINT unique_locked_by_locked_at UNIQUE (locked_by, locked_at) DEFERRABLE INITIALLY DEFERRED; -- Name: schema_migrations; Type: TABLE diff --git a/test/expectations/order_column_definitions.sql b/test/expectations/order_column_definitions.sql index 5089ca8..5b8aa9a 100644 --- a/test/expectations/order_column_definitions.sql +++ b/test/expectations/order_column_definitions.sql @@ -46,6 +46,11 @@ CREATE TABLE public.schema_migrations ( ALTER TABLE ONLY public.ar_internal_metadata ADD CONSTRAINT ar_internal_metadata_pkey PRIMARY KEY (key); +-- Name: unique_locked_by_locked_at; Type: CONSTRAINT + +ALTER TABLE ONLY public.delayed_jobs + ADD CONSTRAINT unique_locked_by_locked_at UNIQUE (locked_by, locked_at) DEFERRABLE INITIALLY DEFERRED; + ALTER TABLE ONLY public.schema_migrations ADD CONSTRAINT schema_migrations_pkey PRIMARY KEY (version); diff --git a/test/expectations/order_schema_migrations_values.sql b/test/expectations/order_schema_migrations_values.sql index cf8fd44..2c832cc 100644 --- a/test/expectations/order_schema_migrations_values.sql +++ b/test/expectations/order_schema_migrations_values.sql @@ -46,6 +46,11 @@ CREATE TABLE public.schema_migrations ( ALTER TABLE ONLY public.ar_internal_metadata ADD CONSTRAINT ar_internal_metadata_pkey PRIMARY KEY (key); +-- Name: unique_locked_by_locked_at; Type: CONSTRAINT + +ALTER TABLE ONLY public.delayed_jobs + ADD CONSTRAINT unique_locked_by_locked_at UNIQUE (locked_by, locked_at) DEFERRABLE INITIALLY DEFERRED; + ALTER TABLE ONLY public.schema_migrations ADD CONSTRAINT schema_migrations_pkey PRIMARY KEY (version);