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



57
58
59
# File 'lib/niceql.rb', line 57

def config
  Niceql.config
end

.prettify_err(err, original_sql_query = nil) ⇒ Object



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

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



122
123
124
125
126
127
128
129
130
# File 'lib/niceql.rb', line 122

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



86
87
88
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
# File 'lib/niceql.rb', line 86

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 = sql_start_line_num < err.lines.length ? err.lines[sql_start_line_num..-1] : original_sql_query&.lines

  # 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



118
119
120
# File 'lib/niceql.rb', line 118

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