activerecord-pg-format-db-structure 0.1.0 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: fdde773cae9c0a23f2fe42d4a1016f3498d37a616dece4e3477fc8e839869243
4
- data.tar.gz: 9d55b019c0938e3c4c6ba1f008adb542b9a156c1ab73bd50b4157a65c6bbf128
3
+ metadata.gz: 1b2d206493754a88a3913e3fb7e3532364f2adbd0dea689226d73d9544c73e98
4
+ data.tar.gz: df009fb052c07eb578b063785ee2186bfbda7ccd758643ae52285b99c784b49b
5
5
  SHA512:
6
- metadata.gz: 6ef698a4873b63ba33863576481eaa858d8363c3acbc37011b0f3c023f120a5783e572995ad3a27a1c57faaef35ba86d6eefd57207313cad0eefb1b21f33253c
7
- data.tar.gz: 142c1205e34fc069cc4a26f0957f9ca76ba142e6012914e7af06d0f47ef84700648c25339757da936b74cfe898e8f4d3b577ecff85bbcfa35cf57f39685fb2fb
6
+ metadata.gz: 9e519793dec134c227413416d750ef8be1d3da7414c921369022fc663ae4ae75b789de632e18cd1f08cfa85e719cd87a0b2ed61336db7130e01094196fcb1823
7
+ data.tar.gz: 64558806595fdecbe27035f5c22b8f3c90b56909a5a2a19b20a1fe6cf2cdbd5dac153cf5d9d860e5ee372144cea5609751b5b1f52dd41072586830a1ae93109e
data/.rubocop.yml CHANGED
@@ -24,6 +24,12 @@ Metrics/MethodLength:
24
24
  Metrics/AbcSize:
25
25
  Enabled: false
26
26
 
27
+ Metrics/ClassLength:
28
+ Enabled: false
29
+
30
+ Metrics/CyclomaticComplexity:
31
+ Enabled: false
32
+
27
33
  RSpec/SpecFilePathFormat:
28
34
  Enabled: false
29
35
 
data/CHANGELOG.md CHANGED
@@ -1,5 +1,14 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [0.1.2] - 2025-01-30
4
+
5
+ - Get rid of `anbt-sql-formatter` dependency since it breaks queries with type casting
6
+
7
+ ## [0.1.1] - 2025-01-29
8
+
9
+ - Proper deparsing of all statements
10
+ - Formatting of select and insert sub-statements using `anbt-sql-formatter`
11
+
3
12
  ## [0.1.0] - 2025-01-24
4
13
 
5
14
  - Initial release
data/README.md CHANGED
@@ -182,9 +182,9 @@ INSERT INTO "schema_migrations" (version) VALUES
182
182
  into this much more compact and normalized version:
183
183
 
184
184
  ```sql
185
- -- Name: pgcrypto; Type: EXTENSION
186
185
 
187
- CREATE EXTENSION IF NOT EXISTS pgcrypto WITH SCHEMA public;
186
+
187
+ CREATE EXTENSION IF NOT EXISTS pgcrypto SCHEMA public;
188
188
 
189
189
 
190
190
  -- Name: comments; Type: TABLE;
@@ -219,8 +219,10 @@ ALTER TABLE ONLY public.comments
219
219
  ADD CONSTRAINT fk_rails_0000000001 FOREIGN KEY (post_id) REFERENCES public.posts (id),
220
220
  ADD CONSTRAINT fk_rails_0000000002 FOREIGN KEY (user_id) REFERENCES public.users (id);
221
221
 
222
- INSERT INTO "schema_migrations" (version) VALUES
223
- ('20250124155339');
222
+
223
+ INSERT INTO schema_migrations (version) VALUES
224
+ ('20250124155339')
225
+ ;
224
226
  ```
225
227
 
226
228
  which is a lot more compact, easier to read, and reduces the risk of
@@ -334,13 +336,9 @@ Should be run after other operations that inline alter statements.
334
336
 
