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
@@ -1,26 +1,26 @@
1
- require 'i18n/core_ext/hash'
1
+ require 'active_support/core_ext/hash/keys'
2
2
 
3
3
  # Rspec matcher `update_index`
4
4
  # To use it - add `require 'chewy/rspec'` to the `spec_helper.rb`
5
- # Simple usage - just pass type as argument.
5
+ # Simple usage - just pass index as argument.
6
6
  #
7
- # specify { expect { user.save! }.to update_index(UsersIndex::User) }
8
- # specify { expect { user.save! }.to update_index('users#user') }
9
- # specify { expect { user.save! }.not_to update_index('users#user') }
7
+ # specify { expect { user.save! }.to update_index(UsersIndex) }
8
+ # specify { expect { user.save! }.to update_index('users') }
9
+ # specify { expect { user.save! }.not_to update_index('users') }
10
10
  #
11
11
  # This example will pass as well because user1 was reindexed
12
12
  # and nothing was said about user2:
13
13
  #
14
14
  # specify { expect { [user1, user2].map(&:save!) }
15
- # .to update_index(UsersIndex.user).and_reindex(user1) }
15
+ # .to update_index(UsersIndex).and_reindex(user1) }
16
16
  #
17
17
  # If you need to specify reindexed records strictly - use `only` chain.
18
18
  # Combined matcher chain methods:
19
19
  #
20
20
  # specify { expect { user1.destroy!; user2.save! } }
21
- # .to update_index(UsersIndex::User).and_reindex(user2).and_delete(user1) }
21
+ # .to update_index(UsersIndex).and_reindex(user2).and_delete(user1) }
22
22
  #
23
- RSpec::Matchers.define :update_index do |type_name, options = {}| # rubocop:disable BlockLength
23
+ RSpec::Matchers.define :update_index do |index_name, options = {}| # rubocop:disable Metrics/BlockLength
24
24
  if !respond_to?(:failure_message) && respond_to?(:failure_message_for_should)
25
25
  alias_method :failure_message, :failure_message_for_should
26
26
  alias_method :failure_message_when_negated, :failure_message_for_should_not
@@ -28,30 +28,30 @@ RSpec::Matchers.define :update_index do |type_name, options = {}| # rubocop:disa
28
28
 
29
29
  # Specify indexed records by passing record itself or id.
30
30
  #
31
- # specify { expect { user.save! }.to update_index(UsersIndex::User).and_reindex(user)
32
- # specify { expect { user.save! }.to update_index(UsersIndex::User).and_reindex(42)
31
+ # specify { expect { user.save! }.to update_index(UsersIndex).and_reindex(user)
32
+ # specify { expect { user.save! }.to update_index(UsersIndex).and_reindex(42)
33
33
  # specify { expect { [user1, user2].map(&:save!) }
34
- # .to update_index(UsersIndex::User).and_reindex(user1, user2) }
34
+ # .to update_index(UsersIndex).and_reindex(user1, user2) }
35
35
  # specify { expect { [user1, user2].map(&:save!) }
36
- # .to update_index(UsersIndex::User).and_reindex(user1).and_reindex(user2) }
36
+ # .to update_index(UsersIndex).and_reindex(user1).and_reindex(user2) }
37
37
  #
38
38
  # Specify indexing count for every particular record. Useful in case
39
39
  # urgent index updates.
40
40
  #
41
41
  # specify { expect { 2.times { user.save! } }
42
- # .to update_index(UsersIndex::User).and_reindex(user, times: 2) }
42
+ # .to update_index(UsersIndex).and_reindex(user, times: 2) }
43
43
  #
44
44
  # Specify reindexed attributes. Note that arrays are
45
45
  # compared position-independently.
46
46
  #
47
47
  # specify { expect { user.update_attributes!(name: 'Duke') }
