Class: OccamsRecord::Query

Inherits:
Object
  • Object
show all
Includes:
Enumerable, Batches, EagerLoaders::Builder, Measureable
Defined in:
lib/occams-record/query.rb

Overview

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

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Measureable

#measure

Methods included from EagerLoaders::Builder

#eager_load, #eager_load_many, #eager_load_one, #nest

Methods included from Batches

#find_each, #find_in_batches

Constructor Details

#initialize(scope, use: nil, eager_loaders: nil, query_logger: nil, measurements: nil) ⇒ Query

Initialize a new query.



53
54
55
56
57
58
59
# File 'lib/occams-record/query.rb', line 53

def initialize(scope, use: nil, eager_loaders: nil, query_logger: nil, measurements: nil)
  @model = scope.klass
  @scope = scope
  @eager_loaders = eager_loaders || EagerLoaders::Context.new(@model)
  @use = use
  @query_logger, @measurements = query_logger, measurements
end

Instance Attribute Details

#modelActiveRecord::Base (readonly)



35
36
37
# File 'lib/occams-record/query.rb', line 35

def model
  @model
end

#scopeActiveRecord::Relation (readonly)



37
38
39
# File 'lib/occams-record/query.rb', line 37

def scope
  @scope
end

Instance Method Details

#countInteger

Returns the number of rows that will be returned if the query is run.



120
121
122
# File 'lib/occams-record/query.rb', line 120

def count
  scope.count
end

#each {|OccamsRecord::Results::Row| ... } ⇒ Object

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



150
151
152
153
154
155
156
# File 'lib/occams-record/query.rb', line 150

def each
  if block_given?
    to_a.each { |row| yield row }
  else
    to_a.each
  end
end

#firstOccamsRecord::Results::Row

Run the query with LIMIT 1 and return the first result (which could be nil).



129
130
131
# File 'lib/occams-record/query.rb', line 129

def first
  run { |q| q.limit 1 }.first
end

#first!OccamsRecord::Results::Row

Run the query with LIMIT 1 and return the first result. If nothing is found an OccamsRecord::NotFound exception will be raised.



139
140
141
# File 'lib/occams-record/query.rb', line 139

def first!
  first || raise(OccamsRecord::NotFound.new(model.name, scope.where_values_hash))
end

#query {|ActiveRecord::Relation| ... } ⇒ OccamsRecord::Query

Returns a new Query object with a modified scope.

Yields:

  • (ActiveRecord::Relation)

    the current scope which you may modify and return



67
68
69
70
# File 'lib/occams-record/query.rb', line 67

def query
  scope = block_given? ? yield(@scope) : @scope
  Query.new(scope, use: @use, eager_loaders: @eager_loaders, query_logger: @query_logger)
end

#run {|ActiveRecord::Relation| ... } ⇒ Array<OccamsRecord::Results::Row> Also known as: to_a

Run the query and return the results.

You may optionally pass a block to modify the query just before it’s run (the change will NOT persist). This is very useful for running paginated queries.

occams = OccamsRecord.query(Widget.all)

# returns first 100 rows
occams.run { |q| q.offset(0).limit(100) }

# returns second 100 rows
occams.run { |q| q.offset(100).limit(100) }

# returns ALL rows
occams.run

Any Enumerable method (e.g. each, to_a, map, reduce, etc.) may be used instead. Additionally, ‘find_each` and `find_in_batches` are available.

Yields:

  • (ActiveRecord::Relation)

    You may use this to return and run a modified relation



95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
# File 'lib/occams-record/query.rb', line 95

def run
  sql = block_given? ? yield(scope).to_sql : scope.to_sql
  @query_logger << sql if @query_logger
  result = if measure?
             record_start_time!
             measure!(model.table_name, sql) {
               model.connection.exec_query sql
             }
           else
             model.connection.exec_query sql
           end
  row_class = OccamsRecord::Results.klass(result.columns, result.column_types, @eager_loaders.names, model: 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