Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,16 @@

* ...

## 0.5.0 2025-07-09

### Added
* Introduced `:group_table_definition` 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 `:group_table_definition` 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)
Expand Down
7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,13 @@ end

## Other options

### indexes_after_tables
### group_table_definition

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 group_table_definition:

```ruby
Rails.application.configure do
config.activerecord_clean_db_structure.indexes_after_tables = true
config.activerecord_clean_db_structure.group_table_definition = true
end
```

Expand All @@ -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
Expand Down
1 change: 1 addition & 0 deletions activerecord-clean-db-structure
Submodule activerecord-clean-db-structure added at 7c3625
23 changes: 20 additions & 3 deletions lib/activerecord-clean-db-structure/clean_dump.rb
Original file line number Diff line number Diff line change
Expand Up @@ -129,17 +129,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 :group_table_definition instead."
end

if options[:indexes_after_tables] || options[:group_table_definition]
# 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
Expand Down
4 changes: 4 additions & 0 deletions test/clean_dump_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ def test_indexes_after_tables
assert_cleans_dump "data/input.sql", "expectations/indexes_after_tables.sql", indexes_after_tables: true
end

def test_group_table_definition
assert_cleans_dump "data/input.sql", "expectations/group_table_definition.sql", group_table_definition: true
end

def test_keep_extensions_all
assert_cleans_dump "data/input.sql", "expectations/keep_extensions_all.sql", keep_extensions: :all
end
Expand Down
5 changes: 5 additions & 0 deletions test/data/input.sql
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,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: -
Expand Down
5 changes: 5 additions & 0 deletions test/expectations/default_props.sql
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
73 changes: 73 additions & 0 deletions test/expectations/group_table_definition.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
SET statement_timeout = 0;
SET lock_timeout = 0;
SET client_encoding = 'UTF8';
SET standard_conforming_strings = on;
SELECT pg_catalog.set_config('search_path', '', false);
SET check_function_bodies = false;
SET client_min_messages = warning;

SET default_tablespace = '';

-- Name: ar_internal_metadata; Type: TABLE

CREATE TABLE public.ar_internal_metadata (
key character varying NOT NULL,
value character varying,
created_at timestamp(6) without time zone NOT NULL,
updated_at timestamp(6) without time zone NOT NULL
);

-- Name: delayed_jobs; Type: TABLE

CREATE TABLE public.delayed_jobs (
id BIGSERIAL PRIMARY KEY,
priority integer DEFAULT 0,
attempts integer DEFAULT 0,
handler text,
last_error text,
run_at timestamp without time zone,
locked_at timestamp without time zone,
failed_at timestamp without time zone,
locked_by character varying(255),
queue character varying(255),
created_at timestamp without time zone NOT NULL,
updated_at timestamp without time zone NOT NULL,
metadata jsonb DEFAULT '{}'::jsonb,
whodunnit text
)
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_failed_at_IS_NULL" ON public.delayed_jobs USING btree (((failed_at IS NULL)));
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

CREATE TABLE public.schema_migrations (
version character varying NOT NULL
);

ALTER TABLE ONLY public.ar_internal_metadata
ADD CONSTRAINT ar_internal_metadata_pkey PRIMARY KEY (key);

ALTER TABLE ONLY public.schema_migrations
ADD CONSTRAINT schema_migrations_pkey PRIMARY KEY (version);

-- PostgreSQL database dump complete

SET search_path TO "$user", public;

INSERT INTO "schema_migrations" (version) VALUES
('20240822225012'),
('20240822224954'),
('20240725043656'),
('20240621041110'),
('20240621020038'),
('20220802204003'),
('20211125055031'),
('20211012054749'),
('20210923052631'),
('20210903003251');
5 changes: 5 additions & 0 deletions test/expectations/ignore_ids.sql
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions test/expectations/indexes_after_tables.sql
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ CREATE INDEX index_delayed_jobs_on_locked_by ON public.delayed_jobs USING btree
CREATE INDEX index_delayed_jobs_on_queue ON public.delayed_jobs USING btree (queue);
CREATE INDEX "index_delayed_jobs_on_failed_at_IS_NULL" ON public.delayed_jobs USING btree (((failed_at IS NULL)));
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

Expand Down
5 changes: 5 additions & 0 deletions test/expectations/keep_extensions_all.sql
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
5 changes: 5 additions & 0 deletions test/expectations/order_column_definitions.sql
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
5 changes: 5 additions & 0 deletions test/expectations/order_schema_migrations_values.sql
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
Loading