48
- # .to update_index(UsersIndex.user).and_reindex(user, with: {name: 'Duke'}) }
48
+ # .to update_index(UsersIndex).and_reindex(user, with: {name: 'Duke'}) }
49
49
  #
50
50
  # You can combine all the options and chain `and_reindex` method to
51
51
  # specify options for every indexed record:
52
52
  #
53
53
  # specify { expect { 2.times { [user1, user2].map { |u| u.update_attributes!(name: "Duke#{u.id}") } } }
54
- # .to update_index(UsersIndex.user)
54
+ # .to update_index(UsersIndex)
55
55
  # .and_reindex(user1, with: {name: 'Duke42'}) }
56
56
  # .and_reindex(user2, times: 1, with: {name: 'Duke43'}) }
57
57
  #
@@ -62,8 +62,8 @@ RSpec::Matchers.define :update_index do |type_name, options = {}| # rubocop:disa
62
62
 
63
63
  # Specify deleted records with record itself or id passed.
64
64
  #
65
- # specify { expect { user.destroy! }.to update_index(UsersIndex::User).and_delete(user) }
66
- # specify { expect { user.destroy! }.to update_index(UsersIndex::User).and_delete(user.id) }
65
+ # specify { expect { user.destroy! }.to update_index(UsersIndex).and_delete(user) }
66
+ # specify { expect { user.destroy! }.to update_index(UsersIndex).and_delete(user.id) }
67
67
  #
68
68
  chain(:and_delete) do |*args|
69
69
  @delete ||= {}
@@ -73,14 +73,14 @@ RSpec::Matchers.define :update_index do |type_name, options = {}| # rubocop:disa
73
73
  # Used for specifying than no other records would be indexed or deleted:
74
74
  #
75
75
  # specify { expect { [user1, user2].map(&:save!) }
76
- # .to update_index(UsersIndex.user).and_reindex(user1, user2).only }
76
+ # .to update_index(UsersIndex).and_reindex(user1, user2).only }
77
77
  # specify { expect { [user1, user2].map(&:destroy!) }
78
- # .to update_index(UsersIndex.user).and_delete(user1, user2).only }
78
+ # .to update_index(UsersIndex).and_delete(user1, user2).only }
79
79
  #
80
80
  # This example will fail:
81
81
  #
82
82
  # specify { expect { [user1, user2].map(&:save!) }
83
- # .to update_index(UsersIndex.user).and_reindex(user1).only }
83
+ # .to update_index(UsersIndex).and_reindex(user1).only }
84
84
  #
85
85
  chain(:only) do |*_args|
86
86
  raise 'Use `only` in conjunction with `and_reindex` or `and_delete`' if @reindex.blank? && @delete.blank?
@@ -88,23 +88,30 @@ RSpec::Matchers.define :update_index do |type_name, options = {}| # rubocop:disa
88
88
  @only = true
89
89
  end
90
90
 
91
+ # Expect import to be called with refresh=false parameter
92
+ chain(:no_refresh) do
93
+ @no_refresh = true
94
+ end
95
+
91
96
  def supports_block_expectations?
92
97
  true
93
98
  end
94
99
 
95
- match do |block| # rubocop:disable BlockLength
100
+ match do |block| # rubocop:disable Metrics/BlockLength
96
101
  @reindex ||= {}
97
102
  @delete ||= {}
98
103
  @missed_reindex = []
99
104
  @missed_delete = []
100
105
 
101
- type = Chewy.derive_type(type_name)
106
+ index = Chewy.derive_name(index_name)
102
107
  if defined?(Mocha) && RSpec.configuration.mock_framework.to_s == 'RSpec::Core::MockingAdapters::Mocha'
103
- Chewy::Type::Import::BulkRequest.stubs(:new).with(type, any_parameters).returns(mock_bulk_request)
108
+ params_matcher = @no_refresh ? has_entry(refresh: false) : any_parameters
109
+ Chewy::Index::Import::BulkRequest.stubs(:new).with(index, params_matcher).returns(mock_bulk_request)
104
110
  else
