class Dynamoid::Criteria::Chain

The criteria chain is equivalent to an ActiveRecord relation (and realistically I should change the name from chain to relation). It is a chainable object that builds up a query and eventually executes it by a Query or Scan.

Attributes

consistent_read[RW]
query[RW]
source[RW]
values[RW]

Public Class Methods

new(source) click to toggle source

Create a new criteria chain.

@param [Class] source the class upon which the ultimate query will be performed.

# File lib/dynamoid/criteria/chain.rb, line 14
def initialize(source)
  @query = {}
  @source = source
  @consistent_read = false
  @scan_index_forward = true
end

Public Instance Methods

all() click to toggle source

Returns all the records matching the criteria.

@since 0.2.0

# File lib/dynamoid/criteria/chain.rb, line 45
def all
  records
end
batch(batch_size) click to toggle source
# File lib/dynamoid/criteria/chain.rb, line 76
def batch(batch_size)
  @batch_size = batch_size
  self
end
consistent() click to toggle source
# File lib/dynamoid/criteria/chain.rb, line 37
def consistent
  @consistent_read = true
  self
end
consistent_opts() click to toggle source
# File lib/dynamoid/criteria/chain.rb, line 98
def consistent_opts
  { :consistent_read => consistent_read }
end
destroy_all() click to toggle source

Destroys all the records matching the criteria.

# File lib/dynamoid/criteria/chain.rb, line 51
def destroy_all
  ids = []

  if key_present?
    ranges = []
    Dynamoid.adapter.query(source.table_name, range_query).collect do |hash|
      ids << hash[source.hash_key.to_sym]
      ranges << hash[source.range_key.to_sym]
    end

    Dynamoid.adapter.delete(source.table_name, ids,{:range_key => ranges})
  else
    Dynamoid.adapter.scan(source.table_name, query, scan_opts).collect do |hash|
      ids << hash[source.hash_key.to_sym]
    end

    Dynamoid.adapter.delete(source.table_name, ids)
  end
end
each(&block) click to toggle source

Allows you to use the results of a search as an enumerable over the results found.

@since 0.2.0

# File lib/dynamoid/criteria/chain.rb, line 94
def each(&block)
  records.each(&block)
end
eval_limit(limit) click to toggle source
# File lib/dynamoid/criteria/chain.rb, line 71
def eval_limit(limit)
  @eval_limit = limit
  self
end
scan_index_forward(scan_index_forward) click to toggle source
# File lib/dynamoid/criteria/chain.rb, line 86
def scan_index_forward(scan_index_forward)
  @scan_index_forward = scan_index_forward
  self
end
start(start) click to toggle source
# File lib/dynamoid/criteria/chain.rb, line 81
def start(start)
  @start = start
  self
end
where(args) click to toggle source

The workhorse method of the criteria chain. Each key in the passed in hash will become another criteria that the ultimate query must match. A key can either be a symbol or a string, and should be an attribute name or an attribute name with a range operator.

@example A simple criteria

where(:name => 'Josh')

@example A more complicated criteria

where(:name => 'Josh', 'created_at.gt' => DateTime.now - 1.day)

@since 0.2.0

# File lib/dynamoid/criteria/chain.rb, line 32
def where(args)
  args.each {|k, v| query[k.to_sym] = v}
  self
end

Private Instance Methods

key_present?() click to toggle source
hash_key

or [hash_key, range_key] is specified in query keys.

# File lib/dynamoid/criteria/chain.rb, line 182
def key_present?
  query_keys == [source.hash_key.to_s] || (query_keys.to_set == [source.hash_key.to_s, source.range_key.to_s].to_set)
end
query_keys() click to toggle source
# File lib/dynamoid/criteria/chain.rb, line 177
def query_keys
  query.keys.collect{|k| k.to_s.split('.').first}
end
query_opts() click to toggle source
# File lib/dynamoid/criteria/chain.rb, line 194
def query_opts
  opts = {}
  opts[:select] = 'ALL_ATTRIBUTES'
  opts[:limit] = @eval_limit if @eval_limit
  opts[:next_token] = start_key if @start
  opts[:scan_index_forward] = @scan_index_forward
  opts
end
range_hash(key) click to toggle source
# File lib/dynamoid/criteria/chain.rb, line 148
def range_hash(key)
  val = query[key]

  return { :range_value => query[key] } if query[key].is_a?(Range)

  case key.to_s.split('.').last
  when 'gt'
    { :range_greater_than => val }
  when 'lt'
    { :range_less_than  => val }
  when 'gte'
    { :range_gte  => val }
  when 'lte'
    { :range_lte => val }
  when 'between'
    { :range_between => val }
  when 'begins_with'
    { :range_begins_with => val }
  end
end
range_query() click to toggle source
# File lib/dynamoid/criteria/chain.rb, line 169
def range_query
  opts = { :hash_value => query[source.hash_key] }
  query.keys.select { |k| k.to_s.include?('.') }.each do |key|
    opts.merge!(range_hash(key))
  end
  opts.merge(query_opts).merge(consistent_opts)
end
records() click to toggle source

The actual records referenced by the association.

@return [Enumerator] an iterator of the found records.

@since 0.2.0

# File lib/dynamoid/criteria/chain.rb, line 109
def records
  results = if key_present?
    records_via_query
  else
    records_via_scan
  end
  @batch_size ? results : Array(results)
end
records_via_query() click to toggle source
# File lib/dynamoid/criteria/chain.rb, line 118
def records_via_query
  Enumerator.new do |yielder|
    Dynamoid.adapter.query(source.table_name, range_query).each do |hash|
      yielder.yield source.from_database(hash)
    end
  end
end
records_via_scan() click to toggle source

If the query does not match an index, we’ll manually scan the associated table to find results.

@return [Enumerator] an iterator of the found records.

@since 0.2.0

# File lib/dynamoid/criteria/chain.rb, line 131
def records_via_scan
  if Dynamoid::Config.warn_on_scan
    Dynamoid.logger.warn 'Queries without an index are forced to use scan and are generally much slower than indexed queries!'
    Dynamoid.logger.warn "You can index this query by adding this to #{source.to_s.downcase}.rb: index [#{source.attributes.sort.collect{|attr| ":#{attr}"}.join(', ')}]"
  end

  if @consistent_read
    raise Dynamoid::Errors::InvalidQuery, 'Consistent read is not supported by SCAN operation'
  end

  Enumerator.new do |yielder|
    Dynamoid.adapter.scan(source.table_name, query, scan_opts).each do |hash|
      yielder.yield source.from_database(hash)
    end
  end
end
scan_opts() click to toggle source
# File lib/dynamoid/criteria/chain.rb, line 203
def scan_opts
  opts = {}
  opts[:limit] = @eval_limit if @eval_limit
  opts[:next_token] = start_key if @start
  opts[:batch_size] = @batch_size if @batch_size
  opts
end
start_key() click to toggle source
# File lib/dynamoid/criteria/chain.rb, line 186
def start_key
  key = { :hash_key_element => @start.hash_key }
  if range_key = @start.class.range_key
    key.merge!({:range_key_element => @start.send(range_key) })
  end
  key
end