Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .rubocop_todo.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ Metrics/AbcSize:
# Offense count: 4
# Configuration parameters: CountComments, CountAsOne.
Metrics/ClassLength:
Max: 267
Max: 300

# Offense count: 13
# Configuration parameters: IgnoredMethods.
Expand All @@ -69,7 +69,7 @@ Metrics/ModuleLength:
# Offense count: 18
# Configuration parameters: IgnoredMethods.
Metrics/PerceivedComplexity:
Max: 13
Max: 14

# Offense count: 11
# Configuration parameters: EnforcedStyle, CheckMethodNames, CheckSymbols, AllowedIdentifiers.
Expand Down
1 change: 1 addition & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ gem 'activejob', require: false
gem 'sidekiq', require: false

gem 'kaminari-core', require: false
gem 'mongoid'

gem 'parallel', require: false
gem 'ruby-progressbar', require: false
Expand Down
29 changes: 25 additions & 4 deletions lib/chewy.rb
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ def try_require(path)
try_require 'kaminari/activerecord'
end

ActiveSupport.on_load(:mongoid) do
try_require 'kaminari/mongoid'
end

require 'chewy/version'
require 'chewy/errors'
require 'chewy/config'
Expand All @@ -55,8 +59,19 @@ def try_require(path)
include Chewy::Index::Observe::ActiveRecordMethods
end

# ActiveSupport.on_load(:mongoid) do
# module Mongoid
# module Document
# module ClassMethods
# include Chewy::Index::Observe::MongoidMethods
# end
# end
# end
# end

module Chewy
@adapters = [
Chewy::Index::Adapter::Mongoid,
Chewy::Index::Adapter::ActiveRecord,
Chewy::Index::Adapter::Object
]
Expand Down Expand Up @@ -97,8 +112,14 @@ def derive_name(index_name)

# Main elasticsearch-ruby client instance
#
def client
Chewy.current[:chewy_client] ||= Chewy::ElasticClient.new
def client(hosts = nil)
# # We are changing this to support multiple clusters in chewy.
thread_cache_key = if hosts
"chewy_client_#{hosts}"
else
'chewy_client'
end
Chewy.current[thread_cache_key.to_sym] ||= Chewy::ElasticClient.new(hosts)
end

# Sends wait_for_status request to ElasticSearch with status
Expand All @@ -108,15 +129,15 @@ def client
#
def wait_for_status
if Chewy.configuration[:wait_for_status].present?
client.cluster.health wait_for_status: Chewy.configuration[:wait_for_status]
client(@hosts_name).cluster.health wait_for_status: Chewy.configuration[:wait_for_status]
end
end

# Deletes all corresponding indexes with current prefix from ElasticSearch.
# Be careful, if current prefix is blank, this will destroy all the indexes.
#
def massacre
Chewy.client.indices.delete(index: [Chewy.configuration[:prefix], '*'].reject(&:blank?).join('_'))
Chewy.client(@hosts_name).indices.delete(index: [Chewy.configuration[:prefix], '*'].reject(&:blank?).join('_'))
Chewy.wait_for_status
end
alias_method :delete_all, :massacre
Expand Down
4 changes: 2 additions & 2 deletions lib/chewy/config.rb
Original file line number Diff line number Diff line change
Expand Up @@ -70,12 +70,12 @@ def initialize
end

def transport_logger=(logger)
Chewy.client.transport.transport.logger = logger
Chewy.client(@hosts_name).transport.transport.logger = logger
@transport_logger = logger
end

def transport_tracer=(tracer)
Chewy.client.transport.transport.tracer = tracer
Chewy.client(@hosts_name).transport.transport.tracer = tracer
@transport_tracer = tracer
end

Expand Down
8 changes: 5 additions & 3 deletions lib/chewy/elastic_client.rb
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
module Chewy
# Replacement for Chewy.client
class ElasticClient
def self.build_es_client(configuration = Chewy.configuration)
def self.build_es_client(hosts = nil, configuration = Chewy.configuration)
client_configuration = configuration.deep_dup
client_configuration[:hosts] = client_configuration[hosts] if hosts
client_configuration.delete(:prefix) # used by Chewy, not relevant to Elasticsearch::Client
block = client_configuration[:transport_options].try(:delete, :proc)
::Elasticsearch::Client.new(client_configuration, &block)
end

def initialize(elastic_client = self.class.build_es_client)
@elastic_client = elastic_client
def initialize(hosts = nil)
@elastic_client ||= self.class.build_es_client(hosts)
@elastic_client
end

