class Chewy::Index::Adapter::Object

This adapter provides an ability to import documents from any source. You can actually use any class or even a symbol as a target.

In case if a class is used - some of the additional features are available: it is possible to provide the default import data (used on reset) and source objects loading logic.

@see import @see load

Public Class Methods

new(target, **options) click to toggle source

The signature of the index scope definition.

@example

index_scope :geoname
index_scope Geoname
index_scope -> { Geoname.all_the_places }, name: 'geoname'

@param target [Class, Symbol, String, Proc] a source of data and everything @option options [String, Symbol] :name redefines the inferred name if necessary @option options [String, Symbol] :import_all_method redefines import method name @option options [String, Symbol] :load_all_method redefines batch load method name @option options [String, Symbol] :load_one_method redefines per-object load method name

# File lib/chewy/index/adapter/object.rb, line 29
def initialize(target, **options)
  @target = target
  @options = options
end

Public Instance Methods

identify(collection) click to toggle source

While for ORM adapters it returns an array of ids for the passed collection, for the object adapter it returns the collection itself.

@param collection [Array<Object>, Object] a collection or an object @return [Array<Object>]

# File lib/chewy/index/adapter/object.rb, line 52
def identify(collection)
  Array.wrap(collection)
end
import(*args, &block) click to toggle source

This method is used internally by `Chewy::Index.import`.

The idea is that any object can be imported to ES if it responds to `#to_json` method.

If method `destroyed?` is defined for object (or, in case of hash object, it has `:_destroyed` or `'_destroyed'` key) and returns `true` or object satisfy `delete_if` option then object will be deleted from index. But in order to be destroyable, objects need to respond to `id` method or have an `id` key so ElasticSearch could know which one to delete.

If nothing is passed the method tries to call `import_all_method`, which is `call` by default, on target to get the default objects batch.

@example

class Geoname
  self < class
    def self.call
      FancyGeoAPI.all_points_collection
    end
    alias_method :import_all, :call
  end
end

# All the following variants will work:
index_scope Geoname
index_scope Geoname, import_all_method: 'import_all'
index_scope -> { FancyGeoAPI.all_points_collection }, name: 'geoname'

