chewy 6.0.0 → 7.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/CODEOWNERS +1 -0
- data/.github/ISSUE_TEMPLATE/bug_report.md +39 -0
- data/.github/ISSUE_TEMPLATE/feature_request.md +20 -0
- data/.github/PULL_REQUEST_TEMPLATE.md +16 -0
- data/.github/dependabot.yml +42 -0
- data/.github/workflows/ruby.yml +60 -0
- data/.rubocop.yml +16 -8
- data/.rubocop_todo.yml +110 -22
- data/CHANGELOG.md +396 -105
- data/CODE_OF_CONDUCT.md +14 -0
- data/CONTRIBUTING.md +63 -0
- data/Gemfile +4 -10
- data/Guardfile +3 -1
- data/README.md +497 -275
- data/chewy.gemspec +5 -20
- data/gemfiles/base.gemfile +12 -0
- data/gemfiles/rails.6.1.activerecord.gemfile +10 -15
- data/gemfiles/rails.7.0.activerecord.gemfile +14 -0
- data/gemfiles/rails.7.1.activerecord.gemfile +14 -0
- data/lib/chewy/config.rb +60 -52
- data/lib/chewy/elastic_client.rb +31 -0
- data/lib/chewy/errors.rb +7 -10
- data/lib/chewy/fields/base.rb +79 -13
- data/lib/chewy/fields/root.rb +4 -14
- data/lib/chewy/index/actions.rb +54 -37
- data/lib/chewy/{type → index}/adapter/active_record.rb +30 -6
- data/lib/chewy/{type → index}/adapter/base.rb +2 -3
- data/lib/chewy/{type → index}/adapter/object.rb +27 -31
- data/lib/chewy/{type → index}/adapter/orm.rb +17 -18
- data/lib/chewy/index/aliases.rb +14 -5
- data/lib/chewy/index/crutch.rb +40 -0
- data/lib/chewy/index/import/bulk_builder.rb +311 -0
- data/lib/chewy/{type → index}/import/bulk_request.rb +6 -7
- data/lib/chewy/{type → index}/import/journal_builder.rb +11 -12
- data/lib/chewy/{type → index}/import/routine.rb +18 -17
- data/lib/chewy/{type → index}/import.rb +76 -32
- data/lib/chewy/{type → index}/mapping.rb +29 -34
- data/lib/chewy/index/observe/active_record_methods.rb +87 -0
- data/lib/chewy/index/observe/callback.rb +34 -0
- data/lib/chewy/index/observe.rb +17 -0
- data/lib/chewy/index/specification.rb +1 -0
- data/lib/chewy/{type → index}/syncer.rb +59 -59
- data/lib/chewy/{type → index}/witchcraft.rb +11 -7
- data/lib/chewy/{type → index}/wrapper.rb +2 -2
- data/lib/chewy/index.rb +67 -94
- data/lib/chewy/journal.rb +25 -14
- data/lib/chewy/log_subscriber.rb +5 -1
- data/lib/chewy/minitest/helpers.rb +86 -13
- data/lib/chewy/minitest/search_index_receiver.rb +24 -26
- data/lib/chewy/railtie.rb +6 -20
- data/lib/chewy/rake_helper.rb +169 -113
- data/lib/chewy/rspec/build_query.rb +12 -0
- data/lib/chewy/rspec/helpers.rb +55 -0
- data/lib/chewy/rspec/update_index.rb +55 -44
- data/lib/chewy/rspec.rb +2 -0
- data/lib/chewy/runtime/version.rb +1 -1
- data/lib/chewy/runtime.rb +1 -1
- data/lib/chewy/search/loader.rb +19 -41
- data/lib/chewy/search/parameters/collapse.rb +16 -0
- data/lib/chewy/search/parameters/concerns/query_storage.rb +2 -2
- data/lib/chewy/search/parameters/ignore_unavailable.rb +27 -0
- data/lib/chewy/search/parameters/indices.rb +13 -58
- data/lib/chewy/search/parameters/knn.rb +16 -0
- data/lib/chewy/search/parameters/order.rb +6 -19
- data/lib/chewy/search/parameters/source.rb +5 -1
- data/lib/chewy/search/parameters/storage.rb +1 -1
- data/lib/chewy/search/parameters/track_total_hits.rb +16 -0
- data/lib/chewy/search/parameters.rb +6 -4
- data/lib/chewy/search/query_proxy.rb +9 -2
- data/lib/chewy/search/request.rb +169 -134
- data/lib/chewy/search/response.rb +5 -5
- data/lib/chewy/search/scoping.rb +7 -8
- data/lib/chewy/search/scrolling.rb +13 -13
- data/lib/chewy/search.rb +9 -19
- data/lib/chewy/stash.rb +19 -30
- data/lib/chewy/strategy/active_job.rb +1 -1
- data/lib/chewy/strategy/atomic_no_refresh.rb +18 -0
- data/lib/chewy/strategy/base.rb +10 -0
- data/lib/chewy/strategy/delayed_sidekiq/scheduler.rb +168 -0
- data/lib/chewy/strategy/delayed_sidekiq/worker.rb +76 -0
- data/lib/chewy/strategy/delayed_sidekiq.rb +30 -0
- data/lib/chewy/strategy/lazy_sidekiq.rb +64 -0
- data/lib/chewy/strategy/sidekiq.rb +2 -1
- data/lib/chewy/strategy.rb +6 -19
- data/lib/chewy/version.rb +1 -1
- data/lib/chewy.rb +39 -86
- data/lib/generators/chewy/install_generator.rb +1 -1
- data/lib/tasks/chewy.rake +36 -32
- data/migration_guide.md +46 -8
- data/spec/chewy/config_spec.rb +16 -41
- data/spec/chewy/elastic_client_spec.rb +26 -0
- data/spec/chewy/fields/base_spec.rb +432 -147
- data/spec/chewy/fields/root_spec.rb +20 -28
- data/spec/chewy/fields/time_fields_spec.rb +5 -5
- data/spec/chewy/index/actions_spec.rb +368 -59
- data/spec/chewy/{type → index}/adapter/active_record_spec.rb +156 -40
- data/spec/chewy/{type → index}/adapter/object_spec.rb +21 -6
- data/spec/chewy/index/aliases_spec.rb +3 -3
- data/spec/chewy/index/import/bulk_builder_spec.rb +494 -0
- data/spec/chewy/{type → index}/import/bulk_request_spec.rb +5 -12
- data/spec/chewy/{type → index}/import/journal_builder_spec.rb +9 -19
- data/spec/chewy/{type → index}/import/routine_spec.rb +19 -19
- data/spec/chewy/{type → index}/import_spec.rb +164 -98
- data/spec/chewy/index/mapping_spec.rb +135 -0
- data/spec/chewy/index/observe/active_record_methods_spec.rb +68 -0
- data/spec/chewy/index/observe/callback_spec.rb +139 -0
- data/spec/chewy/index/observe_spec.rb +143 -0
- data/spec/chewy/index/settings_spec.rb +3 -1
- data/spec/chewy/index/specification_spec.rb +20 -30
- data/spec/chewy/{type → index}/syncer_spec.rb +14 -19
- data/spec/chewy/{type → index}/witchcraft_spec.rb +20 -22
- data/spec/chewy/index/wrapper_spec.rb +100 -0
- data/spec/chewy/index_spec.rb +60 -105
- data/spec/chewy/journal_spec.rb +25 -74
- data/spec/chewy/minitest/helpers_spec.rb +123 -15
- data/spec/chewy/minitest/search_index_receiver_spec.rb +28 -30
- data/spec/chewy/multi_search_spec.rb +4 -5
- data/spec/chewy/rake_helper_spec.rb +315 -55
- data/spec/chewy/rspec/build_query_spec.rb +34 -0
- data/spec/chewy/rspec/helpers_spec.rb +61 -0
- data/spec/chewy/rspec/update_index_spec.rb +74 -71
- data/spec/chewy/runtime_spec.rb +2 -2
- data/spec/chewy/search/loader_spec.rb +19 -53
- data/spec/chewy/search/pagination/kaminari_examples.rb +4 -6
- data/spec/chewy/search/pagination/kaminari_spec.rb +2 -2
- data/spec/chewy/search/parameters/collapse_spec.rb +5 -0
- data/spec/chewy/search/parameters/ignore_unavailable_spec.rb +67 -0
- data/spec/chewy/search/parameters/indices_spec.rb +26 -117
- data/spec/chewy/search/parameters/knn_spec.rb +5 -0
- data/spec/chewy/search/parameters/order_spec.rb +18 -11
- data/spec/chewy/search/parameters/query_storage_examples.rb +67 -21
- data/spec/chewy/search/parameters/search_after_spec.rb +4 -1
- data/spec/chewy/search/parameters/source_spec.rb +8 -2
- data/spec/chewy/search/parameters/track_total_hits_spec.rb +5 -0
- data/spec/chewy/search/parameters_spec.rb +18 -4
- data/spec/chewy/search/query_proxy_spec.rb +68 -17
- data/spec/chewy/search/request_spec.rb +292 -110
- data/spec/chewy/search/response_spec.rb +12 -12
- data/spec/chewy/search/scrolling_spec.rb +10 -17
- data/spec/chewy/search_spec.rb +40 -34
- data/spec/chewy/stash_spec.rb +9 -21
- data/spec/chewy/strategy/active_job_spec.rb +16 -16
- data/spec/chewy/strategy/atomic_no_refresh_spec.rb +60 -0
- data/spec/chewy/strategy/atomic_spec.rb +9 -10
- data/spec/chewy/strategy/delayed_sidekiq_spec.rb +208 -0
- data/spec/chewy/strategy/lazy_sidekiq_spec.rb +214 -0
- data/spec/chewy/strategy/sidekiq_spec.rb +12 -12
- data/spec/chewy/strategy_spec.rb +19 -15
- data/spec/chewy_spec.rb +24 -107
- data/spec/spec_helper.rb +3 -22
- data/spec/support/active_record.rb +25 -7
- metadata +78 -339
- data/.circleci/config.yml +0 -240
- data/Appraisals +0 -81
- data/gemfiles/rails.5.2.activerecord.gemfile +0 -17
- data/gemfiles/rails.5.2.mongoid.6.4.gemfile +0 -17
- data/gemfiles/rails.6.0.activerecord.gemfile +0 -17
- data/gemfiles/sequel.4.45.gemfile +0 -11
- data/lib/chewy/backports/deep_dup.rb +0 -46
- data/lib/chewy/backports/duplicable.rb +0 -91
- data/lib/chewy/search/pagination/will_paginate.rb +0 -43
- data/lib/chewy/search/parameters/types.rb +0 -20
- data/lib/chewy/strategy/resque.rb +0 -27
- data/lib/chewy/strategy/shoryuken.rb +0 -40
- data/lib/chewy/type/actions.rb +0 -43
- data/lib/chewy/type/adapter/mongoid.rb +0 -67
- data/lib/chewy/type/adapter/sequel.rb +0 -93
- data/lib/chewy/type/crutch.rb +0 -32
- data/lib/chewy/type/import/bulk_builder.rb +0 -122
- data/lib/chewy/type/observe.rb +0 -82
- data/lib/chewy/type.rb +0 -120
- data/lib/sequel/plugins/chewy_observe.rb +0 -63
- data/spec/chewy/search/pagination/will_paginate_examples.rb +0 -63
- data/spec/chewy/search/pagination/will_paginate_spec.rb +0 -23
- data/spec/chewy/search/parameters/types_spec.rb +0 -5
- data/spec/chewy/strategy/resque_spec.rb +0 -46
- data/spec/chewy/strategy/shoryuken_spec.rb +0 -70
- data/spec/chewy/type/actions_spec.rb +0 -50
- data/spec/chewy/type/adapter/mongoid_spec.rb +0 -372
- data/spec/chewy/type/adapter/sequel_spec.rb +0 -472
- data/spec/chewy/type/import/bulk_builder_spec.rb +0 -194
- data/spec/chewy/type/mapping_spec.rb +0 -175
- data/spec/chewy/type/observe_spec.rb +0 -137
- data/spec/chewy/type/wrapper_spec.rb +0 -100
- data/spec/chewy/type_spec.rb +0 -55
- data/spec/support/mongoid.rb +0 -93
- data/spec/support/sequel.rb +0 -80
data/lib/chewy/type/actions.rb
DELETED
@@ -1,43 +0,0 @@
|
|
1
|
-
module Chewy
|
2
|
-
class Type
|
3
|
-
module Actions
|
4
|
-
extend ActiveSupport::Concern
|
5
|
-
|
6
|
-
module ClassMethods
|
7
|
-
# Deletes all documents of a type and reimports them
|
8
|
-
#
|
9
|
-
# @example
|
10
|
-
# UsersIndex::User.reset
|
11
|
-
#
|
12
|
-
# @see Chewy::Type::Import::ClassMethods#import
|
13
|
-
# @see Chewy::Type::Import::ClassMethods#import
|
14
|
-
# @return [true, false] the result of import
|
15
|
-
def reset
|
16
|
-
delete_all
|
17
|
-
import
|
18
|
-
end
|
19
|
-
|
20
|
-
# Performs missing and outdated objects synchronization for the current type.
|
21
|
-
#
|
22
|
-
# @example
|
23
|
-
# UsersIndex::User.sync
|
24
|
-
#
|
25
|
-
# @see Chewy::Type::Syncer
|
26
|
-
# @param parallel [true, Integer, Hash] options for parallel execution or the number of processes
|
27
|
-
# @return [Hash{Symbol, Object}, nil] a number of missing and outdated documents reindexed and their ids, nil in case of errors
|
28
|
-
def sync(parallel: nil)
|
29
|
-
syncer = Syncer.new(self, parallel: parallel)
|
30
|
-
count = syncer.perform
|
31
|
-
{count: count, missing: syncer.missing_ids, outdated: syncer.outdated_ids} if count
|
32
|
-
end
|
33
|
-
|
34
|
-
# A {Chewy::Journal} instance for the particular type
|
35
|
-
#
|
36
|
-
# @return [Chewy::Journal] journal instance
|
37
|
-
def journal
|
38
|
-
@journal ||= Chewy::Journal.new(self)
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|
@@ -1,67 +0,0 @@
|
|
1
|
-
require 'chewy/type/adapter/orm'
|
2
|
-
|
3
|
-
module Chewy
|
4
|
-
class Type
|
5
|
-
module Adapter
|
6
|
-
class Mongoid < Orm
|
7
|
-
def self.accepts?(target)
|
8
|
-
defined?(::Mongoid::Document) && (
|
9
|
-
target.is_a?(Class) && target.ancestors.include?(::Mongoid::Document) ||
|
10
|
-
target.is_a?(::Mongoid::Criteria))
|
11
|
-
end
|
12
|
-
|
13
|
-
def identify(collection)
|
14
|
-
super(collection).map { |id| id.is_a?(BSON::ObjectId) ? id.to_s : id }
|
15
|
-
end
|
16
|
-
|
17
|
-
private
|
18
|
-
|
19
|
-
def cleanup_default_scope!
|
20
|
-
Chewy.logger.warn('Default type scope order, limit and offset are ignored and will be nullified') if Chewy.logger && @default_scope.options.values_at(:sort, :limit, :skip).compact.present?
|
21
|
-
|
22
|
-
@default_scope.options.delete(:limit)
|
23
|
-
@default_scope.options.delete(:skip)
|
24
|
-
@default_scope = @default_scope.reorder(nil)
|
25
|
-
end
|
26
|
-
|
27
|
-
def import_scope(scope, options)
|
28
|
-
pluck_in_batches(scope, **options.slice(:batch_size)).map do |ids|
|
29
|
-
yield grouped_objects(default_scope_where_ids_in(ids))
|
30
|
-
end.all?
|
31
|
-
end
|
32
|
-
|
33
|
-
def primary_key
|
34
|
-
:_id
|
35
|
-
end
|
36
|
-
|
37
|
-
def pluck(scope, fields: [])
|
38
|
-
scope.pluck(primary_key, *fields)
|
39
|
-
end
|
40
|
-
|
41
|
-
def pluck_in_batches(scope, fields: [], batch_size: nil, **options)
|
42
|
-
return enum_for(:pluck_in_batches, scope, fields: fields, batch_size: batch_size, **options) unless block_given?
|
43
|
-
|
44
|
-
scope.batch_size(batch_size).no_timeout.pluck(primary_key, *fields).each_slice(batch_size) do |batch|
|
45
|
-
yield batch
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
def scope_where_ids_in(scope, ids)
|
50
|
-
scope.where(primary_key.in => ids)
|
51
|
-
end
|
52
|
-
|
53
|
-
def all_scope
|
54
|
-
target.all
|
55
|
-
end
|
56
|
-
|
57
|
-
def relation_class
|
58
|
-
::Mongoid::Criteria
|
59
|
-
end
|
60
|
-
|
61
|
-
def object_class
|
62
|
-
::Mongoid::Document
|
63
|
-
end
|
64
|
-
end
|
65
|
-
end
|
66
|
-
end
|
67
|
-
end
|
@@ -1,93 +0,0 @@
|
|
1
|
-
require 'chewy/type/adapter/base'
|
2
|
-
|
3
|
-
module Chewy
|
4
|
-
class Type
|
5
|
-
module Adapter
|
6
|
-
class Sequel < Orm
|
7
|
-
attr_reader :default_scope
|
8
|
-
alias_method :default_dataset, :default_scope
|
9
|
-
|
10
|
-
def self.accepts?(target)
|
11
|
-
defined?(::Sequel::Model) && (
|
12
|
-
target.is_a?(Class) && target < ::Sequel::Model ||
|
13
|
-
target.is_a?(::Sequel::Dataset))
|
14
|
-
end
|
15
|
-
|
16
|
-
private
|
17
|
-
|
18
|
-
def cleanup_default_scope!
|
19
|
-
Chewy.logger.warn('Default type scope order, limit and offset are ignored and will be nullified') if Chewy.logger && @default_scope != @default_scope.unordered.unlimited
|
20
|
-
|
21
|
-
@default_scope = @default_scope.unordered.unlimited
|
22
|
-
end
|
23
|
-
|
24
|
-
def import_scope(scope, options)
|
25
|
-
pluck_in_batches(scope, **options.slice(:batch_size)).inject(true) do |result, ids|
|
26
|
-
result & yield(grouped_objects(default_scope_where_ids_in(ids).all))
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
def primary_key
|
31
|
-
target.primary_key
|
32
|
-
end
|
33
|
-
|
34
|
-
def full_column_name(column)
|
35
|
-
::Sequel.qualify(target.table_name, column)
|
36
|
-
end
|
37
|
-
|
38
|
-
def all_scope
|
39
|
-
target.dataset
|
40
|
-
end
|
41
|
-
|
42
|
-
def target_columns
|
43
|
-
@target_columns ||= target.columns.to_set
|
44
|
-
end
|
45
|
-
|
46
|
-
def pluck(scope, fields: [])
|
47
|
-
fields = fields.map(&:to_sym).unshift(primary_key).map do |column|
|
48
|
-
target_columns.include?(column) ? full_column_name(column) : column
|
49
|
-
end
|
50
|
-
scope.distinct.select_map(fields.one? ? fields.first : fields)
|
51
|
-
end
|
52
|
-
|
53
|
-
def pluck_in_batches(scope, fields: [], batch_size: nil, **options)
|
54
|
-
return enum_for(:pluck_in_batches, scope, fields: fields, batch_size: batch_size, **options) unless block_given?
|
55
|
-
|
56
|
-
scope = scope.unordered.order(full_column_name(primary_key).asc).limit(batch_size)
|
57
|
-
|
58
|
-
ids = pluck(scope, fields: fields)
|
59
|
-
count = 0
|
60
|
-
|
61
|
-
while ids.present?
|
62
|
-
yield ids
|
63
|
-
break if ids.size < batch_size
|
64
|
-
last_id = ids.last.is_a?(Array) ? ids.last.first : ids.last
|
65
|
-
ids = pluck(scope.where { |_o| full_column_name(primary_key) > last_id }, fields: fields)
|
66
|
-
end
|
67
|
-
|
68
|
-
count
|
69
|
-
end
|
70
|
-
|
71
|
-
def scope_where_ids_in(scope, ids)
|
72
|
-
scope.where(full_column_name(primary_key) => Array.wrap(ids))
|
73
|
-
end
|
74
|
-
|
75
|
-
def model_of_relation(relation)
|
76
|
-
relation.model
|
77
|
-
end
|
78
|
-
|
79
|
-
def relation_class
|
80
|
-
::Sequel::Dataset
|
81
|
-
end
|
82
|
-
|
83
|
-
def object_class
|
84
|
-
::Sequel::Model
|
85
|
-
end
|
86
|
-
|
87
|
-
def load_scope_objects(*args)
|
88
|
-
super.all
|
89
|
-
end
|
90
|
-
end
|
91
|
-
end
|
92
|
-
end
|
93
|
-
end
|
data/lib/chewy/type/crutch.rb
DELETED
@@ -1,32 +0,0 @@
|
|
1
|
-
module Chewy
|
2
|
-
class Type
|
3
|
-
module Crutch
|
4
|
-
extend ActiveSupport::Concern
|
5
|
-
|
6
|
-
included do
|
7
|
-
class_attribute :_crutches
|
8
|
-
self._crutches = {}
|
9
|
-
end
|
10
|
-
|
11
|
-
class Crutches
|
12
|
-
def initialize(type, collection)
|
13
|
-
@type = type
|
14
|
-
@collection = collection
|
15
|
-
@type._crutches.each_key do |name|
|
16
|
-
singleton_class.class_eval <<-METHOD, __FILE__, __LINE__ + 1
|
17
|
-
def #{name}
|
18
|
-
@#{name} ||= @type._crutches[:#{name}].call @collection
|
19
|
-
end
|
20
|
-
METHOD
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
module ClassMethods
|
26
|
-
def crutch(name, &block)
|
27
|
-
self._crutches = _crutches.merge(name.to_sym => block)
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
32
|
-
end
|
@@ -1,122 +0,0 @@
|
|
1
|
-
module Chewy
|
2
|
-
class Type
|
3
|
-
module Import
|
4
|
-
# This class purpose is to build ES client-acceptable bulk
|
5
|
-
# request body from the passed objects for index and deletion.
|
6
|
-
# It handles parent-child relationships as well by fetching
|
7
|
-
# existing documents from ES, taking their `_parent` field and
|
8
|
-
# using it in the bulk body.
|
9
|
-
# If fields are passed - it creates partial update entries except for
|
10
|
-
# the cases when the type has parent and parent_id has been changed.
|
11
|
-
class BulkBuilder
|
12
|
-
# @param type [Chewy::Type] desired type
|
13
|
-
# @param index [Array<Object>] objects to index
|
14
|
-
# @param delete [Array<Object>] objects or ids to delete
|
15
|
-
# @param fields [Array<Symbol, String>] and array of fields for documents update
|
16
|
-
def initialize(type, index: [], delete: [], fields: [])
|
17
|
-
@type = type
|
18
|
-
@index = index
|
19
|
-
@delete = delete
|
20
|
-
@fields = fields.map!(&:to_sym)
|
21
|
-
end
|
22
|
-
|
23
|
-
# Returns ES API-ready bulk requiest body.
|
24
|
-
# @see https://github.com/elastic/elasticsearch-ruby/blob/master/elasticsearch-api/lib/elasticsearch/api/actions/bulk.rb
|
25
|
-
# @return [Array<Hash>] bulk body
|
26
|
-
def bulk_body
|
27
|
-
@bulk_body ||= @index.flat_map(&method(:index_entry)).concat(
|
28
|
-
@delete.flat_map(&method(:delete_entry))
|
29
|
-
)
|
30
|
-
end
|
31
|
-
|
32
|
-
# The only purpose of this method is to cache document ids for
|
33
|
-
# all the passed object for index to avoid ids recalculation.
|
34
|
-
#
|
35
|
-
# @return [Hash[String => Object]] an ids-objects index hash
|
36
|
-
def index_objects_by_id
|
37
|
-
@index_objects_by_id ||= index_object_ids.invert.stringify_keys!
|
38
|
-
end
|
39
|
-
|
40
|
-
private
|
41
|
-
|
42
|
-
def crutches
|
43
|
-
@crutches ||= Chewy::Type::Crutch::Crutches.new @type, @index
|
44
|
-
end
|
45
|
-
|
46
|
-
def parents
|
47
|
-
return unless type_root.parent_id
|
48
|
-
|
49
|
-
@parents ||= begin
|
50
|
-
ids = @index.map do |object|
|
51
|
-
object.respond_to?(:id) ? object.id : object
|
52
|
-
end
|
53
|
-
ids.concat(@delete.map do |object|
|
54
|
-
object.respond_to?(:id) ? object.id : object
|
55
|
-
end)
|
56
|
-
@type.filter(ids: {values: ids}).order('_doc').pluck(:_id, :_parent).to_h
|
57
|
-
end
|
58
|
-
end
|
59
|
-
|
60
|
-
def index_entry(object)
|
61
|
-
entry = {}
|
62
|
-
entry[:_id] = index_object_ids[object] if index_object_ids[object]
|
63
|
-
|
64
|
-
if parents
|
65
|
-
entry[:parent] = type_root.compose_parent(object)
|
66
|
-
parent = entry[:_id].present? && parents[entry[:_id].to_s]
|
67
|
-
end
|
68
|
-
|
69
|
-
if parent && entry[:parent].to_s != parent
|
70
|
-
entry[:data] = @type.compose(object, crutches)
|
71
|
-
[{delete: entry.except(:data).merge(parent: parent)}, {index: entry}]
|
72
|
-
elsif @fields.present?
|
73
|
-
return [] unless entry[:_id]
|
74
|
-
entry[:data] = {doc: @type.compose(object, crutches, fields: @fields)}
|
75
|
-
[{update: entry}]
|
76
|
-
else
|
77
|
-
entry[:data] = @type.compose(object, crutches)
|
78
|
-
[{index: entry}]
|
79
|
-
end
|
80
|
-
end
|
81
|
-
|
82
|
-
def delete_entry(object)
|
83
|
-
entry = {}
|
84
|
-
entry[:_id] = entry_id(object)
|
85
|
-
entry[:_id] ||= object.as_json
|
86
|
-
|
87
|
-
return [] if entry[:_id].blank?
|
88
|
-
|
89
|
-
if parents
|
90
|
-
parent = entry[:_id].present? && parents[entry[:_id].to_s]
|
91
|
-
return [] unless parent
|
92
|
-
entry[:parent] = parent
|
93
|
-
end
|
94
|
-
|
95
|
-
[{delete: entry}]
|
96
|
-
end
|
97
|
-
|
98
|
-
def entry_id(object)
|
99
|
-
if type_root.id
|
100
|
-
type_root.compose_id(object)
|
101
|
-
else
|
102
|
-
id = object.id if object.respond_to?(:id)
|
103
|
-
id ||= object[:id] || object['id'] if object.is_a?(Hash)
|
104
|
-
id = id.to_s if defined?(BSON) && id.is_a?(BSON::ObjectId)
|
105
|
-
id
|
106
|
-
end
|
107
|
-
end
|
108
|
-
|
109
|
-
def index_object_ids
|
110
|
-
@index_object_ids ||= @index.each_with_object({}) do |object, result|
|
111
|
-
id = entry_id(object)
|
112
|
-
result[object] = id if id.present?
|
113
|
-
end
|
114
|
-
end
|
115
|
-
|
116
|
-
def type_root
|
117
|
-
@type_root ||= @type.root
|
118
|
-
end
|
119
|
-
end
|
120
|
-
end
|
121
|
-
end
|
122
|
-
end
|
data/lib/chewy/type/observe.rb
DELETED
@@ -1,82 +0,0 @@
|
|
1
|
-
module Chewy
|
2
|
-
class Type
|
3
|
-
module Observe
|
4
|
-
extend ActiveSupport::Concern
|
5
|
-
|
6
|
-
module Helpers
|
7
|
-
def update_proc(type_name, *args, &block)
|
8
|
-
options = args.extract_options!
|
9
|
-
method = args.first
|
10
|
-
|
11
|
-
proc do
|
12
|
-
reference = if type_name.is_a?(Proc)
|
13
|
-
if type_name.arity.zero?
|
14
|
-
instance_exec(&type_name)
|
15
|
-
else
|
16
|
-
type_name.call(self)
|
17
|
-
end
|
18
|
-
else
|
19
|
-
type_name
|
20
|
-
end
|
21
|
-
|
22
|
-
type = Chewy.derive_type(reference)
|
23
|
-
|
24
|
-
next if Chewy.strategy.current.name == :bypass
|
25
|
-
|
26
|
-
backreference = if method && method.to_s == 'self'
|
27
|
-
self
|
28
|
-
elsif method
|
29
|
-
send(method)
|
30
|
-
else
|
31
|
-
instance_eval(&block)
|
32
|
-
end
|
33
|
-
|
34
|
-
type.update_index(backreference, options)
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
def extract_callback_options!(args)
|
39
|
-
options = args.extract_options!
|
40
|
-
result = options.each_key.with_object({}) do |key, hash|
|
41
|
-
hash[key] = options.delete(key) if %i[if unless].include?(key)
|
42
|
-
end
|
43
|
-
args.push(options) unless options.empty?
|
44
|
-
result
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
extend Helpers
|
49
|
-
|
50
|
-
module MongoidMethods
|
51
|
-
def update_index(type_name, *args, &block)
|
52
|
-
callback_options = Observe.extract_callback_options!(args)
|
53
|
-
update_proc = Observe.update_proc(type_name, *args, &block)
|
54
|
-
|
55
|
-
after_save(callback_options, &update_proc)
|
56
|
-
after_destroy(callback_options, &update_proc)
|
57
|
-
end
|
58
|
-
end
|
59
|
-
|
60
|
-
module ActiveRecordMethods
|
61
|
-
def update_index(type_name, *args, &block)
|
62
|
-
callback_options = Observe.extract_callback_options!(args)
|
63
|
-
update_proc = Observe.update_proc(type_name, *args, &block)
|
64
|
-
|
65
|
-
if Chewy.use_after_commit_callbacks
|
66
|
-
after_commit(**callback_options, &update_proc)
|
67
|
-
else
|
68
|
-
after_save(**callback_options, &update_proc)
|
69
|
-
after_destroy(**callback_options, &update_proc)
|
70
|
-
end
|
71
|
-
end
|
72
|
-
end
|
73
|
-
|
74
|
-
module ClassMethods
|
75
|
-
def update_index(objects, options = {})
|
76
|
-
Chewy.strategy.current.update(self, objects, options)
|
77
|
-
true
|
78
|
-
end
|
79
|
-
end
|
80
|
-
end
|
81
|
-
end
|
82
|
-
end
|
data/lib/chewy/type.rb
DELETED
@@ -1,120 +0,0 @@
|
|
1
|
-
require 'chewy/search'
|
2
|
-
require 'chewy/type/adapter/object'
|
3
|
-
require 'chewy/type/adapter/active_record'
|
4
|
-
require 'chewy/type/adapter/mongoid'
|
5
|
-
require 'chewy/type/adapter/sequel'
|
6
|
-
require 'chewy/type/mapping'
|
7
|
-
require 'chewy/type/wrapper'
|
8
|
-
require 'chewy/type/observe'
|
9
|
-
require 'chewy/type/actions'
|
10
|
-
require 'chewy/type/syncer'
|
11
|
-
require 'chewy/type/crutch'
|
12
|
-
require 'chewy/type/import'
|
13
|
-
require 'chewy/type/witchcraft'
|
14
|
-
|
15
|
-
module Chewy
|
16
|
-
class Type
|
17
|
-
IMPORT_OPTIONS_KEYS = %i[
|
18
|
-
batch_size bulk_size consistency direct_import journal
|
19
|
-
pipeline raw_import refresh replication
|
20
|
-
].freeze
|
21
|
-
|
22
|
-
include Search
|
23
|
-
include Mapping
|
24
|
-
include Wrapper
|
25
|
-
include Observe
|
26
|
-
include Actions
|
27
|
-
include Crutch
|
28
|
-
include Witchcraft
|
29
|
-
include Import
|
30
|
-
|
31
|
-
singleton_class.delegate :index_name, :derivable_index_name, :client, to: :index
|
32
|
-
|
33
|
-
class_attribute :_default_import_options
|
34
|
-
self._default_import_options = {}
|
35
|
-
|
36
|
-
class << self
|
37
|
-
# Chewy index current type belongs to. Defined inside `Chewy.create_type`
|
38
|
-
#
|
39
|
-
def index
|
40
|
-
raise NotImplementedError, 'Looks like this type was defined outside the index scope and `.index` method is undefined for it'
|
41
|
-
end
|
42
|
-
|
43
|
-
# Current type adapter. Defined inside `Chewy.create_type`, derived from
|
44
|
-
# `Chewy::Index.define_type` arguments.
|
45
|
-
#
|
46
|
-
def adapter
|
47
|
-
raise NotImplementedError
|
48
|
-
end
|
49
|
-
|
50
|
-
# Returns type name string
|
51
|
-
#
|
52
|
-
def type_name
|
53
|
-
adapter.type_name
|
54
|
-
end
|
55
|
-
|
56
|
-
# Appends type name to {Chewy::Index.derivable_name}
|
57
|
-
#
|
58
|
-
# @example
|
59
|
-
# class Namespace::UsersIndex < Chewy::Index
|
60
|
-
# define_type User
|
61
|
-
# end
|
62
|
-
# UsersIndex::User.derivable_name # => 'namespace/users#user'
|
63
|
-
#
|
64
|
-
# @see Chewy::Index.derivable_name
|
65
|
-
# @return [String, nil] derivable name or nil when it is impossible to calculate
|
66
|
-
def derivable_name
|
67
|
-
@derivable_name ||= [index.derivable_name, type_name].join('#') if index && index.derivable_name
|
68
|
-
end
|
69
|
-
|
70
|
-
# This method is an API shared with {Chewy::Index}, added for convenience.
|
71
|
-
#
|
72
|
-
# @return [Chewy::Type] array containing itself
|
73
|
-
def types
|
74
|
-
[self]
|
75
|
-
end
|
76
|
-
|
77
|
-
# Returns list of public class methods defined in current type
|
78
|
-
#
|
79
|
-
def scopes
|
80
|
-
public_methods - Chewy::Type.public_methods
|
81
|
-
end
|
82
|
-
|
83
|
-
def default_import_options(params)
|
84
|
-
params.assert_valid_keys(IMPORT_OPTIONS_KEYS)
|
85
|
-
self._default_import_options = _default_import_options.merge(params)
|
86
|
-
end
|
87
|
-
|
88
|
-
def method_missing(method, *args, &block)
|
89
|
-
if index.scopes.include?(method)
|
90
|
-
define_singleton_method method do |*method_args, &method_block|
|
91
|
-
all.scoping { index.public_send(method, *method_args, &method_block) }
|
92
|
-
end
|
93
|
-
send(method, *args, &block)
|
94
|
-
else
|
95
|
-
super
|
96
|
-
end
|
97
|
-
end
|
98
|
-
|
99
|
-
def respond_to_missing?(method, _)
|
100
|
-
index.scopes.include?(method) || super
|
101
|
-
end
|
102
|
-
|
103
|
-
def const_missing(name)
|
104
|
-
to_resolve = "#{self}::#{name}"
|
105
|
-
to_resolve[index.to_s] = ''
|
106
|
-
|
107
|
-
@__resolved_constants ||= {}
|
108
|
-
|
109
|
-
if to_resolve.empty? || @__resolved_constants[to_resolve]
|
110
|
-
super
|
111
|
-
else
|
112
|
-
@__resolved_constants[to_resolve] = true
|
113
|
-
to_resolve.constantize
|
114
|
-
end
|
115
|
-
rescue NotImplementedError
|
116
|
-
super
|
117
|
-
end
|
118
|
-
end
|
119
|
-
end
|
120
|
-
end
|
@@ -1,63 +0,0 @@
|
|
1
|
-
require 'active_support/callbacks'
|
2
|
-
|
3
|
-
module Sequel
|
4
|
-
module Plugins
|
5
|
-
# This Sequel plugin adds support for chewy's model-observing hook for
|
6
|
-
# updating indexes after model save or destroy.
|
7
|
-
#
|
8
|
-
# Usage:
|
9
|
-
#
|
10
|
-
# # Make all model subclasses support the `update_index` hook (called
|
11
|
-
# # before loading subclasses).
|
12
|
-
# Sequel::Model.plugin :chewy_observe
|
13
|
-
#
|
14
|
-
# # Make the Album class support the `update_index` hooks.
|
15
|
-
# Album.plugin :chewy_observe
|
16
|
-
#
|
17
|
-
# # Declare one or more `update_index` observers in model.
|
18
|
-
# class Album < Sequel::Model
|
19
|
-
# update_index('albums#album') { self }
|
20
|
-
# end
|
21
|
-
#
|
22
|
-
module ChewyObserve
|
23
|
-
extend ::Chewy::Type::Observe::Helpers
|
24
|
-
|
25
|
-
def self.apply(model)
|
26
|
-
model.instance_eval do
|
27
|
-
include ActiveSupport::Callbacks
|
28
|
-
define_callbacks :commit, :destroy_commit, :save, :destroy
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
# Class level methods for Sequel::Model
|
33
|
-
#
|
34
|
-
module ClassMethods
|
35
|
-
def update_index(type_name, *args, &block)
|
36
|
-
callback_options = ChewyObserve.extract_callback_options!(args)
|
37
|
-
update_proc = ChewyObserve.update_proc(type_name, *args, &block)
|
38
|
-
|
39
|
-
set_callback(:save, callback_options, &update_proc)
|
40
|
-
set_callback(:destroy, callback_options, &update_proc)
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
# Instance level methods for Sequel::Model
|
45
|
-
#
|
46
|
-
module InstanceMethods
|
47
|
-
def after_save
|
48
|
-
run_callbacks(:save) do
|
49
|
-
super
|
50
|
-
db.after_commit {} if Chewy.use_after_commit_callbacks
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
def after_destroy
|
55
|
-
run_callbacks(:destroy) do
|
56
|
-
super
|
57
|
-
db.after_commit {} if Chewy.use_after_commit_callbacks
|
58
|
-
end
|
59
|
-
end
|
60
|
-
end
|
61
|
-
end
|
62
|
-
end
|
63
|
-
end
|
@@ -1,63 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
shared_examples :will_paginate do |request_base_class|
|
4
|
-
before { Chewy.massacre }
|
5
|
-
|
6
|
-
before do
|
7
|
-
stub_index(:products) do
|
8
|
-
define_type(:product) do
|
9
|
-
field :name
|
10
|
-
field :age, type: 'integer'
|
11
|
-
end
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
|
-
let(:except_fields) { %w[_score _explanation] }
|
16
|
-
let(:request_class) do
|
17
|
-
Class.new(request_base_class).tap do |k|
|
18
|
-
k.include Chewy::Search::Pagination::WillPaginate
|
19
|
-
end
|
20
|
-
end
|
21
|
-
let(:search) { request_class.new(ProductsIndex).order(:age) }
|
22
|
-
|
23
|
-
specify { expect(search.total_pages).to eq(1) } # defaults to 1 on will_paginate
|
24
|
-
|
25
|
-
context do
|
26
|
-
let(:data) { Array.new(10) { |i| {id: i.next.to_s, name: "Name#{i.next}", age: 10 * i.next}.stringify_keys! } }
|
27
|
-
|
28
|
-
before { ProductsIndex::Product.import!(data.map { |h| double(h) }) }
|
29
|
-
before { allow(::WillPaginate).to receive_messages(per_page: 3) }
|
30
|
-
|
31
|
-
describe '#page' do
|
32
|
-
specify { expect(search.map { |e| e.attributes.except(*except_fields) }).to match_array(data) }
|
33
|
-
specify { expect(search.page(1).map { |e| e.attributes.except(*except_fields) }).to eq(data[0..2]) }
|
34
|
-
specify { expect(search.page(2).map { |e| e.attributes.except(*except_fields) }).to eq(data[3..5]) }
|
35
|
-
end
|
36
|
-
|
37
|
-
describe '#paginate' do
|
38
|
-
specify { expect(search.paginate(page: 2, per_page: 4).map { |e| e.attributes.except(*except_fields) }).to eq(data[4..7]) }
|
39
|
-
specify { expect(search.paginate(per_page: 2, page: 3).page(3).map { |e| e.attributes.except(*except_fields) }).to eq(data[4..5]) }
|
40
|
-
specify { expect(search.paginate(per_page: 5).map { |e| e.attributes.except(*except_fields) }).to eq(data[0..4]) }
|
41
|
-
specify { expect(search.paginate(per_page: 4).map { |e| e.attributes.except(*except_fields) }).to eq(data[0..3]) }
|
42
|
-
end
|
43
|
-
|
44
|
-
describe '#total_pages' do
|
45
|
-
specify { expect(search.paginate(page: 2, per_page: 5).total_pages).to eq(2) }
|
46
|
-
specify { expect(search.paginate(page: 3, per_page: 2).total_pages).to eq(5) }
|
47
|
-
end
|
48
|
-
|
49
|
-
describe '#total_entries' do
|
50
|
-
specify { expect(search.paginate(page: 1, per_page: 4).total_entries).to eq(10) }
|
51
|
-
specify { expect(search.query(range: {age: {gt: 20}}).limit(3).total_entries).to eq(8) }
|
52
|
-
end
|
53
|
-
|
54
|
-
describe '#load' do
|
55
|
-
specify { expect(search.paginate(per_page: 2, page: 1).load.first.age).to eq(10) }
|
56
|
-
specify { expect(search.paginate(per_page: 2, page: 3).load.first.age).to eq(50) }
|
57
|
-
specify { expect(search.paginate(per_page: 2, page: 3).load.page(2).load.first.age).to eq(30) }
|
58
|
-
|
59
|
-
specify { expect(search.paginate(per_page: 4, page: 1).load.total_count).to eq(10) }
|
60
|
-
specify { expect(search.paginate(per_page: 2, page: 3).load.total_pages).to eq(5) }
|
61
|
-
end
|
62
|
-
end
|
63
|
-
end
|