Class: Mxrb::Oql::Analyzer

Inherits:
Object
  • Object
show all
Defined in:
lib/mxrb/oql/analyzer.rb

Overview

Lightweight positional analysis for OQL and SQL source. This deliberately stays independent from Translator's tokenizer: findings preserve the original fragment for editor highlighting. rubocop:disable Metrics/ClassLength

Constant Summary collapse

DIALECTS =
Translator::DIALECTS
LIKE =
/\bLIKE\s+'(?<pattern>(?:''|[^'])*)'/i
WHERE =
/\bWHERE\b(?<body>.*?)(?=\b(?:GROUP\s+BY|ORDER\s+BY|HAVING|LIMIT|OFFSET|UNION)\b|\z)/im
FUNCTION =
/\b(?:LOWER|UPPER|CAST)\s*\([^)]*\)/i
FROM =
/\bFROM\b(?<body>.*?)(?=\b(?:WHERE|GROUP\s+BY|ORDER\s+BY|HAVING|LIMIT|OFFSET|UNION)\b|\z)/im
SELECT =
/\bSELECT\b(?:\s+DISTINCT)?\s+(?<body>.*?)(?=\bFROM\b)/im
STAR =
%r{(?<!\()(?:\b[A-Za-z_][A-Za-z0-9_$]*\s*/\s*)?\*}

Instance Method Summary collapse

Constructor Details

#initialize(dialect: :postgresql) ⇒ Analyzer

Returns a new instance of Analyzer.

Raises:

  • (ArgumentError)


18
19
20
21
22
# File 'lib/mxrb/oql/analyzer.rb', line 18

def initialize(dialect: :postgresql)
  @dialect = dialect.to_sym
  raise ArgumentError, "unsupported analysis dialect #{@dialect.inspect}" \
    unless DIALECTS.include?(@dialect)
end

Instance Method Details

#analyze(query) ⇒ Object



24
25
26
27
28
29
30
31
32
33
# File 'lib/mxrb/oql/analyzer.rb', line 24

def analyze(query)
  source = query.oql.to_s
  findings = [
    *like_findings(source),
    *function_findings(source),
    *cartesian_findings(source),
    *select_star_findings(source)
  ].freeze
  AnalysisReport.new(query, findings)
end

#analyze_source(source, language: :oql) ⇒ Object



35
36
37
# File 'lib/mxrb/oql/analyzer.rb', line 35

def analyze_source(source, language: :oql)
  analyze(ad_hoc_query(source, language))
end

#analyze_sql(source) ⇒ Object



39
# File 'lib/mxrb/oql/analyzer.rb', line 39

def analyze_sql(source) = analyze_source(source, language: :sql)