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.
Files changed (188) hide show
  1. checksums.yaml +4 -4
  2. data/.github/CODEOWNERS +1 -0
  3. data/.github/ISSUE_TEMPLATE/bug_report.md +39 -0
  4. data/.github/ISSUE_TEMPLATE/feature_request.md +20 -0
  5. data/.github/PULL_REQUEST_TEMPLATE.md +16 -0
  6. data/.github/dependabot.yml +42 -0
  7. data/.github/workflows/ruby.yml +60 -0
  8. data/.rubocop.yml +16 -8
  9. data/.rubocop_todo.yml +110 -22
  10. data/CHANGELOG.md +396 -105
  11. data/CODE_OF_CONDUCT.md +14 -0
  12. data/CONTRIBUTING.md +63 -0
  13. data/Gemfile +4 -10
  14. data/Guardfile +3 -1
  15. data/README.md +497 -275
  16. data/chewy.gemspec +5 -20
  17. data/gemfiles/base.gemfile +12 -0
  18. data/gemfiles/rails.6.1.activerecord.gemfile +10 -15
  19. data/gemfiles/rails.7.0.activerecord.gemfile +14 -0
  20. data/gemfiles/rails.7.1.activerecord.gemfile +14 -0
  21. data/lib/chewy/config.rb +60 -52
  22. data/lib/chewy/elastic_client.rb +31 -0
  23. data/lib/chewy/errors.rb +7 -10
  24. data/lib/chewy/fields/base.rb +79 -13
  25. data/lib/chewy/fields/root.rb +4 -14
  26. data/lib/chewy/index/actions.rb +54 -37
  27. data/lib/chewy/{type → index}/adapter/active_record.rb +30 -6
  28. data/lib/chewy/{type → index}/adapter/base.rb +2 -3
  29. data/lib/chewy/{type → index}/adapter/object.rb +27 -31
  30. data/lib/chewy/{type → index}/adapter/orm.rb +17 -18
  31. data/lib/chewy/index/aliases.rb +14 -5
  32. data/lib/chewy/index/crutch.rb +40 -0
  33. data/lib/chewy/index/import/bulk_builder.rb +311 -0
  34. data/lib/chewy/{type → index}/import/bulk_request.rb +6 -7
  35. data/lib/chewy/{type → index}/import/journal_builder.rb +11 -12
  36. data/lib/chewy/{type → index}/import/routine.rb +18 -17
  37. data/lib/chewy/{type → index}/import.rb +76 -32
  38. data/lib/chewy/{type → index}/mapping.rb +29 -34
  39. data/lib/chewy/index/observe/active_record_methods.rb +87 -0
  40. data/lib/chewy/index/observe/callback.rb +34 -0
  41. data/lib/chewy/index/observe.rb +17 -0
  42. data/lib/chewy/index/specification.rb +1 -0
  43. data/lib/chewy/{type → index}/syncer.rb +59 -59
  44. data/lib/chewy/{type → index}/witchcraft.rb +11 -7
  45. data/lib/chewy/{type → index}/wrapper.rb +2 -2
  46. data/lib/chewy/index.rb +67 -94
  47. data/lib/chewy/journal.rb +25 -14
  48. data/lib/chewy/log_subscriber.rb +5 -1
  49. data/lib/chewy/minitest/helpers.rb +86 -13
  50. data/lib/chewy/minitest/search_index_receiver.rb +24 -26
  51. data/lib/chewy/railtie.rb +6 -20
  52. data/lib/chewy/rake_helper.rb +169 -113
  53. data/lib/chewy/rspec/build_query.rb +12 -0
  54. data/lib/chewy/rspec/helpers.rb +55 -0
  55. data/lib/chewy/rspec/update_index.rb +55 -44
  56. data/lib/chewy/rspec.rb +2 -0
  57. data/lib/chewy/runtime/version.rb +1 -1
  58. data/lib/chewy/runtime.rb +1 -1
  59. data/lib/chewy/search/loader.rb +19 -41
  60. data/lib/chewy/search/parameters/collapse.rb +16 -0
  61. data/lib/chewy/search/parameters/concerns/query_storage.rb +2 -2
  62. data/lib/chewy/search/parameters/ignore_unavailable.rb +27 -0
  63. data/lib/chewy/search/parameters/indices.rb +13 -58
  64. data/lib/chewy/search/parameters/knn.rb +16 -0
  65. data/lib/chewy/search/parameters/order.rb +6 -19
  66. data/lib/chewy/search/parameters/source.rb +5 -1
  67. data/lib/chewy/search/parameters/storage.rb +1 -1
  68. data/lib/chewy/search/parameters/track_total_hits.rb +16 -0
  69. data/lib/chewy/search/parameters.rb +6 -4
  70. data/lib/chewy/search/query_proxy.rb +9 -2
  71. data/lib/chewy/search/request.rb +169 -134
  72. data/lib/chewy/search/response.rb +5 -5
  73. data/lib/chewy/search/scoping.rb +7 -8
  74. data/lib/chewy/search/scrolling.rb +13 -13
  75. data/lib/chewy/search.rb +9 -19
  76. data/lib/chewy/stash.rb +19 -30
  77. data/lib/chewy/strategy/active_job.rb +1 -1
  78. data/lib/chewy/strategy/atomic_no_refresh.rb +18 -0
  79. data/lib/chewy/strategy/base.rb +10 -0
  80. data/lib/chewy/strategy/delayed_sidekiq/scheduler.rb +168 -0
  81. data/lib/chewy/strategy/delayed_sidekiq/worker.rb +76 -0
  82. data/lib/chewy/strategy/delayed_sidekiq.rb +30 -0
  83. data/lib/chewy/strategy/lazy_sidekiq.rb +64 -0
  84. data/lib/chewy/strategy/sidekiq.rb +2 -1
  85. data/lib/chewy/strategy.rb +6 -19
  86. data/lib/chewy/version.rb +1 -1
  87. data/lib/chewy.rb +39 -86
  88. data/lib/generators/chewy/install_generator.rb +1 -1
  89. data/lib/tasks/chewy.rake +36 -32
  90. data/migration_guide.md +46 -8
  91. data/spec/chewy/config_spec.rb +16 -41
  92. data/spec/chewy/elastic_client_spec.rb +26 -0
  93. data/spec/chewy/fields/base_spec.rb +432 -147
  94. data/spec/chewy/fields/root_spec.rb +20 -28
  95. data/spec/chewy/fields/time_fields_spec.rb +5 -5
  96. data/spec/chewy/index/actions_spec.rb +368 -59
  97. data/spec/chewy/{type → index}/adapter/active_record_spec.rb +156 -40
  98. data/spec/chewy/{type → index}/adapter/object_spec.rb +21 -6
  99. data/spec/chewy/index/aliases_spec.rb +3 -3
  100. data/spec/chewy/index/import/bulk_builder_spec.rb +494 -0
  101. data/spec/chewy/{type → index}/import/bulk_request_spec.rb +5 -12
  102. data/spec/chewy/{type → index}/import/journal_builder_spec.rb +9 -19
  103. data/spec/chewy/{type → index}/import/routine_spec.rb +19 -19
  104. data/spec/chewy/{type → index}/import_spec.rb +164 -98
  105. data/spec/chewy/index/mapping_spec.rb +135 -0
  106. data/spec/chewy/index/observe/active_record_methods_spec.rb +68 -0
  107. data/spec/chewy/index/observe/callback_spec.rb +139 -0
  108. data/spec/chewy/index/observe_spec.rb +143 -0
  109. data/spec/chewy/index/settings_spec.rb +3 -1
  110. data/spec/chewy/index/specification_spec.rb +20 -30
  111. data/spec/chewy/{type → index}/syncer_spec.rb +14 -19
  112. data/spec/chewy/{type → index}/witchcraft_spec.rb +20 -22
  113. data/spec/chewy/index/wrapper_spec.rb +100 -0
  114. data/spec/chewy/index_spec.rb +60 -105
  115. data/spec/chewy/journal_spec.rb +25 -74
  116. data/spec/chewy/minitest/helpers_spec.rb +123 -15
  117. data/spec/chewy/minitest/search_index_receiver_spec.rb +28 -30
  118. data/spec/chewy/multi_search_spec.rb +4 -5
  119. data/spec/chewy/rake_helper_spec.rb +315 -55
  120. data/spec/chewy/rspec/build_query_spec.rb +34 -0
  121. data/spec/chewy/rspec/helpers_spec.rb +61 -0
  122. data/spec/chewy/rspec/update_index_spec.rb +74 -71
  123. data/spec/chewy/runtime_spec.rb +2 -2
  124. data/spec/chewy/search/loader_spec.rb +19 -53
  125. data/spec/chewy/search/pagination/kaminari_examples.rb +4 -6
  126. data/spec/chewy/search/pagination/kaminari_spec.rb +2 -2
  127. data/spec/chewy/search/parameters/collapse_spec.rb +5 -0
  128. data/spec/chewy/search/parameters/ignore_unavailable_spec.rb +67 -0
  129. data/spec/chewy/search/parameters/indices_spec.rb +26 -117
  130. data/spec/chewy/search/parameters/knn_spec.rb +5 -0
  131. data/spec/chewy/search/parameters/order_spec.rb +18 -11
  132. data/spec/chewy/search/parameters/query_storage_examples.rb +67 -21
  133. data/spec/chewy/search/parameters/search_after_spec.rb +4 -1
  134. data/spec/chewy/search/parameters/source_spec.rb +8 -2
  135. data/spec/chewy/search/parameters/track_total_hits_spec.rb +5 -0
  136. data/spec/chewy/search/parameters_spec.rb +18 -4
  137. data/spec/chewy/search/query_proxy_spec.rb +68 -17
  138. data/spec/chewy/search/request_spec.rb +292 -110
  139. data/spec/chewy/search/response_spec.rb +12 -12
  140. data/spec/chewy/search/scrolling_spec.rb +10 -17
  141. data/spec/chewy/search_spec.rb +40 -34
  142. data/spec/chewy/stash_spec.rb +9 -21
  143. data/spec/chewy/strategy/active_job_spec.rb +16 -16
  144. data/spec/chewy/strategy/atomic_no_refresh_spec.rb +60 -0
  145. data/spec/chewy/strategy/atomic_spec.rb +9 -10
  146. data/spec/chewy/strategy/delayed_sidekiq_spec.rb +208 -0
  147. data/spec/chewy/strategy/lazy_sidekiq_spec.rb +214 -0
  148. data/spec/chewy/strategy/sidekiq_spec.rb +12 -12
  149. data/spec/chewy/strategy_spec.rb +19 -15
  150. data/spec/chewy_spec.rb +24 -107
  151. data/spec/spec_helper.rb +3 -22
  152. data/spec/support/active_record.rb +25 -7
  153. metadata +78 -339
  154. data/.circleci/config.yml +0 -240
  155. data/Appraisals +0 -81
  156. data/gemfiles/rails.5.2.activerecord.gemfile +0 -17
  157. data/gemfiles/rails.5.2.mongoid.6.4.gemfile +0 -17
  158. data/gemfiles/rails.6.0.activerecord.gemfile +0 -17
  159. data/gemfiles/sequel.4.45.gemfile +0 -11
  160. data/lib/chewy/backports/deep_dup.rb +0 -46
  161. data/lib/chewy/backports/duplicable.rb +0 -91
  162. data/lib/chewy/search/pagination/will_paginate.rb +0 -43
  163. data/lib/chewy/search/parameters/types.rb +0 -20
  164. data/lib/chewy/strategy/resque.rb +0 -27
  165. data/lib/chewy/strategy/shoryuken.rb +0 -40
  166. data/lib/chewy/type/actions.rb +0 -43
  167. data/lib/chewy/type/adapter/mongoid.rb +0 -67
  168. data/lib/chewy/type/adapter/sequel.rb +0 -93
  169. data/lib/chewy/type/crutch.rb +0 -32
  170. data/lib/chewy/type/import/bulk_builder.rb +0 -122
  171. data/lib/chewy/type/observe.rb +0 -82
  172. data/lib/chewy/type.rb +0 -120
  173. data/lib/sequel/plugins/chewy_observe.rb +0 -63
  174. data/spec/chewy/search/pagination/will_paginate_examples.rb +0 -63
  175. data/spec/chewy/search/pagination/will_paginate_spec.rb +0 -23
  176. data/spec/chewy/search/parameters/types_spec.rb +0 -5
  177. data/spec/chewy/strategy/resque_spec.rb +0 -46
  178. data/spec/chewy/strategy/shoryuken_spec.rb +0 -70
  179. data/spec/chewy/type/actions_spec.rb +0 -50
  180. data/spec/chewy/type/adapter/mongoid_spec.rb +0 -372
  181. data/spec/chewy/type/adapter/sequel_spec.rb +0 -472
  182. data/spec/chewy/type/import/bulk_builder_spec.rb +0 -194
  183. data/spec/chewy/type/mapping_spec.rb +0 -175
  184. data/spec/chewy/type/observe_spec.rb +0 -137
  185. data/spec/chewy/type/wrapper_spec.rb +0 -100
  186. data/spec/chewy/type_spec.rb +0 -55
  187. data/spec/support/mongoid.rb +0 -93
  188. data/spec/support/sequel.rb +0 -80
