chewy 5.1.0 → 7.2.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (234) 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/workflows/ruby.yml +73 -0
  7. data/.rubocop.yml +13 -8
  8. data/.rubocop_todo.yml +110 -22
  9. data/CHANGELOG.md +449 -347
  10. data/CODE_OF_CONDUCT.md +14 -0
  11. data/CONTRIBUTING.md +63 -0
  12. data/Gemfile +3 -7
  13. data/Guardfile +3 -1
  14. data/LICENSE.txt +1 -1
  15. data/README.md +423 -311
  16. data/chewy.gemspec +8 -10
  17. data/gemfiles/rails.5.2.activerecord.gemfile +9 -14
  18. data/gemfiles/rails.6.0.activerecord.gemfile +11 -0
  19. data/gemfiles/rails.6.1.activerecord.gemfile +13 -0
  20. data/gemfiles/rails.7.0.activerecord.gemfile +13 -0
  21. data/lib/chewy/config.rb +42 -60
  22. data/lib/chewy/errors.rb +4 -10
  23. data/lib/chewy/fields/base.rb +80 -20
  24. data/lib/chewy/fields/root.rb +7 -17
  25. data/lib/chewy/index/actions.rb +62 -35
  26. data/lib/chewy/{type → index}/adapter/active_record.rb +18 -4
  27. data/lib/chewy/{type → index}/adapter/base.rb +2 -3
  28. data/lib/chewy/{type → index}/adapter/object.rb +28 -32
  29. data/lib/chewy/{type → index}/adapter/orm.rb +26 -24
  30. data/lib/chewy/index/aliases.rb +14 -5
  31. data/lib/chewy/{type → index}/crutch.rb +5 -5
  32. data/lib/chewy/index/import/bulk_builder.rb +311 -0
  33. data/lib/chewy/{type → index}/import/bulk_request.rb +6 -7
  34. data/lib/chewy/{type → index}/import/journal_builder.rb +11 -12
  35. data/lib/chewy/{type → index}/import/routine.rb +17 -16
  36. data/lib/chewy/{type → index}/import.rb +51 -33
  37. data/lib/chewy/{type → index}/mapping.rb +32 -37
  38. data/lib/chewy/index/observe/active_record_methods.rb +87 -0
  39. data/lib/chewy/index/observe/callback.rb +34 -0
  40. data/lib/chewy/index/observe.rb +17 -0
  41. data/lib/chewy/index/specification.rb +1 -0
  42. data/lib/chewy/{type → index}/syncer.rb +61 -62
  43. data/lib/chewy/{type → index}/witchcraft.rb +15 -9
  44. data/lib/chewy/{type → index}/wrapper.rb +13 -3
  45. data/lib/chewy/index.rb +46 -96
  46. data/lib/chewy/journal.rb +25 -14
  47. data/lib/chewy/minitest/helpers.rb +86 -13
  48. data/lib/chewy/minitest/search_index_receiver.rb +22 -26
  49. data/lib/chewy/multi_search.rb +62 -0
  50. data/lib/chewy/railtie.rb +6 -20
  51. data/lib/chewy/rake_helper.rb +136 -108
  52. data/lib/chewy/rspec/build_query.rb +12 -0
  53. data/lib/chewy/rspec/helpers.rb +55 -0
  54. data/lib/chewy/rspec/update_index.rb +55 -44
  55. data/lib/chewy/rspec.rb +2 -0
  56. data/lib/chewy/runtime.rb +1 -1
  57. data/lib/chewy/search/loader.rb +19 -41
  58. data/lib/chewy/search/parameters/collapse.rb +16 -0
  59. data/lib/chewy/search/parameters/concerns/query_storage.rb +2 -2
  60. data/lib/chewy/search/parameters/ignore_unavailable.rb +27 -0
  61. data/lib/chewy/search/parameters/indices.rb +12 -57
  62. data/lib/chewy/search/parameters/none.rb +1 -3
  63. data/lib/chewy/search/parameters/order.rb +6 -19
  64. data/lib/chewy/search/parameters/source.rb +5 -1
  65. data/lib/chewy/search/parameters/track_total_hits.rb +16 -0
  66. data/lib/chewy/search/parameters.rb +7 -4
  67. data/lib/chewy/search/query_proxy.rb +9 -2
  68. data/lib/chewy/search/request.rb +180 -154
  69. data/lib/chewy/search/response.rb +5 -5
  70. data/lib/chewy/search/scoping.rb +7 -8
  71. data/lib/chewy/search/scrolling.rb +16 -13
  72. data/lib/chewy/search.rb +7 -22
  73. data/lib/chewy/stash.rb +19 -30
  74. data/lib/chewy/strategy/active_job.rb +2 -2
  75. data/lib/chewy/strategy/atomic_no_refresh.rb +18 -0
  76. data/lib/chewy/strategy/base.rb +10 -0
  77. data/lib/chewy/strategy/lazy_sidekiq.rb +64 -0
  78. data/lib/chewy/strategy/sidekiq.rb +3 -2
  79. data/lib/chewy/strategy.rb +5 -19
  80. data/lib/chewy/version.rb +1 -1
  81. data/lib/chewy.rb +36 -80
  82. data/lib/generators/chewy/install_generator.rb +1 -1
  83. data/lib/tasks/chewy.rake +26 -32
  84. data/migration_guide.md +56 -0
  85. data/spec/chewy/config_spec.rb +15 -61
  86. data/spec/chewy/fields/base_spec.rb +432 -145
  87. data/spec/chewy/fields/root_spec.rb +20 -28
  88. data/spec/chewy/fields/time_fields_spec.rb +5 -5
  89. data/spec/chewy/index/actions_spec.rb +388 -55
  90. data/spec/chewy/{type → index}/adapter/active_record_spec.rb +110 -44
  91. data/spec/chewy/{type → index}/adapter/object_spec.rb +21 -6
  92. data/spec/chewy/index/aliases_spec.rb +3 -3
  93. data/spec/chewy/index/import/bulk_builder_spec.rb +494 -0
  94. data/spec/chewy/{type → index}/import/bulk_request_spec.rb +5 -12
  95. data/spec/chewy/{type → index}/import/journal_builder_spec.rb +14 -22
  96. data/spec/chewy/{type → index}/import/routine_spec.rb +19 -19
  97. data/spec/chewy/{type → index}/import_spec.rb +149 -96
  98. data/spec/chewy/index/mapping_spec.rb +135 -0
  99. data/spec/chewy/index/observe/active_record_methods_spec.rb +68 -0
  100. data/spec/chewy/index/observe/callback_spec.rb +139 -0
  101. data/spec/chewy/index/observe_spec.rb +143 -0
  102. data/spec/chewy/index/settings_spec.rb +3 -1
  103. data/spec/chewy/index/specification_spec.rb +20 -30
  104. data/spec/chewy/{type → index}/syncer_spec.rb +14 -19
  105. data/spec/chewy/{type → index}/witchcraft_spec.rb +34 -21
  106. data/spec/chewy/index/wrapper_spec.rb +100 -0
  107. data/spec/chewy/index_spec.rb +69 -137
  108. data/spec/chewy/journal_spec.rb +46 -91
  109. data/spec/chewy/minitest/helpers_spec.rb +122 -14
  110. data/spec/chewy/minitest/search_index_receiver_spec.rb +24 -26
  111. data/spec/chewy/multi_search_spec.rb +84 -0
  112. data/spec/chewy/rake_helper_spec.rb +293 -101
  113. data/spec/chewy/rspec/build_query_spec.rb +34 -0
  114. data/spec/chewy/rspec/helpers_spec.rb +61 -0
  115. data/spec/chewy/rspec/update_index_spec.rb +106 -102
  116. data/spec/chewy/runtime_spec.rb +2 -2
  117. data/spec/chewy/search/loader_spec.rb +19 -53
  118. data/spec/chewy/search/pagination/kaminari_examples.rb +3 -5
  119. data/spec/chewy/search/pagination/kaminari_spec.rb +1 -1
  120. data/spec/chewy/search/parameters/collapse_spec.rb +5 -0
  121. data/spec/chewy/search/parameters/ignore_unavailable_spec.rb +67 -0
  122. data/spec/chewy/search/parameters/indices_spec.rb +26 -118
  123. data/spec/chewy/search/parameters/none_spec.rb +1 -1
  124. data/spec/chewy/search/parameters/order_spec.rb +18 -11
  125. data/spec/chewy/search/parameters/query_storage_examples.rb +67 -21
  126. data/spec/chewy/search/parameters/search_after_spec.rb +4 -1
  127. data/spec/chewy/search/parameters/source_spec.rb +8 -2
  128. data/spec/chewy/search/parameters/track_total_hits_spec.rb +5 -0
  129. data/spec/chewy/search/parameters_spec.rb +23 -7
  130. data/spec/chewy/search/query_proxy_spec.rb +68 -17
  131. data/spec/chewy/search/request_spec.rb +344 -149
  132. data/spec/chewy/search/response_spec.rb +35 -25
  133. data/spec/chewy/search/scrolling_spec.rb +28 -26
  134. data/spec/chewy/search_spec.rb +69 -59
  135. data/spec/chewy/stash_spec.rb +16 -26
  136. data/spec/chewy/strategy/active_job_spec.rb +23 -10
  137. data/spec/chewy/strategy/atomic_no_refresh_spec.rb +60 -0
  138. data/spec/chewy/strategy/atomic_spec.rb +9 -10
  139. data/spec/chewy/strategy/lazy_sidekiq_spec.rb +214 -0
  140. data/spec/chewy/strategy/sidekiq_spec.rb +14 -10
  141. data/spec/chewy/strategy_spec.rb +19 -15
  142. data/spec/chewy_spec.rb +17 -110
  143. data/spec/spec_helper.rb +6 -29
  144. data/spec/support/active_record.rb +43 -5
  145. metadata +102 -198
  146. data/.travis.yml +0 -45
  147. data/Appraisals +0 -81
  148. data/LEGACY_DSL.md +0 -497
  149. data/gemfiles/rails.4.0.activerecord.gemfile +0 -15
  150. data/gemfiles/rails.4.1.activerecord.gemfile +0 -15
  151. data/gemfiles/rails.4.2.activerecord.gemfile +0 -16
  152. data/gemfiles/rails.4.2.mongoid.5.2.gemfile +0 -16
  153. data/gemfiles/rails.5.0.activerecord.gemfile +0 -16
  154. data/gemfiles/rails.5.0.mongoid.6.1.gemfile +0 -16
  155. data/gemfiles/rails.5.1.activerecord.gemfile +0 -16
  156. data/gemfiles/rails.5.1.mongoid.6.3.gemfile +0 -16
  157. data/gemfiles/sequel.4.45.gemfile +0 -11
  158. data/lib/chewy/backports/deep_dup.rb +0 -46
  159. data/lib/chewy/backports/duplicable.rb +0 -91
  160. data/lib/chewy/query/compose.rb +0 -68
  161. data/lib/chewy/query/criteria.rb +0 -191
  162. data/lib/chewy/query/filters.rb +0 -244
  163. data/lib/chewy/query/loading.rb +0 -110
  164. data/lib/chewy/query/nodes/and.rb +0 -25
  165. data/lib/chewy/query/nodes/base.rb +0 -17
  166. data/lib/chewy/query/nodes/bool.rb +0 -34
  167. data/lib/chewy/query/nodes/equal.rb +0 -34
  168. data/lib/chewy/query/nodes/exists.rb +0 -20
  169. data/lib/chewy/query/nodes/expr.rb +0 -28
  170. data/lib/chewy/query/nodes/field.rb +0 -110
  171. data/lib/chewy/query/nodes/has_child.rb +0 -15
  172. data/lib/chewy/query/nodes/has_parent.rb +0 -15
  173. data/lib/chewy/query/nodes/has_relation.rb +0 -59
  174. data/lib/chewy/query/nodes/match_all.rb +0 -11
  175. data/lib/chewy/query/nodes/missing.rb +0 -20
  176. data/lib/chewy/query/nodes/not.rb +0 -25
  177. data/lib/chewy/query/nodes/or.rb +0 -25
  178. data/lib/chewy/query/nodes/prefix.rb +0 -19
  179. data/lib/chewy/query/nodes/query.rb +0 -20
  180. data/lib/chewy/query/nodes/range.rb +0 -63
  181. data/lib/chewy/query/nodes/raw.rb +0 -15
  182. data/lib/chewy/query/nodes/regexp.rb +0 -35
  183. data/lib/chewy/query/nodes/script.rb +0 -20
  184. data/lib/chewy/query/pagination.rb +0 -25
  185. data/lib/chewy/query.rb +0 -1142
  186. data/lib/chewy/search/pagination/will_paginate.rb +0 -43
  187. data/lib/chewy/search/parameters/types.rb +0 -20
  188. data/lib/chewy/strategy/resque.rb +0 -27
  189. data/lib/chewy/strategy/shoryuken.rb +0 -40
  190. data/lib/chewy/type/actions.rb +0 -43
  191. data/lib/chewy/type/adapter/mongoid.rb +0 -67
  192. data/lib/chewy/type/adapter/sequel.rb +0 -93
  193. data/lib/chewy/type/import/bulk_builder.rb +0 -122
  194. data/lib/chewy/type/observe.rb +0 -82
  195. data/lib/chewy/type.rb +0 -117
  196. data/lib/sequel/plugins/chewy_observe.rb +0 -63
  197. data/spec/chewy/query/criteria_spec.rb +0 -700
  198. data/spec/chewy/query/filters_spec.rb +0 -201
  199. data/spec/chewy/query/loading_spec.rb +0 -124
  200. data/spec/chewy/query/nodes/and_spec.rb +0 -12
  201. data/spec/chewy/query/nodes/bool_spec.rb +0 -14
  202. data/spec/chewy/query/nodes/equal_spec.rb +0 -32
  203. data/spec/chewy/query/nodes/exists_spec.rb +0 -18
  204. data/spec/chewy/query/nodes/has_child_spec.rb +0 -59
  205. data/spec/chewy/query/nodes/has_parent_spec.rb +0 -59
  206. data/spec/chewy/query/nodes/match_all_spec.rb +0 -11
  207. data/spec/chewy/query/nodes/missing_spec.rb +0 -16
  208. data/spec/chewy/query/nodes/not_spec.rb +0 -14
  209. data/spec/chewy/query/nodes/or_spec.rb +0 -12
  210. data/spec/chewy/query/nodes/prefix_spec.rb +0 -16
  211. data/spec/chewy/query/nodes/query_spec.rb +0 -12
  212. data/spec/chewy/query/nodes/range_spec.rb +0 -32
  213. data/spec/chewy/query/nodes/raw_spec.rb +0 -11
  214. data/spec/chewy/query/nodes/regexp_spec.rb +0 -43
  215. data/spec/chewy/query/nodes/script_spec.rb +0 -15
  216. data/spec/chewy/query/pagination/kaminari_spec.rb +0 -5
  217. data/spec/chewy/query/pagination/will_paginate_spec.rb +0 -5
  218. data/spec/chewy/query/pagination_spec.rb +0 -39
  219. data/spec/chewy/query_spec.rb +0 -637
  220. data/spec/chewy/search/pagination/will_paginate_examples.rb +0 -63
  221. data/spec/chewy/search/pagination/will_paginate_spec.rb +0 -23
  222. data/spec/chewy/search/parameters/types_spec.rb +0 -5
  223. data/spec/chewy/strategy/resque_spec.rb +0 -46
  224. data/spec/chewy/strategy/shoryuken_spec.rb +0 -66
  225. data/spec/chewy/type/actions_spec.rb +0 -50
  226. data/spec/chewy/type/adapter/mongoid_spec.rb +0 -372
  227. data/spec/chewy/type/adapter/sequel_spec.rb +0 -472
  228. data/spec/chewy/type/import/bulk_builder_spec.rb +0 -279
  229. data/spec/chewy/type/mapping_spec.rb +0 -173
  230. data/spec/chewy/type/observe_spec.rb +0 -137
  231. data/spec/chewy/type/wrapper_spec.rb +0 -98
  232. data/spec/chewy/type_spec.rb +0 -55
  233. data/spec/support/mongoid.rb +0 -93
  234. data/spec/support/sequel.rb +0 -80
