activerecord-clean-db-structure 0.3.0 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 6ee2c62ab134b71d0ccce4e02928038c983c4403
4
- data.tar.gz: 6264e28734c7ca2066fefbd2a6ef3dc68e68c1c1
2
+ SHA256:
3
+ metadata.gz: 412a73ec5fd32ea8373d0fdc86dfd290f4a8524d1e7f3fbf3611fd5c4f75fefa
4
+ data.tar.gz: b5020420e5d3b258e252306411f09cdb82e2c57dfc41dcd81775b0e866f28470
5
5
  SHA512:
6
- metadata.gz: bf88f74415c68337f2b9f409a358085d4d71c64be4696a942b973a2d34c420024f9bde791f3edb120c1df26357d8c3d0f5d47ed94892437b63ef72b388ae5175
7
- data.tar.gz: 1b086ae9152601942d7999ab0491c2d5d4e812e34208688f5bd8d8437530d74c868b0ca6a5639b237b2cb9cdd80c3caa1cd7871c601100b586ee748a86fe5def
6
+ metadata.gz: e9f21da42eecc194ae9dbbfc5289d2733d115e7ddfe9a7bdea651bc8171cc15514af85e5825386f8bba14d73d3b58136433b92c9fcc94ed8a35d8dfae306cc5e
7
+ data.tar.gz: 16988f199aff2f875dc0513e18da004d2b6ed4d09fbda5d0de05e914f69ae69ca6c685a408c6393a5467a5e957eac4b13da4f207283650b08fb786f4c4a3a535
data/CHANGELOG.md CHANGED
@@ -1,5 +1,31 @@
1
1
  # Changelog
2
2
 