@@ -0,0 +1,64 @@
1
+ module Chewy
2
+ class Strategy
3
+ # The strategy works the same way as sidekiq, but performs
4
+ # async evaluation of all index callbacks on model create and update
5
+ # driven by sidekiq
6
+ #
7
+ # Chewy.strategy(:lazy_sidekiq) do
8
+ # User.all.map(&:save) # Does nothing here
9
+ # Post.all.map(&:save) # And here
10
+ # # It schedules import of all the changed users and posts right here
11
+ # end
12
+ #
13
+ class LazySidekiq < Sidekiq
14
+ class IndicesUpdateWorker
15
+ include ::Sidekiq::Worker
16
+
17
+ def perform(models)
18
+ Chewy.strategy(strategy) do
19
+ models.each do |model_type, model_ids|
20
+ model_type.constantize.where(id: model_ids).each(&:run_chewy_callbacks)
21
+ end
22
+ end
23
+ end
24
+
25
+ private
26
+
27
+ def strategy
28
+ Chewy.disable_refresh_async ? :atomic_no_refresh : :atomic
29
+ end
30
+ end
31
+
32
+ def initialize
33
+ # Use parent's @stash to store destroyed records, since callbacks for them have to
34
+ # be run immediately on the strategy block end because we won't be able to fetch
35
+ # records further in IndicesUpdateWorker. This will be done by avoiding of
36
+ # LazySidekiq#update_chewy_indices call and calling LazySidekiq#update instead.
37
+ super
38
+
39
+ # @lazy_stash is used to store all the lazy evaluated callbacks with call of
40
+ # strategy's #update_chewy_indices.
41
+ @lazy_stash = {}
42
+ end
43
+
44
+ def leave
45
+ # Fallback to Sidekiq#leave implementation for destroyed records stored in @stash.
46
+ super
47
+
48
+ # Proceed with other records stored in @lazy_stash
49
+ return if @lazy_stash.empty?
50
+
51
+ ::Sidekiq::Client.push(
52
+ 'queue' => sidekiq_queue,
53
+ 'class' => Chewy::Strategy::LazySidekiq::IndicesUpdateWorker,
54
+ 'args' => [@lazy_stash]
55
+ )
56
+ end
57
+
58
+ def update_chewy_indices(object)
59
+ @lazy_stash[object.class.name] ||= []
60
+ @lazy_stash[object.class.name] |= Array.wrap(object.id)
61
+ end
62
+ end
63
+ end
64
+ end
@@ -15,13 +15,14 @@ module Chewy
15
15
 
