meilisearch 0.17.3 → 0.18.2

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: 3c90df98b1b08039b339c49b47bfd052639e1301e9e7e3b25989b9ce6e3d1e67
4
- data.tar.gz: 3f200a9de09db7a47780b01aa20a8ce5b2b1d0d0579954cd8842cb208b06b4dc
3
+ metadata.gz: 9b69f3c0d8bf43393b59abe4e44aabf40ff673dd08bde8f6e60d1c996be8b7bf
4
+ data.tar.gz: d2ff90fe7e1cf738dc4e3297cf7e7215e80c7a63317d06144681fab39206d1b2
5
5
  SHA512:
6
- metadata.gz: b3b38312517176303e9fdc49af5c38647ea4d719d8988cb1e1fd60839e7c593226fd9369febd24a326d214dbb606acd201464fd6590f46438383cf25f3e7e934
7
- data.tar.gz: 494fa30322be3d624851117e460c31046c51ea3ef4d00326f4be969a76f5f056a15147c065b1ef02a56f3a589643e137ac4af1a05a088bab606cdf6d31bc8abc
6
+ metadata.gz: 59dfc2b7ced1fec8a75c32b4b02b49d42a8a63af862bcb86931692be8e9c92b89657b93958c150937ddbe295d645eff5192a181ef439885462c2f6174c1519c3
7
+ data.tar.gz: 71b81d762f8c609a7e2d50ac0052e6c8e0b904c28b2cb7b98f0c55934122c97c1160a4c0b4a2659adcf474a59be85ea609a75183e69550ca4971d177afb8e2b0
data/README.md CHANGED
@@ -1,11 +1,11 @@
1
1
  <p align="center">
2
- <img src="https://res.cloudinary.com/meilisearch/image/upload/v1587402338/SDKs/meilisearch_ruby.svg" alt="MeiliSearch-Ruby" width="200" height="200" />
2
+ <img src="https://raw.githubusercontent.com/meilisearch/integration-guides/main/assets/logos/meilisearch_ruby.svg" alt="Meilisearch-Ruby" width="200" height="200" />
3
3
  </p>
4
4
 
5
- <h1 align="center">MeiliSearch Ruby</h1>
5
+ <h1 align="center">Meilisearch Ruby</h1>
6
6
 
7
7
  <h4 align="center">
8
- <a href="https://github.com/meilisearch/MeiliSearch">MeiliSearch</a> |
8
+ <a href="https://github.com/meilisearch/meilisearch">Meilisearch</a> |
9
9
  <a href="https://docs.meilisearch.com">Documentation</a> |
10
10
  <a href="https://slack.meilisearch.com">Slack</a> |
11
11
  <a href="https://roadmap.meilisearch.com/tabs/1-under-consideration">Roadmap</a> |
@@ -17,21 +17,21 @@
17
17
  <a href="https://badge.fury.io/rb/meilisearch"><img src="https://badge.fury.io/rb/meilisearch.svg" alt="Latest Stable Version"></a>
18
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
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://app.bors.tech/repositories/28781"><img src="https://bors.tech/images/badge_small.svg" alt="Bors enabled"></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
21
  </p>
22
22
 
23
- <p align="center">⚡ The MeiliSearch API client written for Ruby 💎</p>
23
+ <p align="center">⚡ The Meilisearch API client written for Ruby 💎</p>
24
24
 
25
- **MeiliSearch Ruby** is the MeiliSearch API client for Ruby developers.
25
+ **Meilisearch Ruby** is the Meilisearch API client for Ruby developers.
26
26
 