@@ -23,7 +23,7 @@ module Chewy
23
23
  #
24
24
  # @return [Integer]
25
25
  def total
26
- @total ||= hits_root['total'] || 0
26
+ @total ||= hits_root.fetch('total', {}).fetch('value', 0)
27
27
  end
28
28
 
29
29
  # Response `max_score` field.
@@ -64,12 +64,12 @@ module Chewy
64
64
  end
65
65
  alias_method :aggregations, :aggs
66
66
 
67
- # {Chewy::Type} wrappers collection instantiated on top of hits.
67
+ # {Chewy::Index} wrappers collection instantiated on top of hits.
68
68
  #
69
- # @return [Array<Chewy::Type>]
69
+ # @return [Array<Chewy::Index>]
70
70
  def wrappers
71
71
  @wrappers ||= hits.map do |hit|
72
- @loader.derive_type(hit['_index'], hit['_type']).build(hit)
72
+ @loader.derive_index(hit['_index']).build(hit)
73
73
  end
74
74
  end
75
75
 
@@ -102,7 +102,7 @@ module Chewy
102
102
  # end
103
103
  # @see #wrappers
104
104
  # @see #objects
105
- # @return [{Chewy::Type => Object}] a hash with wrappers as keys and ORM/ODM objects as values
105
+ # @return [{Chewy::Index => Object}] a hash with wrappers as keys and ORM/ODM objects as values
106
106
  def object_hash