private
Expand Down
10 changes: 10 additions & 0 deletions lib/chewy/index.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
require 'chewy/search'
require 'chewy/index/actions'
require 'chewy/index/adapter/active_record'
require 'chewy/index/adapter/mongoid'
require 'chewy/index/adapter/object'
require 'chewy/index/aliases'
require 'chewy/index/crutch'
Expand Down Expand Up @@ -48,6 +49,8 @@ class Index
self._default_import_options = {}

class << self
attr_reader :hosts_name

# @overload index_name(suggest)
# If suggested name is passed, it is set up as the new base name for
# the index. Used for the index base name redefinition.
Expand Down Expand Up @@ -92,6 +95,13 @@ def index_name(suggest = nil, prefix: nil, suffix: nil)
end
end

# Sets the hosts name of the index. If hosts_name is nil, use the default
# hosts in chewy.yml. Otherwise use the hosts with the specified name for
# indexing/queries.
def es_cluster_host(hosts_name)
@hosts_name = hosts_name
end

# Base name for the index. Uses the default value inferred from the
# class name unless redefined.
#
Expand Down
20 changes: 10 additions & 10 deletions lib/chewy/index/actions.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ module ClassMethods
# UsersIndex.exists? #=> true
#
def exists?
client.indices.exists(index: index_name)
client(@hosts_name).indices.exists(index: index_name)
end

# Creates index and applies mappings and settings.
Expand Down Expand Up @@ -59,7 +59,7 @@ def create!(suffix = nil, **options)

body = specification_hash
body[:aliases] = {general_name => {}} if options[:alias] && suffixed_name != general_name
result = client.indices.create(index: suffixed_name, body: body)
result = client(@hosts_name).indices.create(index: suffixed_name, body: body)

Chewy.wait_for_status if result
result
Expand All @@ -79,8 +79,8 @@ def delete(suffix = nil)
# "The index parameter in the delete index API no longer accepts alias names.
# Instead, it accepts only index names (or wildcards which will expand to matching indices)."
# https://www.elastic.co/guide/en/elasticsearch/reference/6.8/breaking-changes-6.0.html#_delete_index_api_resolves_indices_expressions_only_against_indices
index_names = client.indices.get_alias(index: index_name(suffix: suffix)).keys
result = client.indices.delete index: index_names.join(',')
index_names = client(@hosts_name).indices.get_alias(index: index_name(suffix: suffix)).keys
result = client(@hosts_name).indices.delete index: index_names.join(',')
Chewy.wait_for_status if result
result
# es-ruby >= 1.0.10 handles Elasticsearch::Transport::Transport::Errors::NotFound
Expand Down Expand Up @@ -164,13 +164,13 @@ def reset!(suffix = nil, apply_journal: true, journal: false, **import_options)
original_index_settings suffixed_name

