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.
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