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