335
337
  ## Deparser
336
338
 
337
- As of today, this is a bare implemenation that works with the current combination of tranformers.
338
-
339
- As of now, it will only deparse `CREATE TABLE`, `CREATE INDEX` and
340
- `ALTER TABLE` statements. Other statements will be kept unchanged from
341
- the input SQL.
339
+ Returns an SQL string from raw PgQuery statements.
342
340
 
343
- In order to support all statements, we will need to find a solution to more cleanly format SQL queries, as deparsing a `CREATE VIEW` statement will result in a single unreadable line if relying on `pg_query`.
341
+ Relying mostly on `PgQuery.deparse`, and does a best effort to add some indentation where possible.
344
342
 
345
343
  ## Development
346
344
 
@@ -7,6 +7,8 @@ module ActiveRecordPgFormatDbStructure
7
7
  class Deparser
8
8
  attr_reader :source
9
9
 
10
+ PRETTY_INDENT_STRING = " "
11
+
10
12
  def initialize(source)
11
13
  @source = source
12
14
  end
@@ -19,17 +21,29 @@ module ActiveRecordPgFormatDbStructure
19
21
  deparse_index_stmt(raw_statement.stmt.index_stmt)
20
22
  in stmt: { alter_table_stmt: _ }
21
23
  deparse_alter_table_stmt(raw_statement.stmt.alter_table_stmt)
24
+ in stmt: { select_stmt: _ }
25
+ deparse_select_stmt(raw_statement.stmt.select_stmt)
26
+ in stmt: { insert_stmt: _ }
27
+ deparse_insert_statement(raw_statement.stmt.insert_stmt)
28
+ in stmt: { create_table_as_stmt: _ }
29
+ deparse_create_table_as_stmt(raw_statement.stmt.create_table_as_stmt)
30
+ in stmt: { view_stmt: _ }
31
+ deparse_view_stmt(raw_statement.stmt.view_stmt)
22
32
  else
23
- keep_original_string(raw_statement)
33
+ "\n#{deparse_stmt(raw_statement.stmt.inner)}"
24
34
  end
25
35
  end
26
36
 
27
37
  private
28
38
 
29
- def keep_original_string(raw_statement)
30
- start = raw_statement.stmt_location || 0
31
- stop = start + raw_statement.stmt_len
32
- source[start..stop]
39
+ def deparse_stmt(stmt)
40
+ "\n#{PgQuery.deparse_stmt(stmt)};"
41
+ end
42
+
43
+ def deparse_select_stmt(select_stmt)
44
+ generic_query_str = +"\n\n"
45
+ generic_query_str << deparse_leaf_select_stmt(select_stmt)
46
+ generic_query_str << ";"
33
47
  end
34
48
 
35
49
  def deparse_index_stmt(index_stmt)
@@ -37,40 +51,195 @@ module ActiveRecordPgFormatDbStructure
37
51
  end
38
52
 
39
53
  def deparse_alter_table_stmt(alter_table_stmt)
40
- "\n#{
41
- deparse_stmt(alter_table_stmt)
42
- .gsub(" ADD ", "\n ADD ")
43
- .gsub(" ALTER COLUMN ", "\n ALTER COLUMN ")
44
- }"
54
+ alter_table_str = +"\n\n"
55
+ alter_table_str << PgQuery.deparse_stmt(
56
+ PgQuery::AlterTableStmt.new(
57
+ **alter_table_stmt.to_h,
58
+ cmds: []
59
+ )
60
+ ).chomp(" ")
61
+
62
+ alter_table_cmds_str = alter_table_stmt.cmds.map do |cmd|
63
+ "\n #{deparse_alter_table_cmd(cmd)}"
64
+ end.join(",")
65
+
66
+ alter_table_str << alter_table_cmds_str
67
+ alter_table_str << ";"
68
+ alter_table_str
45
69
  end
46
70
 
