algolia 2.0.0.pre.alpha.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 +7 -0
- data/.circleci/config.yml +146 -0
- data/.github/ISSUE_TEMPLATE.md +20 -0
- data/.github/PULL_REQUEST_TEMPLATE.md +22 -0
- data/.gitignore +38 -0
- data/.rubocop.yml +186 -0
- data/.rubocop_todo.yml +14 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +18 -0
- data/LICENSE +21 -0
- data/README.md +56 -0
- data/Rakefile +45 -0
- data/Steepfile +6 -0
- data/algolia.gemspec +41 -0
- data/bin/console +21 -0
- data/bin/setup +8 -0
- data/lib/algolia.rb +42 -0
- data/lib/algolia/account_client.rb +65 -0
- data/lib/algolia/analytics_client.rb +105 -0
- data/lib/algolia/config/algolia_config.rb +40 -0
- data/lib/algolia/config/analytics_config.rb +20 -0
- data/lib/algolia/config/insights_config.rb +20 -0
- data/lib/algolia/config/recommendation_config.rb +20 -0
- data/lib/algolia/config/search_config.rb +40 -0
- data/lib/algolia/defaults.rb +35 -0
- data/lib/algolia/enums/call_type.rb +4 -0
- data/lib/algolia/enums/retry_outcome_type.rb +5 -0
- data/lib/algolia/error.rb +29 -0
- data/lib/algolia/helpers.rb +83 -0
- data/lib/algolia/http/http_requester.rb +84 -0
- data/lib/algolia/http/response.rb +23 -0
- data/lib/algolia/insights_client.rb +238 -0
- data/lib/algolia/iterators/base_iterator.rb +19 -0
- data/lib/algolia/iterators/object_iterator.rb +27 -0
- data/lib/algolia/iterators/paginator_iterator.rb +44 -0
- data/lib/algolia/iterators/rule_iterator.rb +9 -0
- data/lib/algolia/iterators/synonym_iterator.rb +9 -0
- data/lib/algolia/logger_helper.rb +14 -0
- data/lib/algolia/recommendation_client.rb +60 -0
- data/lib/algolia/responses/add_api_key_response.rb +38 -0
- data/lib/algolia/responses/base_response.rb +9 -0
- data/lib/algolia/responses/delete_api_key_response.rb +40 -0
- data/lib/algolia/responses/indexing_response.rb +28 -0
- data/lib/algolia/responses/multiple_batch_indexing_response.rb +29 -0
- data/lib/algolia/responses/multiple_response.rb +45 -0
- data/lib/algolia/responses/restore_api_key_response.rb +36 -0
- data/lib/algolia/responses/update_api_key_response.rb +39 -0
- data/lib/algolia/search_client.rb +614 -0
- data/lib/algolia/search_index.rb +1094 -0
- data/lib/algolia/transport/request_options.rb +94 -0
- data/lib/algolia/transport/retry_strategy.rb +117 -0
- data/lib/algolia/transport/stateful_host.rb +26 -0
- data/lib/algolia/transport/transport.rb +161 -0
- data/lib/algolia/user_agent.rb +25 -0
- data/lib/algolia/version.rb +3 -0
- data/sig/config/algolia_config.rbs +24 -0
- data/sig/config/analytics_config.rbs +11 -0
- data/sig/config/insights_config.rbs +11 -0
- data/sig/config/recommendation_config.rbs +11 -0
- data/sig/config/search_config.rbs +11 -0
- data/sig/enums/call_type.rbs +5 -0
- data/sig/helpers.rbs +12 -0
- data/sig/http/http_requester.rbs +17 -0
- data/sig/http/response.rbs +14 -0
- data/sig/interfaces/_connection.rbs +16 -0
- data/sig/iterators/base_iterator.rbs +15 -0
- data/sig/iterators/object_iterator.rbs +6 -0
- data/sig/iterators/paginator_iterator.rbs +8 -0
- data/sig/iterators/rule_iterator.rbs +5 -0
- data/sig/iterators/synonym_iterator.rbs +5 -0
- data/sig/transport/request_options.rbs +33 -0
- data/sig/transport/stateful_host.rbs +21 -0
- data/test/algolia/integration/account_client_test.rb +47 -0
- data/test/algolia/integration/analytics_client_test.rb +113 -0
- data/test/algolia/integration/base_test.rb +9 -0
- data/test/algolia/integration/insights_client_test.rb +80 -0
- data/test/algolia/integration/mocks/mock_requester.rb +45 -0
- data/test/algolia/integration/recommendation_client_test.rb +30 -0
- data/test/algolia/integration/search_client_test.rb +361 -0
- data/test/algolia/integration/search_index_test.rb +698 -0
- data/test/algolia/unit/helpers_test.rb +69 -0
- data/test/algolia/unit/retry_strategy_test.rb +139 -0
- data/test/algolia/unit/user_agent_test.rb +16 -0
- data/test/test_helper.rb +89 -0
- data/upgrade_guide.md +595 -0
- metadata +307 -0
@@ -0,0 +1,69 @@
|
|
1
|
+
require 'algolia'
|
2
|
+
require 'test_helper'
|
3
|
+
|
4
|
+
class HelpersTest
|
5
|
+
include Helpers
|
6
|
+
|
7
|
+
describe 'test helpers' do
|
8
|
+
def test_deserialize_settings
|
9
|
+
old_settings = {
|
10
|
+
attributesToIndex: %w(attr1 attr2),
|
11
|
+
numericAttributesToIndex: %w(attr1 attr2),
|
12
|
+
slaves: %w(index1 index2)
|
13
|
+
}
|
14
|
+
|
15
|
+
new_settings = {
|
16
|
+
searchableAttributes: %w(attr1 attr2),
|
17
|
+
numericAttributesForFiltering: %w(attr1 attr2),
|
18
|
+
replicas: %w(index1 index2)
|
19
|
+
}
|
20
|
+
|
21
|
+
deserialized_settings = deserialize_settings(old_settings)
|
22
|
+
assert_equal new_settings, deserialized_settings
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe 'test hash_includes_subset' do
|
27
|
+
def test_empty_hashes
|
28
|
+
h = {}
|
29
|
+
subset = {}
|
30
|
+
assert hash_includes_subset?(h, subset)
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_with_empty_subset
|
34
|
+
h = { a: 100, b: 200 }
|
35
|
+
subset = {}
|
36
|
+
assert hash_includes_subset?(h, subset)
|
37
|
+
end
|
38
|
+
|
39
|
+
def test_subset_included
|
40
|
+
h = { a: 100, b: 200 }
|
41
|
+
subset = { a: 100 }
|
42
|
+
assert hash_includes_subset?(h, subset)
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_subset_not_included
|
46
|
+
h = { a: 100, b: 200 }
|
47
|
+
subset = { c: 300 }
|
48
|
+
refute hash_includes_subset?(h, subset)
|
49
|
+
end
|
50
|
+
|
51
|
+
def test_subset_included_but_wrong_value
|
52
|
+
h = { a: 100, b: 200 }
|
53
|
+
subset = { a: 200 }
|
54
|
+
refute hash_includes_subset?(h, subset)
|
55
|
+
end
|
56
|
+
|
57
|
+
def test_subset_included_with_multiple_values
|
58
|
+
h = { a: 100, b: 200, c: 300 }
|
59
|
+
subset = { a: 100, b: 200 }
|
60
|
+
assert hash_includes_subset?(h, subset)
|
61
|
+
end
|
62
|
+
|
63
|
+
def test_subset_not_included_because_too_many_values
|
64
|
+
h = { a: 100, b: 200 }
|
65
|
+
subset = { a: 100, b: 200, c: 300 }
|
66
|
+
refute hash_includes_subset?(h, subset)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,139 @@
|
|
1
|
+
require 'algolia'
|
2
|
+
require 'test_helper'
|
3
|
+
|
4
|
+
class RetryStrategyTest
|
5
|
+
include RetryOutcomeType
|
6
|
+
include CallType
|
7
|
+
describe 'get tryable hosts' do
|
8
|
+
def before_all
|
9
|
+
super
|
10
|
+
@app_id = 'app_id'
|
11
|
+
@api_key = 'api_key'
|
12
|
+
stateful_hosts = []
|
13
|
+
stateful_hosts << "#{@app_id}-4.algolianet.com"
|
14
|
+
stateful_hosts << "#{@app_id}-5.algolianet.com"
|
15
|
+
stateful_hosts << "#{@app_id}-6.algolianet.com"
|
16
|
+
@config = Algolia::Search::Config.new(app_id: @app_id, api_key: @api_key, custom_hosts: stateful_hosts)
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_resets_expired_hosts_according_to_read_type
|
20
|
+
@config.default_hosts[1].up = false
|
21
|
+
retry_strategy = Algolia::Transport::RetryStrategy.new(@config)
|
22
|
+
|
23
|
+
hosts = retry_strategy.get_tryable_hosts(READ)
|
24
|
+
assert_equal 2, hosts.length
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_resets_expired_hosts_according_to_write_type
|
28
|
+
@config.default_hosts[1].up = false
|
29
|
+
retry_strategy = Algolia::Transport::RetryStrategy.new(@config)
|
30
|
+
|
31
|
+
hosts = retry_strategy.get_tryable_hosts(WRITE)
|
32
|
+
assert_equal 2, hosts.length
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_resets_expired_hosts_according_to_read_type_with_timeout
|
36
|
+
@config.default_hosts[1].up = false
|
37
|
+
@config.default_hosts[1].last_use = Time.new.utc - 1000
|
38
|
+
retry_strategy = Algolia::Transport::RetryStrategy.new(@config)
|
39
|
+
|
40
|
+
hosts = retry_strategy.get_tryable_hosts(READ)
|
41
|
+
assert_equal 3, hosts.length
|
42
|
+
end
|
43
|
+
|
44
|
+
def test_resets_expired_hosts_according_to_write_type_with_timeout
|
45
|
+
@config.default_hosts[1].up = false
|
46
|
+
@config.default_hosts[1].last_use = Time.new.utc - 1000
|
47
|
+
retry_strategy = Algolia::Transport::RetryStrategy.new(@config)
|
48
|
+
|
49
|
+
hosts = retry_strategy.get_tryable_hosts(WRITE)
|
50
|
+
assert_equal 3, hosts.length
|
51
|
+
end
|
52
|
+
|
53
|
+
def test_resets_all_hosts_when_expired_according_to_read_type
|
54
|
+
0.upto(2).map do |i|
|
55
|
+
@config.default_hosts[i].up = false
|
56
|
+
end
|
57
|
+
retry_strategy = Algolia::Transport::RetryStrategy.new(@config)
|
58
|
+
|
59
|
+
hosts = retry_strategy.get_tryable_hosts(READ)
|
60
|
+
assert_equal 3, hosts.length
|
61
|
+
end
|
62
|
+
|
63
|
+
def test_resets_all_hosts_when_expired_according_to_write_type
|
64
|
+
0.upto(2).map do |i|
|
65
|
+
@config.default_hosts[i].up = false
|
66
|
+
end
|
67
|
+
retry_strategy = Algolia::Transport::RetryStrategy.new(@config)
|
68
|
+
|
69
|
+
hosts = retry_strategy.get_tryable_hosts(WRITE)
|
70
|
+
assert_equal 3, hosts.length
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
describe 'All hosts are unreachable' do
|
75
|
+
def test_failure_when_all_hosts_are_down
|
76
|
+
stateful_hosts = ['0.0.0.0']
|
77
|
+
@config = Algolia::Search::Config.new(app_id: 'foo', api_key: 'bar', custom_hosts: stateful_hosts)
|
78
|
+
client = Algolia::Search::Client.create_with_config(@config)
|
79
|
+
index = client.init_index(get_test_index_name('failure'))
|
80
|
+
|
81
|
+
exception = assert_raises Algolia::AlgoliaUnreachableHostError do
|
82
|
+
index.save_object({ objectID: 'one' })
|
83
|
+
end
|
84
|
+
|
85
|
+
assert_equal 'Unreachable hosts', exception.message
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
describe 'retry stategy decisions' do
|
90
|
+
def before_all
|
91
|
+
super
|
92
|
+
@app_id = 'app_id'
|
93
|
+
@api_key = 'api_key'
|
94
|
+
@config = Algolia::Search::Config.new(app_id: @app_id, api_key: @api_key)
|
95
|
+
@retry_strategy = Algolia::Transport::RetryStrategy.new(@config)
|
96
|
+
@hosts = @retry_strategy.get_tryable_hosts(READ|WRITE)
|
97
|
+
end
|
98
|
+
|
99
|
+
def test_retry_decision_on_300
|
100
|
+
decision = @retry_strategy.decide(@hosts.first, http_response_code: 300)
|
101
|
+
assert_equal RETRY, decision
|
102
|
+
end
|
103
|
+
|
104
|
+
def test_retry_decision_on_500
|
105
|
+
retry_strategy = Algolia::Transport::RetryStrategy.new(@config)
|
106
|
+
|
107
|
+
decision = retry_strategy.decide(@hosts.first, http_response_code: 500)
|
108
|
+
assert_equal RETRY, decision
|
109
|
+
end
|
110
|
+
|
111
|
+
def test_retry_decision_on_timed_out
|
112
|
+
retry_strategy = Algolia::Transport::RetryStrategy.new(@config)
|
113
|
+
|
114
|
+
decision = retry_strategy.decide(@hosts.first, is_timed_out: true)
|
115
|
+
assert_equal RETRY, decision
|
116
|
+
end
|
117
|
+
|
118
|
+
def test_retry_decision_on_400
|
119
|
+
retry_strategy = Algolia::Transport::RetryStrategy.new(@config)
|
120
|
+
|
121
|
+
decision = retry_strategy.decide(@hosts.first, http_response_code: 400)
|
122
|
+
assert_equal FAILURE, decision
|
123
|
+
end
|
124
|
+
|
125
|
+
def test_retry_decision_on_404
|
126
|
+
retry_strategy = Algolia::Transport::RetryStrategy.new(@config)
|
127
|
+
|
128
|
+
decision = retry_strategy.decide(@hosts.first, http_response_code: 404)
|
129
|
+
assert_equal FAILURE, decision
|
130
|
+
end
|
131
|
+
|
132
|
+
def test_retry_decision_on_200
|
133
|
+
retry_strategy = Algolia::Transport::RetryStrategy.new(@config)
|
134
|
+
|
135
|
+
decision = retry_strategy.decide(@hosts.first, http_response_code: 200)
|
136
|
+
assert_equal SUCCESS, decision
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'algolia'
|
2
|
+
require 'test_helper'
|
3
|
+
|
4
|
+
class UserAgentTest
|
5
|
+
describe 'define user agent' do
|
6
|
+
def before_all
|
7
|
+
@default = "Algolia for Ruby (#{Algolia::VERSION}), Ruby (#{RUBY_VERSION})"
|
8
|
+
end
|
9
|
+
|
10
|
+
def test_add_user_agents
|
11
|
+
Algolia::UserAgent.add('Foo Bar', 'v1.0')
|
12
|
+
Algolia::UserAgent.add('Front Web', '2.0')
|
13
|
+
assert_equal(format('%<default>s; Foo Bar (v1.0); Front Web (2.0)', default: @default), Algolia::UserAgent.value)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,89 @@
|
|
1
|
+
require 'simplecov'
|
2
|
+
|
3
|
+
if ENV['COVERAGE']
|
4
|
+
SimpleCov.start
|
5
|
+
end
|
6
|
+
|
7
|
+
require 'bundler/setup'
|
8
|
+
require 'algolia'
|
9
|
+
require 'minitest/autorun'
|
10
|
+
require 'minitest/hooks'
|
11
|
+
require 'algolia/integration/mocks/mock_requester'
|
12
|
+
|
13
|
+
APPLICATION_ID_1 = ENV['ALGOLIA_APPLICATION_ID_1']
|
14
|
+
ADMIN_KEY_1 = ENV['ALGOLIA_ADMIN_KEY_1']
|
15
|
+
SEARCH_KEY_1 = ENV['ALGOLIA_SEARCH_KEY_1']
|
16
|
+
APPLICATION_ID_2 = ENV['ALGOLIA_APPLICATION_ID_2']
|
17
|
+
ADMIN_KEY_2 = ENV['ALGOLIA_ADMIN_KEY_2']
|
18
|
+
MCM_APPLICATION_ID = ENV['ALGOLIA_APPLICATION_ID_MCM']
|
19
|
+
MCM_ADMIN_KEY = ENV['ALGOLIA_ADMIN_KEY_MCM']
|
20
|
+
USER_AGENT = 'test-ruby'
|
21
|
+
|
22
|
+
class Minitest::Test
|
23
|
+
attr_reader :search_client
|
24
|
+
|
25
|
+
include Minitest::Hooks
|
26
|
+
include Helpers
|
27
|
+
@@search_config = Algolia::Search::Config.new(app_id: APPLICATION_ID_1, api_key: ADMIN_KEY_1, user_agent: USER_AGENT)
|
28
|
+
@@search_client = Algolia::Search::Client.new(@@search_config)
|
29
|
+
end
|
30
|
+
|
31
|
+
def check_environment_variables
|
32
|
+
raise Algolia::AlgoliaError, 'ALGOLIA_APPLICATION_ID_1 must be defined' if ENV['ALGOLIA_APPLICATION_ID_1'].to_s.strip.empty?
|
33
|
+
raise Algolia::AlgoliaError, 'ALGOLIA_ADMIN_KEY_1 must be defined' if ENV['ALGOLIA_ADMIN_KEY_1'].to_s.strip.empty?
|
34
|
+
raise Algolia::AlgoliaError, 'ALGOLIA_SEARCH_KEY_1 must be defined' if ENV['ALGOLIA_SEARCH_KEY_1'].to_s.strip.empty?
|
35
|
+
raise Algolia::AlgoliaError, 'ALGOLIA_APPLICATION_ID_2 must be defined' if ENV['ALGOLIA_APPLICATION_ID_2'].to_s.strip.empty?
|
36
|
+
raise Algolia::AlgoliaError, 'ALGOLIA_ADMIN_KEY_2 must be defined' if ENV['ALGOLIA_ADMIN_KEY_2'].to_s.strip.empty?
|
37
|
+
raise Algolia::AlgoliaError, 'ALGOLIA_APPLICATION_ID_MCM must be defined' if ENV['ALGOLIA_APPLICATION_ID_MCM'].to_s.strip.empty?
|
38
|
+
raise Algolia::AlgoliaError, 'ALGOLIA_ADMIN_KEY_MCM must be defined' if ENV['ALGOLIA_ADMIN_KEY_MCM'].to_s.strip.empty?
|
39
|
+
end
|
40
|
+
|
41
|
+
def get_test_index_name(name)
|
42
|
+
date = DateTime.now.strftime('%Y-%m-%d_%H_%M_%S')
|
43
|
+
user = ENV['USER'] || 'unknown'
|
44
|
+
|
45
|
+
instance = ENV['CI'].to_s == 'true' ? ENV['CIRCLE_BUILD_NUM'] : user
|
46
|
+
|
47
|
+
format('ruby_%<date>s_%<instance>s_%<name>s', date: date, instance: instance, name: name)
|
48
|
+
end
|
49
|
+
|
50
|
+
def get_mcm_user_name(user_id)
|
51
|
+
date = DateTime.now.strftime('%Y-%m-%d')
|
52
|
+
user = ENV['USER'] || 'unknown'
|
53
|
+
|
54
|
+
instance = ENV['CI'].to_s == 'true' ? ENV['CIRCLE_BUILD_NUM'] : user
|
55
|
+
|
56
|
+
format('ruby-%<date>s-%<instance>s-%<user_id>s', date: date, instance: instance, user_id: user_id)
|
57
|
+
end
|
58
|
+
|
59
|
+
def generate_object(object_id = nil)
|
60
|
+
object = { property: 'property' }
|
61
|
+
if object_id
|
62
|
+
object[:objectID] = object_id
|
63
|
+
end
|
64
|
+
|
65
|
+
object
|
66
|
+
end
|
67
|
+
|
68
|
+
def create_employee_records
|
69
|
+
[
|
70
|
+
{ company: 'Algolia', name: 'Julien Lemoine', objectID: 'julien-lemoine' },
|
71
|
+
{ company: 'Algolia', name: 'Nicolas Dessaigne', objectID: 'nicolas-dessaigne' },
|
72
|
+
{ company: 'Amazon', name: 'Jeff Bezos' },
|
73
|
+
{ company: 'Apple', name: 'Steve Jobs' },
|
74
|
+
{ company: 'Apple', name: 'Steve Wozniak' },
|
75
|
+
{ company: 'Arista Networks', name: 'Jayshree Ullal' },
|
76
|
+
{ company: 'Google', name: 'Larry Page' },
|
77
|
+
{ company: 'Google', name: 'Rob Pike' },
|
78
|
+
{ company: 'Google', name: 'Serguey Brin' },
|
79
|
+
{ company: 'Microsoft', name: 'Bill Gates' },
|
80
|
+
{ company: 'SpaceX', name: 'Elon Musk' },
|
81
|
+
{ company: 'Tesla', name: 'Elon Musk' },
|
82
|
+
{ company: 'Yahoo', name: 'Marissa Mayer' }
|
83
|
+
]
|
84
|
+
end
|
85
|
+
|
86
|
+
def rule_without_metadata(rule)
|
87
|
+
rule.delete(:_metadata)
|
88
|
+
rule
|
89
|
+
end
|
data/upgrade_guide.md
ADDED
@@ -0,0 +1,595 @@
|
|
1
|
+
# Upgrading to v2 of the Ruby API client
|
2
|
+
|
3
|
+
## Gem
|
4
|
+
First, you'll have to include the new version in your Gemfile. To do so, change the following:
|
5
|
+
|
6
|
+
```diff
|
7
|
+
- gem 'algoliasearch'
|
8
|
+
+ gem 'algolia', git: 'https://github.com/algolia/algoliasearch-client-ruby.git', tag: 'v2.0.0-alpha.1'
|
9
|
+
```
|
10
|
+
|
11
|
+
Then, you'll need to change your current `require` statements:
|
12
|
+
|
13
|
+
```diff
|
14
|
+
- require 'algoliasearch'
|
15
|
+
+ require 'algolia'
|
16
|
+
```
|
17
|
+
|
18
|
+
## Class names
|
19
|
+
All classes have been namespaced. The mostly used classes are now as follows:
|
20
|
+
|
21
|
+
- `Algolia::Client` -> `Algolia::Search::Client`
|
22
|
+
- `Algolia::Index` -> `Algolia::Search::Index`
|
23
|
+
- `Algolia::AccountClient` -> `Algolia::Account::Client`
|
24
|
+
- `Algolia::Analytics` -> `Algolia::Analytics::Client`
|
25
|
+
- `Algolia::Insights` -> `Algolia::Insights::Client`
|
26
|
+
|
27
|
+
## Initialize the client and index
|
28
|
+
There's a slight change in how you initialize the client. The index initialization didn't change.
|
29
|
+
```ruby
|
30
|
+
# Before
|
31
|
+
client = Algolia::Client.new(
|
32
|
+
application_id: 'APP_ID',
|
33
|
+
api_key: 'API_KEY'
|
34
|
+
)
|
35
|
+
index = client.init_index('index_name')
|
36
|
+
|
37
|
+
# After
|
38
|
+
client = Algolia::Search::Client.create('APP_ID', 'API_KEY')
|
39
|
+
index = client.init_index('index_name')
|
40
|
+
# or
|
41
|
+
search_config = Algolia::Search::Config.new(app_id: app_id, api_key: api_key)
|
42
|
+
client = Algolia::Search::Client.create_with_config(search_config)
|
43
|
+
index = client.init_index('index_name')
|
44
|
+
```
|
45
|
+
|
46
|
+
## Search parameters and request options
|
47
|
+
The search parameters and request options are still optional, but they are combined into a single hash instead of two.
|
48
|
+
For example:
|
49
|
+
```ruby
|
50
|
+
# Before
|
51
|
+
request_opts = { 'X-Algolia-UserToken': 'user123' }
|
52
|
+
search_params = { hitsPerPage: 50 }
|
53
|
+
|
54
|
+
index.search('query', search_params, request_opts)
|
55
|
+
|
56
|
+
# After
|
57
|
+
opts = {
|
58
|
+
:headers => {
|
59
|
+
'X-Algolia-UserToken': 'user123'
|
60
|
+
},
|
61
|
+
:params => {
|
62
|
+
hitsPerPage: 50
|
63
|
+
}
|
64
|
+
}
|
65
|
+
index.search('query', opts)
|
66
|
+
```
|
67
|
+
|
68
|
+
## Methods
|
69
|
+
|
70
|
+
### `Client`
|
71
|
+
|
72
|
+
#### `multiple_queries`
|
73
|
+
The `strategy` parameter is no longer a string, but a key in the `requestOptions`.
|
74
|
+
```ruby
|
75
|
+
queries = [
|
76
|
+
{ indexName: 'index_name1', params: { query: 'query', hitsPerPage: 2 } },
|
77
|
+
{ indexName: 'index_name2', params: { query: 'another_query', hitsPerPage: 5 } }
|
78
|
+
]
|
79
|
+
|
80
|
+
# Before
|
81
|
+
client.multiple_queries(queries, 'stopIfEnoughMatches')
|
82
|
+
|
83
|
+
# After
|
84
|
+
client.multiple_queries(queries, { strategy: 'stopIfEnoughMatches' })
|
85
|
+
```
|
86
|
+
|
87
|
+
#### `copy_settings`
|
88
|
+
No change.
|
89
|
+
|
90
|
+
#### `list_indexes`
|
91
|
+
No change.
|
92
|
+
|
93
|
+
#### `copy_index`
|
94
|
+
No change.
|
95
|
+
|
96
|
+
#### `move_index`
|
97
|
+
No change.
|
98
|
+
|
99
|
+
#### `generate_secured_api_key`
|
100
|
+
This method is moved to the `Algolia::Search::Client` class.
|
101
|
+
```ruby
|
102
|
+
# Before
|
103
|
+
secured_api_key = Algolia.generate_secured_api_key('api_key', {
|
104
|
+
validUntil: now - (10 * 60)
|
105
|
+
})
|
106
|
+
|
107
|
+
# After
|
108
|
+
secured_api_key = Algolia::Search::Client.generate_secured_api_key('api_key', {
|
109
|
+
validUntil: now - (10 * 60)
|
110
|
+
})
|
111
|
+
```
|
112
|
+
|
113
|
+
#### `add_api_key`
|
114
|
+
`acl` is still the first parameter. The other parameters have been moved to the `requestOptions`.
|
115
|
+
|
116
|
+
```ruby
|
117
|
+
# Before
|
118
|
+
client.add_api_key({ acl: ['search'], description: 'A description', indexes: ['index']})
|
119
|
+
|
120
|
+
# After
|
121
|
+
client.add_api_key(['search'], {
|
122
|
+
description: 'A description',
|
123
|
+
indexes: ['index']
|
124
|
+
})
|
125
|
+
```
|
126
|
+
|
127
|
+
#### `update_api_key`
|
128
|
+
This method is moved to the `Algolia::Search::Client` class.
|
129
|
+
```ruby
|
130
|
+
# Before
|
131
|
+
Algolia.update_api_key('api_key', { maxHitsPerQuery: 42 })
|
132
|
+
|
133
|
+
# After
|
134
|
+
client.update_api_key('api_key', { maxHitsPerQuery: 42 })
|
135
|
+
```
|
136
|
+
|
137
|
+
#### `delete_api_key`
|
138
|
+
No change.
|
139
|
+
|
140
|
+
#### `restore_api_key`
|
141
|
+
No change.
|
142
|
+
|
143
|
+
#### `get_api_key`
|
144
|
+
No change.
|
145
|
+
|
146
|
+
#### `list_api_keys`
|
147
|
+
No change.
|
148
|
+
|
149
|
+
#### `get_secured_api_key_remaining_validity`
|
150
|
+
This method is moved to the `Algolia::Search::Client` class.
|
151
|
+
```ruby
|
152
|
+
# Before
|
153
|
+
Algolia.get_secured_api_key_remaining_validity('api_key')
|
154
|
+
|
155
|
+
# After
|
156
|
+
Algolia::Search::Client.get_secured_api_key_remaining_validity('api_key')
|
157
|
+
```
|
158
|
+
|
159
|
+
#### `copy_synonyms`
|
160
|
+
No change.
|
161
|
+
|
162
|
+
#### `assign_user_id`
|
163
|
+
No change.
|
164
|
+
|
165
|
+
#### `assign_user_ids`
|
166
|
+
Newly added method to add multiple userIDs to a cluster.
|
167
|
+
```ruby
|
168
|
+
user_ids = ['1','2','3']
|
169
|
+
|
170
|
+
# Before
|
171
|
+
user_ids.each { |id| client.assign_user_id(id, 'my-cluster')}
|
172
|
+
|
173
|
+
# After
|
174
|
+
client.assign_user_ids(user_ids, 'my-cluster')
|
175
|
+
```
|
176
|
+
|
177
|
+
#### `get_top_user_id`
|
178
|
+
No change.
|
179
|
+
|
180
|
+
#### `get_user_id`
|
181
|
+
No change.
|
182
|
+
|
183
|
+
#### `list_clusters`
|
184
|
+
No change.
|
185
|
+
|
186
|
+
#### `list_user_ids`
|
187
|
+
The `page` and `hitsPerPage` parameters are now part of the `requestOptions`.
|
188
|
+
```ruby
|
189
|
+
# Before
|
190
|
+
page = 0
|
191
|
+
hits_per_page = 20
|
192
|
+
client.list_user_ids(page, hits_per_page)
|
193
|
+
|
194
|
+
# After
|
195
|
+
client.list_user_ids({ hitPerPage: 20, page: 0 })
|
196
|
+
```
|
197
|
+
|
198
|
+
#### `remove_user_id`
|
199
|
+
No change.
|
200
|
+
|
201
|
+
#### `search_user_ids`
|
202
|
+
The `clusterName`, `page` and `hitsPerPage` parameters are now part of the `requestOptions`.
|
203
|
+
```ruby
|
204
|
+
# Before
|
205
|
+
page = 0
|
206
|
+
hits_per_page = 12
|
207
|
+
client.search_user_ids('query', 'my-cluster', page, hits_per_page)
|
208
|
+
|
209
|
+
# After
|
210
|
+
client.search_user_ids('query', {clusterName: 'my-cluster', hitPerPage: 12, page: 0 })
|
211
|
+
```
|
212
|
+
|
213
|
+
#### `pending_mappings`
|
214
|
+
New method to check the status of your clusters' migration or user creation.
|
215
|
+
```ruby
|
216
|
+
client.pending_mapping?({ retrieveMappings: true })
|
217
|
+
```
|
218
|
+
|
219
|
+
#### `get_logs`
|
220
|
+
The `offset`, `length`, and `type` parameters are now part of the `requestOptions`.
|
221
|
+
```ruby
|
222
|
+
# Before
|
223
|
+
offset = 5
|
224
|
+
length = 100
|
225
|
+
puts client.get_logs(offset, length, 'all')
|
226
|
+
|
227
|
+
# After
|
228
|
+
client.get_logs({ offset: 5, length: 10, type: 'all' })
|
229
|
+
```
|
230
|
+
|
231
|
+
#### `copy_rules`
|
232
|
+
No change.
|
233
|
+
|
234
|
+
### `Index`
|
235
|
+
#### `search`
|
236
|
+
`searchParameters` and `requestOptions` are a single parameter now.
|
237
|
+
|
238
|
+
```ruby
|
239
|
+
# Before
|
240
|
+
request_opts = { 'X-Algolia-UserToken': 'user123' }
|
241
|
+
search_params = { hitsPerPage: 50 }
|
242
|
+
|
243
|
+
index.search('query', search_params, request_opts)
|
244
|
+
|
245
|
+
# After
|
246
|
+
opts = {
|
247
|
+
:headers => {
|
248
|
+
'X-Algolia-UserToken': 'user123'
|
249
|
+
},
|
250
|
+
:params => {
|
251
|
+
hitsPerPage: 50
|
252
|
+
}
|
253
|
+
}
|
254
|
+
index.search('query', opts)
|
255
|
+
```
|
256
|
+
|
257
|
+
#### `search_for_facet_values`
|
258
|
+
`searchParameters` and `requestOptions` are a single parameter now.
|
259
|
+
```ruby
|
260
|
+
# Before
|
261
|
+
request_opts = { 'X-Algolia-UserToken': 'user123' }
|
262
|
+
search_params = { hitsPerPage: 50 }
|
263
|
+
|
264
|
+
index.search_for_facet_values('category', 'phone', search_params, request_opts)
|
265
|
+
|
266
|
+
# After
|
267
|
+
opts = {
|
268
|
+
:headers => {
|
269
|
+
'X-Algolia-UserToken': 'user123'
|
270
|
+
},
|
271
|
+
:params => {
|
272
|
+
hitsPerPage: 50
|
273
|
+
}
|
274
|
+
}
|
275
|
+
index.search_for_facet_values('category', 'phone', opts)
|
276
|
+
```
|
277
|
+
|
278
|
+
#### `find_object`
|
279
|
+
The method takes a lambda, proc or block as the first argument (anything that responds to `call`), and the `requestOptions` as the second
|
280
|
+
```ruby
|
281
|
+
# Before
|
282
|
+
index.find_object({query: 'query', paginate: true}) { |hit| hit[:title].include?('algolia') }
|
283
|
+
|
284
|
+
# After
|
285
|
+
index.find_object(-> (hit) { hit[:title].include?('algolia') }, { query: 'query', paginate: true })
|
286
|
+
```
|
287
|
+
|
288
|
+
#### `get_object_position`
|
289
|
+
The classname has changed, not the method itself.
|
290
|
+
```ruby
|
291
|
+
# Before
|
292
|
+
position = Algolia::Index.get_object_position(results, 'object')
|
293
|
+
|
294
|
+
# After
|
295
|
+
position = Algolia::Search::Index.get_object_position(results, 'object')
|
296
|
+
```
|
297
|
+
|
298
|
+
#### `add_object` and `add_objects`
|
299
|
+
These methods have been removed in favor of `save_object` and `save_objects`.
|
300
|
+
|
301
|
+
#### `save_object` and `save_objects`
|
302
|
+
No change.
|
303
|
+
|
304
|
+
#### `partial_update_object`
|
305
|
+
The `objectID` parameter is removed. `create_if_not_exists` is now part of the `requestOptions` parameter.
|
306
|
+
|
307
|
+
```ruby
|
308
|
+
obj = { objectID: '1234', prop: 'value' }
|
309
|
+
|
310
|
+
# Before
|
311
|
+
create_if_not_exists = true
|
312
|
+
index.partial_update_object(obj, obj[:objectID], create_if_not_exists)
|
313
|
+
|
314
|
+
# After
|
315
|
+
index.partial_update_object(obj, { createIfNotExists: true })
|
316
|
+
```
|
317
|
+
|
318
|
+
#### `partial_update_objects`
|
319
|
+
The `create_if_not_exists` parameter is now part of the `requestOptions` parameter.
|
320
|
+
|
321
|
+
```ruby
|
322
|
+
# Before
|
323
|
+
create_if_not_exists = true
|
324
|
+
index.partial_update_objects(objects, create_if_not_exists)
|
325
|
+
|
326
|
+
# After
|
327
|
+
index.partial_update_objects(objects, { createIfNotExists: true })
|
328
|
+
```
|
329
|
+
|
330
|
+
#### `delete_object` and `delete_objects`
|
331
|
+
No change.
|
332
|
+
|
333
|
+
#### `replace_all_objects`
|
334
|
+
No change.
|
335
|
+
|
336
|
+
#### `delete_by`
|
337
|
+
No change.
|
338
|
+
|
339
|
+
#### `clear_index`
|
340
|
+
Renamed to `clear_objects`.
|
341
|
+
```ruby
|
342
|
+
# Before
|
343
|
+
index.clear_index
|
344
|
+
|
345
|
+
# After
|
346
|
+
index.clear_objects
|
347
|
+
```
|
348
|
+
|
349
|
+
#### `get_object` and `get_objects`
|
350
|
+
The `attributesToRetrieve` parameter is now part of the `requestOptions`.
|
351
|
+
```ruby
|
352
|
+
# Before
|
353
|
+
index.get_object('1234', ['title'])
|
354
|
+
index.get_objects([1,2,3], ['title'])
|
355
|
+
|
356
|
+
# After
|
357
|
+
index.get_object('1234', { attributesToRetrieve: ['title'] })
|
358
|
+
index.get_objects([1,2,3], { attributesToRetrieve: ['title'] })
|
359
|
+
```
|
360
|
+
|
361
|
+
#### `multiple_get_objects`
|
362
|
+
No change.
|
363
|
+
|
364
|
+
#### `batch`
|
365
|
+
No change.
|
366
|
+
|
367
|
+
#### `get_settings`
|
368
|
+
No change.
|
369
|
+
|
370
|
+
#### `set_settings`
|
371
|
+
No change.
|
372
|
+
|
373
|
+
#### `delete_index`
|
374
|
+
Instead of calling the `delete_index` method on the client, you should call the `delete` method directly on the index object.
|
375
|
+
|
376
|
+
```ruby
|
377
|
+
# Before
|
378
|
+
client.delete_index('foo')
|
379
|
+
|
380
|
+
# After
|
381
|
+
index.delete
|
382
|
+
```
|
383
|
+
|
384
|
+
#### `browse`
|
385
|
+
Renamed to `browse_objects`.
|
386
|
+
```ruby
|
387
|
+
# Before
|
388
|
+
request_opts = { 'X-Algolia-UserToken': 'user123' }
|
389
|
+
index.browse({ query: 'query'}, nil, request_opts) do |hit|
|
390
|
+
puts hit
|
391
|
+
end
|
392
|
+
|
393
|
+
# After
|
394
|
+
opts = {
|
395
|
+
query: 'query',
|
396
|
+
headers: { 'X-Algolia-UserToken': 'user123' }
|
397
|
+
}
|
398
|
+
index.browse_objects(opts) do |hit|
|
399
|
+
puts hit
|
400
|
+
end
|
401
|
+
```
|
402
|
+
|
403
|
+
#### `index.exists?`
|
404
|
+
No change.
|
405
|
+
|
406
|
+
#### `save_synonym`
|
407
|
+
The `objectID` parameter has been removed, and should be part of the synonym hash.
|
408
|
+
```ruby
|
409
|
+
# Before
|
410
|
+
forward_to_replicas = true
|
411
|
+
index.save_synonym('one', { objectID: 'one', type: 'synonym', synonyms: %w(one two) }, forward_to_replicas)
|
412
|
+
|
413
|
+
# After
|
414
|
+
index.save_synonym({ objectID: 'one', type: 'synonym', synonyms: %w(one two) }, { forwardToReplicas: true})
|
415
|
+
```
|
416
|
+
|
417
|
+
#### `batch_synonyms`
|
418
|
+
Renamed to `save_synonyms`. `forwardToReplicas` and `replaceExistingSynonyms` parmameters are now part of `requestOptions`.
|
419
|
+
```ruby
|
420
|
+
# Before
|
421
|
+
forward_to_replicas = true
|
422
|
+
replace_existing_synonyms = true
|
423
|
+
index.batch_synonyms(synonyms, forward_to_replicas, replace_existing_synonyms)
|
424
|
+
# After
|
425
|
+
index.save_synonyms(synonyms, { forwardToReplicas: true, replaceExistingSynonyms: true })
|
426
|
+
```
|
427
|
+
|
428
|
+
#### `delete_synonym`
|
429
|
+
No change.
|
430
|
+
|
431
|
+
#### `clear_synonyms`
|
432
|
+
No change.
|
433
|
+
|
434
|
+
#### `get_synonym`
|
435
|
+
No change.
|
436
|
+
|
437
|
+
#### `search_synonyms`
|
438
|
+
No change.
|
439
|
+
|
440
|
+
#### `replace_all_synonyms`
|
441
|
+
No change.
|
442
|
+
|
443
|
+
#### `export_synonyms`
|
444
|
+
Renamed to `browse_synonyms`.
|
445
|
+
```ruby
|
446
|
+
# Before
|
447
|
+
synonyms = index.export_synonyms
|
448
|
+
|
449
|
+
# After
|
450
|
+
synonyms = index.browse_synonyms
|
451
|
+
```
|
452
|
+
|
453
|
+
#### `save_rule`
|
454
|
+
The `objectID` parameter has been removed, and should be part of the Rule object.
|
455
|
+
```ruby
|
456
|
+
# Before
|
457
|
+
index.save_rule('unique-id', {
|
458
|
+
objectID: 'unique-id',
|
459
|
+
condition: { anchoring: 'is', pattern: 'pattern' },
|
460
|
+
consequence: {
|
461
|
+
params: {
|
462
|
+
query: {
|
463
|
+
edits: [
|
464
|
+
{ type: 'remove', delete: 'pattern' }
|
465
|
+
]
|
466
|
+
}
|
467
|
+
}
|
468
|
+
}
|
469
|
+
})
|
470
|
+
|
471
|
+
# After
|
472
|
+
index.save_rule({
|
473
|
+
objectID: 'unique-id',
|
474
|
+
condition: { anchoring: 'is', pattern: 'pattern' },
|
475
|
+
consequence: {
|
476
|
+
params: {
|
477
|
+
query: {
|
478
|
+
edits: [
|
479
|
+
{ type: 'remove', delete: 'pattern' }
|
480
|
+
]
|
481
|
+
}
|
482
|
+
}
|
483
|
+
}
|
484
|
+
})
|
485
|
+
```
|
486
|
+
|
487
|
+
#### `batch_rules`
|
488
|
+
Renamed to `save_rules`. The `forwardToReplicas` and `clearExistingRules` parameters should now be part of the `requestOptions`.
|
489
|
+
```ruby
|
490
|
+
# Before
|
491
|
+
forward_to_replicas = true
|
492
|
+
clear_existing_rules = true
|
493
|
+
index.batch_rules(rules, forward_to_replicas, clear_existing_rules)
|
494
|
+
|
495
|
+
# After
|
496
|
+
index.save_rules(rules, { forwardToReplicas: true, clearExistingRules: true })
|
497
|
+
```
|
498
|
+
|
499
|
+
#### `get_rule`
|
500
|
+
No change.
|
501
|
+
|
502
|
+
#### `delete_rule`
|
503
|
+
The `forwardToReplicas` parameter is now part of the `requestOptions`.
|
504
|
+
```ruby
|
505
|
+
# Before
|
506
|
+
forward_to_replicas = true
|
507
|
+
index.delete_rule('rule-id', forward_to_replicas)
|
508
|
+
|
509
|
+
# After
|
510
|
+
index.delete_rule('rule-id', { forwardToReplicas: true })
|
511
|
+
```
|
512
|
+
|
513
|
+
#### `clear_rules`
|
514
|
+
The `forwardToReplicas` parameter is now part of the `requestOptions`.
|
515
|
+
```ruby
|
516
|
+
# Before
|
517
|
+
forward_to_replicas = true
|
518
|
+
index.clear_rules(forward_to_replicas)
|
519
|
+
|
520
|
+
# After
|
521
|
+
index.clear_rules({ forwardToReplicas: true })
|
522
|
+
```
|
523
|
+
|
524
|
+
#### `search_rules`
|
525
|
+
No change.
|
526
|
+
|
527
|
+
#### `replace_all_rules`
|
528
|
+
No change.
|
529
|
+
|
530
|
+
#### `export_rules`
|
531
|
+
Renamed to `browse_rules`.
|
532
|
+
|
533
|
+
### `AnalyticsClient`
|
534
|
+
#### `add_ab_test`
|
535
|
+
No change.
|
536
|
+
|
537
|
+
#### `get_ab_test`
|
538
|
+
No change.
|
539
|
+
|
540
|
+
#### `get_ab_tests`
|
541
|
+
No change.
|
542
|
+
|
543
|
+
#### `stop_ab_test`
|
544
|
+
No change.
|
545
|
+
|
546
|
+
#### `delete_ab_test`
|
547
|
+
No change.
|
548
|
+
|
549
|
+
### `InsightsClient`
|
550
|
+
#### `clicked_object_ids_after_search`
|
551
|
+
No change.
|
552
|
+
|
553
|
+
#### `clicked_object_ids`
|
554
|
+
No change.
|
555
|
+
|
556
|
+
#### `clicked_filters`
|
557
|
+
No change.
|
558
|
+
|
559
|
+
#### `converted_object_ids_after_search`
|
560
|
+
No change.
|
561
|
+
|
562
|
+
#### `converted_object_ids`
|
563
|
+
No change.
|
564
|
+
|
565
|
+
#### `converted_filters`
|
566
|
+
No change.
|
567
|
+
|
568
|
+
#### `viewed_object_ids`
|
569
|
+
No change.
|
570
|
+
|
571
|
+
#### `viewed_filters`
|
572
|
+
No change.
|
573
|
+
|
574
|
+
### `RecommendationClient`
|
575
|
+
#### `set_personalization_strategy`
|
576
|
+
This new method is available on the `Algolia::Recommendation::Client` class.
|
577
|
+
|
578
|
+
#### `set_personalization_strategy`
|
579
|
+
This new method is available on the `Algolia::Recommendation::Client` class.
|
580
|
+
|
581
|
+
## Configuring timeouts
|
582
|
+
You can configure timeouts by passing a custom `Algolia::Search::Config` object to the constructor of your client.
|
583
|
+
```ruby
|
584
|
+
# Before
|
585
|
+
client = Algolia::Client.new({
|
586
|
+
application_id: 'app_id',
|
587
|
+
api_key: 'api_key',
|
588
|
+
connect_timeout: 2,
|
589
|
+
receive_timeout: 10,
|
590
|
+
})
|
591
|
+
|
592
|
+
# After
|
593
|
+
search_config = Algolia::Search::Config.new(app_id: 'app_id', api_key: 'api_key', read_timeout: 10, connect_timeout: 2)
|
594
|
+
client = Algolia::Search::Client.create_with_config(search_config)
|
595
|
+
```
|