chewy 0.10.1 → 7.3.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (243) hide show
  1. checksums.yaml +5 -5
  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 +74 -0
  7. data/.rubocop.yml +28 -23
  8. data/.rubocop_todo.yml +110 -22
  9. data/CHANGELOG.md +480 -298
  10. data/CODE_OF_CONDUCT.md +14 -0
  11. data/CONTRIBUTING.md +63 -0
  12. data/Gemfile +3 -5
  13. data/Guardfile +3 -1
  14. data/LICENSE.txt +1 -1
  15. data/README.md +571 -333
  16. data/chewy.gemspec +12 -15
  17. data/gemfiles/rails.5.2.activerecord.gemfile +11 -0
  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 +48 -77
  22. data/lib/chewy/errors.rb +4 -10
  23. data/lib/chewy/fields/base.rb +88 -16
  24. data/lib/chewy/fields/root.rb +15 -21
  25. data/lib/chewy/index/actions.rb +67 -38
  26. data/lib/chewy/{type → index}/adapter/active_record.rb +18 -4
  27. data/lib/chewy/{type → index}/adapter/base.rb +11 -12
  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/index/crutch.rb +40 -0
  32. data/lib/chewy/index/import/bulk_builder.rb +311 -0
  33. data/lib/chewy/{type → index}/import/bulk_request.rb +10 -9
  34. data/lib/chewy/{type → index}/import/journal_builder.rb +11 -12
  35. data/lib/chewy/{type → index}/import/routine.rb +19 -18
  36. data/lib/chewy/{type → index}/import.rb +82 -36
  37. data/lib/chewy/{type → index}/mapping.rb +63 -62
  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/settings.rb +2 -0
  42. data/lib/chewy/index/specification.rb +13 -10
  43. data/lib/chewy/{type → index}/syncer.rb +62 -63
  44. data/lib/chewy/{type → index}/witchcraft.rb +15 -9
  45. data/lib/chewy/{type → index}/wrapper.rb +16 -6
  46. data/lib/chewy/index.rb +68 -93
  47. data/lib/chewy/journal.rb +25 -14
  48. data/lib/chewy/minitest/helpers.rb +91 -18
  49. data/lib/chewy/minitest/search_index_receiver.rb +29 -33
  50. data/lib/chewy/multi_search.rb +62 -0
  51. data/lib/chewy/railtie.rb +8 -24
  52. data/lib/chewy/rake_helper.rb +141 -112
  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 +58 -49
  56. data/lib/chewy/rspec.rb +2 -0
  57. data/lib/chewy/runtime.rb +1 -1
  58. data/lib/chewy/search/loader.rb +19 -41
  59. data/lib/chewy/search/parameters/allow_partial_search_results.rb +27 -0
  60. data/lib/chewy/search/parameters/collapse.rb +16 -0
  61. data/lib/chewy/search/parameters/concerns/query_storage.rb +6 -5
  62. data/lib/chewy/search/parameters/ignore_unavailable.rb +27 -0
  63. data/lib/chewy/search/parameters/indices.rb +78 -0
  64. data/lib/chewy/search/parameters/none.rb +1 -3
  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/track_total_hits.rb +16 -0
  68. data/lib/chewy/search/parameters.rb +28 -8
  69. data/lib/chewy/search/query_proxy.rb +9 -2
  70. data/lib/chewy/search/request.rb +207 -157
  71. data/lib/chewy/search/response.rb +5 -5
  72. data/lib/chewy/search/scoping.rb +7 -8
  73. data/lib/chewy/search/scrolling.rb +14 -13
  74. data/lib/chewy/search.rb +7 -26
  75. data/lib/chewy/stash.rb +27 -29
  76. data/lib/chewy/strategy/active_job.rb +2 -2
  77. data/lib/chewy/strategy/atomic.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 +148 -0
  81. data/lib/chewy/strategy/delayed_sidekiq/worker.rb +52 -0
  82. data/lib/chewy/strategy/delayed_sidekiq.rb +17 -0
  83. data/lib/chewy/strategy/lazy_sidekiq.rb +64 -0
  84. data/lib/chewy/strategy/sidekiq.rb +3 -2
  85. data/lib/chewy/strategy.rb +6 -19
  86. data/lib/chewy/version.rb +1 -1
  87. data/lib/chewy.rb +37 -80
  88. data/lib/generators/chewy/install_generator.rb +1 -1
  89. data/lib/tasks/chewy.rake +26 -32
  90. data/migration_guide.md +56 -0
  91. data/spec/chewy/config_spec.rb +27 -57
  92. data/spec/chewy/fields/base_spec.rb +457 -174
  93. data/spec/chewy/fields/root_spec.rb +24 -32
  94. data/spec/chewy/fields/time_fields_spec.rb +5 -5
  95. data/spec/chewy/index/actions_spec.rb +425 -60
  96. data/spec/chewy/{type → index}/adapter/active_record_spec.rb +110 -44
  97. data/spec/chewy/{type → index}/adapter/object_spec.rb +21 -6
  98. data/spec/chewy/index/aliases_spec.rb +3 -3
  99. data/spec/chewy/index/import/bulk_builder_spec.rb +494 -0
  100. data/spec/chewy/{type → index}/import/bulk_request_spec.rb +5 -12
  101. data/spec/chewy/{type → index}/import/journal_builder_spec.rb +22 -30
  102. data/spec/chewy/{type → index}/import/routine_spec.rb +19 -19
  103. data/spec/chewy/{type → index}/import_spec.rb +154 -95
  104. data/spec/chewy/index/mapping_spec.rb +135 -0
  105. data/spec/chewy/index/observe/active_record_methods_spec.rb +68 -0
  106. data/spec/chewy/index/observe/callback_spec.rb +139 -0
  107. data/spec/chewy/index/observe_spec.rb +143 -0
  108. data/spec/chewy/index/settings_spec.rb +3 -1
  109. data/spec/chewy/index/specification_spec.rb +32 -33
  110. data/spec/chewy/{type → index}/syncer_spec.rb +14 -19
  111. data/spec/chewy/{type → index}/witchcraft_spec.rb +34 -21
  112. data/spec/chewy/index/wrapper_spec.rb +100 -0
  113. data/spec/chewy/index_spec.rb +99 -114
  114. data/spec/chewy/journal_spec.rb +56 -101
  115. data/spec/chewy/minitest/helpers_spec.rb +122 -14
  116. data/spec/chewy/minitest/search_index_receiver_spec.rb +24 -26
  117. data/spec/chewy/multi_search_spec.rb +84 -0
  118. data/spec/chewy/rake_helper_spec.rb +325 -101
  119. data/spec/chewy/rspec/build_query_spec.rb +34 -0
  120. data/spec/chewy/rspec/helpers_spec.rb +61 -0
  121. data/spec/chewy/rspec/update_index_spec.rb +106 -102
  122. data/spec/chewy/runtime_spec.rb +2 -2
  123. data/spec/chewy/search/loader_spec.rb +19 -53
  124. data/spec/chewy/search/pagination/kaminari_examples.rb +3 -5
  125. data/spec/chewy/search/pagination/kaminari_spec.rb +1 -1
  126. data/spec/chewy/search/parameters/collapse_spec.rb +5 -0
  127. data/spec/chewy/search/parameters/ignore_unavailable_spec.rb +67 -0
  128. data/spec/chewy/search/parameters/indices_spec.rb +99 -0
  129. data/spec/chewy/search/parameters/none_spec.rb +1 -1
  130. data/spec/chewy/search/parameters/order_spec.rb +18 -11
  131. data/spec/chewy/search/parameters/query_storage_examples.rb +67 -21
  132. data/spec/chewy/search/parameters/search_after_spec.rb +4 -1
  133. data/spec/chewy/search/parameters/source_spec.rb +8 -2
  134. data/spec/chewy/search/parameters/track_total_hits_spec.rb +5 -0
  135. data/spec/chewy/search/parameters_spec.rb +39 -8
  136. data/spec/chewy/search/query_proxy_spec.rb +68 -17
  137. data/spec/chewy/search/request_spec.rb +360 -149
  138. data/spec/chewy/search/response_spec.rb +35 -25
  139. data/spec/chewy/search/scrolling_spec.rb +28 -26
  140. data/spec/chewy/search_spec.rb +73 -53
  141. data/spec/chewy/stash_spec.rb +16 -26
  142. data/spec/chewy/strategy/active_job_spec.rb +23 -10
  143. data/spec/chewy/strategy/atomic_no_refresh_spec.rb +60 -0
  144. data/spec/chewy/strategy/atomic_spec.rb +9 -10
  145. data/spec/chewy/strategy/delayed_sidekiq_spec.rb +190 -0
  146. data/spec/chewy/strategy/lazy_sidekiq_spec.rb +214 -0
  147. data/spec/chewy/strategy/sidekiq_spec.rb +14 -10
  148. data/spec/chewy/strategy_spec.rb +19 -15
  149. data/spec/chewy_spec.rb +17 -110
  150. data/spec/spec_helper.rb +7 -22
  151. data/spec/support/active_record.rb +43 -5
  152. metadata +123 -198
  153. data/.travis.yml +0 -53
  154. data/Appraisals +0 -79
  155. data/LEGACY_DSL.md +0 -497
  156. data/gemfiles/rails.4.0.activerecord.gemfile +0 -14
  157. data/gemfiles/rails.4.1.activerecord.gemfile +0 -14
  158. data/gemfiles/rails.4.2.activerecord.gemfile +0 -15
  159. data/gemfiles/rails.4.2.mongoid.5.1.gemfile +0 -15
  160. data/gemfiles/rails.5.0.activerecord.gemfile +0 -15
  161. data/gemfiles/rails.5.0.mongoid.6.0.gemfile +0 -15
  162. data/gemfiles/rails.5.1.activerecord.gemfile +0 -15
  163. data/gemfiles/rails.5.1.mongoid.6.1.gemfile +0 -15
  164. data/gemfiles/sequel.4.45.gemfile +0 -11
  165. data/lib/chewy/backports/deep_dup.rb +0 -46
  166. data/lib/chewy/backports/duplicable.rb +0 -91
  167. data/lib/chewy/query/compose.rb +0 -68
  168. data/lib/chewy/query/criteria.rb +0 -191
  169. data/lib/chewy/query/filters.rb +0 -227
  170. data/lib/chewy/query/loading.rb +0 -111
  171. data/lib/chewy/query/nodes/and.rb +0 -25
  172. data/lib/chewy/query/nodes/base.rb +0 -17
  173. data/lib/chewy/query/nodes/bool.rb +0 -34
  174. data/lib/chewy/query/nodes/equal.rb +0 -34
  175. data/lib/chewy/query/nodes/exists.rb +0 -20
  176. data/lib/chewy/query/nodes/expr.rb +0 -28
  177. data/lib/chewy/query/nodes/field.rb +0 -110
  178. data/lib/chewy/query/nodes/has_child.rb +0 -15
  179. data/lib/chewy/query/nodes/has_parent.rb +0 -15
  180. data/lib/chewy/query/nodes/has_relation.rb +0 -59
  181. data/lib/chewy/query/nodes/match_all.rb +0 -11
  182. data/lib/chewy/query/nodes/missing.rb +0 -20
  183. data/lib/chewy/query/nodes/not.rb +0 -25
  184. data/lib/chewy/query/nodes/or.rb +0 -25
  185. data/lib/chewy/query/nodes/prefix.rb +0 -19
  186. data/lib/chewy/query/nodes/query.rb +0 -20
  187. data/lib/chewy/query/nodes/range.rb +0 -63
  188. data/lib/chewy/query/nodes/raw.rb +0 -15
  189. data/lib/chewy/query/nodes/regexp.rb +0 -35
  190. data/lib/chewy/query/nodes/script.rb +0 -20
  191. data/lib/chewy/query/pagination.rb +0 -25
  192. data/lib/chewy/query.rb +0 -1098
  193. data/lib/chewy/search/pagination/will_paginate.rb +0 -43
  194. data/lib/chewy/search/parameters/types.rb +0 -20
  195. data/lib/chewy/strategy/resque.rb +0 -27
  196. data/lib/chewy/strategy/shoryuken.rb +0 -40
  197. data/lib/chewy/type/actions.rb +0 -43
  198. data/lib/chewy/type/adapter/mongoid.rb +0 -69
  199. data/lib/chewy/type/adapter/sequel.rb +0 -95
  200. data/lib/chewy/type/crutch.rb +0 -32
  201. data/lib/chewy/type/import/bulk_builder.rb +0 -122
  202. data/lib/chewy/type/observe.rb +0 -78
  203. data/lib/chewy/type.rb +0 -117
  204. data/lib/sequel/plugins/chewy_observe.rb +0 -78
  205. data/spec/chewy/query/criteria_spec.rb +0 -700
  206. data/spec/chewy/query/filters_spec.rb +0 -201
  207. data/spec/chewy/query/loading_spec.rb +0 -124
  208. data/spec/chewy/query/nodes/and_spec.rb +0 -12
  209. data/spec/chewy/query/nodes/bool_spec.rb +0 -14
  210. data/spec/chewy/query/nodes/equal_spec.rb +0 -32
  211. data/spec/chewy/query/nodes/exists_spec.rb +0 -18
  212. data/spec/chewy/query/nodes/has_child_spec.rb +0 -59
  213. data/spec/chewy/query/nodes/has_parent_spec.rb +0 -59
  214. data/spec/chewy/query/nodes/match_all_spec.rb +0 -11
  215. data/spec/chewy/query/nodes/missing_spec.rb +0 -16
  216. data/spec/chewy/query/nodes/not_spec.rb +0 -13
  217. data/spec/chewy/query/nodes/or_spec.rb +0 -12
  218. data/spec/chewy/query/nodes/prefix_spec.rb +0 -16
  219. data/spec/chewy/query/nodes/query_spec.rb +0 -12
  220. data/spec/chewy/query/nodes/range_spec.rb +0 -32
  221. data/spec/chewy/query/nodes/raw_spec.rb +0 -11
  222. data/spec/chewy/query/nodes/regexp_spec.rb +0 -43
  223. data/spec/chewy/query/nodes/script_spec.rb +0 -15
  224. data/spec/chewy/query/pagination/kaminari_spec.rb +0 -5
  225. data/spec/chewy/query/pagination/will_paginate_spec.rb +0 -5
  226. data/spec/chewy/query/pagination_spec.rb +0 -39
  227. data/spec/chewy/query_spec.rb +0 -636
  228. data/spec/chewy/search/pagination/will_paginate_examples.rb +0 -63
  229. data/spec/chewy/search/pagination/will_paginate_spec.rb +0 -23
  230. data/spec/chewy/search/parameters/indices_boost_spec.rb +0 -83
  231. data/spec/chewy/search/parameters/types_spec.rb +0 -5
  232. data/spec/chewy/strategy/resque_spec.rb +0 -46
  233. data/spec/chewy/strategy/shoryuken_spec.rb +0 -64
  234. data/spec/chewy/type/actions_spec.rb +0 -50
  235. data/spec/chewy/type/adapter/mongoid_spec.rb +0 -372
  236. data/spec/chewy/type/adapter/sequel_spec.rb +0 -472
  237. data/spec/chewy/type/import/bulk_builder_spec.rb +0 -279
  238. data/spec/chewy/type/mapping_spec.rb +0 -142
  239. data/spec/chewy/type/observe_spec.rb +0 -137
  240. data/spec/chewy/type/wrapper_spec.rb +0 -98
  241. data/spec/chewy/type_spec.rb +0 -55
  242. data/spec/support/mongoid.rb +0 -93
  243. 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,40 +73,45 @@ 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