107
107
  @object_hash ||= wrappers.zip(objects).to_h
108
108
  end
@@ -9,17 +9,16 @@ module Chewy
9
9
  # query(match: {name: name})
10
10
  # end
11
11
  #
12
- # define_type :user do
13
- # def self.by_age(age)
14
- # filter(term: {age: age})
15
- # end
12
+ #
13
+ # def self.by_age(age)
14
+ # filter(term: {age: age})
16
15
  # end
17
16
  # end
18
17
  #
19
18
  # UsersIndex.limit(10).by_name('Martin')
20
19
  # # => <UsersIndex::Query {..., :body=>{:size=>10, :query=>{:match=>{:name=>"Martin"}}}}>
21
- # UsersIndex::User.limit(10).by_name('Martin').by_age(42)
22
- # # => <UsersIndex::User::Query {..., :body=>{:size=>10, :query=>{:bool=>{
20
+ # UsersIndex.limit(10).by_name('Martin').by_age(42)
21
+ # # => <UsersIndex::Query {..., :body=>{:size=>10, :query=>{:bool=>{
23
22
  # # :must=>{:match=>{:name=>"Martin"}},
24
23
  # # :filter=>{:term=>{:age=>42}}}}}}>
25
24
  module Scoping
@@ -28,9 +27,9 @@ module Chewy
28
27
  module ClassMethods
