Skip to content

Commit

Permalink
Merge pull request #11 from sonota88/devel_v0.0.7
Browse files Browse the repository at this point in the history
v0.0.7
  • Loading branch information
sonota88 authored Aug 11, 2018
2 parents d97bc81 + 4e7b25b commit 6db3038
Show file tree
Hide file tree
Showing 7 changed files with 288 additions and 43 deletions.
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
# 0.0.7 (2018-08-11)

No breaking changes.

## Feattues

- New configuration parameter `Rule#in_values_num`
for controlling number of values in IN clause per line.


# 0.0.6 (2018-03-31)

No breaking changes.
Expand Down
10 changes: 2 additions & 8 deletions bin/anbt-sql-formatter
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,8 @@ begin
require "anbt-sql-formatter/formatter"
rescue LoadError
$LOAD_PATH << File.expand_path(
File.join(
__FILE__,
"..",
"..",
"lib"
)
)
File.join(__FILE__, "..", "..", "lib")
)
require "anbt-sql-formatter/formatter"
end

Expand All @@ -36,7 +31,6 @@ def main
rule.function_names << func_name.upcase
}

#rule.indentString = "('-')"
rule.indent_string = " "

formatter = AnbtSql::Formatter.new(rule)
Expand Down
65 changes: 36 additions & 29 deletions lib/anbt-sql-formatter/formatter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
require "anbt-sql-formatter/rule"
require "anbt-sql-formatter/parser"
require "anbt-sql-formatter/exception"
require "anbt-sql-formatter/in_values_checker"
require "anbt-sql-formatter/helper" # Stack


Expand All @@ -16,7 +17,7 @@ class Formatter
def initialize(rule)
@rule = rule
@parser = AnbtSql::Parser.new(@rule)

# 丸カッコが関数のものかどうかを記憶
@function_bracket = Stack.new
end
Expand Down Expand Up @@ -52,7 +53,7 @@ def format(sql_str)
if sql_str.end_with?("\n")
is_sql_ends_with_new_line = true
end

tokens = @parser.parse(sql_str)

statements = split_to_statements(tokens)
Expand All @@ -74,12 +75,12 @@ def format(sql_str)
end
end


def modify_keyword_case(tokens)
# SQLキーワードは大文字とする。or ...
tokens.each{ |token|
next if token._type != AnbtSql::TokenConstants::KEYWORD

case @rule.keyword
when AnbtSql::Rule::KEYWORD_NONE
;
Expand All @@ -91,7 +92,7 @@ def modify_keyword_case(tokens)
}
end


##
# .
# ["(", "+", ")"] => ["(+)"]
Expand All @@ -101,7 +102,7 @@ def concat_operator_for_oracle(tokens)
while index < tokens.size - 2
if (tokens[index ].string == "(" &&
tokens[index + 1].string == "+" &&
tokens[index + 2].string == ")")
tokens[index + 2].string == ")")
tokens[index].string = "(+)"
ArrayUtil.remove(tokens, index + 1)
ArrayUtil.remove(tokens, index + 1)
Expand Down Expand Up @@ -142,30 +143,30 @@ def insert_space_between_tokens(tokens)
token = ArrayUtil.get(tokens, index )

if (prev._type != AnbtSql::TokenConstants::SPACE &&
token._type != AnbtSql::TokenConstants::SPACE)
token._type != AnbtSql::TokenConstants::SPACE)
# カンマの後にはスペース入れない
if not @rule.space_after_comma
if prev.string == ","
index += 1 ; next
end
end

# 関数名の後ろにはスペースは入れない
# no space after function name
if (@rule.function?(prev.string) &&
token.string == "(")
index += 1 ; next
end

ArrayUtil.add(tokens, index,
AnbtSql::Token.new(AnbtSql::TokenConstants::SPACE, " ")
)
end
index += 1
end
end


def format_list_main_loop(tokens)
# インデントを整える。
indent = 0
Expand All @@ -176,13 +177,14 @@ def format_list_main_loop(tokens)
" ")

encounter_between = false
in_values_checker = nil

index = 0
# Length of tokens changes in loop!
while index < tokens.size
token = ArrayUtil.get(tokens, index)
if token._type == AnbtSql::TokenConstants::SYMBOL # ****

if token._type == AnbtSql::TokenConstants::SYMBOL

# indentを1つ増やし、'('のあとで改行。
if token.string == "("
Expand All @@ -196,18 +198,23 @@ def format_list_main_loop(tokens)
indent = (bracket_indent.pop()).to_i
index += insert_return_and_indent(tokens, index, indent)
@function_bracket.pop()

# ','の前で改行
elsif token.string == ","
index += insert_return_and_indent(tokens, index, indent, "x")
if in_values_checker.nil? || in_values_checker.check()
index += insert_return_and_indent(tokens, index, indent, "x")
end

elsif token.string == ";"
# 2005.07.26 Tosiki Iga とりあえずセミコロンでSQL文がつぶれないように改良
indent = 0
index += insert_return_and_indent(tokens, index, indent)
end

elsif token._type == AnbtSql::TokenConstants::KEYWORD # ****

elsif token._type == AnbtSql::TokenConstants::KEYWORD
in_values_checker = nil if in_values_checker

in_values_checker = AnbtSql::InValuesChecker.new(@rule) if equals_ignore_case(token.string, "IN")

