sql_beautifier 0.3.0 → 0.5.0
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 +4 -4
- data/CHANGELOG.md +8 -0
- data/lib/sql_beautifier/condition_formatter.rb +2 -1
- data/lib/sql_beautifier/create_table_as_formatter.rb +177 -0
- data/lib/sql_beautifier/cte_formatter.rb +192 -0
- data/lib/sql_beautifier/formatter.rb +6 -0
- data/lib/sql_beautifier/version.rb +1 -1
- data/lib/sql_beautifier.rb +2 -0
- metadata +3 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 74ce2777ba2e1a7635aa92623cbb6e252bef41abafa62fff7b3f9f651aad05af
|
|
4
|
+
data.tar.gz: 83f543391d4e60f2ab928eb44c6975d4f935b84c7e63bcbb05685331bcdf59a2
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 3bbfe00044b32a468fb019a9d32010ce355803000d627d6b16146398b54515531d0a6b76a84022facaec39b1afb849307b08ee96b8859b00ad99f7f2895b2668
|
|
7
|
+
data.tar.gz: 2252b3c944667589b17c0bde79e2eca176ced558c6bf8d19795607490788dc468200a00a2dedbce667adee966956389b3957f70cc39fa317d865435ceee22007
|
data/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
## [X.X.X] - YYYY-MM-DD
|
|
4
4
|
|
|
5
|
+
## [0.5.0] - 2026-03-28
|
|
6
|
+
|
|
7
|
+
- Add support for Create Table As (CTA) formatting
|
|
8
|
+
|
|
9
|
+
## [0.4.0] - 2026-03-27
|
|
10
|
+
|
|
11
|
+
- Add CTE (Common Table Expression) formatting with recursive indentation
|
|
12
|
+
|
|
5
13
|
## [0.3.0] - 2026-03-27
|
|
6
14
|
|
|
7
15
|
- Add configuration system with `SqlBeautifier.configure` block and `SqlBeautifier.reset_configuration!`
|
|
@@ -4,7 +4,8 @@ module SqlBeautifier
|
|
|
4
4
|
module ConditionFormatter
|
|
5
5
|
module_function
|
|
6
6
|
|
|
7
|
-
def format(text,
|
|
7
|
+
def format(text, args = {})
|
|
8
|
+
indent_width = args.fetch(:indent_width, 0)
|
|
8
9
|
conditions = Tokenizer.split_top_level_conditions(text)
|
|
9
10
|
return text.strip if conditions.length <= 1 && !parse_condition_group(conditions.dig(0, 1))
|
|
10
11
|
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module SqlBeautifier
|
|
4
|
+
module CreateTableAsFormatter
|
|
5
|
+
MODIFIERS = %w[
|
|
6
|
+
temp
|
|
7
|
+
temporary
|
|
8
|
+
unlogged
|
|
9
|
+
local
|
|
10
|
+
].freeze
|
|
11
|
+
|
|
12
|
+
WITH_DATA_SUFFIX_REGEX = %r{\s+(with\s+(?:no\s+)?data)\s*\z}i
|
|
13
|
+
|
|
14
|
+
module_function
|
|
15
|
+
|
|
16
|
+
def format(normalized_sql, _args = {})
|
|
17
|
+
return nil unless create_table_as_query?(normalized_sql)
|
|
18
|
+
|
|
19
|
+
parsed = parse(normalized_sql)
|
|
20
|
+
return nil unless parsed
|
|
21
|
+
|
|
22
|
+
format_statement(parsed[:preamble], parsed[:body], parsed[:suffix])
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def create_table_as_query?(sql)
|
|
26
|
+
Tokenizer.keyword_at?(sql, 0, "create")
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def parse(sql)
|
|
30
|
+
position = 0
|
|
31
|
+
return nil unless Tokenizer.keyword_at?(sql, position, "create")
|
|
32
|
+
|
|
33
|
+
position = skip_past_keyword(sql, position, "create")
|
|
34
|
+
|
|
35
|
+
modifier = detect_modifier(sql, position)
|
|
36
|
+
position = skip_past_keyword(sql, position, modifier) if modifier
|
|
37
|
+
|
|
38
|
+
return nil unless Tokenizer.keyword_at?(sql, position, "table")
|
|
39
|
+
|
|
40
|
+
position = skip_past_keyword(sql, position, "table")
|
|
41
|
+
|
|
42
|
+
if_not_exists = detect_if_not_exists?(sql, position)
|
|
43
|
+
position = skip_past_if_not_exists(sql, position) if if_not_exists
|
|
44
|
+
|
|
45
|
+
table_name, position = read_identifier(sql, position)
|
|
46
|
+
return nil unless table_name
|
|
47
|
+
|
|
48
|
+
position = skip_whitespace(sql, position)
|
|
49
|
+
return nil unless Tokenizer.keyword_at?(sql, position, "as")
|
|
50
|
+
|
|
51
|
+
position = skip_past_keyword(sql, position, "as")
|
|
52
|
+
|
|
53
|
+
result = extract_body(sql, position)
|
|
54
|
+
return nil unless result
|
|
55
|
+
|
|
56
|
+
body_sql, suffix = result
|
|
57
|
+
return nil unless body_sql
|
|
58
|
+
|
|
59
|
+
preamble = build_preamble(modifier, if_not_exists, table_name)
|
|
60
|
+
{ preamble: preamble, body: body_sql, suffix: suffix }
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def detect_modifier(sql, position)
|
|
64
|
+
MODIFIERS.detect { |modifier| Tokenizer.keyword_at?(sql, position, modifier) }
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def detect_if_not_exists?(sql, position)
|
|
68
|
+
Tokenizer.keyword_at?(sql, position, "if") && Tokenizer.keyword_at?(sql, skip_past_keyword(sql, position, "if"), "not") && Tokenizer.keyword_at?(sql, skip_past_keyword(sql, skip_past_keyword(sql, position, "if"), "not"), "exists")
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def skip_past_if_not_exists(sql, position)
|
|
72
|
+
position = skip_past_keyword(sql, position, "if")
|
|
73
|
+
position = skip_past_keyword(sql, position, "not")
|
|
74
|
+
skip_past_keyword(sql, position, "exists")
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def extract_body(sql, position)
|
|
78
|
+
position = skip_whitespace(sql, position)
|
|
79
|
+
return nil if position >= sql.length
|
|
80
|
+
|
|
81
|
+
if sql[position] == Constants::OPEN_PARENTHESIS
|
|
82
|
+
closing = Tokenizer.find_matching_parenthesis(sql, position)
|
|
83
|
+
return nil unless closing
|
|
84
|
+
|
|
85
|
+
body = sql[(position + 1)...closing].strip
|
|
86
|
+
suffix = sql[(closing + 1)..].strip.presence
|
|
87
|
+
[body, suffix]
|
|
88
|
+
else
|
|
89
|
+
extract_unparenthesized_body(sql[position..].strip)
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def extract_unparenthesized_body(raw_body)
|
|
94
|
+
return nil unless raw_body.present?
|
|
95
|
+
|
|
96
|
+
match = raw_body.match(WITH_DATA_SUFFIX_REGEX)
|
|
97
|
+
|
|
98
|
+
if match
|
|
99
|
+
body = raw_body[0...match.begin(0)].strip
|
|
100
|
+
return nil unless body.present?
|
|
101
|
+
|
|
102
|
+
[body, match[1]]
|
|
103
|
+
else
|
|
104
|
+
[raw_body, nil]
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def build_preamble(modifier, if_not_exists, table_name)
|
|
109
|
+
parts = [Util.format_keyword("create")]
|
|
110
|
+
parts << Util.format_keyword(modifier) if modifier
|
|
111
|
+
parts << Util.format_keyword("table")
|
|
112
|
+
parts << "#{Util.format_keyword('if')} #{Util.format_keyword('not')} #{Util.format_keyword('exists')}" if if_not_exists
|
|
113
|
+
parts << Util.format_table_name(table_name)
|
|
114
|
+
parts << Util.format_keyword("as")
|
|
115
|
+
parts.join(" ")
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def format_statement(preamble, body_sql, suffix)
|
|
119
|
+
indent_spaces = SqlBeautifier.config_for(:indent_spaces) || 4
|
|
120
|
+
formatted = Formatter.new(body_sql, depth: 0).call
|
|
121
|
+
return "#{preamble}\n" unless formatted
|
|
122
|
+
|
|
123
|
+
indentation = Util.whitespace(indent_spaces)
|
|
124
|
+
indented_lines = formatted.chomp.lines.map { |line| line.strip.empty? ? "\n" : "#{indentation}#{line}" }.join
|
|
125
|
+
|
|
126
|
+
formatted_suffix = suffix ? " #{format_suffix(suffix)}" : ""
|
|
127
|
+
"#{preamble} (\n#{indented_lines}\n)#{formatted_suffix}\n"
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def format_suffix(suffix)
|
|
131
|
+
suffix.strip.split(%r{\s+}).map { |word| Util.format_keyword(word) }.join(" ")
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
def read_identifier(sql, position)
|
|
135
|
+
position = skip_whitespace(sql, position)
|
|
136
|
+
return nil if position >= sql.length
|
|
137
|
+
|
|
138
|
+
if sql[position] == Constants::DOUBLE_QUOTE
|
|
139
|
+
start = position
|
|
140
|
+
position += 1
|
|
141
|
+
|
|
142
|
+
while position < sql.length
|
|
143
|
+
if sql[position] == Constants::DOUBLE_QUOTE
|
|
144
|
+
if position + 1 < sql.length && sql[position + 1] == Constants::DOUBLE_QUOTE
|
|
145
|
+
position += 2
|
|
146
|
+
next
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
position += 1
|
|
150
|
+
break
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
position += 1
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
return nil unless position <= sql.length && sql[position - 1] == Constants::DOUBLE_QUOTE
|
|
157
|
+
|
|
158
|
+
return [sql[start...position], position]
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
start = position
|
|
162
|
+
position += 1 while position < sql.length && sql[position] =~ Tokenizer::IDENTIFIER_CHARACTER
|
|
163
|
+
return nil if position == start
|
|
164
|
+
|
|
165
|
+
[sql[start...position], position]
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
def skip_whitespace(sql, position)
|
|
169
|
+
position += 1 while position < sql.length && sql[position] =~ Constants::WHITESPACE_CHARACTER_REGEX
|
|
170
|
+
position
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
def skip_past_keyword(sql, position, keyword)
|
|
174
|
+
skip_whitespace(sql, position + keyword.length)
|
|
175
|
+
end
|
|
176
|
+
end
|
|
177
|
+
end
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module SqlBeautifier
|
|
4
|
+
module CteFormatter
|
|
5
|
+
module_function
|
|
6
|
+
|
|
7
|
+
def format(normalized_sql, args = {})
|
|
8
|
+
depth = args.fetch(:depth, 0)
|
|
9
|
+
return nil unless cte_query?(normalized_sql)
|
|
10
|
+
|
|
11
|
+
recursive, definitions, main_query_sql = parse(normalized_sql)
|
|
12
|
+
return nil unless definitions.any? && main_query_sql.present?
|
|
13
|
+
|
|
14
|
+
format_cte_statement(recursive, definitions, main_query_sql, depth)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def cte_query?(sql)
|
|
18
|
+
Tokenizer.keyword_at?(sql, 0, "with")
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def parse(sql)
|
|
22
|
+
position = skip_past_keyword(sql, 0, "with")
|
|
23
|
+
|
|
24
|
+
recursive = Tokenizer.keyword_at?(sql, position, "recursive")
|
|
25
|
+
position = skip_past_keyword(sql, position, "recursive") if recursive
|
|
26
|
+
|
|
27
|
+
definitions = []
|
|
28
|
+
|
|
29
|
+
loop do
|
|
30
|
+
definition, new_position = parse_definition(sql, position)
|
|
31
|
+
break unless definition
|
|
32
|
+
|
|
33
|
+
definitions << definition
|
|
34
|
+
position = skip_whitespace(sql, new_position)
|
|
35
|
+
|
|
36
|
+
break unless position < sql.length && sql[position] == Constants::COMMA
|
|
37
|
+
|
|
38
|
+
position = skip_whitespace(sql, position + 1)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
main_query_sql = sql[position..].strip
|
|
42
|
+
|
|
43
|
+
[recursive, definitions, main_query_sql]
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def parse_definition(sql, position)
|
|
47
|
+
name, position = read_identifier(sql, position)
|
|
48
|
+
return nil unless name
|
|
49
|
+
|
|
50
|
+
position = skip_whitespace(sql, position)
|
|
51
|
+
|
|
52
|
+
column_list = parse_column_list(sql, position)
|
|
53
|
+
position = column_list[:next_position] if column_list
|
|
54
|
+
|
|
55
|
+
return nil unless Tokenizer.keyword_at?(sql, position, "as")
|
|
56
|
+
|
|
57
|
+
position = skip_past_keyword(sql, position, "as")
|
|
58
|
+
materialization, position = parse_materialization(sql, position)
|
|
59
|
+
|
|
60
|
+
return nil unless position < sql.length && sql[position] == Constants::OPEN_PARENTHESIS
|
|
61
|
+
|
|
62
|
+
closing = Tokenizer.find_matching_parenthesis(sql, position)
|
|
63
|
+
return nil unless closing
|
|
64
|
+
|
|
65
|
+
body_sql = sql[(position + 1)...closing].strip
|
|
66
|
+
definition = { name: name, body: body_sql }
|
|
67
|
+
definition[:column_list] = column_list[:text] if column_list
|
|
68
|
+
definition[:materialization] = materialization if materialization
|
|
69
|
+
|
|
70
|
+
[definition, closing + 1]
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def parse_column_list(sql, position)
|
|
74
|
+
return nil unless position < sql.length && sql[position] == Constants::OPEN_PARENTHESIS
|
|
75
|
+
|
|
76
|
+
closing = Tokenizer.find_matching_parenthesis(sql, position)
|
|
77
|
+
return nil unless closing
|
|
78
|
+
|
|
79
|
+
after_paren = skip_whitespace(sql, closing + 1)
|
|
80
|
+
return nil unless Tokenizer.keyword_at?(sql, after_paren, "as")
|
|
81
|
+
|
|
82
|
+
{ text: sql[(position + 1)...closing].strip, next_position: after_paren }
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def format_cte_statement(recursive, definitions, main_query_sql, depth)
|
|
86
|
+
keyword_width = SqlBeautifier.config_for(:keyword_column_width)
|
|
87
|
+
cte_name_column = keyword_width
|
|
88
|
+
continuation_indent = Util.continuation_padding
|
|
89
|
+
|
|
90
|
+
output = +""
|
|
91
|
+
|
|
92
|
+
definitions.each_with_index do |definition, index|
|
|
93
|
+
if index.zero?
|
|
94
|
+
output << Util.keyword_padding("with")
|
|
95
|
+
output << "#{Util.format_keyword('recursive')} " if recursive
|
|
96
|
+
else
|
|
97
|
+
output << continuation_indent
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
output << definition_header(definition)
|
|
101
|
+
output << format_body(definition[:body], cte_name_column)
|
|
102
|
+
output << (index < definitions.length - 1 ? ",\n" : "\n\n")
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
formatted_main = Formatter.new(main_query_sql, depth: depth).call
|
|
106
|
+
output << formatted_main if formatted_main
|
|
107
|
+
|
|
108
|
+
output
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def definition_header(definition)
|
|
112
|
+
header = +definition[:name].to_s
|
|
113
|
+
header << " (#{definition[:column_list]})" if definition[:column_list]
|
|
114
|
+
header << " #{Util.format_keyword('as')}"
|
|
115
|
+
header << " #{format_materialization(definition[:materialization])}" if definition[:materialization]
|
|
116
|
+
header << " "
|
|
117
|
+
header
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def parse_materialization(sql, position)
|
|
121
|
+
position = skip_whitespace(sql, position)
|
|
122
|
+
return ["materialized", skip_past_keyword(sql, position, "materialized")] if Tokenizer.keyword_at?(sql, position, "materialized")
|
|
123
|
+
return [nil, position] unless Tokenizer.keyword_at?(sql, position, "not")
|
|
124
|
+
|
|
125
|
+
materialized_position = skip_past_keyword(sql, position, "not")
|
|
126
|
+
return [nil, position] unless Tokenizer.keyword_at?(sql, materialized_position, "materialized")
|
|
127
|
+
|
|
128
|
+
["not materialized", skip_past_keyword(sql, materialized_position, "materialized")]
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def format_materialization(materialization)
|
|
132
|
+
return Util.format_keyword("materialized") if materialization == "materialized"
|
|
133
|
+
|
|
134
|
+
[Util.format_keyword("not"), Util.format_keyword("materialized")].join(" ")
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
def format_body(body_sql, base_indent)
|
|
138
|
+
indent_spaces = SqlBeautifier.config_for(:indent_spaces) || 4
|
|
139
|
+
body_indent = base_indent + indent_spaces
|
|
140
|
+
formatted = Formatter.new(body_sql, depth: 0).call
|
|
141
|
+
return "(#{body_sql})" unless formatted
|
|
142
|
+
|
|
143
|
+
indentation = Util.whitespace(body_indent)
|
|
144
|
+
indented_lines = formatted.chomp.lines.map { |line| line.strip.empty? ? "\n" : "#{indentation}#{line}" }.join
|
|
145
|
+
|
|
146
|
+
"(\n#{indented_lines}\n#{Util.whitespace(base_indent)})"
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
def read_identifier(sql, position)
|
|
150
|
+
position = skip_whitespace(sql, position)
|
|
151
|
+
return nil if position >= sql.length
|
|
152
|
+
|
|
153
|
+
if sql[position] == Constants::DOUBLE_QUOTE
|
|
154
|
+
start = position
|
|
155
|
+
position += 1
|
|
156
|
+
|
|
157
|
+
while position < sql.length
|
|
158
|
+
if sql[position] == Constants::DOUBLE_QUOTE
|
|
159
|
+
if position + 1 < sql.length && sql[position + 1] == Constants::DOUBLE_QUOTE
|
|
160
|
+
position += 2
|
|
161
|
+
next
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
position += 1
|
|
165
|
+
break
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
position += 1
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
return nil unless position <= sql.length && sql[position - 1] == Constants::DOUBLE_QUOTE
|
|
172
|
+
|
|
173
|
+
return [sql[start...position], position]
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
start = position
|
|
177
|
+
position += 1 while position < sql.length && sql[position] =~ Tokenizer::IDENTIFIER_CHARACTER
|
|
178
|
+
return nil if position == start
|
|
179
|
+
|
|
180
|
+
[sql[start...position], position]
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
def skip_whitespace(sql, position)
|
|
184
|
+
position += 1 while position < sql.length && sql[position] =~ Constants::WHITESPACE_CHARACTER_REGEX
|
|
185
|
+
position
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
def skip_past_keyword(sql, position, keyword)
|
|
189
|
+
skip_whitespace(sql, position + keyword.length)
|
|
190
|
+
end
|
|
191
|
+
end
|
|
192
|
+
end
|
|
@@ -17,6 +17,12 @@ module SqlBeautifier
|
|
|
17
17
|
@normalized_value = Normalizer.call(@value)
|
|
18
18
|
return unless @normalized_value.present?
|
|
19
19
|
|
|
20
|
+
cte_result = CteFormatter.format(@normalized_value, depth: @depth)
|
|
21
|
+
return cte_result if cte_result
|
|
22
|
+
|
|
23
|
+
create_table_as_result = CreateTableAsFormatter.format(@normalized_value, depth: @depth)
|
|
24
|
+
return create_table_as_result if create_table_as_result
|
|
25
|
+
|
|
20
26
|
first_clause_position = Tokenizer.first_clause_position(@normalized_value)
|
|
21
27
|
return "#{@normalized_value}\n" if first_clause_position.nil? || first_clause_position.positive?
|
|
22
28
|
|
data/lib/sql_beautifier.rb
CHANGED
|
@@ -12,6 +12,8 @@ require_relative "sql_beautifier/tokenizer"
|
|
|
12
12
|
require_relative "sql_beautifier/table_registry"
|
|
13
13
|
require_relative "sql_beautifier/condition_formatter"
|
|
14
14
|
require_relative "sql_beautifier/subquery_formatter"
|
|
15
|
+
require_relative "sql_beautifier/cte_formatter"
|
|
16
|
+
require_relative "sql_beautifier/create_table_as_formatter"
|
|
15
17
|
require_relative "sql_beautifier/clauses/base"
|
|
16
18
|
require_relative "sql_beautifier/clauses/condition_clause"
|
|
17
19
|
require_relative "sql_beautifier/clauses/select"
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: sql_beautifier
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.5.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Kinnell Shah
|
|
@@ -49,6 +49,8 @@ files:
|
|
|
49
49
|
- lib/sql_beautifier/condition_formatter.rb
|
|
50
50
|
- lib/sql_beautifier/configuration.rb
|
|
51
51
|
- lib/sql_beautifier/constants.rb
|
|
52
|
+
- lib/sql_beautifier/create_table_as_formatter.rb
|
|
53
|
+
- lib/sql_beautifier/cte_formatter.rb
|
|
52
54
|
- lib/sql_beautifier/formatter.rb
|
|
53
55
|
- lib/sql_beautifier/normalizer.rb
|
|
54
56
|
- lib/sql_beautifier/subquery_formatter.rb
|