29
28
  # The scopes stack.
30
29
  #
31
- # @return [Array<Chewy::Search::Reques>] array of scopes
30
+ # @return [Array<Chewy::Search::Request>] array of scopes
32
31
  def scopes
33
- Thread.current[:chewy_scopes] ||= []
32
+ Chewy.current[:chewy_scopes] ||= []
34
33
  end
35
34
  end
36
35
 
@@ -28,19 +28,23 @@ module Chewy
28
28
  return enum_for(:scroll_batches, batch_size: batch_size, scroll: scroll) unless block_given?
29
29
 
30
30
  result = perform(size: batch_size, scroll: scroll)
31
- total = [raw_limit_value, result.fetch('hits', {}).fetch('total', 0)].compact.min
31
+ total = [raw_limit_value, result.fetch('hits', {}).fetch('total', {}).fetch('value', 0)].compact.min
32
32
  last_batch_size = total % batch_size
33
33
  fetched = 0
34
+ scroll_id = nil
34
35
 
35
36
  loop do
36
37
  hits = result.fetch('hits', {}).fetch('hits', [])
37
38
  fetched += hits.size
38
39
  hits = hits.first(last_batch_size) if last_batch_size != 0 && fetched >= total
39
40
  yield(hits) if hits.present?
40
- break if fetched >= total
41
41
  scroll_id = result['_scroll_id']
