chewy 0.8.4 → 7.3.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (340) 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/.gitignore +1 -0
  8. data/.rubocop.yml +61 -0
  9. data/.rubocop_todo.yml +132 -0
  10. data/.yardopts +5 -0
  11. data/CHANGELOG.md +554 -245
  12. data/CODE_OF_CONDUCT.md +14 -0
  13. data/CONTRIBUTING.md +63 -0
  14. data/Gemfile +14 -11
  15. data/Guardfile +8 -6
  16. data/LICENSE.txt +1 -1
  17. data/README.md +748 -623
  18. data/Rakefile +11 -1
  19. data/chewy.gemspec +15 -19
  20. data/gemfiles/rails.5.2.activerecord.gemfile +11 -0
  21. data/gemfiles/rails.6.0.activerecord.gemfile +11 -0
  22. data/gemfiles/rails.6.1.activerecord.gemfile +13 -0
  23. data/gemfiles/rails.7.0.activerecord.gemfile +13 -0
  24. data/lib/chewy/config.rb +64 -50
  25. data/lib/chewy/errors.rb +10 -16
  26. data/lib/chewy/fields/base.rb +122 -32
  27. data/lib/chewy/fields/root.rb +48 -23
  28. data/lib/chewy/index/actions.rb +140 -54
  29. data/lib/chewy/index/adapter/active_record.rb +112 -0
  30. data/lib/chewy/{type → index}/adapter/base.rb +31 -12
  31. data/lib/chewy/index/adapter/object.rb +249 -0
  32. data/lib/chewy/index/adapter/orm.rb +194 -0
  33. data/lib/chewy/index/aliases.rb +14 -4
  34. data/lib/chewy/index/crutch.rb +40 -0
  35. data/lib/chewy/index/import/bulk_builder.rb +311 -0
  36. data/lib/chewy/index/import/bulk_request.rb +77 -0
  37. data/lib/chewy/index/import/journal_builder.rb +44 -0
  38. data/lib/chewy/index/import/routine.rb +139 -0
  39. data/lib/chewy/index/import.rb +243 -0
  40. data/lib/chewy/{type → index}/mapping.rb +79 -68
  41. data/lib/chewy/index/observe/active_record_methods.rb +87 -0
  42. data/lib/chewy/index/observe/callback.rb +34 -0
  43. data/lib/chewy/index/observe.rb +17 -0
  44. data/lib/chewy/index/settings.rb +10 -5
  45. data/lib/chewy/index/specification.rb +61 -0
  46. data/lib/chewy/index/syncer.rb +221 -0
  47. data/lib/chewy/{type → index}/witchcraft.rb +100 -39
  48. data/lib/chewy/index/wrapper.rb +95 -0
  49. data/lib/chewy/index.rb +216 -140
  50. data/lib/chewy/journal.rb +66 -0
  51. data/lib/chewy/log_subscriber.rb +8 -8
  52. data/lib/chewy/minitest/helpers.rb +150 -0
  53. data/lib/chewy/minitest/search_index_receiver.rb +76 -0
  54. data/lib/chewy/minitest.rb +1 -0
  55. data/lib/chewy/multi_search.rb +62 -0
  56. data/lib/chewy/railtie.rb +12 -25
  57. data/lib/chewy/rake_helper.rb +335 -37
  58. data/lib/chewy/repository.rb +2 -2
  59. data/lib/chewy/rspec/build_query.rb +12 -0
  60. data/lib/chewy/rspec/helpers.rb +55 -0
  61. data/lib/chewy/rspec/update_index.rb +106 -90
  62. data/lib/chewy/rspec.rb +3 -1
  63. data/lib/chewy/runtime/version.rb +4 -4
  64. data/lib/chewy/runtime.rb +1 -1
  65. data/lib/chewy/search/loader.rb +61 -0
  66. data/lib/chewy/{query → search}/pagination/kaminari.rb +13 -5
  67. data/lib/chewy/search/parameters/aggs.rb +16 -0
  68. data/lib/chewy/search/parameters/allow_partial_search_results.rb +27 -0
  69. data/lib/chewy/search/parameters/collapse.rb +16 -0
  70. data/lib/chewy/search/parameters/concerns/bool_storage.rb +24 -0
  71. data/lib/chewy/search/parameters/concerns/hash_storage.rb +23 -0
  72. data/lib/chewy/search/parameters/concerns/integer_storage.rb +14 -0
  73. data/lib/chewy/search/parameters/concerns/query_storage.rb +238 -0
  74. data/lib/chewy/search/parameters/concerns/string_array_storage.rb +23 -0
  75. data/lib/chewy/search/parameters/concerns/string_storage.rb +14 -0
  76. data/lib/chewy/search/parameters/docvalue_fields.rb +12 -0
  77. data/lib/chewy/search/parameters/explain.rb +16 -0
  78. data/lib/chewy/search/parameters/filter.rb +47 -0
  79. data/lib/chewy/search/parameters/highlight.rb +16 -0
  80. data/lib/chewy/search/parameters/ignore_unavailable.rb +27 -0
  81. data/lib/chewy/search/parameters/indices.rb +78 -0
  82. data/lib/chewy/search/parameters/indices_boost.rb +52 -0
  83. data/lib/chewy/search/parameters/limit.rb +17 -0
  84. data/lib/chewy/search/parameters/load.rb +32 -0
  85. data/lib/chewy/search/parameters/min_score.rb +16 -0
  86. data/lib/chewy/search/parameters/none.rb +25 -0
  87. data/lib/chewy/search/parameters/offset.rb +17 -0
  88. data/lib/chewy/search/parameters/order.rb +51 -0
  89. data/lib/chewy/search/parameters/post_filter.rb +19 -0
  90. data/lib/chewy/search/parameters/preference.rb +16 -0
  91. data/lib/chewy/search/parameters/profile.rb +16 -0
  92. data/lib/chewy/search/parameters/query.rb +19 -0
  93. data/lib/chewy/search/parameters/request_cache.rb +27 -0
  94. data/lib/chewy/search/parameters/rescore.rb +29 -0
  95. data/lib/chewy/search/parameters/script_fields.rb +16 -0
  96. data/lib/chewy/search/parameters/search_after.rb +20 -0
  97. data/lib/chewy/search/parameters/search_type.rb +16 -0
  98. data/lib/chewy/search/parameters/source.rb +77 -0
  99. data/lib/chewy/search/parameters/storage.rb +95 -0
  100. data/lib/chewy/search/parameters/stored_fields.rb +63 -0
  101. data/lib/chewy/search/parameters/suggest.rb +16 -0
  102. data/lib/chewy/search/parameters/terminate_after.rb +16 -0
  103. data/lib/chewy/search/parameters/timeout.rb +16 -0
  104. data/lib/chewy/search/parameters/track_scores.rb +16 -0
  105. data/lib/chewy/search/parameters/track_total_hits.rb +16 -0
  106. data/lib/chewy/search/parameters/version.rb +16 -0
  107. data/lib/chewy/search/parameters.rb +170 -0
  108. data/lib/chewy/search/query_proxy.rb +264 -0
  109. data/lib/chewy/search/request.rb +1071 -0
  110. data/lib/chewy/search/response.rb +119 -0
  111. data/lib/chewy/search/scoping.rb +49 -0
  112. data/lib/chewy/search/scrolling.rb +137 -0
  113. data/lib/chewy/search.rb +68 -28
  114. data/lib/chewy/stash.rb +68 -0
  115. data/lib/chewy/strategy/active_job.rb +3 -2
  116. data/lib/chewy/strategy/atomic.rb +2 -4
  117. data/lib/chewy/strategy/atomic_no_refresh.rb +18 -0
  118. data/lib/chewy/strategy/base.rb +13 -3
  119. data/lib/chewy/strategy/bypass.rb +1 -2
  120. data/lib/chewy/strategy/delayed_sidekiq/scheduler.rb +148 -0
  121. data/lib/chewy/strategy/delayed_sidekiq/worker.rb +52 -0
  122. data/lib/chewy/strategy/delayed_sidekiq.rb +17 -0
  123. data/lib/chewy/strategy/lazy_sidekiq.rb +64 -0
  124. data/lib/chewy/strategy/sidekiq.rb +15 -2
  125. data/lib/chewy/strategy/urgent.rb +1 -1
  126. data/lib/chewy/strategy.rb +16 -20
  127. data/lib/chewy/version.rb +1 -1
  128. data/lib/chewy.rb +81 -82
  129. data/lib/generators/chewy/install_generator.rb +3 -3
  130. data/lib/tasks/chewy.rake +99 -32
  131. data/migration_guide.md +56 -0
  132. data/spec/chewy/config_spec.rb +87 -15
  133. data/spec/chewy/fields/base_spec.rb +542 -233
  134. data/spec/chewy/fields/root_spec.rb +115 -17
  135. data/spec/chewy/fields/time_fields_spec.rb +13 -12
  136. data/spec/chewy/index/actions_spec.rb +595 -77
  137. data/spec/chewy/index/adapter/active_record_spec.rb +601 -0
  138. data/spec/chewy/index/adapter/object_spec.rb +243 -0
  139. data/spec/chewy/index/aliases_spec.rb +5 -5
  140. data/spec/chewy/index/import/bulk_builder_spec.rb +494 -0
  141. data/spec/chewy/index/import/bulk_request_spec.rb +95 -0
  142. data/spec/chewy/index/import/journal_builder_spec.rb +87 -0
  143. data/spec/chewy/index/import/routine_spec.rb +110 -0
  144. data/spec/chewy/index/import_spec.rb +615 -0
  145. data/spec/chewy/index/mapping_spec.rb +135 -0
  146. data/spec/chewy/index/observe/active_record_methods_spec.rb +68 -0
  147. data/spec/chewy/index/observe/callback_spec.rb +139 -0
  148. data/spec/chewy/index/observe_spec.rb +143 -0
  149. data/spec/chewy/index/settings_spec.rb +103 -50
  150. data/spec/chewy/index/specification_spec.rb +159 -0
  151. data/spec/chewy/index/syncer_spec.rb +118 -0
  152. data/spec/chewy/index/witchcraft_spec.rb +245 -0
  153. data/spec/chewy/index/wrapper_spec.rb +100 -0
  154. data/spec/chewy/index_spec.rb +149 -121
  155. data/spec/chewy/journal_spec.rb +223 -0
  156. data/spec/chewy/minitest/helpers_spec.rb +198 -0
  157. data/spec/chewy/minitest/search_index_receiver_spec.rb +118 -0
  158. data/spec/chewy/multi_search_spec.rb +84 -0
  159. data/spec/chewy/rake_helper_spec.rb +656 -0
  160. data/spec/chewy/repository_spec.rb +8 -8
  161. data/spec/chewy/rspec/build_query_spec.rb +34 -0
  162. data/spec/chewy/rspec/helpers_spec.rb +61 -0
  163. data/spec/chewy/rspec/update_index_spec.rb +220 -114
  164. data/spec/chewy/runtime_spec.rb +2 -2
  165. data/spec/chewy/search/loader_spec.rb +83 -0
  166. data/spec/chewy/search/pagination/kaminari_examples.rb +69 -0
  167. data/spec/chewy/search/pagination/kaminari_spec.rb +21 -0
  168. data/spec/chewy/search/parameters/aggs_spec.rb +5 -0
  169. data/spec/chewy/search/parameters/bool_storage_examples.rb +53 -0
  170. data/spec/chewy/search/parameters/collapse_spec.rb +5 -0
  171. data/spec/chewy/search/parameters/docvalue_fields_spec.rb +5 -0
  172. data/spec/chewy/search/parameters/explain_spec.rb +5 -0
  173. data/spec/chewy/search/parameters/filter_spec.rb +5 -0
  174. data/spec/chewy/search/parameters/hash_storage_examples.rb +59 -0
  175. data/spec/chewy/search/parameters/highlight_spec.rb +5 -0
  176. data/spec/chewy/search/parameters/ignore_unavailable_spec.rb +67 -0
  177. data/spec/chewy/search/parameters/indices_spec.rb +99 -0
  178. data/spec/chewy/search/parameters/integer_storage_examples.rb +32 -0
  179. data/spec/chewy/search/parameters/limit_spec.rb +5 -0
  180. data/spec/chewy/search/parameters/load_spec.rb +60 -0
  181. data/spec/chewy/search/parameters/min_score_spec.rb +32 -0
  182. data/spec/chewy/search/parameters/none_spec.rb +5 -0
  183. data/spec/chewy/search/parameters/offset_spec.rb +5 -0
  184. data/spec/chewy/search/parameters/order_spec.rb +72 -0
  185. data/spec/chewy/search/parameters/post_filter_spec.rb +5 -0
  186. data/spec/chewy/search/parameters/preference_spec.rb +5 -0
  187. data/spec/chewy/search/parameters/profile_spec.rb +5 -0
  188. data/spec/chewy/search/parameters/query_spec.rb +5 -0
  189. data/spec/chewy/search/parameters/query_storage_examples.rb +434 -0
  190. data/spec/chewy/search/parameters/request_cache_spec.rb +67 -0
  191. data/spec/chewy/search/parameters/rescore_spec.rb +62 -0
  192. data/spec/chewy/search/parameters/script_fields_spec.rb +5 -0
  193. data/spec/chewy/search/parameters/search_after_spec.rb +35 -0
  194. data/spec/chewy/search/parameters/search_type_spec.rb +5 -0
  195. data/spec/chewy/search/parameters/source_spec.rb +162 -0
  196. data/spec/chewy/search/parameters/storage_spec.rb +60 -0
  197. data/spec/chewy/search/parameters/stored_fields_spec.rb +126 -0
  198. data/spec/chewy/search/parameters/string_array_storage_examples.rb +63 -0
  199. data/spec/chewy/search/parameters/string_storage_examples.rb +32 -0
  200. data/spec/chewy/search/parameters/suggest_spec.rb +5 -0
  201. data/spec/chewy/search/parameters/terminate_after_spec.rb +5 -0
  202. data/spec/chewy/search/parameters/timeout_spec.rb +5 -0
  203. data/spec/chewy/search/parameters/track_scores_spec.rb +5 -0
  204. data/spec/chewy/search/parameters/track_total_hits_spec.rb +5 -0
  205. data/spec/chewy/search/parameters/version_spec.rb +5 -0
  206. data/spec/chewy/search/parameters_spec.rb +161 -0
  207. data/spec/chewy/search/query_proxy_spec.rb +119 -0
  208. data/spec/chewy/search/request_spec.rb +880 -0
  209. data/spec/chewy/search/response_spec.rb +202 -0
  210. data/spec/chewy/search/scrolling_spec.rb +171 -0
  211. data/spec/chewy/search_spec.rb +82 -55
  212. data/spec/chewy/stash_spec.rb +85 -0
  213. data/spec/chewy/strategy/active_job_spec.rb +27 -8
  214. data/spec/chewy/strategy/atomic_no_refresh_spec.rb +60 -0
  215. data/spec/chewy/strategy/atomic_spec.rb +13 -11
  216. data/spec/chewy/strategy/delayed_sidekiq_spec.rb +190 -0
  217. data/spec/chewy/strategy/lazy_sidekiq_spec.rb +214 -0
  218. data/spec/chewy/strategy/sidekiq_spec.rb +19 -7
  219. data/spec/chewy/strategy_spec.rb +19 -15
  220. data/spec/chewy_spec.rb +65 -88
  221. data/spec/spec_helper.rb +11 -20
  222. data/spec/support/active_record.rb +48 -6
  223. data/spec/support/class_helpers.rb +4 -19
  224. metadata +299 -183
  225. data/.travis.yml +0 -76
  226. data/Appraisals +0 -76
  227. data/gemfiles/rails.3.2.activerecord.gemfile +0 -15
  228. data/gemfiles/rails.3.2.activerecord.kaminari.gemfile +0 -14
  229. data/gemfiles/rails.3.2.activerecord.will_paginate.gemfile +0 -14
  230. data/gemfiles/rails.4.0.activerecord.gemfile +0 -15
  231. data/gemfiles/rails.4.0.activerecord.kaminari.gemfile +0 -14
  232. data/gemfiles/rails.4.0.activerecord.will_paginate.gemfile +0 -14
  233. data/gemfiles/rails.4.0.mongoid.4.0.0.gemfile +0 -15
  234. data/gemfiles/rails.4.0.mongoid.4.0.0.kaminari.gemfile +0 -14
  235. data/gemfiles/rails.4.0.mongoid.4.0.0.will_paginate.gemfile +0 -14
  236. data/gemfiles/rails.4.0.mongoid.5.1.0.gemfile +0 -15
  237. data/gemfiles/rails.4.0.mongoid.5.1.0.kaminari.gemfile +0 -14
  238. data/gemfiles/rails.4.0.mongoid.5.1.0.will_paginate.gemfile +0 -14
  239. data/gemfiles/rails.4.1.activerecord.gemfile +0 -15
  240. data/gemfiles/rails.4.1.activerecord.kaminari.gemfile +0 -14
  241. data/gemfiles/rails.4.1.activerecord.will_paginate.gemfile +0 -14
  242. data/gemfiles/rails.4.1.mongoid.4.0.0.gemfile +0 -15
  243. data/gemfiles/rails.4.1.mongoid.4.0.0.kaminari.gemfile +0 -14
  244. data/gemfiles/rails.4.1.mongoid.4.0.0.will_paginate.gemfile +0 -14
  245. data/gemfiles/rails.4.1.mongoid.5.1.0.gemfile +0 -15
  246. data/gemfiles/rails.4.1.mongoid.5.1.0.kaminari.gemfile +0 -14
  247. data/gemfiles/rails.4.1.mongoid.5.1.0.will_paginate.gemfile +0 -14
  248. data/gemfiles/rails.4.2.activerecord.gemfile +0 -16
  249. data/gemfiles/rails.4.2.activerecord.kaminari.gemfile +0 -15
  250. data/gemfiles/rails.4.2.activerecord.will_paginate.gemfile +0 -15
  251. data/gemfiles/rails.4.2.mongoid.4.0.0.gemfile +0 -15
  252. data/gemfiles/rails.4.2.mongoid.4.0.0.kaminari.gemfile +0 -14
  253. data/gemfiles/rails.4.2.mongoid.4.0.0.will_paginate.gemfile +0 -14
  254. data/gemfiles/rails.4.2.mongoid.5.1.0.gemfile +0 -15
  255. data/gemfiles/rails.4.2.mongoid.5.1.0.kaminari.gemfile +0 -14
  256. data/gemfiles/rails.4.2.mongoid.5.1.0.will_paginate.gemfile +0 -14
  257. data/gemfiles/rails.5.0.0.beta3.activerecord.gemfile +0 -16
  258. data/gemfiles/rails.5.0.0.beta3.activerecord.kaminari.gemfile +0 -16
  259. data/gemfiles/rails.5.0.0.beta3.activerecord.will_paginate.gemfile +0 -15
  260. data/gemfiles/sequel.4.31.gemfile +0 -13
  261. data/lib/chewy/backports/deep_dup.rb +0 -46
  262. data/lib/chewy/backports/duplicable.rb +0 -90
  263. data/lib/chewy/query/compose.rb +0 -69
  264. data/lib/chewy/query/criteria.rb +0 -181
  265. data/lib/chewy/query/filters.rb +0 -227
  266. data/lib/chewy/query/loading.rb +0 -111
  267. data/lib/chewy/query/nodes/and.rb +0 -25
  268. data/lib/chewy/query/nodes/base.rb +0 -17
  269. data/lib/chewy/query/nodes/bool.rb +0 -32
  270. data/lib/chewy/query/nodes/equal.rb +0 -34
  271. data/lib/chewy/query/nodes/exists.rb +0 -20
  272. data/lib/chewy/query/nodes/expr.rb +0 -28
  273. data/lib/chewy/query/nodes/field.rb +0 -106
  274. data/lib/chewy/query/nodes/has_child.rb +0 -14
  275. data/lib/chewy/query/nodes/has_parent.rb +0 -14
  276. data/lib/chewy/query/nodes/has_relation.rb +0 -61
  277. data/lib/chewy/query/nodes/match_all.rb +0 -11
  278. data/lib/chewy/query/nodes/missing.rb +0 -20
  279. data/lib/chewy/query/nodes/not.rb +0 -25
  280. data/lib/chewy/query/nodes/or.rb +0 -25
  281. data/lib/chewy/query/nodes/prefix.rb +0 -18
  282. data/lib/chewy/query/nodes/query.rb +0 -20
  283. data/lib/chewy/query/nodes/range.rb +0 -63
  284. data/lib/chewy/query/nodes/raw.rb +0 -15
  285. data/lib/chewy/query/nodes/regexp.rb +0 -31
  286. data/lib/chewy/query/nodes/script.rb +0 -20
  287. data/lib/chewy/query/pagination/will_paginate.rb +0 -27
  288. data/lib/chewy/query/pagination.rb +0 -16
  289. data/lib/chewy/query/scoping.rb +0 -20
  290. data/lib/chewy/query.rb +0 -1026
  291. data/lib/chewy/strategy/resque.rb +0 -26
  292. data/lib/chewy/type/actions.rb +0 -19
  293. data/lib/chewy/type/adapter/active_record.rb +0 -72
  294. data/lib/chewy/type/adapter/mongoid.rb +0 -58
  295. data/lib/chewy/type/adapter/object.rb +0 -89
  296. data/lib/chewy/type/adapter/orm.rb +0 -156
  297. data/lib/chewy/type/adapter/sequel.rb +0 -75
  298. data/lib/chewy/type/crutch.rb +0 -31
  299. data/lib/chewy/type/import.rb +0 -224
  300. data/lib/chewy/type/observe.rb +0 -76
  301. data/lib/chewy/type/wrapper.rb +0 -53
  302. data/lib/chewy/type.rb +0 -89
  303. data/lib/sequel/plugins/chewy_observe.rb +0 -78
  304. data/spec/chewy/query/criteria_spec.rb +0 -433
  305. data/spec/chewy/query/filters_spec.rb +0 -173
  306. data/spec/chewy/query/loading_spec.rb +0 -86
  307. data/spec/chewy/query/nodes/and_spec.rb +0 -16
  308. data/spec/chewy/query/nodes/bool_spec.rb +0 -22
  309. data/spec/chewy/query/nodes/equal_spec.rb +0 -32
  310. data/spec/chewy/query/nodes/exists_spec.rb +0 -18
  311. data/spec/chewy/query/nodes/has_child_spec.rb +0 -40
  312. data/spec/chewy/query/nodes/has_parent_spec.rb +0 -40
  313. data/spec/chewy/query/nodes/match_all_spec.rb +0 -11
  314. data/spec/chewy/query/nodes/missing_spec.rb +0 -15
  315. data/spec/chewy/query/nodes/not_spec.rb +0 -16
  316. data/spec/chewy/query/nodes/or_spec.rb +0 -16
  317. data/spec/chewy/query/nodes/prefix_spec.rb +0 -16
  318. data/spec/chewy/query/nodes/query_spec.rb +0 -12
  319. data/spec/chewy/query/nodes/range_spec.rb +0 -32
  320. data/spec/chewy/query/nodes/raw_spec.rb +0 -11
  321. data/spec/chewy/query/nodes/regexp_spec.rb +0 -31
  322. data/spec/chewy/query/nodes/script_spec.rb +0 -15
  323. data/spec/chewy/query/pagination/kaminari_spec.rb +0 -57
  324. data/spec/chewy/query/pagination/will_paginage_spec.rb +0 -60
  325. data/spec/chewy/query/pagination_spec.rb +0 -36
  326. data/spec/chewy/query_spec.rb +0 -632
  327. data/spec/chewy/strategy/resque_spec.rb +0 -40
  328. data/spec/chewy/type/actions_spec.rb +0 -31
  329. data/spec/chewy/type/adapter/active_record_spec.rb +0 -317
  330. data/spec/chewy/type/adapter/mongoid_spec.rb +0 -253
  331. data/spec/chewy/type/adapter/object_spec.rb +0 -139
  332. data/spec/chewy/type/adapter/sequel_spec.rb +0 -320
  333. data/spec/chewy/type/import_spec.rb +0 -433
  334. data/spec/chewy/type/mapping_spec.rb +0 -106
  335. data/spec/chewy/type/observe_spec.rb +0 -127
  336. data/spec/chewy/type/witchcraft_spec.rb +0 -154
  337. data/spec/chewy/type/wrapper_spec.rb +0 -58
  338. data/spec/chewy/type_spec.rb +0 -33
  339. data/spec/support/mongoid.rb +0 -81
  340. data/spec/support/sequel.rb +0 -75
