tsql_parser 0.1.7 → 0.1.8

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: e4dde0372fc9ba584c66ef9f7515ee506e0feb922551eb7512fb29e5e60142df
4
- data.tar.gz: 98374051fb7dc1d225eb228a36f69bfcdf3745bb3bb462f079b5cf56b3c804cb
3
+ metadata.gz: 9e811afa0fc437610f1466d197aae259f227095dfa7c2d8ebfc6022387984072
4
+ data.tar.gz: c903812e94a81e2ba40c37f514315e25b86731768af0ce3829ca95879cf98ae9
5
5
  SHA512:
6
- metadata.gz: e7d9f42e40942a2c72c127babea562f021ed46dadc806d92a0a567f84c3f915beaaa9aaccc22efebdb3a165d8920ae6b6782135e75e7d6a9c851ed7c9d02d2a9
7
- data.tar.gz: d7538fe063532844abb2d4d5f393420fe9d8b4832fe56d502a5366a22e4fa4054a93b15ac80f3ee9ec89a4f04708e20457cb993d82fc9d94830a3eb4e8d99602
6
+ metadata.gz: d6b6cd6ccaf82f4267b5028c053f98e6f0960a3a88110d9b623cc3ddc4e770392fb452e7d9fa78126071d89aa742102ecd0e1e49b7030d830c5d39cc6bb49d3a
7
+ data.tar.gz: a4ed89d5d67b03a7128a102a28edfe2b9b5b46bc115e25e83c14293314170e2cfa3f1c8e5bd182f967aad786c1aabd9d40f7f2c172e097c68a75a33d67d6b417
@@ -25,14 +25,15 @@ module TSqlParser::Parsing
25
25
  lines = TokenTransformer.transform(tokens)
26
26
  lines = self.cleanup_whitespace(lines)
27
27
  lines = self.insert_indentation(lines, tab_count, tab)
28
- #lines = self.insert_newlines(lines)
29
28
  text = lines.join("\n")
30
- text = TextFormatter.new(JOIN, text, tab).format
31
- text = TextFormatter.new(INSERT, text, tab).format
32
- text = TextFormatter.new(UPDATE, text, tab).format
33
- text = TextFormatter.new(WHERE, text, tab).format
34
- text = TextFormatter.new(SELECT, text, tab).format
35
- text = TextFormatter.new(SET, text, tab).format
29
+ text = TextFormatter.new(CTE, text, tab).format
30
+ text = TextFormatter.new(WHERE, text, tab).format if text.include? " WHERE "
31
+ text = TextFormatter.new(FROM, text, tab).format if text.include? " FROM "
32
+ text = TextFormatter.new(SELECT, text, tab).format if text.include? " SELECT "
33
+ text = TextFormatter.new(SET, text, tab).format if text.include? " SET "
34
+ text = TextFormatter.new(UPDATE, text, tab).format if text.include? " UPDATE "
35
+ text = TextFormatter.new(JOIN, text, tab).format if text.include? " JOIN "
36
+ text = TextFormatter.new(INSERT, text, tab).format if text.include? " INSERT "
36
37
  text
37
38
  end
38
39
 
@@ -26,6 +26,7 @@ module TSqlParser::Parsing
26
26
  when SET then Formatters::SetFormatter.new
27
27
  when UPDATE then Formatters::UpdateFormatter.new
28
28
  when WHERE then Formatters::WhereFormatter.new
29
+ when FROM then Formatters::FromFormatter.new
29
30
  end
30
31
  end
31
32
  end
@@ -20,6 +20,7 @@ module TSqlParser::Parsing
20
20
  require_relative "select_formatter"
21
21
  require_relative "update_formatter"
22
22
  require_relative "where_formatter"
23
+ require_relative "from_formatter"
23
24
 
24
25
  CTE = 0
25
26
  INSERT = 1
@@ -28,4 +29,5 @@ module TSqlParser::Parsing
28
29
  SET = 4
29
30
  UPDATE = 5
30
31
  WHERE = 6
32
+ FROM = 7
31
33
  end
@@ -19,6 +19,34 @@ module TSqlParser::Parsing::Formatters
19
19
 
20
20
  class CommonTableExpressionFormatter < BaseFormatter
21
21
  def format(text, tab = Defaults.get_default_tab)
