activerecord-pg-format-db-structure 0.1.2 → 0.1.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +2 -11
- data/CHANGELOG.md +4 -0
- data/README.md +1 -1
- data/lib/activerecord-pg-format-db-structure/deparser.rb +41 -198
- data/lib/activerecord-pg-format-db-structure/indenter.rb +278 -0
- data/lib/activerecord-pg-format-db-structure/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9eadcc90f7e5d8ec76f9f9494e7049646bf68ed37df502df31a1dc9fae87d2b6
|
4
|
+
data.tar.gz: bee026074f768393231546155fc52e0d00098cbdec981729a63c5a8d1efeb1c4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: efe9804695f586ea988faa923d5db83483b0a0e1395bdaaaabd3dcdbd93358d96a7c5a0f7688b5bf1512d4e14d49bf68f46c65000c9700cb3ad8ef7d63094908
|
7
|
+
data.tar.gz: dbdfa7873bd2551f2c1284befbd039c194cc87aaafea7690df8daabc84724c78a06ff3f021940204aa80cdef569566b9c81bfe4cc0aa3aa6180cb7a660e0bb21
|
data/.rubocop.yml
CHANGED
@@ -15,19 +15,10 @@ Style/StringLiteralsInInterpolation:
|
|
15
15
|
Naming/FileName:
|
16
16
|
Enabled: false
|
17
17
|
|
18
|
-
|
18
|
+
Naming/VariableNumber:
|
19
19
|
Enabled: false
|
20
20
|
|
21
|
-
Metrics
|
22
|
-
Enabled: false
|
23
|
-
|
24
|
-
Metrics/AbcSize:
|
25
|
-
Enabled: false
|
26
|
-
|
27
|
-
Metrics/ClassLength:
|
28
|
-
Enabled: false
|
29
|
-
|
30
|
-
Metrics/CyclomaticComplexity:
|
21
|
+
Metrics:
|
31
22
|
Enabled: false
|
32
23
|
|
33
24
|
RSpec/SpecFilePathFormat:
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -1,245 +1,88 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "pg_query"
|
4
|
+
require_relative "indenter"
|
4
5
|
|
5
6
|
module ActiveRecordPgFormatDbStructure
|
6
7
|
# Returns a list of SQL strings from a list of PgQuery::RawStmt.
|
7
8
|
class Deparser
|
8
9
|
attr_reader :source
|
9
10
|
|
10
|
-
PRETTY_INDENT_STRING = " "
|
11
|
-
|
12
11
|
def initialize(source)
|
13
12
|
@source = source
|
14
13
|
end
|
15
14
|
|
16
15
|
def deparse_raw_statement(raw_statement)
|
17
16
|
case raw_statement.to_h
|
17
|
+
in stmt: { insert_stmt: _ }
|
18
|
+
deparse_insert_stmt(raw_statement.stmt.insert_stmt)
|
18
19
|
in stmt: { create_stmt: _ }
|
19
20
|
deparse_create_stmt(raw_statement.stmt.create_stmt)
|
20
|
-
in stmt: { index_stmt: _ }
|
21
|
-
deparse_index_stmt(raw_statement.stmt.index_stmt)
|
22
|
-
in stmt: { alter_table_stmt: _ }
|
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
21
|
in stmt: { view_stmt: _ }
|
31
22
|
deparse_view_stmt(raw_statement.stmt.view_stmt)
|
23
|
+
in stmt: { create_table_as_stmt: _ }
|
24
|
+
deparse_create_table_as_stmt(raw_statement.stmt.create_table_as_stmt)
|
25
|
+
in stmt: { index_stmt: _ }
|
26
|
+
deparse_stmt_compact(raw_statement.stmt.index_stmt)
|
32
27
|
else
|
33
|
-
|
28
|
+
deparse_stmt_generic(raw_statement.stmt.inner)
|
34
29
|
end
|
35
30
|
end
|
36
31
|
|
37
32
|
private
|
38
33
|
|
39
|
-
def
|
40
|
-
"\n
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
generic_query_str = +"\n\n"
|
45
|
-
generic_query_str << deparse_leaf_select_stmt(select_stmt)
|
46
|
-
generic_query_str << ";"
|
47
|
-
end
|
48
|
-
|
49
|
-
def deparse_index_stmt(index_stmt)
|
50
|
-
deparse_stmt(index_stmt)
|
34
|
+
def deparse_stmt_generic(stmt)
|
35
|
+
generic_str = +"\n\n"
|
36
|
+
generic_str << deparse_stmt_and_indent(stmt)
|
37
|
+
generic_str << ";"
|
38
|
+
generic_str
|
51
39
|
end
|
52
40
|
|
53
|
-
def
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
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
|
41
|
+
def deparse_stmt_compact(stmt)
|
42
|
+
compact_str = +"\n"
|
43
|
+
compact_str << deparse_stmt(stmt)
|
44
|
+
compact_str << ";"
|
45
|
+
compact_str
|
69
46
|
end
|
70
47
|
|
71
|
-
def
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
)
|
77
|
-
).gsub(/\AALTER ONLY tmp /, "")
|
48
|
+
def deparse_insert_stmt(stmt)
|
49
|
+
insert_str = +"\n\n\n"
|
50
|
+
insert_str << deparse_stmt_and_indent(stmt)
|
51
|
+
insert_str << "\n;"
|
52
|
+
insert_str
|
78
53
|
end
|
79
54
|
|
80
|
-
def deparse_create_stmt(
|
81
|
-
|
82
|
-
|
83
|
-
colname: "placeholder_column",
|
84
|
-
type_name: {
|
85
|
-
names: [PgQuery::Node.from_string("placeholder_type")]
|
86
|
-
}
|
87
|
-
)
|
88
|
-
)
|
89
|
-
|
90
|
-
table_str = "\n\n\n-- Name: #{create_stmt.relation.relname}; Type: TABLE;\n\n"
|
91
|
-
table_str << PgQuery.deparse_stmt(
|
92
|
-
PgQuery::CreateStmt.new(
|
93
|
-
**create_stmt.to_h,
|
94
|
-
table_elts: [placeholder_column]
|
95
|
-
)
|
96
|
-
)
|
55
|
+
def deparse_create_stmt(stmt)
|
56
|
+
table_str = "\n\n\n-- Name: #{stmt.relation.relname}; Type: TABLE;\n\n"
|
57
|
+
table_str << deparse_stmt_and_indent(stmt)
|
97
58
|
table_str << ";"
|
98
|
-
|
99
|
-
table_columns = create_stmt.table_elts.map do |elt|
|
100
|
-
"\n #{deparse_table_elt(elt)}"
|
101
|
-
end.join(",")
|
102
|
-
table_columns << "\n"
|
103
|
-
|
104
|
-
table_str[deparse_table_elt(placeholder_column)] = table_columns
|
105
|
-
|
106
59
|
table_str
|
107
60
|
end
|
108
61
|
|
109
|
-
def deparse_table_elt(elt)
|
110
|
-
PgQuery.deparse_stmt(
|
111
|
-
PgQuery::CreateStmt.new(
|
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
62
|
def deparse_view_stmt(stmt)
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
query: PgQuery::Node.from(placeholder_query_stmt)
|
141
|
-
)
|
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
|
63
|
+
table_str = "\n\n\n-- Name: #{stmt.view.relname}; Type: VIEW;\n\n"
|
64
|
+
table_str << deparse_stmt_and_indent(stmt)
|
65
|
+
table_str << ";"
|
66
|
+
table_str
|
179
67
|
end
|
180
68
|
|
181
|
-
def
|
182
|
-
|
183
|
-
|
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!(/ +$/, "")
|
69
|
+
def deparse_create_table_as_stmt(stmt)
|
70
|
+
table_str = "\n\n\n-- Name: #{stmt.into.rel.relname}; Type: MATERIALIZED VIEW;\n\n"
|
71
|
+
table_str << deparse_stmt_and_indent(stmt)
|
227
72
|
|
228
|
-
|
229
|
-
|
73
|
+
# couldn't find a better solution for this, but probably an OK workaround?
|
74
|
+
table_str.gsub!(/ WITH NO DATA\z/, "\nWITH NO DATA")
|
230
75
|
|
231
|
-
|
232
|
-
|
233
|
-
PgQuery::SelectStmt.new(target_list: [PgQuery::Node.from(res_target)])
|
234
|
-
).gsub(/\ASELECT /, "")
|
76
|
+
table_str << ";"
|
77
|
+
table_str
|
235
78
|
end
|
236
79
|
|
237
|
-
def
|
238
|
-
|
80
|
+
def deparse_stmt_and_indent(stmt)
|
81
|
+
Indenter.new(deparse_stmt(stmt)).indent
|
239
82
|
end
|
240
83
|
|
241
|
-
def
|
242
|
-
PgQuery.
|
84
|
+
def deparse_stmt(stmt)
|
85
|
+
PgQuery.deparse_stmt(stmt)
|
243
86
|
end
|
244
87
|
end
|
245
88
|
end
|
@@ -0,0 +1,278 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "pg_query"
|
4
|
+
|
5
|
+
module ActiveRecordPgFormatDbStructure
|
6
|
+
# Inserts newlines and whitespace on a deparsed SQL string
|
7
|
+
class Indenter
|
8
|
+
Token = Data.define(:type, :string)
|
9
|
+
|
10
|
+
# Reserved Keywords
|
11
|
+
ADD = :ADD_P
|
12
|
+
ALTER = :ALTER
|
13
|
+
AND = :AND
|
14
|
+
AS = :AS
|
15
|
+
CASE = :CASE
|
16
|
+
CREATE = :CREATE
|
17
|
+
CROSS = :CROSS
|
18
|
+
DROP = :DROP
|
19
|
+
ELSE = :ELSE
|
20
|
+
END_P = :END_P
|
21
|
+
EXCEPT = :EXCEPT
|
22
|
+
FETCH = :FETCH
|
23
|
+
FOR = :FOR
|
24
|
+
FROM = :FROM
|
25
|
+
GROUP = :GROUP_P
|
26
|
+
HAVING = :HAVING
|
27
|
+
INNER = :INNER
|
28
|
+
INSERT = :INSERT
|
29
|
+
INTERSECT = :INTERSECT
|
30
|
+
JOIN = :JOIN
|
31
|
+
LEFT = :LEFT
|
32
|
+
LIMIT = :LIMIT
|
33
|
+
OFFSET = :OFFSET
|
34
|
+
OR = :OR
|
35
|
+
ORDER = :ORDER
|
36
|
+
RIGHT = :RIGHT
|
37
|
+
SELECT = :SELECT
|
38
|
+
TABLE = :TABLE
|
39
|
+
THEN = :THEN
|
40
|
+
UNION = :UNION
|
41
|
+
VALUES = :VALUES
|
42
|
+
VIEW = :VIEW
|
43
|
+
WHEN = :WHEN
|
44
|
+
WHERE = :WHERE
|
45
|
+
WHITESPACE = :WHITESPACE
|
46
|
+
WINDOW = :WINDOW
|
47
|
+
WITH = :WITH
|
48
|
+
|
49
|
+
# ASCII tokens
|
50
|
+
COMMA = :ASCII_44
|
51
|
+
OPEN_PARENS = :ASCII_40
|
52
|
+
CLOSE_PARENS = :ASCII_41
|
53
|
+
|
54
|
+
# Helpers
|
55
|
+
PARENS = :PARENS
|
56
|
+
INDENT_STRING = " "
|
57
|
+
SELECT_PADDING = " "
|
58
|
+
TABLE_ELTS = :TABLE_ELTS
|
59
|
+
|
60
|
+
attr_reader :source
|
61
|
+
|
62
|
+
def initialize(source)
|
63
|
+
@source = PgQuery.deparse(PgQuery.parse(source).tree)
|
64
|
+
end
|
65
|
+
|
66
|
+
def indent
|
67
|
+
output = Output.new
|
68
|
+
prev_token = nil
|
69
|
+
tokens.each do |token|
|
70
|
+
output.current_token = token
|
71
|
+
case { current_token: token.type, prev_token: prev_token&.type, inside: output.current_scope_type }
|
72
|
+
in { current_token: CREATE, inside: nil }
|
73
|
+
output.append_scope(type: CREATE)
|
74
|
+
output.append_token
|
75
|
+
in { current_token: ALTER, inside: nil }
|
76
|
+
output.append_scope(type: ALTER, indent: 1)
|
77
|
+
output.append_token
|
78
|
+
in { current_token: INSERT, inside: nil }
|
79
|
+
output.append_scope(type: INSERT, indent: 0)
|
80
|
+
output.append_token
|
81
|
+
in { current_token: VIEW, inside: CREATE }
|
82
|
+
output.append_scope(type: VIEW, indent: 2)
|
83
|
+
output.append_token
|
84
|
+
in { current_token: WITH, inside: CREATE | VIEW | nil }
|
85
|
+
output.append_scope(type: WITH)
|
86
|
+
output.append_token
|
87
|
+
in { current_token: WHITESPACE, prev_token: AS, inside: VIEW }
|
88
|
+
output.append_token
|
89
|
+
output.newline
|
90
|
+
output.apply_indent
|
91
|
+
in { current_token: WHITESPACE, prev_token: COMMA, inside: WITH | SELECT | TABLE_ELTS }
|
92
|
+
output.append_token
|
93
|
+
output.newline
|
94
|
+
output.apply_indent
|
95
|
+
in { current_token: COMMA, inside: INSERT }
|
96
|
+
output.newline
|
97
|
+
output.apply_indent
|
98
|
+
output.append_token
|
99
|
+
in { current_token: SELECT, inside: WITH | INSERT }
|
100
|
+
output.pop_scope
|
101
|
+
output.newline
|
102
|
+
output.apply_indent
|
103
|
+
output.append_token
|
104
|
+
output.append_scope(type: SELECT, indent: 2, padding: SELECT_PADDING)
|
105
|
+
in { current_token: SELECT }
|
106
|
+
output.append_token
|
107
|
+
output.append_scope(type: SELECT, indent: 2, padding: SELECT_PADDING)
|
108
|
+
in { current_token: ALTER | ADD | DROP, inside: ALTER }
|
109
|
+
output.newline
|
110
|
+
output.apply_indent
|
111
|
+
output.append_token
|
112
|
+
in {
|
113
|
+
current_token: CROSS | INNER | LEFT | RIGHT | JOIN => type,
|
114
|
+
inside: SELECT | FROM | JOIN
|
115
|
+
}
|
116
|
+
output.pop_scope
|
117
|
+
output.newline
|
118
|
+
output.apply_indent
|
119
|
+
output.append_token
|
120
|
+
output.append_scope(type:, indent: 0)
|
121
|
+
in {
|
122
|
+
current_token: CROSS | INNER | LEFT | RIGHT | JOIN => type,
|
123
|
+
inside: CROSS | INNER | LEFT | RIGHT
|
124
|
+
}
|
125
|
+
output.append_token
|
126
|
+
output.pop_scope
|
127
|
+
output.append_scope(type:, indent: 0)
|
128
|
+
in {
|
129
|
+
current_token: FROM | WHERE | GROUP | ORDER | WINDOW | HAVING | LIMIT | OFFSET | FETCH | FOR | UNION |
|
130
|
+
INTERSECT | EXCEPT => token_type
|
131
|
+
}
|
132
|
+
output.pop_scope
|
133
|
+
output.newline
|
134
|
+
output.apply_indent
|
135
|
+
output.append_token
|
136
|
+
output.append_scope(type: token_type, indent: 1)
|
137
|
+
in { current_token: OR | AND, inside: WHERE }
|
138
|
+
output.newline
|
139
|
+
output.apply_indent
|
140
|
+
output.append_token(rjust: 3)
|
141
|
+
in { current_token: CASE }
|
142
|
+
output.append_token
|
143
|
+
output.append_scope(type: CASE, indent: 1, padding: output.current_padding)
|
144
|
+
in { current_token: WHEN | ELSE, inside: CASE }
|
145
|
+
output.newline
|
146
|
+
output.apply_indent
|
147
|
+
output.append_token
|
148
|
+
in { current_token: END_P }
|
149
|
+
output.pop_scope
|
150
|
+
output.newline
|
151
|
+
output.apply_indent
|
152
|
+
output.append_token
|
153
|
+
in { current_token: VALUES, inside: INSERT }
|
154
|
+
output.append_token
|
155
|
+
output.newline
|
156
|
+
output.append_whitespace
|
157
|
+
in { current_token: OPEN_PARENS, inside: CREATE }
|
158
|
+
output.append_token
|
159
|
+
output.newline
|
160
|
+
output.append_scope(type: TABLE_ELTS, indent: 2)
|
161
|
+
output.apply_indent
|
162
|
+
in { current_token: OPEN_PARENS, inside: WITH }
|
163
|
+
output.append_token
|
164
|
+
output.newline
|
165
|
+
output.append_scope(type: PARENS, indent: 2)
|
166
|
+
output.apply_indent
|
167
|
+
in { current_token: OPEN_PARENS, inside: JOIN }
|
168
|
+
output.append_token
|
169
|
+
output.newline
|
170
|
+
output.append_scope(type: PARENS, indent: 2)
|
171
|
+
output.apply_indent
|
172
|
+
in { current_token: OPEN_PARENS }
|
173
|
+
output.append_scope(type: PARENS)
|
174
|
+
output.append_token
|
175
|
+
in { current_token: CLOSE_PARENS, inside: TABLE_ELTS }
|
176
|
+
output.pop_scope
|
177
|
+
output.newline
|
178
|
+
output.apply_indent
|
179
|
+
output.append_token
|
180
|
+
in { current_token: CLOSE_PARENS, inside: PARENS }
|
181
|
+
output.pop_scope
|
182
|
+
output.append_token
|
183
|
+
in { current_token: CLOSE_PARENS }
|
184
|
+
loop do
|
185
|
+
break if output.pop_scope in PARENS | nil
|
186
|
+
end
|
187
|
+
output.newline
|
188
|
+
output.apply_indent
|
189
|
+
output.append_token
|
190
|
+
else
|
191
|
+
output.append_token
|
192
|
+
end
|
193
|
+
prev_token = token
|
194
|
+
end
|
195
|
+
output.to_s
|
196
|
+
end
|
197
|
+
|
198
|
+
private
|
199
|
+
|
200
|
+
def tokens
|
201
|
+
tmp_tokens = []
|
202
|
+
prev_token = Data.define(:end).new(0)
|
203
|
+
PgQuery.scan(source).first.tokens.each do |token|
|
204
|
+
if prev_token.end != token.start
|
205
|
+
tmp_tokens << Token.new(
|
206
|
+
type: WHITESPACE,
|
207
|
+
string: " "
|
208
|
+
)
|
209
|
+
end
|
210
|
+
prev_token = token
|
211
|
+
tmp_tokens << Token.new(
|
212
|
+
type: token.token,
|
213
|
+
string: source[token.start...token.end]
|
214
|
+
)
|
215
|
+
end
|
216
|
+
tmp_tokens
|
217
|
+
end
|
218
|
+
|
219
|
+
# Wrapper that ensures we only append whitespace, and always
|
220
|
+
# append the current token exactly once for each loop.
|
221
|
+
class Output
|
222
|
+
Scope = Data.define(:type, :indent, :padding)
|
223
|
+
|
224
|
+
def initialize
|
225
|
+
@string = +""
|
226
|
+
@scopes = [Scope.new(type: nil, indent: 0, padding: "")]
|
227
|
+
@current_token = nil
|
228
|
+
end
|
229
|
+
|
230
|
+
def to_s
|
231
|
+
# clean extra whitespace at end of string
|
232
|
+
@string.gsub(/\s+\n/, "\n").freeze
|
233
|
+
end
|
234
|
+
|
235
|
+
def current_scope_type
|
236
|
+
@scopes.last.type
|
237
|
+
end
|
238
|
+
|
239
|
+
def current_token=(token)
|
240
|
+
raise "Previous token was not appended!" unless @current_token.nil?
|
241
|
+
|
242
|
+
@current_token = token
|
243
|
+
end
|
244
|
+
|
245
|
+
def append_scope(type:, indent: 0, padding: "")
|
246
|
+
@scopes << Scope.new(type:, indent:, padding:)
|
247
|
+
end
|
248
|
+
|
249
|
+
def current_padding
|
250
|
+
@scopes.last.padding
|
251
|
+
end
|
252
|
+
|
253
|
+
def pop_scope
|
254
|
+
@scopes.pop.type
|
255
|
+
end
|
256
|
+
|
257
|
+
def newline
|
258
|
+
@string << "\n"
|
259
|
+
end
|
260
|
+
|
261
|
+
def append_whitespace
|
262
|
+
@string << " "
|
263
|
+
end
|
264
|
+
|
265
|
+
def apply_indent
|
266
|
+
@string << (INDENT_STRING * @scopes.sum(&:indent))
|
267
|
+
@string << @scopes.last.padding
|
268
|
+
end
|
269
|
+
|
270
|
+
def append_token(rjust: 0)
|
271
|
+
raise "Token was already appended!" if @current_token.nil?
|
272
|
+
|
273
|
+
@string << @current_token.string.rjust(rjust)
|
274
|
+
@current_token = nil
|
275
|
+
end
|
276
|
+
end
|
277
|
+
end
|
278
|
+
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.
|
4
|
+
version: 0.1.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jell
|
8
8
|
bindir: exe
|
9
9
|
cert_chain: []
|
10
|
-
date: 2025-
|
10
|
+
date: 2025-02-02 00:00:00.000000000 Z
|
11
11
|
dependencies:
|
12
12
|
- !ruby/object:Gem::Dependency
|
13
13
|
name: pg_query
|
@@ -41,6 +41,7 @@ files:
|
|
41
41
|
- lib/activerecord-pg-format-db-structure.rb
|
42
42
|
- lib/activerecord-pg-format-db-structure/deparser.rb
|
43
43
|
- lib/activerecord-pg-format-db-structure/formatter.rb
|
44
|
+
- lib/activerecord-pg-format-db-structure/indenter.rb
|
44
45
|
- lib/activerecord-pg-format-db-structure/preprocessors/remove_whitespaces.rb
|
45
46
|
- lib/activerecord-pg-format-db-structure/railtie.rb
|
46
47
|
- lib/activerecord-pg-format-db-structure/tasks/clean_db_structure.rake
|