42
+ break if fetched >= total
43
+
42
44
  result = perform_scroll(scroll: scroll, scroll_id: scroll_id)
43
45
  end
46
+ ensure
47
+ Chewy.client.clear_scroll(body: {scroll_id: scroll_id}) if scroll_id
44
48
  end
45
49
 
46
50
  # @!method scroll_hits(batch_size: 1000, scroll: '1m')
@@ -58,17 +62,17 @@ module Chewy
58
62
  # @example
59
63
  # PlaceIndex.scroll_hits.map { |hit| hit['_id'] }
60
64
  # @return [Enumerator] a standard ruby Enumerator
61
- def scroll_hits(**options)
65
+ def scroll_hits(**options, &block)
62
66
  return enum_for(:scroll_hits, **options) unless block_given?
63
67
 
64
68
  scroll_batches(**options).each do |batch|
65
- batch.each { |hit| yield hit }
69
+ batch.each(&block)
66
70
  end
67
71
  end
68
72
 
69
73
  # @!method scroll_wrappers(batch_size: 1000, scroll: '1m')
70
74
  # Iterates through the documents of the scope in batches. Yields
71
- # each hit wrapped with {Chewy::Type}.
75
+ # each hit wrapped with {Chewy::Index}.
72
76
  #
73
77
  # @param batch_size [Integer] batch size obviously, replaces `size` query parameter