22
+ formatted = []
23
+ lines = text.split("\n")
24
+ lines.each_with_index do |line, index|
25
+ clean_line = line.strip
26
+ tab_count = self.get_tab_count(line, tab)
27
+ if clean_line.include? " AS (SELECT "
28
+ if clean_line.start_with? "WITH" and clean_line.end_with? ")"
29
+ cte_parts = clean_line.split(" AS (SELECT ")
30
+ cte_name = cte_parts[0]
31
+ cte_body = "AS (\n#{tab * (tab_count + 1)}SELECT #{cte_parts[1][..-2]}\n#{tab * tab_count})"
32
+ formatted << "#{tab * tab_count}#{cte_name} #{cte_body}"
33
+ elsif clean_line.end_with? ") ,"
34
+ cte_parts = clean_line.split(" AS (SELECT ")
35
+ cte_name = cte_parts[0]
36
+ cte_body = "AS (\n#{tab * (tab_count + 1)}SELECT #{cte_parts[1].sub(") ,", "")}\n#{tab * tab_count}),"
37
+ formatted << "#{tab * tab_count}#{cte_name} #{cte_body}"
38
+ elsif clean_line.end_with? ")"
39
+ cte_parts = clean_line.split(" AS (SELECT ")
40
+ cte_name = cte_parts[0]
41
+ cte_body = "AS (\n#{tab * (tab_count + 1)}SELECT #{cte_parts[1][..-2]}\n#{tab * tab_count})"
42
+ formatted << "#{tab * tab_count}#{cte_name} #{cte_body}"
43
+ end
44
+ else
45
+ formatted << line
46
+ end
47
+ end
48
+
49
+ formatted.join("\n")
22
50
  end
23
51
  end
24
52
  end
@@ -0,0 +1,46 @@
1
+ # __ .__
2
+ # _/ |_ ___________| | ___________ _______ ______ ___________
3
+ # \ __\/ ___/ ____/ | ______ \____ \__ \\_ __ \/ ___// __ \_ __ \
4
+ # | | \___ < <_| | |__ /_____/ | |_> > __ \| | \/\___ \\ ___/| | \/
5
+ # |__| /____ >__ |____/ | __(____ /__| /____ >\___ >__|
6
+ # \/ |__| |__| \/ \/ \/
7
+ #
8
+ # A very light-weight and opinionated T-SQL parser and formatter.
9
+ #
10
+ # github.com/scstauf
11
+ #
12
+ # path:
13
+ # parsing/formatters/from_formatter.rb
14
+ # object:
15
+ # TSqlParser::Parsing::Formatters::FromFormatter
16
+
17
+ module TSqlParser::Parsing::Formatters
18
+ require_relative "base_formatter"
19
+
20
+ class FromFormatter < BaseFormatter
21
+ def format(text, tab = Defaults.get_default_tab)
22
+ formatted = []
23
+ lines = text.split("\n")
24
+ lines.each_with_index do |line, index|
25
+ if line.strip.start_with? "--" or line.strip.start_with? "/*" or line.strip.end_with? "'"
26
+ formatted << line
27
+ next
28
+ end
29
+
30
+ if line.include? " FROM " and not line.include? " EXISTS ("
31
+ tab_count = self.get_tab_count(line, tab)
32
+ if line.count(" FROM ") == 1
33
+ from_parts = line.split(" FROM ")
34
+ formatted << "#{from_parts[0]}\n#{tab * tab_count}FROM #{from_parts[1]}"
35
+ else
36
+ formatted << line[..line.index(" FROM ") - 1]
37
+ formatted << "#{tab * tab_count}#{line[line.index(" FROM ") + 1..]}"
38
+ end
39
+ else
40
+ formatted << line
41
+ end
42
+ end
43
+ formatted.join("\n")
44
+ end
45
+ end
46
+ end
@@ -24,6 +24,7 @@ module TSqlParser::Parsing::Formatters
24
24
  search = "INSERT INTO"
25
25
  lines.each do |line|
26
26
  first = line.strip.split(" ").first
27
+ next if first.nil?
27
28
  if first != "INSERT"
28
29
  formatted << line
29
30
  next
@@ -28,13 +28,17 @@ module TSqlParser::Parsing::Formatters
28
28
 
29
29
  lines.each do |line|
30
30
  first = line.strip.split(" ").first
31
- if line.include? " WHERE " and first != "WHERE" and not first.start_with? "--" and not first.start_with? "/*" and not line.strip.end_with? "'"
32
- tab_count = self.get_tab_count(line, tab)
33
- where_parts = line.strip.split(" WHERE ")
34
- where_text = []
35
- where_text << "#{tab * tab_count}#{where_parts[0]}"
36
- where_text << "#{tab * tab_count}WHERE #{where_parts[1]}"
37
- new_text << where_text.join("\n")
31
+ next if first.nil?
32
+
33
+ if first.start_with? "--" or first.start_with? "/*" or line.strip.end_with? "'"
34
+ new_text << line
35
+ next
36
+ end
37
+
38
+ tab_count = self.get_tab_count(line, tab)
39
+
40
+ if line.include? " JOIN "
41
+ new_text << self.format_joins(line, tab, tab_count)
38
42
  else
