Class: SqlGenius::Core::QueryRunner

Inherits:
Object
  • Object
show all
Defined in:
lib/sql_genius/core/query_runner.rb,
lib/sql_genius/core/query_runner/config.rb

Overview

Forward declaration so Config can be namespaced under QueryRunner. The full QueryRunner class is defined in query_runner.rb.

Defined Under Namespace

Classes: Config, Rejected, Timeout

Constant Summary collapse

TIMEOUT_PATTERNS =
[
  "max_statement_time",
  "max_execution_time",
  "Query execution was interrupted",
  "canceling statement due to statement timeout",
].freeze

Instance Method Summary collapse

Constructor Details

#initialize(connection, config) ⇒ QueryRunner

Returns a new instance of QueryRunner.



32
33
34
35
# File 'lib/sql_genius/core/query_runner.rb', line 32

def initialize(connection, config)
  @connection = connection
  @config = config
end

Instance Method Details

#run(sql, row_limit:) ⇒ Object

Raises:



37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
# File 'lib/sql_genius/core/query_runner.rb', line 37

def run(sql, row_limit:)
  validation_error = SqlValidator.validate(
    sql,
    blocked_tables: @config.blocked_tables,
    connection: @connection,
  )
  raise Rejected, validation_error if validation_error

  normalized = SqlValidator.normalize_identifier_quotes(sql, @connection)
  limited = SqlValidator.apply_row_limit(normalized, row_limit)

  start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
  result = with_timeout do
    @connection.exec_query(apply_timeout_hint(limited))
  end
  duration_ms = ((Process.clock_gettime(Process::CLOCK_MONOTONIC) - start) * 1000).round(1)

  masked_rows = mask_rows(result)

  ExecutionResult.new(
    columns: result.columns,
    rows: masked_rows,
    execution_time_ms: duration_ms,
    truncated: masked_rows.length >= row_limit,
  )
end