search_flip 2.0.0.beta2 → 2.0.0.beta3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 61c625b2c60157b40c9508e6847e9727b1a468e03910afe317f39fd9687310bd
4
- data.tar.gz: bdfc1613945464bb559243cf3d98fe9d29308d35ab2c6133db065bd9efa70322
3
+ metadata.gz: 55f88fe9b429304c6f605a0175b3b711334cf47613facc78864511b012e2eb4e
4
+ data.tar.gz: 12c5e164eb18caaf72a361c7d1ba24f9b0324c412f2c7712f79f87e9248dbf1c
5
5
  SHA512:
6
- metadata.gz: 24dbb5c4294827bd66b24d67a873adfb819eba35d74c393149afe5133f6b59339254e2d3348130035675b0e2ce40cdc223133db0ed52bd2e9ca34d87e9383992
7
- data.tar.gz: 8066d64b3695d56fff2f4445602f7d4a86a815a536e825ed7a5287c5738193dfc2e4e8a81d6ea95c03e945cea564a7ff70be43c9fb97e3c30d96c972703ab57f
6
+ metadata.gz: 26842b8df4ee2014ee77f1429ab6438350f45458e150fe1786f654bb2d925c53524007d2ec88bed42f80d0983887b8720c19b617ec1e00de8de8964c70a602dd
7
+ data.tar.gz: 6976b12cd544bbc19f88fb69e855c6107badd49c565578b6b5a75b07d63d85ad4d85762e0e18b02010b9376123f44c8bb73dc81676e3f28cdd5b9ab9d237659c
data/.rubocop.yml CHANGED
@@ -47,10 +47,10 @@ Layout/LeadingBlankLines:
47
47
  Enabled: false
48
48
 
49
49
  Metrics/LineLength:
50
- Max: 150
50
+ Enabled: false
51
51
 
52
52
  Metrics/MethodLength:
53
- Max: 60
53
+ Enabled: false
54
54
 
55
55
  Metrics/ModuleLength:
56
56
  Enabled: false
@@ -71,7 +71,7 @@ Metrics/CyclomaticComplexity:
71
71
  Enabled: false
72
72
 
73
73
  Metrics/BlockLength:
74
- Max: 30
74
+ Enabled: false
75
75
 
76
76
  Metrics/BlockNesting:
77
77
  Enabled: false
@@ -108,3 +108,10 @@ Lint/UnusedMethodArgument:
108
108
 
109
109
  Layout/IndentArray:
110
110
  EnforcedStyle: consistent
111
+
112
+ Style/IfUnlessModifier:
113
+ Enabled: false
114
+
115
+ Style/RedundantBegin:
116
+ Enabled: false
117
+
data/README.md CHANGED
@@ -373,7 +373,7 @@ CommentIndex.highlight(title: { type: "fvh" })
373
373
 
374
374
  ```ruby
375
375
  query = CommentIndex.highlight(:title).search("hello")
376
- query.results[0].highlight.title # => "<em>hello</em> world"
376
+ query.results[0]._hit.highlight.title # => "<em>hello</em> world"
377
377
  ```
378
378
 
379
379
  ### Advanced Criteria Methods
@@ -558,6 +558,27 @@ end
558
558
  This allows to use different clusters per index e.g. when migrating indices to
559
559
  new versions of Elasticsearch.
560
560
 
561
+ ## Routing and other index-time options
562
+
563
+ Override `index_options` in case you want to use routing or pass other
564
+ index-time options:
565
+
566
+ ```ruby
567
+ class CommentIndex
568
+ include SearchFlip::Index
569
+
570
+ def self.index_options(comment)
571
+ {
572
+ routing: comment.user_id,
573
+ version: comment.version,
574
+ version_type: "external_gte"
575
+ }
576
+ end
577
+ end
578
+ ```
579
+
580
+ These options will be passed whenever records get indexed, deleted, etc.
581
+
561
582
  ## Non-ActiveRecord models
