meilisearch 0.15.4 → 0.17.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 03f23776fd7b1baeabbfcc33fcd848f8bd89f56655579756d9e2c06492f8d824
4
- data.tar.gz: d5137b74a7def336e41e746d56f714847be1f73185c5f05abf70a03310cc79b4
3
+ metadata.gz: d989f446194c8260cc87880abfaaf641d0e4b88ae80300d7f9d99fd4c6edfd2e
4
+ data.tar.gz: cbec6b1faeab1d84990b7b1390eb386e536bbaa2442231593d1377b5a5ba0da4
5
5
  SHA512:
6
- metadata.gz: c2c1fee375d80f6e0c372438b3fbb4c76b4c504f0c7ddf1d12d810e89f93f8173e838b1d6d8cf1d57ba02f75277f784660379c8961ccb47884eb2e37d7a43f06
7
- data.tar.gz: ab566b980a0ab15a5ffef99fb47520f667783c098e3ea81fa35784a12d1806846b18a80f42116f0605e2770655a62f35b97e8881983b08ff865de28fcde89c7a
6
+ metadata.gz: 328b4fcec0d6ca099c34ee40340a5a191cec576cbef198a4b0a18fd0afaa1c77708146531204347e67a0037599a35b7caa514940674f28e5a8b06ecaba7ba55c
7
+ data.tar.gz: db01b2e587efc423138437505840b73879d26a0a5d340eb3f1ea56753b8e2f7eaba6f13b22e1a464c8bfec9728b1af42e0c164a735e624844a1a81a99504bd5f
@@ -6,15 +6,22 @@ module MeiliSearch
6
6
  class Client < HTTPRequest
7
7
  ### INDEXES
8
8
 
9
+ def raw_indexes
10
+ http_get('/indexes')
11
+ end
12
+
9
13
  def indexes
10
- http_get '/indexes'
14
+ raw_indexes.map do |index_hash|
15
+ index_object(index_hash['uid'], index_hash['primaryKey'])
16
+ end
11
17
  end
12
18
 
13
19
  # Usage:
14
20
  # client.create_index('indexUID')
15
21
  # client.create_index('indexUID', primaryKey: 'id')
16
22
  def create_index(index_uid, options = {})
17
- body = options.merge(uid: index_uid)
23
+ body = Utils.transform_attributes(options.merge(uid: index_uid))
24
+
18
25
  index_hash = http_post '/indexes', body
19
26
  index_object(index_hash['uid'], index_hash['primaryKey'])
20
27
  end
@@ -34,6 +41,17 @@ module MeiliSearch
34
41
  index_object(index_uid).delete
35
42
  end
36
43
 
44
+ # Usage:
45
+ # client.delete_index_if_exists('indexUID')
46
+ def delete_index_if_exists(index_uid)
47
+ index_object(index_uid).delete
48
+ true
49
+ rescue ApiError => e
50
+ raise e if e.code != 'index_not_found'
51
+
52
+ false
53
+ end
54
+
37
55
  # Usage:
38
56
  # client.index('indexUID')
39
57
  def index(index_uid)
@@ -44,6 +62,10 @@ module MeiliSearch
44
62
  index_object(index_uid).fetch_info
45
63
  end
46
64
 
65
+ def fetch_raw_index(index_uid)
66
+ index_object(index_uid).fetch_raw_info
67
+ end
68
+
47
69
  ### KEYS
48
70
 
49
71
  def keys
@@ -29,10 +29,15 @@ module MeiliSearch
29
29
 
30
30
  def get_meilisearch_error_info(http_body)
31
31
  @http_body = JSON.parse(http_body)
32
- @ms_code = @http_body['errorCode']
32
+ @ms_code = @http_body['code']
33
33
  @ms_message = @http_body['message']
34
- @ms_type = @http_body['errorType']
35
- @ms_link = @http_body['errorLink']
34
+ @ms_type = @http_body['type']
35
+ @ms_link = @http_body['link']
36
+ rescue JSON::ParserError
37
+ # We might receive a JSON::ParserError when, for example, MeiliSearch is running behind
38
+ # some proxy (ELB or Nginx, for example), and the request timeouts, returning us
39
+ # a raw HTML body instead of a JSON as we were expecting
40
+ @ms_message = "The server has not returned a valid JSON HTTP body: #{http_body}"
36
41
  end
37
42
 
