algolia 2.0.4 → 2.2.2

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: e2ba367e6308158bc455c60a0d0a5c16fbb1ed4565aaa3a6b8d4cca3e16f0c0d
4
- data.tar.gz: af53995633ba454c929265d5d81d311c67a99fcdd76e8eeec51f98aa8e89f778
3
+ metadata.gz: 5c2f4626569fa71c66f1801a6608a0d66bdd7afc5d2d42342856d8083281d0ee
4
+ data.tar.gz: bbc716503ac0354dd80a1e5d1196cfc8ff5e8d80c3c166c196bd1ec5e227a446
5
5
  SHA512:
6
- metadata.gz: 896b3821ad99f02449f652090c6b4249a932d454bd03e58879c2fad030d6179480b208c36bd07003dd3c58f96cd7630e28aa1afa026cc83f907a3bcf015f2f02
7
- data.tar.gz: bdc286d0c8df062b33fc6d25fd6d3d4348dc82cce74703d26a12d8374a91c5e378e3d7f03ff2d617a76beab88828a8004d3457997394df2a9832277ca308f411
6
+ metadata.gz: bd82583938e41074786a9f6e3518256af5f54c6946e8224a9e2ecc40952f211475dbec10ba5d054058764bdccbdceff80a9147c195a8c3f62a5ab4f033c11757
7
+ data.tar.gz: 25971344a9f64260d29f8c1a7878605a2e408369de05b4e4add74e828697cefde461bb83ed5564dbd6f94de3844844e6e357568e830de53a3d77253a27151e33
data/.circleci/config.yml CHANGED
@@ -23,6 +23,13 @@ aliases:
23
23
  name: Run linting tool
24
24
  command: bundle exec rake rubocop
25
25
 
26
+ - &credentials
27
+ name: Retrieve temporary Algolia credentials if needed
28
+ command: |
29
+ if [ "$CIRCLE_PR_REPONAME" ]; then
30
+ curl -s https://algoliasearch-client-keygen.herokuapp.com | sh >> $BASH_ENV
31
+ fi
32
+
26
33
  - &run_tests
27
34
  name: Run unit and integration tests
28
35
  command: |
@@ -73,6 +80,7 @@ jobs:
73
80
  - restore_cache: *restore_cache
74
81
  - run: *install_bundler
75
82
  - save_cache: *save_cache
83
+ - run: *credentials
76
84
  - run: *run_tests
77
85
 
78
86
  test_jruby:
@@ -88,6 +96,7 @@ jobs:
88
96
  - restore_cache: *restore_cache
89
97
  - run: *install_bundler
90
98
  - save_cache: *save_cache
99
+ - run: *credentials
91
100
  - run: *run_tests
92
101
 
93
102
  release:
@@ -122,7 +131,7 @@ workflows:
122
131
  - test_ruby:
123
132
  matrix:
124
133
  parameters:
125
- 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']
126
135
  filters:
127
136
  tags:
128
137
  only: /.*/
data/CHANGELOG.md CHANGED
@@ -1,6 +1,32 @@
1
1
  # ChangeLog
2
2
 
