activerecord-pg-format-db-structure 0.1.4 → 0.1.5
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
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 231e1ce74a64d5b68e27b122465855bf382cb24c5f573da3983b2ab1e11b3c23
|
4
|
+
data.tar.gz: 3341fb271ea14d6762cb879f28b6b526d51a76c37c83163fe26ce2955d9b1b83
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2f06ac5c8140c6766f4dd77909ba62f60fb2b86b2453d4fad3eb190221de590025eb079e6c2e74999ff3e39fcf90dcac8b1751d52fa33bf9a33ec26ea9c05b91
|
7
|
+
data.tar.gz: 790f40bbc56b3b0062e72b7793a9c1645ea286f9a3f557f180aea1fc261dc52401ef721ee2320901cf2ec30d1dc6b763eb0662d30906ab6e351e0b4ab33b1377
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -1,4 +1,7 @@
|
|
1
1
|
# activerecord-pg-format-db-structure
|
2
|
+
[](https://rubygems.org/gems/activerecord-pg-format-db-structure)
|
3
|
+

|
4
|
+
|
2
5
|
|
3
6
|
Automatically cleans up your `structure.sql` file after each rails migration.
|
4
7
|
|
@@ -9,6 +12,8 @@ By default, it will:
|
|
9
12
|
* Inline table constraints
|
10
13
|
* Move index creation below their corresponding tables
|
11
14
|
* Group `ALTER TABLE` statements into a single statement per table
|
15
|
+
* Sorts table column declarations (primary key / foreign keys / data / timestamp / constraints)
|
16
|
+
* Sorts `schema_migrations` inserts
|
12
17
|
* Removes unnecessary whitespace
|
13
18
|
|
14
19
|
The task will transform this raw `structure.sql`:
|
@@ -265,7 +270,8 @@ Rails.application.configure do
|
|
265
270
|
ActiveRecordPgFormatDbStructure::Transforms::InlineSerials,
|
266
271
|
ActiveRecordPgFormatDbStructure::Transforms::InlineConstraints,
|
267
272
|
ActiveRecordPgFormatDbStructure::Transforms::MoveIndicesAfterCreateTable,
|
268
|
-
ActiveRecordPgFormatDbStructure::Transforms::GroupAlterTableStatements
|
273
|
+
ActiveRecordPgFormatDbStructure::Transforms::GroupAlterTableStatements,
|
274
|
+
ActiveRecordPgFormatDbStructure::Transforms::SortTableColumns,
|
269
275
|
]
|
270
276
|
|
271
277
|
config.activerecord_pg_format_db_structure.deparser = ActiveRecordPgFormatDbStructure::Deparser
|
@@ -339,6 +345,49 @@ table.
|
|
339
345
|
|
340
346
|
Should be run after other operations that inline alter statements.
|
341
347
|
|
348
|
+
### SortTableColumns
|
349
|
+
|
350
|
+
Sort table columns, by order of priority and alphabetically:
|
351
|
+
|
352
|
+
1. primary key
|
353
|
+
2. foreign keys
|
354
|
+
3. generic columns
|
355
|
+
4. timestamps
|
356
|
+
5. constraints
|
357
|
+
|
358
|
+
Note that you can define your own ordering by replacing the default `priority_mapping`:
|
359
|
+
|
360
|
+
```ruby
|
361
|
+
ActiveRecordPgFormatDbStructure::Transforms::SortTableColumns.priority_mapping = lambda do |sortable_entry|
|
362
|
+
case sortable_entry
|
363
|
+
in is_column: true, is_primary_key: true, name:
|
364
|
+
[0, name]
|
365
|
+
in is_column: true, is_foreign_key: true, name:
|
366
|
+
[1, name]
|
367
|
+
in is_column: true, is_timestamp: false, name:
|
368
|
+
[2, name]
|
369
|
+
in is_column: true, is_timestamp: true, name:
|
370
|
+
[3, name]
|
371
|
+
in is_constraint: true, name:
|
372
|
+
[5, name]
|
373
|
+
end
|
374
|
+
end
|
375
|
+
```
|
376
|
+
|
377
|
+
where `sortable_entry` is an instance of:
|
378
|
+
|
379
|
+
```ruby
|
380
|
+
SORTABLE_ENTRY = Data.define(
|
381
|
+
:name,
|
382
|
+
:is_column,
|
383
|
+
:is_constraint,
|
384
|
+
:is_primary_key,
|
385
|
+
:is_foreign_key,
|
386
|
+
:is_timestamp,
|
387
|
+
:raw_entry
|
388
|
+
)
|
389
|
+
```
|
390
|
+
|
342
391
|
## Deparser
|
343
392
|
|
344
393
|
Returns an SQL string from raw PgQuery statements.
|
@@ -0,0 +1,220 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "base"
|
4
|
+
|
5
|
+
module ActiveRecordPgFormatDbStructure
|
6
|
+
module Transforms
|
7
|
+
# Sort table columns
|
8
|
+
class SortTableColumns < Base
|
9
|
+
SORTABLE_ENTRY = Data.define(
|
10
|
+
:name,
|
11
|
+
:is_column,
|
12
|
+
:is_constraint,
|
13
|
+
:is_primary_key,
|
14
|
+
:is_foreign_key,
|
15
|
+
:is_timestamp,
|
16
|
+
:raw_entry
|
17
|
+
)
|
18
|
+
|
19
|
+
class << self
|
20
|
+
attr_accessor :priority_mapping
|
21
|
+
end
|
22
|
+
|
23
|
+
self.priority_mapping = lambda do |sortable_entry|
|
24
|
+
case sortable_entry
|
25
|
+
in is_column: true, is_primary_key: true, name:
|
26
|
+
[0, name]
|
27
|
+
in is_column: true, is_foreign_key: true, name:
|
28
|
+
[1, name]
|
29
|
+
in is_column: true, is_timestamp: false, name:
|
30
|
+
[2, name]
|
31
|
+
in is_column: true, is_timestamp: true, name:
|
32
|
+
[3, name]
|
33
|
+
in is_constraint: true, name:
|
34
|
+
[5, name]
|
35
|
+
# :nocov:
|
36
|
+
# non-reachable else
|
37
|
+
# :nocov:
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def transform!
|
42
|
+
foreign_keys = extract_foreign_keys
|
43
|
+
primary_keys = extract_primary_keys
|
44
|
+
raw_statements.each do |raw_statement|
|
45
|
+
next unless raw_statement.stmt.to_h in create_stmt: { relation: { schemaname:, relname: } }
|
46
|
+
|
47
|
+
raw_statement.stmt.create_stmt.table_elts.sort_by! do |table_elt|
|
48
|
+
elt_priority(
|
49
|
+
table_elt:,
|
50
|
+
primary_keys: primary_keys.fetch({ schemaname:, relname: }, Set.new),
|
51
|
+
foreign_keys: foreign_keys.fetch({ schemaname:, relname: }, Set.new)
|
52
|
+
)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
private
|
58
|
+
|
59
|
+
def extract_primary_keys
|
60
|
+
primary_keys = {}
|
61
|
+
raw_statements.each do |raw_statement|
|
62
|
+
case raw_statement.stmt.to_h
|
63
|
+
in alter_table_stmt: {
|
64
|
+
objtype: :OBJECT_TABLE,
|
65
|
+
relation: {
|
66
|
+
schemaname:,
|
67
|
+
relname:
|
68
|
+
}
|
69
|
+
}
|
70
|
+
primary_keys[{ schemaname:, relname: }] ||= Set.new
|
71
|
+
raw_statement.stmt.alter_table_stmt.cmds.each do |cmd|
|
72
|
+
extract_primary_keys_from_alter_table_cmd(cmd:).each do |key|
|
73
|
+
primary_keys[{ schemaname:, relname: }] << key
|
74
|
+
end
|
75
|
+
end
|
76
|
+
in create_stmt: { relation: { schemaname:, relname: } }
|
77
|
+
primary_keys[{ schemaname:, relname: }] ||= Set.new
|
78
|
+
raw_statement.stmt.create_stmt.table_elts.each do |table_elt|
|
79
|
+
extract_primary_keys_from_table_elt(table_elt:).each do |key|
|
80
|
+
primary_keys[{ schemaname:, relname: }] << key
|
81
|
+
end
|
82
|
+
end
|
83
|
+
else
|
84
|
+
end
|
85
|
+
end
|
86
|
+
primary_keys
|
87
|
+
end
|
88
|
+
|
89
|
+
def extract_primary_keys_from_alter_table_cmd(cmd:)
|
90
|
+
if cmd.to_h in {
|
91
|
+
alter_table_cmd: {
|
92
|
+
subtype: :AT_AddConstraint,
|
93
|
+
def: {
|
94
|
+
constraint: {
|
95
|
+
contype: :CONSTR_PRIMARY
|
96
|
+
}
|
97
|
+
}
|
98
|
+
}
|
99
|
+
}
|
100
|
+
cmd.alter_table_cmd.def.constraint.keys.map do |key|
|
101
|
+
key.string.sval
|
102
|
+
end
|
103
|
+
else
|
104
|
+
[]
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def extract_primary_keys_from_table_elt(table_elt:)
|
109
|
+
case table_elt.to_h
|
110
|
+
in column_def: { constraints: [*, {constraint: {contype: :CONSTR_PRIMARY}}, *] }
|
111
|
+
[table_elt.column_def.colname]
|
112
|
+
in constraint: { contype: :CONSTR_PRIMARY }
|
113
|
+
table_elt.constraint.keys.map do |key|
|
114
|
+
key.string.sval
|
115
|
+
end
|
116
|
+
else
|
117
|
+
[]
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
def extract_foreign_keys
|
122
|
+
foreign_keys = {}
|
123
|
+
raw_statements.each do |raw_statement|
|
124
|
+
case raw_statement.stmt.to_h
|
125
|
+
in alter_table_stmt: {
|
126
|
+
objtype: :OBJECT_TABLE,
|
127
|
+
relation: {
|
128
|
+
schemaname:,
|
129
|
+
relname:
|
130
|
+
}
|
131
|
+
}
|
132
|
+
foreign_keys[{ schemaname:, relname: }] ||= Set.new
|
133
|
+
raw_statement.stmt.alter_table_stmt.cmds.each do |cmd|
|
134
|
+
extract_foreign_keys_from_alter_table_cmd(cmd:).each do |key|
|
135
|
+
foreign_keys[{ schemaname:, relname: }] << key
|
136
|
+
end
|
137
|
+
end
|
138
|
+
in create_stmt: { relation: { schemaname:, relname: } }
|
139
|
+
foreign_keys[{ schemaname:, relname: }] ||= Set.new
|
140
|
+
raw_statement.stmt.create_stmt.table_elts.each do |table_elt|
|
141
|
+
extract_foreign_keys_from_table_elt(table_elt:).each do |key|
|
142
|
+
foreign_keys[{ schemaname:, relname: }] << key
|
143
|
+
end
|
144
|
+
end
|
145
|
+
else
|
146
|
+
end
|
147
|
+
end
|
148
|
+
foreign_keys
|
149
|
+
end
|
150
|
+
|
151
|
+
def extract_foreign_keys_from_alter_table_cmd(cmd:)
|
152
|
+
if cmd.to_h in {
|
153
|
+
alter_table_cmd: {
|
154
|
+
subtype: :AT_AddConstraint,
|
155
|
+
def: {
|
156
|
+
constraint: {
|
157
|
+
contype: :CONSTR_FOREIGN
|
158
|
+
}
|
159
|
+
}
|
160
|
+
}
|
161
|
+
}
|
162
|
+
cmd.alter_table_cmd.def.constraint.fk_attrs.map do |fk_attr|
|
163
|
+
fk_attr.string.sval
|
164
|
+
end
|
165
|
+
else
|
166
|
+
[]
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
def extract_foreign_keys_from_table_elt(table_elt:)
|
171
|
+
case table_elt.to_h
|
172
|
+
in column_def: { constraints: [*, {constraint: {contype: :CONSTR_FOREIGN}}, *] }
|
173
|
+
[table_elt.column_def.colname]
|
174
|
+
in constraint: { contype: :CONSTR_FOREIGN }
|
175
|
+
table_elt.constraint.fk_attrs.map do |fk_attr|
|
176
|
+
fk_attr.string.sval
|
177
|
+
end
|
178
|
+
else
|
179
|
+
[]
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
def elt_priority(table_elt:, primary_keys:, foreign_keys:)
|
184
|
+
case table_elt.to_h
|
185
|
+
in column_def: _
|
186
|
+
self.class.priority_mapping[
|
187
|
+
SORTABLE_ENTRY.new(
|
188
|
+
name: table_elt.column_def.colname,
|
189
|
+
is_column: true,
|
190
|
+
is_constraint: false,
|
191
|
+
is_primary_key: primary_keys.include?(table_elt.column_def.colname),
|
192
|
+
is_timestamp: timestamp?(table_elt.column_def),
|
193
|
+
is_foreign_key: foreign_keys.include?(table_elt.column_def.colname),
|
194
|
+
raw_entry: table_elt
|
195
|
+
)
|
196
|
+
]
|
197
|
+
in constraint: _
|
198
|
+
self.class.priority_mapping[
|
199
|
+
SORTABLE_ENTRY.new(
|
200
|
+
name: table_elt.constraint.conname,
|
201
|
+
is_column: false,
|
202
|
+
is_constraint: true,
|
203
|
+
is_primary_key: false,
|
204
|
+
is_timestamp: false,
|
205
|
+
is_foreign_key: false,
|
206
|
+
raw_entry: table_elt
|
207
|
+
)
|
208
|
+
]
|
209
|
+
# :nocov:
|
210
|
+
# non-reachable else
|
211
|
+
# :nocov:
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
def timestamp?(table_elt)
|
216
|
+
table_elt.type_name.names.any? { |name| name.to_h in string: { sval: "timestamp" } }
|
217
|
+
end
|
218
|
+
end
|
219
|
+
end
|
220
|
+
end
|
@@ -12,6 +12,7 @@ require_relative "activerecord-pg-format-db-structure/transforms/move_indices_af
|
|
12
12
|
require_relative "activerecord-pg-format-db-structure/transforms/inline_constraints"
|
13
13
|
require_relative "activerecord-pg-format-db-structure/transforms/group_alter_table_statements"
|
14
14
|
require_relative "activerecord-pg-format-db-structure/transforms/sort_schema_migrations"
|
15
|
+
require_relative "activerecord-pg-format-db-structure/transforms/sort_table_columns"
|
15
16
|
|
16
17
|
module ActiveRecordPgFormatDbStructure
|
17
18
|
DEFAULT_PREPROCESSORS = [
|
@@ -26,7 +27,8 @@ module ActiveRecordPgFormatDbStructure
|
|
26
27
|
Transforms::InlineSerials,
|
27
28
|
Transforms::InlineConstraints,
|
28
29
|
Transforms::MoveIndicesAfterCreateTable,
|
29
|
-
Transforms::GroupAlterTableStatements
|
30
|
+
Transforms::GroupAlterTableStatements,
|
31
|
+
Transforms::SortTableColumns
|
30
32
|
].freeze
|
31
33
|
|
32
34
|
DEFAULT_DEPARSER = Deparser
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: activerecord-pg-format-db-structure
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jell
|
@@ -54,6 +54,7 @@ files:
|
|
54
54
|
- lib/activerecord-pg-format-db-structure/transforms/move_indices_after_create_table.rb
|
55
55
|
- lib/activerecord-pg-format-db-structure/transforms/remove_comments_on_extensions.rb
|
56
56
|
- lib/activerecord-pg-format-db-structure/transforms/sort_schema_migrations.rb
|
57
|
+
- lib/activerecord-pg-format-db-structure/transforms/sort_table_columns.rb
|
57
58
|
- lib/activerecord-pg-format-db-structure/version.rb
|
58
59
|
homepage: https://github.com/ReifyAB/activerecord-pg-format-db-structure
|
59
60
|
licenses:
|