74
78
  # @param scroll [String] cursor expiration time
@@ -76,7 +80,7 @@ module Chewy
76
80
  # @overload scroll_wrappers(batch_size: 1000, scroll: '1m')
77
81
  # @example
78
82
  # PlaceIndex.scroll_wrappers { |object| p object.id }
79
- # @yieldparam object [Chewy::Type] block is executed for each hit object
83
+ # @yieldparam object [Chewy::Index] block is executed for each hit object
80
84
  #
81
85
  # @overload scroll_wrappers(batch_size: 1000, scroll: '1m')
82
86
  # @example
@@ -86,7 +90,7 @@ module Chewy
86
90
  return enum_for(:scroll_wrappers, **options) unless block_given?
87
91
 
88
92
  scroll_hits(**options).each do |hit|
89
- yield loader.derive_type(hit['_index'], hit['_type']).build(hit)
93
+ yield loader.derive_index(hit['_index']).build(hit)
90
94
  end
91
95
  end
92
96
 
@@ -110,12 +114,12 @@ module Chewy
110
114
  # @example
111
115
  # PlaceIndex.scroll_objects.map { |record| record.id }
112
116
  # @return [Enumerator] a standard ruby Enumerator
113
- def scroll_objects(**options)
117
+ def scroll_objects(**options, &block)
114
118
  return enum_for(:scroll_objects, **options) unless block_given?
115
119
 
116
120
  except(:source, :stored_fields, :script_fields, :docvalue_fields)
117
121
  .source(false).scroll_batches(**options).each do |batch|
118
- loader.load(batch).each { |object| yield object }
122
+ loader.load(batch).each(&block)
119
123
  end
120
124
  end
121
125
  alias_method :scroll_records, :scroll_objects
@@ -124,10 +128,9 @@ module Chewy
124
128
  private
125
129
 
126
130
  def perform_scroll(body)
127
- ActiveSupport::Notifications.instrument 'search_query.chewy',
128
- notification_payload(request: body) do
129
- Chewy.client.scroll(body)
130
- end
131
+ ActiveSupport::Notifications.instrument 'search_query.chewy', notification_payload(request: body) do
132
+ Chewy.client.scroll(body)
133
+ end
131
134
  end
132
135
  end
133
136
  end
data/lib/chewy/search.rb CHANGED
@@ -1,5 +1,4 @@
1
1
  require 'chewy/search/scoping'
2
- require 'chewy/query'
3
2
  require 'chewy/search/scrolling'
4
3
  require 'chewy/search/query_proxy'
5
4
  require 'chewy/search/parameters'
@@ -7,31 +6,22 @@ require 'chewy/search/response'
7
6
  require 'chewy/search/loader'
8
7
  require 'chewy/search/request'
9
8
  require 'chewy/search/pagination/kaminari'
10
- require 'chewy/search/pagination/will_paginate'
11
9
 
12
10
  module Chewy
13
11
  # This module being included to any provides an interface to the
14
- # request DSL. By default it is included to {Chewy::Index} and
15
- # {Chewy::Type}.
12
+ # request DSL. By default it is included to {Chewy::Index}.
16
13
  #
17
14
  # The class used as a request DSL provider is
18
- # inherited from {Chewy::Search::Request} by default, but if you
19
- # need ES < 2.0 DSL support - you can switch it to {Chewy::Query}
20
- # using {Chewy::Config#search_class}
15
+ # inherited from {Chewy::Search::Request}
21
16
  #
22
- # Also, the search class is refined with one of the pagination-
23
- # providing modules: {Chewy::Search::Pagination::Kaminari} or
24
- # {Chewy::Search::Pagination::WillPaginate}.
17
+ # Also, the search class is refined with the pagination module {Chewy::Search::Pagination::Kaminari}.
25
18
  #
26
19
  # @example
27
20
  # PlacesIndex.query(match: {name: 'Moscow'})
28
- # PlacesIndex::City.query(match: {name: 'Moscow'})
29
21
  # @see Chewy::Index
30
- # @see Chewy::Type
31
22
  # @see Chewy::Search::Request
32
23
  # @see Chewy::Search::ClassMethods
33
24
  # @see Chewy::Search::Pagination::Kaminari
34
- # @see Chewy::Search::Pagination::WillPaginate
35
25
  module Search
36
26
  extend ActiveSupport::Concern