105
- mocked_already = ::RSpec::Mocks.space.proxy_for(Chewy::Type::Import::BulkRequest).method_double_if_exists_for_message(:new)
106
- allow(Chewy::Type::Import::BulkRequest).to receive(:new).and_call_original unless mocked_already
107
- allow(Chewy::Type::Import::BulkRequest).to receive(:new).with(type, any_args).and_return(mock_bulk_request)
111
+ mocked_already = ::RSpec::Mocks.space.proxy_for(Chewy::Index::Import::BulkRequest).method_double_if_exists_for_message(:new)
112
+ allow(Chewy::Index::Import::BulkRequest).to receive(:new).and_call_original unless mocked_already
113
+ params_matcher = @no_refresh ? hash_including(refresh: false) : any_args
114
+ allow(Chewy::Index::Import::BulkRequest).to receive(:new).with(index, params_matcher).and_return(mock_bulk_request)
108
115
  end
109
116
 
110
117
  Chewy.strategy(options[:strategy] || :atomic) { block.call }
@@ -127,13 +134,13 @@ RSpec::Matchers.define :update_index do |type_name, options = {}| # rubocop:disa
127
134
  end
128
135
 
129
136
  @reindex.each_value do |document|
130
- document[:match_count] = (!document[:expected_count] && document[:real_count] > 0) ||
137
+ document[:match_count] = (!document[:expected_count] && (document[:real_count]).positive?) ||
131
138
  (document[:expected_count] && document[:expected_count] == document[:real_count])
132
139
  document[:match_attributes] = document[:expected_attributes].blank? ||
133
140
  compare_attributes(document[:expected_attributes], document[:real_attributes])
134
141
  end
135
142
  @delete.each_value do |document|
136
- document[:match_count] = (!document[:expected_count] && document[:real_count] > 0) ||
143
+ document[:match_count] = (!document[:expected_count] && (document[:real_count]).positive?) ||
137
144
  (document[:expected_count] && document[:expected_count] == document[:real_count])
138
145
  end
139
146
 
@@ -142,13 +149,13 @@ RSpec::Matchers.define :update_index do |type_name, options = {}| # rubocop:disa
142
149
  @delete.all? { |_, document| document[:match_count] }
143
150
  end
144
151
 
145
- failure_message do # rubocop:disable BlockLength
152
+ failure_message do # rubocop:disable Metrics/BlockLength
146
153
  output = ''
147
154
 
148
155
  if mock_bulk_request.updates.none?
149
- output << "Expected index `#{type_name}` to be updated, but it was not\n"
156
+ output << "Expected index `#{index_name}` to be updated#{' with no refresh' if @no_refresh}, but it was not\n"
150
157
  elsif @missed_reindex.present? || @missed_delete.present?
