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
data/sig/helpers.rbs
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
module Helpers
|
2
|
+
|
3
|
+
def to_json: (String|Hash[Symbol, String] body) -> String
|
4
|
+
def symbolize_hash: (Hash[Symbol|String, untyped] hash) -> Hash[Symbol, untyped]
|
5
|
+
def handle_params: (Hash[Symbol, String] params) -> String
|
6
|
+
def to_query_string: (Hash[Symbol, String] params) -> String
|
7
|
+
def json_to_hash: (String json, bool symbolize_keys) -> Hash[Symbol, String]
|
8
|
+
def get_option: ([Symbol|String, String] hash, String key) -> (String | [String])
|
9
|
+
def path_encode: (String path, *String args) -> String
|
10
|
+
def deserialize_settings: (Hash[Symbol|String, String] data) -> Hash[Symbol, String]
|
11
|
+
def self.included: (self base) -> self
|
12
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Algolia
|
2
|
+
module Http
|
3
|
+
class HttpRequester
|
4
|
+
attr_accessor adapter: String
|
5
|
+
|
6
|
+
attr_accessor logger: Logger
|
7
|
+
|
8
|
+
def initialize: (String adapter, Logger logger) -> void
|
9
|
+
|
10
|
+
def send_request: (Algolia::Transport::StatefulHost host, Symbol method, String path, Hash[Symbol|String, untyped] body, Hash[String|Symbol, String|bool] headers, Integer timeout, Integer connect_timeout) -> Algolia::Http::Response
|
11
|
+
|
12
|
+
def connection: (Algolia::Transport::StatefulHost host) -> _Connection
|
13
|
+
|
14
|
+
def build_url: (Algolia::Transport::StatefulHost host) -> String
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module Algolia
|
2
|
+
module Http
|
3
|
+
class Response
|
4
|
+
attr_reader status: String
|
5
|
+
attr_reader body: String
|
6
|
+
attr_reader error: String
|
7
|
+
attr_reader headers: String
|
8
|
+
attr_reader has_timed_out: bool
|
9
|
+
attr_reader network_failure: bool
|
10
|
+
|
11
|
+
def initialize: (?::Hash[Symbol, String|bool] opts) -> untyped
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
interface _Connection
|
2
|
+
|
3
|
+
def options: () -> _ConnectionOptions
|
4
|
+
|
5
|
+
def run_request: (Symbol method, String path, Hash[Symbol, String|[String]] body, Hash[String, String] headers) -> Http::Response
|
6
|
+
|
7
|
+
end
|
8
|
+
|
9
|
+
interface _ConnectionOptions
|
10
|
+
|
11
|
+
def timeout: () -> Integer
|
12
|
+
def timeout=: (Integer timeout) -> Integer
|
13
|
+
def open_timeout: () -> Integer
|
14
|
+
def open_timeout=: (Integer timeout) -> Integer
|
15
|
+
|
16
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Algolia
|
2
|
+
class BaseIterator
|
3
|
+
include Helpers
|
4
|
+
#TODO: double check Enumerable
|
5
|
+
include Enumerable[Hash[Symbol, String|[String]], void]
|
6
|
+
|
7
|
+
# TODO: add Transporter
|
8
|
+
attr_reader transporter: untyped
|
9
|
+
attr_reader index_name: String
|
10
|
+
attr_reader opts: Hash[Symbol, String|[String]]
|
11
|
+
|
12
|
+
# TODO: add Transporter
|
13
|
+
def initialize: (untyped transporter, String index_name, Hash[Symbol, String|[String]] opts) -> void
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,8 @@
|
|
1
|
+
module Algolia
|
2
|
+
class PaginatorIterator < BaseIterator
|
3
|
+
# TODO: type transporter
|
4
|
+
def initialize: (untyped transporter, String index_name, Hash[Symbol, String|[String]] opts) -> bool
|
5
|
+
def each: () { (Hash[Symbol, String|[String]]) -> void } -> Hash[Symbol, String|[String]]
|
6
|
+
def get_endpoint: () -> String
|
7
|
+
end
|
8
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Algolia
|
2
|
+
module Transport
|
3
|
+
class RequestOptions
|
4
|
+
attr_accessor headers: Hash[Symbol|String, String]
|
5
|
+
|
6
|
+
attr_accessor params: Hash[Symbol|String, untyped]
|
7
|
+
|
8
|
+
attr_accessor data: Hash[Symbol|String, untyped]
|
9
|
+
|
10
|
+
attr_accessor timeout: Integer
|
11
|
+
|
12
|
+
attr_accessor connect_timeout: Integer
|
13
|
+
|
14
|
+
attr_accessor compression_type: String
|
15
|
+
|
16
|
+
def initialize: (Algolia::Search::Config config) -> void
|
17
|
+
|
18
|
+
def create: (?::Hash[Symbol|String, untyped] opts) -> void
|
19
|
+
|
20
|
+
def add_headers: (?::Hash[Symbol|String, untyped] opts) -> void
|
21
|
+
|
22
|
+
def add_params: (?::Hash[Symbol|String, untyped] opts) -> void
|
23
|
+
|
24
|
+
def add_timeout: (?::Hash[Symbol|String, untyped] opts) -> void
|
25
|
+
|
26
|
+
def add_connect_timeout: (?::Hash[Symbol|String, untyped] opts) -> void
|
27
|
+
|
28
|
+
def add_compression_type: (?::Hash[Symbol|String, untyped] opts) -> void
|
29
|
+
|
30
|
+
def add_data_body: (?::Hash[Symbol|String, untyped] opts) -> void
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Algolia
|
2
|
+
module Transport
|
3
|
+
class StatefulHost
|
4
|
+
include CallType
|
5
|
+
|
6
|
+
attr_reader url: untyped
|
7
|
+
|
8
|
+
attr_reader protocol: untyped
|
9
|
+
|
10
|
+
attr_reader accept: untyped
|
11
|
+
|
12
|
+
attr_accessor last_use: untyped
|
13
|
+
|
14
|
+
attr_accessor retry_count: untyped
|
15
|
+
|
16
|
+
attr_accessor up: untyped
|
17
|
+
|
18
|
+
def initialize: (String url, ?::Hash[Symbol|String, untyped] opts) -> void
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require_relative 'base_test'
|
2
|
+
|
3
|
+
class AccountClientTest < BaseTest
|
4
|
+
describe 'Account client' do
|
5
|
+
def test_account_client
|
6
|
+
index1 = @@search_client.init_index(get_test_index_name('copy_index'))
|
7
|
+
index2 = @@search_client.init_index(get_test_index_name('copy_index2'))
|
8
|
+
|
9
|
+
exception = assert_raises Algolia::AlgoliaError do
|
10
|
+
Algolia::Account::Client.copy_index(index1, index2)
|
11
|
+
end
|
12
|
+
|
13
|
+
assert_equal 'The indices are on the same application. Use Algolia::Search::Client.copy_index instead.', exception.message
|
14
|
+
|
15
|
+
search_client2 = Algolia::Search::Client.create(APPLICATION_ID_2, ADMIN_KEY_2)
|
16
|
+
index2 = search_client2.init_index(get_test_index_name('copy_index2'))
|
17
|
+
index1.save_object!({ objectID: 'one' })
|
18
|
+
index1.save_rule!({
|
19
|
+
objectID: 'one',
|
20
|
+
condition: { anchoring: 'is', pattern: 'pattern' },
|
21
|
+
consequence: {
|
22
|
+
params: {
|
23
|
+
query: {
|
24
|
+
edits: [
|
25
|
+
{ type: 'remove', delete: 'pattern' }
|
26
|
+
]
|
27
|
+
}
|
28
|
+
}
|
29
|
+
}
|
30
|
+
})
|
31
|
+
index1.save_synonym!({ objectID: 'one', type: 'synonym', synonyms: %w(one two) })
|
32
|
+
index1.set_settings!({ searchableAttributes: ['objectID'] })
|
33
|
+
|
34
|
+
Algolia::Account::Client.copy_index!(index1, index2)
|
35
|
+
assert_equal 'one', index2.get_object('one')[:objectID]
|
36
|
+
assert_equal 'one', index2.get_synonym('one')[:objectID]
|
37
|
+
assert_equal 'one', index2.get_rule('one')[:objectID]
|
38
|
+
assert index2.get_settings[:searchableAttributes]
|
39
|
+
|
40
|
+
exception = assert_raises Algolia::AlgoliaError do
|
41
|
+
Algolia::Account::Client.copy_index(index1, index2)
|
42
|
+
end
|
43
|
+
|
44
|
+
assert_equal 'Destination index already exists. Please delete it before copying index across applications.', exception.message
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,113 @@
|
|
1
|
+
require_relative 'base_test'
|
2
|
+
require 'date'
|
3
|
+
|
4
|
+
class AnalyticsClientTest < BaseTest
|
5
|
+
describe 'Analytics client' do
|
6
|
+
def test_ab_testing
|
7
|
+
index1 = @@search_client.init_index(get_test_index_name('ab_testing'))
|
8
|
+
index2 = @@search_client.init_index(get_test_index_name('ab_testing_dev'))
|
9
|
+
client = Algolia::Analytics::Client.create(APPLICATION_ID_1, ADMIN_KEY_1)
|
10
|
+
|
11
|
+
index1.save_object!({ objectID: 'one' })
|
12
|
+
index2.save_object!({ objectID: 'one' })
|
13
|
+
|
14
|
+
ab_test_name = index1.index_name
|
15
|
+
tomorrow = Time.now + 24*60*60
|
16
|
+
|
17
|
+
ab_test = {
|
18
|
+
name: ab_test_name,
|
19
|
+
variants: [
|
20
|
+
{ index: index1.index_name, trafficPercentage: 60, description: 'a description' },
|
21
|
+
{ index: index2.index_name, trafficPercentage: 40 }
|
22
|
+
],
|
23
|
+
endAt: tomorrow.strftime('%Y-%m-%dT%H:%M:%SZ')
|
24
|
+
}
|
25
|
+
|
26
|
+
response = client.add_ab_test(ab_test)
|
27
|
+
ab_test_id = response[:abTestID]
|
28
|
+
|
29
|
+
index1.wait_task(response[:taskID])
|
30
|
+
result = client.get_ab_test(ab_test_id)
|
31
|
+
|
32
|
+
assert_equal ab_test[:name], result[:name]
|
33
|
+
assert_equal ab_test[:variants][0][:index], result[:variants][0][:index]
|
34
|
+
assert_equal ab_test[:variants][0][:trafficPercentage], result[:variants][0][:trafficPercentage]
|
35
|
+
assert_equal ab_test[:variants][0][:description], result[:variants][0][:description]
|
36
|
+
assert_equal ab_test[:endAt], result[:endAt]
|
37
|
+
refute_equal 'stopped', result[:status]
|
38
|
+
|
39
|
+
ab_tests = client.get_ab_tests
|
40
|
+
found = false
|
41
|
+
ab_tests[:abtests].each do |iterated_ab_test|
|
42
|
+
if iterated_ab_test[:name] == ab_test_name
|
43
|
+
assert_equal ab_test[:name], iterated_ab_test[:name]
|
44
|
+
assert_equal ab_test[:variants][0][:index], iterated_ab_test[:variants][0][:index]
|
45
|
+
assert_equal ab_test[:variants][0][:trafficPercentage], iterated_ab_test[:variants][0][:trafficPercentage]
|
46
|
+
assert_equal ab_test[:variants][0][:description], iterated_ab_test[:variants][0][:description]
|
47
|
+
assert_equal ab_test[:endAt], iterated_ab_test[:endAt]
|
48
|
+
refute_equal 'stopped', iterated_ab_test[:status]
|
49
|
+
found = true
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
assert found
|
54
|
+
|
55
|
+
response = client.stop_ab_test(ab_test_id)
|
56
|
+
index1.wait_task(response[:taskID])
|
57
|
+
result = client.get_ab_test(ab_test_id)
|
58
|
+
assert_equal 'stopped', result[:status]
|
59
|
+
|
60
|
+
response = client.delete_ab_test(ab_test_id)
|
61
|
+
index1.wait_task(response[:taskID])
|
62
|
+
|
63
|
+
exception = assert_raises Algolia::AlgoliaHttpError do
|
64
|
+
client.get_ab_test(ab_test_id)
|
65
|
+
end
|
66
|
+
|
67
|
+
assert_equal 404, exception.code
|
68
|
+
assert_equal 'ABTestID not found', exception.message
|
69
|
+
end
|
70
|
+
|
71
|
+
def test_aa_testing
|
72
|
+
index = @@search_client.init_index(get_test_index_name('aa_testing'))
|
73
|
+
client = Algolia::Analytics::Client.create(APPLICATION_ID_1, ADMIN_KEY_1)
|
74
|
+
|
75
|
+
index.save_object!({ objectID: 'one' })
|
76
|
+
|
77
|
+
ab_test_name = index.index_name
|
78
|
+
tomorrow = Time.now + 24*60*60
|
79
|
+
|
80
|
+
ab_test = {
|
81
|
+
name: ab_test_name,
|
82
|
+
variants: [
|
83
|
+
{ index: index.index_name, trafficPercentage: 90 },
|
84
|
+
{ index: index.index_name, trafficPercentage: 10, customSearchParameters: { ignorePlurals: true } }
|
85
|
+
],
|
86
|
+
endAt: tomorrow.strftime('%Y-%m-%dT%H:%M:%SZ')
|
87
|
+
}
|
88
|
+
|
89
|
+
response = client.add_ab_test(ab_test)
|
90
|
+
ab_test_id = response[:abTestID]
|
91
|
+
|
92
|
+
index.wait_task(response[:taskID])
|
93
|
+
result = client.get_ab_test(ab_test_id)
|
94
|
+
|
95
|
+
assert_equal ab_test[:name], result[:name]
|
96
|
+
assert_equal ab_test[:variants][0][:index], result[:variants][0][:index]
|
97
|
+
assert_equal ab_test[:variants][0][:trafficPercentage], result[:variants][0][:trafficPercentage]
|
98
|
+
assert_equal ab_test[:variants][1][:customSearchParameters], result[:variants][1][:customSearchParameters]
|
99
|
+
assert_equal ab_test[:endAt], result[:endAt]
|
100
|
+
refute_equal 'stopped', result[:status]
|
101
|
+
|
102
|
+
response = client.delete_ab_test(ab_test_id)
|
103
|
+
index.wait_task(response[:taskID])
|
104
|
+
|
105
|
+
exception = assert_raises Algolia::AlgoliaHttpError do
|
106
|
+
client.get_ab_test(ab_test_id)
|
107
|
+
end
|
108
|
+
|
109
|
+
assert_equal 404, exception.code
|
110
|
+
assert_equal 'ABTestID not found', exception.message
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
require_relative 'base_test'
|
2
|
+
require 'date'
|
3
|
+
|
4
|
+
class InsightsClientTest < BaseTest
|
5
|
+
describe 'Insights client' do
|
6
|
+
def test_insights_client
|
7
|
+
index = @@search_client.init_index(get_test_index_name('sending_events'))
|
8
|
+
client = Algolia::Insights::Client.create(APPLICATION_ID_1, ADMIN_KEY_1)
|
9
|
+
|
10
|
+
index.save_objects!([
|
11
|
+
{ objectID: 'one' },
|
12
|
+
{ objectID: 'two' }
|
13
|
+
])
|
14
|
+
|
15
|
+
today = Date.today
|
16
|
+
|
17
|
+
client.send_event({
|
18
|
+
eventType: 'click',
|
19
|
+
eventName: 'foo',
|
20
|
+
index: index.index_name,
|
21
|
+
userToken: 'bar',
|
22
|
+
objectIDs: %w(one two),
|
23
|
+
timestamp: (today - 2).strftime('%Q').to_i
|
24
|
+
})
|
25
|
+
|
26
|
+
client.send_events([
|
27
|
+
{
|
28
|
+
eventType: 'click',
|
29
|
+
eventName: 'foo',
|
30
|
+
index: index.index_name,
|
31
|
+
userToken: 'bar',
|
32
|
+
objectIDs: %w(one two),
|
33
|
+
timestamp: (today - 2).strftime('%Q').to_i
|
34
|
+
}, {
|
35
|
+
eventType: 'click',
|
36
|
+
eventName: 'foo',
|
37
|
+
index: index.index_name,
|
38
|
+
userToken: 'bar',
|
39
|
+
objectIDs: %w(one two),
|
40
|
+
timestamp: (today - 2).strftime('%Q').to_i
|
41
|
+
}
|
42
|
+
])
|
43
|
+
|
44
|
+
user_client = client.user('bar')
|
45
|
+
response = user_client.clicked_object_ids('foo', index.index_name, %w(one two))
|
46
|
+
assert_equal 200, response[:status]
|
47
|
+
assert_equal 'OK', response[:message]
|
48
|
+
|
49
|
+
query_id = index.search('', { clickAnalytics: true })[:queryID]
|
50
|
+
|
51
|
+
response = user_client.clicked_object_ids_after_search('foo', index.index_name, %w(one two), [1, 2], query_id)
|
52
|
+
assert_equal 200, response[:status]
|
53
|
+
assert_equal 'OK', response[:message]
|
54
|
+
|
55
|
+
response = user_client.clicked_filters('foo', index.index_name, %w(filter:foo filter:bar))
|
56
|
+
assert_equal 200, response[:status]
|
57
|
+
assert_equal 'OK', response[:message]
|
58
|
+
|
59
|
+
response = user_client.converted_object_ids('foo', index.index_name, %w(one two))
|
60
|
+
assert_equal 200, response[:status]
|
61
|
+
assert_equal 'OK', response[:message]
|
62
|
+
|
63
|
+
response = user_client.converted_object_ids_after_search('foo', index.index_name, %w(one two), query_id)
|
64
|
+
assert_equal 200, response[:status]
|
65
|
+
assert_equal 'OK', response[:message]
|
66
|
+
|
67
|
+
response = user_client.converted_filters('foo', index.index_name, %w(filter:foo filter:bar))
|
68
|
+
assert_equal 200, response[:status]
|
69
|
+
assert_equal 'OK', response[:message]
|
70
|
+
|
71
|
+
response = user_client.viewed_object_ids('foo', index.index_name, %w(one two))
|
72
|
+
assert_equal 200, response[:status]
|
73
|
+
assert_equal 'OK', response[:message]
|
74
|
+
|
75
|
+
response = user_client.viewed_filters('foo', index.index_name, %w(filter:foo filter:bar))
|
76
|
+
assert_equal 200, response[:status]
|
77
|
+
assert_equal 'OK', response[:message]
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|