Class: Chewy::Index::Adapter::Object

Inherits:
Base
  • Object
show all
Defined in:
lib/chewy/index/adapter/object.rb

Overview

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 Also:

Constant Summary

Constants inherited from Base

Base::BATCH_SIZE

Instance Attribute Summary

Attributes inherited from Base

#options, #target

Instance Method Summary collapse

Methods inherited from Base

accepts?, #type_name

Constructor Details

#initialize(target, **options) ⇒ Object

The signature of the index scope definition.

Examples:

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

Parameters:

  • target (Class, Symbol, String, Proc)

    a source of data and everything

  • options (Hash)

    a customizable set of options

Options Hash (**options):

  • :name (String, Symbol)

    redefines the inferred name if necessary

  • :import_all_method (String, Symbol)

    redefines import method name

  • :load_all_method (String, Symbol)

    redefines batch load method name

  • :load_one_method (String, Symbol)

    redefines per-object load method name



29
30
31
32
# File 'lib/chewy/index/adapter/object.rb', line 29

def initialize(target, **options)
  @target = target
  @options = options
end

Instance Method Details

#identify(collection) ⇒ Array<Object>

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

Parameters:

  • collection (Array<Object>, Object)

    a collection or an object

Returns:



52
53
54
# File 'lib/chewy/index/adapter/object.rb', line 52

def identify(collection)
  Array.wrap(collection)
end

#import(*args, &block) ⇒ true, false

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.

Examples:

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'

Parameters:

  • args (Array<#to_json>)
  • options (Hash)

    a customizable set of options

Returns:

  • (true, false)


88
89
90
91
# 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, &block) ⇒ Object

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.

Examples:

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 Also:



116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
# 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) ⇒ Object

For the Object adapter returns the objects themselves in batches.



142
143
144
145
146
147
# 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) ⇒ Array<Object>?

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.

Examples:

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

Parameters:

  • ids (Array<Hash>)

    an array of ids from ES hits

  • options (Hash)

    any options passed here with the request DSL load method.

Returns:



179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
# 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

#nameString

Inferred from the target by default if possible.

Examples:

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

Returns:

  • (String)


43
44
45
# File 'lib/chewy/index/adapter/object.rb', line 43

def name
  @name ||= (options[:name] || @target).to_s.camelize.demodulize
end