47
- def deparse_stmt(stmt)
48
- "\n#{PgQuery.deparse_stmt(stmt)};"
71
+ def deparse_alter_table_cmd(cmd)
72
+ PgQuery.deparse_stmt(
73
+ PgQuery::AlterTableStmt.new(
74
+ relation: { relname: "tmp" },
75
+ cmds: [cmd]
76
+ )
77
+ ).gsub(/\AALTER ONLY tmp /, "")
49
78
  end
50
79
 
51
80
  def deparse_create_stmt(create_stmt)
81
+ placeholder_column = PgQuery::Node.from(
82
+ PgQuery::ColumnDef.new(
83
+ colname: "placeholder_column",
84
+ type_name: {
85
+ names: [PgQuery::Node.from_string("placeholder_type")]
86
+ }
87
+ )
88
+ )
89
+
52
90
  table_str = "\n\n\n-- Name: #{create_stmt.relation.relname}; Type: TABLE;\n\n"
53
91
  table_str << PgQuery.deparse_stmt(
54
92
  PgQuery::CreateStmt.new(
55
93
  **create_stmt.to_h,
56
- table_elts: []
94
+ table_elts: [placeholder_column]
57
95
  )
58
96
  )
59
- table_str.gsub!(/\(\)\z/, "")
60
- table_str << "("
61
- table_str << create_stmt.table_elts.map do |elt|
97
+ table_str << ";"
98
+
99
+ table_columns = create_stmt.table_elts.map do |elt|
62
100
  "\n #{deparse_table_elt(elt)}"
63
101
  end.join(",")
64
- table_str << "\n);"
102
+ table_columns << "\n"
103
+
104
+ table_str[deparse_table_elt(placeholder_column)] = table_columns
105
+
65
106
  table_str
66
107
  end
67
108
 
68
109
  def deparse_table_elt(elt)