562
583
 
563
584
  SearchFlip ships with built-in support for ActiveRecord models, but using
data/UPDATING.md CHANGED
@@ -3,7 +3,7 @@
3
3
 
4
4
  ## Update 1.x to 2.x
5
5
 
6
- * [BREAKING] Changed `SearchFlip::Index.base_url` to `SearchFlip::Index.connection`
6
+ * **[BREAKING]** Changed `SearchFlip::Index.base_url` to `SearchFlip::Index.connection`
7
7
 
8
8
  1.x:
9
9
 
@@ -33,7 +33,7 @@ class MyIndex
33
33
  end
34
34
  ```
35
35
 
36
- * [BREAKING] Changed `SearchFlip.version` to `SearchFlip::Connection#version`
36
+ * **[BREAKING]** Changed `SearchFlip.version` to `SearchFlip::Connection#version`
37
37
 
38
38
  1.x:
39
39
 
@@ -52,7 +52,7 @@ connection = SearchFlip::Connection.new(base_url: "...")
52
52
  connection.version
53
53
  ```
54
54
 
55
- * [BREAKING] Changed `SearchFlip.aliases` to `SearchFlip::Connection#update_aliases`
55
+ * **[BREAKING]** Changed `SearchFlip.aliases` to `SearchFlip::Connection#update_aliases`
56
56
 
57
57
  1.x:
58
58
 
@@ -77,7 +77,7 @@ connection.update_aliases(actions: [
77
77
  ])
78
78
  ```
79
79
 
80
- * [BREAKING] Changed `SearchFlip.msearch` to `SearchFlip::Connection#msearch`
80
+ * **[BREAKING]** Changed `SearchFlip.msearch` to `SearchFlip::Connection#msearch`
81
81
 
82
82
  1.x:
83
83
 
@@ -96,7 +96,7 @@ connection = SearchFlip::Connection.new(base_url: "...")
96
96
  connection.msearch(queries)
97
97
  ```
98
98
 
99
- * [BREAKING] Removed `base_url` param from `SearchFlip::Critiera#execute`
99
+ * **[BREAKING]** Removed `base_url` param from `SearchFlip::Critiera#execute`
100
100
 
101
101
  1.x:
102
102
 
@@ -111,3 +111,19 @@ connection = SearchFlip::Connection.new(base_url: "...")
111
111
  MyIndex.where(id: 1).with_settings(connection: connection).execute