3
- ## [Unreleased](https://github.com/algolia/algoliasearch-client-ruby/compare/2.0.4...master)
3
+ ## [Unreleased](https://github.com/algolia/algoliasearch-client-ruby/compare/2.2.2..master)
4
+
5
+ ## [2.2.1](https://github.com/algolia/algoliasearch-client-ruby/compare/2.2.1...2.2.2) (2021-12-08)
6
+ ### Fixed
7
+ - Added a `status` field to the `MockRequester` ([`#467`](https://github.com/algolia/algoliasearch-client-ruby/pull/467))
8
+
9
+ ## [2.2.1](https://github.com/algolia/algoliasearch-client-ruby/compare/2.2.0...2.2.1) (2021-11-12)
10
+ ### Chore
11
+ - Deprecated `RecommendationClient` in favor of `PersonalizationClient` ([`#461`](https://github.com/algolia/algoliasearch-client-ruby/pull/461))
12
+
13
+ ## [2.2.0](https://github.com/algolia/algoliasearch-client-ruby/compare/2.1.1...2.2.0) (2021-11-08)
14
+ ### Added
15
+ - Added RecommendClient ([`#466`](https://github.com/algolia/algoliasearch-client-ruby/pull/466))
16
+ - Added `search` alias for `multiple_queries` ([`#457`](https://github.com/algolia/algoliasearch-client-ruby/pull/457))
17
+
18
+ ## [2.1.1](https://github.com/algolia/algoliasearch-client-ruby/compare/2.1.0...2.1.1) (2021-05-27)
19
+
20
+ ### Fix
21
+ - Bug with read/write nodes caching ([`#455`](https://github.com/algolia/algoliasearch-client-ruby/pull/455))
22
+
23
+ ## [2.1.0](https://github.com/algolia/algoliasearch-client-ruby/compare/2.0.4...2.1.0) (2021-03-30)
24
+
25
+ ### Feat
26
+ - Custom dictionaries methods
27
+
28
+ ### Fix
29
+ - The parameter `forwardToReplicas` should be handled independently in the `set_settings` method
4
30
 
5
31
  ## [2.0.4](https://github.com/algolia/algoliasearch-client-ruby/compare/2.0.3...2.0.4) (2021-01-05)
6
32
 
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,20 @@
1
+ module Algolia
2
+ module Personalization
3
+ class Config < BaseConfig
4
+ attr_accessor :region, :default_hosts
5
+
6
+ # Initialize a config
7
+ #
8
+ # @option options [String] :application_id
9
+ # @option options [String] :api_key
10
+ # @option options [String] :region
11
+ #
12
+ def initialize(opts = {})
13
+ super(opts)
14
+
15
+ @region = opts[:region] || 'us'
16
+ @default_hosts = [Transport::StatefulHost.new("personalization.#{region}.algolia.com")]
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,6 @@
1
+ module Algolia
2
+ module Recommend
3
+ class Config < Algolia::Search::Config
4
+ end
5
+ end
6
+ end
@@ -1,20 +1,7 @@
1
1
  module Algolia
2
2
  module Recommendation
3
- class Config < BaseConfig
4
- attr_accessor :region, :default_hosts
5
-
6
- # Initialize a config
7
- #
8
- # @option options [String] :application_id
9
- # @option options [String] :api_key
10
- # @option options [String] :region
11
- #
12
- def initialize(opts = {})
13
- super(opts)
14
-
15
- @region = opts[:region] || 'us'
16
- @default_hosts = [Transport::StatefulHost.new("recommendation.#{region}.algolia.com")]
17
- end
3
+ # <b>DEPRECATED:</b> Please use <tt>Algolia::Personalization::Config</tt> instead.
4
+ class Config < Algolia::Personalization::Config
18
5
  end
19
6
  end
20
7
  end
@@ -82,4 +82,53 @@ module Helpers
82
82
  end
83
83
  res
84
84
  end
85
+
86
+ # Check the passed object to determine if it's an array
87
+ #
88
+ # @param object [Object]
89
+ #
90
+ def check_array(object)
91
+ raise Algolia::AlgoliaError, 'argument must be an array of objects' unless object.is_a?(Array)
92
+ end
93
+
94
+ # Check the passed object
95
+ #
96
+ # @param object [Object]
97
+ # @param in_array [Boolean] whether the object is an array or not
98
+ #
99
+ def check_object(object, in_array = false)
100
+ case object
101
+ when Array
102
+ raise Algolia::AlgoliaError, in_array ? 'argument must be an array of objects' : 'argument must not be an array'
103
+ when String, Integer, Float, TrueClass, FalseClass, NilClass
104
+ raise Algolia::AlgoliaError, "argument must be an #{'array of' if in_array} object, got: #{object.inspect}"
105
+ end
106
+ end
107
+
108
+ # Check if passed object has a objectID
109
+ #
110
+ # @param object [Object]
111
+ # @param object_id [String]
112
+ #
113
+ def get_object_id(object, object_id = nil)
114
+ check_object(object)
115
+ object_id ||= object[:objectID] || object['objectID']
116
+ raise Algolia::AlgoliaError, "Missing 'objectID'" if object_id.nil?
117
+ object_id
118
+ end
119
+
120
+ # Build a batch request
121
+ #
122
+ # @param action [String] action to perform on the engine
123
+ # @param objects [Array] objects on which build the action
124
+ # @param with_object_id [Boolean] if set to true, check if each object has an objectID set
125
+ #
126
+ def chunk(action, objects, with_object_id = false)
127
+ objects.map do |object|
128
+ check_object(object, true)
129
+ request = { action: action, body: object }
130
+ request[:objectID] = get_object_id(object).to_s if with_object_id
131
+ request
132
+ end
133
+ end
85
134
  end
@@ -9,9 +9,9 @@ module Algolia
9
9
  # @param logger [Object] logger used to log requests. Defaults to Algolia::LoggerHelper
10
10
  #
11
11
  def initialize(adapter, logger)
12
- @adapter = adapter
13
- @logger = logger
14
- @connection = nil
12
+ @adapter = adapter
13
+ @logger = logger
14
+ @connections = {}
15
15
  end
16
16
 
17
17
  # Sends request to the engine
@@ -65,7 +65,7 @@ module Algolia
65
65
  # @return [Faraday::Connection]
66
66
  #
67
67
  def connection(host)
68
- @connection ||= Faraday.new(build_url(host)) do |f|
68
+ @connections[host.accept] ||= Faraday.new(build_url(host)) do |f|
69
69
  f.adapter @adapter.to_sym
70
70
  end
71
71
  end
@@ -0,0 +1,60 @@
1
+ module Algolia
2
+ module Personalization
3
+ class Client
4
+ # Initializes the Personalization client
5
+ #
6
+ # @param personalization_config [Personalization::Config] a Personalization::Config object which contains your APP_ID and API_KEY
7
+ # @option adapter [Object] adapter object used for the connection
8
+ # @option logger [Object]
9
+ # @option http_requester [Object] http_requester object used for the connection
10
+ #
11
+ def initialize(personalization_config, opts = {})
12
+ @config = personalization_config
13
+ adapter = opts[:adapter] || Defaults::ADAPTER
14
+ logger = opts[:logger] || LoggerHelper.create('debug.log')
15
+ requester = opts[:http_requester] || Defaults::REQUESTER_CLASS.new(adapter, logger)
16
+ @transporter = Transport::Transport.new(@config, requester)
17
+ end
18
+
19
+ # Create a new client providing only app ID and API key
20
+ #
21
+ # @param app_id [String] Algolia application ID
22
+ # @param api_key [String] Algolia API key
23
+ #
24
+ # @return self
25
+ #
26
+ def self.create(app_id, api_key)
27
+ config = Personalization::Config.new(application_id: app_id, api_key: api_key)
28
+ create_with_config(config)
29
+ end
30
+
31
+ # Create a new client providing only an Personalization::Config object
32
+ #
33
+ # @param config [Personalization::Config]
34
+ #
35
+ # @return self
36
+ #
37
+ def self.create_with_config(config)
38
+ new(config)
39
+ end
40
+
41
+ # Set the personalization strategy.
42
+ #
43
+ # @param personalization_strategy [Hash] A strategy object.
44
+ #
45
+ # @return [Hash]
46
+ #
47
+ def set_personalization_strategy(personalization_strategy, opts = {})
48
+ @transporter.write(:POST, '1/strategies/personalization', personalization_strategy, opts)
49
+ end
50
+
51
+ # Get the personalization strategy.
52
+ #
53
+ # @return [Hash]
54
+ #
55
+ def get_personalization_strategy(opts = {})
56
+ @transporter.read(:GET, '1/strategies/personalization', {}, opts)
57
+ end
58
+ end
59
+ end
60
+ 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
@@ -1,60 +1,7 @@
1
1
  module Algolia
2
2
  module Recommendation
3
- class Client
4
- # Initializes the Recommendation client
5
- #
6
- # @param recommendation_config [Recommendation::Config] a Recommendation::Config object which contains your APP_ID and API_KEY
7
- # @option adapter [Object] adapter object used for the connection
8
- # @option logger [Object]
9
- # @option http_requester [Object] http_requester object used for the connection
10
- #
11
- def initialize(recommendation_config, opts = {})
12
- @config = recommendation_config
13
- adapter = opts[:adapter] || Defaults::ADAPTER
14
- logger = opts[:logger] || LoggerHelper.create('debug.log')
15
- requester = opts[:http_requester] || Defaults::REQUESTER_CLASS.new(adapter, logger)
16
- @transporter = Transport::Transport.new(@config, requester)
17
- end
18
-
19
- # Create a new client providing only app ID and API key
20
- #
21
- # @param app_id [String] Algolia application ID
22
- # @param api_key [String] Algolia API key
23
- #
24
- # @return self
25
- #
26
- def self.create(app_id, api_key)
27
- config = Recommendation::Config.new(application_id: app_id, api_key: api_key)
28
- create_with_config(config)
29
- end
30
-
31
- # Create a new client providing only an Recommendation::Config object
32
- #
33
- # @param config [Recommendation::Config]
34
- #
35
- # @return self
36
- #
37
- def self.create_with_config(config)
38
- new(config)
39
- end
40
-
41
- # Set the personalization strategy.
42
- #
43
- # @param personalization_strategy [Hash] A strategy object.
44
- #
45
- # @return [Hash]
46
- #
47
- def set_personalization_strategy(personalization_strategy, opts = {})
48
- @transporter.write(:POST, '1/strategies/personalization', personalization_strategy, opts)
49
- end
50
-
51
- # Get the personalization strategy.
52
- #
53
- # @return [Hash]
54
- #
55
- def get_personalization_strategy(opts = {})
56
- @transporter.read(:GET, '1/strategies/personalization', {}, opts)
57
- end
3
+ # <b>DEPRECATED:</b> Please use <tt>Algolia::Personalization::Client</tt> instead.
4
+ class Client < Algolia::Personalization::Client
58
5
  end
59
6
  end
60
7
  end
@@ -0,0 +1,33 @@
1
+ module Algolia
2
+ class DictionaryResponse < BaseResponse
3
+ include CallType
4
+
5
+ attr_reader :raw_response
6
+
7
+ # @param client [Search::Client] Algolia Search Client used for verification
8
+ # @param response [Hash] Raw response from the client
9
+ #
10
+ def initialize(client, response)
11
+ @client = client
12
+ @raw_response = response
13
+ @done = false
14
+ end
15
+
16
+ # Wait for the task to complete
17
+ #
18
+ # @param opts [Hash] contains extra parameters to send with your query
19
+ #
20
+ def wait(_opts = {})
21
+ until @done
22
+ res = @client.custom_request({}, path_encode('/1/task/%s', @raw_response[:taskID]), :GET, READ)
23
+ status = get_option(res, 'status')
24
+ if status == 'published'
25
+ @done = true
26
+ end
27
+ sleep(Defaults::WAIT_TASK_DEFAULT_TIME_BEFORE_RETRY / 1000)
28
+ end
29
+
30
+ self
31
+ end
32
+ end
33
+ end
@@ -80,7 +80,7 @@ module Algolia
80
80
  end
81
81
 
82
82
  # # # # # # # # # # # # # # # # # # # # #
83
- # MISC
83
+ # INDEX METHODS
84
84
  # # # # # # # # # # # # # # # # # # # # #
85
85
 
86
86
  # Initialize an index with a given name
@@ -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
@@ -594,12 +595,185 @@ module Algolia
594
595
  @transporter.read(:GET, '/1/clusters/mapping/pending' + handle_params({ getClusters: retrieve_mappings }), {}, request_options)
595
596
  end
596
597
 
597
- #
598
598
  # Aliases the pending_mappings? method
599
599
  #
600
600
  alias_method :has_pending_mappings, :pending_mappings?
601
601
 
602
+ # # # # # # # # # # # # # # # # # # # # #
603
+ # CUSTOM DICTIONARIES METHODS
604
+ # # # # # # # # # # # # # # # # # # # # #
605
+
606
+ # Save entries for a given dictionary
607
+ #
608
+ # @param dictionary [String] dictionary name. Can be either 'stopwords', 'plurals' or 'compounds'
609
+ # @param dictionary_entries [Array<Hash>] array of dictionary entries
610
+ # @param opts [Hash] contains extra parameters to send with your query
611
+ #
612
+ # @return DictionaryResponse
613
+ #
614
+ def save_dictionary_entries(dictionary, dictionary_entries, opts = {})
615
+ response = @transporter.write(
616
+ :POST,
617
+ path_encode('/1/dictionaries/%s/batch', dictionary),
618
+ { clearExistingDictionaryEntries: false, requests: chunk('addEntry', dictionary_entries) },
619
+ opts
620
+ )
621
+
622
+ DictionaryResponse.new(self, response)
623
+ end
624
+
625
+ # Save entries for a given dictionary and wait for the task to finish
626
+ #
627
+ # @param dictionary [String] dictionary name. Can be either 'stopwords', 'plurals' or 'compounds'
628
+ # @param dictionary_entries [Array<Hash>] array of dictionary entries
629
+ # @param opts [Hash] contains extra parameters to send with your query
630
+ #
631
+ def save_dictionary_entries!(dictionary, dictionary_entries, opts = {})
632
+ response = save_dictionary_entries(dictionary, dictionary_entries, opts)
633
+
634
+ response.wait(opts)
635
+ end
636
+
637
+ # Replace entries for a given dictionary
638
+ #
639
+ # @param dictionary [String] dictionary name. Can be either 'stopwords', 'plurals' or 'compounds'
640
+ # @param dictionary_entries [Array<Hash>] array of dictionary entries
641
+ # @param opts [Hash] contains extra parameters to send with your query
642
+ #
643
+ # @return DictionaryResponse
644
+ #
645
+ def replace_dictionary_entries(dictionary, dictionary_entries, opts = {})
646
+ response = @transporter.write(
647
+ :POST,
648
+ path_encode('/1/dictionaries/%s/batch', dictionary),
649
+ { clearExistingDictionaryEntries: true, requests: chunk('addEntry', dictionary_entries) },
650
+ opts
651
+ )
652
+
653
+ DictionaryResponse.new(self, response)
654
+ end
655
+
656
+ # Replace entries for a given dictionary and wait for the task to finish
657
+ #
658
+ # @param dictionary [String] dictionary name. Can be either 'stopwords', 'plurals' or 'compounds'
659
+ # @param dictionary_entries [Array<Hash>] array of dictionary entries
660
+ # @param opts [Hash] contains extra parameters to send with your query
661
+ #
662
+ def replace_dictionary_entries!(dictionary, dictionary_entries, opts = {})
663
+ response = replace_dictionary_entries(dictionary, dictionary_entries, opts)
664
+
665
+ response.wait(opts)
666
+ end
667
+
668
+ # Delete entries for a given dictionary
669
+ #
670
+ # @param dictionary [String] dictionary name. Can be either 'stopwords', 'plurals' or 'compounds'
671
+ # @param object_ids [Array<Hash>] array of object ids
672
+ # @param opts [Hash] contains extra parameters to send with your query
673
+ #
674
+ # @return DictionaryResponse
675
+ #
676
+ def delete_dictionary_entries(dictionary, object_ids, opts = {})
677
+ request = object_ids.map do |object_id|
678
+ { objectID: object_id }
679
+ end
680
+ response = @transporter.write(
681
+ :POST,
682
+ path_encode('/1/dictionaries/%s/batch', dictionary),
683
+ { clearExistingDictionaryEntries: false, requests: chunk('deleteEntry', request) },
684
+ opts
685
+ )
686
+
687
+ DictionaryResponse.new(self, response)
688
+ end
689
+
690
+ # Delete entries for a given dictionary and wait for the task to finish
691
+ #
692
+ # @param dictionary [String] dictionary name. Can be either 'stopwords', 'plurals' or 'compounds'
693
+ # @param object_ids [Array<Hash>] array of object ids
694
+ # @param opts [Hash] contains extra parameters to send with your query
602
695
  #
696
+ def delete_dictionary_entries!(dictionary, object_ids, opts = {})
697
+ response = delete_dictionary_entries(dictionary, object_ids, opts)
698
+
699
+ response.wait(opts)
700
+ end
701
+
702
+ # Clear all entries for a given dictionary
703
+ #
704
+ # @param dictionary [String] dictionary name. Can be either 'stopwords', 'plurals' or 'compounds'
705
+ # @param opts [Hash] contains extra parameters to send with your query
706
+ #
707
+ # @return DictionaryResponse
708
+ #
709
+ def clear_dictionary_entries(dictionary, opts = {})
710
+ replace_dictionary_entries(dictionary, [], opts)
711
+ end
712
+
713
+ # Clear all entries for a given dictionary and wait for the task to finish
714
+ #
715
+ # @param dictionary [String] dictionary name. Can be either 'stopwords', 'plurals' or 'compounds'
716
+ # @param opts [Hash] contains extra parameters to send with your query
717
+ #
718
+ def clear_dictionary_entries!(dictionary, opts = {})
719
+ response = replace_dictionary_entries(dictionary, [], opts)
720
+
721
+ response.wait(opts)
722
+ end
723
+
724
+ # Search entries for a given dictionary
725
+ #
726
+ # @param dictionary [String] dictionary name. Can be either 'stopwords', 'plurals' or 'compounds'
727
+ # @param query [String] query to send
728
+ # @param opts [Hash] contains extra parameters to send with your query
729
+ #
730
+ def search_dictionary_entries(dictionary, query, opts = {})
731
+ @transporter.read(
732
+ :POST,
733
+ path_encode('/1/dictionaries/%s/search', dictionary),
734
+ { query: query },
735
+ opts
736
+ )
737
+ end
738
+
739
+ # Set settings for all the dictionaries
740
+ #
741
+ # @param dictionary_settings [Hash]
742
+ # @param opts [Hash] contains extra parameters to send with your query
743
+ #
744
+ # @return DictionaryResponse
745
+ #
746
+ def set_dictionary_settings(dictionary_settings, opts = {})
747
+ response = @transporter.write(:PUT, '/1/dictionaries/*/settings', dictionary_settings, opts)
748
+
749
+ DictionaryResponse.new(self, response)
750
+ end
751
+
752
+ # Set settings for all the dictionaries and wait for the task to finish
753
+ #
754
+ # @param dictionary_settings [Hash]
755
+ # @param opts [Hash] contains extra parameters to send with your query
756
+ #
757
+ # @return DictionaryResponse
758
+ #
759
+ def set_dictionary_settings!(dictionary_settings, opts = {})
760
+ response = set_dictionary_settings(dictionary_settings, opts)
761
+
762
+ response.wait(opts)
763
+ end
764
+
765
+ # Retrieve settings for all the dictionaries
766
+ #
767
+ # @param opts [Hash] contains extra parameters to send with your query
768
+ #
769
+ def get_dictionary_settings(opts = {})
770
+ @transporter.read(:GET, '/1/dictionaries/*/settings', {}, opts)
771
+ end
772
+
773
+ # # # # # # # # # # # # # # # # # # # # #
774
+ # MISC METHODS
775
+ # # # # # # # # # # # # # # # # # # # # #
776
+
603
777
  # Method available to make custom requests to the API
604
778
  #
605
779
  def custom_request(data, uri, method, call_type, opts = {})
@@ -987,7 +987,15 @@ module Algolia
987
987
  # @return [IndexingResponse]
988
988
  #
989
989
  def set_settings(settings, opts = {})
990
- response = @transporter.write(:PUT, path_encode('/1/indexes/%s/settings', @name), settings, opts)
990
+ request_options = symbolize_hash(opts)
991
+ forward_to_replicas = request_options.delete(:forwardToReplicas) || false
992
+
993
+ response = @transporter.write(
994
+ :PUT,
995
+ path_encode('/1/indexes/%s/settings', @name) + handle_params({ forwardToReplicas: forward_to_replicas }),
996
+ settings,
997
+ request_options
998
+ )
991
999
 
992
1000
  IndexingResponse.new(self, response)
993
1001
  end
@@ -1037,55 +1045,6 @@ module Algolia
1037
1045
 
1038
1046
  private
1039
1047
 
1040
- # Check the passed object to determine if it's an array
1041
- #
1042
- # @param object [Object]
1043
- #
1044
- def check_array(object)
1045
- raise AlgoliaError, 'argument must be an array of objects' unless object.is_a?(Array)
1046
- end
1047
-
1048
- # Check the passed object
1049
- #
1050
- # @param object [Object]
1051
- # @param in_array [Boolean] whether the object is an array or not
1052
- #
1053
- def check_object(object, in_array = false)
1054
- case object
1055
- when Array
1056
- raise AlgoliaError, in_array ? 'argument must be an array of objects' : 'argument must not be an array'
1057
- when String, Integer, Float, TrueClass, FalseClass, NilClass
1058
- raise AlgoliaError, "argument must be an #{'array of' if in_array} object, got: #{object.inspect}"
1059
- end
1060
- end
1061
-
1062
- # Check if passed object has a objectID
1063
- #
1064
- # @param object [Object]
1065
- # @param object_id [String]
1066
- #
1067
- def get_object_id(object, object_id = nil)
1068
- check_object(object)
1069
- object_id ||= object[:objectID] || object['objectID']
1070
- raise AlgoliaError, "Missing 'objectID'" if object_id.nil?
1071
- object_id
1072
- end
1073
-
1074
- # Build a batch request
1075
- #
1076
- # @param action [String] action to perform on the engine
1077
- # @param objects [Array] objects on which build the action
1078
- # @param with_object_id [Boolean] if set to true, check if each object has an objectID set
1079
- #
1080
- def chunk(action, objects, with_object_id = false)
1081
- objects.map do |object|
1082
- check_object(object, true)
1083
- request = { action: action, body: object }
1084
- request[:objectID] = get_object_id(object).to_s if with_object_id
1085
- request
1086
- end
1087
- end
1088
-
1089
1048
  def raw_batch(requests, opts)
1090
1049
  @transporter.write(:POST, path_encode('/1/indexes/%s/batch', @name), { requests: requests }, opts)
1091
1050
  end
@@ -1,3 +1,3 @@
1
1
  module Algolia
2
- VERSION = '2.0.4'.freeze
2
+ VERSION = '2.2.2'.freeze
3
3
  end
data/lib/algolia.rb CHANGED
@@ -7,6 +7,8 @@ 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'
11
+ require 'algolia/config/personalization_config'
10
12
  require 'algolia/config/recommendation_config'
11
13
  require 'algolia/enums/call_type'
12
14
  require 'algolia/enums/retry_outcome_type'
@@ -20,6 +22,7 @@ require 'algolia/responses/indexing_response'
20
22
  require 'algolia/responses/add_api_key_response'
21
23
  require 'algolia/responses/update_api_key_response'
22
24
  require 'algolia/responses/delete_api_key_response'
25
+ require 'algolia/responses/dictionary_response'
23
26
  require 'algolia/responses/restore_api_key_response'
24
27
  require 'algolia/responses/multiple_batch_indexing_response'
25
28
  require 'algolia/responses/multiple_response'
@@ -32,6 +35,8 @@ require 'algolia/account_client'
32
35
  require 'algolia/search_client'
33
36
  require 'algolia/analytics_client'
34
37
  require 'algolia/insights_client'
38
+ require 'algolia/recommend_client'
39
+ require 'algolia/personalization_client'
35
40
  require 'algolia/recommendation_client'
36
41
  require 'algolia/error'
37
42
  require 'algolia/search_index'
@@ -23,7 +23,9 @@ class AnalyticsClientTest < BaseTest
23
23
  endAt: tomorrow.strftime('%Y-%m-%dT%H:%M:%SZ')
24
24
  }
25
25
 
26
- response = client.add_ab_test(ab_test)
26
+ response = retry_test do
27
+ client.add_ab_test(ab_test)
28
+ end
27
29
  ab_test_id = response[:abTestID]
28
30
 
29
31
  index1.wait_task(response[:taskID])
@@ -86,7 +88,9 @@ class AnalyticsClientTest < BaseTest
86
88
  endAt: tomorrow.strftime('%Y-%m-%dT%H:%M:%SZ')
87
89
  }
88
90
 
89
- response = client.add_ab_test(ab_test)
91
+ response = retry_test do
92
+ client.add_ab_test(ab_test)
93
+ end
90
94
  ab_test_id = response[:abTestID]
91
95
 
92
96
  index.wait_task(response[:taskID])
@@ -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": [], "status": "published"}',
24
+ headers: {}
23
25
  )
24
26
  end
25
27
 
@@ -0,0 +1,30 @@
1
+ require_relative 'base_test'
2
+ require 'date'
3
+
4
+ class PersonalizationClientTest < BaseTest
5
+ describe 'Personalization client' do
6
+ def test_personalization_client
7
+ client = Algolia::Personalization::Client.create(APPLICATION_ID_1, ADMIN_KEY_1)
8
+ personalization_strategy = {
9
+ eventsScoring: [
10
+ { eventName: 'Add to cart', eventType: 'conversion', score: 50 },
11
+ { eventName: 'Purchase', eventType: 'conversion', score: 100 }
12
+ ],
13
+ facetsScoring: [
14
+ { facetName: 'brand', score: 100 },
15
+ { facetName: 'categories', score: 10 }
16
+ ],
17
+ personalizationImpact: 0
18
+ }
19
+
20
+ begin
21
+ client.set_personalization_strategy(personalization_strategy)
22
+ rescue Algolia::AlgoliaHttpError => e
23
+ raise e unless e.code == 429
24
+ end
25
+ response = client.get_personalization_strategy
26
+
27
+ assert_equal response, personalization_strategy
28
+ end
29
+ end
30
+ end
@@ -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
@@ -1,3 +1,4 @@
1
+ require 'securerandom'
1
2
  require_relative 'base_test'
2
3
 
3
4
  class SearchClientTest < BaseTest
@@ -223,7 +224,9 @@ class SearchClientTest < BaseTest
223
224
  assert_includes api_keys, @api_key[:value]
224
225
 
225
226
  @@search_client.update_api_key!(@api_key[:value], { maxHitsPerQuery: 42 })
226
- updated_api_key = @@search_client.get_api_key(@api_key[:value])
227
+ updated_api_key = retry_test do
228
+ @@search_client.get_api_key(@api_key[:value], test: 'test')
229
+ end
227
230
  assert_equal 42, updated_api_key[:maxHitsPerQuery]
228
231
 
229
232
  @@search_client.delete_api_key!(@api_key[:value])
@@ -234,18 +237,13 @@ class SearchClientTest < BaseTest
234
237
 
235
238
  assert_equal 'Key does not exist', exception.message
236
239
 
237
- loop do
238
- begin
239
- @@search_client.restore_api_key!(@api_key[:value])
240
- break
241
- rescue Algolia::AlgoliaHttpError => e
242
- if e.code != 404
243
- raise StandardError
244
- end
245
- end
240
+ retry_test do
241
+ @@search_client.restore_api_key!(@api_key[:value])
246
242
  end
247
243
 
248
- restored_key = @@search_client.get_api_key(@api_key[:value])
244
+ restored_key = retry_test do
245
+ @@search_client.get_api_key(@api_key[:value])
246
+ end
249
247
 
250
248
  refute_nil restored_key
251
249
  end
@@ -334,7 +332,12 @@ class SearchClientTest < BaseTest
334
332
  secured_index1 = secured_client.init_index(@index1.name)
335
333
  secured_index2 = secured_client.init_index(@index2.name)
336
334
 
337
- secured_index1.search('')
335
+ res = retry_test do
336
+ secured_index1.search('')
337
+ end
338
+
339
+ assert_equal 1, res[:hits].length
340
+
338
341
  exception = assert_raises Algolia::AlgoliaHttpError do
339
342
  secured_index2.search('')
340
343
  end
@@ -367,5 +370,96 @@ class SearchClientTest < BaseTest
367
370
  assert_equal 'The SecuredAPIKey doesn\'t have a validUntil parameter.', exception.message
368
371
  end
369
372
  end
373
+
374
+ describe 'Custom Dictionaries' do
375
+ def before_all
376
+ @client = Algolia::Search::Client.create(APPLICATION_ID_2, ADMIN_KEY_2)
377
+ end
378
+
379
+ def test_stopwords_dictionaries
380
+ entry_id = SecureRandom.hex
381
+ assert_equal 0, @client.search_dictionary_entries('stopwords', entry_id)[:nbHits]
382
+
383
+ entry = {
384
+ objectID: entry_id,
385
+ language: 'en',
386
+ word: 'down'
387
+ }
388
+ @client.save_dictionary_entries!('stopwords', [entry])
389
+
390
+ stopwords = @client.search_dictionary_entries('stopwords', entry_id)
391
+ assert_equal 1, stopwords[:nbHits]
392
+ assert_equal stopwords[:hits][0][:objectID], entry[:objectID]
393
+ assert_equal stopwords[:hits][0][:word], entry[:word]
394
+
395
+ @client.delete_dictionary_entries!('stopwords', [entry_id])
396
+ assert_equal 0, @client.search_dictionary_entries('stopwords', entry_id)[:nbHits]
397
+
398
+ old_dictionary_state = @client.search_dictionary_entries('stopwords', '')
399
+ old_dictionary_entries = old_dictionary_state[:hits].map do |hit|
400
+ hit.reject { |key| key == :type }
401
+ end
402
+
403
+ @client.save_dictionary_entries!('stopwords', [entry])
404
+ assert_equal 1, @client.search_dictionary_entries('stopwords', entry_id)[:nbHits]
405
+
406
+ @client.replace_dictionary_entries!('stopwords', old_dictionary_entries)
407
+ assert_equal 0, @client.search_dictionary_entries('stopwords', entry_id)[:nbHits]
408
+
409
+ stopwords_settings = {
410
+ disableStandardEntries: {
411
+ stopwords: {
412
+ en: true
413
+ }
414
+ }
415
+ }
416
+
417
+ @client.set_dictionary_settings!(stopwords_settings)
418
+
419
+ assert_equal @client.get_dictionary_settings, stopwords_settings
420
+ end
421
+
422
+ def test_plurals_dictionaries
423
+ entry_id = SecureRandom.hex
424
+ assert_equal 0, @client.search_dictionary_entries('plurals', entry_id)[:nbHits]
425
+
426
+ entry = {
427
+ objectID: entry_id,
428
+ language: 'fr',
429
+ words: %w(cheval chevaux)
430
+ }
431
+ @client.save_dictionary_entries!('plurals', [entry])
432
+
433
+ plurals = @client.search_dictionary_entries('plurals', entry_id)
434
+ assert_equal 1, plurals[:nbHits]
435
+ assert_equal plurals[:hits][0][:objectID], entry[:objectID]
436
+ assert_equal plurals[:hits][0][:words], entry[:words]
437
+
438
+ @client.delete_dictionary_entries!('plurals', [entry_id])
439
+ assert_equal 0, @client.search_dictionary_entries('plurals', entry_id)[:nbHits]
440
+ end
441
+
442
+ def test_compounds_dictionaries
443
+ entry_id = SecureRandom.hex
444
+ assert_equal 0, @client.search_dictionary_entries('compounds', entry_id)[:nbHits]
445
+
446
+ entry = {
447
+ objectID: entry_id,
448
+ language: 'de',
449
+ word: 'kopfschmerztablette',
450
+ decomposition: %w(kopf schmerz tablette)
451
+ }
452
+ @client.save_dictionary_entries!('compounds', [entry])
453
+
454
+ compounds = @client.search_dictionary_entries('compounds', entry_id)
455
+ assert_equal 1, compounds[:nbHits]
456
+ assert_equal compounds[:hits][0][:objectID], entry[:objectID]
457
+ assert_equal compounds[:hits][0][:word], entry[:word]
458
+ assert_equal compounds[:hits][0][:decomposition], entry[:decomposition]
459
+
460
+ @client.delete_dictionary_entries!('compounds', [entry_id])
461
+ assert_equal 0, @client.search_dictionary_entries('compounds', entry_id)[:nbHits]
462
+ end
463
+ end
370
464
  end
371
465
  end
@@ -274,6 +274,9 @@ class SearchIndexTest < BaseTest
274
274
  @index.set_settings!(settings)
275
275
 
276
276
  assert_equal @index.get_settings, settings
277
+
278
+ # check that the forwardToReplicas parameter is passed correctly
279
+ assert @index.set_settings!(settings, { forwardToReplicas: true })
277
280
  end
278
281
  end
279
282
 
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?
@@ -87,3 +103,15 @@ def rule_without_metadata(rule)
87
103
  rule.delete(:_metadata)
88
104
  rule
89
105
  end
106
+
107
+ def retry_test(delay = 0.1, max_retries = 30)
108
+ (1...max_retries).each do |i|
109
+ begin
110
+ return yield
111
+ rescue Algolia::AlgoliaHttpError
112
+ sleep delay * i
113
+ end
114
+ end
115
+
116
+ raise StandardError, 'reached the maximum number of retries'
117
+ end
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.0.4
4
+ version: 2.2.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Algolia
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-01-05 00:00:00.000000000 Z
11
+ date: 2021-12-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -218,6 +218,8 @@ 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/personalization_config.rb
222
+ - lib/algolia/config/recommend_config.rb
221
223
  - lib/algolia/config/recommendation_config.rb
222
224
  - lib/algolia/config/search_config.rb
223
225
  - lib/algolia/defaults.rb
@@ -234,10 +236,13 @@ files:
234
236
  - lib/algolia/iterators/rule_iterator.rb
235
237
  - lib/algolia/iterators/synonym_iterator.rb
236
238
  - lib/algolia/logger_helper.rb
239
+ - lib/algolia/personalization_client.rb
240
+ - lib/algolia/recommend_client.rb
237
241
  - lib/algolia/recommendation_client.rb
238
242
  - lib/algolia/responses/add_api_key_response.rb
239
243
  - lib/algolia/responses/base_response.rb
240
244
  - lib/algolia/responses/delete_api_key_response.rb
245
+ - lib/algolia/responses/dictionary_response.rb
241
246
  - lib/algolia/responses/indexing_response.rb
242
247
  - lib/algolia/responses/multiple_batch_indexing_response.rb
243
248
  - lib/algolia/responses/multiple_response.rb
@@ -273,6 +278,8 @@ files:
273
278
  - test/algolia/integration/base_test.rb
274
279
  - test/algolia/integration/insights_client_test.rb
275
280
  - test/algolia/integration/mocks/mock_requester.rb
281
+ - test/algolia/integration/personalization_client_test.rb
282
+ - test/algolia/integration/recommend_client_test.rb
276
283
  - test/algolia/integration/recommendation_client_test.rb
277
284
  - test/algolia/integration/search_client_test.rb
278
285
  - test/algolia/integration/search_index_test.rb
@@ -304,7 +311,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
304
311
  - !ruby/object:Gem::Version
305
312
  version: '0'
306
313
  requirements: []
307
- rubygems_version: 3.1.4
314
+ rubygems_version: 3.0.6
308
315
  signing_key:
309
316
  specification_version: 4
310
317
  summary: A simple Ruby client for the algolia.com REST API
@@ -314,6 +321,8 @@ test_files:
314
321
  - test/algolia/integration/base_test.rb
315
322
  - test/algolia/integration/insights_client_test.rb
316
323
  - test/algolia/integration/mocks/mock_requester.rb
324
+ - test/algolia/integration/personalization_client_test.rb
325
+ - test/algolia/integration/recommend_client_test.rb
317
326
  - test/algolia/integration/recommendation_client_test.rb
318
327
  - test/algolia/integration/search_client_test.rb
319
328
  - test/algolia/integration/search_index_test.rb