class OccamsRecord::RawQuery

Represents a raw SQL query to be run and eager associations to be loaded. Use OccamsRecord.sql to create your queries instead of instantiating objects directly.

Attributes

binds[R]

@return [Hash]

sql[R]

@return [String]

Public Class Methods

new(sql, binds, use: nil, eager_loaders: nil, query_logger: nil, measurements: nil) click to toggle source

Initialize a new query.

@param sql [String] The SELECT statement to run. Binds should use Ruby's named string substitution. @param binds [Hash] Bind values (Symbol keys) @param use [Array<Module>] optional Module to include in the result class (single or array) @param eager_loaders [OccamsRecord::EagerLoaders::Context] @param query_logger [Array] (optional) an array into which all queries will be inserted for logging/debug purposes @param measurements [Array]

# File lib/occams-record/raw_query.rb, line 79
def initialize(sql, binds, use: nil, eager_loaders: nil, query_logger: nil, measurements: nil)
  @sql = sql
  @binds = binds
  @use = use
  @eager_loaders = eager_loaders || EagerLoaders::Context.new
  @query_logger, @measurements = query_logger, measurements
end

Public Instance Methods

each() { |row| ... } click to toggle source

If you pass a block, each result row will be yielded to it. If you don't, an Enumerable will be returned.

@yield [OccansR::Results::Row] @return [Enumerable]

# File lib/occams-record/raw_query.rb, line 134
def each
  if block_given?
    to_a.each { |row| yield row }
  else
    to_a.each
  end
end
model(klass) click to toggle source

Specify the model to be used to load eager associations. Normally this would be the main table you're SELECTing from.

NOTE Some database adapters, notably SQLite's, require that the model always be specified, even if you aren't doing eager loading.

@param klass [ActiveRecord::Base] @return [OccamsRecord::RawQuery] self

# File lib/occams-record/raw_query.rb, line 97
def model(klass)
  @eager_loaders.model = klass
  self
end
run() click to toggle source

Run the query and return the results.

@return [Array<OccamsRecord::Results::Row>]

# File lib/occams-record/raw_query.rb, line 107
def run
  _escaped_sql = escaped_sql
  @query_logger << _escaped_sql if @query_logger
  result = if measure?
             record_start_time!
             measure!(table_name, _escaped_sql) {
               conn.exec_query _escaped_sql
             }
           else
             conn.exec_query _escaped_sql
           end
  row_class = OccamsRecord::Results.klass(result.columns, result.column_types, @eager_loaders.names, model: @eager_loaders.model, modules: @use)
  rows = result.rows.map { |row| row_class.new row }
  @eager_loaders.run!(rows, query_logger: @query_logger, measurements: @measurements)
  yield_measurements!
  rows
end
Also aliased as: to_a
to_a()
Alias for: run

Private Instance Methods

batches(of:, use_transaction: true, append_order_by: nil) click to toggle source

Returns an Enumerator that yields batches of records, of size “of”. The SQL string must include 'LIMIT %{batch_limit} OFFSET %{batch_offset}'. The bind values will be provided by OccamsRecord.

@param of [Integer] batch size @param use_transaction [Boolean] Ensure it runs inside of a database transaction @return [Enumerator] yields batches

# File lib/occams-record/raw_query.rb, line 170
def batches(of:, use_transaction: true, append_order_by: nil)
  unless @sql =~ /LIMIT\s+%\{batch_limit\}/i and @sql =~ /OFFSET\s+%\{batch_offset\}/i
    raise ArgumentError, "When using find_each/find_in_batches you must specify 'LIMIT %{batch_limit} OFFSET %{batch_offset}'. SQL statement: #{@sql}"
  end

  Enumerator.new do |y|
    if use_transaction and conn.open_transactions == 0
      conn.transaction {
        run_batches y, of
      }
    else
      run_batches y, of
    end
  end
end
conn() click to toggle source
# File lib/occams-record/raw_query.rb, line 200
def conn
  @conn ||= @eager_loaders.model&.connection || ActiveRecord::Base.connection
end
escaped_sql() click to toggle source

Returns the SQL as a String with all variables escaped

# File lib/occams-record/raw_query.rb, line 145
def escaped_sql
  return sql if binds.empty?
  sql % binds.reduce({}) { |a, (col, val)|
    a[col.to_sym] = if val.is_a? Array
                      val.map { |x| conn.quote x }.join(', ')
                    else
                      conn.quote val
                    end
    a
  }
end
run_batches(y, of) click to toggle source
# File lib/occams-record/raw_query.rb, line 186
def run_batches(y, of)
  offset = 0
  loop do
    results = RawQuery.new(@sql, @binds.merge({
      batch_limit: of,
      batch_offset: offset,
    }), use: @use, query_logger: @query_logger, eager_loaders: @eager_loaders).run

    y.yield results if results.any?
    break if results.size < of
    offset += results.size
  end
end
table_name() click to toggle source
# File lib/occams-record/raw_query.rb, line 157
def table_name
  @sql.match(/\s+FROM\s+"?(\w+)"?/i)&.captures&.first
end