Module: Niceql::Prettifier

Defined in:
lib/niceql.rb

Defined Under Namespace

Classes: QueryNormalizer

Constant Summary collapse

AFTER_KEYWORD_SPACE =

?= – should be present but without being added to MatchData

'(?=\s{1})'
JOIN_KEYWORDS =
'(RIGHT\s+|LEFT\s+){0,1}(INNER\s+|OUTER\s+){0,1}JOIN(\s+LATERAL){0,1}'
INLINE_KEYWORDS =
"WITH|ASC|COALESCE|AS|WHEN|THEN|ELSE|END|AND|UNION|ALL|ON|DISTINCT|"\
"INTERSECT|EXCEPT|EXISTS|NOT|COUNT|ROUND|CAST|IN"
NEW_LINE_KEYWORDS =
"SELECT|FROM|WHERE|CASE|ORDER BY|LIMIT|GROUP BY|HAVING|OFFSET|UPDATE|SET|#{JOIN_KEYWORDS}"
POSSIBLE_INLINER =
/(ORDER BY|CASE)/
KEYWORDS =
"(#{NEW_LINE_KEYWORDS}|#{INLINE_KEYWORDS})#{AFTER_KEYWORD_SPACE}"
MULTILINE_INDENTABLE_LITERAL =

?: – will not match partial enclosed by (..)

/(?:'[^']+'\s*\n+\s*)+(?:'[^']+')+/
STRINGS =

STRINGS matched both kind of strings the multiline solid and single quoted multiline strings with s*n+s* separation

/("[^"]+")|((?:'[^']+'\s*\n+\s*)*(?:'[^']+')+)/
BRACKETS =
'[\(\)]'
SQL_COMMENTS =

will match all /* single line and multiline comments */ and – based comments the last will be matched as single block whenever comment lines followed each other. For instance: SELECT * – comment 1 – comment 2 all comments will be matched as a single block

%r{(\s*?--[^\n]+\n*)+|(\s*?/\*[^/\*]*\*/\s*)}m
COMMENT_CONTENT =
/[\S]+[\s\S]*[\S]+/
NAMED_DOLLAR_QUOTED_STRINGS_REGEX =
/[^\$](\$[^\$]+\$)[^\$]/
DOLLAR_QUOTED_STRINGS =
/(\$\$.*\$\$)/

Class Method Summary collapse

Class Method Details

.configObject



60
61
62
# File 'lib/niceql.rb', line 60

def config
  Niceql.config
end

.prettify_err(err, original_sql_query = nil) ⇒ Object



64
65
66
# File 'lib/niceql.rb', line 64

def prettify_err(err, original_sql_query = nil)
  prettify_pg_err(err.to_s, original_sql_query)
end

.prettify_multiple(sql_multi, colorize = true) ⇒ Object



129
130
131
132
133
134
135
136
137
# File 'lib/niceql.rb', line 129

def prettify_multiple(sql_multi, colorize = true)
  sql_multi.split(/(?>#{SQL_COMMENTS})|(\;)/).each_with_object([""]) do |pattern, queries|
    queries[-1] += pattern
    queries << "" if pattern == ";"
  end.map! do |sql|
    # we were splitting by comments and ';', so if next sql start with comment we've got a misplaced \n\n
    sql.match?(/\A\s+\z/) ? nil : prettify_sql(sql, colorize)
  end.compact.join("\n")
end

.prettify_pg_err(err, original_sql_query = nil) ⇒ Object

prettify_pg_err parses ActiveRecord::StatementInvalid string, but you may use it without ActiveRecord either way: prettify_pg_err( err + “n” + sql ) OR prettify_pg_err( err, sql ) don’t mess with original sql query, or prettify_pg_err will deliver incorrect results



89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
# File 'lib/niceql.rb', line 89

def prettify_pg_err(err, original_sql_query = nil)
  return err if err[/LINE \d+/].nil?

  # LINE 2: ... -> err_line_num = 2
  err_line_num = err.match(/LINE (\d+):/)[1].to_i
  # LINE 1: SELECT usr FROM users ORDER BY 1
  err_address_line = err.lines[1]

  sql_start_line_num = 3 if err.lines.length <= 3
  # error not always contains HINT
  sql_start_line_num ||= err.lines[3][/(HINT|DETAIL)/] ? 4 : 3
  sql_body_lines = if sql_start_line_num < err.lines.length
    err.lines[sql_start_line_num..-1]
  else
    original_sql_query&.lines
  end

  # this means original query is missing so it's nothing to prettify
  return err unless sql_body_lines

  # this is an SQL line with an error.
  # we need err_line to properly align the caret in the caret line
  # and to apply a full red colorizing schema on an SQL line with error
  err_line = sql_body_lines[err_line_num - 1]

  # colorizing keywords, strings and error line
  err_body = sql_body_lines.map do |ln|
    ln == err_line ? StringColorize.colorize_err(ln) : colorize_err_line(ln)
  end

  err_caret_line = extract_err_caret_line(err_address_line, err_line, sql_body_lines, err)
  err_body.insert(err_line_num, StringColorize.colorize_err(err_caret_line))

  err.lines[0..sql_start_line_num - 1].join + err_body.join
end

.prettify_sql(sql, colorize = true) ⇒ Object



125
126
127
# File 'lib/niceql.rb', line 125

def prettify_sql(sql, colorize = true)
  QueryNormalizer.new(sql, colorize).prettified_sql
end