112
112
  ```
113
113
 
114
+ * **[BREAKING]** Move hit data within results in `_hit` namespace
115
+
116
+ 1.x:
117
+
118
+ ```ruby
119
+ query = CommentIndex.highlight(:title).search("hello")
120
+ query.results[0].highlight.title # => "<em>hello</em> world"
121
+ ```
122
+
123
+ 2.x:
124
+
125
+ ```ruby
126
+ query = CommentIndex.highlight(:title).search("hello")
127
+ query.results[0]._hit.highlight.title # => "<em>hello</em> world"
128
+ ```
129
+
@@ -14,7 +14,7 @@ module SearchFlip
14
14
  class Bulk
15
15
  class Error < StandardError; end
16
16
 
17
- attr_accessor :url, :count, :options, :ignore_errors
17
+ attr_accessor :url, :count, :options, :http_client, :ignore_errors
18
18
 
19
19
  # Builds and yields a new Bulk object, ie initiates the buffer, yields,
20
20
  # sends batches of records each time the buffer is full, and sends a final
@@ -40,11 +40,14 @@ module SearchFlip
40
40
  # @option options raise [Boolean] If you want the bulk requests to never
41
41
  # raise any exceptions (fire and forget), you can pass false here.
42
42
  # Default is true.
43
+ # @option options http_client [SearchFlip::HTTPClient] An optional http
44
+ # client instance
43
45
 
44
46
  def initialize(url, count = 1_000, options = {})
45
47
  self.url = url
46
48
  self.count = count
47
49
  self.options = options
50
+ self.http_client = options[:http_client] || SearchFlip::HTTPClient.new
48
51
  self.ignore_errors = Array(options[:ignore_errors]).to_set if options[:ignore_errors]
49
52
 
50
53
  init
@@ -114,7 +117,7 @@ module SearchFlip
114
117
 
115
118
  def upload
116
119
  response =
117
- SearchFlip::HTTPClient
120
+ http_client
118
121
  .headers(accept: "application/json", content_type: "application/x-ndjson")
119
122
  .put(url, body: @payload, params: ignore_errors ? {} : { filter_path: "errors" })
120
123
 
@@ -1,10 +1,19 @@
1
1
 
2
2
  module SearchFlip
3
3
  class Connection
4
- attr_reader :base_url
4
+ attr_reader :base_url, :http_client
5
5
 
6
- def initialize(base_url: SearchFlip::Config[:base_url])
6
+ # Creates a new connection.
7
+ #
8
+ # @example
9
+ # SearchFlip::Connection.new(base_url: "http://elasticsearch.host:9200")
10
+ #
11
+ # @param base_url [String] The base url for the connection
12
+ # @param http_client [SearchFlip::HTTPClient] An optional http client instance
13
+
14
+ def initialize(base_url: SearchFlip::Config[:base_url], http_client: SearchFlip::HTTPClient.new)
7
15
  @base_url = base_url
16
+ @http_client = http_client
8
17
  end
9
18
 
10
19
  # Queries and returns the ElasticSearch version used.
@@ -15,7 +24,7 @@ module SearchFlip
15
24
  # @return [String] The ElasticSearch version
16
25
 
17
26
  def version
18
- @version ||= SearchFlip::HTTPClient.get("#{base_url}/").parse["version"]["number"]
27
+ @version ||= http_client.headers(accept: "application/json").get("#{base_url}/").parse["version"]["number"]
19
28
  end
20
29
 
21
30
  # Uses the ElasticSearch Multi Search API to execute multiple search requests
@@ -42,7 +51,7 @@ module SearchFlip
42
51
  payload << "\n"
43
52
 
44
53
  raw_response =
45
- SearchFlip::HTTPClient
54
+ http_client
46
55
  .headers(accept: "application/json", content_type: "application/x-ndjson")
47
56
  .post("#{base_url}/_msearch", body: payload)
48
57
 
@@ -65,7 +74,7 @@ module SearchFlip
65
74
  # @return [Hash] The raw response
66
75
 
67
76
  def update_aliases(payload)
68
- SearchFlip::HTTPClient
77
+ http_client
69
78
  .headers(accept: "application/json", content_type: "application/json")
70
79
  .post("#{base_url}/_aliases", body: SearchFlip::JSON.generate(payload))
71
80
  .parse
@@ -84,10 +93,11 @@ module SearchFlip
84
93
  # @return [Hash] The raw response
85
94
 
86
95
  def get_aliases(index_name: "*", alias_name: "*")
87
- res = SearchFlip::HTTPClient
88
- .headers(accept: "application/json", content_type: "application/json")
89
- .get("#{base_url}/#{index_name}/_alias/#{alias_name}")
90
- .parse
96
+ res =
97
+ http_client
98
+ .headers(accept: "application/json", content_type: "application/json")
99
+ .get("#{base_url}/#{index_name}/_alias/#{alias_name}")
100
+ .parse
91
101
 
92
102
  Hashie::Mash.new(res)
93
103
  end
@@ -101,7 +111,7 @@ module SearchFlip
101
111
  # @return [Boolean] Whether or not the alias exists
102
112
 
103
113
  def alias_exists?(alias_name)
104
- SearchFlip::HTTPClient
114
+ http_client
105
115
  .headers(accept: "application/json", content_type: "application/json")
106
116
  .get("#{base_url}/_alias/#{alias_name}")
107
117
 
@@ -121,7 +131,7 @@ module SearchFlip
121
131
  # @return [Array] The raw response
122
132
 
123
133
  def get_indices(name = "*")
124
- SearchFlip::HTTPClient
134
+ http_client
125
135
  .headers(accept: "application/json", content_type: "application/json")
126
136
  .get("#{base_url}/_cat/indices/#{name}")
127
137
  .parse
@@ -136,7 +146,7 @@ module SearchFlip
136
146
  # @return [Boolean] Returns true or raises SearchFlip::ResponseError
137
147
 
138
148
  def create_index(index_name, index_settings = {})
139
- SearchFlip::HTTPClient.put(index_url(index_name), json: index_settings)
149
+ http_client.put(index_url(index_name), json: index_settings)
140
150
 
141
151
  true
142
152
  end
@@ -150,7 +160,7 @@ module SearchFlip
150
160
  # @return [Boolean] Returns true or raises SearchFlip::ResponseError
151
161
 
152
162
  def update_index_settings(index_name, index_settings)
153
- SearchFlip::HTTPClient.put("#{index_url(index_name)}/_settings", json: index_settings)
163
+ http_client.put("#{index_url(index_name)}/_settings", json: index_settings)
154
164
 
155
165
  true
156
166
  end
@@ -163,7 +173,7 @@ module SearchFlip
163
173
  # @return [Hash] The index settings
164
174
 
165
175
  def get_index_settings(index_name)
166
- SearchFlip::HTTPClient.headers(accept: "application/json").get("#{index_url(index_name)}/_settings").parse
176
+ http_client.headers(accept: "application/json").get("#{index_url(index_name)}/_settings").parse
167
177
  end
168
178
 
169
179
  # Sends a refresh request to ElasticSearch. Raises
@@ -173,7 +183,7 @@ module SearchFlip
173
183
  # @return [Boolean] Returns true or raises SearchFlip::ResponseError
174
184
 
175
185
  def refresh(index_names = nil)
176
- SearchFlip::HTTPClient.post("#{index_names ? index_url(Array(index_names).join(",")) : base_url}/_refresh", json: {})
186
+ http_client.post("#{index_names ? index_url(Array(index_names).join(",")) : base_url}/_refresh", json: {})
177
187
 
178
188
  true
179
189
  end
@@ -188,7 +198,7 @@ module SearchFlip
188
198
  # @return [Boolean] Returns true or raises SearchFlip::ResponseError
189
199
 
190
200
  def update_mapping(index_name, type_name, mapping)
191
- SearchFlip::HTTPClient.put("#{type_url(index_name, type_name)}/_mapping", json: mapping)
201
+ http_client.put("#{type_url(index_name, type_name)}/_mapping", json: mapping)
192
202
 
193
203
  true
194
204
  end
@@ -201,7 +211,7 @@ module SearchFlip
201
211
  # @return [Hash] The current type mapping
202
212
 
203
213
  def get_mapping(index_name, type_name)
204
- SearchFlip::HTTPClient.headers(accept: "application/json").get("#{type_url(index_name, type_name)}/_mapping").parse
214
+ http_client.headers(accept: "application/json").get("#{type_url(index_name, type_name)}/_mapping").parse
205
215
  end
206
216
 
207
217
  # Deletes the specified index from ElasticSearch. Raises
@@ -211,7 +221,7 @@ module SearchFlip
211
221
  # @return [Boolean] Returns true or raises SearchFlip::ResponseError
212
222
 
213
223
  def delete_index(index_name)
214
- SearchFlip::HTTPClient.delete index_url(index_name)
224
+ http_client.delete index_url(index_name)
215
225
 
216
226
  true
217
227
  end
@@ -222,7 +232,7 @@ module SearchFlip
222
232
  # @return [Boolean] Whether or not the index exists
223
233
 
224
234
  def index_exists?(index_name)
225
- SearchFlip::HTTPClient.headers(accept: "application/json").head(index_url(index_name))
235
+ http_client.headers(accept: "application/json").head(index_url(index_name))
226
236
 
227
237
  true
228
238
  rescue SearchFlip::ResponseError => e
@@ -39,18 +39,18 @@ module SearchFlip
39
39
 
40
40
  fresh.tap do |criteria|
41
41
  criteria.profile_value = other.profile_value unless other.profile_value.nil?
42
- criteria.source_value = (criteria.source_value || []) + other.source_value if other.source_value
43
- criteria.sort_values = (criteria.sort_values || []) + other.sort_values if other.sort_values
44
- criteria.highlight_values = (criteria.highlight_values || {}).merge(other.highlight_values) if other.highlight_values
45
- criteria.suggest_values = (criteria.suggest_values || {}).merge(other.suggest_values) if other.suggest_values
42
+ criteria.failsafe_value = other.failsafe_value unless other.failsafe_value.nil?
43
+ criteria.terminate_after_value = other.terminate_after_value unless other.terminate_after_value.nil?
44
+ criteria.timeout_value = other.timeout_value unless other.timeout_value.nil?
46
45
  criteria.offset_value = other.offset_value if other.offset_value
47
46
  criteria.limit_value = other.limit_value if other.limit_value
47
+ criteria.scroll_args = other.scroll_args if other.scroll_args
48
+
49
+ criteria.source_value = (criteria.source_value || []) + other.source_value if other.source_value
50
+ criteria.sort_values = (criteria.sort_values || []) + other.sort_values if other.sort_values
48
51
  criteria.includes_values = (criteria.includes_values || []) + other.includes_values if other.includes_values
49
52
  criteria.preload_values = (criteria.preload_values || []) + other.preload_values if other.preload_values
50
53
  criteria.eager_load_values = (criteria.eager_load_values || []) + other.eager_load_values if other.eager_load_values
51
- criteria.failsafe_value = other.failsafe_value unless other.failsafe_value.nil?
52
- criteria.scroll_args = other.scroll_args if other.scroll_args
53
- criteria.custom_value = (criteria.custom_value || {}).merge(other.custom_value) if other.custom_value
54
54
  criteria.search_values = (criteria.search_values || []) + other.search_values if other.search_values
55
55
  criteria.must_values = (criteria.must_values || []) + other.must_values if other.must_values
56
56
  criteria.must_not_values = (criteria.must_not_values || []) + other.must_not_values if other.must_not_values
@@ -61,9 +61,11 @@ module SearchFlip
61
61
  criteria.post_must_not_values = (criteria.post_must_not_values || []) + other.post_must_not_values if other.post_must_not_values
62
62
  criteria.post_should_values = (criteria.post_should_values || []) + other.post_should_values if other.post_should_values
63
63
  criteria.post_filter_values = (criteria.post_filter_values || []) + other.post_filter_values if other.post_filter_values
64
+
65
+ criteria.highlight_values = (criteria.highlight_values || {}).merge(other.highlight_values) if other.highlight_values
66
+ criteria.suggest_values = (criteria.suggest_values || {}).merge(other.suggest_values) if other.suggest_values
67
+ criteria.custom_value = (criteria.custom_value || {}).merge(other.custom_value) if other.custom_value
64
68
  criteria.aggregation_values = (criteria.aggregation_values || {}).merge(other.aggregation_values) if other.aggregation_values
65
- criteria.terminate_after_value = other.terminate_after_value unless other.terminate_after_value.nil?
66
- criteria.timeout_value = other.timeout_value unless other.timeout_value.nil?
67
69
  end
68
70
  end
69
71
 
@@ -175,7 +177,7 @@ module SearchFlip
175
177
  res = {}
176
178
 
177
179
  if must_values || search_values || must_not_values || should_values || filter_values
178
- if target.connection.version.to_i >= 2
180
+ if connection.version.to_i >= 2
179
181
  res[:query] = {
180
182
  bool: {}
181
183
  .merge(must_values || search_values ? { must: (must_values || []) + (search_values || []) } : {})
@@ -213,7 +215,7 @@ module SearchFlip
213
215
  res[:aggregations] = aggregation_values if aggregation_values
214
216
 
215
217
  if post_must_values || post_search_values || post_must_not_values || post_should_values || post_filter_values
216
- if target.connection.version.to_i >= 2
218
+ if connection.version.to_i >= 2
217
219
  res[:post_filter] = {
218
220
  bool: {}
219
221
  .merge(post_must_values || post_search_values ? { must: (post_must_values || []) + (post_search_values || []) } : {})
@@ -357,10 +359,10 @@ module SearchFlip
357
359
  dupped_request.delete(:from)
358
360
  dupped_request.delete(:size)
359
361
 
360
- if target.connection.version.to_i >= 5
361
- SearchFlip::HTTPClient.post("#{target.type_url}/_delete_by_query", json: dupped_request)
362
+ if connection.version.to_i >= 5
363
+ connection.http_client.post("#{target.type_url}/_delete_by_query", json: dupped_request)
362
364
  else
363
- SearchFlip::HTTPClient.delete("#{target.type_url}/_query", json: dupped_request)
365
+ connection.http_client.delete("#{target.type_url}/_query", json: dupped_request)
364
366
  end
365
367
 
366
368
  target.refresh if SearchFlip::Config[:auto_refresh]
@@ -673,6 +675,32 @@ module SearchFlip
673
675
 
674
676
  alias_method :each, :find_each
675
677
 
678
+ # Fetches the results specified by the criteria in batches using the
679
+ # ElasticSearch scroll API and yields each result. The batch size and scroll
680
+ # API timeout can be specified. Checkout out the ElasticSearch docs for
681
+ # further details.
682
+ #
683
+ # @example
684
+ # CommentIndex.search("hello world").find_each_result(batch_size: 100) do |result|
685
+ # # ...
686
+ # end
687
+ #
688
+ # @param options [Hash] The options to control the fetching of batches
689
+ # @option options batch_size [Fixnum] The number of records to fetch per
690
+ # batch. Uses #limit to control the batch size.
691
+ # @option options timeout [String] The timeout per scroll request, ie how
692
+ # long ElasticSearch will keep the request handle open.
693
+
694
+ def find_each_result(options = {})
695
+ return enum_for(:find_each_result, options) unless block_given?
696
+
697
+ find_results_in_batches options do |batch|
698
+ batch.each do |result|
699
+ yield result
700
+ end
701
+ end
702
+ end
703
+
676
704
  # Executes the search request for the current criteria, ie sends the
677
705
  # request to ElasticSearch and returns the response. Connection and
678
706
  # response errors will be rescued if you specify the criteria to be
@@ -685,19 +713,19 @@ module SearchFlip
685
713
 
686
714
  def execute
687
715
  @response ||= begin
688
- http_request = SearchFlip::HTTPClient.headers(accept: "application/json")
716
+ http_request = connection.http_client.headers(accept: "application/json")
689
717
 
690
718
  http_response =
691
719
  if scroll_args && scroll_args[:id]
692
- if target.connection.version.to_i >= 2
720
+ if connection.version.to_i >= 2
693
721
  http_request.post(
694
- "#{target.connection.base_url}/_search/scroll",
722
+ "#{connection.base_url}/_search/scroll",
695
723
  json: { scroll: scroll_args[:timeout], scroll_id: scroll_args[:id] }
696
724
  )
697
725
  else
698
726
  http_request
699
727
  .headers(content_type: "text/plain")
700
- .post("#{target.connection.base_url}/_search/scroll", params: { scroll: scroll_args[:timeout] }, body: scroll_args[:id])
728
+ .post("#{connection.base_url}/_search/scroll", params: { scroll: scroll_args[:timeout] }, body: scroll_args[:id])
701
729
  end
702
730
  elsif scroll_args
703
731
  http_request.post(
@@ -776,6 +804,8 @@ module SearchFlip
776
804
  :hits, :ids, :count, :size, :length, :took, :aggregations, :suggestions,
777
805
  :scope, :results, :records, :scroll_id, :raw_response
778
806
 
807
+ def_delegators :target, :connection
808
+
779
809
  private
780
810
 
781
811
  def yield_in_batches(options = {})
@@ -7,42 +7,43 @@ module SearchFlip
7
7
  # with ElasticSearch.
8
8
 
9
9
  class HTTPClient
10
- class Request
11
- attr_accessor :headers_hash
10
+ attr_accessor :request
12
11
 
13
- def headers(hash = {})
14
- dup.tap do |request|
15
- request.headers_hash = (request.headers_hash || {}).merge(hash)
16
- end
17
- end
18
-
19
- [:get, :post, :put, :delete, :head].each do |method|
20
- define_method method do |*args|
21
- execute(method, *args)
22
- end
23
- end
24
-
25
- private
12
+ def initialize
13
+ self.request = HTTP
14
+ end
26
15
 
27
- def execute(method, *args)
28
- response = HTTP.headers(headers_hash || {}).send(method, *args)
16
+ class << self
17
+ extend Forwardable
29
18
 
30
- raise SearchFlip::ResponseError.new(code: response.code, body: response.body.to_s) unless response.status.success?
19
+ def_delegators :new, :headers, :via, :basic_auth, :auth
20
+ def_delegators :new, :get, :post, :put, :delete, :head
21
+ end
31
22
 
32
- response
33
- rescue HTTP::ConnectionError => e
34
- raise SearchFlip::ConnectionError, e.message
23
+ [:headers, :via, :basic_auth, :auth].each do |method|
24
+ define_method method do |*args|
25
+ dup.tap do |client|
26
+ client.request = request.send(method, *args)
27
+ end
35
28
  end
36
29
  end
37
30
 
38
- def self.request
39
- Request.new
31
+ [:get, :post, :put, :delete, :head].each do |method|
32
+ define_method method do |*args|
33
+ execute(method, *args)
34
+ end
40
35
  end
41
36
 
42
- class << self
43
- extend Forwardable
37
+ private
38
+
39
+ def execute(method, *args)
40
+ response = request.send(method, *args)
41
+
42
+ raise SearchFlip::ResponseError.new(code: response.code, body: response.body.to_s) unless response.status.success?
44
43
 
45
- def_delegators :request, :headers, :get, :post, :put, :delete, :head
44
+ response
45
+ rescue HTTP::ConnectionError => e
46
+ raise SearchFlip::ConnectionError, e.message
46
47
  end
47
48
  end
48
49
  end
@@ -247,8 +247,8 @@ module SearchFlip
247
247
  :post_filter, :post_must, :post_must_not, :post_should, :aggregate, :scroll, :source,
248
248
  :includes, :eager_load, :preload, :sort, :resort, :order, :reorder, :offset, :limit, :paginate,
249
249
  :page, :per, :search, :highlight, :suggest, :custom, :find_in_batches, :find_results_in_batches,
250
- :find_each, :failsafe, :total_entries, :total_count, :timeout, :terminate_after, :records,
251
- :should, :should_not, :must, :must_not
250
+ :find_each, :find_each_result, :failsafe, :total_entries, :total_count, :timeout, :terminate_after,
251
+ :records, :results, :should, :should_not, :must, :must_not
252
252
 
253
253
  # Override to specify the type name used within ElasticSearch. Recap,
254
254
  # this gem uses an individual index for each index class, because
@@ -396,7 +396,7 @@ module SearchFlip
396
396
  # @return [Hash] The specified document
397
397
 
398
398
  def get(id, params = {})
399
- SearchFlip::HTTPClient.headers(accept: "application/json").get("#{type_url}/#{id}", params: params).parse
399
+ connection.http_client.headers(accept: "application/json").get("#{type_url}/#{id}", params: params).parse
400
400
  end
401
401
 
402
402
  # Sends a index refresh request to ElasticSearch. Raises
@@ -532,7 +532,9 @@ module SearchFlip
532
532
  # raise.
533
533
 
534
534
  def bulk(options = {})
535
- SearchFlip::Bulk.new("#{type_url}/_bulk", SearchFlip::Config[:bulk_limit], options) do |indexer|
535
+ opts = { http_client: connection.http_client }.merge(options)
536
+
537
+ SearchFlip::Bulk.new("#{type_url}/_bulk", SearchFlip::Config[:bulk_limit], opts) do |indexer|
536
538
  yield indexer
537
539
  end
538
540
 
@@ -167,7 +167,15 @@ module SearchFlip
167
167
  # @return [Array] An array of results
168
168
 
169
169
  def results
170
- @results ||= hits["hits"].map { |hit| Result.new hit["_source"].merge(hit["highlight"] ? { highlight: hit["highlight"] } : {}) }
170
+ @results ||= hits["hits"].map do |hit|
171
+ raw_result = hit["_source"]
172
+
173
+ raw_result["_hit"] = hit.each_with_object({}) do |(key, value), hash|
174
+ hash[key] = value if key != "_source"
175
+ end
176
+
177
+ Result.new(raw_result)
178
+ end
171
179
  end
172
180
 
173
181
  # Returns the named sugggetion, if a name is specified or alle suggestions.
@@ -1,5 +1,5 @@
1
1
 
2
2
  module SearchFlip
3
- VERSION = "2.0.0.beta2"
3
+ VERSION = "2.0.0.beta3"
4
4
  end
5
5
 
data/search_flip.gemspec CHANGED
@@ -19,12 +19,17 @@ Gem::Specification.new do |spec|
19
19
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
20
20
  spec.require_paths = ["lib"]
21
21
 
22
+ spec.post_install_message = <<~MESSAGE
23
+ Thanks for using search_flip!
24
+ When upgrading from 1.x to 2.x, please check out
25
+ https://github.com/mrkamel/search_flip/blob/master/UPDATING.md
26
+ MESSAGE
27
+
22
28
  spec.add_development_dependency "activerecord", ">= 3.0"
23
29
  spec.add_development_dependency "bundler"
24
30
  spec.add_development_dependency "factory_bot"
25
- spec.add_development_dependency "minitest"
26
- spec.add_development_dependency "mocha"
27
31
  spec.add_development_dependency "rake"
32
+ spec.add_development_dependency "rspec"
28
33
  spec.add_development_dependency "sqlite3", "~> 1.3.6"
29
34
  spec.add_development_dependency "timecop"
30
35
  spec.add_development_dependency "webmock"
@@ -0,0 +1,32 @@
1
+
2
+ RSpec::Matchers.define :delegate do |method|
3
+ match do |delegator|
4
+ @method = method
5
+ @delegator = delegator
6
+
7
+ return false unless @delegator.respond_to?(@to)
8
+ return false unless @delegator.respond_to?(@method)
9
+
10
+ target = double
11
+
12
+ allow(@delegator).to receive(@to).and_return(target)
13
+ allow(target).to receive(@method).and_return(:called)
14
+
15
+ @delegator.send(@method) == :called
16
+ end
17
+
18
+ description do
19
+ "delegate :#{@method} to :#{@to}"
20
+ end
21
+
22
+ failure_message do
23
+ "expected #{@delegator} to delegate :#{@method} to :#{@to}"
24
+ end
25
+
26
+ failure_message_when_negated do
27
+ "expected #{@delegator} not to delegate :#{@method} to :#{@to}"
28
+ end
29
+
30
+ chain(:to) { |to| @to = to }
31
+ end
32
+