38
43
  def details
@@ -17,13 +17,17 @@ module MeiliSearch
17
17
  'Content-Type' => 'application/json',
18
18
  'X-Meili-API-Key' => api_key
19
19
  }.compact
20
+ @headers_no_body = {
21
+ 'X-Meili-API-Key' => api_key
22
+ }.compact
20
23
  end
21
24
 
22
25
  def http_get(relative_path = '', query_params = {})
23
26
  send_request(
24
27
  proc { |path, config| self.class.get(path, config) },
25
28
  relative_path,
26
- query_params
29
+ query_params: query_params,
30
+ headers: @headers_no_body
27
31
  )
28
32
  end
29
33
 
@@ -31,8 +35,9 @@ module MeiliSearch
31
35
  send_request(
32
36
  proc { |path, config| self.class.post(path, config) },
33
37
  relative_path,
34
- query_params,
35
- body
38
+ query_params: query_params,
39
+ body: body,
40
+ headers: @headers
36
41
  )
37
42
  end
38
43
 
@@ -40,22 +45,24 @@ module MeiliSearch
40
45
  send_request(
41
46
  proc { |path, config| self.class.put(path, config) },
42
47
  relative_path,
43
- query_params,
44
- body
48
+ query_params: query_params,
49
+ body: body,
50
+ headers: @headers
45
51
  )
46
52
  end
47
53
 
48
54
  def http_delete(relative_path = '')
49
55
  send_request(
50
56
  proc { |path, config| self.class.delete(path, config) },
51
- relative_path
57
+ relative_path,
58
+ headers: @headers_no_body
52
59
  )
53
60
  end
54
61
 
55
62
  private
56
63
 
57
- def send_request(http_method, relative_path, query_params = nil, body = nil)
58
- config = http_config(query_params, body)
64
+ def send_request(http_method, relative_path, query_params: nil, body: nil, headers: nil)
65
+ config = http_config(query_params, body, headers)
59
66
  begin
60
67
  response = http_method.call(@base_url + relative_path, config)
61
68
  rescue Errno::ECONNREFUSED => e
@@ -64,12 +71,11 @@ module MeiliSearch
64
71
  validate(response)
65
72
  end
66
73
 
67
- def http_config(query_params, body)
68
- body = body.to_json
74
+ def http_config(query_params, body, headers)
69
75
  {
70
- headers: @headers,
76
+ headers: headers,
71
77
  query: query_params,
72
- body: body,
78
+ body: body.to_json,
73
79
  timeout: @options[:timeout] || 1,
74
80
  max_retries: @options[:max_retries] || 0
75
81
  }.compact
@@ -5,7 +5,7 @@ require 'timeout'
5
5
 
6
6
  module MeiliSearch
7
7
  class Index < HTTPRequest
8
- attr_reader :uid, :primary_key
8
+ attr_reader :uid, :primary_key, :created_at, :updated_at
9
9
 
10
10
  def initialize(index_uid, url, api_key = nil, primary_key = nil, options = {})
11
11
  @uid = index_uid
@@ -14,27 +14,47 @@ module MeiliSearch
14
14
  end
15
15
 
16
16
  def fetch_info
17
- index_hash = http_get "/indexes/#{@uid}"
18
- @primary_key = index_hash['primaryKey']
17
+ index_hash = http_get indexes_path(id: @uid)
18
+ set_base_properties index_hash
19
19
  self
20
20
  end
21
21
 
22
+ def fetch_primary_key
23
+ fetch_info.primary_key
24
+ end
25
+ alias get_primary_key fetch_primary_key
26
+
27
+ def fetch_raw_info
28
+ index_hash = http_get indexes_path(id: @uid)
29
+ set_base_properties index_hash
30
+ index_hash
31
+ end
32
+
22
33
  def update(body)
23
- index_hash = http_put "/indexes/#{@uid}", body
24
- @primary_key = index_hash['primaryKey']
34
+ index_hash = http_put indexes_path(id: @uid), Utils.transform_attributes(body)
35
+ set_base_properties index_hash
36
+
25
37
  self
26
38
  end
39
+
27
40
  alias update_index update
28
41
 
29
42
  def delete
30
- http_delete "/indexes/#{@uid}"
43
+ http_delete indexes_path(id: @uid)
31
44
  end
32
45
  alias delete_index delete
33
46
 