16
16
  def perform(type, ids, options = {})
17
17
  options[:refresh] = !Chewy.disable_refresh_async if Chewy.disable_refresh_async
18
- type.constantize.import!(ids, options)
18
+ type.constantize.import!(ids, **options)
19
19
  end
20
20
  end
21
21
 
22
22
  def leave
23
23
  @stash.each do |type, ids|
24
24
  next if ids.empty?
25
+
25
26
  ::Sidekiq::Client.push(
26
27
  'queue' => sidekiq_queue,
27
28
  'class' => Chewy::Strategy::Sidekiq::Worker,
@@ -2,24 +2,13 @@ require 'chewy/strategy/base'
2
2
  require 'chewy/strategy/bypass'
3
3
  require 'chewy/strategy/urgent'
4
4
  require 'chewy/strategy/atomic'
5
-
6
- begin
7
- require 'resque'
8
- require 'chewy/strategy/resque'
9
- rescue LoadError
10
- nil
11
- end
5
+ require 'chewy/strategy/atomic_no_refresh'
12
6
 
13
7
  begin
14
8
  require 'sidekiq'
15
9
  require 'chewy/strategy/sidekiq'
16
- rescue LoadError
17
- nil
18
- end
19
-
20
- begin
21
- require 'shoryuken'
22
- require 'chewy/strategy/shoryuken'
10
+ require 'chewy/strategy/lazy_sidekiq'
11
+ require 'chewy/strategy/delayed_sidekiq'
23
12
  rescue LoadError
24
13
  nil
25
14
  end
@@ -60,6 +49,7 @@ module Chewy
60
49
 
61
50
  def pop
62
51
  raise "Can't pop root strategy" if @stack.one?
52
+
63
53
  result = @stack.pop.tap(&:leave)
64
54
  debug "[#{@stack.size}] -> #{result.name}, now #{current.name}" if @stack.size > 1
65
55
  result
@@ -75,17 +65,14 @@ module Chewy
75
65
  private
76
66
 
77
67
  def debug(string)
78
- return unless Chewy.logger && Chewy.logger.debug?
68
+ return unless Chewy.logger&.debug?
69
+
79
70
  line = caller.detect { |l| l !~ %r{lib/chewy/strategy.rb:|lib/chewy.rb:} }
80
71
  Chewy.logger.debug(["Chewy strategies stack: #{string}", line.sub(/:in\s.+$/, '')].join(' @ '))
81
72
  end
82
73
 
83
74
  def resolve(name)
84
75
  "Chewy::Strategy::#{name.to_s.camelize}".safe_constantize or raise "Can't find update strategy `#{name}`"
85
- rescue NameError => ex
86
- # WORKAROUND: Strange behavior of `safe_constantize` with mongoid gem
87
- raise "Can't find update strategy `#{name}`" if ex.name.to_s.demodulize == name.to_s.camelize
88
- raise
89
76
  end
90
77
  end
91
78
  end
data/lib/chewy/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Chewy
2
- VERSION = '6.0.0'.freeze
2
+ VERSION = '7.6.0'.freeze
3
3
  end
data/lib/chewy.rb CHANGED
@@ -1,21 +1,22 @@
1
+ require 'active_support'
1
2
  require 'active_support/version'
2
3
  require 'active_support/concern'
3
4
  require 'active_support/deprecation'
4
5
  require 'active_support/json'
5
6
  require 'active_support/log_subscriber'
6
7
 
8
+ require 'active_support/isolated_execution_state' if ActiveSupport::VERSION::MAJOR >= 7
7
9
  require 'active_support/core_ext/array/access'
8
10
  require 'active_support/core_ext/array/wrap'
9
11
  require 'active_support/core_ext/enumerable'
10
12
  require 'active_support/core_ext/hash/reverse_merge'
13
+ require 'active_support/core_ext/hash/keys'
11
14
  require 'active_support/core_ext/numeric/time'
12
15
  require 'active_support/core_ext/numeric/bytes'
13
16
  require 'active_support/core_ext/object/blank'
14
17
  require 'active_support/core_ext/object/inclusion'
15
18
  require 'active_support/core_ext/string/inflections'
16
19
 
17
- require 'i18n/core_ext/hash'
18
- require 'chewy/backports/deep_dup' unless Object.respond_to?(:deep_dup)
19
20
  require 'singleton'
20
21
  require 'base64'
21
22
 
@@ -29,20 +30,12 @@ end
29
30
 
30
31
  try_require 'kaminari'
31
32
  try_require 'kaminari/core'
32
- try_require 'will_paginate'
33
- try_require 'will_paginate/collection'
34
33
  try_require 'parallel'
35
34
 
36
35
  ActiveSupport.on_load(:active_record) do
37
- try_require 'will_paginate/active_record'
38
36
  try_require 'kaminari/activerecord'
39
37
  end
40
38
 
41
- ActiveSupport.on_load(:mongoid) do
42
- try_require 'will_paginate/mongoid'
43
- try_require 'kaminari/mongoid'
44
- end
45
-
46
39
  require 'chewy/version'
47
40
  require 'chewy/errors'
48
41
  require 'chewy/config'
@@ -52,105 +45,60 @@ require 'chewy/runtime'
52
45
  require 'chewy/log_subscriber'
53
46
  require 'chewy/strategy'
54
47
  require 'chewy/index'
55
- require 'chewy/type'
56
48
  require 'chewy/fields/base'
57
49
  require 'chewy/fields/root'
58
50
  require 'chewy/journal'
59
- require 'chewy/railtie' if defined?(::Rails::Railtie)
51
+ require 'chewy/railtie' if defined?(Rails::Railtie)
52
+ require 'chewy/elastic_client'
60
53
 
61
54
  ActiveSupport.on_load(:active_record) do
62
- extend Chewy::Type::Observe::ActiveRecordMethods
63
- end
64
-
65
- ActiveSupport.on_load(:mongoid) do
66
- module Mongoid
67
- module Document
68
- module ClassMethods
69
- include Chewy::Type::Observe::MongoidMethods
70
- end
71
- end
72
- end
55
+ include Chewy::Index::Observe::ActiveRecordMethods
73
56
  end
74
57
 
75
58
  module Chewy
76
59
  @adapters = [
77
- Chewy::Type::Adapter::ActiveRecord,
78
- Chewy::Type::Adapter::Mongoid,
79
- Chewy::Type::Adapter::Sequel,
80
- Chewy::Type::Adapter::Object
60
+ Chewy::Index::Adapter::ActiveRecord,
61
+ Chewy::Index::Adapter::Object
81
62
  ]
82
63
 
83
64
  class << self
84
65
  attr_accessor :adapters
85
66
 
86
- # Derives a single type for the passed string identifier if possible.
87
- #
88
- # @example
89
- # Chewy.derive_types(UsersIndex::User) # => UsersIndex::User
90
- # Chewy.derive_types('namespace/users') # => Namespace::UsersIndex::User
91
- # Chewy.derive_types('places') # => raises Chewy::UnderivableType
92
- # Chewy.derive_types('places#city') # => PlacesIndex::City
93
- #
94
- # @param name [String, Chewy::Type] string type identifier
95
- # @raise [Chewy::UnderivableType] in cases when it is impossble to find index or type or more than one type found
96
- # @return [Chewy::Type] an array of derived types
97
- def derive_type(name)
98
- return name if name.is_a?(Class) && name < Chewy::Type
99
-
100
- types = derive_types(name)
101
- raise Chewy::UnderivableType, "Index `#{types.first.index}` has more than one type, please specify type via `#{types.first.index.derivable_name}#type_name`" unless types.one?
102
- types.first
67
+ # A thread-local variables accessor
68
+ # @return [Hash]
69
+ def current
70
+ unless Thread.current.thread_variable?(:chewy)
71
+ Thread.current.thread_variable_set(:chewy, {})
72
+ end
73
+
74
+ Thread.current.thread_variable_get(:chewy)
103
75
  end
104
76
 
105
- # Derives all the types for the passed string identifier if possible.
77
+ # Derives an index for the passed string identifier if possible.
106
78
  #
107
79
  # @example
108
- # Chewy.derive_types('namespace/users') # => [Namespace::UsersIndex::User]
109
- # Chewy.derive_types('places') # => [PlacesIndex::City, PlacesIndex::Country]
110
- # Chewy.derive_types('places#city') # => [PlacesIndex::City]
80
+ # Chewy.derive_name(UsersIndex) # => UsersIndex
81
+ # Chewy.derive_name('namespace/users') # => Namespace::UsersIndex
82
+ # Chewy.derive_name('missing') # => raises Chewy::UndefinedIndex
111
83
  #
112
- # @param from [String] string type identifier
113
- # @raise [Chewy::UnderivableType] in cases when it is impossible to find index or type
114
- # @return [Array<Chewy::Type>] an array of derived types
115
- def derive_types(from)
116
- return from.types if from.is_a?(Class) && (from < Chewy::Index || from < Chewy::Type)
84
+ # @param index_name [String, Chewy::Index] index identifier or class
85
+ # @raise [Chewy::UndefinedIndex] in cases when it is impossible to find index
86
+ # @return [Chewy::Index]
87
+ def derive_name(index_name)
88
+ return index_name if index_name.is_a?(Class) && index_name < Chewy::Index
117
89
 
118
- index_name, type_name = from.split('#', 2)
119
90
  class_name = "#{index_name.camelize.gsub(/Index\z/, '')}Index"
120
91
  index = class_name.safe_constantize
121
- raise Chewy::UnderivableType, "Can not find index named `#{class_name}`" unless index && index < Chewy::Index
122
- if type_name.present?
123
- type = index.type_hash[type_name] or raise Chewy::UnderivableType, "Index `#{class_name}` doesn`t have type named `#{type_name}`"
124
- [type]
125
- else
126
- index.types
127
- end
128
- end
129
-
130
- # Creates Chewy::Type ancestor defining index and adapter methods.
131
- #
132
- def create_type(index, target, options = {}, &block)
133
- type = Class.new(Chewy::Type)
134
-
135
- adapter = adapters.find { |klass| klass.accepts?(target) }.new(target, **options)
136
92
 
137
- index.const_set(adapter.name, type)
138
- type.send(:define_singleton_method, :index) { index }
139
- type.send(:define_singleton_method, :adapter) { adapter }
93
+ return index if index && index < Chewy::Index
140
94
 
141
- type.class_eval(&block) if block
142
- type
95
+ raise Chewy::UndefinedIndex, "Can not find index named `#{class_name}`"
143
96
  end
144
97
 
145
98
  # Main elasticsearch-ruby client instance
146
99
  #
147
100
  def client
148
- Thread.current[:chewy_client] ||= begin
149
- client_configuration = configuration.deep_dup
150
- client_configuration.delete(:prefix) # used by Chewy, not relevant to Elasticsearch::Client
151
- block = client_configuration[:transport_options].try(:delete, :proc)
152
- ::Elasticsearch::Client.new(client_configuration, &block)
153
- end
101
+ Chewy.current[:chewy_client] ||= Chewy::ElasticClient.new
154
102
  end
155
103
 
156
104
  # Sends wait_for_status request to ElasticSearch with status
@@ -159,7 +107,9 @@ module Chewy
159
107
  # Does nothing in case of config `wait_for_status` is undefined.
160
108
  #
161
109
  def wait_for_status
162
- client.cluster.health wait_for_status: Chewy.configuration[:wait_for_status] if Chewy.configuration[:wait_for_status].present?
110
+ if Chewy.configuration[:wait_for_status].present?
111
+ client.cluster.health wait_for_status: Chewy.configuration[:wait_for_status]
112
+ end
163
113
  end
164
114
 
165
115
  # Deletes all corresponding indexes with current prefix from ElasticSearch.
@@ -195,15 +145,15 @@ module Chewy
195
145
  # city3.do_update! # index updated again
196
146
  #
197
147
  def strategy(name = nil, &block)
198
- Thread.current[:chewy_strategy] ||= Chewy::Strategy.new
148
+ Chewy.current[:chewy_strategy] ||= Chewy::Strategy.new
199
149
  if name
200
150
  if block
201
- Thread.current[:chewy_strategy].wrap name, &block
151
+ Chewy.current[:chewy_strategy].wrap name, &block
202
152
  else
203
- Thread.current[:chewy_strategy].push name
153
+ Chewy.current[:chewy_strategy].push name
204
154
  end
205
155
  else
206
- Thread.current[:chewy_strategy]
156
+ Chewy.current[:chewy_strategy]
207
157
  end
208
158
  end
209
159
 
@@ -227,7 +177,10 @@ module Chewy
227
177
 
228
178
  def eager_load!
229
179
  return unless defined?(Chewy::Railtie)
230
- dirs = Chewy::Railtie.all_engines.map { |engine| engine.paths[Chewy.configuration[:indices_path]] }.compact.map(&:existent).flatten.uniq
180
+
181
+ dirs = Chewy::Railtie.all_engines.map do |engine|
182
+ engine.paths[Chewy.configuration[:indices_path]]
183
+ end.compact.map(&:existent).flatten.uniq
231
184
 
232
185
  dirs.each do |dir|
233
186
  Dir.glob(File.join(dir, '**/*.rb')).each do |file|
@@ -1,7 +1,7 @@
1
1
  module Chewy
2
2
  module Generators
3
3
  class InstallGenerator < Rails::Generators::Base
4
- source_root File.expand_path('../../templates', __FILE__)
4
+ source_root File.expand_path('../templates', __dir__)
5
5
 
6
6
  def copy_configuration
7
7
  template 'chewy.yml', 'config/chewy.yml'
data/lib/tasks/chewy.rake CHANGED
@@ -23,22 +23,22 @@ end
23
23
  namespace :chewy do
24
24
  desc 'Destroys, recreates and imports data for the specified indexes or all of them'
25
25
  task reset: :environment do |_task, args|
26
- Chewy::RakeHelper.reset(parse_classes(args.extras))
26
+ Chewy::RakeHelper.reset(**parse_classes(args.extras))
27
27
  end
28
28
 
29
29
  desc 'Resets data for the specified indexes or all of them only if the index specification is changed'
30
30
  task upgrade: :environment do |_task, args|
31
- Chewy::RakeHelper.upgrade(parse_classes(args.extras))
31
+ Chewy::RakeHelper.upgrade(**parse_classes(args.extras))
32
32
  end
33
33
 
34
34
  desc 'Updates data for the specified indexes/types or all of them'
35
35
  task update: :environment do |_task, args|
36
- Chewy::RakeHelper.update(parse_classes(args.extras))
36
+ Chewy::RakeHelper.update(**parse_classes(args.extras))
37
37
  end
38
38
 
39
39
  desc 'Synchronizes data for the specified indexes/types or all of them'
40
40
  task sync: :environment do |_task, args|
41
- Chewy::RakeHelper.sync(parse_classes(args.extras))
41
+ Chewy::RakeHelper.sync(**parse_classes(args.extras))
42
42
  end
43
43
 
44
44
  desc 'Resets all the indexes with the specification changed and synchronizes the rest of them'
@@ -47,25 +47,40 @@ namespace :chewy do
47
47
  Chewy::RakeHelper.sync(except: processed)
48
48
  end
49
49
 
50
+ desc 'Reindex data from source index to destination index'
51
+ task :reindex, %i[source dest] => :environment do |_task, args|
52
+ Chewy::RakeHelper.reindex(source: args[:source], dest: args[:dest])
53
+ end
54
+
55
+ desc 'Update mapping of exising index with body hash'
56
+ task :update_mapping, %i[index_name] => :environment do |_task, args|
57
+ Chewy::RakeHelper.update_mapping(name: args[:index_name])
58
+ end
59
+
60
+ desc 'Creates missing indexes'
61
+ task create_missing_indexes: :environment do
62
+ Chewy::RakeHelper.create_missing_indexes!
63
+ end
64
+
50
65
  namespace :parallel do
51
66
  desc 'Parallel version of `rake chewy:reset`'
52
67
  task reset: :environment do |_task, args|
53
- Chewy::RakeHelper.reset(parse_parallel_args(args.extras))
68
+ Chewy::RakeHelper.reset(**parse_parallel_args(args.extras))
54
69
  end
55
70
 
56
71
  desc 'Parallel version of `rake chewy:upgrade`'
57
72
  task upgrade: :environment do |_task, args|
58
- Chewy::RakeHelper.upgrade(parse_parallel_args(args.extras))
73
+ Chewy::RakeHelper.upgrade(**parse_parallel_args(args.extras))
59
74
  end
60
75
 
61
76
  desc 'Parallel version of `rake chewy:update`'
62
77
  task update: :environment do |_task, args|
63
- Chewy::RakeHelper.update(parse_parallel_args(args.extras))
78
+ Chewy::RakeHelper.update(**parse_parallel_args(args.extras))
64
79
  end
65
80
 
66
81
  desc 'Parallel version of `rake chewy:sync`'
67
82
  task sync: :environment do |_task, args|
68
- Chewy::RakeHelper.sync(parse_parallel_args(args.extras))
83
+ Chewy::RakeHelper.sync(**parse_parallel_args(args.extras))
69
84
  end
70
85
 
71
86
  desc 'Parallel version of `rake chewy:deploy`'
@@ -77,36 +92,25 @@ namespace :chewy do
77
92
  end
78
93
 
79
94
  namespace :journal do
95
+ desc 'Create manually journal, useful when `skip_journal_creation_on_import` is used'
96
+ task create: :environment do |_task, _args|
97
+ Chewy::RakeHelper.journal_create
98
+ end
99
+
80
100
  desc 'Applies changes that were done after the specified time for the specified indexes/types or all of them'
81
101
  task apply: :environment do |_task, args|
82
- Chewy::RakeHelper.journal_apply(parse_journal_args(args.extras))
102
+ Chewy::RakeHelper.journal_apply(**parse_journal_args(args.extras))
83
103
  end
84
104
 
85
105
  desc 'Removes journal records created before the specified timestamp for the specified indexes/types or all of them'
86
106
  task clean: :environment do |_task, args|
87
- Chewy::RakeHelper.journal_clean(parse_journal_args(args.extras))
107
+ delete_options = Chewy::RakeHelper.delete_by_query_options_from_env(ENV)
108
+ Chewy::RakeHelper.journal_clean(
109
+ **[
110
+ parse_journal_args(args.extras),
111
+ {delete_by_query_options: delete_options}
112
+ ].reduce({}, :merge)
113
+ )
88
114
  end
89
115
  end
90
-
91
- task apply_changes_from: :environment do |_task, args|
92
- ActiveSupport::Deprecation.warn '`rake chewy:apply_changes_from` is deprecated and will be removed soon, use `rake chewy:journal:apply` instead'
93
-
94
- Chewy::RakeHelper.subscribed_task_stats do
95
- params = args.extras
96
-
97
- if params.empty?
98
- puts 'Please specify a timestamp like chewy:apply_changes_from[1469528705]'
99
- else
100
- timestamp, retries = params
101
- time = Time.at(timestamp.to_i)
102
- Chewy::Journal.new.apply(time, retries: (retries.to_i if retries))
103
- end
104
- end
105
- end
106
-
107
- task clean_journal: :environment do |_task, args|
108
- ActiveSupport::Deprecation.warn '`rake chewy:clean_journal` is deprecated and will be removed soon, use `rake chewy:journal:clean` instead'
109
-
110
- Chewy::Journal.new.clean(args.extras.first)
111
- end
112
116
  end
data/migration_guide.md CHANGED
@@ -1,18 +1,56 @@
1
1
  # Migration guide
2
2
 
3
- ## Chewy 5 / ES 5 to Chewy 6 / ES 6
3
+ This document outlines the steps you need to take when migrating between major versions of
4
+ Chewy and Elasticsearch. For simplicity's sake the guide will assume that you're using
5
+ Chewy alongside a matching Elasticsearch version.
4
6
 
5
- In order to upgrade chewy5/ES5 to chewy6/ES6 in the most seamless manner you have to:
6
- * Upgrade to the latest 5.x stable releases: Chewy 5.2, ES 5.6
7
+ ## Chewy 6/Elasticsearch 6 to Chewy 7/Elasticsearch 7
8
+
9
+ In order to upgrade Chewy 6/Elasticsearch 6 to Chewy 7/Elasticsearch 7 in the most seamless manner you have to:
10
+
11
+ * Upgrade to the latest 6.x stable releases, namely Chewy 6.0, Elasticsearch 6.8
12
+ * Study carefully [Breaking changes in 7.0](https://www.elastic.co/guide/en/elasticsearch/reference/7.17/breaking-changes-7.0.html), make sure your application conforms.
13
+ * Run your test suite on Chewy 7.0 / Elasticsearch 7
14
+ * Run manual tests on Chewy 7.0 / Elasticsearch 7
15
+ * Upgrade to Chewy 7.0
16
+ * The “total hits” counter is an integer for ES versions < 7 and an object (hash) for the versions starting from 7.0.0. Elasticsearch added a special option, `rest_total_hits_as_int`, to ease the upgrade, that could be appended to any request and results in the old “total hits” format. Unfortunately, this option is not recognized by ES versions prior to 7.0.0, which means that we have to check the version to decide if we need this option.
17
+ Normally Chewy does memoization of the current ES version, but this might be inappropriate for the upgrade, as the version changes live.
18
+ To handle that we have 2 versions of Chewy for this stage of the upgrade: 7.0.0 and 7.0.1. Version 7.0.0 does the memoization and version 7.0.1 requests the current version on every search request.
19
+ * You can use the 7.0.0 version if it's fine for you to have an application restart immediately after ES cluster upgrade.
20
+ * If you're using the 7.0.1 version you might be interested in keeping the timeframe between this step and updating to Chewy 7.1 as small as possible, as version 7.0.1 skips ES version memoization for search requests to help dynamically detect ES version. This leads to an extra version request on each search request, i.e. could affect the overall performance/latency of the search and a load of ES cluster.
21
+ * Perform a [rolling upgrade](https://www.elastic.co/guide/en/elasticsearch/reference//rolling-upgrades.html) of Elasticsearch
22
+ * Run your test suite on Chewy 7.1 / Elasticsearch 7
23
+ * Run manual tests on Chewy 7.1 / Elasticsearch 7
24
+ * Upgrade to Chewy 7.1
25
+ * Upgrade to Chewy 7.2:
26
+ * Remove all the the `Chewy::Type` class usages, e.g. remove `CitiesIndex::City` / `CitiesIndex.city`
27
+ * `CitiesIndex::City.import! ...` becomes `CitiesIndex.import! ...`
28
+ * Update indexes with simplified DSL:
29
+ * `define_type` block -> `index_scope` clause
30
+ * it can be omitted completely, if you don't need to specify the scope or options, e.g. `name`
31
+ * Remove type names from string representations:
32
+ * in `update_index` ActiveRecord helper and RSpec matcher, e.g.
33
+ * `update_index('cities#city')` -> `update_index('cities')`
34
+ * `update_index(UsersIndex::User)` -> `update_index(UsersIndex)`
35
+ * in rake tasks (e.g. `rake chewy:update[cities#city]` -> `rake chewy:update[cities]`)
36
+ * rake tasks output is also changed (e.g. `Imported CitiesIndex::City in 1s, stats: index 3` -> `Imported CitiesIndex in 1s, stats: index 3`)
37
+ * Use index name instead of type name in loader additional scope
38
+ * e.g. `CitiesIndex.filter(...).load(city: {scope: City.where(...)})` -> `CitiesIndex.filter(...).load(cities: {scope: City.where(...)})`
39
+
40
+ ## Chewy 5/Elasticsearch 5 to Chewy 6/Elasticsearch 6
41
+
42
+ In order to upgrade Chewy 5/Elasticsearch 5 to Chewy 6/Elasticsearch 6 in the most seamless manner you have to:
43
+
44
+ * Upgrade to the latest 5.x stable releases, namely Chewy 5.2, Elasticsearch 5.6
7
45
  * [Migrate any multi-typed indexes into single-typed](https://www.elastic.co/guide/en/elasticsearch/reference/6.8/removal-of-types.html)
8
46
  * Using [multi-index queries](https://github.com/toptal/chewy/pull/657) could be helpful
9
- * Parent/Child [relationship is deprecated](https://www.elastic.co/guide/en/elasticsearch/reference/6.8/removal-of-types.html#parent-child-mapping-types) in favor of the [join field](https://www.elastic.co/guide/en/elasticsearch/reference/6.8/parent-join.html)
47
+ * Parent/Child [relationship is deprecated](https://www.elastic.co/guide/en/elasticsearch/reference/6.8/removal-of-types.html#parent-child-mapping-types) in favor of the [join field](https://www.elastic.co/guide/en/elasticsearch/reference/6.8/parent-join.html)
10
48
  * Handle deprecation of `string` type & `not_analyzed` value for the `index` mapping parameter:
11
49
  * replace fields with `{ type: 'string', index: 'not_analyzed'}` by `{type: 'keyword'}`
12
50
  * replace fields with `{ type: 'string', index: 'analyzed'}` by `{type: 'text'}`
13
51
  * `PathHierarchy` tokenizer' param `delimiter` now accepts only one argument, [others should be replaced by character filter ](https://discuss.elastic.co/t/multichar-delimiter-in-path-hierarchy-tokenizer/16203)
14
- * Make sure you don't use any other of the [deprecated ES5 features](https://www.elastic.co/guide/en/elasticsearch/reference/6.8/breaking-changes-6.0.html)
15
- * Run your test suite on ES6
16
- * Run manual tests on ES6
17
- * Perform a [rolling upgrade](https://www.elastic.co/guide/en/elasticsearch/reference/6.8/rolling-upgrades.html) of Elasticsearch
52
+ * Make sure you don't use any other of the [deprecated Elasticsearch 5 features](https://www.elastic.co/guide/en/elasticsearch/reference/6.8/breaking-changes-6.0.html)
53
+ * Run your test suite on Chewy 6 / Elasticsearch 6
54
+ * Run manual tests on Chewy 6 / Elasticsearch 6
18
55
  * Upgrade to Chewy 6
56
+ * Perform a [rolling upgrade](https://www.elastic.co/guide/en/elasticsearch/reference/6.8/rolling-upgrades.html) of Elasticsearch
@@ -8,6 +8,7 @@ describe Chewy::Config do
8
8
  its(:transport_logger) { should be_nil }
9
9
  its(:root_strategy) { should == :base }
10
10
  its(:request_strategy) { should == :atomic }
11
+ its(:console_strategy) { should == :urgent }
11
12
  its(:use_after_commit_callbacks) { should == true }
12
13
  its(:indices_path) { should == 'app/chewy' }
13
14
  its(:reset_disable_refresh_interval) { should == false }
@@ -21,7 +22,7 @@ describe Chewy::Config do
21
22
 
22
23
  specify do
23
24
  expect { subject.transport_logger = logger }
24
- .to change { Chewy.client.transport.logger }.to(logger)
25
+ .to change { Chewy.client.transport.transport.logger }.to(logger)
25
26
  end
26
27
  specify do
27
28
  expect { subject.transport_logger = logger }
@@ -39,7 +40,7 @@ describe Chewy::Config do
39
40
 
40
41
  specify do
41
42
  expect { subject.transport_tracer = tracer }
42
- .to change { Chewy.client.transport.tracer }.to(tracer)
43
+ .to change { Chewy.client.transport.transport.tracer }.to(tracer)
43
44
  end
44
45
  specify do
45
46
  expect { subject.transport_tracer = tracer }
@@ -55,58 +56,19 @@ describe Chewy::Config do
55
56
  context 'nothing is defined' do
56
57
  before do
57
58
  hide_const('Kaminari')
58
- hide_const('WillPaginate')
59
59
  end
60
60
 
61
61
  specify do
62
62
  expect(subject.search_class.included_modules)
63
63
  .not_to include(Chewy::Search::Pagination::Kaminari)
64
64
  end
65
-
66
- specify do
67
- expect(subject.search_class.included_modules)
68
- .not_to include(Chewy::Search::Pagination::WillPaginate)
69
- end
70
65
  end
71
66
 
72
67
  context 'kaminari' do
73
- before { hide_const('WillPaginate') }
74
-
75
- specify do
76
- expect(subject.search_class.included_modules)
77
- .to include(Chewy::Search::Pagination::Kaminari)
78
- end
79
-
80
- specify do
81
- expect(subject.search_class.included_modules)
82
- .not_to include(Chewy::Search::Pagination::WillPaginate)
83
- end
84
- end
85
-
86
- context 'will_paginate' do
87
- before { hide_const('Kaminari') }
88
-
89
- specify do
90
- expect(subject.search_class.included_modules)
91
- .not_to include(Chewy::Search::Pagination::Kaminari)
92
- end
93
-
94
- specify do
95
- expect(subject.search_class.included_modules)
96
- .to include(Chewy::Search::Pagination::WillPaginate)
97
- end
98
- end
99
-
100
- context 'both are defined' do
101
68
  specify do
102
69
  expect(subject.search_class.included_modules)
103
70
  .to include(Chewy::Search::Pagination::Kaminari)
104
71
  end
105
-
106
- specify do
107
- expect(subject.search_class.included_modules)
108
- .not_to include(Chewy::Search::Pagination::WillPaginate)
109
- end
110
72
  end
111
73
  end
112
74
 
@@ -133,4 +95,17 @@ describe Chewy::Config do
133
95
  end
134
96
  end
135
97
  end
98
+
99
+ describe '.console_strategy' do
100
+ context 'sets .console_strategy' do
101
+ let(:default_strategy) { subject.console_strategy }
102
+ let(:new_strategy) { :atomic }
103
+ after { subject.console_strategy = default_strategy }
104
+
105
+ specify do
106
+ expect { subject.console_strategy = new_strategy }
107
+ .to change { subject.console_strategy }.to(new_strategy)
108
+ end
109
+ end
110
+ end
136
111
  end