@param args [Array<#to_json>] @option options [Integer] :batch_size import processing batch size @return [true, false]

# File lib/chewy/index/adapter/object.rb, line 88
def import(*args, &block)
  collection, options = import_args(*args)
  import_objects(collection, options, &block)
end
import_fields(*args) { |map { |object| object_field(object, :id) || object }| ... } click to toggle source

For the object adapter this method tries to fetch :id and requested fields from the passed collection or the target's `import_all_method` when defined. Otherwise it tries to call the target `pluck_method`, which is configurable and `pluck` by default. The `pluck_method` have to act exactly the same way as the AR one. It returns an empty array when none of the methods are found.

@example

class Geoname
  self < class
    def self.pluck(*fields)
      if fields.one?
        whatever_source.map { |object| object.send(fields.first) }
      else
        whatever_source.map do |object|
          fields.map { |field| object.send(field) }
        end
      end
    end
  end
end

@see Chewy::Index::Adapter::Base#import_fields

# File lib/chewy/index/adapter/object.rb, line 116
def import_fields(*args, &block)
  return enum_for(:import_fields, *args) unless block_given?

  options = args.extract_options!
  options[:batch_size] ||= BATCH_SIZE

  if args.empty? && @target.respond_to?(pluck_method)
    @target.send(pluck_method, :id, *options[:fields]).each_slice(options[:batch_size], &block)
  elsif options[:fields].blank?
    import_references(*args, options) do |batch|
      yield batch.map { |object| object_field(object, :id) || object }
    end
  else
    import_references(*args, options) do |batch|
      batch = batch.map do |object|
        options[:fields].map { |field| object_field(object, field) }
          .unshift(object_field(object, :id) || object)
      end
      yield batch
    end
  end
end
import_references(*args, &block) click to toggle source

For the Object adapter returns the objects themselves in batches.

@see Chewy::Index::Adapter::Base#import_references

# File lib/chewy/index/adapter/object.rb, line 142
def import_references(*args, &block)
  return enum_for(:import_references, *args) unless block_given?

  collection, options = import_args(*args)
  collection.each_slice(options[:batch_size], &block)
end
load(ids, **options) click to toggle source

This method is used internally by the request DSL when the collection of ORM/ODM objects is requested.

Options usage is implemented by `load_all_method` and `load_one_method`.

If none of the `load_all_method` or `load_one_method` is implemented for the target - the method will return nil. This means that the loader will return an array `Chewy::Index` objects that actually was passed.

To use loading for objects it is obviously required to provide some meaningful ids for ES documents.

@example

class Geoname
  def self.load_all(wrappers, options)
    if options[:additional_data]
      wrappers.map do |wrapper|
        FancyGeoAPI.point_by_name(wrapper.name)
      end
    else
      wrappers
    end
  end
end

MyIndex.load(additional_data: true).objects

@param ids [Array<Hash>] an array of ids from ES hits @param options [Hash] any options passed here with the request DSL `load` method. @return [Array<Object>, nil]

# File lib/chewy/index/adapter/object.rb, line 179
def load(ids, **options)
  if target.respond_to?(load_all_method)
    if target.method(load_all_method).arity == 1
      target.send(load_all_method, ids)
    else
      target.send(load_all_method, ids, options)
    end
  elsif target.respond_to?(load_one_method)
    if target.method(load_one_method).arity == 1
      ids.map { |hit| target.send(load_one_method, hit) }
    else
      ids.map { |hit| target.send(load_one_method, hit, options) }
    end
  end
end
name() click to toggle source

Inferred from the target by default if possible.

@example

# defines name = Geoname
index_scope :geoname
# still defines name = Geoname
index_scope -> { Geoname.all_the_places }, name: 'geoname'

@return [String]

# File lib/chewy/index/adapter/object.rb, line 43
def name
  @name ||= (options[:name] || @target).to_s.camelize.demodulize
end

Private Instance Methods

delete_from_index?(object) click to toggle source
# File lib/chewy/index/adapter/object.rb, line 203
def delete_from_index?(object)
  delete = super
  delete ||= object.destroyed? if object.respond_to?(:destroyed?)
  delete ||= object[:_destroyed] || object['_destroyed'] if object.is_a?(Hash)
  !!delete
end
import_all_method() click to toggle source
# File lib/chewy/index/adapter/object.rb, line 218
def import_all_method
  @import_all_method ||= options[:import_all_method] || :call
end
import_args(*args) click to toggle source
# File lib/chewy/index/adapter/object.rb, line 234
def import_args(*args)
  options = args.extract_options!
  options[:batch_size] ||= BATCH_SIZE

  collection = if args.empty? && @target.respond_to?(import_all_method)
    @target.send(import_all_method)
  else
    args.flatten(1).compact
  end

  [collection, options]
end
import_objects(objects, options) { |grouped_objects(group)| ... } click to toggle source
# File lib/chewy/index/adapter/object.rb, line 197
def import_objects(objects, options)
  objects.each_slice(options[:batch_size]).map do |group|
    yield grouped_objects(group)
  end.all?
end
load_all_method() click to toggle source
# File lib/chewy/index/adapter/object.rb, line 226
def load_all_method
  @load_all_method ||= options[:load_all_method] || :load_all
end
load_one_method() click to toggle source
# File lib/chewy/index/adapter/object.rb, line 230
def load_one_method
  @load_one_method ||= options[:load_one_method] || :load_one
end
object_field(object, name) click to toggle source
# File lib/chewy/index/adapter/object.rb, line 210
def object_field(object, name)
  if object.respond_to?(name)
    object.send(name)
  elsif object.is_a?(Hash)
    object[name.to_sym] || object[name.to_s]
  end
end
pluck_method() click to toggle source
# File lib/chewy/index/adapter/object.rb, line 222
def pluck_method
  @pluck_method ||= options[:pluck_method] || :pluck
end