swiftype-app-search 0.3.0 → 0.4.0

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: 7ed5f865b5826a9e1f6ef4159e8666f40854d88507d5e385ade79843be1ec328
4
- data.tar.gz: 8de8289db41e4b425c88890c7e9ec9d2347b6f234654c0813d9f79b51c40601c
3
+ metadata.gz: c0889b18cde354daea10527a1e192cd972e0d7c539fa4bbee73b2683de3b3822
4
+ data.tar.gz: 0b65d19dcf830652d055ead107abdc554dcb28f3f5d74d528d2be5d53cf15d63
5
5
  SHA512:
6
- metadata.gz: 2fd5aafef38257cae51fc924825020cceb127c980d54c26e6011ee28a3b620d8143fa94e56d49de5fd9e646e3509f2242afbc425da220a013e040d6f6e2aa3f8
7
- data.tar.gz: d78bda22152a9e4046582612c136a63bdd3a18daa0d1a305a847ac04a4f90b077a9805f17f7c638807fba3dd58702143b861fe29158a2032ec6a7c5cadc2c3da
6
+ metadata.gz: cfe38cefe4f27e5d3056041b6166ce7779f759b77600d10bf345959dfaa2661f76543d44fbaac028814da267620824a5112334b424c18c6b9ed3c1f9bdd49fe8
7
+ data.tar.gz: 1ceada4a0bbb951a2c4a3885f683a3d5fb148569cdeb386ce9a224d7621d0402a0e33a3e424fada53b017efa9d5c5efc3b2c837a51bca6eff6a411a4a70e5803
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.1.3` in your `Gemfile` and run `bundle install`.
13
+ Or place `gem 'swiftype-app-search', '~> 0.4.0` in your `Gemfile` and run `bundle install`.
14
14
 
15
15
  ## Usage
16
16
 
@@ -42,15 +42,10 @@ document = {
42
42
  :body => 'A wonderful video of a magnificent cat.'
43
43
  }
44
44
 
45
- begin
46
- response = client.index_document(engine_name, document)
47
- puts response
48
- rescue SwiftypeAppSearch::ClientException => e
49
- puts e
50
- end
45
+ client.index_document(engine_name, document)
51
46
  ```
52
47
 
53
- #### Indexing: Creating or Updating Documents
48
+ #### Indexing: Creating or Replacing Documents
54
49
 
55
50
  ```ruby
56
51
  engine_name = 'favorite-videos'
@@ -69,26 +64,37 @@ documents = [
69
64
  }
70
65
  ]
71
66
 
72
- begin
73
- response = client.index_documents(engine_name, documents)
74
- puts response
75
- rescue SwiftypeAppSearch::ClientException => e
76
- puts e
77
- end
67
+ client.index_documents(engine_name, documents)
78
68
  ```
79
69
 
80
- #### Listing Documents
70
+ #### Indexing: Updating Documents (Partial Updates)
71
+
72
+ ```ruby
73
+ engine_name = 'favorite-videos'
74
+ documents = [
75
+ {
76
+ :id => 'INscMGmhmX4',
77
+ :title => 'Updated title'
78
+ }
79
+ ]
80
+
81
+ client.update_documents(engine_name, documents)
82
+ ```
83
+
84
+ #### Retrieving Documents
81
85
 
82
86
  ```ruby
83
87
  engine_name = 'favorite-videos'
84
88
  document_ids = ['INscMGmhmX4', 'JNDFojsd02']
85
89
 
86
- begin
87
- response = client.get_documents(engine_name, document_ids)
88
- puts response
89
- rescue SwiftypeAppSearch::ClientException => e
90
- puts e
91
- end
90
+ client.get_documents(engine_name, document_ids)
91
+ ```
92
+
93
+ #### Listing Documents
94
+ ```ruby
95
+ engine_name = 'favorite-videos'
96
+
97
+ client.list_documents(engine_name)
92
98
  ```
93
99
 
94
100
  #### Destroying Documents
@@ -97,23 +103,13 @@ end
97
103
  engine_name = 'favorite-videos'
98
104
  document_ids = ['INscMGmhmX4', 'JNDFojsd02']
99
105
 
100
- begin
101
- response = client.destroy_documents(engine_name, document_ids)
102
- puts response
103
- rescue SwiftypeAppSearch::ClientException => e
104
- puts e
105
- end
106
+ client.destroy_documents(engine_name, document_ids)
106
107
  ```
