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.
- checksums.yaml +4 -4
- data/.rubocop.yml +1416 -0
- data/README.md +1 -1
- data/lib/swiftype-app-search/exceptions.rb +5 -1
- data/lib/swiftype-app-search/version.rb +1 -1
- data/spec/client_spec.rb +122 -55
- data/spec/config_helper.rb +22 -0
- data/spec/spec_helper.rb +7 -11
- metadata +5 -2
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.
|
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 =
|
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
|
data/spec/client_spec.rb
CHANGED
@@ -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
|
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
|
-
|
86
|
-
|
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
|
-
|
96
|
-
|
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
|
-
|
108
|
-
|
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,
|
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 {
|
193
|
-
let
|
194
|
-
let
|
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
|
-
|
198
|
-
|
199
|
-
|
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 {
|
232
|
+
subject { @static_client.multi_search(@static_engine_name, queries) }
|
205
233
|
|
206
234
|
context 'when options are provided' do
|
207
|
-
let
|
208
|
-
|
209
|
-
|
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
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
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
|
224
|
-
|
225
|
-
|
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
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
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
|
data/spec/spec_helper.rb
CHANGED
@@ -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
|
10
|
-
let(:as_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) {
|
13
|
-
let(:as_api_endpoint) {
|
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 =
|
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.
|
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-
|
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
|