swiftype-app-search 0.4.0 → 0.4.1

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.
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