algolia 2.0.0.pre.alpha.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (86) hide show
  1. checksums.yaml +7 -0
  2. data/.circleci/config.yml +146 -0
  3. data/.github/ISSUE_TEMPLATE.md +20 -0
  4. data/.github/PULL_REQUEST_TEMPLATE.md +22 -0
  5. data/.gitignore +38 -0
  6. data/.rubocop.yml +186 -0
  7. data/.rubocop_todo.yml +14 -0
  8. data/CODE_OF_CONDUCT.md +74 -0
  9. data/Gemfile +18 -0
  10. data/LICENSE +21 -0
  11. data/README.md +56 -0
  12. data/Rakefile +45 -0
  13. data/Steepfile +6 -0
  14. data/algolia.gemspec +41 -0
  15. data/bin/console +21 -0
  16. data/bin/setup +8 -0
  17. data/lib/algolia.rb +42 -0
  18. data/lib/algolia/account_client.rb +65 -0
  19. data/lib/algolia/analytics_client.rb +105 -0
  20. data/lib/algolia/config/algolia_config.rb +40 -0
  21. data/lib/algolia/config/analytics_config.rb +20 -0
  22. data/lib/algolia/config/insights_config.rb +20 -0
  23. data/lib/algolia/config/recommendation_config.rb +20 -0
  24. data/lib/algolia/config/search_config.rb +40 -0
  25. data/lib/algolia/defaults.rb +35 -0
  26. data/lib/algolia/enums/call_type.rb +4 -0
  27. data/lib/algolia/enums/retry_outcome_type.rb +5 -0
  28. data/lib/algolia/error.rb +29 -0
  29. data/lib/algolia/helpers.rb +83 -0
  30. data/lib/algolia/http/http_requester.rb +84 -0
  31. data/lib/algolia/http/response.rb +23 -0
  32. data/lib/algolia/insights_client.rb +238 -0
  33. data/lib/algolia/iterators/base_iterator.rb +19 -0
  34. data/lib/algolia/iterators/object_iterator.rb +27 -0
  35. data/lib/algolia/iterators/paginator_iterator.rb +44 -0
  36. data/lib/algolia/iterators/rule_iterator.rb +9 -0
  37. data/lib/algolia/iterators/synonym_iterator.rb +9 -0
  38. data/lib/algolia/logger_helper.rb +14 -0
  39. data/lib/algolia/recommendation_client.rb +60 -0
  40. data/lib/algolia/responses/add_api_key_response.rb +38 -0
  41. data/lib/algolia/responses/base_response.rb +9 -0
  42. data/lib/algolia/responses/delete_api_key_response.rb +40 -0
  43. data/lib/algolia/responses/indexing_response.rb +28 -0
  44. data/lib/algolia/responses/multiple_batch_indexing_response.rb +29 -0
  45. data/lib/algolia/responses/multiple_response.rb +45 -0
  46. data/lib/algolia/responses/restore_api_key_response.rb +36 -0
  47. data/lib/algolia/responses/update_api_key_response.rb +39 -0
  48. data/lib/algolia/search_client.rb +614 -0
  49. data/lib/algolia/search_index.rb +1094 -0
  50. data/lib/algolia/transport/request_options.rb +94 -0
  51. data/lib/algolia/transport/retry_strategy.rb +117 -0
  52. data/lib/algolia/transport/stateful_host.rb +26 -0
  53. data/lib/algolia/transport/transport.rb +161 -0
  54. data/lib/algolia/user_agent.rb +25 -0
  55. data/lib/algolia/version.rb +3 -0
  56. data/sig/config/algolia_config.rbs +24 -0
  57. data/sig/config/analytics_config.rbs +11 -0
  58. data/sig/config/insights_config.rbs +11 -0
  59. data/sig/config/recommendation_config.rbs +11 -0
  60. data/sig/config/search_config.rbs +11 -0
  61. data/sig/enums/call_type.rbs +5 -0
  62. data/sig/helpers.rbs +12 -0
  63. data/sig/http/http_requester.rbs +17 -0
  64. data/sig/http/response.rbs +14 -0
  65. data/sig/interfaces/_connection.rbs +16 -0
  66. data/sig/iterators/base_iterator.rbs +15 -0
  67. data/sig/iterators/object_iterator.rbs +6 -0
  68. data/sig/iterators/paginator_iterator.rbs +8 -0
  69. data/sig/iterators/rule_iterator.rbs +5 -0
  70. data/sig/iterators/synonym_iterator.rbs +5 -0
  71. data/sig/transport/request_options.rbs +33 -0
  72. data/sig/transport/stateful_host.rbs +21 -0
  73. data/test/algolia/integration/account_client_test.rb +47 -0
  74. data/test/algolia/integration/analytics_client_test.rb +113 -0
  75. data/test/algolia/integration/base_test.rb +9 -0
  76. data/test/algolia/integration/insights_client_test.rb +80 -0
  77. data/test/algolia/integration/mocks/mock_requester.rb +45 -0
  78. data/test/algolia/integration/recommendation_client_test.rb +30 -0
  79. data/test/algolia/integration/search_client_test.rb +361 -0
  80. data/test/algolia/integration/search_index_test.rb +698 -0
  81. data/test/algolia/unit/helpers_test.rb +69 -0
  82. data/test/algolia/unit/retry_strategy_test.rb +139 -0
  83. data/test/algolia/unit/user_agent_test.rb +16 -0
  84. data/test/test_helper.rb +89 -0
  85. data/upgrade_guide.md +595 -0
  86. metadata +307 -0
@@ -0,0 +1,11 @@
1
+ module Algolia
2
+ module Analytics
3
+ class Config < AlgoliaConfig
4
+ attr_accessor region: String
5
+
6
+ attr_accessor default_hosts: [String]
7
+
8
+ def initialize: (?::Hash[Symbol, String] opts) -> void
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ module Algolia
2
+ module Insights
3
+ class Config < AlgoliaConfig
4
+ attr_accessor region: String
5
+
6
+ attr_accessor default_hosts: [String]
7
+
8
+ def initialize: (?::Hash[Symbol, String] opts) -> void
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ module Algolia
2
+ module Recommendation
3
+ class Config < AlgoliaConfig
4
+ attr_accessor region: String
5
+
6
+ attr_accessor default_hosts: [String]
7
+
8
+ def initialize: (?::Hash[Symbol, String] opts) -> void
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ module Algolia
2
+ module Search
3
+ class Config < AlgoliaConfig
4
+ include CallType
5
+
6
+ attr_accessor default_hosts: Array[untyped]
7
+
8
+ def initialize: (?::Hash[Symbol, String|[String]] opts) -> void
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,5 @@
1
+ module CallType
2
+ READ: ::Integer
3
+
4
+ WRITE: ::Integer
5
+ end
@@ -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,6 @@
1
+ module Algolia
2
+ class ObjectIterator < BaseIterator
3
+
4
+ def each: () { (Hash[Symbol, String|[String]]) -> void } -> Hash[Symbol, String|[String]]
5
+ end
6
+ 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,5 @@
1
+ module Algolia
2
+ class RuleIterator < PaginatorIterator
3
+ def get_endpoint: () -> String
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ module Algolia
2
+ class SynonymIterator < PaginatorIterator
3
+ def get_endpoint: () -> String
4
+ end
5
+ 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,9 @@
1
+ require 'test_helper'
2
+ require 'minitest/hell'
3
+
4
+ class BaseTest < Minitest::Test
5
+ parallelize_me!
6
+ def setup
7
+ check_environment_variables
8
+ end
9
+ 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