27
- **MeiliSearch** is an open-source search engine. [Discover what MeiliSearch is!](https://github.com/meilisearch/MeiliSearch)
27
+ **Meilisearch** is an open-source search engine. [Discover what Meilisearch is!](https://github.com/meilisearch/meilisearch)
28
28
 
29
29
  ## Table of Contents <!-- omit in toc -->
30
30
 
31
31
  - [📖 Documentation](#-documentation)
32
32
  - [🔧 Installation](#-installation)
33
33
  - [🚀 Getting Started](#-getting-started)
34
- - [🤖 Compatibility with MeiliSearch](#-compatibility-with-meilisearch)
34
+ - [🤖 Compatibility with Meilisearch](#-compatibility-with-meilisearch)
35
35
  - [💡 Learn More](#-learn-more)
36
36
  - [⚙️ Development Workflow and Contributing](#️-development-workflow-and-contributing)
37
37
 
@@ -55,21 +55,21 @@ source 'https://rubygems.org'
55
55
  gem 'meilisearch'
56
56
  ```
57
57
 
58
- ### Run MeiliSearch <!-- omit in toc -->
58
+ ### Run Meilisearch <!-- omit in toc -->
59
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).
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
61
 
62
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
63
 
64
64
  ```sh
65
- #Install MeiliSearch
65
+ #Install Meilisearch
66
66
  curl -L https://install.meilisearch.com | sh
67
67
 
68
- # Launch MeiliSearch
68
+ # Launch Meilisearch
69
69
  ./meilisearch --master-key=masterKey
70
70
  ```
71
71
 
72
- NB: you can also download MeiliSearch from **Homebrew** or **APT** or even run it using **Docker**.
72
+ NB: you can also download Meilisearch from **Homebrew** or **APT** or even run it using **Docker**.
73
73
 
74
74
  ## 🚀 Getting Started
75
75
 
@@ -91,18 +91,18 @@ documents = [
91
91
  { id: 5, title: 'Moana', genres: ['Fantasy', 'Action']},
92
92
  { id: 6, title: 'Philadelphia', genres: ['Drama'] },
93
93
  ]
94
- # If the index 'movies' does not exist, MeiliSearch creates it when you first add the documents.
95
- index.add_documents(documents) # => { "updateId": 0 }
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
96
  ```
97
97
 
98
- With the `updateId`, you can check the status (`enqueued`, `processing`, `processed` or `failed`) of your documents addition using the [update endpoint](https://docs.meilisearch.com/reference/api/updates.html#get-an-update-status).
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
99
 
100
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
101
 
102
102
  #### Basic Search <!-- omit in toc -->
103
103
 
104
104
  ``` ruby
105
- # MeiliSearch is typo-tolerant:
105
+ # Meilisearch is typo-tolerant:
106
106
  puts index.search('carlo')
107
107
  ```
108
108
  Output:
@@ -165,7 +165,7 @@ index.update_filterable_attributes([
165
165
 
166
166
  You only need to perform this operation once.
167
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 [update status](https://docs.meilisearch.com/reference/api/updates.html#get-an-update-status).
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
169
 
170
170
  Then, you can perform the search:
171
171
 
@@ -196,9 +196,9 @@ JSON output:
196
196
  }
197
197
  ```
198
198
 
199
- ## 🤖 Compatibility with MeiliSearch
199
+ ## 🤖 Compatibility with Meilisearch
200
200
 
201
- This package only guarantees the compatibility with the [version v0.24.0 of MeiliSearch](https://github.com/meilisearch/MeiliSearch/releases/tag/v0.24.0).
201
+ This package only guarantees the compatibility with the [version v0.26.0 of Meilisearch](https://github.com/meilisearch/meilisearch/releases/tag/v0.26.0).
202
202
 
203
203
  ## 💡 Learn More
204
204
 
@@ -219,4 +219,4 @@ If you want to know more about the development workflow or want to contribute, p
219
219
 
220
220
  <hr>
221
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.
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.
@@ -1,9 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'meilisearch/http_request'
4
-
5
3
  module MeiliSearch
6
4
  class Client < HTTPRequest
5
+ include MeiliSearch::TenantToken
6
+
7
7
  ### INDEXES
8
8
 
9
9
  def raw_indexes
@@ -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
@@ -62,4 +62,10 @@ module MeiliSearch
62
62
  super(@message)
63
63
  end
64
64
  end
65
+
66
+ module TenantToken
67
+ class ExpireOrInvalidSignature < StandardError; end
68
+ class InvalidApiKey < StandardError; end
69
+ class InvalidSearchRules < StandardError; end
70
+ end
65
71
  end
@@ -7,25 +7,30 @@ 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 = merge_options({
16
- timeout: 1,
17
- max_retries: 0,
18
- headers: build_default_options_headers(api_key),
19
- convert_body?: true
20
- }, options)
21
+ @options = DEFAULT_OPTIONS.merge(options)
22
+ @headers = build_default_options_headers
21
23
  end
22
24
 
23
25
  def http_get(relative_path = '', query_params = {})
24
26
  send_request(
25
27
  proc { |path, config| self.class.get(path, config) },
26
28
  relative_path,
27
- query_params: query_params,
28
- options: remove_options_header(@options, 'Content-Type')
29
+ config: {
30
+ query_params: query_params,
31
+ headers: remove_headers(@headers.dup, 'Content-Type'),
32
+ options: @options
33
+ }
29
34
  )
30
35
  end
31
36
 
@@ -33,9 +38,12 @@ module MeiliSearch
33
38
  send_request(
34
39
  proc { |path, config| self.class.post(path, config) },
35
40
  relative_path,
36
- query_params: query_params,
37
- body: body,
38
- options: merge_options(@options, options)
41
+ config: {
42
+ query_params: query_params,
43
+ body: body,
44
+ headers: @headers.dup.merge(options[:headers] || {}),
45
+ options: @options.merge(options)
46
+ }
39
47
  )
40
48
  end
41
49
 
@@ -43,9 +51,25 @@ module MeiliSearch
43
51
  send_request(
44
52
  proc { |path, config| self.class.put(path, config) },
45
53
  relative_path,
46
- query_params: query_params,
47
- body: body,
48
- options: @options
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
+ }
49
73
  )
50
74
  end
51
75
 
@@ -53,52 +77,43 @@ module MeiliSearch
53
77
  send_request(
54
78
  proc { |path, config| self.class.delete(path, config) },
55
79
  relative_path,
56
- options: remove_options_header(@options, 'Content-Type')
80
+ config: {
81
+ headers: remove_headers(@headers.dup, 'Content-Type'),
82
+ options: @options
83
+ }
57
84
  )
58
85
  end
59
86
 
60
87
  private
61
88
 
62
- def build_default_options_headers(api_key = nil)
89
+ def build_default_options_headers
63
90
  {
64
91
  'Content-Type' => 'application/json',
65
- 'X-Meili-API-Key' => api_key
92
+ 'Authorization' => ("Bearer #{@api_key}" unless @api_key.nil?),
93
+ 'User-Agent' => MeiliSearch.qualified_version
66
94
  }.compact
67
95
  end
68
96
 
69
- def merge_options(default_options, added_options = {})
70
- default_cloned_headers = default_options[:headers].clone
71
- merged_options = default_options.merge(added_options)
72
- merged_options[:headers] = default_cloned_headers.merge(added_options[:headers]) if added_options.key?(:headers)
73
- merged_options
74
- end
75
-
76
- def remove_options_header(options, key)
77
- cloned_options = clone_options(options)
78
- cloned_options[:headers].tap { |headers| headers.delete(key) }
79
- cloned_options
97
+ def remove_headers(data, *keys)
98
+ data.delete_if { |k| keys.include?(k) }
80
99
  end
81
100
 
82
- def clone_options(options)
83
- cloned_options = options.clone
84
- cloned_options[:headers] = options[:headers].clone
85
- cloned_options
86
- end
101
+ def send_request(http_method, relative_path, config: {})
102
+ config = http_config(config[:query_params], config[:body], config[:options], config[:headers])
87
103
 
88
- def send_request(http_method, relative_path, query_params: nil, body: nil, options: {})
89
- config = http_config(query_params, body, options)
90
104
  begin
91
105
  response = http_method.call(@base_url + relative_path, config)
92
106
  rescue Errno::ECONNREFUSED => e
93
107
  raise CommunicationError, e.message
94
108
  end
109
+
95
110
  validate(response)
96
111
  end
97
112
 
98
- def http_config(query_params, body, options)
113
+ def http_config(query_params, body, options, headers)
99
114
  body = body.to_json if options[:convert_body?] == true
100
115
  {
101
- headers: options[:headers],
116
+ headers: headers,
102
117
  query: query_params,
103
118
  body: body,
104
119
  timeout: options[:timeout],
@@ -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,14 +74,14 @@ 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
 
87
83
  def add_documents_json(documents, primary_key = nil)
88
- options = { headers: { 'Content-Type' => 'application/json' }, convert_body?: false }
84
+ options = { convert_body?: false }
89
85
  http_post "/indexes/#{@uid}/documents", documents, { primaryKey: primary_key }.compact, options
90
86
  end
91
87
  alias replace_documents_json add_documents_json
@@ -112,41 +108,41 @@ module MeiliSearch
112
108
  alias add_or_update_documents update_documents
113
109
 
114
110
  def update_documents!(documents, primary_key = nil)
115
- update = update_documents(documents, primary_key)
116
- wait_for_pending_update(update['updateId'])
111
+ task = update_documents(documents, primary_key)
112
+ wait_for_task(task['uid'])
117
113
  end
118
114
  alias add_or_update_documents! update_documents!
119
115
 
120
116
  def add_documents_in_batches(documents, batch_size = 1000, primary_key = nil)
121
- update_ids = []
117
+ tasks = []
122
118
  documents.each_slice(batch_size) do |batch|
123
- update_ids.append(add_documents(batch, primary_key))
119
+ tasks.append(add_documents(batch, primary_key))
124
120
  end
125
- update_ids
121
+ tasks
126
122
  end
127
123
 
128
124
  def add_documents_in_batches!(documents, batch_size = 1000, primary_key = nil)
129
- update_ids = add_documents_in_batches(documents, batch_size, primary_key)
125
+ tasks = add_documents_in_batches(documents, batch_size, primary_key)
130
126
  responses = []
131
- update_ids.each do |update_object|
132
- responses.append(wait_for_pending_update(update_object['updateId']))
127
+ tasks.each do |task_obj|
128
+ responses.append(wait_for_task(task_obj['uid']))
133
129
  end
134
130
  responses
135
131
  end
136
132
 
137
133
  def update_documents_in_batches(documents, batch_size = 1000, primary_key = nil)
138
- update_ids = []
134
+ tasks = []
139
135
  documents.each_slice(batch_size) do |batch|
140
- update_ids.append(update_documents(batch, primary_key))
136
+ tasks.append(update_documents(batch, primary_key))
141
137
  end
142
- update_ids
138
+ tasks
143
139
  end
144
140
 
145
141
  def update_documents_in_batches!(documents, batch_size = 1000, primary_key = nil)
146
- update_ids = update_documents_in_batches(documents, batch_size, primary_key)
142
+ tasks = update_documents_in_batches(documents, batch_size, primary_key)
147
143
  responses = []
148
- update_ids.each do |update_object|
149
- responses.append(wait_for_pending_update(update_object['updateId']))
144
+ tasks.each do |task_obj|
145
+ responses.append(wait_for_task(task_obj['uid']))
150
146
  end
151
147
  responses
152
148
  end
@@ -161,8 +157,8 @@ module MeiliSearch
161
157
  alias delete_multiple_documents delete_documents
162
158
 
163
159
  def delete_documents!(documents_ids)
164
- update = delete_documents(documents_ids)
165
- wait_for_pending_update(update['updateId'])
160
+ task = delete_documents(documents_ids)
161
+ wait_for_task(task['uid'])
166
162
  end
167
163
  alias delete_multiple_documents! delete_documents!
168
164
 
@@ -173,8 +169,8 @@ module MeiliSearch
173
169
  alias delete_one_document delete_document
174
170
 
175
171
  def delete_document!(document_id)
176
- update = delete_document(document_id)
177
- wait_for_pending_update(update['updateId'])
172
+ task = delete_document(document_id)
173
+ wait_for_task(task['uid'])
178
174
  end
179
175
  alias delete_one_document! delete_document!
180
176
 
@@ -183,8 +179,8 @@ module MeiliSearch
183
179
  end
184
180
 
185
181
  def delete_all_documents!
186
- update = delete_all_documents
187
- wait_for_pending_update(update['updateId'])
182
+ task = delete_all_documents
183
+ wait_for_task(task['uid'])
188
184
  end
189
185
 
190
186
  ### SEARCH
@@ -195,31 +191,23 @@ module MeiliSearch
195
191
  http_post "/indexes/#{@uid}/search", parsed_options
196
192
  end
197
193
 
198
- ### UPDATES
194
+ ### TASKS
199
195
 
200
- def get_update_status(update_id)
201
- http_get "/indexes/#{@uid}/updates/#{update_id}"
196
+ def task_endpoint
197
+ @task_endpoint ||= Task.new(@base_url, @api_key, @options)
202
198
  end
199
+ private :task_endpoint
203
200
 
204
- def get_all_update_status
205
- http_get "/indexes/#{@uid}/updates"
201
+ def task(task_uid)
202
+ task_endpoint.index_task(@uid, task_uid)
206
203
  end
207
204
 
208
- def achieved_upate?(update)
209
- update['status'] != 'enqueued' && update['status'] != 'processing'
205
+ def tasks
206
+ task_endpoint.index_tasks(@uid)
210
207
  end
211
208
 
212
- def wait_for_pending_update(update_id, timeout_in_ms = 5000, interval_in_ms = 50)
213
- Timeout.timeout(timeout_in_ms.to_f / 1000) do
214
- loop do
215
- get_update = get_update_status(update_id)
216
- return get_update if achieved_upate?(get_update)
217
-
218
- sleep interval_in_ms.to_f / 1000
219
- end
220
- end
221
- rescue Timeout::Error
222
- 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)
223
211
  end
224
212
 
225
213
  ### STATS
@@ -236,10 +224,6 @@ module MeiliSearch
236
224
  stats['isIndexing']
237
225
  end
238
226
 
239
- def last_update
240
- stats['lastUpdate']
241
- end
242
-
243
227
  def field_distribution
244
228
  stats['fieldDistribution']
245
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,70 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MeiliSearch
4
+ module TenantToken
5
+ HEADER = {
6
+ typ: 'JWT',
7
+ alg: 'HS256'
8
+ }.freeze
9
+
10
+ def generate_tenant_token(search_rules, api_key: nil, expires_at: nil)
11
+ signature = retrieve_valid_key!(api_key, @api_key)
12
+ expiration = validate_expires_at!(expires_at)
13
+ rules = validate_search_rules!(search_rules)
14
+ unsigned_data = build_payload(expiration, rules, signature)
15
+
16
+ combine(unsigned_data, to_base64(sign_data(signature, unsigned_data)))
17
+ end
18
+
19
+ private
20
+
21
+ def build_payload(expiration, rules, signature)
22
+ payload = {
23
+ searchRules: rules,
24
+ apiKeyPrefix: signature[0..7],
25
+ exp: expiration
26
+ }
27
+
28
+ combine(encode(HEADER), encode(payload))
29
+ end
30
+
31
+ def validate_expires_at!(expires_at)
32
+ return unless expires_at
33
+ return expires_at.to_i if expires_at.utc? && expires_at > Time.now.utc
34
+
35
+ raise
36
+ rescue StandardError
37
+ raise ExpireOrInvalidSignature
38
+ end
39
+
40
+ def validate_search_rules!(data)
41
+ return data if data
42
+
43
+ raise InvalidSearchRules
44
+ end
45
+
46
+ def retrieve_valid_key!(*keys)
47
+ key = keys.compact.find { |k| !k.empty? }
48
+
49
+ raise InvalidApiKey if key.nil?
50
+
51
+ key
52
+ end
53
+
54
+ def sign_data(key, msg)
55
+ OpenSSL::HMAC.digest('SHA256', key, msg)
56
+ end
57
+
58
+ def to_base64(data)
59
+ Base64.urlsafe_encode64(data, padding: false)
60
+ end
61
+
62
+ def encode(data)
63
+ to_base64(JSON.generate(data))
64
+ end
65
+
66
+ def combine(*parts)
67
+ parts.join('.')
68
+ end
69
+ end
70
+ end
@@ -1,5 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module MeiliSearch
4
- VERSION = '0.17.3'
4
+ VERSION = '0.18.2'
5
+
6
+ def self.qualified_version
7
+ "Meilisearch Ruby (v#{VERSION})"
8
+ end
5
9
  end
data/lib/meilisearch.rb CHANGED
@@ -2,6 +2,9 @@
2
2
 
3
3
  require 'meilisearch/version'
4
4
  require 'meilisearch/utils'
5
+ require 'meilisearch/http_request'
6
+ require 'meilisearch/tenant_token'
7
+ require 'meilisearch/task'
5
8
  require 'meilisearch/client'
6
9
  require 'meilisearch/index'
7
10
 
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.3
4
+ version: 0.18.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Meili
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-12-13 00:00:00.000000000 Z
11
+ date: 2022-03-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: httparty
@@ -30,7 +30,7 @@ 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: []
@@ -43,6 +43,8 @@ files:
43
43
  - lib/meilisearch/error.rb
44
44
  - lib/meilisearch/http_request.rb
45
45
  - lib/meilisearch/index.rb
46
+ - lib/meilisearch/task.rb
47
+ - lib/meilisearch/tenant_token.rb
46
48
  - lib/meilisearch/utils.rb
47
49
  - lib/meilisearch/version.rb
48
50
  homepage: https://github.com/meilisearch/meilisearch-ruby