tsql_parser 0.1.6 → 0.1.8

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: d67275fb1f5b1ff478b0e8a79d99af69a2d33b53059822e882b6a0c94e68d0a1
4
- data.tar.gz: 50b27357c58d8c0ca89b069ddef3a03e4565b1e354a7e322d79c9ba64440895d
3
+ metadata.gz: 9e811afa0fc437610f1466d197aae259f227095dfa7c2d8ebfc6022387984072
4
+ data.tar.gz: c903812e94a81e2ba40c37f514315e25b86731768af0ce3829ca95879cf98ae9
5
5
  SHA512:
6
- metadata.gz: dd4314846a33bd5b4c0e99dd41ecb67c65494faf015fc5ec81ffcf74cd5f98c52215bc28fd1a8729e0a1694ad7a055b09f51b724b0d7f27ae945a3ed2f778d13
7
- data.tar.gz: 664dce679b765bf73e229f5cafc4eb0059f540c85674d4b6d41f1e3508e7536d512c457b64075d6c0f12b70bf7d3bfabdf4887466894beceec4182f444a5b986
6
+ metadata.gz: d6b6cd6ccaf82f4267b5028c053f98e6f0960a3a88110d9b623cc3ddc4e770392fb452e7d9fa78126071d89aa742102ecd0e1e49b7030d830c5d39cc6bb49d3a
7
+ data.tar.gz: a4ed89d5d67b03a7128a102a28edfe2b9b5b46bc115e25e83c14293314170e2cfa3f1c8e5bd182f967aad786c1aabd9d40f7f2c172e097c68a75a33d67d6b417
@@ -25,15 +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
36
- puts text
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 "
37
37
  text
38
38
  end
39
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.6
4
+ version: 0.1.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Scott Stauffer
@@ -10,7 +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.
13
+ description: |-
14
+ A very light-weight and opinionated T-SQL parser and formatter.
15
+ Github has the most recent docs.
16
+ Contributions welcome!
14
17
  email: scott@fuseraft.com
15
18
  executables: []
16
19
  extensions: []
@@ -23,6 +26,7 @@ files:
23
26
  - lib/parsing/formatters/strategy/__formatters.rb
24
27
  - lib/parsing/formatters/strategy/base_formatter.rb
25
28
  - lib/parsing/formatters/strategy/cte_formatter.rb
29
+ - lib/parsing/formatters/strategy/from_formatter.rb
26
30
  - lib/parsing/formatters/strategy/insert_formatter.rb
27
31
  - lib/parsing/formatters/strategy/join_formatter.rb
28
32
  - lib/parsing/formatters/strategy/select_formatter.rb