Class: Chewy::Type::Adapter::Object

Inherits:
Base show all
Defined in:
lib/chewy/type/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 type definition.

Examples:

define_type :geoname
define_type Geoname
define_type -> { 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 type 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/type/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:

Returns:



53
54
55
# File 'lib/chewy/type/adapter/object.rb', line 53

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

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

This method is used internally by Chewy::Type.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 type 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 folloving variants will work:
define_type Geoname
define_type Geoname, import_all_method: 'import_all'
define_type -> { FancyGeoAPI.all_points_collection }, name: 'geoname'

Parameters:

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

    a customizable set of options

Returns:

  • (true, false)


89
90
91
92
# File 'lib/chewy/type/adapter/object.rb', line 89

def import(*args, &block)
  collection, options = import_args(*args)
  import_objects(collection, options, &block)
end

#import_fields(*args) ⇒ 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:



117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
# File 'lib/chewy/type/adapter/object.rb', line 117

def import_fields(*args)
  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]) do |batch|
      yield batch
    end
  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) ⇒ Object

For the Object adapter returns the objects themselves in batches.



144
145
146
147
148
149
150
151
# File 'lib/chewy/type/adapter/object.rb', line 144

def import_references(*args)
  return enum_for(:import_references, *args) unless block_given?

  collection, options = import_args(*args)
  collection.each_slice(options[:batch_size]) do |batch|
    yield batch
  end
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::Type 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::Geoname.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:



183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
# File 'lib/chewy/type/adapter/object.rb', line 183

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

Name is used for the type class creation. Inferred from the target by default if possible.

Examples:

# defines MyIndex::Geoname
define_type :geoname
# still defines MyIndex::Geoname
define_type -> { Geoname.all_the_places }, name: 'geoname'

Returns:

  • (String)


44
45
46
# File 'lib/chewy/type/adapter/object.rb', line 44

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