69
110
  PgQuery.deparse_stmt(
70
111
  PgQuery::CreateStmt.new(
71
- relation: PgQuery::RangeVar.new(relname: "tmp"), table_elts: [elt]
112
+ relation: { relname: "tmp" }, table_elts: [elt]
113
+ )
114
+ ).gsub(/\ACREATE TABLE ONLY tmp \((.*)\)\z/, '\1')
115
+ end
116
+
117
+ def deparse_create_table_as_stmt(stmt)
118
+ create_table_as_stmt_str = +"\n\n"
119
+ create_table_as_stmt_str << PgQuery.deparse_stmt(
120
+ PgQuery::CreateTableAsStmt.new(
121
+ **stmt.to_h,
122
+ query: PgQuery::Node.from(placeholder_query_stmt)
123
+ )
124
+ )
125
+ create_table_as_stmt_str << ";"
126
+
127
+ query_str = +"(\n"
128
+ query_str << deparse_leaf_select_stmt(stmt.query.select_stmt).gsub(/^/, PRETTY_INDENT_STRING)
129
+ query_str << "\n)"
130
+
131
+ create_table_as_stmt_str[placeholder_query_string] = query_str
132
+ create_table_as_stmt_str
133
+ end
134
+
135
+ def deparse_view_stmt(stmt)
136
+ view_stmt_str = +"\n\n"
137
+ view_stmt_str << PgQuery.deparse_stmt(
138
+ PgQuery::ViewStmt.new(
139
+ **stmt.to_h,
140
+ query: PgQuery::Node.from(placeholder_query_stmt)
72
141
  )
73
- ).sub(/\ACREATE TABLE ONLY tmp \(/, "").sub(/\)\z/, "")
142
+ )
143
+ view_stmt_str << ";"
144
+
145
+ query_str = +"(\n"
146
+ query_str << deparse_leaf_select_stmt(stmt.query.select_stmt).gsub(/^/, PRETTY_INDENT_STRING)
147
+ query_str << "\n)"
148
+
149
+ view_stmt_str[placeholder_query_string] = query_str
150
+ view_stmt_str
151
+ end
152
+
153
+ def deparse_insert_statement(insert_stmt)
154
+ insert_stmt_str = +"\n\n\n"
155
+ insert_stmt_str << PgQuery.deparse_stmt(
156
+ PgQuery::InsertStmt.new(
157
+ **insert_stmt.to_h,
158
+ select_stmt: PgQuery::Node.from(placeholder_query_stmt)
159
+ )
160
+ )
161
+ insert_stmt_str << "\n;"
162
+
163
+ query_str = if insert_stmt.select_stmt.inner.values_lists.any?
164
+ deparse_values_list_select_stmt(insert_stmt.select_stmt.inner)
165
+ else
166
+ deparse_leaf_select_stmt(insert_stmt.select_stmt.inner)
167
+ end
168
+
169
+ insert_stmt_str[placeholder_query_string] = query_str
170
+ insert_stmt_str
171
+ end
172
+
173
+ def deparse_values_list_select_stmt(select_stmt)
174
+ values_str = +"VALUES\n "
175
+ values_str << select_stmt.values_lists.map do |values_list|
176
+ PgQuery.deparse_stmt(PgQuery::SelectStmt.new(values_lists: [values_list])).gsub(/\AVALUES /, "")
177
+ end.join("\n,")
178
+ values_str
179
+ end
180
+
181
+ def deparse_leaf_select_stmt(select_stmt) # rubocop:disable Metrics/PerceivedComplexity
182
+ target_list_placeholder = PgQuery::ResTarget.new(
183
+ val: { a_const: { sval: { sval: "target_list_placeholder" } } }
184
+ )
185
+
186
+ if select_stmt.with_clause
187
+ placeholder_with_clause = PgQuery::WithClause.new(
188
+ **select_stmt.with_clause.to_h,
189
+ ctes: select_stmt.with_clause.ctes.map do |cte|
190
+ PgQuery::Node.from(
191
+ PgQuery::CommonTableExpr.new(
192
+ **cte.inner.to_h,
193
+ ctequery: PgQuery::Node.from(placeholder_query_stmt("placeholder_for_#{cte.inner.ctename}_cte"))
194
+ )
195
+ )
196
+ end
197
+ )
198
+ end
199
+
200
+ select_stmt_str = PgQuery.deparse_stmt(
201
+ PgQuery::SelectStmt.new(
202
+ **select_stmt.to_h,
203
+ with_clause: placeholder_with_clause,
204
+ target_list: ([PgQuery::Node.from(target_list_placeholder)] if select_stmt.target_list.any?)
205
+ )
206
+ )
207
+
208
+ if select_stmt.target_list.any?
209
+ target_list_str = +"\n"
210
+ target_list_str << select_stmt.target_list.map do |target|
211
+ deparse_res_target(target.inner).gsub(/^/, PRETTY_INDENT_STRING)
212
+ end.join(",\n")
213
+ target_list_str << "\n"
214
+
215
+ select_stmt_str[deparse_res_target(target_list_placeholder)] = target_list_str
216
+ end
217
+
218
+ select_stmt.with_clause&.ctes&.each do |cte|
219
+ cte_str = +"\n"
220
+ cte_str << deparse_leaf_select_stmt(cte.inner.ctequery.inner).gsub(/^/, PRETTY_INDENT_STRING)
221
+ cte_str << "\n"
222
+
223
+ select_stmt_str["SELECT placeholder_for_#{cte.inner.ctename}_cte"] = cte_str
224
+ end
225
+
226
+ select_stmt_str.gsub!(/ +$/, "")
227
+
228
+ select_stmt_str
229
+ end
230
+
231
+ def deparse_res_target(res_target)
232
+ PgQuery.deparse_stmt(
233
+ PgQuery::SelectStmt.new(target_list: [PgQuery::Node.from(res_target)])
234
+ ).gsub(/\ASELECT /, "")
235
+ end
236
+
237
+ def placeholder_query_string(placeholder_name = "placeholder")
238
+ PgQuery.deparse_stmt(placeholder_query_stmt(placeholder_name))
239
+ end
240
+
241
+ def placeholder_query_stmt(placeholder_name = "placeholder")
242
+ PgQuery.parse("SELECT #{placeholder_name}").tree.stmts.first.stmt.select_stmt
74
243
  end
