algolia 2.0.0.pre.alpha.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|