@@ -0,0 +1,1071 @@
1
+ module Chewy
2
+ module Search
3
+ # The main request DSL class. Supports multiple index requests.
4
+ # Supports ES5 search API and query DSL.
5
+ #
6
+ # @note The class tries to be as immutable as possible,
7
+ # so most of the methods return a new instance of the class.
8
+ # @see Chewy::Search
9
+ # @example
10
+ # scope = Chewy::Search::Request.new(PlacesIndex)
11
+ # # => <Chewy::Search::Request {:index=>["places"], :body=>{}}>
12
+ # scope.limit(20)
13
+ # # => <Chewy::Search::Request {:index=>["places"], :body=>{:size=>20}}>
14
+ # scope.order(:name).offset(10)
15
+ # # => <Chewy::Search::Request {:index=>["places"], :body=>{:sort=>["name"], :from=>10}}>
16
+ class Request
17
+ include Enumerable
18
+ include Scoping
19
+ include Scrolling
20
+ UNDEFINED = Class.new.freeze
21
+ EVERFIELDS = %w[_index _type _id _parent _routing].freeze
22
+ DELEGATED_METHODS = %i[
23
+ query filter post_filter order reorder docvalue_fields
24
+ track_scores track_total_hits request_cache explain version profile
25
+ search_type preference limit offset terminate_after
26
+ timeout min_score source stored_fields search_after
27
+ load script_fields suggest aggs aggregations collapse none
28
+ indices_boost rescore highlight total total_count
29
+ total_entries indices types delete_all count exists?
30
+ exist? find pluck scroll_batches scroll_hits
31
+ scroll_results scroll_wrappers ignore_unavailable
32
+ ].to_set.freeze
33
+ DEFAULT_BATCH_SIZE = 1000
34
+ DEFAULT_PLUCK_BATCH_SIZE = 10_000
35
+ DEFAULT_SCROLL = '1m'.freeze
36
+ # An array of storage names that are modifying returned fields in hits
37
+ FIELD_STORAGES = %i[
38
+ source docvalue_fields script_fields stored_fields
39
+ ].freeze
40
+ # An array of storage names that are not related to hits at all.
41
+ EXTRA_STORAGES = %i[aggs suggest].freeze
42
+ # An array of storage names that are changing the returned hist collection in any way.
43
+ WHERE_STORAGES = %i[
44
+ query filter post_filter none min_score rescore indices_boost collapse
45
+ ].freeze
46
+
47
+ delegate :hits, :wrappers, :objects, :records, :documents,
48
+ :object_hash, :record_hash, :document_hash,
49
+ :total, :max_score, :took, :timed_out?, to: :response
50
+ delegate :each, :size, :to_a, :[], to: :wrappers
51
+ alias_method :to_ary, :to_a
52
+ alias_method :total_count, :total
53
+ alias_method :total_entries, :total
54
+
55
+ # The class is initialized with the list of chewy indexes,
56
+ # which are later used to compose requests.
57
+ # Any symbol/string passed is treated as an index identifier.
58
+ #
59
+ # @example
60
+ # Chewy::Search::Request.new(:places)
61
+ # # => <Chewy::Search::Request {:index=>["places"], :body=>{}}>
62
+ # Chewy::Search::Request.new(PlacesIndex)
63
+ # # => <Chewy::Search::Request {:index=>["places"], :body=>{}}>
64
+ # Chewy::Search::Request.new(UsersIndex, PlacesIndex)
65
+ # # => <Chewy::Search::Request {:index=>["users", "places"], :body=>{}}>
66
+ # @param indexes [Array<Chewy::Index, String, Symbol>] indexes
67
+ def initialize(*indexes)
68
+ parameters.modify!(:indices) do
69
+ replace!(indices: indexes)
70
+ end
71
+ end
72
+
73
+ # Underlying parameter storage collection.
74
+ #
75
+ # @return [Chewy::Search::Parameters]
76
+ def parameters
77
+ @parameters ||= Parameters.new
78
+ end
79
+
80
+ # Compare two scopes or scope with a collection of wrappers.
81
+ # If other is a collection it performs the request to fetch
82
+ # data from ES.
83
+ #
84
+ # @example
85
+ # PlacesIndex.limit(10) == PlacesIndex.limit(10) # => true
86
+ # PlacesIndex.limit(10) == PlacesIndex.limit(10).to_a # => true
87
+ # PlacesIndex.limit(10) == PlacesIndex.limit(10).objects # => true
88
+ #
89
+ # PlacesIndex.limit(10) == UsersIndex.limit(10) # => false
90
+ # PlacesIndex.limit(10) == UsersIndex.limit(10).to_a # => false
91
+ #
92
+ # PlacesIndex.limit(10) == Object.new # => false
93
+ # @param other [Object] any object
94
+ # @return [true, false] the result of comparison
95
+ def ==(other)
96
+ super || other.is_a?(Chewy::Search::Request) ? compare_internals(other) : to_a == other
97
+ end
98
+
99
+ # Access to ES response wrappers providing useful methods such as
100
+ # {Chewy::Search::Response#total} or {Chewy::Search::Response#max_score}.
101
+ #
102
+ # @see Chewy::Search::Response
103
+ # @return [Chewy::Search::Response] a response object instance
104
+ def response
105
+ @response ||= build_response(perform)
106
+ end
107
+
108
+ # Wraps and sets the raw Elasticsearch response to provide access
109
+ # to convenience methods.
110
+ #
111
+ # @see Chewy::Search::Response
112
+ # @param from_elasticsearch [Hash] An Elasticsearch response
113
+ def response=(from_elasticsearch)
114
+ @response = build_response(from_elasticsearch)
115
+ end
116
+
117
+ # ES request body
118
+ #
119
+ # @return [Hash] request body
120
+ def render
121
+ @render ||= parameters.render
122
+ end
123
+
124
+ # Includes the class name and the result of rendering.
125
+ #
126
+ # @return [String]
127
+ def inspect
128
+ "<#{self.class} #{render}>"
129
+ end
130
+
131
+ # @!group Chainable request modifications
132
+
133
+ # @!method query(query_hash=nil, &block)
134
+ # Adds `query` parameter to the search request body.
135
+ #
136
+ # @see https://www.elastic.co/guide/en/elasticsearch/reference/current/search-request-query.html
137
+ # @see Chewy::Search::Parameters::Query
138
+ # @return [Chewy::Search::Request, Chewy::Search::QueryProxy]
139
+ #
140
+ # @overload query(query_hash)
141
+ # If pure hash is passed it goes straight to the `query` parameter storage.
142
+ # Acts exactly the same way as {Chewy::Search::QueryProxy#must}.
143
+ #
144
+ # @see https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl.html
145
+ # @example
146
+ # PlacesIndex.query(match: {name: 'Moscow'})
147
+ # # => <PlacesIndex::Query {..., :body=>{:query=>{:match=>{:name=>"Moscow"}}}}>
148
+ # @param query_hash [Hash] pure query hash
149
+ # @return [Chewy::Search::Request]
150
+ #
151
+ # @overload query
152
+ # If block is passed instead of a pure hash, `elasticsearch-dsl"
153
+ # gem will be used to process it.
154
+ # Acts exactly the same way as {Chewy::Search::QueryProxy#must} with a block.
155
+ #
156
+ # @see https://github.com/elastic/elasticsearch-ruby/tree/master/elasticsearch-dsl
157
+ # @example
158
+ # PlacesIndex.query { match name: 'Moscow' }
159
+ # # => <PlacesIndex::Query {..., :body=>{:query=>{:match=>{:name=>"Moscow"}}}}>
160
+ # @yield the block is processed by `elasticsearch-dsl` gem
161
+ # @return [Chewy::Search::Request]
162
+ #
163
+ # @overload query
164
+ # If nothing is passed it returns a proxy for additional
165
+ # parameter manipulations.
166
+ #
167
+ # @see Chewy::Search::QueryProxy
168
+ # @example
169
+ # PlacesIndex.query.should(match: {name: 'Moscow'}).query.not(match: {name: 'London'})
170
+ # # => <PlacesIndex::Query {..., :body=>{:query=>{:bool=>{
171
+ # # :should=>{:match=>{:name=>"Moscow"}},
172
+ # # :must_not=>{:match=>{:name=>"London"}}}}}}>
173
+ # @return [Chewy::Search::QueryProxy]
174
+ #
175
+ # @!method filter(query_hash=nil, &block)
176
+ # Adds `filter` context of the `query` parameter at the
177
+ # search request body.
178
+ #
179
+ # @see https://www.elastic.co/guide/en/elasticsearch/reference/current/query-filter-context.html
180
+ # @see Chewy::Search::Parameters::Filter
181
+ # @return [Chewy::Search::Request, Chewy::Search::QueryProxy]
182
+ #
183
+ # @overload filter(query_hash)
184
+ # If pure hash is passed it goes straight to the `filter` context of the `query` parameter storage.
185
+ # Acts exactly the same way as {Chewy::Search::QueryProxy#must}.
186
+ #
187
+ # @see https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl.html
188
+ # @example
189
+ # PlacesIndex.filter(match: {name: 'Moscow'})
190
+ # # => <PlacesIndex::Query {..., :body=>{:query=>{:bool=>{
191
+ # # :filter=>{:match=>{:name=>"Moscow"}}}}}}>
192
+ # @param query_hash [Hash] pure query hash
193
+ # @return [Chewy::Search::Request]
194
+ #
195
+ # @overload filter
196
+ # If block is passed instead of a pure hash, `elasticsearch-dsl"
197
+ # gem will be used to process it.
198
+ # Acts exactly the same way as {Chewy::Search::QueryProxy#must} with a block.
199
+ #
200
+ # @see https://github.com/elastic/elasticsearch-ruby/tree/master/elasticsearch-dsl
201
+ # @example
202
+ # PlacesIndex.filter { match name: 'Moscow' }
203
+ # # => <PlacesIndex::Query {..., :body=>{:query=>{:bool=>{
204
+ # # :filter=>{:match=>{:name=>"Moscow"}}}}}}>
205
+ # @yield the block is processed by `elasticsearch-dsl` gem
206
+ # @return [Chewy::Search::Request]
207
+ #
208
+ # @overload filter
209
+ # If nothing is passed it returns a proxy for additional
210
+ # parameter manipulations.
211
+ #
212
+ # @see Chewy::Search::QueryProxy
213
+ # @example
214
+ # PlacesIndex.filter.should(match: {name: 'Moscow'}).filter.not(match: {name: 'London'})
215
+ # # => <PlacesIndex::Query {..., :body=>{:query=>{:bool=>{
216
+ # # :filter=>{:bool=>{:should=>{:match=>{:name=>"Moscow"}},
217
+ # # :must_not=>{:match=>{:name=>"London"}}}}}}}}>
218
+ # @return [Chewy::Search::QueryProxy]
219
+ #
220
+ # @!method post_filter(query_hash=nil, &block)
221
+ # Adds `post_filter` parameter to the search request body.
222
+ #
223
+ # @see https://www.elastic.co/guide/en/elasticsearch/reference/current/filter-search-results.html#post-filter
224
+ # @see Chewy::Search::Parameters::PostFilter
225
+ # @return [Chewy::Search::Request, Chewy::Search::QueryProxy]
226
+ #
227
+ # @overload post_filter(query_hash)
228
+ # If pure hash is passed it goes straight to the `post_filter` parameter storage.
229
+ # Acts exactly the same way as {Chewy::Search::QueryProxy#must}.
230
+ #
231
+ # @see https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl.html
232
+ # @example
233
+ # PlacesIndex.post_filter(match: {name: 'Moscow'})
234
+ # # => <PlacesIndex::Query {..., :body=>{:post_filter=>{:match=>{:name=>"Moscow"}}}}>
235
+ # @param query_hash [Hash] pure query hash
236
+ # @return [Chewy::Search::Request]
237
+ #
238
+ # @overload post_filter
239
+ # If block is passed instead of a pure hash, `elasticsearch-dsl"
240
+ # gem will be used to process it.
241
+ # Acts exactly the same way as {Chewy::Search::QueryProxy#must} with a block.
242
+ #
243
+ # @see https://github.com/elastic/elasticsearch-ruby/tree/master/elasticsearch-dsl
244
+ # @example
245
+ # PlacesIndex.post_filter { match name: 'Moscow' }
246
+ # # => <PlacesIndex::Query {..., :body=>{:post_filter=>{:match=>{:name=>"Moscow"}}}}>
247
+ # @yield the block is processed by `elasticsearch-dsl` gem
248
+ # @return [Chewy::Search::Request]
249
+ #
250
+ # @overload post_filter
251
+ # If nothing is passed it returns a proxy for additional
252
+ # parameter manipulations.
253
+ #
254
+ # @see Chewy::Search::QueryProxy
255
+ # @example
256
+ # PlacesIndex.post_filter.should(match: {name: 'Moscow'}).post_filter.not(match: {name: 'London'})
257
+ # # => <PlacesIndex::Query {..., :body=>{:post_filter=>{:bool=>{
258
+ # # :should=>{:match=>{:name=>"Moscow"}},
259
+ # # :must_not=>{:match=>{:name=>"London"}}}}}}>
260
+ # @return [Chewy::Search::QueryProxy]
261
+ %i[query filter post_filter].each do |name|
262
+ define_method name do |query_hash = UNDEFINED, &block|
263
+ if block || query_hash != UNDEFINED
264
+ modify(name) { must(block || query_hash) }
265
+ else
266
+ Chewy::Search::QueryProxy.new(name, self)
267
+ end
268
+ end
269
+ end
270
+
271
+ # @!method order(*values)
272
+ # Modifies `sort` request parameter. Updates the storage on every call.
273
+ #
274
+ # @example
275
+ # PlacesIndex.order(:name, population: {order: :asc}).order(:coordinates)
276
+ # # => <PlacesIndex::Query {..., :body=>{:sort=>["name", {"population"=>{:order=>:asc}}, "coordinates"]}}>
277
+ # @see Chewy::Search::Parameters::Order
278
+ # @see https://www.elastic.co/guide/en/elasticsearch/reference/current/sort-search-results.html
279
+ # @param values [Array<Hash, String, Symbol>] sort fields and options
280
+ # @return [Chewy::Search::Request]
281
+ #
282
+ # @!method docvalue_fields(*values)
283
+ # Modifies `docvalue_fields` request parameter. Updates the storage on every call.
284
+ #
285
+ # @example
286
+ # PlacesIndex.docvalue_fields(:name).docvalue_fields(:population, :coordinates)
287
+ # # => <PlacesIndex::Query {..., :body=>{:docvalue_fields=>["name", "population", "coordinates"]}}>
288
+ # @see Chewy::Search::Parameters::DocvalueFields
289
+ # @see https://www.elastic.co/guide/en/elasticsearch/reference/current/search-fields.html#docvalue-fields
290
+ # @param values [Array<String, Symbol>] field names
291
+ # @return [Chewy::Search::Request]
292
+ %i[order docvalue_fields].each do |name|
293
+ define_method name do |value, *values|
294
+ modify(name) { update!([value, *values]) }
295
+ end
296
+ end
297
+
298
+ # Modifies `index` request parameter. Updates the storage on every call.
299
+ # Added passed indexes to the parameter list.
300
+ #
301
+ # @example
302
+ # UsersIndex.indices(CitiesIndex).indices(:another)
303
+ # # => <UsersIndex::Query {:index=>["another", "cities", "users"]}>
304
+ # @see Chewy::Search::Parameters::Indices
305
+ # @see https://www.elastic.co/guide/en/elasticsearch/reference/current/search-search.html
306
+ # @param values [Array<Chewy::Index, String, Symbol>] index names
307
+ # @return [Chewy::Search::Request]
308
+ def indices(value, *values)
309
+ modify(:indices) { update!(indices: [value, *values]) }
310
+ end
311
+
312
+ # @overload reorder(*values)
313
+ # Replaces the value of the `sort` parameter with the provided value.
314
+ #
315
+ # @example
316
+ # PlacesIndex.order(:name, population: {order: :asc}).reorder(:coordinates)
317
+ # # => <PlacesIndex::Query {..., :body=>{:sort=>["coordinates"]}}>
318
+ # @see Chewy::Search::Parameters::Order
319
+ # @see https://www.elastic.co/guide/en/elasticsearch/reference/current/sort-search-results.html
320
+ # @param values [Array<Hash, String, Symbol>] sort fields and options
321
+ # @return [Chewy::Search::Request]
322
+ def reorder(value, *values)
323
+ modify(:order) { replace!([value, *values]) }
324
+ end
325
+
326
+ # @!method track_scores(value = true)
327
+ # Replaces the value of the `track_scores` parameter with the provided value.
328
+ #
329
+ # @example
330
+ # PlacesIndex.track_scores
331
+ # # => <PlacesIndex::Query {..., :body=>{:track_scores=>true}}>
332
+ # PlacesIndex.track_scores.track_scores(false)
333
+ # # => <PlacesIndex::Query {:index=>["places"]}>
334
+ # @see Chewy::Search::Parameters::TrackScores
335
+ # @see https://www.elastic.co/guide/en/elasticsearch/reference/current/sort-search-results.html#_track_scores
336
+ # @param value [true, false]
337
+ # @return [Chewy::Search::Request]
338
+ #
339
+ # @!method track_total_hits(value = true)
340
+ # Replaces the value of the `track_total_hits` parameter with the provided value.
341
+ #
342
+ # @example
343
+ # PlacesIndex.track_total_hits
344
+ # # => <PlacesIndex::Query {..., :body=>{:track_total_hits=>true}}>
345
+ # PlacesIndex.track_total_hits.track_total_hits(false)
346
+ # # => <PlacesIndex::Query {:index=>["places"]}>
347
+ # @see Chewy::Search::Parameters::TrackTotalHits
348
+ # @see https://www.elastic.co/guide/en/elasticsearch/reference/current/search-your-data.html#track-total-hits
349
+ # @param value [true, false]
350
+ # @return [Chewy::Search::Request]
351
+ #
352
+ # @!method explain(value = true)
353
+ # Replaces the value of the `explain` parameter with the provided value.
354
+ #
355
+ # @example
356
+ # PlacesIndex.explain
357
+ # # => <PlacesIndex::Query {..., :body=>{:explain=>true}}>
358
+ # PlacesIndex.explain.explain(false)
359
+ # # => <PlacesIndex::Query {:index=>["places"]}>
360
+ # @see Chewy::Search::Parameters::Explain
361
+ # @see https://www.elastic.co/guide/en/elasticsearch/reference/current/search-explain.html
362
+ # @param value [true, false]
363
+ # @return [Chewy::Search::Request]
364
+ #
365
+ # @!method version(value = true)
366
+ # Replaces the value of the `version` parameter with the provided value.
367
+ #
368
+ # @example
369
+ # PlacesIndex.version
370
+ # # => <PlacesIndex::Query {..., :body=>{:version=>true}}>
371
+ # PlacesIndex.version.version(false)
372
+ # # => <PlacesIndex::Query {:index=>["places"]}>
373
+ # @see Chewy::Search::Parameters::Version
374
+ # @see https://www.elastic.co/guide/en/elasticsearch/reference/current/search-search.html
375
+ # @param value [true, false]
376
+ # @return [Chewy::Search::Request]
377
+ #
378
+ # @!method profile(value = true)
379
+ # Replaces the value of the `profile` parameter with the provided value.
380
+ #
381
+ # @example
382
+ # PlacesIndex.profile
383
+ # # => <PlacesIndex::Query {..., :body=>{:profile=>true}}>
384
+ # PlacesIndex.profile.profile(false)
385
+ # # => <PlacesIndex::Query {:index=>["places"]}>
386
+ # @see Chewy::Search::Parameters::Profile
387
+ # @see https://www.elastic.co/guide/en/elasticsearch/reference/current/search-profile.html
388
+ # @param value [true, false]
389
+ # @return [Chewy::Search::Request]
390
+ #
391
+ # @!method none(value = true)
392
+ # Enables `NullObject` pattern for the request, doesn't perform the
393
+ # request, `#hits` are empty, `#total` is 0, etc.
394
+ #
395
+ # @example
396
+ # PlacesIndex.none.to_a
397
+ # # => []
398
+ # PlacesIndex.none.total
399
+ # # => 0
400
+ # @see Chewy::Search::Parameters::None
401
+ # @see https://en.wikipedia.org/wiki/Null_Object_pattern
402
+ # @param value [true, false]
403
+ # @return [Chewy::Search::Request]
404
+ %i[track_scores track_total_hits explain version profile none].each do |name|
405
+ define_method name do |value = true|
406
+ modify(name) { replace!(value) }
407
+ end
408
+ end
409
+
410
+ # @!method request_cache(value)
411
+ # Replaces the value of the `request_cache` parameter with the provided value.
412
+ # Unlike other boolean fields, the value have to be specified explicitly
413
+ # since it overrides the index-level setting.
414
+ #
415
+ # @example
416
+ # PlacesIndex.request_cache(true)
417
+ # # => <PlacesIndex::Query {..., :body=>{:request_cache=>true}}>
418
+ # PlacesIndex.request_cache(false)
419
+ # # => <PlacesIndex::Query {..., :body=>{:request_cache=>false}}>
420
+ # @see Chewy::Search::Parameters::RequestCache
421
+ # @see https://www.elastic.co/guide/en/elasticsearch/reference/current/shard-request-cache.html#_enabling_and_disabling_caching_per_request
422
+ # @param value [true, false, nil]
423
+ # @return [Chewy::Search::Request]
424
+ #
425
+ # @!method search_type(value)
426
+ # Replaces the value of the `search_type` request part.
427
+ #
428
+ # @example
429
+ # PlacesIndex.search_type(:dfs_query_then_fetch)
430
+ # # => <PlacesIndex::Query {..., :body=>{:search_type=>"dfs_query_then_fetch"}}>
431
+ # @see Chewy::Search::Parameters::SearchType
432
+ # @see https://www.elastic.co/guide/en/elasticsearch/reference/current/search-search.html#search-type
433
+ # @param value [String, Symbol]
434
+ # @return [Chewy::Search::Request]
435
+ #
436
+ # @!method preference(value)
437
+ # Replaces the value of the `preference` request part.
438
+ #
439
+ # @example
440
+ # PlacesIndex.preference(:_primary_first)
441
+ # # => <PlacesIndex::Query {..., :body=>{:preference=>"_primary_first"}}>
442
+ # @see Chewy::Search::Parameters::Preference
443
+ # @see https://www.elastic.co/guide/en/elasticsearch/reference/current/search-search.html#search-preference
444
+ # @param value [String, Symbol]
445
+ # @return [Chewy::Search::Request]
446
+ #
447
+ # @!method timeout(value)
448
+ # Replaces the value of the `timeout` request part.
449
+ #
450
+ # @example
451
+ # PlacesIndex.timeout('1m')
452
+ # <PlacesIndex::Query {..., :body=>{:timeout=>"1m"}}>
453
+ # @see Chewy::Search::Parameters::Timeout
454
+ # @see https://www.elastic.co/guide/en/elasticsearch/reference/current/common-options.html#time-units
455
+ # @param value [String, Symbol]
456
+ # @return [Chewy::Search::Request]
457
+ #
458
+ # @!method limit(value)
459
+ # Replaces the value of the `size` request part.
460
+ #
461
+ # @example
462
+ # PlacesIndex.limit(10)
463
+ # <PlacesIndex::Query {..., :body=>{:size=>10}}>
464
+ # @see Chewy::Search::Parameters::Limit
465
+ # @see https://www.elastic.co/guide/en/elasticsearch/reference/current/paginate-search-results.html
466
+ # @param value [String, Integer]
467
+ # @return [Chewy::Search::Request]
468
+ #
469
+ # @!method offset(value)
470
+ # Replaces the value of the `from` request part.
471
+ #
472
+ # @example
473
+ # PlacesIndex.offset(10)
474
+ # <PlacesIndex::Query {..., :body=>{:from=>10}}>
475
+ # @see Chewy::Search::Parameters::Offset
476
+ # @see https://www.elastic.co/guide/en/elasticsearch/reference/current/paginate-search-results.html
477
+ # @param value [String, Integer]
478
+ # @return [Chewy::Search::Request]
479
+ #
480
+ # @!method terminate_after(value)
481
+ # Replaces the value of the `terminate_after` request part.
482
+ #
483
+ # @example
484
+ # PlacesIndex.terminate_after(10)
485
+ # <PlacesIndex::Query {..., :body=>{:terminate_after=>10}}>
486
+ # @see Chewy::Search::Parameters::Offset
487
+ # @see https://www.elastic.co/guide/en/elasticsearch/reference/current/search-your-data.html#quickly-check-for-matching-docs
488
+ # @param value [String, Integer]
489
+ # @return [Chewy::Search::Request]
490
+ #
491
+ # @!method min_score(value)
492
+ # Replaces the value of the `min_score` request part.
493
+ #
494
+ # @example
495
+ # PlacesIndex.min_score(2)
496
+ # <PlacesIndex::Query {..., :body=>{:min_score=>2.0}}>
497
+ # @see Chewy::Search::Parameters::Offset
498
+ # @see https://www.elastic.co/guide/en/elasticsearch/reference/current/search-search.html#search-api-min-score
499
+ # @param value [String, Integer, Float]
500
+ # @return [Chewy::Search::Request]
501
+ #
502
+ # @!method ignore_unavailable(value)
503
+ # Replaces the value of the `ignore_unavailable` request part.
504
+ #
505
+ # @example
506
+ # PlacesIndex.ignore_unavailable(true)
507
+ # <PlacesIndex::Query {..., :ignore_unavailable => true, :body=>{ ... }}>
508
+ # @see Chewy::Search::Parameters::IgnoreUnavailable
509
+ # @see https://www.elastic.co/guide/en/elasticsearch/reference/current/multi-index.html#multi-index
510
+ # @param value [true, false, nil]
511
+ # @return [Chewy::Search::Request]
512
+ #
513
+ # @!method collapse(value)
514
+ # Replaces the value of the `collapse` request part.
515
+ #
516
+ # @example
517
+ # PlacesIndex.collapse(field: :name)
518
+ # # => <PlacesIndex::Query {..., :body=>{:collapse=>{"field"=>:name}}}>
519
+ # @see Chewy::Search::Parameters::Collapse
520
+ # @see https://www.elastic.co/guide/en/elasticsearch/reference/current/collapse-search-results.html
521
+ # @param value [Hash]
522
+ # @return [Chewy::Search::Request]
523
+ %i[request_cache search_type preference timeout limit offset terminate_after min_score ignore_unavailable collapse].each do |name|
524
+ define_method name do |value|
525
+ modify(name) { replace!(value) }
526
+ end
527
+ end
528
+
529
+ # @!method source(*values)
530
+ # Updates `_source` request part. Accepts either an array
531
+ # of field names/templates or a hash with `includes` and `excludes`
532
+ # keys. Source also can be disabled entirely or enabled again.
533
+ #
534
+ # @example
535
+ # PlacesIndex.source(:name).source(includes: [:popularity], excludes: :description)
536
+ # # => <PlacesIndex::Query {..., :body=>{:_source=>{:includes=>["name", "popularity"], :excludes=>["description"]}}}>
537
+ # PlacesIndex.source(false)
538
+ # # => <PlacesIndex::Query {..., :body=>{:_source=>false}}>
539
+ # @see Chewy::Search::Parameters::Source
540
+ # @see https://www.elastic.co/guide/en/elasticsearch/reference/current/search-fields.html#source-filtering
541
+ # @param values [true, false, {Symbol => Array<String, Symbol>, String, Symbol}, Array<String, Symbol>, String, Symbol]
542
+ # @return [Chewy::Search::Request]
543
+ #
544
+ # @!method stored_fields(*values)
545
+ # Updates `stored_fields` request part. Accepts an array of field
546
+ # names. Can be entirely disabled and enabled back.
547
+ #
548
+ # @example
549
+ # PlacesIndex.stored_fields(:name).stored_fields(:description)
550
+ # # => <PlacesIndex::Query {..., :body=>{:stored_fields=>["name", "description"]}}>
551
+ # PlacesIndex.stored_fields(false)
552
+ # # => <PlacesIndex::Query {..., :body=>{:stored_fields=>"_none_"}}>
553
+ # @see Chewy::Search::Parameters::StoredFields
554
+ # @see https://www.elastic.co/guide/en/elasticsearch/reference/current/search-fields.html#stored-fields
555
+ # @param values [true, false, String, Symbol, Array<String, Symbol>]
556
+ # @return [Chewy::Search::Request]
557
+ %i[source stored_fields].each do |name|
558
+ define_method name do |value, *values|
559
+ modify(name) { update!(values.empty? ? value : [value, *values]) }
560
+ end
561
+ end
562
+
563
+ # @overload search_after(*values)
564
+ # Replaces the storage value for `search_after` request part.
565
+ #
566
+ # @example
567
+ # PlacesIndex.search_after(42, 'Moscow').search_after('London')
568
+ # # => <PlacesIndex::Query {..., :body=>{:search_after=>["London"]}}>
569
+ # @see Chewy::Search::Parameters::SearchAfter
570
+ # @see https://www.elastic.co/guide/en/elasticsearch/reference/current/paginate-search-results.html#search-after
571
+ # @param value [Array, Object]
572
+ # @return [Chewy::Search::Request]
573
+ def search_after(value, *values)
574
+ modify(:search_after) { replace!(values.empty? ? value : [value, *values]) }
575
+ end
576
+
577
+ # Stores ORM/ODM objects loading options. Options
578
+ # might be define per-index or be global, depends on the adapter
579
+ # loading implementation. Also, there are 2 loading options to select
580
+ # or exclude indexes from loading: `only` and `except` respectively.
581
+ # Options are updated on further method calls.
582
+ #
583
+ # @example
584
+ # PlaceIndex.load(only: 'city').load(scope: -> { active })
585
+ # @see Chewy::Search::Loader
586
+ # @see Chewy::Search::Response#objects
587
+ # @see Chewy::Search::Scrolling#scroll_objects
588
+ # @param options [Hash] adapter-specific loading options
589
+ def load(options = nil)
590
+ modify(:load) { update!(options) }
591
+ end
592
+
593
+ # @!method script_fields(value)
594
+ # Add a `script_fields` part to the request. Further
595
+ # call values are merged to the storage hash.
596
+ #
597
+ # @example
598
+ # PlacesIndex
599
+ # .script_fields(field1: {script: {lang: 'painless', inline: 'some script here'}})
600
+ # .script_fields(field2: {script: {lang: 'painless', inline: 'some script here'}})
601
+ # # => <PlacesIndex::Query {..., :body=>{:script_fields=>{
602
+ # # "field1"=>{:script=>{:lang=>"painless", :inline=>"some script here"}},
603
+ # # "field2"=>{:script=>{:lang=>"painless", :inline=>"some script here"}}}}}>
604
+ # @see Chewy::Search::Parameters::ScriptFields
605
+ # @see https://www.elastic.co/guide/en/elasticsearch/reference/current/search-fields.html#script-fields
606
+ # @param value [Hash]
607
+ # @return [Chewy::Search::Request]
608
+ #
609
+ # @!method indices_boost(value)
610
+ # Add an `indices_boost` part to the request. Further
611
+ # call values are merged to the storage hash.
612
+ #
613
+ # @example
614
+ # PlacesIndex.indices_boost(index1: 1.2, index2: 1.3).indices_boost(index1: 1.5)
615
+ # # => <PlacesIndex::Query {..., :body=>{:indices_boost=>[{"index2"=>1.3}, {"index1"=>1.5}]}}>
616
+ # @see Chewy::Search::Parameters::IndicesBoost
617
+ # @see https://www.elastic.co/guide/en/elasticsearch/reference/current/search-multiple-indices.html#index-boost
618
+ # @param value [{String, Symbol => String, Integer, Float}]
619
+ # @return [Chewy::Search::Request]
620
+ #
621
+ # @!method rescore(value)
622
+ # Add a `rescore` part to the request. Further
623
+ # call values are added to the storage array.
624
+ #
625
+ # @example
626
+ # PlacesIndex.rescore(window_size: 100, query: {}).rescore(window_size: 200, query: {})
627
+ # # => <PlacesIndex::Query {..., :body=>{:rescore=>[{:window_size=>100, :query=>{}}, {:window_size=>200, :query=>{}}]}}>
628
+ # @see Chewy::Search::Parameters::Rescore
629
+ # @see https://www.elastic.co/guide/en/elasticsearch/reference/current/filter-search-results.html#rescore
630
+ # @param value [Hash, Array<Hash>]
631
+ # @return [Chewy::Search::Request]
632
+ #
633
+ # @!method highlight(value)
634
+ # Add a `highlight` configuration to the request. Further
635
+ # call values are merged to the storage hash.
636
+ #
637
+ # @example
638
+ # PlacesIndex
639
+ # .highlight(fields: {description: {type: 'plain'}})
640
+ # .highlight(pre_tags: ['<em>'], post_tags: ['</em>'])
641
+ # # => <PlacesIndex::Query {..., :body=>{:highlight=>{
642
+ # # "fields"=>{:description=>{:type=>"plain"}},
643
+ # # "pre_tags"=>["<em>"], "post_tags"=>["</em>"]}}}>
644
+ # @see Chewy::Search::Parameters::Highlight
645
+ # @see https://www.elastic.co/guide/en/elasticsearch/reference/current/highlighting.html
646
+ # @param value [Hash]
647
+ # @return [Chewy::Search::Request]
648
+ %i[script_fields indices_boost rescore highlight].each do |name|
649
+ define_method name do |value|
650
+ modify(name) { update!(value) }
651
+ end
652
+ end
653
+
654
+ # A dual-purpose method.
655
+ #
656
+ # @overload suggest(value)
657
+ # With the value provided it adds a new suggester
658
+ # to the suggestion hash.
659
+ #
660
+ # @example
661
+ # PlacesIndex
662
+ # .suggest(names: {text: 'tring out Elasticsearch'})
663
+ # .suggest(descriptions: {text: 'some other text'})
664
+ # # => <PlacesIndex::Query {..., :body=>{:suggest=>{
665
+ # # "names"=>{:text=>"tring out Elasticsearch"},
666
+ # # "descriptions"=>{:text=>"some other text"}}}}>
667
+ # @see Chewy::Search::Parameters::Suggest
668
+ # @see https://www.elastic.co/guide/en/elasticsearch/reference/current/search-suggesters.html
669
+ # @param value [Hash]
670
+ # @return [Chewy::Search::Request]
671
+ #
672
+ # @overload suggest
673
+ # Without value provided, it performs the request and
674
+ # returns {Chewy::Search::Response#suggest} contents.
675
+ #
676
+ # @example
677
+ # PlacesIndex.suggest(names: {text: 'tring out Elasticsearch'}).suggest
678
+ # @see Chewy::Search::Response#suggest
679
+ # @return [Hash]
680
+ def suggest(value = UNDEFINED)
681
+ if value == UNDEFINED
682
+ response.suggest
683
+ else
684
+ modify(:suggest) { update!(value) }
685
+ end
686
+ end
687
+
688
+ # A dual-purpose method.
689
+ #
690
+ # @overload aggs(value)
691
+ # With the value provided it adds a new aggregation
692
+ # to the aggregation hash.
693
+ #
694
+ # @example
695
+ # PlacesIndex
696
+ # .aggs(avg_population: {avg: {field: :population}})
697
+ # .aggs(avg_age: {avg: {field: :age}})
698
+ # # => <PlacesIndex::Query {..., :body=>{:aggs=>{
699
+ # # "avg_population"=>{:avg=>{:field=>:population}},
700
+ # # "avg_age"=>{:avg=>{:field=>:age}}}}}>
701
+ # @see Chewy::Search::Parameters::Aggs
702
+ # @see https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations.html
703
+ # @param value [Hash]
704
+ # @return [Chewy::Search::Request]
705
+ #
706
+ # @overload aggs
707
+ # Without value provided, it performs the request and
708
+ # returns {Chewy::Search::Response#aggs} contents.
709
+ #
710
+ # @example
711
+ # PlacesIndex.aggs(avg_population: {avg: {field: :population}}).aggs
712
+ # @see Chewy::Search::Response#aggs
713
+ # @return [Hash]
714
+ def aggs(value = UNDEFINED)
715
+ if value == UNDEFINED
716
+ response.aggs
717
+ else
718
+ modify(:aggs) { update!(value) }
719
+ end
720
+ end
721
+ alias_method :aggregations, :aggs
722
+
723
+ # @!group Scopes manipulation
724
+
725
+ # Merges 2 scopes by merging their parameters.
726
+ #
727
+ # @example
728
+ # scope1 = PlacesIndex.limit(10).offset(10)
729
+ # scope2 = PlacesIndex.limit(20)
730
+ # scope1.merge(scope2)
731
+ # # => <PlacesIndex::Query {..., :body=>{:size=>20, :from=>10}}>
732
+ # scope2.merge(scope1)
733
+ # # => <PlacesIndex::Query {..., :body=>{:size=>10, :from=>10}}>
734
+ # @see Chewy::Search::Parameters#merge
735
+ # @param other [Chewy::Search::Request] scope to merge
736
+ # @return [Chewy::Search::Request] new scope
737
+ def merge(other)
738
+ chain { parameters.merge!(other.parameters) }
739
+ end
740
+
741
+ # @!method and(other)
742
+ # Takes `query`, `filter`, `post_filter` from the passed scope
743
+ # and performs {Chewy::Search::QueryProxy#and} operation for each
744
+ # of them. Unlike merge, every other parameter is kept unmerged
745
+ # (values from the first scope are used in the result scope).
746
+ #
747
+ # @see Chewy::Search::QueryProxy#and
748
+ # @example
749
+ # scope1 = PlacesIndex.filter(term: {name: 'Moscow'}).query(match: {name: 'London'})
750
+ # scope2 = PlacesIndex.filter.not(term: {name: 'Berlin'}).query(match: {name: 'Washington'})
751
+ # scope1.and(scope2)
752
+ # # => <PlacesIndex::Query {..., :body=>{:query=>{:bool=>{
753
+ # # :must=>[{:match=>{:name=>"London"}}, {:match=>{:name=>"Washington"}}],
754
+ # # :filter=>{
755
+ # # :bool=>{:must=>[{:term=>{:name=>"Moscow"}}, {:bool=>{:must_not=>{:term=>{:name=>"Berlin"}}}}]}
756
+ # # }
757
+ # # }}}}>
758
+ # @param other [Chewy::Search::Request] scope to merge
759
+ # @return [Chewy::Search::Request] new scope
760
+ #
761
+ # @!method or(other)
762
+ # Takes `query`, `filter`, `post_filter` from the passed scope
763
+ # and performs {Chewy::Search::QueryProxy#or} operation for each
764
+ # of them. Unlike merge, every other parameter is kept unmerged
765
+ # (values from the first scope are used in the result scope).
766
+ #
767
+ # @see Chewy::Search::QueryProxy#or
768
+ # @example
769
+ # scope1 = PlacesIndex.filter(term: {name: 'Moscow'}).query(match: {name: 'London'})
770
+ # scope2 = PlacesIndex.filter.not(term: {name: 'Berlin'}).query(match: {name: 'Washington'})
771
+ # scope1.or(scope2)
772
+ # # => <PlacesIndex::Query {..., :body=>{:query=>{:bool=>{
773
+ # # :should=>[{:match=>{:name=>"London"}}, {:match=>{:name=>"Washington"}}],
774
+ # # :filter=>{
775
+ # # :bool=>{:should=>[{:term=>{:name=>"Moscow"}}, {:bool=>{:must_not=>{:term=>{:name=>"Berlin"}}}}]}
776
+ # # }
777
+ # # }}}}>
778
+ # @param other [Chewy::Search::Request] scope to merge
779
+ # @return [Chewy::Search::Request] new scope
780
+ #
781
+ # @!method not(other)
782
+ # Takes `query`, `filter`, `post_filter` from the passed scope
783
+ # and performs {Chewy::Search::QueryProxy#not} operation for each
784
+ # of them. Unlike merge, every other parameter is kept unmerged
785
+ # (values from the first scope are used in the result scope).
786
+ #
787
+ # @see Chewy::Search::QueryProxy#not
788
+ # @example
789
+ # scope1 = PlacesIndex.filter(term: {name: 'Moscow'}).query(match: {name: 'London'})
790
+ # scope2 = PlacesIndex.filter.not(term: {name: 'Berlin'}).query(match: {name: 'Washington'})
791
+ # scope1.not(scope2)
792
+ # # => <PlacesIndex::Query {..., :body=>{:query=>{:bool=>{
793
+ # # :must=>{:match=>{:name=>"London"}}, :must_not=>{:match=>{:name=>"Washington"}},
794
+ # # :filter=>{
795
+ # # :bool=>{
796
+ # # :must=>{:term=>{:name=>"Moscow"}},
797
+ # # :must_not=>{:bool=>{:must_not=>{:term=>{:name=>"Berlin"}}}}
798
+ # # }
799
+ # # }
800
+ # # }}}}>
801
+ # @param other [Chewy::Search::Request] scope to merge
802
+ # @return [Chewy::Search::Request] new scope
803
+ %i[and or not].each do |name|
804
+ define_method name do |other|
805
+ %i[query filter post_filter].inject(self) do |scope, parameter_name|
806
+ scope.send(parameter_name).send(name, other.parameters[parameter_name].value)
807
+ end
808
+ end
809
+ end
810
+
811
+ # Returns a new scope containing only specified storages.
812
+ #
813
+ # @example
814
+ # PlacesIndex.limit(10).offset(10).order(:name).only(:offset, :order)
815
+ # # => <PlacesIndex::Query {..., :body=>{:from=>10, :sort=>["name"]}}>
816
+ # @param values [Array<String, Symbol>]
817
+ # @return [Chewy::Search::Request] new scope
818
+ def only(*values)
819
+ chain { parameters.only!(values.flatten(1) + [:indices]) }
820
+ end
821
+
822
+ # Returns a new scope containing all the storages except specified.
823
+ #
824
+ # @example
825
+ # PlacesIndex.limit(10).offset(10).order(:name).except(:offset, :order)
826
+ # # => <PlacesIndex::Query {..., :body=>{:size=>10}}>
827
+ # @param values [Array<String, Symbol>]
828
+ # @return [Chewy::Search::Request] new scope
829
+ def except(*values)
830
+ chain { parameters.except!(values.flatten(1)) }
831
+ end
832
+
833
+ # @!group Additional actions
834
+
835
+ # Returns total count of hits for the request. If the request
836
+ # was already performed - it uses the `total` value, otherwise
837
+ # it executes a fast count request.
838
+ #
839
+ # @return [Integer] total hits count
840
+ def count
841
+ if performed?
842
+ total
843
+ else
844
+ Chewy.client.count(only(WHERE_STORAGES).render)['count']
845
+ end
846
+ rescue Elasticsearch::Transport::Transport::Errors::NotFound
847
+ 0
848
+ end
849
+
850
+ # Checks if any of the document exist for this request. If
851
+ # the request was already performed - it uses the `total`,
852
+ # otherwise it executes a fast request to check existence.
853
+ #
854
+ # @return [true, false] wether hits exist or not
855
+ def exists?
856
+ if performed?
857
+ total != 0
858
+ else
859
+ limit(0).terminate_after(1).total != 0
860
+ end
861
+ end
862
+ alias_method :exist?, :exists?
863
+
864
+ # Return first wrapper object or a collection of first N wrapper
865
+ # objects if the argument is provided.
866
+ # Tries to use cached results of possible. If the amount of
867
+ # cached results is insufficient - performs a new request.
868
+ #
869
+ # @overload first
870
+ # If nothing is passed - it returns a single object.
871
+ #
872
+ # @return [Chewy::Index] result document
873
+ #
874
+ # @overload first(limit)
875
+ # If limit is provided - it returns the limit amount or less
876
+ # of wrapper objects.
877
+ #
878
+ # @param limit [Integer] amount of requested results
879
+ # @return [Array<Chewy::Index>] result document collection
880
+ def first(limit = UNDEFINED)
881
+ request_limit = limit == UNDEFINED ? 1 : limit
882
+
883
+ if performed? && (request_limit <= size || size == total)
884
+ limit == UNDEFINED ? wrappers.first : wrappers.first(limit)
885
+ else
886
+ result = except(EXTRA_STORAGES).limit(request_limit).to_a
887
+ limit == UNDEFINED ? result.first : result
888
+ end
889
+ end
890
+
891
+ # Finds documents with specified ids for the current request scope.
892
+ #
893
+ # @raise [Chewy::DocumentNotFound] in case of any document is missing
894
+ # @overload find(id)
895
+ # If single id is passed - it returns a single object.
896
+ #
897
+ # @param id [Integer, String] id of the desired document
898
+ # @return [Chewy::Index] result document
899
+ #
900
+ # @overload find(*ids)
901
+ # If several field are passed - it returns an array of wrappers.
902
+ # Respect the amount of passed ids and if it is more than the default
903
+ # batch size - uses scroll API to retrieve everything.
904
+ #
905
+ # @param ids [Array<Integer, String>] ids of the desired documents
906
+ # @return [Array<Chewy::Index>] result documents
907
+ def find(*ids)
908
+ return super if block_given?
909
+
910
+ ids = ids.flatten(1).map(&:to_s)
911
+ scope = except(EXTRA_STORAGES).filter(ids: {values: ids})
912
+
913
+ results = if ids.size > DEFAULT_BATCH_SIZE
914
+ scope.scroll_wrappers
915
+ else
916
+ scope.limit(ids.size)
917
+ end.to_a
918
+
919
+ if ids.size != results.size
920
+ missing_ids = ids - results.map(&:id).map(&:to_s)
921
+ raise Chewy::DocumentNotFound, "Could not find documents for ids: #{missing_ids.to_sentence}"
922
+ end
923
+ results.one? ? results.first : results
924
+ end
925
+
926
+ # Returns and array of values for specified fields.
927
+ # Uses `source` to restrict the list of returned fields.
928
+ # Fields `_id`, `_type`, `_routing` and `_index` are also supported.
929
+ #
930
+ # @overload pluck(field)
931
+ # If single field is passed - it returns and array of values.
932
+ #
933
+ # @param field [String, Symbol] field name
934
+ # @return [Array<Object>] specified field values
935
+ #
936
+ # @overload pluck(*fields)
937
+ # If several field are passed - it returns an array of arrays of values.
938
+ #
939
+ # @param fields [Array<String, Symbol>] field names
940
+ # @return [Array<Array<Object>>] specified field values
941
+ def pluck(*fields)
942
+ fields = fields.flatten(1).reject(&:blank?).map(&:to_s)
943
+
944
+ source_fields = fields - EVERFIELDS
945
+ scope = except(FIELD_STORAGES, EXTRA_STORAGES)
946
+ .source(source_fields.presence || false)
947
+
948
+ hits = raw_limit_value ? scope.hits : scope.scroll_hits(batch_size: DEFAULT_PLUCK_BATCH_SIZE)
949
+ hits.map do |hit|
950
+ if fields.one?
951
+ fetch_field(hit, fields.first)
952
+ else
953
+ fields.map do |field|
954
+ fetch_field(hit, field)
955
+ end
956
+ end
957
+ end
958
+ end
959
+
960
+ # Deletes all the documents from the specified scope it uses
961
+ # `delete_by_query`
962
+ #
963
+ # @see https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-delete-by-query.html
964
+ # @note The result hash is different for different API used.
965
+ # @param refresh [true, false] Refreshes all shards involved in the delete by query
966
+ # @param wait_for_completion [true, false] wait for request completion or run it asynchronously
967
+ # and return task reference at `.tasks/task/${taskId}`.
968
+ # @param requests_per_second [Float] The throttle for this request in sub-requests per second
969
+ # @param scroll_size [Integer] Size of the scroll request that powers the operation
970
+
971
+ # @return [Hash] the result of query execution
972
+ def delete_all(refresh: true, wait_for_completion: nil, requests_per_second: nil, scroll_size: nil)
973
+ request_body = only(WHERE_STORAGES).render.merge(
974
+ {
975
+ refresh: refresh,
976
+ wait_for_completion: wait_for_completion,
977
+ requests_per_second: requests_per_second,
978
+ scroll_size: scroll_size
979
+ }.compact
980
+ )
981
+ ActiveSupport::Notifications.instrument 'delete_query.chewy', notification_payload(request: request_body) do
982
+ request_body[:body] = {query: {match_all: {}}} if request_body[:body].empty?
983
+ Chewy.client.delete_by_query(request_body)
984
+ end
985
+ end
986
+
987
+ # Returns whether or not the query has been performed.
988
+ #
989
+ # @return [true, false]
990
+ def performed?
991
+ !@response.nil?
992
+ end
993
+
994
+ protected
995
+
996
+ def initialize_clone(origin)
997
+ @parameters = origin.parameters.clone
998
+ reset
999
+ end
1000
+
1001
+ private
1002
+
1003
+ def build_response(raw_response)
1004
+ Response.new(raw_response, loader, collection_paginator)
1005
+ end
1006
+
1007
+ def compare_internals(other)
1008
+ parameters == other.parameters
1009
+ end
1010
+
1011
+ def modify(name, &block)
1012
+ chain { parameters.modify!(name, &block) }
1013
+ end
1014
+
1015
+ def chain(&block)
1016
+ clone.tap { |r| r.instance_exec(&block) }
1017
+ end
1018
+
1019
+ def reset
1020
+ @response, @render, @loader = nil
1021
+ end
1022
+
1023
+ def perform(additional = {})
1024
+ request_body = render.merge(additional)
1025
+ ActiveSupport::Notifications.instrument 'search_query.chewy', notification_payload(request: request_body) do
1026
+ Chewy.client.search(request_body)
1027
+ rescue Elasticsearch::Transport::Transport::Errors::NotFound
1028
+ {}
1029
+ end
1030
+ end
1031
+
1032
+ def notification_payload(additional)
1033
+ {
1034
+ indexes: _indices,
1035
+ index: _indices.one? ? _indices.first : _indices
1036
+ }.merge(additional)
1037
+ end
1038
+
1039
+ def _indices
1040
+ parameters[:indices].indices
1041
+ end
1042
+
1043
+ def raw_limit_value
1044
+ parameters[:limit].value
1045
+ end
1046
+
1047
+ def raw_offset_value
1048
+ parameters[:offset].value
1049
+ end
1050
+
1051
+ def loader
1052
+ @loader ||= Loader.new(
1053
+ indexes: parameters[:indices].indices,
1054
+ **parameters[:load].value
1055
+ )
1056
+ end
1057
+
1058
+ def fetch_field(hit, field)
1059
+ if EVERFIELDS.include?(field)
1060
+ hit[field]
1061
+ else
1062
+ hit.fetch('_source', {})[field]
1063
+ end
1064
+ end
1065
+
1066
+ def collection_paginator
1067
+ method(:paginated_collection).to_proc if respond_to?(:paginated_collection, true)
1068
+ end
1069
+ end
1070
+ end
1071
+ end