151
- message = "Expected index `#{type_name}` "
158
+ message = "Expected index `#{index_name}` "
152
159
  message << [
153
160
  ("to update documents #{@reindex.keys}" if @reindex.present?),
154
161
  ("to delete documents #{@delete.keys}" if @delete.present?)
@@ -166,9 +173,13 @@ RSpec::Matchers.define :update_index do |type_name, options = {}| # rubocop:disa
166
173
  output << @reindex.each.with_object('') do |(id, document), result|
167
174
  unless document[:match_count] && document[:match_attributes]
168
175
  result << "Expected document with id `#{id}` to be reindexed"
169
- if document[:real_count] > 0
170
- result << "\n #{document[:expected_count]} times, but was reindexed #{document[:real_count]} times" if document[:expected_count] && !document[:match_count]
171
- result << "\n with #{document[:expected_attributes]}, but it was reindexed with #{document[:real_attributes]}" if document[:expected_attributes].present? && !document[:match_attributes]
176
+ if (document[:real_count]).positive?
177
+ if document[:expected_count] && !document[:match_count]
178
+ result << "\n #{document[:expected_count]} times, but was reindexed #{document[:real_count]} times"
179
+ end
180
+ if document[:expected_attributes].present? && !document[:match_attributes]
181
+ result << "\n with #{document[:expected_attributes]}, but it was reindexed with #{document[:real_attributes]}"
182
+ end
172
183
  else
173
184
  result << ', but it was not'
174
185
  end
@@ -179,11 +190,11 @@ RSpec::Matchers.define :update_index do |type_name, options = {}| # rubocop:disa
179
190
  output << @delete.each.with_object('') do |(id, document), result|
180
191
  unless document[:match_count]
181
192
  result << "Expected document with id `#{id}` to be deleted"
182
- result << if document[:real_count] > 0 && document[:expected_count]
183
- "\n #{document[:expected_count]} times, but was deleted #{document[:real_count]} times"
184
- else
185
- ', but it was not'
186
- end
193
+ result << if (document[:real_count]).positive? && document[:expected_count]
194
+ "\n #{document[:expected_count]} times, but was deleted #{document[:real_count]} times"
195
+ else
196
+ ', but it was not'
197
+ end
187
198
  result << "\n"
188
199
  end
189
200
  end
@@ -193,9 +204,9 @@ RSpec::Matchers.define :update_index do |type_name, options = {}| # rubocop:disa
193
204
 
194
205
  failure_message_when_negated do
195
206
  if mock_bulk_request.updates.present?
196
- "Expected index `#{type_name}` not to be updated, but it was with #{mock_bulk_request.updates.map(&:values).flatten.group_by { |documents| documents[:_id] }.map do |id, documents|
197
- "\n document id `#{id}` (#{documents.count} times)"
198
- end.join}\n"
207
+ "Expected index `#{index_name}` not to be updated, but it was with #{mock_bulk_request.updates.map(&:values).flatten.group_by { |documents| documents[:_id] }.map do |id, documents|
208
+ "\n document id `#{id}` (#{documents.count} times)"
209
+ end.join}\n"
199
210
  end
200
211
  end
201
212
 
@@ -209,7 +220,7 @@ RSpec::Matchers.define :update_index do |type_name, options = {}| # rubocop:disa
209
220
  expected_count = options[:times] || options[:count]
210
221
  expected_attributes = (options[:with] || options[:attributes] || {}).deep_symbolize_keys
211
222
 
212
- Hash[args.flatten.map do |document|
223
+ args.flatten.map do |document|
213
224
  id = document.respond_to?(:id) ? document.id.to_s : document.to_s
214
225
  [id, {
215
226
  document: document,
@@ -218,7 +229,7 @@ RSpec::Matchers.define :update_index do |type_name, options = {}| # rubocop:disa
218
229
  real_count: 0,
219
230
  real_attributes: {}
220
231
  }]
221
- end]
232
+ end.to_h
222
233
  end
223
234
 
224
235
  def compare_attributes(expected, real)
data/lib/chewy/rspec.rb CHANGED
@@ -1 +1,3 @@
1
+ require 'chewy/rspec/build_query'
2
+ require 'chewy/rspec/helpers'
1
3
  require 'chewy/rspec/update_index'
data/lib/chewy/runtime.rb CHANGED
@@ -3,7 +3,7 @@ require 'chewy/runtime/version'
3
3
  module Chewy
4
4
  module Runtime
5
5
  def self.version
6
- Thread.current[:chewy_runtime_version] ||= Version.new(Chewy.client.info['version']['number'])
6
+ Chewy.current[:chewy_runtime_version] ||= Version.new(Chewy.client.info['version']['number'])
7
7
  end
8
8
  end
9
9
  end
@@ -3,36 +3,28 @@ module Chewy
3
3
  # This class is used for two different purposes: load ORM/ODM
4
4
  # source objects.
5
5
  #