- if @reindex.blank? && @delete.blank?
87
- raise 'Use `only` in conjunction with `and_reindex` or `and_delete`'
88
- end
86
+ raise 'Use `only` in conjunction with `and_reindex` or `and_delete`' if @reindex.blank? && @delete.blank?
89
87
 
90
88
  @only = true
91
89
  end
92
90
 
91
+ # Expect import to be called with refresh=false parameter
92
+ chain(:no_refresh) do
93
+ @no_refresh = true
94
+ end
95
+
93
96
  def supports_block_expectations?
94
97
  true
95
98
  end
96
99
 
97
- match do |block| # rubocop:disable BlockLength
100
+ match do |block| # rubocop:disable Metrics/BlockLength
98
101
  @reindex ||= {}
99
102
  @delete ||= {}
100
103
  @missed_reindex = []
101
104
  @missed_delete = []
102
105
 
103
- type = Chewy.derive_type(type_name)
106
+ index = Chewy.derive_name(index_name)
104
107
  if defined?(Mocha) && RSpec.configuration.mock_framework.to_s == 'RSpec::Core::MockingAdapters::Mocha'
105
- 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)
106
110
  else
107
- mocked_already = ::RSpec::Mocks.space.proxy_for(Chewy::Type::Import::BulkRequest).method_double_if_exists_for_message(:new)
108
- allow(Chewy::Type::Import::BulkRequest).to receive(:new).and_call_original unless mocked_already
109
- 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)
110
115
  end
