swiftype-app-search 0.4.0 → 0.4.1

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -10,7 +10,7 @@ To install the gem, execute:
10
10
  gem install swiftype-app-search
11
11
  ```
12
12
 
13
- Or place `gem 'swiftype-app-search', '~> 0.4.0` in your `Gemfile` and run `bundle install`.
13
+ Or place `gem 'swiftype-app-search', '~> 0.4.1` in your `Gemfile` and run `bundle install`.
14
14
 
15
15
  ## Usage
16
16
 
@@ -3,7 +3,11 @@ module SwiftypeAppSearch
3
3
  attr_reader :errors
4
4
 
5
5
  def initialize(response)
6
- @errors = response['errors'] || [ response ]
6
+ @errors = if response.is_a?(Array)
7
+ response.flat_map { |r| r['errors'] }
8
+ else
9
+ response['errors'] || [response]
10
+ end
7
11
  message = (errors.count == 1) ? "Error: #{errors.first}" : "Errors: #{errors.inspect}"
8
12
  super(message)
9
13
  end
@@ -1,3 +1,3 @@
1
1
  module SwiftypeAppSearch
2
- VERSION = '0.4.0'
2
+ VERSION = '0.4.1'
3
3
  end
@@ -1,17 +1,49 @@
1
+ require 'config_helper'
1
2
 
2
3
  describe SwiftypeAppSearch::Client do
3
4
  let(:engine_name) { "ruby-client-test-#{Time.now.to_i}" }
4
5
 
5
- include_context "App Search Credentials"
6
+ include_context 'App Search Credentials'
6
7
  let(:client) { SwiftypeAppSearch::Client.new(client_options) }
7
8
 
9
+ before(:all) do
10
+ # Bootstraps a static engine for 'read-only' options that require indexing
11
+ # across the test suite
12
+ @static_engine_name = "ruby-client-test-static-#{Time.now.to_i}"
13
+ as_api_key = ConfigHelper.get_as_api_key
14
+ as_host_identifier = ConfigHelper.get_as_host_identifier
15
+ as_api_endpoint = ConfigHelper.get_as_api_endpoint
16
+ client_options = ConfigHelper.get_client_options(as_api_key, as_host_identifier, as_api_endpoint)
17
+ @static_client = SwiftypeAppSearch::Client.new(client_options)
18
+ @static_client.create_engine(@static_engine_name)
19
+
20
+ @document1 = { 'id' => '1', 'title' => 'The Great Gatsby' }
21
+ @document2 = { 'id' => '2', 'title' => 'Catcher in the Rye' }
22
+ @documents = [@document1, @document2]
23
+ @static_client.index_documents(@static_engine_name, @documents)
24
+
25
+ # Wait until documents are indexed
26
+ start = Time.now
27
+ ready = false
28
+ until (ready)
29
+ sleep(3)
30
+ results = @static_client.search(@static_engine_name, '')
31
+ ready = true if results['results'].length == 2
32
+ ready = true if (Time.now - start).to_i >= 120 # Time out after 2 minutes
33
+ end
34
+ end
35
+
36
+ after(:all) do
37
+ @static_client.destroy_engine(@static_engine_name)
38
+ end
39
+
8
40
  describe 'Requests' do
9
41
  it 'should include client name and version in headers' do
10
42
  stub_request(:any, "#{client_options[:host_identifier]}.api.swiftype.com/api/as/v1/engines")
11
43
  client.list_engines
