Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Hotfix/chewy upgrade #972

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
33 changes: 27 additions & 6 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,16 +112,22 @@ 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
# defined in configuration.
#
# Does nothing in case of config `wait_for_status` is undefined.
#
def wait_for_status
def wait_for_status(client)
if Chewy.configuration[:wait_for_status].present?
client.cluster.health wait_for_status: Chewy.configuration[:wait_for_status]
end
Expand All @@ -115,9 +136,9 @@ def wait_for_status
# 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.wait_for_status
def massacre(client)
client.indices.delete(index: [Chewy.configuration[:prefix], '*'].reject(&:blank?).join('_'))
wait_for_status(client)
end
alias_method :delete_all, :massacre

Expand Down
2 changes: 2 additions & 0 deletions lib/chewy/config.rb
Original file line number Diff line number Diff line change
Expand Up @@ -70,11 +70,13 @@ def initialize
end

def transport_logger=(logger)
# TODO Add support for hostname
Chewy.client.transport.transport.logger = logger
@transport_logger = logger
end

def transport_tracer=(tracer)
# TODO Add support for hostname
Chewy.client.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
15 changes: 15 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,18 @@ 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

# Calls the delegated method above to Chewy.client
def es_client
client(@hosts_name)
end

# Base name for the index. Uses the default value inferred from the
# class name unless redefined.
#
Expand Down
25 changes: 13 additions & 12 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)
es_client.indices.exists(index: index_name)
end

# Creates index and applies mappings and settings.
Expand Down Expand Up @@ -59,9 +59,10 @@ 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)
es_client = client(@hosts_name)
result = es_client.indices.create(index: suffixed_name, body: body)

Chewy.wait_for_status if result
Chewy.wait_for_status(es_client) if result
result
end

Expand All @@ -79,9 +80,9 @@ 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(',')
Chewy.wait_for_status if result
index_names = es_client.indices.get_alias(index: index_name(suffix: suffix)).keys
result = es_client.indices.delete index: index_names.join(',')
Chewy.wait_for_status(es_client) if result
result
# es-ruby >= 1.0.10 handles Elasticsearch::Transport::Transport::Errors::NotFound
# by itself, rescue is for previous versions
Expand Down Expand Up @@ -164,13 +165,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: [
es_client.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?
es_client.indices.delete index: indexes if indexes.present?

self.journal.apply(start_time, **import_options) if apply_journal
result
Expand All @@ -192,11 +193,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(
es_client.reindex(
{
body:
{
Expand All @@ -214,7 +215,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(
es_client.indices.put_mapping(
index: name,
body: body
)['acknowledged']
Expand Down Expand Up @@ -255,7 +256,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]}
es_client.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 { es_client.indices.get(index: index_name).keys }
indexes += empty_if_not_found { es_client.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|
es_client.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
Loading