34
- def fetch_primary_key
35
- fetch_info.primary_key
47
+ def indexes_path(id: nil)
48
+ "/indexes/#{id}"
36
49
  end
37
- alias get_primary_key fetch_primary_key
50
+ private :indexes_path
51
+
52
+ def set_base_properties(index_hash)
53
+ @primary_key = index_hash['primaryKey']
54
+ @created_at = Time.parse(index_hash['createdAt'])
55
+ @updated_at = Time.parse(index_hash['updatedAt'])
56
+ end
57
+ private :set_base_properties
38
58
 
39
59
  ### DOCUMENTS
40
60
 
@@ -46,7 +66,7 @@ module MeiliSearch
46
66
  alias get_one_document document
47
67
 
48
68
  def documents(options = {})
49
- http_get "/indexes/#{@uid}/documents", options
69
+ http_get "/indexes/#{@uid}/documents", Utils.transform_attributes(options)
50
70
  end
51
71
  alias get_documents documents
52
72
 
@@ -76,6 +96,40 @@ module MeiliSearch
76
96
  end
77
97
  alias add_or_update_documents! update_documents!
78
98
 
99
+ def add_documents_in_batches(documents, batch_size = 1000, primary_key = nil)
100
+ update_ids = []
101
+ documents.each_slice(batch_size) do |batch|
102
+ update_ids.append(add_documents(batch, primary_key))
103
+ end
104
+ update_ids
105
+ end
106
+
107
+ def add_documents_in_batches!(documents, batch_size = 1000, primary_key = nil)
108
+ update_ids = add_documents_in_batches(documents, batch_size, primary_key)
109
+ responses = []
110
+ update_ids.each do |update_object|
111
+ responses.append(wait_for_pending_update(update_object['updateId']))
112
+ end
113
+ responses
114
+ end
115
+
116
+ def update_documents_in_batches(documents, batch_size = 1000, primary_key = nil)
117
+ update_ids = []
118
+ documents.each_slice(batch_size) do |batch|
119
+ update_ids.append(update_documents(batch, primary_key))
120
+ end
121
+ update_ids
122
+ end
123
+
124
+ def update_documents_in_batches!(documents, batch_size = 1000, primary_key = nil)
125
+ update_ids = update_documents_in_batches(documents, batch_size, primary_key)
126
+ responses = []
127
+ update_ids.each do |update_object|
128
+ responses.append(wait_for_pending_update(update_object['updateId']))
129
+ end
130
+ responses
131
+ end
132
+
79
133
  def delete_documents(documents_ids)
80
134
  if documents_ids.is_a?(Array)
81
135
  http_post "/indexes/#{@uid}/documents/delete-batch", documents_ids
@@ -115,8 +169,9 @@ module MeiliSearch
115
169
  ### SEARCH
116
170
 
117
171
  def search(query, options = {})
118
- parsed_options = options.compact
119
- http_post "/indexes/#{@uid}/search", { q: query.to_s }.merge(parsed_options)
172
+ parsed_options = Utils.transform_attributes({ q: query.to_s }.merge(options.compact))
173
+
174
+ http_post "/indexes/#{@uid}/search", parsed_options
120
175
  end
121
176
 
122
177
  ### UPDATES
@@ -129,11 +184,15 @@ module MeiliSearch
129
184
  http_get "/indexes/#{@uid}/updates"
130
185
  end
131
186
 
187
+ def achieved_upate?(update)
188
+ update['status'] != 'enqueued' && update['status'] != 'processing'
189
+ end
190
+
132
191
  def wait_for_pending_update(update_id, timeout_in_ms = 5000, interval_in_ms = 50)
133
192
  Timeout.timeout(timeout_in_ms.to_f / 1000) do
134
193
  loop do
135
194
  get_update = get_update_status(update_id)
136
- return get_update if get_update['status'] != 'enqueued'
195
+ return get_update if achieved_upate?(get_update)
137
196
 
138
197
  sleep interval_in_ms.to_f / 1000
139
198
  end
@@ -160,8 +219,8 @@ module MeiliSearch
160
219
  stats['lastUpdate']
161
220
  end
162
221
 
163
- def fields_distribution
164
- stats['fieldsDistribution']
222
+ def field_distribution
223
+ stats['fieldDistribution']
165
224
  end
166
225
 
167
226
  ### SETTINGS - GENERAL