delete if indexes.blank?
client.indices.update_aliases body: {actions: [
client(@hosts_name).indices.update_aliases body: {actions: [
*indexes.map do |index|
{remove: {index: index, alias: general_name}}
end,
{add: {index: suffixed_name, alias: general_name}}
]}
client.indices.delete index: indexes if indexes.present?
client(@hosts_name).indices.delete index: indexes if indexes.present?

self.journal.apply(start_time, **import_options) if apply_journal
result
Expand All @@ -192,11 +192,11 @@ def journal
end

def clear_cache(args = {index: index_name})
client.indices.clear_cache(args)
client(@hosts_name).indices.clear_cache(args)
end

def reindex(source: index_name, dest: index_name)
client.reindex(
client(@hosts_name).reindex(
{
body:
{
Expand All @@ -214,7 +214,7 @@ def reindex(source: index_name, dest: index_name)
# Chewy.client.update_mapping('cities', {properties: {new_field: {type: :text}}})
#
def update_mapping(name = index_name, body = root.mappings_hash)
client.indices.put_mapping(
client(@hosts_name).indices.put_mapping(
index: name,
body: body
)['acknowledged']
Expand Down Expand Up @@ -255,7 +255,7 @@ def original_index_settings(index_name)
end

def update_settings(index_name, **options)
client.indices.put_settings index: index_name, body: {index: options[:settings]}
client(@hosts_name).indices.put_settings index: index_name, body: {index: options[:settings]}
end

def index_settings(setting_name)
Expand Down
87 changes: 87 additions & 0 deletions lib/chewy/index/adapter/mongoid.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
require 'chewy/index/adapter/orm'

module Chewy
class Index
module Adapter
class Mongoid < Orm
def self.accepts?(target)
defined?(::Mongoid::Document) && (
(target.is_a?(Class) && target.ancestors.include?(::Mongoid::Document)) ||
target.is_a?(::Mongoid::Criteria))
end

def identify(collection)
super(collection).map { |id| id.is_a?(BSON::ObjectId) ? id.to_s : id }
end

private

def cleanup_default_scope!
Chewy.logger.warn('Default type scope order, limit and offset are ignored and will be nullified') if Chewy.logger && sort_or_limit_or_skip_options?

@default_scope.options.delete(:limit)
@default_scope.options.delete(:skip)
@default_scope = @default_scope.reorder(nil)
end

def sort_or_limit_or_skip_options?
@default_scope.options.values_at(:sort, :limit, :skip).compact.present?
end

def import_scope(scope, options)
pluck_in_batches(scope, **options.slice(:batch_size)).map do |ids|
yield grouped_objects(default_scope_where_ids_in(ids))
end.all?
end

def import_objects(collection, options)
direct_import = (default_scope.selector.empty? || @options[:searchable_proc]) &&
!options[:raw_import] &&
collection.is_a?(Array) &&
!collection.empty? &&
collection.all? { |item| item.is_a?(::Mongoid::Document) && item.__selected_fields.nil? }
options[:direct_import] = direct_import unless options[:direct_import].present?
super(collection, options)
end

def primary_key
:_id
end

def pluck(scope, fields: [])
scope.pluck(primary_key, *fields)
end

def pluck_in_batches(scope, fields: [], batch_size: nil, **options, &block)
unless block_given?
return enum_for(
:pluck_in_batches,
scope,
fields: fields,
batch_size: batch_size,
**options
)
end

scope.batch_size(batch_size).no_timeout.pluck(primary_key, *fields).each_slice(batch_size, &block)
end

def scope_where_ids_in(scope, ids)
scope.where(primary_key.in => ids)
end

def all_scope
target.all
end

def relation_class
::Mongoid::Criteria
end

def object_class
::Mongoid::Document
end
end
end
end
end
2 changes: 1 addition & 1 deletion lib/chewy/index/adapter/orm.rb
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ def import_objects(collection, options)
else
default_scope_where_ids_in(ids)
end

batch = batch.select { |object| @options[:searchable_proc].call(object) } if @options[:searchable_proc].present?
if batch.empty?
true
else
Expand Down
6 changes: 3 additions & 3 deletions lib/chewy/index/aliases.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@ module Aliases

module ClassMethods
def indexes
indexes = empty_if_not_found { client.indices.get(index: index_name).keys }
indexes += empty_if_not_found { client.indices.get_alias(name: index_name).keys }
indexes = empty_if_not_found { client(@hosts_name).indices.get(index: index_name).keys }
indexes += empty_if_not_found { client(@hosts_name).indices.get_alias(name: index_name).keys }
indexes.compact.uniq
end

def aliases
empty_if_not_found do
client.indices.get_alias(index: index_name, name: '*').values.flat_map do |aliases|
client(@hosts_name).indices.get_alias(index: index_name, name: '*').values.flat_map do |aliases|
aliases['aliases'].keys
end
end.compact.uniq
Expand Down
7 changes: 6 additions & 1 deletion lib/chewy/index/crutch.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,12 @@ def respond_to_missing?(name, include_private = false)
end

def [](name)
@crutches_instances[name] ||= @index._crutches[:"#{name}"].call(@collection)
execution_block = @index._crutches[:"#{name}"]
@crutches_instances[name] ||= if execution_block.arity == 2
execution_block.call(@collection, self)
else
execution_block.call(@collection)
end
end
end

Expand Down
2 changes: 1 addition & 1 deletion lib/chewy/index/import/bulk_request.rb
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ def perform(body)
return [] if body.blank?

request_bodies(body).each_with_object([]) do |request_body, results|
response = @index.client.bulk(**request_base.merge(body: request_body)) if request_body.present?
response = @index.client(@index.hosts_name).bulk(**request_base.merge(body: request_body)) if request_body.present?

next unless response.try(:[], 'errors')

Expand Down
20 changes: 20 additions & 0 deletions lib/chewy/index/observe/mongoid_methods.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# frozen_string_literal: true

module Chewy
class Index
module Observe
extend Helpers
module MongoidMethods
class_methods do
def update_index(type_name, *args, &block)
# callback_options = Observe.extract_callback_options!(args)
# update_proc = Observe.update_proc(type_name, *args, &block)
#
# after_save(callback_options, &update_proc)
# after_destroy(callback_options, &update_proc)
end
end
end
end
end
end
Loading