search_flip 2.0.0.beta2 → 2.0.0.beta3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
+