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

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