39
43
  new_text << line
40
44
  end
@@ -42,5 +46,50 @@ module TSqlParser::Parsing::Formatters
42
46
 
43
47
  new_text.join("\n")
44
48
  end
49
+
50
+ private
51
+
52
+ def format_joins(line, tab, tab_count)
53
+ formatted = []
54
+ builder = []
55
+ tokens = line.strip.split(" ")
56
+ skip_count = 0
57
+ tokens.each_with_index do |t, i|
58
+ if skip_count > 0
59
+ skip_count -= 1
60
+ next
61
+ end
62
+
63
+ last_one = tokens[i - 1] if i - 1 > 0
64
+ future_one = tokens[i + 1] if i + 1 < tokens.size
65
+ future_two = tokens[i + 2] if i + 2 < tokens.size
66
+ future_three = tokens[i + 3] if i + 3 < tokens.size
67
+
68
+ next_two = "#{future_one} #{future_two}"
69
+ next_three = "#{future_one} #{future_two} #{future_three}"
70
+
71
+ if ["INNER JOIN", "LEFT JOIN", "RIGHT JOIN", "FULL JOIN", "CROSS JOIN"].include? next_two
72
+ builder << t
73
+ formatted << "#{tab * tab_count}#{builder.join(" ")}" unless builder.empty?
74
+ builder = [next_two]
75
+ skip_count = 2
76
+ elsif ["LEFT OUTER JOIN", "RIGHT OUTER JOIN", "FULL OUTER JOIN"].include? next_three
77
+ builder << t
78
+ formatted << "#{tab * tab_count}#{builder.join(" ")}" unless builder.empty?
79
+ builder = [next_three]
80
+ skip_count = 3
81
+ elsif t == "JOIN" and (not last_one.nil? and not %w[INNER LEFT RIGHT FULL CROSS OUTER].include? last_one)
82
+ formatted << "#{tab * tab_count}#{builder.join(" ")}" unless builder.empty?
83
+ builder = [t]
84
+ else
85
+ builder << t
86
+ end
87
+ end
88
+
89
+ formatted << "#{tab * tab_count}#{builder.join(" ")}" unless builder.empty?
90
+ builder = []
91
+
92
+ formatted.join("\n")
93
+ end
45
94
  end
46
95
  end
@@ -23,6 +23,8 @@ module TSqlParser::Parsing::Formatters
23
23
  lines = text.split("\n")
24
24
  lines.each do |line|
25
25
  first = line.strip.split(" ").first
26
+ next if first.nil?
27
+
26
28
  if first != "SELECT"
27
29
  formatted << line
28
30
  next
@@ -45,8 +47,31 @@ module TSqlParser::Parsing::Formatters
45
47
  def format_select(s, tab_count = Defaults.get_default_tab_count, tab = Defaults.get_default_tab)
46
48
  return s if s.nil?
47
49
 
48
- tokens = s.split(", ")
49
- "\n#{tokens.map { |t| "#{tab * (tab_count + 1)}#{t}" }.join(",\n")}"
50
+ new_tokens = []
51
+ parenthesis = 0
52
+ builder = ""
53
+ skip_count = 0
54
+ s.split("").each do |c|
55
+ parenthesis += 1 if c == "("
56
+ parenthesis -= 1 if c == ")"
57
+
58
+ if skip_count > 0
59
+ skip_count -= 1
60
+ next
61
+ end
62
+
63
+ if c == "," and parenthesis == 0
64
+ new_tokens << builder unless builder.empty?
65
+ builder = ""
66
+ skip_count = 1
67
+ else
68
+ builder += c
69
+ end
70
+ end
71
+
72
+ new_tokens << builder unless builder.empty?
73
+
74
+ "\n#{new_tokens.map { |t| "#{tab * (tab_count + 1)}#{t}" }.join(",\n")}"
50
75
  end
51
76
  end
52
77
  end
@@ -28,6 +28,7 @@ module TSqlParser::Parsing::Formatters
28
28
  lines.each do |line|
29
29
  tokens = line.strip.split(" ")
30
30
  first = tokens.first
31
+ next if first.nil?
31
32
  next_token = tokens[1] if tokens.size > 1
32
33
 