107
108
 
108
109
  #### Listing Engines
109
110
 
110
111
  ```ruby
111
- begin
112
- response = client.list_engines
113
- puts response
114
- rescue SwiftypeAppSearch::ClientException => e
115
- puts e
116
- end
112
+ client.list_engines
117
113
  ```
118
114
 
119
115
  #### Retrieving Engines
@@ -121,12 +117,7 @@ end
121
117
  ```ruby
122
118
  engine_name = 'favorite-videos'
123
119
 
124
- begin
125
- response = client.get_engine(engine_name)
126
- puts response
127
- rescue SwiftypeAppSearch::ClientException => e
128
- puts e
129
- end
120
+ client.get_engine(engine_name)
130
121
  ```
131
122
 
132
123
  #### Creating Engines
@@ -134,12 +125,7 @@ end
134
125
  ```ruby
135
126
  engine_name = 'favorite-videos'
136
127
 
137
- begin
138
- response = client.create_engine(engine_name)
139
- puts response
140
- rescue SwiftypeAppSearch::ClientException => e
141
- puts e
142
- end
128
+ client.create_engine(engine_name)
143
129
  ```
144
130
 
145
131
  #### Destroying Engines
@@ -147,12 +133,7 @@ end
147
133
  ```ruby
148
134
  engine_name = 'favorite-videos'
149
135
 
150
- begin
151
- response = client.destroy_engine(engine_name)
152
- puts response
153
- rescue SwiftypeAppSearch::ClientException => e
154
- puts e
155
- end
136
+ client.destroy_engine(engine_name)
156
137
  ```
157
138
 
158
139
  #### Searching
@@ -164,12 +145,23 @@ search_fields = { :title => {} }
164
145
  result_fields = { :title => { :raw => {} } }
165
146
  options = { :search_fields => search_fields, :result_fields => result_fields }
166
147
 