75
244
  end
76
245
  end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "pg_query"
4
+
5
+ module ActiveRecordPgFormatDbStructure
6
+ module Transforms
7
+ # :nodoc:
8
+ class Base
9
+ attr_reader :raw_statements
10
+
11
+ def initialize(raw_statements)
12
+ @raw_statements = raw_statements
13
+ end
14
+ end
15
+ end
16
+ end
@@ -1,18 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "pg_query"
3
+ require_relative "base"
4
4
 
5
5
  module ActiveRecordPgFormatDbStructure
6
6
  module Transforms
7
7
  # Group alter table statements into one operation per
8
8
  # table. Should be run after other operations that inline alter statements.
9
- class GroupAlterTableStatements
10
- attr_reader :raw_statements
11
-
12
- def initialize(raw_statements)
13
- @raw_statements = raw_statements
14
- end
15
-
9
+ class GroupAlterTableStatements < Base
16
10
  def transform!
17
11
  alter_groups = extract_alter_table_statements!
18
12
 
@@ -1,27 +1,20 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "pg_query"
3
+ require_relative "base"
4
4
 
5
5
  module ActiveRecordPgFormatDbStructure
6
6
  module Transforms
7
7
  # Inline non-foreign key constraints into table declaration
8
- class InlineConstraints
9
- attr_reader :raw_statements
10
-
11
- def initialize(raw_statements)
12
- @raw_statements = raw_statements
13
- @tables_with_constraint = {}
14
- end
15
-
8
+ class InlineConstraints < Base
16
9
  def transform!
17
- extract_constraints_to_inline!
10
+ tables_with_constraint = extract_constraints_to_inline!
18
11
  raw_statements.each do |raw_statement|
19
12
  next unless raw_statement.stmt.to_h in create_stmt: { relation: { schemaname:, relname: }}
20
13
 
21
14
  relation = { schemaname:, relname: }
22
- next unless @tables_with_constraint.include?(relation)
15
+ next unless tables_with_constraint.include?(relation)
23
16
 
24
- @tables_with_constraint[relation].each do |constraint|
17
+ tables_with_constraint[relation].each do |constraint|
25
18
  add_constraint!(raw_statement, constraint)
26
19
  end
27
20
  end
@@ -30,14 +23,16 @@ module ActiveRecordPgFormatDbStructure
30
23
  private
31
24
 
32
25
  def extract_constraints_to_inline!
26
+ tables_with_constraint = {}
33
27
  raw_statements.delete_if do |raw_statement|
34
28
  next unless match_alter_column_statement(raw_statement) in { table:, constraint: }
35
29
 
36
- @tables_with_constraint[table] ||= []
37
- @tables_with_constraint[table] << constraint
30
+ tables_with_constraint[table] ||= []
31
+ tables_with_constraint[table] << constraint
38
32
 
39
33
  true
40
34
  end
35
+ tables_with_constraint
41
36
  end
42
37
 
43
38
  def match_alter_column_statement(raw_statement)
@@ -68,8 +63,8 @@ module ActiveRecordPgFormatDbStructure
68
63
  end
69
64
 
70
65
  def add_constraint!(raw_statement, constraint)