6
- # @see Chewy::Type::Import
6
+ # @see Chewy::Index::Import
7
7
  # @see Chewy::Search::Request#load
8
8
  # @see Chewy::Search::Response#objects
9
9
  # @see Chewy::Search::Scrolling#scroll_objects
10
10
  class Loader
11
- # @param indexes [Array<Chewy::Index>] list of indexes to lookup types
12
- # @param only [Array<String, Symbol>] list of selected type names to load
13
- # @param except [Array<String, Symbol>] list of type names which will not be loaded
11
+ # @param indexes [Array<Chewy::Index>] list of indexes to lookup
14
12
  # @param options [Hash] adapter-specific load options
15
- # @see Chewy::Type::Adapter::Base#load
16
- def initialize(indexes: [], only: [], except: [], **options)
13
+ # @see Chewy::Index::Adapter::Base#load
14
+ def initialize(indexes: [], **options)
17
15
  @indexes = indexes
18
- @only = Array.wrap(only).map(&:to_s)
19
- @except = Array.wrap(except).map(&:to_s)
20
16
  @options = options
21
17
  end
22
18
 
23
- # Returns a {Chewy::Type} object for index name and type name passed. Caches
24
- # the result for each pair to make lookup faster.
25
- #
26
- # @param index [String] index name
27
- # @param type [String] type name
28
- # @return [Chewy::Type]
29
- # @raise [Chewy::UnderivableType] when index or hash were not found
30
- def derive_type(index, type)
31
- (@derive_type ||= {})[[index, type]] ||= begin
32
- index_class = derive_index(index)
33
- raise Chewy::UnderivableType, "Can not find index named `#{index}`" unless index_class
34
- index_class.type_hash[type] or raise Chewy::UnderivableType, "Index `#{index}` doesn`t have type named `#{type}`"
35
- end
19
+ def derive_index(index_name)
20
+ index = (@derive_index ||= {})[index_name] ||= indexes_hash[index_name] ||
21
+ indexes_hash[indexes_hash.keys.sort_by(&:length)
22
+ .reverse.detect do |name|
23
+ index_name.match(/#{name}(_.+|\z)/)
24
+ end]
25
+ raise Chewy::UndefinedIndex, "Can not find index named `#{index}`" unless index
26
+
27
+ index
36
28
  end
37
29
 
38
30
  # For each passed hit this method loads an ORM/ORD source object
@@ -41,19 +33,17 @@ module Chewy
41
33
  # will be returned at the corresponding position in array.
42
34
  #
43
35
  # Records/documents are loaded in an efficient manner, performing
44
- # a single query for each type present.
36
+ # a single query for each index present.
45
37
  #
46
38
  # @param hits [Array<Hash>] ES hits array
47
39
  # @return [Array<Object, nil>] the array of corresponding ORM/ODM objects
48
40
  def load(hits)
49
- hit_groups = hits.group_by { |hit| [hit['_index'], hit['_type']] }
50
- loaded_objects = hit_groups.each_with_object({}) do |((index_name, type_name), hit_group), result|
51
- next if skip_type?(type_name)
52
-
53
- type = derive_type(index_name, type_name)
41
+ hit_groups = hits.group_by { |hit| hit['_index'] }
42
+ loaded_objects = hit_groups.each_with_object({}) do |(index_name, hit_group), result|
43
+ index = derive_index(index_name)
54
44
  ids = hit_group.map { |hit| hit['_id'] }
55
- loaded = type.adapter.load(ids, @options.merge(_type: type))
56
- loaded ||= hit_group.map { |hit| type.build(hit) }
45
+ loaded = index.adapter.load(ids, **@options.merge(_index: index.base_name))
46
+ loaded ||= hit_group.map { |hit| index.build(hit) }
57
47
 
58
48
  result.merge!(hit_group.zip(loaded).to_h)
59
49
  end
@@ -63,21 +53,9 @@ module Chewy
63
53
 
64
54
  private
65
55
 
66
- def derive_index(index_name)
67
- (@derive_index ||= {})[index_name] ||= indexes_hash[index_name] ||
68
- indexes_hash[indexes_hash.keys.sort_by(&:length)
69
- .reverse.detect do |name|
70
- index_name.match(/#{name}(_.+|\z)/)
71
- end]
72
- end
73
-
74
56
  def indexes_hash
75
57
  @indexes_hash ||= @indexes.index_by(&:index_name)
76
58
  end
77
-
78
- def skip_type?(type_name)
79
- @except.include?(type_name) || @only.present? && !@only.include?(type_name)
80
- end
81
59
  end
82
60
  end
83
61
  end
@@ -0,0 +1,16 @@
1
+ require 'chewy/search/parameters/storage'
2
+
3
+ module Chewy
4
+ module Search
5
+ class Parameters
6
+ # Just a standard hash storage. Nothing to see here.
7
+ #
8
+ # @see Chewy::Search::Parameters::HashStorage
9
+ # @see Chewy::Search::Request#collapse
10
+ # @see https://www.elastic.co/guide/en/elasticsearch/reference/current/collapse-search-results.html
11
+ class Collapse < Storage
12
+ include HashStorage
13
+ end
14
+ end
15
+ end
16
+ end
@@ -5,7 +5,7 @@ module Chewy
5
5
  class Parameters
6
6
  # This is a basic storage implementation for `query`, `filter`
7
7
  # and `post_filter` storages. It uses `bool` query as a root
8
- # structure for each of them. The `bool` root is ommited on
8
+ # structure for each of them. The `bool` root is omitted on
9
9
  # rendering if there is only a single query in the `must` or
10
10
  # `should` array. Besides the standard parameter storage
11
11
  # capabilities, it provides specialized methods for the `bool`
@@ -86,7 +86,7 @@ module Chewy
86
86
  def reduce
87
87
  value = to_h
88
88
  .reject { |_, v| v.blank? }
89
- .map { |k, v| [k, v.is_a?(Array) && v.one? ? v.first : v] }.to_h
89
+ .transform_values { |v| v.is_a?(Array) && v.one? ? v.first : v }
90
90
  value.delete(:minimum_should_match) if should.empty?
91
91
  value
92
92
  end
@@ -0,0 +1,27 @@
1
+ require 'chewy/search/parameters/storage'
2
+
3
+ module Chewy
4
+ module Search
5
+ class Parameters
6
+ # Stores boolean value, but has 3 states: `true`, `false` and `nil`.
7
+ #
8
+ # @see Chewy::Search::Request#ignore_unavailable
9
+ # @see https://www.elastic.co/guide/en/elasticsearch/reference/current/multi-index.html#multi-index
10
+ class IgnoreUnavailable < Storage
11
+ # We don't want to render `nil`, but render `true` and `false` values.
12
+ #
13
+ # @see Chewy::Search::Parameters::Storage#render
14
+ # @return [{Symbol => Object}, nil]
15
+ def render
16
+ {self.class.param_name => value} unless value.nil?
17
+ end
18
+
19
+ private
20
+
21
+ def normalize(value)
22
+ !!value unless value.nil?
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -3,70 +3,48 @@ require 'chewy/search/parameters/storage'
3
3
  module Chewy
4
4
  module Search
5
5
  class Parameters
6
- # Stores indices and/or types to query.
6
+ # Stores indices to query.
7
7
  # Renders it to lists of string accepted by ElasticSearch
8
8
  # API.
9
9
  #
10
- # The semantics behind it can be described in the
11
- # following statements:
12
- # 1. If index is added to the storage, no matter, a class
10
+ # If index is added to the storage, no matter, a class
13
11
  # or a string/symbol, it gets appended to the list.
14
- # 2. If type is added to the storage, it filters out types
15
- # assigned via indices.
16
- # 3. But when a type class with non-existing index is added,
17
- # this index got also added to the list if indices.
18
- # 4. In cases when of an index identifier added, type
19
- # indetifiers also got appended instead of filtering.
20
12
  class Indices < Storage
21
13
  # Two index storages are equal if they produce the
22
14
  # same output on render.
23
15
  #
24
16
  # @see Chewy::Search::Parameters::Storage#==
25
17
  # @param other [Chewy::Search::Parameters::Storage] any storage instance
26
- # @return [true, false] the result of comparision
18
+ # @return [true, false] the result of comparison
27
19
  def ==(other)
28
20
  super || other.class == self.class && other.render == render
29
21
  end
30
22
 
31
- # Just adds types to types and indices to indices.
23
+ # Just adds indices to indices.
32
24
  #
33
25
  # @see Chewy::Search::Parameters::Storage#update!
34
- # @param other_value [{Symbol => Array<Chewy::Index, Chewy::Type, String, Symbol>}] any acceptable storage value
35
- # @return [{Symbol => Array<Chewy::Index, Chewy::Type, String, Symbol>}] updated value
26
+ # @param other_value [{Symbol => Array<Chewy::Index, String, Symbol>}] any acceptable storage value
27
+ # @return [{Symbol => Array<Chewy::Index, String, Symbol>}] updated value
36
28
  def update!(other_value)
37
29
  new_value = normalize(other_value)
38
30
 
39
- @value = {
40
- indices: value[:indices] | new_value[:indices],
41
- types: value[:types] | new_value[:types]
42
- }
31
+ @value = {indices: value[:indices] | new_value[:indices]}
43
32
  end
44
33
 
45
- # Returns desired index and type names.
34
+ # Returns desired index names.
46
35
  #
47
36
  # @see Chewy::Search::Parameters::Storage#render
48
37
  # @return [{Symbol => Array<String>}] rendered value with the parameter name
49
38
  def render
50
- {
51
- index: index_names.uniq.sort,
52
- type: type_names.uniq.sort
53
- }.reject { |_, v| v.blank? }
39
+ {index: index_names.uniq.sort}.reject { |_, v| v.blank? }
54
40
  end
55
41
 
56
42
  # Returns index classes used for the request.
57
- # No strings/symbos included.
43
+ # No strings/symbols included.
58
44
  #
59
45
  # @return [Array<Chewy::Index>] a list of index classes
60
46
  def indices
61
- index_classes | type_classes.map(&:index)
62
- end
63
-
64
- # Returns type classes used for the request.
65
- # No strings/symbos included.
66
- #
67
- # @return [Array<Chewy::Type>] a list of types classes
68
- def types
69
- type_classes | (index_classes - type_classes.map(&:index)).flat_map(&:types)
47
+ index_classes
70
48
  end
71
49
 
72
50
  private
@@ -78,10 +56,7 @@ module Chewy
78
56
  def normalize(value)
79
57
  value ||= {}
80
58
 
81
- {
82
- indices: Array.wrap(value[:indices]).flatten.compact,
83
- types: Array.wrap(value[:types]).flatten.compact
84
- }
59
+ {indices: Array.wrap(value[:indices]).flatten.compact}
85
60
  end
86
61
 
87
62
  def index_classes
@@ -97,26 +72,6 @@ module Chewy
97
72
  def index_names
98
73
  indices.map(&:index_name) | index_identifiers.map(&:to_s)
99
74
  end
100
-
101
- def type_classes
102
- value[:types].select do |klass|
103
- klass.is_a?(Class) && klass < Chewy::Type
104
- end
105
- end
106
-
107
- def type_identifiers
108
- value[:types] - type_classes
109
- end
110
-
111
- def type_names
112
- type_names = types.map(&:type_name)
113
-
114
- if index_identifiers.blank? && type_identifiers.present?
115
- (type_names & type_identifiers.map(&:to_s)).presence || type_names
116
- else
117
- type_names | type_identifiers.map(&:to_s)
118
- end
119
- end
120
75
  end
121
76
  end
122
77
  end
@@ -12,14 +12,12 @@ module Chewy
12
12
  include BoolStorage
13
13
 
14
14
  # Renders `match_none` query if the values is set to true.
15
- # Well, we can't really use match none because we need to support
16
- # ES2, so we are simulating it with `match_all` negation.
17
15
  #
18
16
  # @see https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-match-all-query.html#query-dsl-match-none-query
19
17
  # @see Chewy::Search::Request
20
18
  # @see Chewy::Search::Request#response
21
19
  def render
22
- {query: {bool: {filter: {bool: {must_not: {match_all: {}}}}}}} if value.present?
20
+ {query: {match_none: {}}} if value.present?
23
21
  end
24
22
  end
25
23
  end
@@ -17,7 +17,7 @@ module Chewy
17
17
  # @param other_value [Object] any acceptable storage value
18
18
  # @return [Object] updated value
19
19
  def update!(other_value)
20
- value.merge!(normalize(other_value))
20
+ value.concat(normalize(other_value))
21
21
  end
22
22
 
23
23
  # Size requires specialized rendering logic, it should return
@@ -28,20 +28,7 @@ module Chewy
28
28
  def render
29
29
  return if value.blank?
30
30
 
31
- sort = value.map do |(field, options)|
32
- options ? {field => options} : field
33
- end
34
- {sort: sort}
35
- end
36
-
37
- # Comparison also reqires additional logic. Hashes are compared
38
- # orderlessly, but for `sort` parameter oder is important, so we
39
- # compare hash key collections additionally.
40
- #
41
- # @see Chewy::Search::Parameters::Storage#==
42
- # @return [true, false]
43
- def ==(other)
44
- super && value.keys == other.value.keys
31
+ {sort: value}
45
32
  end
46
33
 
47
34
  private
@@ -49,13 +36,13 @@ module Chewy
49
36
  def normalize(value)
50
37
  case value
51
38
  when Array
52
- value.each_with_object({}) do |sv, res|
53
- res.merge!(normalize(sv))
39
+ value.each_with_object([]) do |sv, res|
40
+ res.concat(normalize(sv))
54
41
  end
55
42
  when Hash
56
- value.stringify_keys
43
+ [value.stringify_keys]
57
44
  else
58
- value.present? ? {value.to_s => nil} : {}
45
+ value.present? ? [value.to_s] : []
59
46
  end
60
47
  end
61
48
  end
@@ -17,7 +17,11 @@ module Chewy
17
17
  # In case of hash, respective values are concatenated as well.
18
18
  #
19
19
  # @see Chewy::Search::Parameters::Storage#update!
20
- # @param other_value [true, false, {Symbol => Array<String, Symbol>, String, Symbol}, Array<String, Symbol>, String, Symbol] any acceptable storage value
20
+ # @param other_value
21
+ # [true, false, {
22
+ # Symbol => Array<String, Symbol>, String, Symbol},
23
+ # Array<String, Symbol>, String, Symbol
24
+ # ] any acceptable storage value
21
25
  # @return [{Symbol => Array<String>, true, false}] updated value
22
26
  def update!(other_value)
23
27
  new_value = normalize(other_value)
@@ -0,0 +1,16 @@
1
+ require 'chewy/search/parameters/storage'
2
+
3
+ module Chewy
4
+ module Search
5
+ class Parameters
6
+ # Just a standard boolean storage, nothing to see here.
7
+ #
8
+ # @see Chewy::Search::Parameters::BoolStorage
9
+ # @see Chewy::Search::Request#track_total_hits
10
+ # @see https://www.elastic.co/guide/en/elasticsearch/reference/current/search-your-data.html#track-total-hits
11
+ class TrackTotalHits < Storage
12
+ include BoolStorage
13
+ end
14
+ end
15
+ end
16
+ end