algolia 2.1.1 → 2.2.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: dc743bd03ca6ebc94d2ae61eec22670ccbaa3531d2a9b66c44858280c644a938
4
- data.tar.gz: 9e5fb85f9d474d266de360c25b7ef3efafa0fe0b78765aa1cae32b402a0865ac
3
+ metadata.gz: 799e36b37cca18189b15d27f6b755904ef5c9707906258cfc3af51691a9af3a6
4
+ data.tar.gz: a4235ea4599c928ac96eb9fc1243b8ccb915d2636d30282ff20d792bc7b1b174
5
5
  SHA512:
6
- metadata.gz: b343a5a32c22f73fd18b33235e9dfd4adcc4c6f3236bac881ad37160dce5af9a7b79e836643ba126e3c0f2943d0187ffb804fe1688fdd6f9599966d39950fa48
7
- data.tar.gz: 98fea72cc28767839cead8d54d75f9d2ac262999bb92b5ba446d81abfb9d43ef7986c99bccc523c892916df6cf605b3e5fcf305935161bf9bdf371ab24e44196
6
+ metadata.gz: bff81541d4dd4392598eb229ee5e854e352988daa7af4892c07e94cd8574b0dab02e1d0a54aba710370775f521ef0338399a5c7876659b2be75d21e083eb4bfc
7
+ data.tar.gz: 6549f6d062a2cecbe6521d7961563917d0a9ea9d660991f644ae00b0ef7772557eae5c416efd633544d81cac3d16a94ed5ba3633297710d553a571c85d746da7
data/.circleci/config.yml CHANGED
@@ -131,7 +131,7 @@ workflows:
131
131
  - test_ruby:
132
132
  matrix:
133
133
  parameters:
134
- version: ['2.2', '2.3', '2.4', '2.5', '2.6', '2.7']
134
+ version: ['2.2', '2.3', '2.4', '2.5', '2.6', '2.7', '3.0']
135
135
  filters:
136
136
  tags:
137
137
  only: /.*/
data/CHANGELOG.md CHANGED
@@ -1,6 +1,11 @@
1
1
  # ChangeLog
2
2
 