37
27
 
@@ -58,16 +48,15 @@ module Chewy
58
48
  # @see https://www.elastic.co/guide/en/elasticsearch/reference/current/search-uri-request.html
59
49
  # @return [Hash] the request result
60
50
  def search_string(query, options = {})
61
- options = options.merge(all.render.slice(:index, :type).merge(q: query))
51
+ options = options.merge(all.render.slice(:index).merge(q: query))
62
52
  Chewy.client.search(options)
63
53
  end
64
54
 
65
- # Delegates methods from the request class to the index or type class
55
+ # Delegates methods from the request class to the index class
66
56
  #
67
57
  # @example
68
58
  # PlacesIndex.query(match: {name: 'Moscow'})
69
- # PlacesIndex::City.query(match: {name: 'Moscow'})
70
- def method_missing(name, *args, &block)
59
+ ruby2_keywords def method_missing(name, *args, &block)
71
60
  if search_class::DELEGATED_METHODS.include?(name)
72
61
  all.send(name, *args, &block)
73
62
  else
@@ -88,11 +77,6 @@ module Chewy
88
77
  def build_search_class(base)
89
78
  search_class = Class.new(base)
90
79
 
91
- if self < Chewy::Type
92
- index_scopes = index.scopes - scopes
93
- delegate_scoped index, search_class, index_scopes
94
- end
95
-
96
80
  delegate_scoped self, search_class, scopes
97
81
  const_set('Query', search_class)
98
82
  end
@@ -103,6 +87,7 @@ module Chewy
103
87
  define_method method do |*args, &block|
104
88
  scoping { source.public_send(method, *args, &block) }
105
89
  end
90
+ ruby2_keywords method
106
91
  end
107
92
  end
108
93
  end
data/lib/chewy/stash.rb CHANGED
@@ -9,11 +9,9 @@ module Chewy
9
9
  class Specification < Chewy::Index
10
10
  index_name 'chewy_specifications'
11
11
 
12
- define_type :specification do
13
- default_import_options journal: false
12
+ default_import_options journal: false
14
13
 
15
- field :specification, type: 'binary'
16
- end
14
+ field :specification, type: 'binary'
17
15
  end
18
16
 
19
17
  class Journal < Chewy::Index
@@ -24,18 +22,18 @@ module Chewy
24
22
  # @param since_time [Time, DateTime] a timestamp from which we load a journal
25
23
  # @param only [Chewy::Index, Array<Chewy::Index>] journal entries related to these indices will be loaded only
26
24
  def self.entries(since_time, only: [])
27
- self.for(only).filter(range: {created_at: {gt: since_time}})
25
+ self.for(only).filter(range: {created_at: {gt: since_time}}).filter.minimum_should_match(1)
28
26
  end
29
27
 
30
28
  # Cleans up all the journal entries until the specified time. If nothing is
31
29
  # specified - cleans up everything.
32
30
  #
33
- # @param since_time [Time, DateTime] the time top boundary
31
+ # @param until_time [Time, DateTime] Clean everything before that date
34
32
  # @param only [Chewy::Index, Array<Chewy::Index>] indexes to clean up journal entries for
35
- def self.clean(until_time = nil, only: [])
33
+ def self.clean(until_time = nil, only: [], delete_by_query_options: {})
36
34
  scope = self.for(only)
37
35
  scope = scope.filter(range: {created_at: {lte: until_time}}) if until_time
38
- scope.delete_all
36
+ scope.delete_all(**delete_by_query_options)
39
37
  end
40
38
 
41
39
  # Selects all the journal entries for the specified indices.
@@ -43,35 +41,26 @@ module Chewy
43
41
  # @param indices [Chewy::Index, Array<Chewy::Index>]
44
42
  def self.for(*something)
45
43
  something = something.flatten.compact
46
- types = something.flat_map { |s| Chewy.derive_types(s) }
47
- return none if something.present? && types.blank?
44
+ indexes = something.flat_map { |s| Chewy.derive_name(s) }
45
+ return none if something.present? && indexes.blank?
46
+
48
47
  scope = all
49
- types.group_by(&:index).each do |index, index_types|
50
- scope = scope.or(
51
- filter(term: {index_name: index.derivable_name})
52
- .filter(terms: {type_name: index_types.map(&:type_name)})
53
- )
48
+ indexes.each do |index|
49
+ scope = scope.or(filter(term: {index_name: index.derivable_name}))
54
50
  end
