Class: Dbviewer::QueryExecutor

Inherits:
Object
  • Object
show all
Defined in:
lib/dbviewer/query_executor.rb

Overview

QueryExecutor handles executing SQL queries and formatting results

Instance Method Summary collapse

Constructor Details

#initialize(connection, config = nil) ⇒ QueryExecutor

Initialize with a connection and configuration

Parameters:

  • connection (ActiveRecord::ConnectionAdapters::AbstractAdapter)

    Database connection

  • config (Dbviewer::Configuration) (defaults to: nil)

    Configuration object



7
8
9
10
# File 'lib/dbviewer/query_executor.rb', line 7

def initialize(connection, config = nil)
  @connection = connection
  @config = config || Dbviewer.configuration
end

Instance Method Details

#execute_query(sql) ⇒ ActiveRecord::Result

Execute a raw SQL query after validating for safety

Parameters:

  • sql (String)

    SQL query to execute

Returns:

  • (ActiveRecord::Result)

    Result set with columns and rows

Raises:

  • (StandardError)

    If the query is invalid or unsafe



16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# File 'lib/dbviewer/query_executor.rb', line 16

def execute_query(sql)
  # Validate and normalize the SQL
  normalized_sql = ::Dbviewer::SqlValidator.validate!(sql.to_s)

  # Get max records from configuration
  max_records = @config.max_records || 10000

  # Add a safety limit if not already present
  unless normalized_sql =~ /\bLIMIT\s+\d+\s*$/i
    normalized_sql = "#{normalized_sql} LIMIT #{max_records}"
  end

  # Log and execute the query
  Rails.logger.debug("[DBViewer] Executing SQL query: #{normalized_sql}")
  start_time = Time.now
  result = @connection.exec_query(normalized_sql)
  duration = Time.now - start_time

  Rails.logger.debug("[DBViewer] Query completed in #{duration.round(2)}s, returned #{result.rows.size} rows")
  result
rescue => e
  Rails.logger.error("[DBViewer] SQL query error: #{e.message} for query: #{sql}")
  raise e
end

#execute_sqlite_pragma(pragma) ⇒ ActiveRecord::Result

Execute a SQLite PRAGMA command without adding a LIMIT clause

Parameters:

  • pragma (String)

    PRAGMA command to execute (without the “PRAGMA” keyword)

Returns:

  • (ActiveRecord::Result)

    Result set with the PRAGMA value

Raises:

  • (StandardError)

    If the query is invalid or cannot be executed



45
46
47
48
49
50
51
52
53
54
# File 'lib/dbviewer/query_executor.rb', line 45

def execute_sqlite_pragma(pragma)
  sql = "PRAGMA #{pragma}"
  Rails.logger.debug("[DBViewer] Executing SQLite pragma: #{sql}")
  result = @connection.exec_query(sql)
  Rails.logger.debug("[DBViewer] Pragma completed, returned #{result.rows.size} rows")
  result
rescue => e
  Rails.logger.error("[DBViewer] SQLite pragma error: #{e.message} for pragma: #{pragma}")
  raise e
end

#to_result_set(records, column_names) ⇒ ActiveRecord::Result

Convert ActiveRecord::Relation to a standard result format

Parameters:

  • records (ActiveRecord::Relation)

    Records to convert

  • column_names (Array<String>)

    Column names

Returns:

  • (ActiveRecord::Result)

    Result set with columns and rows



60
61
62
63
64
65
66
67
68
69
70
71
72
73
# File 'lib/dbviewer/query_executor.rb', line 60

def to_result_set(records, column_names)
  rows = records.map do |record|
    column_names.map do |col|
      # Handle serialized attributes
      value = record[col]
      serialize_if_needed(value)
    end
  end

  ActiveRecord::Result.new(column_names, rows)
rescue => e
  Rails.logger.error("[DBViewer] Error converting to result set: #{e.message}")
  ActiveRecord::Result.new([], [])
end