algolia 2.0.4 → 2.2.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.
- checksums.yaml +4 -4
- data/.circleci/config.yml +10 -1
- data/CHANGELOG.md +27 -1
- data/README.md +1 -1
- data/lib/algolia/config/personalization_config.rb +20 -0
- data/lib/algolia/config/recommend_config.rb +6 -0
- data/lib/algolia/config/recommendation_config.rb +2 -15
- data/lib/algolia/helpers.rb +49 -0
- data/lib/algolia/http/http_requester.rb +4 -4
- data/lib/algolia/personalization_client.rb +60 -0
- data/lib/algolia/recommend_client.rb +134 -0
- data/lib/algolia/recommendation_client.rb +2 -55
- data/lib/algolia/responses/dictionary_response.rb +33 -0
- data/lib/algolia/search_client.rb +176 -2
- data/lib/algolia/search_index.rb +9 -50
- data/lib/algolia/version.rb +1 -1
- data/lib/algolia.rb +5 -0
- data/test/algolia/integration/analytics_client_test.rb +6 -2
- data/test/algolia/integration/mocks/mock_requester.rb +13 -11
- data/test/algolia/integration/personalization_client_test.rb +30 -0
- data/test/algolia/integration/recommend_client_test.rb +70 -0
- data/test/algolia/integration/search_client_test.rb +106 -12
- data/test/algolia/integration/search_index_test.rb +3 -0
- data/test/test_helper.rb +28 -0
- metadata +12 -3
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 5c2f4626569fa71c66f1801a6608a0d66bdd7afc5d2d42342856d8083281d0ee
         | 
| 4 | 
            +
              data.tar.gz: bbc716503ac0354dd80a1e5d1196cfc8ff5e8d80c3c166c196bd1ec5e227a446
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 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. | 
| 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
         | 
| @@ -1,20 +1,7 @@ | |
| 1 1 | 
             
            module Algolia
         | 
| 2 2 | 
             
              module Recommendation
         | 
| 3 | 
            -
                 | 
| 4 | 
            -
             | 
| 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
         | 
    
        data/lib/algolia/helpers.rb
    CHANGED
    
    | @@ -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 | 
| 13 | 
            -
                    @logger | 
| 14 | 
            -
                    @ | 
| 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 | 
            -
                    @ | 
| 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 | 
            -
                 | 
| 4 | 
            -
             | 
| 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 | 
            -
                  #  | 
| 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 = {})
         | 
    
        data/lib/algolia/search_index.rb
    CHANGED
    
    | @@ -987,7 +987,15 @@ module Algolia | |
| 987 987 | 
             
                  # @return [IndexingResponse]
         | 
| 988 988 | 
             
                  #
         | 
| 989 989 | 
             
                  def set_settings(settings, opts = {})
         | 
| 990 | 
            -
                     | 
| 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
         | 
    
        data/lib/algolia/version.rb
    CHANGED
    
    
    
        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   =  | 
| 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   =  | 
| 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,  | 
| 7 | 
            -
                 | 
| 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 | 
            -
                   | 
| 14 | 
            -
                   | 
| 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:  | 
| 21 | 
            -
                  body:  | 
| 22 | 
            -
                  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 =  | 
| 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 | 
            -
                   | 
| 238 | 
            -
                     | 
| 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 =  | 
| 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 | 
            -
                     | 
| 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. | 
| 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- | 
| 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. | 
| 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
         |