55
51
  scope
56
52
  end
57
53
 
58
- define_type :journal do
59
- default_import_options journal: false
54
+ default_import_options journal: false
60
55
 
61
- field :index_name, type: 'keyword'
62
- field :type_name, type: 'keyword'
63
- field :action, type: 'keyword'
64
- field :references, type: 'binary'
65
- field :created_at, type: 'date'
66
-
67
- def type
68
- @type ||= Chewy.derive_type("#{index_name}##{type_name}")
69
- end
56
+ field :index_name, type: 'keyword'
57
+ field :action, type: 'keyword'
58
+ field :references, type: 'binary'
59
+ field :created_at, type: 'date'
70
60
 
71
- def references
72
- @references ||= Array.wrap(@attributes['references']).map do |item|
73
- JSON.load(Base64.decode64(item)) # rubocop:disable Security/JSONLoad
74
- end
61
+ def references
62
+ @references ||= Array.wrap(@attributes['references']).map do |item|
63
+ JSON.load(Base64.decode64(item)) # rubocop:disable Security/JSONLoad
75
64
  end
76
65
  end
77
66
  end
@@ -11,11 +11,11 @@ module Chewy
11
11
  #
12
12
  class ActiveJob < Atomic
13
13
  class Worker < ::ActiveJob::Base
14
- queue_as :chewy
14
+ queue_as { Chewy.settings.dig(:active_job, :queue) || '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
 
@@ -0,0 +1,18 @@
1
+ module Chewy
2
+ class Strategy
3
+ # This strategy works like atomic but import objects with `refresh=false` parameter.
4
+ #
5
+ # Chewy.strategy(:atomic_no_refresh) do
6
+ # User.all.map(&:save) # Does nothing here
7
+ # Post.all.map(&:save) # And here
8
+ # # It imports all the changed users and posts right here
9
+ # # before block leaving with bulk ES API, kinda optimization
10
+ # end
11
+ #
12
+ class AtomicNoRefresh < Atomic
13
+ def leave
14
+ @stash.all? { |type, ids| type.import!(ids, refresh: false) }
15
+ end
16
+ end
17
+ end
18
+ end
@@ -22,6 +22,16 @@ module Chewy
22
22
  # strategies stack
23
23
  #
24
24
  def leave; end
25
+
26
+ # This method called when some model record is created or updated.
27
+ # Normally it will just evaluate all the Chewy callbacks and pass results
28
+ # to current strategy's update method.
29
+ # However it's possible to override it to achieve delayed evaluation of
30
+ # callbacks, e.g. using sidekiq.
31
+ #
32
+ def update_chewy_indices(object)
33
+ object.run_chewy_callbacks
34
+ end
25
35
  end
26
36
  end
27
37
  end
@@ -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,
@@ -33,7 +34,7 @@ module Chewy
33
34
  private
34
35
 
35
36
  def sidekiq_queue
36
- Chewy.settings.fetch(:sidekiq, {})[:queue] || 'chewy'
37
+ Chewy.settings.dig(:sidekiq, :queue) || 'chewy'
37
38
  end
38
39
  end
39
40
  end
@@ -2,24 +2,12 @@ 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'
23
11
  rescue LoadError
24
12
  nil
25
13
  end
@@ -60,6 +48,7 @@ module Chewy
60
48
 
61
49
  def pop
62
50
  raise "Can't pop root strategy" if @stack.one?
51
+
63
52
  result = @stack.pop.tap(&:leave)
64
53
  debug "[#{@stack.size}] -> #{result.name}, now #{current.name}" if @stack.size > 1
65
54
  result
@@ -75,17 +64,14 @@ module Chewy
75
64
  private
76
65
 
77
66
  def debug(string)
78
- return unless Chewy.logger && Chewy.logger.debug?
67
+ return unless Chewy.logger&.debug?
68
+
79
69
  line = caller.detect { |l| l !~ %r{lib/chewy/strategy.rb:|lib/chewy.rb:} }
80
70
  Chewy.logger.debug(["Chewy strategies stack: #{string}", line.sub(/:in\s.+$/, '')].join(' @ '))
81
71
  end
82
72
 
83
73
  def resolve(name)
84
74
  "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
75
  end
90
76
  end
91
77
  end
data/lib/chewy/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Chewy
2
- VERSION = '5.1.0'.freeze
2
+ VERSION = '7.2.7'.freeze
3
3
  end