3
- ## [Unreleased](https://github.com/algolia/algoliasearch-client-ruby/compare/2.1.1..master)
3
+ ## [Unreleased](https://github.com/algolia/algoliasearch-client-ruby/compare/2.2.0..master)
4
+
5
+ ## [2.2.0](https://github.com/algolia/algoliasearch-client-ruby/compare/2.1.1...2.2.0) (2021-11-08)
6
+ ### Added
7
+ - Added RecommendClient ([`#466`](https://github.com/algolia/algoliasearch-client-ruby/pull/466))
8
+ - Added `search` alias for `multiple_queries` ([`#457`](https://github.com/algolia/algoliasearch-client-ruby/pull/457))
4
9
 
5
10
  ## [2.1.1](https://github.com/algolia/algoliasearch-client-ruby/compare/2.1.0...2.1.1) (2021-05-27)
6
11
 
data/README.md CHANGED
@@ -41,7 +41,7 @@ Then, create objects on your index:
41
41
  client = Algolia::Search::Client.create('YourApplicationID', 'YourAPIKey')
42
42
  index = client.init_index('your_index_name')
43
43
 
44
- index.save_objects([objectID: 1, name: 'Foo'])
44
+ index.save_objects([{objectID: 1, name: 'Foo'}])
45
45
  ```
46
46
 
47
47
  Finally, you may begin searching a object using the `search` method:
@@ -0,0 +1,6 @@
1
+ module Algolia
2
+ module Recommend
3
+ class Config < Algolia::Search::Config
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,134 @@
1
+ module Algolia
2
+ module Recommend
3
+ class Model
4
+ BOUGHT_TOGETHER = 'bought-together'
5
+ RELATED_PRODUCTS = 'related-products'
6
+ end
7
+
8
+ class Client
9
+ include Helpers
10
+
11
+ # Initializes the Recommend client
12
+ #
13
+ # @param recommend_config [Recommend::Config] a Recommend::Config object which contains your APP_ID and API_KEY
14
+ # @option adapter [Object] adapter object used for the connection
15
+ # @option logger [Object]
16
+ # @option http_requester [Object] http_requester object used for the connection
17
+ #
18
+ def initialize(recommend_config, opts = {})
19
+ @config = recommend_config
20
+ adapter = opts[:adapter] || Defaults::ADAPTER
21
+ logger = opts[:logger] || LoggerHelper.create('debug.log')
22
+ requester = opts[:http_requester] || Defaults::REQUESTER_CLASS.new(adapter, logger)
23
+ @transporter = Transport::Transport.new(@config, requester)
24
+ end
25
+
26
+ # Create a new client providing only app ID and API key
27
+ #
28
+ # @param app_id [String] Algolia application ID
29
+ # @param api_key [String] Algolia API key
30
+ #
31
+ # @return self
32
+ #
33
+ def self.create(app_id, api_key)
34
+ config = Recommend::Config.new(application_id: app_id, api_key: api_key)
35
+ create_with_config(config)
36
+ end
37
+
38
+ # Create a new client providing only an Recommend::Config object
39
+ #
40
+ # @param config [Recommend::Config]
41
+ #
42
+ # @return self
43
+ #
44
+ def self.create_with_config(config)
45
+ new(config)
46
+ end
47
+
48
+ # Get recommendation for the given queries
49
+ #
50
+ # @param requests [Array<Hash>] the queries to retrieve recommendations for
51
+ # @param opts [Hash] extra parameters to send with your request
52
+ #
53
+ # @return [Hash]
54
+ #
55
+ def get_recommendations(requests, opts = {})
56
+ @transporter.write(
57
+ :POST,
58
+ '/1/indexes/*/recommendations',
59
+ { requests: format_recommendation_requests(symbolize_all(requests)) },
60
+ opts
61
+ )
62
+ end
63
+
64
+ # Get related products for the given requests
65
+ #
66
+ # @param requests [Array<Hash>] the requests to get related products for
67
+ # @param opts [Hash] extra parameters to send with your request
68
+ #
69
+ # @return [Hash]
70
+ #
71
+ def get_related_products(requests, opts = {})
72
+ get_recommendations(
73
+ set_request_models(symbolize_all(requests), Model::RELATED_PRODUCTS),
74
+ opts
75
+ )
76
+ end
77
+
78
+ # Get frequently bought together items for the given requests
79
+ #
80
+ # @param requests [Array<Hash>] the requests to get frequently bought together items for
81
+ # @param opts [Hash] extra parameters to send with your request
82
+ #
83
+ # @return [Hash]
84
+ #
85
+ def get_frequently_bought_together(requests, opts = {})
86
+ get_recommendations(
87
+ set_request_models(symbolize_all(requests), Model::BOUGHT_TOGETHER),
88
+ opts
89
+ )
90
+ end
91
+
92
+ private
93
+
94
+ # Symbolize all hashes in an array
95
+ #
96
+ # @param hash_array [Array<Hash<String|Symbol, any>>] the hashes to symbolize
97
+ #
98
+ # @return [Array<Hash<Symbol, any>>]
99
+ #
100
+ def symbolize_all(hash_array)
101
+ hash_array.map { |q| symbolize_hash(q) }
102
+ end
103
+
104
+ # Format the recommendation requests
105
+ #
106
+ # @param requests [Array<Hash>] the requests to retrieve recommendations for
107
+ #
108
+ # @return [Array<Hash>]
109
+ #
110
+ def format_recommendation_requests(requests)
111
+ requests.map do |request|
112
+ request[:threshold] = 0 unless request[:threshold].is_a? Numeric
113
+ request.delete(:fallbackParameters) if request[:model] == Model::BOUGHT_TOGETHER
114
+
115
+ request
116
+ end
117
+ end
118
+
119
+ # Force the requests to target a specific model
120
+ #
121
+ # @param requests [Array<Hash>] the requests to change
122
+ # @param model [String] the model to enforce
123
+ #
124
+ # @return [Array<Hash>]
125
+ #
126
+ def set_request_models(requests, model)
127
+ requests.map do |query|
128
+ query[:model] = model
129
+ query
130
+ end
131
+ end
132
+ end
133
+ end
134
+ end
@@ -480,6 +480,7 @@ module Algolia
480
480
  def multiple_queries(queries, opts = {})
481
481
  @transporter.read(:POST, '/1/indexes/*/queries', { requests: queries }, opts)
482
482
  end
483
+ alias_method :search, :multiple_queries
483
484
 
484
485
  # # # # # # # # # # # # # # # # # # # # #
485
486
  # MCM METHODS
@@ -1,3 +1,3 @@
1
1
  module Algolia
2
- VERSION = '2.1.1'.freeze
2
+ VERSION = '2.2.0'.freeze
3
3
  end
data/lib/algolia.rb CHANGED
@@ -7,6 +7,7 @@ require 'algolia/config/base_config'
7
7
  require 'algolia/config/search_config'
8
8
  require 'algolia/config/analytics_config'
9
9
  require 'algolia/config/insights_config'
10
+ require 'algolia/config/recommend_config'
10
11
  require 'algolia/config/recommendation_config'
11
12
  require 'algolia/enums/call_type'
12
13
  require 'algolia/enums/retry_outcome_type'
@@ -33,6 +34,7 @@ require 'algolia/account_client'
33
34
  require 'algolia/search_client'
34
35
  require 'algolia/analytics_client'
35
36
  require 'algolia/insights_client'
37
+ require 'algolia/recommend_client'
36
38
  require 'algolia/recommendation_client'
37
39
  require 'algolia/error'
38
40
  require 'algolia/search_index'
@@ -1,25 +1,27 @@
1
1
  class MockRequester
2
+ attr_accessor :requests
2
3
  def initialize
3
4
  @connection = nil
5
+ @requests = []
4
6
  end
5
7
 
6
- def send_request(host, method, path, _body, headers, _timeout, _connect_timeout)
7
- connection = get_connection(host)
8
- response = {
9
- connection: connection,
8
+ def send_request(host, method, path, body, headers, timeout, connect_timeout)
9
+ request = {
10
10
  host: host,
11
+ method: method,
11
12
  path: path,
13
+ body: body,
12
14
  headers: headers,
13
- method: method,
14
- status: 200,
15
- body: '{"hits":[],"nbHits":0,"page":0,"nbPages":1,"hitsPerPage":20,"exhaustiveNbHits":true,"query":"test","params":"query=test","processingTimeMS":1}',
16
- success: true
15
+ timeout: timeout,
16
+ connect_timeout: connect_timeout
17
17
  }
18
18
 
19
+ @requests.push(request)
20
+
19
21
  Algolia::Http::Response.new(
20
- status: response[:status],
21
- body: response[:body],
22
- headers: response[:headers]
22
+ status: 200,
23
+ body: '{"hits": []}',
24
+ headers: {}
23
25
  )
24
26
  end
25
27
 
@@ -0,0 +1,70 @@
1
+ require 'securerandom'
2
+ require_relative 'base_test'
3
+
4
+ class RecommendClientTest < BaseTest
5
+ describe 'Recommendations' do
6
+ def test_get_recommendations
7
+ requester = MockRequester.new
8
+ client = Algolia::Recommend::Client.new(@@search_config, http_requester: requester)
9
+
10
+ # It correctly formats queries using the 'bought-together' model
11
+ client.get_recommendations([{ indexName: 'products', objectID: 'B018APC4LE', model: Algolia::Recommend::Model::BOUGHT_TOGETHER }])
12
+
13
+ # It correctly formats queries using the 'related-products' model
14
+ client.get_recommendations([{ indexName: 'products', objectID: 'B018APC4LE', model: Algolia::Recommend::Model::RELATED_PRODUCTS }])
15
+
16
+ # It correctly formats multiple queries.
17
+ client.get_recommendations(
18
+ [
19
+ { indexName: 'products', objectID: 'B018APC4LE-1', model: Algolia::Recommend::Model::RELATED_PRODUCTS, threshold: 0 },
20
+ { indexName: 'products', objectID: 'B018APC4LE-2', model: Algolia::Recommend::Model::RELATED_PRODUCTS, threshold: 0 }
21
+ ]
22
+ )
23
+
24
+ # It resets the threshold to 0 if it's not numeric.
25
+ client.get_recommendations([{ indexName: 'products', objectID: 'B018APC4LE', model: Algolia::Recommend::Model::BOUGHT_TOGETHER, threshold: nil }])
26
+
27
+ # It passes the threshold correctly if it's numeric.
28
+ client.get_recommendations([{ indexName: 'products', objectID: 'B018APC4LE', model: Algolia::Recommend::Model::BOUGHT_TOGETHER, threshold: 42 }])
29
+
30
+ assert_requests(
31
+ requester,
32
+ [
33
+ { method: :post, path: '/1/indexes/*/recommendations', body: '{"requests":[{"indexName":"products","objectID":"B018APC4LE","model":"bought-together","threshold":0}]}' },
34
+ { method: :post, path: '/1/indexes/*/recommendations', body: '{"requests":[{"indexName":"products","objectID":"B018APC4LE","model":"related-products","threshold":0}]}' },
35
+ { method: :post, path: '/1/indexes/*/recommendations', body: '{"requests":[{"indexName":"products","objectID":"B018APC4LE-1","model":"related-products","threshold":0},{"indexName":"products","objectID":"B018APC4LE-2","model":"related-products","threshold":0}]}' },
36
+ { method: :post, path: '/1/indexes/*/recommendations', body: '{"requests":[{"indexName":"products","objectID":"B018APC4LE","model":"bought-together","threshold":0}]}' },
37
+ { method: :post, path: '/1/indexes/*/recommendations', body: '{"requests":[{"indexName":"products","objectID":"B018APC4LE","model":"bought-together","threshold":42}]}' }
38
+ ]
39
+ )
40
+ end
41
+
42
+ def test_get_related_products
43
+ requester = MockRequester.new
44
+ client = Algolia::Recommend::Client.new(@@search_config, http_requester: requester)
45
+
46
+ client.get_related_products([{ indexName: 'products', objectID: 'B018APC4LE' }])
47
+
48
+ assert_requests(
49
+ requester,
50
+ [{ method: :post, path: '/1/indexes/*/recommendations', body: '{"requests":[{"indexName":"products","objectID":"B018APC4LE","model":"related-products","threshold":0}]}' }]
51
+ )
52
+ end
53
+
54
+ def test_get_frequently_bought_together
55
+ requester = MockRequester.new
56
+ client = Algolia::Recommend::Client.new(@@search_config, http_requester: requester)
57
+
58
+ client.get_frequently_bought_together([{ indexName: 'products', objectID: 'B018APC4LE' }])
59
+ client.get_frequently_bought_together([{ indexName: 'products', objectID: 'B018APC4LE', fallbackParameters: {} }])
60
+
61
+ assert_requests(
62
+ requester,
63
+ [
64
+ { method: :post, path: '/1/indexes/*/recommendations', body: '{"requests":[{"indexName":"products","objectID":"B018APC4LE","model":"bought-together","threshold":0}]}' },
65
+ { method: :post, path: '/1/indexes/*/recommendations', body: '{"requests":[{"indexName":"products","objectID":"B018APC4LE","model":"bought-together","threshold":0}]}' }
66
+ ]
67
+ )
68
+ end
69
+ end
70
+ end
data/test/test_helper.rb CHANGED
@@ -28,6 +28,22 @@ class Minitest::Test
28
28
  @@search_client = Algolia::Search::Client.new(@@search_config)
29
29
  end
30
30
 
31
+ def assert_requests(requester, requests)
32
+ refute_empty requests
33
+ refute_nil requester
34
+
35
+ actual_requests = requester.requests
36
+ assert_equal requests.size, actual_requests.size
37
+
38
+ requests.each_with_index do |expected_request, i|
39
+ request = actual_requests[i]
40
+
41
+ assert_equal(expected_request[:body], request[:body])
42
+ assert_equal(expected_request[:method], request[:method])
43
+ assert_equal(expected_request[:path], request[:path])
44
+ end
45
+ end
46
+
31
47
  def check_environment_variables
32
48
  raise Algolia::AlgoliaError, 'ALGOLIA_APPLICATION_ID_1 must be defined' if ENV['ALGOLIA_APPLICATION_ID_1'].to_s.strip.empty?
33
49
  raise Algolia::AlgoliaError, 'ALGOLIA_ADMIN_KEY_1 must be defined' if ENV['ALGOLIA_ADMIN_KEY_1'].to_s.strip.empty?
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: algolia
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.1
4
+ version: 2.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Algolia
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-05-27 00:00:00.000000000 Z
11
+ date: 2021-11-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -218,6 +218,7 @@ files:
218
218
  - lib/algolia/config/analytics_config.rb
219
219
  - lib/algolia/config/base_config.rb
220
220
  - lib/algolia/config/insights_config.rb
221
+ - lib/algolia/config/recommend_config.rb
221
222
  - lib/algolia/config/recommendation_config.rb
222
223
  - lib/algolia/config/search_config.rb
223
224
  - lib/algolia/defaults.rb
@@ -234,6 +235,7 @@ files:
234
235
  - lib/algolia/iterators/rule_iterator.rb
235
236
  - lib/algolia/iterators/synonym_iterator.rb
236
237
  - lib/algolia/logger_helper.rb
238
+ - lib/algolia/recommend_client.rb
237
239
  - lib/algolia/recommendation_client.rb
238
240
  - lib/algolia/responses/add_api_key_response.rb
239
241
  - lib/algolia/responses/base_response.rb
@@ -274,6 +276,7 @@ files:
274
276
  - test/algolia/integration/base_test.rb
275
277
  - test/algolia/integration/insights_client_test.rb
276
278
  - test/algolia/integration/mocks/mock_requester.rb
279
+ - test/algolia/integration/recommend_client_test.rb
277
280
  - test/algolia/integration/recommendation_client_test.rb
278
281
  - test/algolia/integration/search_client_test.rb
279
282
  - test/algolia/integration/search_index_test.rb
@@ -315,6 +318,7 @@ test_files:
315
318
  - test/algolia/integration/base_test.rb
316
319
  - test/algolia/integration/insights_client_test.rb
317
320
  - test/algolia/integration/mocks/mock_requester.rb
321
+ - test/algolia/integration/recommend_client_test.rb
318
322
  - test/algolia/integration/recommendation_client_test.rb
319
323
  - test/algolia/integration/search_client_test.rb
320
324
  - test/algolia/integration/search_index_test.rb