@@ -172,7 +231,7 @@ module MeiliSearch
172
231
  alias get_settings settings
173
232
 
174
233
  def update_settings(settings)
175
- http_post "/indexes/#{@uid}/settings", settings
234
+ http_post "/indexes/#{@uid}/settings", Utils.transform_attributes(settings)
176
235
  end
177
236
  alias settings= update_settings
178
237
 
@@ -220,7 +279,7 @@ module MeiliSearch
220
279
  alias get_stop_words stop_words
221
280
 
222
281
  def update_stop_words(stop_words)
223
- body = stop_words.is_a?(Array) ? stop_words : [stop_words]
282
+ body = stop_words.nil? || stop_words.is_a?(Array) ? stop_words : [stop_words]
224
283
  http_post "/indexes/#{@uid}/settings/stop-words", body
225
284
  end
226
285
  alias stop_words= update_stop_words
@@ -277,20 +336,36 @@ module MeiliSearch
277
336
  http_delete "/indexes/#{@uid}/settings/displayed-attributes"
278
337
  end
279
338
 
280
- ### SETTINGS - ATTRIBUTES FOR FACETING
339
+ ### SETTINGS - FILTERABLE ATTRIBUTES
340
+
341
+ def filterable_attributes
342
+ http_get "/indexes/#{@uid}/settings/filterable-attributes"
343
+ end
344
+ alias get_filterable_attributes filterable_attributes
345
+
346
+ def update_filterable_attributes(filterable_attributes)
347
+ http_post "/indexes/#{@uid}/settings/filterable-attributes", filterable_attributes
348
+ end
349
+ alias filterable_attributes= update_filterable_attributes
350
+
351
+ def reset_filterable_attributes
352
+ http_delete "/indexes/#{@uid}/settings/filterable-attributes"
353
+ end
354
+
355
+ ### SETTINGS - SORTABLE ATTRIBUTES
281
356
 
282
- def attributes_for_faceting
283
- http_get "/indexes/#{@uid}/settings/attributes-for-faceting"
357
+ def sortable_attributes
358
+ http_get "/indexes/#{@uid}/settings/sortable-attributes"
284
359
  end
285
- alias get_attributes_for_faceting attributes_for_faceting
360
+ alias get_sortable_attributes sortable_attributes
286
361
 
287
- def update_attributes_for_faceting(attributes_for_faceting)
288
- http_post "/indexes/#{@uid}/settings/attributes-for-faceting", attributes_for_faceting
362
+ def update_sortable_attributes(sortable_attributes)
363
+ http_post "/indexes/#{@uid}/settings/sortable-attributes", sortable_attributes
289
364
  end
290
- alias attributes_for_faceting= update_attributes_for_faceting
365
+ alias sortable_attributes= update_sortable_attributes
291
366
 
292
- def reset_attributes_for_faceting
293
- http_delete "/indexes/#{@uid}/settings/attributes-for-faceting"
367
+ def reset_sortable_attributes
368
+ http_delete "/indexes/#{@uid}/settings/sortable-attributes"
294
369
  end
295
370
  end
296
371
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module MeiliSearch
4
- VERSION = '0.15.4'
4
+ VERSION = '0.17.1'
5
5
  end
data/lib/meilisearch.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'meilisearch/version'
4
+ require 'meilisearch/utils'
4
5
  require 'meilisearch/client'
5
6
  require 'meilisearch/index'
6
7
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: meilisearch
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.15.4
4
+ version: 0.17.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Meili
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-06-11 00:00:00.000000000 Z
11
+ date: 2021-11-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: httparty
@@ -19,7 +19,7 @@ dependencies:
19
19
  version: 0.17.1
20
20
  - - "<"
21
21
  - !ruby/object:Gem::Version
22
- version: 0.19.0
22
+ version: 0.21.0
23
23
  type: :runtime
24
24
  prerelease: false
25
25
  version_requirements: !ruby/object:Gem::Requirement
@@ -29,7 +29,7 @@ dependencies:
29
29
  version: 0.17.1
30
30
  - - "<"
31
31
  - !ruby/object:Gem::Version
32
- version: 0.19.0
32
+ version: 0.21.0
33
33
  description: An easy-to-use ruby client for Meilisearch API. See https://github.com/meilisearch/MeiliSearch
34
34
  email: bonjour@meilisearch.com
35
35
  executables: []