module DatastaxRails::FinderMethods

Relation methods to locate a single record either by PK or set of values.

Public Instance Methods

find(*args) { |*block_args| ... } click to toggle source

Find operates with four different retrieval approaches:

  • Find by id - This can either be a specific id (1), a list of ids (1, 5, 6), or an array of ids ([5, 6, 10]). If no record can be found for all of the listed ids, then RecordNotFound will be raised.

  • Find first - This will return the first record matched by the options used. These options can either be specific conditions or merely an order. If no record can be matched, nil is returned. Use Model.find(:first, *args) or its shortcut Model.first(*args).

  • Find last - This will return the last record matched by the options used. These options can either be specific conditions or merely an order. If no record can be matched, nil is returned. Use Model.find(:last, *args) or its shortcut Model.last(*args).

All approaches accept an options hash as their last parameter.

Options

  • :conditions - See conditions in the intro.

  • :order - An SQL fragment like “created_at DESC, name”.

  • :limit - An integer determining the limit on the number of rows that should be returned.

  • :offset - An integer determining the offset from where the rows should be fetched. So at 5, it would skip rows 0 through 4.

Examples

# find by id

Person.find(1) # returns the object for ID = 1
Person.find(1, 2, 6) # returns an array for objects with IDs in (1, 2, 6)
Person.find([7, 17]) # returns an array for objects with IDs in (7, 17)
Person.find([1]) # returns an array for the object with ID = 1
Person.where(:administrator => 1).order(:created_on => :desc).find(1)

Note that the returned order is undefined unless you give a specific :order clause. Further note that order is handled in memory and so does suffer a performance penalty.

Examples

# find first
Person.first # returns the first object fetched by SELECT * FROM people
Person.where(:user_name => user_name).first
Person.order(:created_on => :desc).offset(5).first

# find last
Person.last # returns the last object in the column family
Person.where(:user_name => user_name).last
Person.order(:created_at => :desc).offset(5).last
# File lib/datastax_rails/relation/finder_methods.rb, line 48
def find(*args)
  return to_a.find { |*block_args| yield(*block_args) } if block_given?

  options = args.extract_options!
  if options.present?
    apply_finder_options(options).find(*args)
  else
    case args.first
    when :first, :last
      send(args.first)
    else
      self.use_solr_value = false
      find_with_ids(*args)
    end
  end
end
find_by(*args) click to toggle source

Finds the first record matching the specified conditions. There is no implied ordering so if order matters, you should specify it yourself.

If no record is found, returns nil.

Post.find_by name: 'Spartacus', rating: 4 Post.find_by “published_at < ?”, 2.weeks.ago

# File lib/datastax_rails/relation/finder_methods.rb, line 73
def find_by(*args)
  where_values << escape_attributes(args.first)
  dont_escape.first
end
find_by!(*args) click to toggle source

Like find_by, except that if no record is found, raises an DatastaxRails::RecordNotFound error.

# File lib/datastax_rails/relation/finder_methods.rb, line 80
def find_by!(*args)
  where_values << escape_attributes(args.first)
  dont_escape.first!
end
first(*args) click to toggle source

A convenience wrapper for find(:first, *args). You can pass in all the same arguments to this method as you can to find(:first).

# File lib/datastax_rails/relation/finder_methods.rb, line 87
def first(*args)
  if args.any?
    if args.first.is_a?(Integer) || (loaded? && !args.first.is_a?(Hash))
      limit(*args).to_a
    else
      apply_finder_options(args.first).first
    end
  else
    find_first
  end
end
first!() click to toggle source

Same as first but raises DatastaxRails::RecordNotFound if no record is found. Note that first! accepts no arguments.

# File lib/datastax_rails/relation/finder_methods.rb, line 101
def first!
  first || fail(RecordNotFound)
end
last(*args) click to toggle source

A convenience wrapper for find(:last, *args). You can pass in all the same arguments to this method as you can to find(:last).

# File lib/datastax_rails/relation/finder_methods.rb, line 107
def last(*args)
  if args.any?
    if args.first.is_a?(Integer) || (loaded? && !args.first.is_a?(Hash))
      if order_values.empty? && reorder_value.nil?
        order(id: :desc).limit(*args).reverse
      else
        to_a.last(*args)
      end
    else
      apply_finder_options(args.first).last
    end
  else
    find_last
  end
end
last!() click to toggle source

Same as last but raises DatastaxRails::RecordNotFound if no record is found. Note that last! accepts no arguments.

# File lib/datastax_rails/relation/finder_methods.rb, line 125
def last!
  last || fail(RecordNotFound)
end

Private Instance Methods

escape_attributes(conditions) click to toggle source
# File lib/datastax_rails/relation/finder_methods.rb, line 145
def escape_attributes(conditions)
  escaped = {}
  conditions.each do |k, v|
    if v.is_a?(String)
      escaped[k] = v.gsub(/([^\w\- ])/, '\\\\\1')
    else
      escaped[k] = v
    end
  end
  escaped
end
find_first() click to toggle source
# File lib/datastax_rails/relation/finder_methods.rb, line 212
def find_first
  if loaded?
    @results.first
  else
    @first ||= limit(1).to_a[0]
  end
end
find_last() click to toggle source
# File lib/datastax_rails/relation/finder_methods.rb, line 220
def find_last
  if loaded?
    @results.last
  else
    @last ||= reverse_order.limit(1).to_a[0]
  end
end
find_one(id) click to toggle source
# File lib/datastax_rails/relation/finder_methods.rb, line 176
def find_one(id)
  key = @klass.attribute_definitions[@klass.primary_key].type_cast_for_cql3(id)
  key || fail(RecordNotFound, "Couldn't find #{@klass.name} with an invalid ID=#{id}")

  with_cassandra.where(@klass.primary_key => key).first ||
    fail(RecordNotFound, "Couldn't find #{@klass.name} with ID=#{id}")
end
find_some(ids) click to toggle source
# File lib/datastax_rails/relation/finder_methods.rb, line 184
def find_some(ids)
  keys = ids.map do |id|
    @klass.attribute_definitions[@klass.primary_key].type_cast_for_cql3(id) ||
    fail(RecordNotFound, "Couldn't find #{@klass.name} with an invalid ID=#{id}")
  end
  result = with_cassandra.where(@klass.primary_key => keys).all

  expected_size =
    if @limit_value && ids.size > @limit_value
      @limit_value
    else
      ids.size
    end

  # 11 ids with limit 3, offset 9 should give 2 results.
  if @offset_value && (ids.size - @offset_value < expected_size)
    expected_size = ids.size - @offset_value
  end

  if result.size == expected_size
    result
  else
    error = "Couldn't find all #{@klass.name.pluralize} with IDs "
    error << "(#{ids.join(', ')}) (found #{result.size} results, but was looking for #{expected_size})"
    fail RecordNotFound, error
  end
end
find_with_ids(*ids) { |*block_args| ... } click to toggle source
# File lib/datastax_rails/relation/finder_methods.rb, line 157
def find_with_ids(*ids)
  return to_a.find { |*block_args| yield(*block_args) } if block_given?

  expects_array = ids.first.is_a?(Array)
  return ids.first if expects_array && ids.first.empty?

  ids = ids.flatten.compact.uniq

  case ids.size
  when 0
    fail RecordNotFound, "Couldn't find #{@klass.name} without an ID"
  when 1
    result = find_one(ids.first)
    expects_array ? [result] : result
  else
    find_some(ids)
  end
end