167
- begin
168
- response = client.search(engine_name, query, options)
169
- puts response
170
- rescue SwiftypeAppSearch::ClientException => e
171
- puts e
172
- end
148
+ client.search(engine_name, query, options)
149
+ ```
150
+
151
+ #### Multi-Search
152
+
153
+ ```ruby
154
+ engine_name = 'favorite-videos'
155
+
156
+ queries = [{
157
+ :query => 'cat',
158
+ :options => { :search_fields => { :title => {} }}
159
+ },{
160
+ :query => 'dog',
161
+ :options => { :search_fields => { :body => {} }}
162
+ }]
163
+
164
+ client.multi_search(engine_name, queries)
173
165
  ```
174
166
 
175
167
  ## Running Tests
@@ -5,13 +5,23 @@ module SwiftypeAppSearch
5
5
  class Client
6
6
  module Documents
7
7
 
8
- # Retrieve Documents from the API by IDs for the {App Search API}[https://swiftype.com/documentation/app-search/]
8
+ # Retrieve all Documents from the API for the {App Search API}[https://swiftype.com/documentation/app-search/]
9
9
  #
10
10
  # @param [String] engine_name the unique Engine name
11
- # @param [Array<String>] ids an Array of Document IDs
11
+ # @option options see the {App Search API}[https://swiftype.com/documentation/app-search/] for supported options.
12
12
  #
13
13
  # @return [Array<Hash>] an Array of Documents
14
+ def list_documents(engine_name, options = {})
15
+ params = Utils.symbolize_keys(options)
16
+ request(:get, "engines/#{engine_name}/documents/list", params)
17
+ end
14
18
 
19
+ # Retrieve Documents from the API by IDs for the {App Search API}[https://swiftype.com/documentation/app-search/]
20
+ #
21
+ # @param [String] engine_name the unique Engine name
22
+ # @param [Array<String>] ids an Array of Document IDs
23
+ #
24
+ # @return [Hash] list results
15
25
  def get_documents(engine_name, ids)
16
26
  get("engines/#{engine_name}/documents", ids)
17
27
  end
@@ -46,6 +56,20 @@ module SwiftypeAppSearch
46
56
  post("engines/#{engine_name}/documents", documents)
47
57
  end
48
58
 
59
+ # Update a batch of documents using the {App Search API}[https://swiftype.com/documentation/app-search/].
60
+ #
61
+ # @param [String] engine_name the unique Engine name
62
+ # @param [Array] documents an Array of Document Hashes including valid ids
63
+ #
64
+ # @return [Array<Hash>] an Array of processed Document Status hashes
65
+ #
66
+ # @raise [SwiftypeAppSearch::InvalidDocument] when any documents have processing errors returned from the api
67
+ # @raise [Timeout::Error] when timeout expires waiting for statuses
68
+ def update_documents(engine_name, documents)
69
+ documents.map! { |document| normalize_document(document) }
70
+ patch("engines/#{engine_name}/documents", documents)
71
+ end
72
+
49
73
  # Destroy a batch of documents given a list of IDs
50
74
  #
51
75
  # @param [Array<String>] ids an Array of Document IDs
@@ -11,8 +11,10 @@ module SwiftypeAppSearch
11
11
  get("engines/#{engine_name}")
12
12
  end
13
13
 
14
- def create_engine(engine_name)
15
- post("engines", :name => engine_name)
14
+ def create_engine(engine_name, language = nil)
15
+ params = { :name => engine_name }
16
+ params[:language] = language if language
17
+ post("engines", params)
16
18
  end
17
19
 
18
20
  def destroy_engine(engine_name)
@@ -7,11 +7,30 @@ module SwiftypeAppSearch
7
7
  # @param [String] query the search query
8
8
  # @option options see the {App Search API}[https://swiftype.com/documentation/app-search/] for supported search options.
9
9
  #
10
- # @return [Array<Hash>] an Array of Document destroy result hashes
10
+ # @return [Hash] search results
11
11
  def search(engine_name, query, options = {})
12
12
  params = Utils.symbolize_keys(options).merge(:query => query)
13
13
  request(:post, "engines/#{engine_name}/search", params)
14
14
  end
15
+
16
+ # Run multiple searches for documents on a single request
17
+ #
18
+ # @param [String] engine_name the unique Engine name
19
+ # @param [{query: String, options: Hash}] searches to execute
20
+ # see the {App Search API}[https://swiftype.com/documentation/app-search/] for supported search options.
21
+ #
22
+ # @return [Array<Hash>] an Array of searh sesults
23
+ def multi_search(engine_name, searches)
24
+ params = searches.map do |search|
25
+ search = Utils.symbolize_keys(search)
26
+ query = search[:query]
27
+ options = search[:options] || {}
28
+ Utils.symbolize_keys(options).merge(:query => query)
29
+ end
30
+ request(:post, "engines/#{engine_name}/multi_search", {
31
+ queries: params
32
+ })
33
+ end
15
34
  end
16
35
  end
17
36
  end
@@ -1,3 +1,3 @@
1
1
  module SwiftypeAppSearch
2
- VERSION = '0.3.0'
2
+ VERSION = '0.4.0'
3
3
  end
data/spec/client_spec.rb CHANGED
@@ -98,6 +98,143 @@ describe SwiftypeAppSearch::Client do
98
98
  end
99
99
  end
100
100
  end
101
+
102
+ describe '#update_documents' do
103
+ let(:documents) { [document, second_document] }
104
+ let(:second_document_id) { 'another_id' }
105
+ 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
+ } ] }
110
+
111
+ subject { client.update_documents(engine_name, updates) }
112
+
113
+ before do
114
+ client.index_documents(engine_name, documents)
115
+ end
116
+
117
+ # Note that since indexing a document takes up to a minute,
118
+ # we don't expect this to succeed, so we simply verify that
119
+ # the request responded with the correct 'id', even though
120
+ # the 'errors' object likely contains errors.
121
+ it 'should update existing documents' do
122
+ response = subject
123
+ expect(subject).to match(['id' => second_document_id, 'errors' => anything])
124
+ end
125
+ end
126
+
127
+ describe '#get_documents' do
128
+ let(:documents) { [first_document, second_document] }
129
+ let(:first_document_id) { 'id' }
130
+ let(:first_document) { { 'id' => first_document_id, 'url' => 'https://www.youtube.com/watch?v=v1uyQZNg2vE' } }
131
+ let(:second_document_id) { 'another_id' }
132
+ let(:second_document) { { 'id' => second_document_id, 'url' => 'https://www.youtube.com/watch?v=9T1vfsHYiKY' } }
133
+
134
+ subject { client.get_documents(engine_name, [first_document_id, second_document_id]) }
135
+
136
+ before do
137
+ client.index_documents(engine_name, documents)
138
+ end
139
+
140
+ it 'will return documents by id' do
141
+ response = subject
142
+ expect(response.size).to eq(2)
143
+ expect(response[0]['id']).to eq(first_document_id)
144
+ expect(response[1]['id']).to eq(second_document_id)
145
+ end
146
+ end
147
+
148
+ describe '#list_documents' do
149
+ let(:documents) { [first_document, second_document] }
150
+ let(:first_document_id) { 'id' }
151
+ let(:first_document) { { 'id' => first_document_id, 'url' => 'https://www.youtube.com/watch?v=v1uyQZNg2vE' } }
152
+ let(:second_document_id) { 'another_id' }
153
+ let(:second_document) { { 'id' => second_document_id, 'url' => 'https://www.youtube.com/watch?v=9T1vfsHYiKY' } }
154
+
155
+ before do
156
+ client.index_documents(engine_name, documents)
157
+ end
158
+
159
+ context 'when no options are specified' do
160
+ it 'will return all documents' do
161
+ response = client.list_documents(engine_name)
162
+ expect(response['results'].size).to eq(2)
163
+ expect(response['results'][0]['id']).to eq(first_document_id)
164
+ expect(response['results'][1]['id']).to eq(second_document_id)
165
+ end
166
+ end
167
+
168
+ context 'when options are specified' do
169
+ it 'will return all documents' do
170
+ response = client.list_documents(engine_name, {page: { size: 1, current: 2}})
171
+ expect(response['results'].size).to eq(1)
172
+ expect(response['results'][0]['id']).to eq(second_document_id)
173
+ end
174
+ end
175
+ end
176
+ end
177
+
178
+ 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
+ describe '#search' do
192
+ subject { client.search(engine_name, query, options) }
193
+ let (:query) { '' }
194
+ let (:options) { { 'page' => { 'size' => 1 } } }
195
+
196
+ it 'should execute a search query' do
197
+ response = subject
198
+ expect(response).to have_key('meta')
199
+ expect(response).to have_key('results')
200
+ end
201
+ end
202
+
203
+ describe '#multi_search' do
204
+ subject { client.multi_search(engine_name, queries) }
205
+
206
+ context 'when options are provided' do
207
+ let (:queries) { [
208
+ {'query': 'foo', 'options' => { 'page' => { 'size' => 1 } }},
209
+ {'query': 'bar', 'options' => { 'page' => { 'size' => 1 } }}
210
+ ] }
211
+
212
+ it 'should execute a multi search query' do
213
+ 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')
219
+ end
220
+ end
221
+
222
+ context 'when options are omitted' do
223
+ let (:queries) { [
224
+ {'query': 'foo' },
225
+ {'query': 'bar' }
226
+ ] }
227
+
228
+ it 'should execute a multi search query' do
229
+ 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')
235
+ end
236
+ end
237
+ end
101
238
  end
102
239
 
103
240
  context 'Engines' do
@@ -112,6 +249,12 @@ describe SwiftypeAppSearch::Client do
112
249
  expect { client.get_engine(engine_name) }.to_not raise_error
113
250
  end
114
251
 
252
+ it 'should accept an optional language parameter' do
253
+ expect { client.get_engine(engine_name) }.to raise_error(SwiftypeAppSearch::NonExistentRecord)
254
+ client.create_engine(engine_name, 'da')
255
+ expect(client.get_engine(engine_name)).to match('name' => anything, 'type' => anything, 'language' => 'da')
256
+ end
257
+
115
258
  it 'should return an engine object' do
116
259
  engine = client.create_engine(engine_name)
117
260
  expect(engine).to be_kind_of(Hash)
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.3.0
4
+ version: 0.4.0
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-07-12 00:00:00.000000000 Z
11
+ date: 2018-10-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: awesome_print