3
+ ## Unreleased
4
+
5
+ * ...
6
+
7
+ ## 0.4.1 2024-08-28
8
+
9
+ * Fix Rake task name for 6.1+ [#32](https://github.com/lfittl/activerecord-clean-db-structure/pull/32)
10
+ * Bump activesupport [#36](https://github.com/lfittl/activerecord-clean-db-structure/pull/36), [#35](https://github.com/lfittl/activerecord-clean-db-structure/pull/35)
11
+ * Bump tzinfo [#29](https://github.com/lfittl/activerecord-clean-db-structure/pull/29)
12
+ * Update rake [#30](https://github.com/lfittl/activerecord-clean-db-structure/pull/30)
13
+ * Bump activerecord [#34](https://github.com/lfittl/activerecord-clean-db-structure/pull/34)
14
+
15
+ ## 0.4.0 2019-08-27
16
+
17
+ * Add "indexes_after_tables" option to allow indexes to be placed following the respective tables [#13](https://github.com/lfittl/activerecord-clean-db-structure/pull/13) [Giovanni Kock Bonetti](https://github.com/giovannibonetti)
18
+ * Add "order_schema_migrations_values" option to prevent schema_migrations values causing merge conflicts [#15](https://github.com/lfittl/activerecord-clean-db-structure/pull/15) [Nicke van Oorschot](https://github.com/nvanoorschot)
19
+ * Add "order_column_definitions" option to sort table columns alphabetically [#11](https://github.com/lfittl/activerecord-clean-db-structure/pull/11) [RKushnir](https://github.com/RKushnir)
20
+ * Generalize handling of schema names to not assume public
21
+ * Rails 6 support
22
+ * Fix Rails 6 compatibility [#16](https://github.com/lfittl/activerecord-clean-db-structure/pull/16) [Giovanni Kock Bonetti](https://github.com/giovannibonetti)
23
+ * Fix handling of multiple structure.sql files
24
+ * Remove Postgres 12 specific GUCs
25
+ * Generalize handling of schema names to not assume public
26
+ * Fix whitespace issue for config settings, remove default_with_oids
27
+
28
+
3
29
  ## 0.3.0 2019-05-07
4
30
 
5
31
  * Add "ignore_ids" option to allow disabling of primary key substitution logic [#12](https://github.com/lfittl/activerecord-clean-db-structure/pull/12) [Vladimir Dementyev](https://github.com/palkan)
data/Gemfile.lock CHANGED
@@ -1,39 +1,36 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- activerecord-clean-db-structure (0.3.0)
4
+ activerecord-clean-db-structure (0.4.1)
5
5
  activerecord (>= 4.2)
6
6
 
7
7
  GEM
8
8
  remote: https://rubygems.org/
9
9
  specs:
10
- activemodel (5.2.3)
11
- activesupport (= 5.2.3)
12
- activerecord (5.2.3)
13
- activemodel (= 5.2.3)
14
- activesupport (= 5.2.3)
15
- arel (>= 9.0)
16
- activesupport (5.2.3)
10
+ activemodel (7.0.4.3)
11
+ activesupport (= 7.0.4.3)
12
+ activerecord (7.0.4.3)
13
+ activemodel (= 7.0.4.3)
14
+ activesupport (= 7.0.4.3)
15
+ activesupport (7.0.4.3)
17
16
  concurrent-ruby (~> 1.0, >= 1.0.2)
18
- i18n (>= 0.7, < 2)
19
- minitest (~> 5.1)
20
- tzinfo (~> 1.1)
21
- arel (9.0.0)
22
- concurrent-ruby (1.1.5)
23
- i18n (1.6.0)
17
+ i18n (>= 1.6, < 2)
18
+ minitest (>= 5.1)
19
+ tzinfo (~> 2.0)
20
+ concurrent-ruby (1.3.3)
21
+ i18n (1.14.5)
22
+ concurrent-ruby (~> 1.0)
23
+ minitest (5.24.1)
24
+ rake (13.0.6)
25
+ tzinfo (2.0.6)
24
26
  concurrent-ruby (~> 1.0)
25
- minitest (5.11.3)
26
- rake (0.9.6)
27
- thread_safe (0.3.6)
28
- tzinfo (1.2.5)
29
- thread_safe (~> 0.1)
30
27
 
31
28
  PLATFORMS
32
29
  ruby
33
30
 
34
31
  DEPENDENCIES
35
32
  activerecord-clean-db-structure!
36
- rake (~> 0)
33
+ rake (~> 13)
37
34
 
38
35
  BUNDLED WITH
39
- 1.16.1
36
+ 1.17.3
data/README.md CHANGED
@@ -38,6 +38,55 @@ Rails.application.configure do
38
38
  end
39
39
  ```
40
40
 
41
+ ## Other options
42
+
43
+ You can optionally have indexes following the respective tables setting `indexes_after_tables`:
44
+
45
+ ```ruby
46
+ Rails.application.configure do
47
+ config.activerecord_clean_db_structure.indexes_after_tables = true
48
+ end
49
+ ```
50
+
51
+ When it is enabled the structure looks like this:
52
+
53
+ ```sql
54
+ CREATE TABLE public.users (
55
+ id SERIAL PRIMARY KEY,
56
+ tenant_id integer,
57
+ email text NOT NULL
58
+ );
59
+
60
+ CREATE INDEX index_users_on_tentant_id ON public.users USING btree (tenant_id);
61
+ CREATE UNIQUE INDEX index_users_on_email ON public.users USING btree (email);
62
+ ```
63
+
64
+ To enable sorting the table column definitions alphabetically, discarding the actual order provided by `pg_dump`, set `order_column_definitions`:
65
+
66
+ ```ruby
67
+ Rails.application.configure do
68
+ config.activerecord_clean_db_structure.order_column_definitions = true
69
+ end
70
+ ```
71
+
72
+ You can have the schema_migrations values reorganized to prevent merge conflicts by setting `order_schema_migrations_values`:
73
+
74
+ ```ruby
75
+ Rails.application.configure do
76
+ config.activerecord_clean_db_structure.order_schema_migrations_values = true
77
+ end
78
+ ```
79
+
80
+ When it is enabled the values are ordered chronological and the semicolon is placed on a separate line:
81
+
82
+ ```sql
83
+ INSERT INTO "schema_migrations" (version) VALUES
84
+ ('20190503120501')
85
+ ,('20190508123941')
86
+ ,('20190508132644')
87
+ ;
88
+ ```
89
+
41
90
  ## Authors
42
91
 
43
92
  * [Lukas Fittl](https://github.com/lfittl)
@@ -17,5 +17,5 @@ Gem::Specification.new do |s|
17
17
 
18
18
  s.add_dependency('activerecord', '>= 4.2')
19
19
 
20
- s.add_development_dependency 'rake', '~> 0'
20
+ s.add_development_dependency 'rake', '~> 13'
21
21
  end
@@ -15,8 +15,11 @@ module ActiveRecordCleanDbStructure
15
15
 
16
16
  # Remove version-specific output
17
17
  dump.gsub!(/^-- Dumped.*/, '')
18
- dump.gsub!(/^SET row_security = off;$/, '') # 9.5
19
- dump.gsub!(/^SET idle_in_transaction_session_timeout = 0;$/, '') # 9.6
18
+ dump.gsub!(/^SET row_security = off;\n/m, '') # 9.5
19
+ dump.gsub!(/^SET idle_in_transaction_session_timeout = 0;\n/m, '') # 9.6
20
+ dump.gsub!(/^SET default_with_oids = false;\n/m, '') # all older than 12
21
+ dump.gsub!(/^SET xmloption = content;\n/m, '') # 12
22
+ dump.gsub!(/^SET default_table_access_method = heap;\n/m, '') # 12
20
23
 
21
24
  # Remove pg_stat_statements extension (its not relevant to the code)
22
25
  dump.gsub!(/^CREATE EXTENSION IF NOT EXISTS pg_stat_statements.*/, '')
@@ -30,7 +33,7 @@ module ActiveRecordCleanDbStructure
30
33
  dump.gsub!(/^COMMENT ON EXTENSION .*/, '')
31
34
 
32
35
  # Remove useless, version-specific parts of comments
33
- dump.gsub!(/^-- (.*); Schema: (public|-); Owner: -.*/, '-- \1')
36
+ dump.gsub!(/^-- (.*); Schema: ([\w_\.]+|-); Owner: -.*/, '-- \1')
34
37
 
35
38
  # Remove useless comment lines
36
39
  dump.gsub!(/^--$/, '')
@@ -41,8 +44,8 @@ module ActiveRecordCleanDbStructure
41
44
  # This is a bit optimistic, but works as long as you don't have an id field thats not a sequence/uuid
42
45
  dump.gsub!(/^ id integer NOT NULL(,)?$/, ' id SERIAL PRIMARY KEY\1')
43
46
  dump.gsub!(/^ id bigint NOT NULL(,)?$/, ' id BIGSERIAL PRIMARY KEY\1')
44
- dump.gsub!(/^ id uuid DEFAULT (public\.)?uuid_generate_v4\(\) NOT NULL(,)?$/, ' id uuid DEFAULT \1uuid_generate_v4() PRIMARY KEY\2')
45
- dump.gsub!(/^ id uuid DEFAULT (public\.)?gen_random_uuid\(\) NOT NULL(,)?$/, ' id uuid DEFAULT \1gen_random_uuid() PRIMARY KEY\2')
47
+ dump.gsub!(/^ id uuid DEFAULT ([\w_]+\.)?uuid_generate_v4\(\) NOT NULL(,)?$/, ' id uuid DEFAULT \1uuid_generate_v4() PRIMARY KEY\2')
48
+ dump.gsub!(/^ id uuid DEFAULT ([\w_]+\.)?gen_random_uuid\(\) NOT NULL(,)?$/, ' id uuid DEFAULT \1gen_random_uuid() PRIMARY KEY\2')
46
49
  dump.gsub!(/^CREATE SEQUENCE [\w\.]+_id_seq\s+(AS integer\s+)?START WITH 1\s+INCREMENT BY 1\s+NO MINVALUE\s+NO MAXVALUE\s+CACHE 1;$/, '')
47
50
  dump.gsub!(/^ALTER SEQUENCE [\w\.]+_id_seq OWNED BY .*;$/, '')
48
51
  dump.gsub!(/^ALTER TABLE ONLY [\w\.]+ ALTER COLUMN id SET DEFAULT nextval\('[\w\.]+_id_seq'::regclass\);$/, '')
@@ -57,9 +60,9 @@ module ActiveRecordCleanDbStructure
57
60
  inherited_tables = dump.scan(inherited_tables_regexp).map(&:first)
58
61
  dump.gsub!(inherited_tables_regexp, '')
59
62
  inherited_tables.each do |inherited_table|
60
- dump.gsub!(/ALTER TABLE ONLY (public\.)?#{inherited_table}[^;]+;/, '')
63
+ dump.gsub!(/ALTER TABLE ONLY ([\w_]+\.)?#{inherited_table}[^;]+;/, '')
61
64
 
62
- index_regexp = /CREATE INDEX ([\w_]+) ON (public\.)?#{inherited_table}[^;]+;/m
65
+ index_regexp = /CREATE INDEX ([\w_]+) ON ([\w_]+\.)?#{inherited_table}[^;]+;/m
63
66
  dump.scan(index_regexp).map(&:first).each do |inherited_table_index|
64
67
  dump.gsub!("-- Name: #{inherited_table_index}; Type: INDEX", '')
65
68
  end
@@ -67,31 +70,122 @@ module ActiveRecordCleanDbStructure
67
70
  end
68
71
 
69
72
  # Remove partitioned tables
70
- partitioned_tables_regexp = /-- Name: ([\w_\.]+); Type: TABLE\n\n[^;]+?PARTITION OF [\w_\.]+\n[^;]+?;/m
71
- partitioned_tables = dump.scan(partitioned_tables_regexp).map(&:first)
72
- dump.gsub!(partitioned_tables_regexp, '')
73
+ partitioned_tables = []
74
+
75
+ # Postgres 12 pg_dump will output separate ATTACH PARTITION statements (even when run against an 11 or older server)
76
+ partitioned_tables_regexp1 = /ALTER TABLE ONLY [\w_\.]+ ATTACH PARTITION ([\w_\.]+)/
77
+ partitioned_tables += dump.scan(partitioned_tables_regexp1).map(&:last)
78
+
79
+ # Earlier versions use an inline PARTITION OF
80
+ partitioned_tables_regexp2 = /-- Name: ([\w_\.]+); Type: TABLE\n\n[^;]+?PARTITION OF [\w_\.]+\n[^;]+?;/m
81
+ partitioned_tables += dump.scan(partitioned_tables_regexp2).map(&:first)
82
+
73
83
  partitioned_tables.each do |partitioned_table|
74
- dump.gsub!(/ALTER TABLE ONLY (public\.)?#{partitioned_table}[^;]+;/, '')
84
+ partitioned_schema_name, partitioned_table_name_only = partitioned_table.split('.', 2)
85
+ dump.gsub!(/-- Name: #{partitioned_table_name_only}; Type: TABLE/, '')
86
+ dump.gsub!(/CREATE TABLE #{partitioned_table} \([^;]+;/m, '')
87
+ dump.gsub!(/ALTER TABLE ONLY ([\w_\.]+) ATTACH PARTITION #{partitioned_table}[^;]+;/m, '')
88
+
89
+ dump.gsub!(/ALTER TABLE ONLY ([\w_]+\.)?#{partitioned_table}[^;]+;/, '')
75
90
  dump.gsub!(/-- Name: #{partitioned_table} [^;]+; Type: DEFAULT/, '')
76
91
 
77
- index_regexp = /CREATE INDEX ([\w_]+) ON (public\.)?#{partitioned_table}[^;]+;/m
78
- dump.scan(index_regexp).map(&:first).each do |partitioned_table_index|
92
+ index_regexp = /CREATE (UNIQUE )?INDEX ([\w_]+) ON ([\w_]+\.)?#{partitioned_table}[^;]+;/m
93
+ dump.scan(index_regexp).each do |m|
94
+ partitioned_table_index = m[1]
79
95
  dump.gsub!("-- Name: #{partitioned_table_index}; Type: INDEX ATTACH", '')
80
96
  dump.gsub!("-- Name: #{partitioned_table_index}; Type: INDEX", '')
81
- dump.gsub!(/ALTER INDEX ([\w_\.]+) ATTACH PARTITION (public\.)?#{partitioned_table_index};/, '')
97
+ dump.gsub!(/ALTER INDEX ([\w_\.]+) ATTACH PARTITION ([\w_]+\.)?#{partitioned_table_index};/, '')
82
98
  end
83
99
  dump.gsub!(index_regexp, '')
84
100
 
85
- dump.gsub!(/-- Name: #{partitioned_table}_pkey; Type: INDEX ATTACH\n\n[^;]+?ATTACH PARTITION (public\.)?#{partitioned_table}_pkey;/, '')
101
+ dump.gsub!(/-- Name: #{partitioned_table}_pkey; Type: INDEX ATTACH\n\n[^;]+?ATTACH PARTITION ([\w_]+\.)?#{partitioned_table}_pkey;/, '')
86
102
  end
87
103
  # This is mostly done to allow restoring Postgres 11 output on Postgres 10
88
104
  dump.gsub!(/CREATE INDEX ([\w_]+) ON ONLY/, 'CREATE INDEX \\1 ON')
89
105
 
90
- # Remove whitespace between schema migration INSERTS to make editing easier
91
- dump.gsub!(/^(INSERT INTO schema_migrations .*)\n\n/, "\\1\n")
106
+ if options[:order_schema_migrations_values] == true
107
+ schema_migrations_cleanup
108
+ else
109
+ # Remove whitespace between schema migration INSERTS to make editing easier
110
+ dump.gsub!(/^(INSERT INTO schema_migrations .*)\n\n/, "\\1\n")
111
+ end
112
+
113
+ if options[:indexes_after_tables] == true
114
+ # Extract indexes, remove comments and place them just after the respective tables
115
+ indexes =
116
+ dump
117
+ .scan(/^CREATE.+INDEX.+ON.+\n/)
118
+ .group_by { |line| line.scan(/\b\w+\.\w+\b/).first }
119
+ .transform_values(&:join)
120
+
121
+ dump.gsub!(/^CREATE( UNIQUE)? INDEX \w+ ON .+\n+/, '')
122
+ dump.gsub!(/^-- Name: \w+; Type: INDEX\n+/, '')
123
+ indexes.each do |table, indexes_for_table|
124
+ dump.gsub!(/^(CREATE TABLE #{table}\b(:?[^;\n]*\n)+\);\n)/) { $1 + "\n" + indexes_for_table }
125
+ end
126
+ end
92
127
 
93
128
  # Reduce 2+ lines of whitespace to one line of whitespace
94
129
  dump.gsub!(/\n{2,}/m, "\n\n")
130
+
131
+ if options[:order_column_definitions] == true
132
+ dump.replace(order_column_definitions(dump))
133
+ end
134
+ end
135
+
136
+ def order_column_definitions(source)
137
+ result = []
138
+
139
+ parse_column_name = ->(line) { line.match(/^ "?([^" ]+)/)[1] }
140
+ with_column_separator = ->(line) { line.sub(/,?\n$/, ",\n") }
141
+ without_column_separator = ->(line) { line.sub(/,\n$/, "\n") }
142
+
143
+ inside_table = false
144
+ columns = []
145
+
146
+ source.each_line do |source_line|
147
+ if source_line.start_with?("CREATE TABLE")
148
+ inside_table = true
149
+ columns = []
150
+ result << source_line
151
+ elsif source_line.start_with?(");")
152
+ if inside_table
153
+ inside_table = false
154
+ columns.sort_by!(&:first)
155
+
156
+ columns[0..-2].each do |_, line|
157
+ result << with_column_separator[line]
158
+ end
159
+
160
+ result << without_column_separator[columns.last[1]]
161
+ end
162
+
163
+ result << source_line
164
+ elsif inside_table
165
+ columns << [parse_column_name[source_line], source_line]
166
+ else
167
+ result << source_line
168
+ end
169
+ end
170
+
171
+ result.join
172
+ end
173
+
174
+ private
175
+
176
+ # Cleanup of schema_migrations values to prevent merge conflicts:
177
+ # - sorts all values chronological
178
+ # - places the comma's in front of each value (except for the first)
179
+ # - places the semicolon on a separate last line
180
+ def schema_migrations_cleanup
181
+ # Read all schema_migrations values from the dump.
182
+ values = dump.scan(/^(\(\'\d{14}\'\))[,;]\n/).flatten.sort
183
+
184
+ # Replace the schema_migrations values.
185
+ dump.sub!(
186
+ /(?<=INSERT INTO "schema_migrations" \(version\) VALUES).+;\n*/m,
187
+ "\n #{values.join("\n,")}\n;\n\n"
188
+ )
95
189
  end
96
190
  end
97
191
  end
@@ -1,18 +1,23 @@
1
1
  require 'activerecord-clean-db-structure/clean_dump'
2
2
 
3
- Rake::Task['db:structure:dump'].enhance do
4
- filenames = ENV['DB_STRUCTURE']
3
+ Rake::Task[ActiveRecord.version >= Gem::Version.new('6.1') ? 'db:schema:dump' : 'db:structure:dump'].enhance do
4
+ filenames = []
5
+ filenames << ENV['DB_STRUCTURE'] if ENV.key?('DB_STRUCTURE')
5
6
 
6
7
  if ActiveRecord::VERSION::MAJOR >= 6
7
- ActiveRecord::Tasks::DatabaseTasks.for_each do |spec_name|
8
- filenames ||= Rails.application.config.paths['db'].map do |path|
9
- File.join(path, spec_name + '_structure.sql')
8
+ # Based on https://github.com/rails/rails/pull/36560/files
9
+ databases = ActiveRecord::Tasks::DatabaseTasks.setup_initial_database_yaml
10
+ ActiveRecord::Tasks::DatabaseTasks.for_each(databases) do |spec_name|
11
+ Rails.application.config.paths['db'].each do |path|
12
+ filenames << File.join(path, spec_name + '_structure.sql')
10
13
  end
11
14
  end
12
15
  end
13
16
 
14
- filenames ||= Rails.application.config.paths['db'].map do |path|
15
- File.join(path, 'structure.sql')
17
+ unless filenames.present?
18
+ Rails.application.config.paths['db'].each do |path|
19
+ filenames << File.join(path, 'structure.sql')
20
+ end
16
21
  end
17
22
 
18
23
  filenames.each do |filename|
@@ -1,3 +1,3 @@
1
1
  module ActiveRecordCleanDbStructure
2
- VERSION = '0.3.0'
2
+ VERSION = '0.4.1'
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: activerecord-clean-db-structure
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.4.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Lukas Fittl
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-05-07 00:00:00.000000000 Z
11
+ date: 2024-08-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -30,14 +30,14 @@ dependencies:
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '0'
33
+ version: '13'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '0'
40
+ version: '13'
41
41
  description: Never worry about weird diffs and merge conflicts again
42
42
  email: lukas@fittl.com
43
43
  executables: []
@@ -61,7 +61,7 @@ homepage: https://github.com/lfittl/activerecord-clean-db-structure
61
61
  licenses:
62
62
  - MIT
63
63
  metadata: {}
64
- post_install_message:
64
+ post_install_message:
65
65
  rdoc_options: []
66
66
  require_paths:
67
67
  - lib
@@ -76,9 +76,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
76
76
  - !ruby/object:Gem::Version
77
77
  version: '0'
78
78
  requirements: []
79
- rubyforge_project:
80
- rubygems_version: 2.6.13
81
- signing_key:
79
+ rubygems_version: 3.1.6
80
+ signing_key:
82
81
  specification_version: 4
83
82
  summary: Automatic cleanup for the Rails db/structure.sql file (ActiveRecord/PostgreSQL)
84
83
  test_files: []