meilisearch 0.17.1 → 0.18.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d989f446194c8260cc87880abfaaf641d0e4b88ae80300d7f9d99fd4c6edfd2e
4
- data.tar.gz: cbec6b1faeab1d84990b7b1390eb386e536bbaa2442231593d1377b5a5ba0da4
3
+ metadata.gz: 6309d55fa663d9fd8126c1bbf290313ddab29e0e8e72ee690b0abe49887d6097
4
+ data.tar.gz: 2386993d60f7fa52c38e10d58e191a0f0797a3672de31a36b5c1013440285584
5
5
  SHA512:
6
- metadata.gz: 328b4fcec0d6ca099c34ee40340a5a191cec576cbef198a4b0a18fd0afaa1c77708146531204347e67a0037599a35b7caa514940674f28e5a8b06ecaba7ba55c
7
- data.tar.gz: db01b2e587efc423138437505840b73879d26a0a5d340eb3f1ea56753b8e2f7eaba6f13b22e1a464c8bfec9728b1af42e0c164a735e624844a1a81a99504bd5f
6
+ metadata.gz: d50aa62ffebcd4d707fc55471e8738d9dd53433c77af3f1bb08e3681395ee19eb35513bc14a1e769bf223a9e16622805dc1010d06b4b84c2252237d1eb5a8b97
7
+ data.tar.gz: fff2a910e52b6c137037c3b011ddba3b0d11d28fd2427c1b4d45e925e2b28711c4e0fca269309de9b97dd99df980e4ed067b322c7148c0fde68a14ce4fe7d388
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2019-2021 Meili
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,222 @@
1
+ <p align="center">
2
+ <img src="https://raw.githubusercontent.com/meilisearch/integration-guides/main/assets/logos/meilisearch_ruby.svg" alt="Meilisearch-Ruby" width="200" height="200" />
3
+ </p>
4
+
5
+ <h1 align="center">Meilisearch Ruby</h1>
6
+
7
+ <h4 align="center">
8
+ <a href="https://github.com/meilisearch/meilisearch">Meilisearch</a> |
9
+ <a href="https://docs.meilisearch.com">Documentation</a> |
10
+ <a href="https://slack.meilisearch.com">Slack</a> |
11
+ <a href="https://roadmap.meilisearch.com/tabs/1-under-consideration">Roadmap</a> |
12
+ <a href="https://www.meilisearch.com">Website</a> |
13
+ <a href="https://docs.meilisearch.com/faq">FAQ</a>
14
+ </h4>
15
+
16
+ <p align="center">
17
+ <a href="https://badge.fury.io/rb/meilisearch"><img src="https://badge.fury.io/rb/meilisearch.svg" alt="Latest Stable Version"></a>
18
+ <a href="https://github.com/meilisearch/meilisearch-ruby/actions"><img src="https://github.com/meilisearch/meilisearch-ruby/workflows/Tests/badge.svg" alt="Test"></a>
19
+ <a href="https://github.com/meilisearch/meilisearch-ruby/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-MIT-informational" alt="License"></a>
20
+ <a href="https://ms-bors.herokuapp.com/repositories/6"><img src="https://bors.tech/images/badge_small.svg" alt="Bors enabled"></a>
21
+ </p>
22
+
23
+ <p align="center">⚡ The Meilisearch API client written for Ruby 💎</p>
24
+
25
+ **Meilisearch Ruby** is the Meilisearch API client for Ruby developers.
26
+
27
+ **Meilisearch** is an open-source search engine. [Discover what Meilisearch is!](https://github.com/meilisearch/meilisearch)
28
+
29
+ ## Table of Contents <!-- omit in toc -->
30
+
31
+ - [📖 Documentation](#-documentation)
32
+ - [🔧 Installation](#-installation)
33
+ - [🚀 Getting Started](#-getting-started)
34
+ - [🤖 Compatibility with Meilisearch](#-compatibility-with-meilisearch)
35
+ - [💡 Learn More](#-learn-more)
36
+ - [⚙️ Development Workflow and Contributing](#️-development-workflow-and-contributing)
37
+
38
+ ## 📖 Documentation
39
+
40
+ See our [Documentation](https://docs.meilisearch.com/learn/tutorials/getting_started.html) or our [API References](https://docs.meilisearch.com/reference/api/).
41
+
42
+ ## 🔧 Installation
43
+
44
+ This package requires Ruby version 2.6.0 or later.
45
+
46
+ With `gem` in command line:
47
+ ```bash
48
+ gem install meilisearch
49
+ ```
50
+
51
+ In your `Gemfile` with [bundler](https://bundler.io/):
52
+ ```ruby
53
+ source 'https://rubygems.org'
54
+
55
+ gem 'meilisearch'
56
+ ```
57
+
58
+ ### Run Meilisearch <!-- omit in toc -->
59
+
60
+ There are many easy ways to [download and run a Meilisearch instance](https://docs.meilisearch.com/reference/features/installation.html#download-and-launch).
61
+
62
+ For example, using the `curl` command in your [Terminal](https://itconnect.uw.edu/learn/workshops/online-tutorials/web-publishing/what-is-a-terminal/):
63
+
64
+ ```sh
65
+ #Install Meilisearch
66
+ curl -L https://install.meilisearch.com | sh
67
+
68
+ # Launch Meilisearch
69
+ ./meilisearch --master-key=masterKey
70
+ ```
71
+
72
+ NB: you can also download Meilisearch from **Homebrew** or **APT** or even run it using **Docker**.
73
+
74
+ ## 🚀 Getting Started
75
+
76
+ #### Add documents <!-- omit in toc -->
77
+
78
+ ```ruby
79
+ require 'meilisearch'
80
+
81
+ client = MeiliSearch::Client.new('http://127.0.0.1:7700', 'masterKey')
82
+
83
+ # An index is where the documents are stored.
84
+ index = client.index('movies')
85
+
86
+ documents = [
87
+ { id: 1, title: 'Carol', genres: ['Romance', 'Drama'] },
88
+ { id: 2, title: 'Wonder Woman', genres: ['Action', 'Adventure'] },
89
+ { id: 3, title: 'Life of Pi', genres: ['Adventure', 'Drama'] },
90
+ { id: 4, title: 'Mad Max: Fury Road', genres: ['Adventure', 'Science Fiction'] },
91
+ { id: 5, title: 'Moana', genres: ['Fantasy', 'Action']},
92
+ { id: 6, title: 'Philadelphia', genres: ['Drama'] },
93
+ ]
94
+ # If the index 'movies' does not exist, Meilisearch creates it when you first add the documents.
95
+ index.add_documents(documents) # => { "uid": 0 }
96
+ ```
97
+
98
+ With the `uid`, you can check the status (`enqueued`, `processing`, `succeeded` or `failed`) of your documents addition using the [task](https://docs.meilisearch.com/reference/api/tasks.html#get-task).
99
+
100
+ 💡 To customize the `Client`, for example, increasing the default timeout, please check out [this section](https://github.com/meilisearch/meilisearch-ruby/wiki/Client-Options) of the Wiki.
101
+
102
+ #### Basic Search <!-- omit in toc -->
103
+
104
+ ``` ruby
105
+ # Meilisearch is typo-tolerant:
106
+ puts index.search('carlo')
107
+ ```
108
+ Output:
109
+
110
+ ```ruby
111
+ {
112
+ "hits" => [{
113
+ "id" => 1,
114
+ "title" => "Carol"
115
+ }],
116
+ "offset" => 0,
117
+ "limit" => 20,
118
+ "processingTimeMs" => 1,
119
+ "query" => "carlo"
120
+ }
121
+ ```
122
+
123
+ #### Custom search <!-- omit in toc -->
124
+
125
+ All the supported options are described in the [search parameters](https://docs.meilisearch.com/reference/features/search_parameters.html) section of the documentation.
126
+
127
+ ```ruby
128
+ index.search(
129
+ 'wonder',
130
+ attributes_to_highlight: ['*']
131
+ )
132
+ ```
133
+
134
+ JSON output:
135
+
136
+ ```json
137
+ {
138
+ "hits": [
139
+ {
140
+ "id": 2,
141
+ "title": "Wonder Woman",
142
+ "_formatted": {
143
+ "id": 2,
144
+ "title": "<em>Wonder</em> Woman"
145
+ }
146
+ }
147
+ ],
148
+ "offset": 0,
149
+ "limit": 20,
150
+ "processingTimeMs": 0,
151
+ "query": "wonder"
152
+ }
153
+ ```
154
+
155
+ #### Custom Search With Filters <!-- omit in toc -->
156
+
157
+ If you want to enable filtering, you must add your attributes to the `filterableAttributes` index setting.
158
+
159
+ ```ruby
160
+ index.update_filterable_attributes([
161
+ 'id',
162
+ 'genres'
163
+ ])
164
+ ```
165
+
166
+ You only need to perform this operation once.
167
+
168
+ Note that Meilisearch will rebuild your index whenever you update `filterableAttributes`. Depending on the size of your dataset, this might take time. You can track the process using the [tasks](https://docs.meilisearch.com/reference/api/tasks.html#get-task)).
169
+
170
+ Then, you can perform the search:
171
+
172
+ ```ruby
173
+ index.search('wonder', { filter: ['id > 1 AND genres = Action'] })
174
+ ```
175
+
176
+ JSON output:
177
+
178
+ ```json
179
+ {
180
+ "hits": [
181
+ {
182
+ "id": 2,
183
+ "title": "Wonder Woman",
184
+ "genres": [
185
+ "Action",
186
+ "Adventure"
187
+ ]
188
+ }
189
+ ],
190
+ "nbHits": 1,
191
+ "exhaustiveNbHits": false,
192
+ "query": "wonder",
193
+ "limit": 20,
194
+ "offset": 0,
195
+ "processingTimeMs": 0
196
+ }
197
+ ```
198
+
199
+ ## 🤖 Compatibility with Meilisearch
200
+
201
+ This package only guarantees the compatibility with the [version v0.25.0 of Meilisearch](https://github.com/meilisearch/meilisearch/releases/tag/v0.25.0).
202
+
203
+ ## 💡 Learn More
204
+
205
+ The following sections may interest you:
206
+
207
+ - **Manipulate documents**: see the [API references](https://docs.meilisearch.com/reference/api/documents.html) or read more about [documents](https://docs.meilisearch.com/learn/core_concepts/documents.html).
208
+ - **Search**: see the [API references](https://docs.meilisearch.com/reference/api/search.html) or follow our guide on [search parameters](https://docs.meilisearch.com/reference/features/search_parameters.html).
209
+ - **Manage the indexes**: see the [API references](https://docs.meilisearch.com/reference/api/indexes.html) or read more about [indexes](https://docs.meilisearch.com/learn/core_concepts/indexes.html).
210
+ - **Configure the index settings**: see the [API references](https://docs.meilisearch.com/reference/api/settings.html) or follow our guide on [settings parameters](https://docs.meilisearch.com/reference/features/settings.html).
211
+
212
+ 📖 Also, check out the [Wiki](https://github.com/meilisearch/meilisearch-ruby/wiki) of this repository to know what this SDK provdes!
213
+
214
+ ## ⚙️ Development Workflow and Contributing
215
+
216
+ Any new contribution is more than welcome in this project!
217
+
218
+ If you want to know more about the development workflow or want to contribute, please visit our [contributing guidelines](/CONTRIBUTING.md) for detailed instructions!
219
+
220
+ <hr>
221
+
222
+ **Meilisearch** provides and maintains many **SDKs and Integration tools** like this one. We want to provide everyone with an **amazing search experience for any kind of project**. If you want to contribute, make suggestions, or just know what's going on right now, visit us in the [integration-guides](https://github.com/meilisearch/integration-guides) repository.
@@ -22,36 +22,20 @@ module MeiliSearch
22
22
  def create_index(index_uid, options = {})
23
23
  body = Utils.transform_attributes(options.merge(uid: index_uid))
24
24
 
25
- index_hash = http_post '/indexes', body
26
- index_object(index_hash['uid'], index_hash['primaryKey'])
25
+ http_post '/indexes', body
27
26
  end
28
27
 
29
- def get_or_create_index(index_uid, options = {})
30
- begin
31
- index_instance = fetch_index(index_uid)
32
- rescue ApiError => e
33
- raise e unless e.code == 'index_not_found'
34
-
35
- index_instance = create_index(index_uid, options)
36
- end
37
- index_instance
28
+ # Synchronous version of create_index.
29
+ # Waits for the task to be achieved, be careful when using it.
30
+ def create_index!(index_uid, options = {})
31
+ task = create_index(index_uid, options)
32
+ wait_for_task(task['uid'])
38
33
  end
39
34
 
40
35
  def delete_index(index_uid)
41
36
  index_object(index_uid).delete
42
37
  end
43
38
 
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
-
55
39
  # Usage:
56
40
  # client.index('indexUID')
57
41
  def index(index_uid)
@@ -71,7 +55,26 @@ module MeiliSearch
71
55
  def keys
72
56
  http_get '/keys'
73
57
  end
74
- alias get_keys keys
58
+
59
+ def key(key_uid)
60
+ http_get "/keys/#{key_uid}"
61
+ end
62
+
63
+ def create_key(key_options)
64
+ body = Utils.transform_attributes(key_options)
65
+
66
+ http_post '/keys', body
67
+ end
68
+
69
+ def update_key(key_uid, key_options)
70
+ body = Utils.transform_attributes(key_options)
71
+
72
+ http_patch "/keys/#{key_uid}", body
73
+ end
74
+
75
+ def delete_key(key_uid)
76
+ http_delete "/keys/#{key_uid}"
77
+ end
75
78
 
76
79
  ### HEALTH
77
80
 
@@ -107,10 +110,28 @@ module MeiliSearch
107
110
  end
108
111
  alias get_dump_status dump_status
109
112
 
113
+ ### TASKS
114
+
115
+ def tasks
116
+ task_endpoint.task_list
117
+ end
118
+
119
+ def task(task_uid)
120
+ task_endpoint.task(task_uid)
121
+ end
122
+
123
+ def wait_for_task(task_uid, timeout_in_ms = 5000, interval_in_ms = 50)
124
+ task_endpoint.wait_for_task(task_uid, timeout_in_ms, interval_in_ms)
125
+ end
126
+
110
127
  private
111
128
 
112
129
  def index_object(uid, primary_key = nil)
113
130
  Index.new(uid, @base_url, @api_key, primary_key, @options)
114
131
  end
132
+
133
+ def task_endpoint
134
+ @task_endpoint ||= Task.new(@base_url, @api_key, @options)
135
+ end
115
136
  end
116
137
  end
@@ -7,37 +7,43 @@ module MeiliSearch
7
7
  class HTTPRequest
8
8
  include HTTParty
9
9
 
10
- attr_reader :options
10
+ attr_reader :options, :headers
11
+
12
+ DEFAULT_OPTIONS = {
13
+ timeout: 1,
14
+ max_retries: 0,
15
+ convert_body?: true
16
+ }.freeze
11
17
 
12
18
  def initialize(url, api_key = nil, options = {})
13
19
  @base_url = url
14
20
  @api_key = api_key
15
- @options = options
16
- @headers = {
17
- 'Content-Type' => 'application/json',
18
- 'X-Meili-API-Key' => api_key
19
- }.compact
20
- @headers_no_body = {
21
- 'X-Meili-API-Key' => api_key
22
- }.compact
21
+ @options = DEFAULT_OPTIONS.merge(options)
22
+ @headers = build_default_options_headers
23
23
  end
24
24
 
25
25
  def http_get(relative_path = '', query_params = {})
26
26
  send_request(
27
27
  proc { |path, config| self.class.get(path, config) },
28
28
  relative_path,
29
- query_params: query_params,
30
- headers: @headers_no_body
29
+ config: {
30
+ query_params: query_params,
31
+ headers: remove_headers(@headers.dup, 'Content-Type'),
32
+ options: @options
33
+ }
31
34
  )
32
35
  end
33
36
 
34
- def http_post(relative_path = '', body = nil, query_params = nil)
37
+ def http_post(relative_path = '', body = nil, query_params = nil, options = {})
35
38
  send_request(
36
39
  proc { |path, config| self.class.post(path, config) },
37
40
  relative_path,
38
- query_params: query_params,
39
- body: body,
40
- headers: @headers
41
+ config: {
42
+ query_params: query_params,
43
+ body: body,
44
+ headers: @headers.dup.merge(options[:headers] || {}),
45
+ options: @options.merge(options)
46
+ }
41
47
  )
42
48
  end
43
49
 
@@ -45,9 +51,25 @@ module MeiliSearch
45
51
  send_request(
46
52
  proc { |path, config| self.class.put(path, config) },
47
53
  relative_path,
48
- query_params: query_params,
49
- body: body,
50
- headers: @headers
54
+ config: {
55
+ query_params: query_params,
56
+ body: body,
57
+ headers: @headers,
58
+ options: @options
59
+ }
60
+ )
61
+ end
62
+
63
+ def http_patch(relative_path = '', body = nil, query_params = nil)
64
+ send_request(
65
+ proc { |path, config| self.class.patch(path, config) },
66
+ relative_path,
67
+ config: {
68
+ query_params: query_params,
69
+ body: body,
70
+ headers: @headers,
71
+ options: @options
72
+ }
51
73
  )
52
74
  end
53
75
 
@@ -55,29 +77,47 @@ module MeiliSearch
55
77
  send_request(
56
78
  proc { |path, config| self.class.delete(path, config) },
57
79
  relative_path,
58
- headers: @headers_no_body
80
+ config: {
81
+ headers: remove_headers(@headers.dup, 'Content-Type'),
82
+ options: @options
83
+ }
59
84
  )
60
85
  end
61
86
 
62
87
  private
63
88
 
64
- def send_request(http_method, relative_path, query_params: nil, body: nil, headers: nil)
65
- config = http_config(query_params, body, headers)
89
+ def build_default_options_headers
90
+ {
91
+ 'Content-Type' => 'application/json',
92
+ 'Authorization' => ("Bearer #{@api_key}" unless @api_key.nil?),
93
+ 'User-Agent' => MeiliSearch.qualified_version
94
+ }.compact
95
+ end
96
+
97
+ def remove_headers(data, *keys)
98
+ data.delete_if { |k| keys.include?(k) }
99
+ end
100
+
101
+ def send_request(http_method, relative_path, config: {})
102
+ config = http_config(config[:query_params], config[:body], config[:options], config[:headers])
103
+
66
104
  begin
67
105
  response = http_method.call(@base_url + relative_path, config)
68
106
  rescue Errno::ECONNREFUSED => e
69
107
  raise CommunicationError, e.message
70
108
  end
109
+
71
110
  validate(response)
72
111
  end
73
112
 
74
- def http_config(query_params, body, headers)
113
+ def http_config(query_params, body, options, headers)
114
+ body = body.to_json if options[:convert_body?] == true
75
115
  {
76
116
  headers: headers,
77
117
  query: query_params,
78
- body: body.to_json,
79
- timeout: @options[:timeout] || 1,
80
- max_retries: @options[:max_retries] || 0
118
+ body: body,
119
+ timeout: options[:timeout],
120
+ max_retries: options[:max_retries]
81
121
  }.compact
82
122
  end
83
123
 
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'meilisearch/http_request'
4
- require 'timeout'
5
4
 
6
5
  module MeiliSearch
7
6
  class Index < HTTPRequest
@@ -31,10 +30,7 @@ module MeiliSearch
31
30
  end
32
31
 
33
32
  def update(body)
34
- index_hash = http_put indexes_path(id: @uid), Utils.transform_attributes(body)
35
- set_base_properties index_hash
36
-
37
- self
33
+ http_put indexes_path(id: @uid), Utils.transform_attributes(body)
38
34
  end
39
35
 
40
36
  alias update_index update
@@ -78,12 +74,33 @@ module MeiliSearch
78
74
  alias add_or_replace_documents add_documents
79
75
 
80
76
  def add_documents!(documents, primary_key = nil)
81
- update = add_documents(documents, primary_key)
82
- wait_for_pending_update(update['updateId'])
77
+ task = add_documents(documents, primary_key)
78
+ wait_for_task(task['uid'])
83
79
  end
84
80
  alias replace_documents! add_documents!
85
81
  alias add_or_replace_documents! add_documents!
86
82
 
83
+ def add_documents_json(documents, primary_key = nil)
84
+ options = { convert_body?: false }
85
+ http_post "/indexes/#{@uid}/documents", documents, { primaryKey: primary_key }.compact, options
86
+ end
87
+ alias replace_documents_json add_documents_json
88
+ alias add_or_replace_documents_json add_documents_json
89
+
90
+ def add_documents_ndjson(documents, primary_key = nil)
91
+ options = { headers: { 'Content-Type' => 'application/x-ndjson' }, convert_body?: false }
92
+ http_post "/indexes/#{@uid}/documents", documents, { primaryKey: primary_key }.compact, options
93
+ end
94
+ alias replace_documents_ndjson add_documents_ndjson
95
+ alias add_or_replace_documents_ndjson add_documents_ndjson
96
+
97
+ def add_documents_csv(documents, primary_key = nil)
98
+ options = { headers: { 'Content-Type' => 'text/csv' }, convert_body?: false }
99
+ http_post "/indexes/#{@uid}/documents", documents, { primaryKey: primary_key }.compact, options
100
+ end
101
+ alias replace_documents_csv add_documents_csv
102
+ alias add_or_replace_documents_csv add_documents_csv
103
+
87
104
  def update_documents(documents, primary_key = nil)
88
105
  documents = [documents] if documents.is_a?(Hash)
89
106
  http_put "/indexes/#{@uid}/documents", documents, { primaryKey: primary_key }.compact
@@ -91,41 +108,41 @@ module MeiliSearch
91
108
  alias add_or_update_documents update_documents
92
109
 
93
110
  def update_documents!(documents, primary_key = nil)
94
- update = update_documents(documents, primary_key)
95
- wait_for_pending_update(update['updateId'])
111
+ task = update_documents(documents, primary_key)
112
+ wait_for_task(task['uid'])
96
113
  end
97
114
  alias add_or_update_documents! update_documents!
98
115
 
99
116
  def add_documents_in_batches(documents, batch_size = 1000, primary_key = nil)
100
- update_ids = []
117
+ tasks = []
101
118
  documents.each_slice(batch_size) do |batch|
102
- update_ids.append(add_documents(batch, primary_key))
119
+ tasks.append(add_documents(batch, primary_key))
103
120
  end
104
- update_ids
121
+ tasks
105
122
  end
106
123
 
107
124
  def add_documents_in_batches!(documents, batch_size = 1000, primary_key = nil)
108
- update_ids = add_documents_in_batches(documents, batch_size, primary_key)
125
+ tasks = add_documents_in_batches(documents, batch_size, primary_key)
109
126
  responses = []
110
- update_ids.each do |update_object|
111
- responses.append(wait_for_pending_update(update_object['updateId']))
127
+ tasks.each do |task_obj|
128
+ responses.append(wait_for_task(task_obj['uid']))
112
129
  end
113
130
  responses
114
131
  end
115
132
 
116
133
  def update_documents_in_batches(documents, batch_size = 1000, primary_key = nil)
117
- update_ids = []
134
+ tasks = []
118
135
  documents.each_slice(batch_size) do |batch|
119
- update_ids.append(update_documents(batch, primary_key))
136
+ tasks.append(update_documents(batch, primary_key))
120
137
  end
121
- update_ids
138
+ tasks
122
139
  end
123
140
 
124
141
  def update_documents_in_batches!(documents, batch_size = 1000, primary_key = nil)
125
- update_ids = update_documents_in_batches(documents, batch_size, primary_key)
142
+ tasks = update_documents_in_batches(documents, batch_size, primary_key)
126
143
  responses = []
127
- update_ids.each do |update_object|
128
- responses.append(wait_for_pending_update(update_object['updateId']))
144
+ tasks.each do |task_obj|
145
+ responses.append(wait_for_task(task_obj['uid']))
129
146
  end
130
147
  responses
131
148
  end
@@ -140,8 +157,8 @@ module MeiliSearch
140
157
  alias delete_multiple_documents delete_documents
141
158
 
142
159
  def delete_documents!(documents_ids)
143
- update = delete_documents(documents_ids)
144
- wait_for_pending_update(update['updateId'])
160
+ task = delete_documents(documents_ids)
161
+ wait_for_task(task['uid'])
145
162
  end
146
163
  alias delete_multiple_documents! delete_documents!
147
164
 
@@ -152,8 +169,8 @@ module MeiliSearch
152
169
  alias delete_one_document delete_document
153
170
 
154
171
  def delete_document!(document_id)
155
- update = delete_document(document_id)
156
- wait_for_pending_update(update['updateId'])
172
+ task = delete_document(document_id)
173
+ wait_for_task(task['uid'])
157
174
  end
158
175
  alias delete_one_document! delete_document!
159
176
 
@@ -162,8 +179,8 @@ module MeiliSearch
162
179
  end
163
180
 
164
181
  def delete_all_documents!
165
- update = delete_all_documents
166
- wait_for_pending_update(update['updateId'])
182
+ task = delete_all_documents
183
+ wait_for_task(task['uid'])
167
184
  end
168
185
 
169
186
  ### SEARCH
@@ -174,31 +191,23 @@ module MeiliSearch
174
191
  http_post "/indexes/#{@uid}/search", parsed_options
175
192
  end
176
193
 
177
- ### UPDATES
194
+ ### TASKS
178
195
 
179
- def get_update_status(update_id)
180
- http_get "/indexes/#{@uid}/updates/#{update_id}"
196
+ def task_endpoint
197
+ @task_endpoint ||= Task.new(@base_url, @api_key, @options)
181
198
  end
199
+ private :task_endpoint
182
200
 
183
- def get_all_update_status
184
- http_get "/indexes/#{@uid}/updates"
201
+ def task(task_uid)
202
+ task_endpoint.index_task(@uid, task_uid)
185
203
  end
186
204
 
187
- def achieved_upate?(update)
188
- update['status'] != 'enqueued' && update['status'] != 'processing'
205
+ def tasks
206
+ task_endpoint.index_tasks(@uid)
189
207
  end
190
208
 
191
- def wait_for_pending_update(update_id, timeout_in_ms = 5000, interval_in_ms = 50)
192
- Timeout.timeout(timeout_in_ms.to_f / 1000) do
193
- loop do
194
- get_update = get_update_status(update_id)
195
- return get_update if achieved_upate?(get_update)
196
-
197
- sleep interval_in_ms.to_f / 1000
198
- end
199
- end
200
- rescue Timeout::Error
201
- raise MeiliSearch::TimeoutError
209
+ def wait_for_task(task_uid, timeout_in_ms = 5000, interval_in_ms = 50)
210
+ task_endpoint.wait_for_task(task_uid, timeout_in_ms, interval_in_ms)
202
211
  end
203
212
 
204
213
  ### STATS
@@ -215,10 +224,6 @@ module MeiliSearch
215
224
  stats['isIndexing']
216
225
  end
217
226
 
218
- def last_update
219
- stats['lastUpdate']
220
- end
221
-
222
227
  def field_distribution
223
228
  stats['fieldDistribution']
224
229
  end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'meilisearch/http_request'
4
+ require 'timeout'
5
+
6
+ module MeiliSearch
7
+ class Task < HTTPRequest
8
+ def task_list
9
+ http_get '/tasks/'
10
+ end
11
+
12
+ def task(task_uid)
13
+ http_get "/tasks/#{task_uid}"
14
+ end
15
+
16
+ def index_tasks(index_uid)
17
+ http_get "/indexes/#{index_uid}/tasks"
18
+ end
19
+
20
+ def index_task(index_uid, task_uid)
21
+ http_get "/indexes/#{index_uid}/tasks/#{task_uid}"
22
+ end
23
+
24
+ def wait_for_task(task_uid, timeout_in_ms = 5000, interval_in_ms = 50)
25
+ Timeout.timeout(timeout_in_ms.to_f / 1000) do
26
+ loop do
27
+ task = task(task_uid)
28
+ return task if achieved_task?(task)
29
+
30
+ sleep interval_in_ms.to_f / 1000
31
+ end
32
+ end
33
+ rescue Timeout::Error
34
+ raise MeiliSearch::TimeoutError
35
+ end
36
+
37
+ private
38
+
39
+ def achieved_task?(task)
40
+ task['status'] != 'enqueued' && task['status'] != 'processing'
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MeiliSearch
4
+ module Utils
5
+ SNAKE_CASE = /[^a-zA-Z0-9]+(.)/.freeze
6
+
7
+ def self.transform_attributes(body)
8
+ case body
9
+ when Array
10
+ body.map { |item| transform_attributes(item) }
11
+ when Hash
12
+ parse(body)
13
+ else
14
+ body
15
+ end
16
+ end
17
+
18
+ def self.parse(body)
19
+ body
20
+ .transform_keys(&:to_s)
21
+ .transform_keys do |key|
22
+ key.include?('_') ? key.downcase.gsub(SNAKE_CASE, &:upcase).gsub('_', '') : key
23
+ end
24
+ end
25
+
26
+ private_class_method :parse
27
+ end
28
+ end
@@ -1,5 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module MeiliSearch
4
- VERSION = '0.17.1'
4
+ VERSION = '0.18.1'
5
+
6
+ def self.qualified_version
7
+ "Meilisearch Ruby (v#{VERSION})"
8
+ end
5
9
  end
data/lib/meilisearch.rb CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  require 'meilisearch/version'
4
4
  require 'meilisearch/utils'
5
+ require 'meilisearch/task'
5
6
  require 'meilisearch/client'
6
7
  require 'meilisearch/index'
7
8
 
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.17.1
4
+ version: 0.18.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-11-18 00:00:00.000000000 Z
11
+ date: 2022-02-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: httparty
@@ -30,17 +30,21 @@ dependencies:
30
30
  - - "<"
31
31
  - !ruby/object:Gem::Version
32
32
  version: 0.21.0
33
- description: An easy-to-use ruby client for Meilisearch API. See https://github.com/meilisearch/MeiliSearch
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: []
36
36
  extensions: []
37
37
  extra_rdoc_files: []
38
38
  files:
39
+ - LICENSE
40
+ - README.md
39
41
  - lib/meilisearch.rb
40
42
  - lib/meilisearch/client.rb
41
43
  - lib/meilisearch/error.rb
42
44
  - lib/meilisearch/http_request.rb
43
45
  - lib/meilisearch/index.rb
46
+ - lib/meilisearch/task.rb
47
+ - lib/meilisearch/utils.rb
44
48
  - lib/meilisearch/version.rb
45
49
  homepage: https://github.com/meilisearch/meilisearch-ruby
46
50
  licenses: