algolia 2.1.1 → 2.2.0

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