111
116
 
112
117
  Chewy.strategy(options[:strategy] || :atomic) { block.call }
@@ -128,14 +133,14 @@ RSpec::Matchers.define :update_index do |type_name, options = {}| # rubocop:disa
128
133
  end
129
134
  end
130
135
 
131
- @reindex.each do |_, document|
132
- document[:match_count] = (!document[:expected_count] && document[:real_count] > 0) ||
136
+ @reindex.each_value do |document|
137
+ document[:match_count] = (!document[:expected_count] && (document[:real_count]).positive?) ||
133
138
  (document[:expected_count] && document[:expected_count] == document[:real_count])
134
139
  document[:match_attributes] = document[:expected_attributes].blank? ||
135
140
  compare_attributes(document[:expected_attributes], document[:real_attributes])
136
141
  end
137
- @delete.each do |_, document|
138
- document[:match_count] = (!document[:expected_count] && document[:real_count] > 0) ||
142
+ @delete.each_value do |document|
143
+ document[:match_count] = (!document[:expected_count] && (document[:real_count]).positive?) ||
139
144
  (document[:expected_count] && document[:expected_count] == document[:real_count])
140
145
  end
141
146
 
@@ -144,13 +149,13 @@ RSpec::Matchers.define :update_index do |type_name, options = {}| # rubocop:disa
144
149
  @delete.all? { |_, document| document[:match_count] }
