module Algolia module Search # Class Index class Index include CallType include Helpers attr_reader :name, :transporter, :config # Initialize an index # # @param name [String] name of the index # @param transporter [Object] transport object used for the connection # @param config [Config] a Config object which contains your APP_ID and API_KEY # def initialize(name, transporter, config) @name = name @transporter = transporter @config = config end # # # # # # # # # # # # # # # # # # # # # # MISC # # # # # # # # # # # # # # # # # # # # # # Wait the publication of a task on the server. # All server task are asynchronous and you can check with this method that the task is published. # # @param task_id the id of the task returned by server # @param time_before_retry the time in milliseconds before retry (default = 100ms) # @param opts [Hash] contains extra parameters to send with your query # def wait_task(task_id, time_before_retry = Defaults::WAIT_TASK_DEFAULT_TIME_BEFORE_RETRY, opts = {}) loop do status = get_task_status(task_id, opts) if status == 'published' return end sleep(time_before_retry / 1000) end end # Check the status of a task on the server. # All server task are asynchronous and you can check the status of a task with this method. # # @param task_id [Integer] the id of the task returned by server # @param opts [Hash] contains extra parameters to send with your query # def get_task_status(task_id, opts = {}) res = @transporter.read(:GET, path_encode('/1/indexes/%s/task/%s', @name, task_id), {}, opts) get_option(res, 'status') end # Delete the index content # # @param opts [Hash] contains extra parameters to send with your query # def clear_objects(opts = {}) response = @transporter.write(:POST, path_encode('/1/indexes/%s/clear', @name), {}, opts) IndexingResponse.new(self, response) end # Delete the index content and wait for operation to complete # # @param opts [Hash] contains extra parameters to send with your query # def clear_objects!(opts = {}) response = clear_objects(opts) response.wait(opts) end # Delete an existing index # # @param opts [Hash] contains extra parameters to send with your query # def delete(opts = {}) response = @transporter.write(:DELETE, path_encode('/1/indexes/%s', @name), opts) IndexingResponse.new(self, response) end # Delete an existing index and wait for operation to complete # # @param opts [Hash] contains extra parameters to send with your query # def delete!(opts = {}) response = delete(opts) response.wait(opts) end # Find object by the given condition. # # Options can be passed in request_options body: # - query (string): pass a query # - paginate (bool): choose if you want to iterate through all the # documents (true) or only the first page (false). Default is true. # The function takes a block to filter the results from search query # Usage example: # index.find_object({'query' => '', 'paginate' => true}) {|obj| obj.key?('company') and obj['company'] == 'Apple'} # # @param callback [Lambda] contains extra parameters to send with your query # @param opts [Hash] contains extra parameters to send with your query # # @return [Hash|AlgoliaHttpError] the matching object and its position in the result set # def find_object(callback, opts = {}) request_options = symbolize_hash(opts) paginate = true page = 0 query = request_options.delete(:query) || '' paginate = request_options.delete(:paginate) if request_options.has_key?(:paginate) has_next_page = true while has_next_page request_options[:page] = page res = symbolize_hash(search(query, request_options)) res[:hits].each_with_index do |hit, i| if callback.call(hit) return { object: hit, position: i, page: page } end end has_next_page = page + 1 < res[:nbPages] raise AlgoliaHttpError.new(404, 'Object not found') unless paginate && has_next_page page += 1 end end # Retrieve the given object position in a set of results. # # @param [Array] objects the result set to browse # @param [String] object_id the object to look for # # @return [Integer] position of the object, or -1 if it's not in the array # def self.get_object_position(objects, object_id) hits = get_option(objects, 'hits') hits.find_index { |hit| get_option(hit, 'objectID') == object_id } || -1 end # Copy the current index to the given destination name # # @param name [String] destination index name # @param opts [Hash] contains extra parameters to send with your query # # @return [IndexingResponse] # def copy_to(name, opts = {}) response = @transporter.write(:POST, path_encode('/1/indexes/%s/operation', @name), { operation: 'copy', destination: name }, opts) IndexingResponse.new(self, response) end # Move the current index to the given destination name # # @param name [String] destination index name # @param opts [Hash] contains extra parameters to send with your query # # @return [IndexingResponse] # def move_to(name, opts = {}) response = @transporter.write(:POST, path_encode('/1/indexes/%s/operation', @name), { operation: 'move', destination: name }, opts) IndexingResponse.new(self, response) end # # # # # # # # # # # # # # # # # # # # # # INDEXING # # # # # # # # # # # # # # # # # # # # # # Retrieve one object from the index # # @param object_id [String] # @param opts [Hash] contains extra parameters to send with your query # # @return [Hash] # def get_object(object_id, opts = {}) @transporter.read(:GET, path_encode('/1/indexes/%s/%s', @name, object_id), {}, opts) end # Retrieve one or more objects in a single API call # # @param object_ids [Array] # @param opts [Hash] contains extra parameters to send with your query # # @return [Hash] # def get_objects(object_ids, opts = {}) request_options = symbolize_hash(opts) attributes_to_retrieve = get_option(request_options, 'attributesToRetrieve') request_options.delete(:attributesToRetrieve) requests = [] object_ids.each do |object_id| request = { indexName: @name, objectID: object_id.to_s } if attributes_to_retrieve request[:attributesToRetrieve] = attributes_to_retrieve end requests.push(request) end @transporter.read(:POST, '/1/indexes/*/objects', { 'requests': requests }, opts) end # Add an object to the index # # @param object [Hash] the object to save # @param opts [Hash] contains extra parameters to send with your query # # @return [IndexingResponse] # def save_object(object, opts = {}) save_objects([object], opts) end # Add an object to the index and wait for operation to complete # # @param object [Hash] the object to save # @param opts [Hash] contains extra parameters to send with your query # # @return [IndexingResponse] # def save_object!(object, opts = {}) response = save_objects([object], opts) response.wait(opts) end # Add several objects to the index # # @param objects [Array] the objects to save # @param opts [Hash] contains extra parameters to send with your query # # @return [IndexingResponse] # def save_objects(objects, opts = {}) request_options = symbolize_hash(opts) generate_object_id = request_options[:auto_generate_object_id_if_not_exist] || false request_options.delete(:auto_generate_object_id_if_not_exist) if generate_object_id IndexingResponse.new(self, raw_batch(chunk('addObject', objects), request_options)) else IndexingResponse.new(self, raw_batch(chunk('updateObject', objects, true), request_options)) end end # Add several objects to the index and wait for operation to complete # # @param objects [Array] the objects to save # @param opts [Hash] contains extra parameters to send with your query # # @return [IndexingResponse] # def save_objects!(objects, opts = {}) response = save_objects(objects, opts) response.wait(opts) end # Partially update an object # # @param object [String] object ID to partially update # @param opts [Hash] contains extra parameters to send with your query # # @return [IndexingResponse] # def partial_update_object(object, opts = {}) partial_update_objects([object], opts) end # Partially update an object and wait for operation to complete # # @param object [String] object ID to partially update # @param opts [Hash] contains extra parameters to send with your query # # @return [IndexingResponse] # def partial_update_object!(object, opts = {}) response = partial_update_objects([object], opts) response.wait(opts) end # Partially update several objects # # @param objects [Array] array of objectIDs to partially update # @param opts [Hash] contains extra parameters to send with your query # # @return [IndexingResponse] # def partial_update_objects(objects, opts = {}) generate_object_id = false request_options = symbolize_hash(opts) if get_option(request_options, 'createIfNotExists') generate_object_id = true request_options.delete(:createIfNotExists) end if generate_object_id IndexingResponse.new(self, raw_batch(chunk('partialUpdateObject', objects), request_options)) else IndexingResponse.new(self, raw_batch(chunk('partialUpdateObjectNoCreate', objects), request_options)) end end # Partially update several objects and wait for operation to complete # # @param objects [Array] array of objectIDs to partially update # @param opts [Hash] contains extra parameters to send with your query # # @return [IndexingResponse] # def partial_update_objects!(objects, opts = {}) response = partial_update_objects(objects, opts) response.wait(opts) end # Delete an existing object from an index # # @param object_id [String] # @param opts [Hash] contains extra parameters to send with your query # # @return [IndexingResponse] # def delete_object(object_id, opts = {}) delete_objects([object_id], opts) end # Delete an existing object from an index and wait for operation to complete # # @param object_id [String] # @param opts [Hash] contains extra parameters to send with your query # # @return [IndexingResponse] # def delete_object!(object_id, opts = {}) response = delete_objects([object_id], opts) response.wait(opts) end # Delete several existing objects from an index # # @param object_ids [Array] # @param opts [Hash] contains extra parameters to send with your query # # @return [IndexingResponse] # def delete_objects(object_ids, opts = {}) objects = object_ids.map do |object_id| { objectID: object_id } end IndexingResponse.new(self, raw_batch(chunk('deleteObject', objects), opts)) end # Delete several existing objects from an index and wait for operation to complete # # @param object_ids [Array] # @param opts [Hash] contains extra parameters to send with your query # # @return [IndexingResponse] # def delete_objects!(object_ids, opts = {}) response = delete_objects(object_ids, opts) response.wait(opts) end # Delete all records matching the query # # @param filters [Hash] # @param opts [Hash] contains extra parameters to send with your query # # @return [IndexingResponse] # def delete_by(filters, opts = {}) response = @transporter.write(:POST, path_encode('/1/indexes/%s/deleteByQuery', @name), filters, opts) IndexingResponse.new(self, response) end # Delete all records matching the query and wait for operation to complete # # @param filters [Hash] # @param opts [Hash] contains extra parameters to send with your query # # @return [IndexingResponse] # def delete_by!(filters, opts = {}) response = delete_by(filters, opts) response.wait(opts) end # Send a batch request # # @param requests [Hash] hash containing the requests to batch # @param opts [Hash] contains extra parameters to send with your query # # @return [IndexingResponse] # def batch(requests, opts = {}) response = raw_batch(requests, opts) IndexingResponse.new(self, response) end # Send a batch request and wait for operation to complete # # @param requests [Hash] hash containing the requests to batch # @param opts [Hash] contains extra parameters to send with your query # # @return [IndexingResponse] # def batch!(requests, opts = {}) response = batch(requests, opts) response.wait(opts) end # # # # # # # # # # # # # # # # # # # # # # QUERY RULES # # # # # # # # # # # # # # # # # # # # # # Retrieve the Rule with the specified objectID # # @param object_id [String] # @param opts [Hash] contains extra parameters to send with your query # # @return [Hash] # def get_rule(object_id, opts = {}) @transporter.read(:GET, path_encode('/1/indexes/%s/rules/%s', @name, object_id), {}, opts) end # Create or update a rule # # @param rule [Hash] a hash containing a rule objectID and different conditions/consequences # @param opts [Hash] contains extra parameters to send with your query # # @return [Array, IndexingResponse] # def save_rule(rule, opts = {}) save_rules([rule], opts) end # Create or update a rule and wait for operation to complete # # @param rule [Hash] a hash containing a rule objectID and different conditions/consequences # @param opts [Hash] contains extra parameters to send with your query # # @return [Array, IndexingResponse] # def save_rule!(rule, opts = {}) response = save_rules([rule], opts) response.wait(opts) end # Create or update rules # # @param rules [Array] an array of hashes containing a rule objectID and different conditions/consequences # @param opts [Hash] contains extra parameters to send with your query # # @return [Array, IndexingResponse] # def save_rules(rules, opts = {}) if rules.is_a?(RuleIterator) iterated = [] rules.each do |rule| iterated.push(rule) end rules = iterated end if rules.empty? return [] end forward_to_replicas = false clear_existing_rules = false request_options = symbolize_hash(opts) if request_options[:forwardToReplicas] forward_to_replicas = true request_options.delete(:forwardToReplicas) end if request_options[:clearExistingRules] clear_existing_rules = true request_options.delete(:clearExistingRules) end rules.each do |rule| get_object_id(rule) end response = @transporter.write(:POST, path_encode('/1/indexes/%s/rules/batch', @name) + handle_params({ forwardToReplicas: forward_to_replicas, clearExistingRules: clear_existing_rules }), rules, request_options) IndexingResponse.new(self, response) end # Create or update rules and wait for operation to complete # # @param rules [Array] an array of hashes containing a rule objectID and different conditions/consequences # @param opts [Hash] contains extra parameters to send with your query # # @return [Array, IndexingResponse] # def save_rules!(rules, opts = {}) response = save_rules(rules, opts) response.wait(opts) end # Delete all Rules in the index # # @param opts [Hash] contains extra parameters to send with your query # # @return [IndexingResponse] # def clear_rules(opts = {}) forward_to_replicas = false request_options = symbolize_hash(opts) if request_options[:forwardToReplicas] forward_to_replicas = true request_options.delete(:forwardToReplicas) end response = @transporter.write(:POST, path_encode('1/indexes/%s/rules/clear', @name) + handle_params({ forwardToReplicas: forward_to_replicas }), '', request_options) IndexingResponse.new(self, response) end # Delete all Rules in the index and wait for operation to complete # # @param opts [Hash] contains extra parameters to send with your query # # @return [IndexingResponse] # def clear_rules!(opts = {}) response = clear_rules(opts) response.wait(opts) end # Delete the Rule with the specified objectID # # @param object_id [String] # @param opts [Hash] contains extra parameters to send with your query # # @return [IndexingResponse] # def delete_rule(object_id, opts = {}) forward_to_replicas = false request_options = symbolize_hash(opts) if request_options[:forwardToReplicas] forward_to_replicas = true request_options.delete(:forwardToReplicas) end response = @transporter.write( :DELETE, path_encode('1/indexes/%s/rules/%s', @name, object_id) + handle_params({ forwardToReplicas: forward_to_replicas }), '', request_options ) IndexingResponse.new(self, response) end # Delete the Rule with the specified objectID and wait for operation to complete # # @param object_id [String] # @param opts [Hash] contains extra parameters to send with your query # # @return [IndexingResponse] # def delete_rule!(object_id, opts = {}) response = delete_rule(object_id, opts) response.wait(opts) end # # # # # # # # # # # # # # # # # # # # # # SYNONYMS # # # # # # # # # # # # # # # # # # # # # # Fetch a synonym object identified by its objectID # # @param object_id [String] # @param opts [Hash] contains extra parameters to send with your query # # @return [Hash] # def get_synonym(object_id, opts = {}) @transporter.read(:GET, path_encode('/1/indexes/%s/synonyms/%s', @name, object_id), {}, opts) end # Create a new synonym object or update the existing synonym object with the given object ID # # @param synonym [Hash] Synonym object # @param opts [Hash] contains extra parameters to send with your query # # @return [Array, IndexingResponse] # def save_synonym(synonym, opts = {}) save_synonyms([synonym], opts) end # Create a new synonym object or update the existing synonym object with the given object ID # and wait for operation to finish # # @param synonym [Hash] Synonym object # @param opts [Hash] contains extra parameters to send with your query # # @return [Array, IndexingResponse] # def save_synonym!(synonym, opts = {}) response = save_synonyms([synonym], opts) response.wait(opts) end # Create/update multiple synonym objects at once, potentially replacing the entire list of synonyms if # replaceExistingSynonyms is true # # @param synonyms [Array] Array of Synonym objects # @param opts [Hash] contains extra parameters to send with your query # # @return [Array, IndexingResponse] # def save_synonyms(synonyms, opts = {}) if synonyms.is_a?(SynonymIterator) iterated = [] synonyms.each do |synonym| iterated.push(synonym) end synonyms = iterated end if synonyms.empty? return [] end synonyms.each do |synonym| get_object_id(synonym) end forward_to_replicas = false replace_existing_synonyms = false request_options = symbolize_hash(opts) if request_options[:forwardToReplicas] forward_to_replicas = true request_options.delete(:forwardToReplicas) end if request_options[:replaceExistingSynonyms] replace_existing_synonyms = true request_options.delete(:replaceExistingSynonyms) end response = @transporter.write( :POST, path_encode('/1/indexes/%s/synonyms/batch', @name) + handle_params({ forwardToReplicas: forward_to_replicas, replaceExistingSynonyms: replace_existing_synonyms }), synonyms, request_options ) IndexingResponse.new(self, response) end # Create/update multiple synonym objects at once, potentially replacing the entire list of synonyms if # replaceExistingSynonyms is true and wait for operation to complete # # @param synonyms [Array] Array of Synonym objects # @param opts [Hash] contains extra parameters to send with your query # # @return [Array, IndexingResponse] # def save_synonyms!(synonyms, opts = {}) response = save_synonyms(synonyms, opts) response.wait(opts) end # Delete all synonyms from the index # # @param opts [Hash] contains extra parameters to send with your query # # @return [IndexingResponse] # def clear_synonyms(opts = {}) forward_to_replicas = false request_options = symbolize_hash(opts) if request_options[:forwardToReplicas] forward_to_replicas = true request_options.delete(:forwardToReplicas) end response = @transporter.write( :POST, path_encode('1/indexes/%s/synonyms/clear', @name) + handle_params({ forwardToReplicas: forward_to_replicas }), '', request_options ) IndexingResponse.new(self, response) end # Delete all synonyms from the index and wait for operation to complete # # @param opts [Hash] contains extra parameters to send with your query # # @return [IndexingResponse] # def clear_synonyms!(opts = {}) response = clear_synonyms(opts) response.wait(opts) end # Delete a single synonyms set, identified by the given objectID # # @param opts [Hash] contains extra parameters to send with your query # # @return [IndexingResponse] # def delete_synonym(object_id, opts = {}) forward_to_replicas = false request_options = symbolize_hash(opts) if request_options[:forwardToReplicas] forward_to_replicas = true request_options.delete(:forwardToReplicas) end response = @transporter.write( :DELETE, path_encode('1/indexes/%s/synonyms/%s', @name, object_id) + handle_params({ forwardToReplicas: forward_to_replicas }), '', request_options ) IndexingResponse.new(self, response) end # Delete a single synonyms set, identified by the given objectID and wait for operation to complete # # @param opts [Hash] contains extra parameters to send with your query # # @return [IndexingResponse] # def delete_synonym!(object_id, opts = {}) response = delete_synonym(object_id, opts) response.wait(opts) end # # # # # # # # # # # # # # # # # # # # # # BROWSING # # # # # # # # # # # # # # # # # # # # # # Browse all index content # # @param opts [Hash] contains extra parameters to send with your query # # @return [Enumerator, ObjectIterator] # def browse_objects(opts = {}, &block) if block_given? ObjectIterator.new(@transporter, @name, opts).each(&block) else ObjectIterator.new(@transporter, @name, opts) end end # Browse all rules # # @param opts [Hash] contains extra parameters to send with your query # # @return [Enumerator, RuleIterator] # def browse_rules(opts = {}, &block) if block_given? RuleIterator.new(@transporter, @name, opts).each(&block) else RuleIterator.new(@transporter, @name, opts) end end # Browse all synonyms # # @param opts [Hash] contains extra parameters to send with your query # # @return [Enumerator, SynonymIterator] # def browse_synonyms(opts = {}, &block) if block_given? SynonymIterator.new(@transporter, @name, opts).each(&block) else SynonymIterator.new(@transporter, @name, opts) end end # # # # # # # # # # # # # # # # # # # # # # REPLACING # # # # # # # # # # # # # # # # # # # # # # Replace all objects in the index # # @param objects [Array] Array of objects # @param opts [Hash] contains extra parameters to send with your query # # @return [Enumerator, SynonymIterator] # def replace_all_objects(objects, opts = {}) safe = false request_options = symbolize_hash(opts) if request_options[:safe] safe = true request_options.delete(:safe) end tmp_index_name = @name + '_tmp_' + rand(10000000).to_s copy_to_response = copy_to(tmp_index_name, request_options.merge({ scope: %w(settings synonyms rules) })) if safe copy_to_response.wait end # TODO: consider create a new client with state of retry is shared tmp_client = Algolia::Search::Client.new(@config) tmp_index = tmp_client.init_index(tmp_index_name) save_objects_response = tmp_index.save_objects(objects, request_options) if safe save_objects_response.wait end move_to_response = tmp_index.move_to(@name) if safe move_to_response.wait end end # Replace all objects in the index and wait for the operation to complete # # @param objects [Array] Array of objects # @param opts [Hash] contains extra parameters to send with your query # # @return [Enumerator, SynonymIterator] # def replace_all_objects!(objects, opts = {}) replace_all_objects(objects, opts.merge(safe: true)) end # Replace all rules in the index # # @param rules [Array] Array of rules # @param opts [Hash] contains extra parameters to send with your query # # @return [Array, IndexingResponse] # def replace_all_rules(rules, opts = {}) request_options = symbolize_hash(opts) request_options[:clearExistingRules] = true save_rules(rules, request_options) end # Replace all rules in the index and wait for the operation to complete # # @param rules [Array] Array of rules # @param opts [Hash] contains extra parameters to send with your query # # @return [Array, IndexingResponse] # def replace_all_rules!(rules, opts = {}) request_options = symbolize_hash(opts) request_options[:clearExistingRules] = true save_rules!(rules, request_options) end # Replace all synonyms in the index # # @param synonyms [Array] Array of synonyms # @param opts [Hash] contains extra parameters to send with your query # # @return [Array, IndexingResponse] # def replace_all_synonyms(synonyms, opts = {}) request_options = symbolize_hash(opts) request_options[:replaceExistingSynonyms] = true save_synonyms(synonyms, request_options) end # Replace all synonyms in the index and wait for the operation to complete # # @param synonyms [Array] Array of synonyms # @param opts [Hash] contains extra parameters to send with your query # # @return [Array, IndexingResponse] # def replace_all_synonyms!(synonyms, opts = {}) request_options = symbolize_hash(opts) request_options[:replaceExistingSynonyms] = true save_synonyms!(synonyms, request_options) end # # # # # # # # # # # # # # # # # # # # # # SEARCHING # # # # # # # # # # # # # # # # # # # # # # Perform a search on the index # # @param query the full text query # @param opts [Hash] contains extra parameters to send with your query # # @return [Hash] # def search(query, opts = {}) @transporter.read(:POST, path_encode('/1/indexes/%s/query', @name), { 'query': query.to_s }, opts) end # Search for values of a given facet, optionally restricting the returned values to those contained # in objects matching other search criteria # # @param facet_name [String] # @param facet_query [String] # @param opts [Hash] contains extra parameters to send with your query # # @return [Hash] # def search_for_facet_values(facet_name, facet_query, opts = {}) @transporter.read(:POST, path_encode('/1/indexes/%s/facets/%s/query', @name, facet_name), { 'facetQuery': facet_query }, opts) end # Search or browse all synonyms, optionally filtering them by type # # @param query [String] Search for specific synonyms matching this string # @param opts [Hash] contains extra parameters to send with your query # # @return [Hash] # def search_synonyms(query, opts = {}) @transporter.read(:POST, path_encode('/1/indexes/%s/synonyms/search', @name), { query: query.to_s }, opts) end # Search or browse all rules, optionally filtering them by type # # @param query [String] Search for specific rules matching this string # @param opts [Hash] contains extra parameters to send with your query # # @return [Hash] # def search_rules(query, opts = {}) @transporter.read(:POST, path_encode('/1/indexes/%s/rules/search', @name), { query: query.to_s }, opts) end # # # # # # # # # # # # # # # # # # # # # # SETTINGS # # # # # # # # # # # # # # # # # # # # # # Retrieve index settings # # @param opts [Hash] contains extra parameters to send with your query # # @return [Hash] # def get_settings(opts = {}) response = @transporter.read(:GET, path_encode('/1/indexes/%s/settings', @name) + handle_params({ getVersion: 2 }), {}, opts) deserialize_settings(response, @config.symbolize_keys) end # Update some index settings. Only specified settings are overridden # # @param settings [Hash] the settings to update # @param opts [Hash] contains extra parameters to send with your query # # @return [IndexingResponse] # def set_settings(settings, opts = {}) request_options = symbolize_hash(opts) forward_to_replicas = request_options.delete(:forwardToReplicas) || false response = @transporter.write( :PUT, path_encode('/1/indexes/%s/settings', @name) + handle_params({ forwardToReplicas: forward_to_replicas }), settings, request_options ) IndexingResponse.new(self, response) end # Update some index settings and wait for operation to complete. # Only specified settings are overridden # # @param settings [Hash] the settings to update # @param opts [Hash] contains extra parameters to send with your query # # @return [IndexingResponse] # def set_settings!(settings, opts = {}) response = set_settings(settings, opts) response.wait(opts) end # # # # # # # # # # # # # # # # # # # # # # EXISTS # # # # # # # # # # # # # # # # # # # # # # Checks if the current index exists # # @return [Boolean] # def exists begin get_settings rescue AlgoliaHttpError => e if e.code == 404 return false end raise e end true end # # Aliases the exists method # alias_method :exists?, :exists # # # # # # # # # # # # # # # # # # # # # # PRIVATE # # # # # # # # # # # # # # # # # # # # # private def raw_batch(requests, opts) @transporter.write(:POST, path_encode('/1/indexes/%s/batch', @name), { requests: requests }, opts) end end end end