33
34
  if %w[FROM WHERE].include? first and wait
@@ -59,7 +60,7 @@ module TSqlParser::Parsing::Formatters
59
60
  parts = line.strip.split(" SET ")
60
61
  tab_count = self.get_tab_count(line, tab)
61
62
  formatted << "#{tab * tab_count}#{parts[0]}\n"
62
- parts[1..].each { |p| formatted << "#{tab * tab_count}SET #{p}" }
63
+ parts[1..].each { |p| formatted << "#{tab * tab_count}SET #{self.format_set(p, tab_count, tab)}" }
63
64
  elsif wait
64
65
  set_lines << line
65
66
  else
@@ -23,6 +23,8 @@ module TSqlParser::Parsing::Formatters
23
23
  lines = text.split("\n")
24
24
  lines.each do |line|
25
25
  first = line.strip.split(" ").first
26
+ next if first.nil?
27
+
26
28
  if first != "UPDATE"
27
29
  formatted << line
28
30
  next
@@ -35,7 +37,7 @@ module TSqlParser::Parsing::Formatters
35
37
  formatted << line
36
38
  next
37
39
  end
38
- formatted << line.sub(update, new_update)
40
+ formatted << "#{tab * tab_count}#{line.strip.sub(update, new_update)}"
39
41
  end
40
42
  formatted.join("\n")
41
43
  end
@@ -22,19 +22,27 @@ module TSqlParser::Parsing::Formatters
22
22
  formatted = []
23
23
  text.split("\n").each do |line|
24
24
  first = line.strip.split(" ").first
25
- if first != "WHERE"
25
+ next if first.nil?
26
+ if not line.include? "WHERE"
26
27
  formatted << line
27
28
  next
28
29
  end
29
30
 
31
+ if line.strip.start_with? "--" or line.strip.start_with? "/*" or line.strip.end_with? "'"
32
+ formatted << line
33
+ next
34
+ end
35
+
36
+ where_clause = line[line.index(" WHERE ")..].strip
37
+
30
38
  tab_count = self.get_tab_count(line, tab)
31
- predicate = line.strip[first.size + 1..]
39
+ predicate = where_clause.strip["WHERE".size + 1..]
32
40
  new_predicate = self.format_predicate(predicate, tab_count, tab)
33
41
  if new_predicate.nil?
34
42
  formatted << line
35
43
  next
36
44
  end
37
- formatted << line.sub(predicate, new_predicate)
45
+ formatted << line.sub("WHERE", "").sub(predicate, "\n#{tab * tab_count}WHERE#{new_predicate}")
38
46
  end
39
47
 
40
48
  formatted.join("\n")
@@ -25,6 +25,7 @@ module TSqlParser::Parsing
25
25
 
26
26
  def basic_tokenize(tsql_string)
27
27
  self.reset
28
+ tsql_string = tsql_string.gsub("\t", Defaults.get_default_tab)
28
29
  tsql_chars = tsql_string.split("")
29
30
 
30
31
  tsql_chars.each_with_index do |c, i|
@@ -64,7 +65,7 @@ module TSqlParser::Parsing
64
65
  def handle_multicomment_start
65
66
  if Parser.is_multiline_comment_start?(@c, @next_c)
66
67
  @multiline_comment = true
67
- self.flush_builder(c)
68
+ self.flush_builder(@c)
68
69
  return true
69
70
  end
70
71
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tsql_parser
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.7
4
+ version: 0.1.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Scott Stauffer
@@ -10,8 +10,10 @@ bindir: bin
10
10
  cert_chain: []
11
11
  date: 2023-04-03 00:00:00.000000000 Z
12
12
  dependencies: []
13
- description: A very light-weight and opinionated T-SQL parser and formatter. Github
14
- has the most recent docs.
13
+ description: |-
14
+ A very light-weight and opinionated T-SQL parser and formatter.
15
+ Github has the most recent docs.
16
+ Contributions welcome!
15
17
  email: scott@fuseraft.com
16
18
  executables: []
17
19
  extensions: []
@@ -24,6 +26,7 @@ files:
24
26
  - lib/parsing/formatters/strategy/__formatters.rb
25
27
  - lib/parsing/formatters/strategy/base_formatter.rb
26
28
  - lib/parsing/formatters/strategy/cte_formatter.rb
29
+ - lib/parsing/formatters/strategy/from_formatter.rb
27
30
  - lib/parsing/formatters/strategy/insert_formatter.rb
28
31
  - lib/parsing/formatters/strategy/join_formatter.rb
29
32
  - lib/parsing/formatters/strategy/select_formatter.rb