145
150
  end
146
151
 
147
- failure_message do # rubocop:disable BlockLength
152
+ failure_message do # rubocop:disable Metrics/BlockLength
148
153
  output = ''
149
154
 
150
155
  if mock_bulk_request.updates.none?
151
- 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"
152
157
  elsif @missed_reindex.present? || @missed_delete.present?
153
- message = "Expected index `#{type_name}` "
158
+ message = "Expected index `#{index_name}` "
154
159
  message << [
155
160
  ("to update documents #{@reindex.keys}" if @reindex.present?),
156
161
  ("to delete documents #{@delete.keys}" if @delete.present?)
@@ -168,9 +173,13 @@ RSpec::Matchers.define :update_index do |type_name, options = {}| # rubocop:disa
168
173
  output << @reindex.each.with_object('') do |(id, document), result|
169
174
  unless document[:match_count] && document[:match_attributes]
170
175
  result << "Expected document with id `#{id}` to be reindexed"
171
- if document[:real_count] > 0
172
- result << "\n #{document[:expected_count]} times, but was reindexed #{document[:real_count]} times" if document[:expected_count] && !document[:match_count]
173
- 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
174
183
  else
175
184
  result << ', but it was not'
176
185
  end
@@ -181,11 +190,11 @@ RSpec::Matchers.define :update_index do |type_name, options = {}| # rubocop:disa
181
190
  output << @delete.each.with_object('') do |(id, document), result|
182
191
  unless document[:match_count]
183
192
  result << "Expected document with id `#{id}` to be deleted"
184
- result << if document[:real_count] > 0 && document[:expected_count]
185
- "\n #{document[:expected_count]} times, but was deleted #{document[:real_count]} times"
186
- else
187
- ', but it was not'
188
- 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
189
198
  result << "\n"
190
199
  end
191
200
  end
@@ -195,9 +204,9 @@ RSpec::Matchers.define :update_index do |type_name, options = {}| # rubocop:disa
195
204
 
196
205
  failure_message_when_negated do
197
206
  if mock_bulk_request.updates.present?
198
- "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|
199
- "\n document id `#{id}` (#{documents.count} times)"
200
- 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"
201
210
  end
202
211
  end
203
212
 
@@ -211,7 +220,7 @@ RSpec::Matchers.define :update_index do |type_name, options = {}| # rubocop:disa
211
220
  expected_count = options[:times] || options[:count]
212
221
  expected_attributes = (options[:with] || options[:attributes] || {}).deep_symbolize_keys
213
222
 
214
- Hash[args.flatten.map do |document|
223
+ args.flatten.map do |document|
215
224
  id = document.respond_to?(:id) ? document.id.to_s : document.to_s
216
225
  [id, {
217
226
  document: document,
@@ -220,7 +229,7 @@ RSpec::Matchers.define :update_index do |type_name, options = {}| # rubocop:disa
220
229
  real_count: 0,
221
230
  real_attributes: {}
222
231
  }]
223
- end]
232
+ end.to_h
224
233
  end
225
234
 
226
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,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#allow_partial_search_results
9
+ # @see https://www.elastic.co/guide/en/elasticsearch/reference/6.4/search-request-body.html#_parameters_4
10
+ class AllowPartialSearchResults < 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
@@ -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`
@@ -20,16 +20,17 @@ module Chewy
20
20
  # rendering logic.
21
21
  #
22
22
  # @!attribute must
23
- # @return [Array<Hash>]
23
+ # @return [Array<Hash>, Hash, nil]
24
24
  # @!attribute should
25
- # @return [Array<Hash>]
25
+ # @return [Array<Hash>, Hash, nil]
26
26
  # @!attribute must_not
27
- # @return [Array<Hash>]
27
+ # @return [[Array<Hash>, Hash, nil]
28
28
  # @!attribute minimum_should_match
29
29
  # @return [String, Integer, nil]
30
30
  class Bool
31
31
  # Acceptable bool query keys
32
32
  KEYS = %i[must should must_not minimum_should_match].freeze
33
+ # @!ignorewarning
33
34
  attr_reader(*KEYS)
34
35
 
35
36
  # @param must [Array<Hash>, Hash, nil]
@@ -85,7 +86,7 @@ module Chewy
85
86
  def reduce
86
87
  value = to_h
87
88
  .reject { |_, v| v.blank? }
88
- .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 }
89
90
  value.delete(:minimum_should_match) if should.empty?
90
91
  value
91
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
@@ -0,0 +1,78 @@
1
+ require 'chewy/search/parameters/storage'
2
+
3
+ module Chewy
4
+ module Search
5
+ class Parameters
6
+ # Stores indices to query.
7
+ # Renders it to lists of string accepted by ElasticSearch
8
+ # API.
9
+ #
10
+ # If index is added to the storage, no matter, a class
11
+ # or a string/symbol, it gets appended to the list.
12
+ class Indices < Storage
13
+ # Two index storages are equal if they produce the
14
+ # same output on render.
15
+ #
16
+ # @see Chewy::Search::Parameters::Storage#==
17
+ # @param other [Chewy::Search::Parameters::Storage] any storage instance
18
+ # @return [true, false] the result of comparison
19
+ def ==(other)
20
+ super || other.class == self.class && other.render == render
21
+ end
22
+
23
+ # Just adds indices to indices.
24
+ #
25
+ # @see Chewy::Search::Parameters::Storage#update!
26
+ # @param other_value [{Symbol => Array<Chewy::Index, String, Symbol>}] any acceptable storage value
27
+ # @return [{Symbol => Array<Chewy::Index, String, Symbol>}] updated value
28
+ def update!(other_value)
29
+ new_value = normalize(other_value)
30
+
31
+ @value = {indices: value[:indices] | new_value[:indices]}
32
+ end
33
+
34
+ # Returns desired index names.
35
+ #
36
+ # @see Chewy::Search::Parameters::Storage#render
37
+ # @return [{Symbol => Array<String>}] rendered value with the parameter name
38
+ def render
39
+ {index: index_names.uniq.sort}.reject { |_, v| v.blank? }
40
+ end
41
+
42
+ # Returns index classes used for the request.
43
+ # No strings/symbols included.
44
+ #
45
+ # @return [Array<Chewy::Index>] a list of index classes
46
+ def indices
47
+ index_classes
48
+ end
49
+
50
+ private
51
+
52
+ def initialize_clone(origin)
53
+ @value = origin.value.dup
54
+ end
55
+
56
+ def normalize(value)
57
+ value ||= {}
58
+
59
+ {indices: Array.wrap(value[:indices]).flatten.compact}
60
+ end
61
+
62
+ def index_classes
63
+ value[:indices].select do |klass|
64
+ klass.is_a?(Class) && klass < Chewy::Index
65
+ end
66
+ end
67
+
68
+ def index_identifiers
69
+ value[:indices] - index_classes
70
+ end
71
+
72
+ def index_names
73
+ indices.map(&:index_name) | index_identifiers.map(&:to_s)
74
+ end
75
+ end
76
+ end
77
+ end
78
+ 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