12
- expect(WebMock).to have_requested(:get, "https://#{client_options[:host_identifier]}.api.swiftype.com/api/as/v1/engines").
13
- with(
14
- headers: {
44
+ expect(WebMock).to have_requested(:get, "https://#{client_options[:host_identifier]}.api.swiftype.com/api/as/v1/engines")
45
+ .with(
46
+ :headers => {
15
47
  'X-Swiftype-Client' => 'swiftype-app-search-ruby',
16
48
  'X-Swiftype-Client-Version' => SwiftypeAppSearch::VERSION
17
49
  }
@@ -81,20 +113,24 @@ describe SwiftypeAppSearch::Client do
81
113
  subject { client.index_documents(engine_name, documents) }
82
114
 
83
115
  it 'should return an array of document status hashes' do
84
- expect(subject).to match([
85
- { 'id' => anything, 'errors' => [] },
86
- { 'id' => second_document_id, 'errors' => [] }
87
- ])
116
+ expect(subject).to match(
117
+ [
118
+ { 'id' => anything, 'errors' => [] },
119
+ { 'id' => second_document_id, 'errors' => [] }
120
+ ]
121
+ )
88
122
  end
89
123
 
90
124
  context 'when one of the documents has processing errors' do
91
125
  let(:second_document) { { 'id' => 'too long' * 100 } }
92
126
 
93
127
  it 'should return respective errors in an array of document processing hashes' do
94
- expect(subject).to match([
95
- { 'id' => anything, 'errors' => [] },
96
- { 'id' => anything, 'errors' => ['Invalid field type: id must be less than 800 characters'] },
97
- ])
128
+ expect(subject).to match(
129
+ [
130
+ { 'id' => anything, 'errors' => [] },
131
+ { 'id' => anything, 'errors' => ['Invalid field type: id must be less than 800 characters'] },
132
+ ]
133
+ )
98
134
  end
99
135
  end
100
136
  end
@@ -103,10 +139,14 @@ describe SwiftypeAppSearch::Client do
103
139
  let(:documents) { [document, second_document] }
104
140
  let(:second_document_id) { 'another_id' }
105
141
  let(:second_document) { { 'id' => second_document_id, 'url' => 'https://www.youtube.com/watch?v=9T1vfsHYiKY' } }
106
- let(:updates) { [ {
107
- 'id' => second_document_id,
108
- 'url' => 'https://www.example.com'
109
- } ] }
142
+ let(:updates) do
143
+ [
144
+ {
145
+ 'id' => second_document_id,
146
+ 'url' => 'https://www.example.com'
147
+ }
148
+ ]
149
+ end
110
150
 
111
151
  subject { client.update_documents(engine_name, updates) }
112
152
 
@@ -119,7 +159,6 @@ describe SwiftypeAppSearch::Client do
119
159
  # the request responded with the correct 'id', even though
120
160
  # the 'errors' object likely contains errors.
121
161
  it 'should update existing documents' do
122
- response = subject
123
162
  expect(subject).to match(['id' => second_document_id, 'errors' => anything])
124
163
  end
125
164
  end
@@ -167,7 +206,7 @@ describe SwiftypeAppSearch::Client do
167
206
 
168
207
  context 'when options are specified' do
169
208
  it 'will return all documents' do
170
- response = client.list_documents(engine_name, {page: { size: 1, current: 2}})
209
+ response = client.list_documents(engine_name, :page => { :size => 1, :current => 2 })
171
210
  expect(response['results'].size).to eq(1)
172
211
  expect(response['results'][0]['id']).to eq(second_document_id)
173
212
  end
@@ -176,62 +215,90 @@ describe SwiftypeAppSearch::Client do
176
215
  end
177
216
 
178
217
  context 'Search' do
179
- # Note that since indexing a document takes up to a minute,
180
- # don't actually expect results to be present, just that
181
- # the request was made
182
-
183
- before do
184
- client.create_engine(engine_name) rescue SwiftypeAppSearch::BadRequest
185
- end
186
-
187
- after do
188
- client.destroy_engine(engine_name) rescue SwiftypeAppSearch::NonExistentRecord
189
- end
190
-
191
218
  describe '#search' do
192
- subject { client.search(engine_name, query, options) }
193
- let (:query) { '' }
194
- let (:options) { { 'page' => { 'size' => 1 } } }
219
+ subject { @static_client.search(@static_engine_name, query, options) }
220
+ let(:query) { '' }
221
+ let(:options) { { 'page' => { 'size' => 2 } } }
195
222
 
196
223
  it 'should execute a search query' do
197
- response = subject
198
- expect(response).to have_key('meta')
199
- expect(response).to have_key('results')
224
+ expect(subject).to match(
225
+ 'meta' => anything,
226
+ 'results' => [anything, anything]
227
+ )
200
228
  end
201
229
  end
202
230
 
203
231
  describe '#multi_search' do
204
- subject { client.multi_search(engine_name, queries) }
232
+ subject { @static_client.multi_search(@static_engine_name, queries) }
205
233
 
206
234
  context 'when options are provided' do
207
- let (:queries) { [
208
- {'query': 'foo', 'options' => { 'page' => { 'size' => 1 } }},
209
- {'query': 'bar', 'options' => { 'page' => { 'size' => 1 } }}
210
- ] }
235
+ let(:queries) do
236
+ [
237
+ { 'query' => 'gatsby', 'options' => { 'page' => { 'size' => 1 } } },
238
+ { 'query' => 'catcher', 'options' => { 'page' => { 'size' => 1 } } }
239
+ ]
240
+ end
211
241
 
212
242
  it 'should execute a multi search query' do
213
243
  response = subject
214
- expect(response.size).to eq(2)
215
- expect(response[0]).to have_key('results')
216
- expect(response[0]).to have_key('meta')
217
- expect(response[1]).to have_key('results')
218
- expect(response[1]).to have_key('meta')
244
+ expect(response).to match(
245
+ [
246
+ {
247
+ 'meta' => anything,
248
+ 'results' => [{ 'id' => { 'raw' => '1' }, 'title' => anything, '_meta' => anything }]
249
+ },
250
+ {
251
+ 'meta' => anything,
252
+ 'results' => [{ 'id' => { 'raw' => '2' }, 'title' => anything, '_meta' => anything }]
253
+ }
254
+ ]
255
+ )
219
256
  end
220
257
  end
221
258
 
222
259
  context 'when options are omitted' do
223
- let (:queries) { [
224
- {'query': 'foo' },
225
- {'query': 'bar' }
226
- ] }
260
+ let(:queries) do
261
+ [
262
+ { 'query' => 'gatsby' },
263
+ { 'query' => 'catcher' }
264
+ ]
265
+ end
227
266
 
228
267
  it 'should execute a multi search query' do
229
268
  response = subject
230
- expect(response.size).to eq(2)
231
- expect(response[0]).to have_key('results')
232
- expect(response[0]).to have_key('meta')
233
- expect(response[1]).to have_key('results')
234
- expect(response[1]).to have_key('meta')
269
+ expect(response).to match(
270
+ [
271
+ {
272
+ 'meta' => anything,
273
+ 'results' => [{ 'id' => { 'raw' => '1' }, 'title' => anything, '_meta' => anything }]
274
+ },
275
+ {
276
+ 'meta' => anything,
277
+ 'results' => [{ 'id' => { 'raw' => '2' }, 'title' => anything, '_meta' => anything }]
278
+ }
279
+ ]
280
+ )
281
+ end
282
+ end
283
+
284
+ context 'when a search is bad' do
285
+ let(:queries) do
286
+ [
287
+ {
288
+ 'query' => 'cat',
289
+ 'options' => { 'search_fields' => { 'taco' => {} } }
290
+ }, {
291
+ 'query' => 'dog',
292
+ 'options' => { 'search_fields' => { 'body' => {} } }
293
+ }
294
+ ]
295
+ end
296
+
297
+ it 'should throw an appropriate error' do
298
+ expect { subject }.to raise_error do |e|
299
+ expect(e).to be_a(SwiftypeAppSearch::BadRequest)
300
+ expect(e.errors).to eq(['Search fields contains invalid field: taco', 'Search fields contains invalid field: body'])
301
+ end
235
302
  end
236
303
  end
237
304
  end
@@ -0,0 +1,22 @@
1
+ module ConfigHelper
2
+ def ConfigHelper.get_as_api_key
3
+ ENV.fetch('AS_API_KEY', 'API_KEY')
4
+ end
5
+
6
+ def ConfigHelper.get_as_host_identifier
7
+ ENV['AS_ACCOUNT_HOST_KEY'] || ENV['AS_HOST_IDENTIFIER'] || 'ACCOUNT_HOST_KEY'
8
+ end
9
+
10
+ def ConfigHelper.get_as_api_endpoint
11
+ ENV.fetch('AS_API_ENDPOINT', nil)
12
+ end
13
+
14
+ def ConfigHelper.get_client_options(as_api_key, as_host_identifier, as_api_endpoint)
15
+ {
16
+ :api_key => as_api_key,
17
+ :host_identifier => as_host_identifier
18
+ }.tap do |opts|
19
+ opts[:api_endpoint] = as_api_endpoint unless as_api_endpoint.nil?
20
+ end
21
+ end
22
+ end
@@ -3,21 +3,17 @@ require 'rspec'
3
3
  require 'webmock/rspec'
4
4
  require 'awesome_print'
5
5
  require 'swiftype-app-search'
6
+ require 'config_helper'
6
7
 
7
8
  WebMock.allow_net_connect!
8
9
 
9
- RSpec.shared_context "App Search Credentials" do
10
- let(:as_api_key) { ENV.fetch('AS_API_KEY', 'API_KEY') }
10
+ RSpec.shared_context 'App Search Credentials' do
11
+ let(:as_api_key) { ConfigHelper.get_as_api_key }
11
12
  # AS_ACCOUNT_HOST_KEY is deprecated
12
- let(:as_host_identifier) { ENV['AS_ACCOUNT_HOST_KEY'] || ENV['AS_HOST_IDENTIFIER'] || 'ACCOUNT_HOST_KEY' }
13
- let(:as_api_endpoint) { ENV.fetch('AS_API_ENDPOINT', nil) }
13
+ let(:as_host_identifier) { ConfigHelper.get_as_host_identifier }
14
+ let(:as_api_endpoint) { ConfigHelper.get_as_api_endpoint }
14
15
  let(:client_options) do
15
- {
16
- :api_key => as_api_key,
17
- :host_identifier => as_host_identifier
18
- }.tap do |opts|
19
- opts[:api_endpoint] = as_api_endpoint unless as_api_endpoint.nil?
20
- end
16
+ ConfigHelper.get_client_options(as_api_key, as_host_identifier, as_api_endpoint)
21
17
  end
22
18
  end
23
19
 
@@ -26,5 +22,5 @@ RSpec.configure do |config|
26
22
  # order dependency and want to debug it, you can fix the order by providing
27
23
  # the seed, which is printed after each run.
28
24
  # --seed 1234
29
- config.order = "random"
25
+ config.order = 'random'
30
26
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: swiftype-app-search
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.4.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Quin Hoxie
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-10-17 00:00:00.000000000 Z
11
+ date: 2018-10-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: awesome_print
@@ -90,6 +90,7 @@ files:
90
90
  - ".circleci/config.yml"
91
91
  - ".gitignore"
92
92
  - ".rspec"
93
+ - ".rubocop.yml"
93
94
  - ".travis.yml"
94
95
  - Gemfile
95
96
  - LICENSE.txt
@@ -107,6 +108,7 @@ files:
107
108
  - lib/swiftype-app-search/version.rb
108
109
  - script/console
109
110
  - spec/client_spec.rb
111
+ - spec/config_helper.rb
110
112
  - spec/spec_helper.rb
111
113
  - swiftype-app-search.gemspec
112
114
  homepage: https://swiftype.com
@@ -135,4 +137,5 @@ specification_version: 4
135
137
  summary: Official gem for accessing the Swiftype App Search API
136
138
  test_files:
137
139
  - spec/client_spec.rb
140
+ - spec/config_helper.rb
138
141
  - spec/spec_helper.rb