# indentを2つ増やし、キーワードの後ろで改行
if (equals_ignore_case(token.string, "DELETE") ||
Expand Down Expand Up @@ -254,7 +261,7 @@ def format_list_main_loop(tokens)
# キーワードの前で改行。indentを強制的に0にする。
if (equals_ignore_case(token.string, "UNION" ) ||
equals_ignore_case(token.string, "INTERSECT") ||
equals_ignore_case(token.string, "EXCEPT" ) )
equals_ignore_case(token.string, "EXCEPT" ) )
indent -= 2
index += insert_return_and_indent(tokens, index , indent)
index += insert_return_and_indent(tokens, index + 1, indent)
Expand All @@ -272,7 +279,7 @@ def format_list_main_loop(tokens)
encounter_between = false
end

elsif (token._type == AnbtSql::TokenConstants::COMMENT) # ****
elsif (token._type == AnbtSql::TokenConstants::COMMENT)

if token.string.start_with?("/*")
# マルチラインコメントの後に改行を入れる。
Expand All @@ -282,20 +289,20 @@ def format_list_main_loop(tokens)
end
end
prev = token

index += 1
end
end


# before: [..., "(", space, "X", space, ")", ...]
# after: [..., "(X)", ...]
# ただし、これでは "(X)" という一つの symbol トークンになってしまう。
# 整形だけが目的ならそれでも良いが、
# せっかくなので symbol/X/symbol と分けたい。
def special_treatment_for_parenthesis_with_one_element(tokens)
(tokens.size - 1).downto(4).each{|index|
next if (index >= tokens.size())
next if (index >= tokens.size())

t0 = ArrayUtil.get(tokens, index )
t1 = ArrayUtil.get(tokens, index - 1)
Expand All @@ -305,7 +312,7 @@ def special_treatment_for_parenthesis_with_one_element(tokens)

if (equals_ignore_case(t4.string , "(") &&
equals_ignore_case(t3.string.strip, "" ) &&
equals_ignore_case(t1.string.strip, "" ) &&
equals_ignore_case(t1.string.strip, "" ) &&
equals_ignore_case(t0.string , ")") )
t4.string = t4.string + t2.string + t0.string
ArrayUtil.remove(tokens, index )
Expand All @@ -316,7 +323,7 @@ def special_treatment_for_parenthesis_with_one_element(tokens)
}
end


def format_list(tokens)
return [] if tokens.empty?

Expand All @@ -328,7 +335,7 @@ def format_list(tokens)
ArrayUtil.remove(tokens, 0)
end
return [] if tokens.empty?

token = ArrayUtil.get(tokens, tokens.size() - 1)
if token._type == AnbtSql::TokenConstants::SPACE
ArrayUtil.remove(tokens, tokens.size() - 1)
Expand Down Expand Up @@ -357,11 +364,11 @@ def insert_return_and_indent(tokens, index, indent, opt=nil)
# 関数内では改行は挿入しない
# No linefeed in function.
return 0 if (@function_bracket.include?(true))

begin
# 挿入する文字列を作成する。
s = "\n"

# インデントをつける。
indent = 0 if indent < 0 ## Java版と異なる
s += @rule.indent_string * indent
Expand Down Expand Up @@ -397,6 +404,6 @@ def insert_return_and_indent(tokens, index, indent, opt=nil)
rescue => e
raise e
end
end
end
end
end
32 changes: 32 additions & 0 deletions lib/anbt-sql-formatter/in_values_checker.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
class AnbtSql
class InValuesChecker
def initialize(rule)
if rule.in_values_num.nil?
@mode = :default
elsif rule.in_values_num == AnbtSql::Rule::ONELINE_IN_VALUES_NUM
@mode = :oneline
@num = rule.in_values_num
else
@mode = :compact
@num = rule.in_values_num
@counter = 0
end
end

def check
if @mode == :default
true
elsif @mode == :oneline
false
else
@counter += 1
if @counter == @num
@counter = 0
true
else
false
end
end
end
end
end
19 changes: 14 additions & 5 deletions lib/anbt-sql-formatter/rule.rb
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,24 @@ class Rule
attr_accessor :kw_nl_x
attr_accessor :kw_nl_x_plus1_indent

# Limit number of values per line in IN clause to this value.
#
# nil:: one value per line (default)
# n (>=2):: n values per line
# ONELINE_IN_VALUES_NUM:: all values in one line
attr_accessor :in_values_num

# キーワードの変換規則: 何もしない
KEYWORD_NONE = 0

# キーワードの変換規則: 大文字にする
KEYWORD_UPPER_CASE = 1

# キーワードの変換規則: 小文字にする
KEYWORD_LOWER_CASE = 2

# IN の値を一行表示する場合の in_values_num 値
ONELINE_IN_VALUES_NUM = 0

def initialize
# キーワードの変換規則.
Expand All @@ -51,7 +60,7 @@ def initialize
@indent_string = " "

@space_after_comma = false

# __foo
# ____KW
@kw_plus1_indent_x_nl = %w(INSERT INTO CREATE DROP TRUNCATE TABLE CASE)
Expand All @@ -65,12 +74,12 @@ def initialize
# __foo
# ____KW
@kw_nl_x_plus1_indent = %w(ON USING)

# __foo
# __KW
@kw_nl_x = %w(OR THEN ELSE)
# @kw_nl_x = %w(OR WHEN ELSE)

@kw_multi_words = ["ORDER BY", "GROUP BY"]

# 関数の名前。
Expand Down Expand Up @@ -117,7 +126,7 @@ def function?(name)
return true
end
end

return false
end
end
Expand Down
2 changes: 1 addition & 1 deletion lib/anbt-sql-formatter/version.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
module Anbt
module Sql
module Formatter
VERSION = "0.0.6"
VERSION = "0.0.7"
end
end
end
Loading

0 comments on commit 6db3038

Please sign in to comment.