71
- raw_statement.stmt.create_stmt.table_elts << PgQuery::Node.new(
72
- constraint: PgQuery::Constraint.new(constraint)
66
+ raw_statement.stmt.create_stmt.table_elts << PgQuery::Node.from(
67
+ PgQuery::Constraint.new(constraint)
73
68
  )
74
69
  end
75
70
  end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "pg_query"
3
+ require_relative "base"
4
4
 
5
5
  module ActiveRecordPgFormatDbStructure
6
6
  module Transforms
@@ -9,23 +9,16 @@ module ActiveRecordPgFormatDbStructure
9
9
  # Note: using this transform makes the structure file no longer
10
10
  # loadable, since tables should be created before a foreign key
11
11
  # can target it.
12
- class InlineForeignKeys
13
- attr_reader :raw_statements
14
-
15
- def initialize(raw_statements)
16
- @raw_statements = raw_statements
17
- @columns_with_foreign_key = {}
18
- end
19
-
12
+ class InlineForeignKeys < Base
20
13
  def transform!
21
- extract_foreign_keys_to_inline!
14
+ columns_with_foreign_key = extract_foreign_keys_to_inline!
22
15
  raw_statements.each do |raw_statement|
23
16
  next unless raw_statement.stmt.to_h in create_stmt: { relation: { schemaname:, relname: }}
24
17
 
25
18
  relation = { schemaname:, relname: }
26
- next unless @columns_with_foreign_key.include?(relation)
19
+ next unless columns_with_foreign_key.include?(relation)
27
20
 
28
- @columns_with_foreign_key[relation].each do |column_name, constraint|
21
+ columns_with_foreign_key[relation].each do |column_name, constraint|
29
22
  add_constraint!(raw_statement, column_name, constraint)
30
23
  end
31
24
  end
@@ -34,15 +27,17 @@ module ActiveRecordPgFormatDbStructure
34
27
  private
35
28
 
36
29
  def extract_foreign_keys_to_inline!
30
+ columns_with_foreign_key = {}
37
31
  raw_statements.delete_if do |raw_statement|
38
32
  next unless match_alter_column_statement(raw_statement) in { column:, constraint: }
39
33
 
40
34
  table = column.except(:colname)
41
- @columns_with_foreign_key[table] ||= {}
42
- @columns_with_foreign_key[table][column[:colname]] = constraint
35
+ columns_with_foreign_key[table] ||= {}
36
+ columns_with_foreign_key[table][column[:colname]] = constraint
43
37
 
44
38
  true
45
39
  end
40
+ columns_with_foreign_key
46
41
  end
47
42
 
48
43
  def match_alter_column_statement(raw_statement)
@@ -99,8 +94,8 @@ module ActiveRecordPgFormatDbStructure
99
94
  raw_statement.stmt.create_stmt.table_elts.each do |table_elt|
100
95
  next unless table_elt.to_h in { column_def: { colname: ^colname } }
101
96
 
102
- table_elt.column_def.constraints << PgQuery::Node.new(
103
- constraint: PgQuery::Constraint.new(constraint)
97
+ table_elt.column_def.constraints << PgQuery::Node.from(
98
+ PgQuery::Constraint.new(constraint)
104
99
  )
105
100
  end
106
101
  end
@@ -1,25 +1,18 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "pg_query"
3
+ require_relative "base"
4
4
 
5
5
  module ActiveRecordPgFormatDbStructure
6
6
  module Transforms
7
7
  # Inlines primary keys with the table declaration
8
- class InlinePrimaryKeys
9
- attr_reader :raw_statements
10
-
11
- def initialize(raw_statements)
12
- @raw_statements = raw_statements
13
- @columns_with_primary_key = {}
14
- end
15
-
8
+ class InlinePrimaryKeys < Base
16
9
  def transform!
17
- extract_primary_keys_to_inline!
10
+ columns_with_primary_key = extract_primary_keys_to_inline!
18
11
  raw_statements.each do |raw_statement|
19
12
  next unless raw_statement.stmt.to_h in create_stmt: { relation: { schemaname:, relname: }}
20
13
 
21
14
  relation = { schemaname:, relname: }
22
- primary_key = @columns_with_primary_key[relation]
15
+ primary_key = columns_with_primary_key[relation]
23
16
  add_primary_key!(raw_statement, primary_key) if primary_key
24
17
  end
25
18
  end
@@ -27,15 +20,17 @@ module ActiveRecordPgFormatDbStructure
27
20
  private
28
21
 
29
22
  def extract_primary_keys_to_inline!
23
+ columns_with_primary_key = {}
30
24
  raw_statements.delete_if do |raw_statement|
31
25
  next unless match_alter_column_statement(raw_statement) in { schemaname:, relname:, colname: }
32
26
 
33
27
  column = { schemaname:, relname:, colname: }
34
28
  table = column.except(:colname)
35
- @columns_with_primary_key[table] = column[:colname]
29
+ columns_with_primary_key[table] = column[:colname]
36
30
 
37
31
  true
38
32
  end
33
+ columns_with_primary_key
39
34
  end
40
35
 
41
36
  def match_alter_column_statement(raw_statement)
@@ -73,10 +68,8 @@ module ActiveRecordPgFormatDbStructure
73
68
  c.to_h in { constraint: { contype: :CONSTR_NOTNULL } }
74
69
  end
75
70
 
76
- table_elt.column_def.constraints << PgQuery::Node.new(
77
- constraint: PgQuery::Constraint.new(
78
- contype: :CONSTR_PRIMARY
79
- )
71
+ table_elt.column_def.constraints << PgQuery::Node.from(
72
+ PgQuery::Constraint.new(contype: :CONSTR_PRIMARY)
80
73
  )
81
74
  end
82
75
  end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "pg_query"
3
+ require_relative "base"
4
4
 
5
5
  module ActiveRecordPgFormatDbStructure
6
6
  module Transforms
@@ -13,25 +13,17 @@ module ActiveRecordPgFormatDbStructure
13
13
  # It also assumes that the associated sequence has default settings. A
14
14
  # later version could try to be more strict / validate that the
15
15
  # sequence indeed has default settings.
16
- class InlineSerials
17
- attr_reader :raw_statements
18
-
19
- def initialize(raw_statements)
20
- @raw_statements = raw_statements
21
- @columns_to_replace_with_serial = {}
22
- @sequences_to_remove = Set.new
23
- end
24
-
16
+ class InlineSerials < Base
25
17
  def transform!
26
- extract_serials_to_inline!
27
- delete_redundant_statements!
18
+ extract_serials_to_inline! => columns_to_replace_with_serial:, sequences_to_remove:
19
+ delete_redundant_statements!(sequences_to_remove)
28
20
  raw_statements.each do |raw_statement|
29
21
  next unless raw_statement.stmt.to_h in create_stmt: { relation: { schemaname:, relname: }}
30
22
 
31
23
  relation = { schemaname:, relname: }
32
- next unless @columns_to_replace_with_serial.include?(relation)
24
+ next unless columns_to_replace_with_serial.include?(relation)
33
25
 
34
- @columns_to_replace_with_serial[relation].each do |colname|
26
+ columns_to_replace_with_serial[relation].each do |colname|
35
27
  replace_id_with_serial!(raw_statement, colname)
36
28
  end
37
29
  end
@@ -40,16 +32,19 @@ module ActiveRecordPgFormatDbStructure
40
32
  private
41
33
 
42
34
  def extract_serials_to_inline!
35
+ columns_to_replace_with_serial = {}
36
+ sequences_to_remove = Set.new
43
37
  raw_statements.delete_if do |raw_statement|
44
38
  next unless match_alter_column_statement(raw_statement) in { column:, sequence: }
45
39
 
46
40
  table = column.except(:column_name)
47
- @columns_to_replace_with_serial[table] ||= []
48
- @columns_to_replace_with_serial[table] << column[:column_name]
49
- @sequences_to_remove << sequence
41
+ columns_to_replace_with_serial[table] ||= []
42
+ columns_to_replace_with_serial[table] << column[:column_name]
43
+ sequences_to_remove << sequence
50
44
 
51
45
  true
52
46
  end
47
+ { columns_to_replace_with_serial:, sequences_to_remove: }
53
48
  end
54
49
 
55
50
  def match_alter_column_statement(raw_statement)
@@ -107,21 +102,21 @@ module ActiveRecordPgFormatDbStructure
107
102
 
108
103
  table_elt.column_def.type_name = PgQuery::TypeName.new(
109
104
  names: [
110
- PgQuery::Node.new(string: PgQuery::String.new(
111
- sval: COLUMN_TYPE_TO_SERIAL_TYPE.fetch(integer_type)
112
- ))
105
+ PgQuery::Node.from_string(
106
+ COLUMN_TYPE_TO_SERIAL_TYPE.fetch(integer_type)
107
+ )
113
108
  ]
114
109
  )
115
110
  end
116
111
  end
117
112
 
118
- def delete_redundant_statements!
113
+ def delete_redundant_statements!(sequences_to_remove)
119
114
  raw_statements.delete_if do |raw_statement|
120
115
  case raw_statement.stmt.to_h
121
116
  in create_seq_stmt: { sequence: { schemaname:, relname: }}
122
- @sequences_to_remove.include?({ schemaname:, relname: })
117
+ sequences_to_remove.include?({ schemaname:, relname: })
123
118
  in alter_seq_stmt: {sequence: { schemaname:, relname: }}
124
- @sequences_to_remove.include?({ schemaname:, relname: })
119
+ sequences_to_remove.include?({ schemaname:, relname: })
125
120
  else
126
121
  false
127
122
  end
@@ -1,17 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "pg_query"
3
+ require_relative "base"
4
4
 
5
5
  module ActiveRecordPgFormatDbStructure
6
6
  module Transforms
7
7
  # Move indice declaration just below the table they index
8
- class MoveIndicesAfterCreateTable
9
- attr_reader :raw_statements
10
-
11
- def initialize(raw_statements)
12
- @raw_statements = raw_statements
13
- end
14
-
8
+ class MoveIndicesAfterCreateTable < Base
15
9
  def transform!
16
10
  extract_table_indices!.each do |table, indices|
17
11
  insert_index = find_insert_index(**table)
@@ -1,17 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "pg_query"
3
+ require_relative "base"
4
4
 
5
5
  module ActiveRecordPgFormatDbStructure
6
6
  module Transforms
7
7
  # Remove COMMENT statement applied to extensions
8
- class RemoveCommentsOnExtensions
9
- attr_reader :raw_statements
10
-
11
- def initialize(raw_statements)
12
- @raw_statements = raw_statements
13
- end
14
-
8
+ class RemoveCommentsOnExtensions < Base
15
9
  def transform!
16
10
  raw_statements.delete_if do |raw_statement|
17
11
  raw_statement.stmt.to_h in {
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ActiveRecordPgFormatDbStructure
4
- VERSION = "0.1.0"
4
+ VERSION = "0.1.2"
5
5
  end
metadata CHANGED
@@ -1,13 +1,13 @@
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.0
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jell
8
8
  bindir: exe
9
9
  cert_chain: []
10
- date: 2025-01-26 00:00:00.000000000 Z
10
+ date: 2025-01-30 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: pg_query
@@ -44,6 +44,7 @@ files:
44
44
  - lib/activerecord-pg-format-db-structure/preprocessors/remove_whitespaces.rb
45
45
  - lib/activerecord-pg-format-db-structure/railtie.rb
46
46
  - lib/activerecord-pg-format-db-structure/tasks/clean_db_structure.rake
47
+ - lib/activerecord-pg-format-db-structure/transforms/base.rb
47
48
  - lib/activerecord-pg-format-db-structure/transforms/group_alter_table_statements.rb
48
49
  - lib/activerecord-pg-format-db-structure/transforms/inline_constraints.rb
49
50
  - lib/activerecord-pg-format-db-structure/transforms/inline_foreign_keys.rb