All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.algolia.api.SearchClient Maven / Gradle / Ivy

There is a newer version: 4.10.2
Show newest version
// Code generated by OpenAPI Generator (https://openapi-generator.tech), manual changes will be lost
// - read more on https://github.com/algolia/api-clients-automation. DO NOT EDIT.

package com.algolia.api;

import com.algolia.ApiClient;
import com.algolia.config.*;
import com.algolia.config.ClientOptions;
import com.algolia.exceptions.*;
import com.algolia.model.search.*;
import com.algolia.utils.*;
import com.fasterxml.jackson.core.type.TypeReference;
import java.util.ArrayList;
import java.util.Collections;
import java.util.EnumSet;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.CompletableFuture;
import java.util.function.IntUnaryOperator;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class SearchClient extends ApiClient {

  public SearchClient(String appId, String apiKey) {
    this(appId, apiKey, null);
  }

  public SearchClient(String appId, String apiKey, ClientOptions options) {
    super(appId, apiKey, "Search", options, getDefaultHosts(appId));
  }

  private static List getDefaultHosts(String appId) {
    List hosts = new ArrayList<>();
    hosts.add(new Host(appId + "-dsn.algolia.net", EnumSet.of(CallType.READ)));
    hosts.add(new Host(appId + ".algolia.net", EnumSet.of(CallType.WRITE)));

    List commonHosts = new ArrayList<>();
    hosts.add(new Host(appId + "-1.algolianet.net", EnumSet.of(CallType.READ, CallType.WRITE)));
    hosts.add(new Host(appId + "-2.algolianet.net", EnumSet.of(CallType.READ, CallType.WRITE)));
    hosts.add(new Host(appId + "-3.algolianet.net", EnumSet.of(CallType.READ, CallType.WRITE)));

    Collections.shuffle(commonHosts, new Random());

    return Stream.concat(hosts.stream(), commonHosts.stream()).collect(Collectors.toList());
  }

  /**
   * Add a new API key with specific permissions and restrictions. The request must be authenticated
   * with the admin API key. The response returns an API key string.
   *
   * @param apiKey (required)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public AddApiKeyResponse addApiKey(ApiKey apiKey, RequestOptions requestOptions) throws AlgoliaRuntimeException {
    return LaunderThrowable.await(addApiKeyAsync(apiKey, requestOptions));
  }

  /**
   * Add a new API key with specific permissions and restrictions. The request must be authenticated
   * with the admin API key. The response returns an API key string.
   *
   * @param apiKey (required)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public AddApiKeyResponse addApiKey(ApiKey apiKey) throws AlgoliaRuntimeException {
    return this.addApiKey(apiKey, null);
  }

  /**
   * (asynchronously) Add a new API key with specific permissions and restrictions. The request must
   * be authenticated with the admin API key. The response returns an API key string.
   *
   * @param apiKey (required)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture addApiKeyAsync(ApiKey apiKey, RequestOptions requestOptions) throws AlgoliaRuntimeException {
    if (apiKey == null) {
      throw new AlgoliaRuntimeException("Parameter `apiKey` is required when calling `addApiKey`.");
    }

    HttpRequest request = HttpRequest.builder().setPath("/1/keys").setMethod("POST").setBody(apiKey).build();

    return executeAsync(request, requestOptions, new TypeReference() {});
  }

  /**
   * (asynchronously) Add a new API key with specific permissions and restrictions. The request must
   * be authenticated with the admin API key. The response returns an API key string.
   *
   * @param apiKey (required)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture addApiKeyAsync(ApiKey apiKey) throws AlgoliaRuntimeException {
    return this.addApiKeyAsync(apiKey, null);
  }

  /**
   * If you use an existing `objectID`, the existing record will be replaced with the new one. To
   * update only some attributes of an existing record, use the [`partial`
   * operation](#tag/Records/operation/partialUpdateObject) instead. To add multiple records to your
   * index in a single API request, use the [`batch` operation](#tag/Records/operation/batch).
   *
   * @param indexName Index on which to perform the request. (required)
   * @param objectID Unique record (object) identifier. (required)
   * @param body Algolia record. (required)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public UpdatedAtWithObjectIdResponse addOrUpdateObject(String indexName, String objectID, Object body, RequestOptions requestOptions)
    throws AlgoliaRuntimeException {
    return LaunderThrowable.await(addOrUpdateObjectAsync(indexName, objectID, body, requestOptions));
  }

  /**
   * If you use an existing `objectID`, the existing record will be replaced with the new one. To
   * update only some attributes of an existing record, use the [`partial`
   * operation](#tag/Records/operation/partialUpdateObject) instead. To add multiple records to your
   * index in a single API request, use the [`batch` operation](#tag/Records/operation/batch).
   *
   * @param indexName Index on which to perform the request. (required)
   * @param objectID Unique record (object) identifier. (required)
   * @param body Algolia record. (required)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public UpdatedAtWithObjectIdResponse addOrUpdateObject(String indexName, String objectID, Object body) throws AlgoliaRuntimeException {
    return this.addOrUpdateObject(indexName, objectID, body, null);
  }

  /**
   * (asynchronously) If you use an existing `objectID`, the existing record will be
   * replaced with the new one. To update only some attributes of an existing record, use the
   * [`partial` operation](#tag/Records/operation/partialUpdateObject) instead. To add
   * multiple records to your index in a single API request, use the [`batch`
   * operation](#tag/Records/operation/batch).
   *
   * @param indexName Index on which to perform the request. (required)
   * @param objectID Unique record (object) identifier. (required)
   * @param body Algolia record. (required)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture addOrUpdateObjectAsync(
    String indexName,
    String objectID,
    Object body,
    RequestOptions requestOptions
  ) throws AlgoliaRuntimeException {
    if (indexName == null) {
      throw new AlgoliaRuntimeException("Parameter `indexName` is required when calling `addOrUpdateObject`.");
    }

    if (objectID == null) {
      throw new AlgoliaRuntimeException("Parameter `objectID` is required when calling `addOrUpdateObject`.");
    }

    if (body == null) {
      throw new AlgoliaRuntimeException("Parameter `body` is required when calling `addOrUpdateObject`.");
    }

    HttpRequest request = HttpRequest
      .builder()
      .setPath("/1/indexes/{indexName}/{objectID}", indexName, objectID)
      .setMethod("PUT")
      .setBody(body)
      .build();
    return executeAsync(request, requestOptions, new TypeReference() {});
  }

  /**
   * (asynchronously) If you use an existing `objectID`, the existing record will be
   * replaced with the new one. To update only some attributes of an existing record, use the
   * [`partial` operation](#tag/Records/operation/partialUpdateObject) instead. To add
   * multiple records to your index in a single API request, use the [`batch`
   * operation](#tag/Records/operation/batch).
   *
   * @param indexName Index on which to perform the request. (required)
   * @param objectID Unique record (object) identifier. (required)
   * @param body Algolia record. (required)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture addOrUpdateObjectAsync(String indexName, String objectID, Object body)
    throws AlgoliaRuntimeException {
    return this.addOrUpdateObjectAsync(indexName, objectID, body, null);
  }

  /**
   * Add a source to the list of allowed sources.
   *
   * @param source Source to add. (required)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CreatedAtResponse appendSource(Source source, RequestOptions requestOptions) throws AlgoliaRuntimeException {
    return LaunderThrowable.await(appendSourceAsync(source, requestOptions));
  }

  /**
   * Add a source to the list of allowed sources.
   *
   * @param source Source to add. (required)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CreatedAtResponse appendSource(Source source) throws AlgoliaRuntimeException {
    return this.appendSource(source, null);
  }

  /**
   * (asynchronously) Add a source to the list of allowed sources.
   *
   * @param source Source to add. (required)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture appendSourceAsync(Source source, RequestOptions requestOptions)
    throws AlgoliaRuntimeException {
    if (source == null) {
      throw new AlgoliaRuntimeException("Parameter `source` is required when calling `appendSource`.");
    }

    HttpRequest request = HttpRequest.builder().setPath("/1/security/sources/append").setMethod("POST").setBody(source).build();
    return executeAsync(request, requestOptions, new TypeReference() {});
  }

  /**
   * (asynchronously) Add a source to the list of allowed sources.
   *
   * @param source Source to add. (required)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture appendSourceAsync(Source source) throws AlgoliaRuntimeException {
    return this.appendSourceAsync(source, null);
  }

  /**
   * Assign or move a user ID to a cluster. The time it takes to move a user is proportional to the
   * amount of data linked to the user ID.
   *
   * @param xAlgoliaUserID userID to assign. (required)
   * @param assignUserIdParams (required)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CreatedAtResponse assignUserId(String xAlgoliaUserID, AssignUserIdParams assignUserIdParams, RequestOptions requestOptions)
    throws AlgoliaRuntimeException {
    return LaunderThrowable.await(assignUserIdAsync(xAlgoliaUserID, assignUserIdParams, requestOptions));
  }

  /**
   * Assign or move a user ID to a cluster. The time it takes to move a user is proportional to the
   * amount of data linked to the user ID.
   *
   * @param xAlgoliaUserID userID to assign. (required)
   * @param assignUserIdParams (required)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CreatedAtResponse assignUserId(String xAlgoliaUserID, AssignUserIdParams assignUserIdParams) throws AlgoliaRuntimeException {
    return this.assignUserId(xAlgoliaUserID, assignUserIdParams, null);
  }

  /**
   * (asynchronously) Assign or move a user ID to a cluster. The time it takes to move a user is
   * proportional to the amount of data linked to the user ID.
   *
   * @param xAlgoliaUserID userID to assign. (required)
   * @param assignUserIdParams (required)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture assignUserIdAsync(
    String xAlgoliaUserID,
    AssignUserIdParams assignUserIdParams,
    RequestOptions requestOptions
  ) throws AlgoliaRuntimeException {
    if (xAlgoliaUserID == null) {
      throw new AlgoliaRuntimeException("Parameter `xAlgoliaUserID` is required when calling `assignUserId`.");
    }

    if (assignUserIdParams == null) {
      throw new AlgoliaRuntimeException("Parameter `assignUserIdParams` is required when calling `assignUserId`.");
    }

    HttpRequest request = HttpRequest
      .builder()
      .setPath("/1/clusters/mapping")
      .setMethod("POST")
      .setBody(assignUserIdParams)
      .addHeader("X-Algolia-User-ID", xAlgoliaUserID)
      .build();
    return executeAsync(request, requestOptions, new TypeReference() {});
  }

  /**
   * (asynchronously) Assign or move a user ID to a cluster. The time it takes to move a user is
   * proportional to the amount of data linked to the user ID.
   *
   * @param xAlgoliaUserID userID to assign. (required)
   * @param assignUserIdParams (required)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture assignUserIdAsync(String xAlgoliaUserID, AssignUserIdParams assignUserIdParams)
    throws AlgoliaRuntimeException {
    return this.assignUserIdAsync(xAlgoliaUserID, assignUserIdParams, null);
  }

  /**
   * To reduce the time spent on network round trips, you can perform several write actions in a
   * single API call. Actions are applied in the order they are specified. The supported `action`s
   * are equivalent to the individual operations of the same name.
   *
   * @param indexName Index on which to perform the request. (required)
   * @param batchWriteParams (required)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public BatchResponse batch(String indexName, BatchWriteParams batchWriteParams, RequestOptions requestOptions)
    throws AlgoliaRuntimeException {
    return LaunderThrowable.await(batchAsync(indexName, batchWriteParams, requestOptions));
  }

  /**
   * To reduce the time spent on network round trips, you can perform several write actions in a
   * single API call. Actions are applied in the order they are specified. The supported `action`s
   * are equivalent to the individual operations of the same name.
   *
   * @param indexName Index on which to perform the request. (required)
   * @param batchWriteParams (required)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public BatchResponse batch(String indexName, BatchWriteParams batchWriteParams) throws AlgoliaRuntimeException {
    return this.batch(indexName, batchWriteParams, null);
  }

  /**
   * (asynchronously) To reduce the time spent on network round trips, you can perform several write
   * actions in a single API call. Actions are applied in the order they are specified. The
   * supported `action`s are equivalent to the individual operations of the same name.
   *
   * @param indexName Index on which to perform the request. (required)
   * @param batchWriteParams (required)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture batchAsync(String indexName, BatchWriteParams batchWriteParams, RequestOptions requestOptions)
    throws AlgoliaRuntimeException {
    if (indexName == null) {
      throw new AlgoliaRuntimeException("Parameter `indexName` is required when calling `batch`.");
    }

    if (batchWriteParams == null) {
      throw new AlgoliaRuntimeException("Parameter `batchWriteParams` is required when calling `batch`.");
    }

    HttpRequest request = HttpRequest
      .builder()
      .setPath("/1/indexes/{indexName}/batch", indexName)
      .setMethod("POST")
      .setBody(batchWriteParams)
      .build();
    return executeAsync(request, requestOptions, new TypeReference() {});
  }

  /**
   * (asynchronously) To reduce the time spent on network round trips, you can perform several write
   * actions in a single API call. Actions are applied in the order they are specified. The
   * supported `action`s are equivalent to the individual operations of the same name.
   *
   * @param indexName Index on which to perform the request. (required)
   * @param batchWriteParams (required)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture batchAsync(String indexName, BatchWriteParams batchWriteParams) throws AlgoliaRuntimeException {
    return this.batchAsync(indexName, batchWriteParams, null);
  }

  /**
   * Assign multiple user IDs to a cluster. **You can't _move_ users with this operation.**.
   *
   * @param xAlgoliaUserID userID to assign. (required)
   * @param batchAssignUserIdsParams (required)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CreatedAtResponse batchAssignUserIds(
    String xAlgoliaUserID,
    BatchAssignUserIdsParams batchAssignUserIdsParams,
    RequestOptions requestOptions
  ) throws AlgoliaRuntimeException {
    return LaunderThrowable.await(batchAssignUserIdsAsync(xAlgoliaUserID, batchAssignUserIdsParams, requestOptions));
  }

  /**
   * Assign multiple user IDs to a cluster. **You can't _move_ users with this operation.**.
   *
   * @param xAlgoliaUserID userID to assign. (required)
   * @param batchAssignUserIdsParams (required)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CreatedAtResponse batchAssignUserIds(String xAlgoliaUserID, BatchAssignUserIdsParams batchAssignUserIdsParams)
    throws AlgoliaRuntimeException {
    return this.batchAssignUserIds(xAlgoliaUserID, batchAssignUserIdsParams, null);
  }

  /**
   * (asynchronously) Assign multiple user IDs to a cluster. **You can't _move_ users with this
   * operation.**.
   *
   * @param xAlgoliaUserID userID to assign. (required)
   * @param batchAssignUserIdsParams (required)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture batchAssignUserIdsAsync(
    String xAlgoliaUserID,
    BatchAssignUserIdsParams batchAssignUserIdsParams,
    RequestOptions requestOptions
  ) throws AlgoliaRuntimeException {
    if (xAlgoliaUserID == null) {
      throw new AlgoliaRuntimeException("Parameter `xAlgoliaUserID` is required when calling `batchAssignUserIds`.");
    }

    if (batchAssignUserIdsParams == null) {
      throw new AlgoliaRuntimeException("Parameter `batchAssignUserIdsParams` is required when calling `batchAssignUserIds`.");
    }

    HttpRequest request = HttpRequest
      .builder()
      .setPath("/1/clusters/mapping/batch")
      .setMethod("POST")
      .setBody(batchAssignUserIdsParams)
      .addHeader("X-Algolia-User-ID", xAlgoliaUserID)
      .build();
    return executeAsync(request, requestOptions, new TypeReference() {});
  }

  /**
   * (asynchronously) Assign multiple user IDs to a cluster. **You can't _move_ users with this
   * operation.**.
   *
   * @param xAlgoliaUserID userID to assign. (required)
   * @param batchAssignUserIdsParams (required)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture batchAssignUserIdsAsync(
    String xAlgoliaUserID,
    BatchAssignUserIdsParams batchAssignUserIdsParams
  ) throws AlgoliaRuntimeException {
    return this.batchAssignUserIdsAsync(xAlgoliaUserID, batchAssignUserIdsParams, null);
  }

  /**
   * Add or remove a batch of dictionary entries.
   *
   * @param dictionaryName Dictionary to search in. (required)
   * @param batchDictionaryEntriesParams (required)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public UpdatedAtResponse batchDictionaryEntries(
    DictionaryType dictionaryName,
    BatchDictionaryEntriesParams batchDictionaryEntriesParams,
    RequestOptions requestOptions
  ) throws AlgoliaRuntimeException {
    return LaunderThrowable.await(batchDictionaryEntriesAsync(dictionaryName, batchDictionaryEntriesParams, requestOptions));
  }

  /**
   * Add or remove a batch of dictionary entries.
   *
   * @param dictionaryName Dictionary to search in. (required)
   * @param batchDictionaryEntriesParams (required)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public UpdatedAtResponse batchDictionaryEntries(DictionaryType dictionaryName, BatchDictionaryEntriesParams batchDictionaryEntriesParams)
    throws AlgoliaRuntimeException {
    return this.batchDictionaryEntries(dictionaryName, batchDictionaryEntriesParams, null);
  }

  /**
   * (asynchronously) Add or remove a batch of dictionary entries.
   *
   * @param dictionaryName Dictionary to search in. (required)
   * @param batchDictionaryEntriesParams (required)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture batchDictionaryEntriesAsync(
    DictionaryType dictionaryName,
    BatchDictionaryEntriesParams batchDictionaryEntriesParams,
    RequestOptions requestOptions
  ) throws AlgoliaRuntimeException {
    if (dictionaryName == null) {
      throw new AlgoliaRuntimeException("Parameter `dictionaryName` is required when calling `batchDictionaryEntries`.");
    }

    if (batchDictionaryEntriesParams == null) {
      throw new AlgoliaRuntimeException("Parameter `batchDictionaryEntriesParams` is required when calling" + " `batchDictionaryEntries`.");
    }

    HttpRequest request = HttpRequest
      .builder()
      .setPath("/1/dictionaries/{dictionaryName}/batch", dictionaryName)
      .setMethod("POST")
      .setBody(batchDictionaryEntriesParams)
      .build();
    return executeAsync(request, requestOptions, new TypeReference() {});
  }

  /**
   * (asynchronously) Add or remove a batch of dictionary entries.
   *
   * @param dictionaryName Dictionary to search in. (required)
   * @param batchDictionaryEntriesParams (required)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture batchDictionaryEntriesAsync(
    DictionaryType dictionaryName,
    BatchDictionaryEntriesParams batchDictionaryEntriesParams
  ) throws AlgoliaRuntimeException {
    return this.batchDictionaryEntriesAsync(dictionaryName, batchDictionaryEntriesParams, null);
  }

  /**
   * Retrieve up to 1,000 records per call. Supports full-text search and filters. For better
   * performance, it doesn't support: - The `distinct` query parameter - Sorting by typos,
   * proximity, words, or geographical distance.
   *
   * @param indexName Index on which to perform the request. (required)
   * @param browseParams (optional)
   * @param innerType The class held by the index, could be your custom class or {@link Object}.
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public  BrowseResponse browse(String indexName, BrowseParams browseParams, Class innerType, RequestOptions requestOptions)
    throws AlgoliaRuntimeException {
    return LaunderThrowable.await(browseAsync(indexName, browseParams, innerType, requestOptions));
  }

  /**
   * Retrieve up to 1,000 records per call. Supports full-text search and filters. For better
   * performance, it doesn't support: - The `distinct` query parameter - Sorting by typos,
   * proximity, words, or geographical distance.
   *
   * @param indexName Index on which to perform the request. (required)
   * @param browseParams (optional)
   * @param innerType The class held by the index, could be your custom class or {@link Object}.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public  BrowseResponse browse(String indexName, BrowseParams browseParams, Class innerType) throws AlgoliaRuntimeException {
    return this.browse(indexName, browseParams, innerType, null);
  }

  /**
   * Retrieve up to 1,000 records per call. Supports full-text search and filters. For better
   * performance, it doesn't support: - The `distinct` query parameter - Sorting by typos,
   * proximity, words, or geographical distance.
   *
   * @param indexName Index on which to perform the request. (required)
   * @param innerType The class held by the index, could be your custom class or {@link Object}.
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public  BrowseResponse browse(String indexName, Class innerType, RequestOptions requestOptions) throws AlgoliaRuntimeException {
    return this.browse(indexName, null, innerType, requestOptions);
  }

  /**
   * Retrieve up to 1,000 records per call. Supports full-text search and filters. For better
   * performance, it doesn't support: - The `distinct` query parameter - Sorting by typos,
   * proximity, words, or geographical distance.
   *
   * @param indexName Index on which to perform the request. (required)
   * @param innerType The class held by the index, could be your custom class or {@link Object}.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public  BrowseResponse browse(String indexName, Class innerType) throws AlgoliaRuntimeException {
    return this.browse(indexName, null, innerType, null);
  }

  /**
   * (asynchronously) Retrieve up to 1,000 records per call. Supports full-text search and filters.
   * For better performance, it doesn't support: - The `distinct` query parameter -
   * Sorting by typos, proximity, words, or geographical distance.
   *
   * @param indexName Index on which to perform the request. (required)
   * @param browseParams (optional)
   * @param innerType The class held by the index, could be your custom class or {@link Object}.
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public  CompletableFuture> browseAsync(
    String indexName,
    BrowseParams browseParams,
    Class innerType,
    RequestOptions requestOptions
  ) throws AlgoliaRuntimeException {
    if (indexName == null) {
      throw new AlgoliaRuntimeException("Parameter `indexName` is required when calling `browse`.");
    }

    HttpRequest request = HttpRequest
      .builder()
      .setPath("/1/indexes/{indexName}/browse", indexName)
      .setMethod("POST")
      .setBody(browseParams)
      .build();
    return executeAsync(request, requestOptions, BrowseResponse.class, innerType);
  }

  /**
   * (asynchronously) Retrieve up to 1,000 records per call. Supports full-text search and filters.
   * For better performance, it doesn't support: - The `distinct` query parameter -
   * Sorting by typos, proximity, words, or geographical distance.
   *
   * @param indexName Index on which to perform the request. (required)
   * @param browseParams (optional)
   * @param innerType The class held by the index, could be your custom class or {@link Object}.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public  CompletableFuture> browseAsync(String indexName, BrowseParams browseParams, Class innerType)
    throws AlgoliaRuntimeException {
    return this.browseAsync(indexName, browseParams, innerType, null);
  }

  /**
   * (asynchronously) Retrieve up to 1,000 records per call. Supports full-text search and filters.
   * For better performance, it doesn't support: - The `distinct` query parameter -
   * Sorting by typos, proximity, words, or geographical distance.
   *
   * @param indexName Index on which to perform the request. (required)
   * @param innerType The class held by the index, could be your custom class or {@link Object}.
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public  CompletableFuture> browseAsync(String indexName, Class innerType, RequestOptions requestOptions)
    throws AlgoliaRuntimeException {
    return this.browseAsync(indexName, null, innerType, requestOptions);
  }

  /**
   * (asynchronously) Retrieve up to 1,000 records per call. Supports full-text search and filters.
   * For better performance, it doesn't support: - The `distinct` query parameter -
   * Sorting by typos, proximity, words, or geographical distance.
   *
   * @param indexName Index on which to perform the request. (required)
   * @param innerType The class held by the index, could be your custom class or {@link Object}.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public  CompletableFuture> browseAsync(String indexName, Class innerType) throws AlgoliaRuntimeException {
    return this.browseAsync(indexName, null, innerType, null);
  }

  /**
   * Delete all synonyms in the index.
   *
   * @param indexName Index on which to perform the request. (required)
   * @param forwardToReplicas Indicates whether changed index settings are forwarded to the replica
   *     indices. (optional)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public UpdatedAtResponse clearAllSynonyms(String indexName, Boolean forwardToReplicas, RequestOptions requestOptions)
    throws AlgoliaRuntimeException {
    return LaunderThrowable.await(clearAllSynonymsAsync(indexName, forwardToReplicas, requestOptions));
  }

  /**
   * Delete all synonyms in the index.
   *
   * @param indexName Index on which to perform the request. (required)
   * @param forwardToReplicas Indicates whether changed index settings are forwarded to the replica
   *     indices. (optional)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public UpdatedAtResponse clearAllSynonyms(String indexName, Boolean forwardToReplicas) throws AlgoliaRuntimeException {
    return this.clearAllSynonyms(indexName, forwardToReplicas, null);
  }

  /**
   * Delete all synonyms in the index.
   *
   * @param indexName Index on which to perform the request. (required)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public UpdatedAtResponse clearAllSynonyms(String indexName, RequestOptions requestOptions) throws AlgoliaRuntimeException {
    return this.clearAllSynonyms(indexName, null, requestOptions);
  }

  /**
   * Delete all synonyms in the index.
   *
   * @param indexName Index on which to perform the request. (required)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public UpdatedAtResponse clearAllSynonyms(String indexName) throws AlgoliaRuntimeException {
    return this.clearAllSynonyms(indexName, null, null);
  }

  /**
   * (asynchronously) Delete all synonyms in the index.
   *
   * @param indexName Index on which to perform the request. (required)
   * @param forwardToReplicas Indicates whether changed index settings are forwarded to the replica
   *     indices. (optional)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture clearAllSynonymsAsync(
    String indexName,
    Boolean forwardToReplicas,
    RequestOptions requestOptions
  ) throws AlgoliaRuntimeException {
    if (indexName == null) {
      throw new AlgoliaRuntimeException("Parameter `indexName` is required when calling `clearAllSynonyms`.");
    }

    HttpRequest request = HttpRequest
      .builder()
      .setPath("/1/indexes/{indexName}/synonyms/clear", indexName)
      .setMethod("POST")
      .addQueryParameter("forwardToReplicas", forwardToReplicas)
      .build();
    return executeAsync(request, requestOptions, new TypeReference() {});
  }

  /**
   * (asynchronously) Delete all synonyms in the index.
   *
   * @param indexName Index on which to perform the request. (required)
   * @param forwardToReplicas Indicates whether changed index settings are forwarded to the replica
   *     indices. (optional)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture clearAllSynonymsAsync(String indexName, Boolean forwardToReplicas)
    throws AlgoliaRuntimeException {
    return this.clearAllSynonymsAsync(indexName, forwardToReplicas, null);
  }

  /**
   * (asynchronously) Delete all synonyms in the index.
   *
   * @param indexName Index on which to perform the request. (required)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture clearAllSynonymsAsync(String indexName, RequestOptions requestOptions)
    throws AlgoliaRuntimeException {
    return this.clearAllSynonymsAsync(indexName, null, requestOptions);
  }

  /**
   * (asynchronously) Delete all synonyms in the index.
   *
   * @param indexName Index on which to perform the request. (required)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture clearAllSynonymsAsync(String indexName) throws AlgoliaRuntimeException {
    return this.clearAllSynonymsAsync(indexName, null, null);
  }

  /**
   * Delete the records but leave settings and index-specific API keys untouched.
   *
   * @param indexName Index on which to perform the request. (required)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public UpdatedAtResponse clearObjects(String indexName, RequestOptions requestOptions) throws AlgoliaRuntimeException {
    return LaunderThrowable.await(clearObjectsAsync(indexName, requestOptions));
  }

  /**
   * Delete the records but leave settings and index-specific API keys untouched.
   *
   * @param indexName Index on which to perform the request. (required)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public UpdatedAtResponse clearObjects(String indexName) throws AlgoliaRuntimeException {
    return this.clearObjects(indexName, null);
  }

  /**
   * (asynchronously) Delete the records but leave settings and index-specific API keys untouched.
   *
   * @param indexName Index on which to perform the request. (required)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture clearObjectsAsync(String indexName, RequestOptions requestOptions)
    throws AlgoliaRuntimeException {
    if (indexName == null) {
      throw new AlgoliaRuntimeException("Parameter `indexName` is required when calling `clearObjects`.");
    }

    HttpRequest request = HttpRequest.builder().setPath("/1/indexes/{indexName}/clear", indexName).setMethod("POST").build();
    return executeAsync(request, requestOptions, new TypeReference() {});
  }

  /**
   * (asynchronously) Delete the records but leave settings and index-specific API keys untouched.
   *
   * @param indexName Index on which to perform the request. (required)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture clearObjectsAsync(String indexName) throws AlgoliaRuntimeException {
    return this.clearObjectsAsync(indexName, null);
  }

  /**
   * Delete all rules in the index.
   *
   * @param indexName Index on which to perform the request. (required)
   * @param forwardToReplicas Indicates whether changed index settings are forwarded to the replica
   *     indices. (optional)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public UpdatedAtResponse clearRules(String indexName, Boolean forwardToReplicas, RequestOptions requestOptions)
    throws AlgoliaRuntimeException {
    return LaunderThrowable.await(clearRulesAsync(indexName, forwardToReplicas, requestOptions));
  }

  /**
   * Delete all rules in the index.
   *
   * @param indexName Index on which to perform the request. (required)
   * @param forwardToReplicas Indicates whether changed index settings are forwarded to the replica
   *     indices. (optional)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public UpdatedAtResponse clearRules(String indexName, Boolean forwardToReplicas) throws AlgoliaRuntimeException {
    return this.clearRules(indexName, forwardToReplicas, null);
  }

  /**
   * Delete all rules in the index.
   *
   * @param indexName Index on which to perform the request. (required)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public UpdatedAtResponse clearRules(String indexName, RequestOptions requestOptions) throws AlgoliaRuntimeException {
    return this.clearRules(indexName, null, requestOptions);
  }

  /**
   * Delete all rules in the index.
   *
   * @param indexName Index on which to perform the request. (required)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public UpdatedAtResponse clearRules(String indexName) throws AlgoliaRuntimeException {
    return this.clearRules(indexName, null, null);
  }

  /**
   * (asynchronously) Delete all rules in the index.
   *
   * @param indexName Index on which to perform the request. (required)
   * @param forwardToReplicas Indicates whether changed index settings are forwarded to the replica
   *     indices. (optional)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture clearRulesAsync(String indexName, Boolean forwardToReplicas, RequestOptions requestOptions)
    throws AlgoliaRuntimeException {
    if (indexName == null) {
      throw new AlgoliaRuntimeException("Parameter `indexName` is required when calling `clearRules`.");
    }

    HttpRequest request = HttpRequest
      .builder()
      .setPath("/1/indexes/{indexName}/rules/clear", indexName)
      .setMethod("POST")
      .addQueryParameter("forwardToReplicas", forwardToReplicas)
      .build();
    return executeAsync(request, requestOptions, new TypeReference() {});
  }

  /**
   * (asynchronously) Delete all rules in the index.
   *
   * @param indexName Index on which to perform the request. (required)
   * @param forwardToReplicas Indicates whether changed index settings are forwarded to the replica
   *     indices. (optional)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture clearRulesAsync(String indexName, Boolean forwardToReplicas) throws AlgoliaRuntimeException {
    return this.clearRulesAsync(indexName, forwardToReplicas, null);
  }

  /**
   * (asynchronously) Delete all rules in the index.
   *
   * @param indexName Index on which to perform the request. (required)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture clearRulesAsync(String indexName, RequestOptions requestOptions)
    throws AlgoliaRuntimeException {
    return this.clearRulesAsync(indexName, null, requestOptions);
  }

  /**
   * (asynchronously) Delete all rules in the index.
   *
   * @param indexName Index on which to perform the request. (required)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture clearRulesAsync(String indexName) throws AlgoliaRuntimeException {
    return this.clearRulesAsync(indexName, null, null);
  }

  /**
   * This method allow you to send requests to the Algolia REST API.
   *
   * @param path Path of the endpoint, anything after \"/1\" must be specified. (required)
   * @param parameters Query parameters to apply to the current query. (optional)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public Object del(String path, Map parameters, RequestOptions requestOptions) throws AlgoliaRuntimeException {
    return LaunderThrowable.await(delAsync(path, parameters, requestOptions));
  }

  /**
   * This method allow you to send requests to the Algolia REST API.
   *
   * @param path Path of the endpoint, anything after \"/1\" must be specified. (required)
   * @param parameters Query parameters to apply to the current query. (optional)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public Object del(String path, Map parameters) throws AlgoliaRuntimeException {
    return this.del(path, parameters, null);
  }

  /**
   * This method allow you to send requests to the Algolia REST API.
   *
   * @param path Path of the endpoint, anything after \"/1\" must be specified. (required)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public Object del(String path, RequestOptions requestOptions) throws AlgoliaRuntimeException {
    return this.del(path, null, requestOptions);
  }

  /**
   * This method allow you to send requests to the Algolia REST API.
   *
   * @param path Path of the endpoint, anything after \"/1\" must be specified. (required)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public Object del(String path) throws AlgoliaRuntimeException {
    return this.del(path, null, null);
  }

  /**
   * (asynchronously) This method allow you to send requests to the Algolia REST API.
   *
   * @param path Path of the endpoint, anything after \"/1\" must be specified. (required)
   * @param parameters Query parameters to apply to the current query. (optional)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture delAsync(String path, Map parameters, RequestOptions requestOptions)
    throws AlgoliaRuntimeException {
    if (path == null) {
      throw new AlgoliaRuntimeException("Parameter `path` is required when calling `del`.");
    }

    HttpRequest request = HttpRequest.builder().setPathEncoded("/1{path}", path).setMethod("DELETE").addQueryParameters(parameters).build();
    return executeAsync(request, requestOptions, new TypeReference() {});
  }

  /**
   * (asynchronously) This method allow you to send requests to the Algolia REST API.
   *
   * @param path Path of the endpoint, anything after \"/1\" must be specified. (required)
   * @param parameters Query parameters to apply to the current query. (optional)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture delAsync(String path, Map parameters) throws AlgoliaRuntimeException {
    return this.delAsync(path, parameters, null);
  }

  /**
   * (asynchronously) This method allow you to send requests to the Algolia REST API.
   *
   * @param path Path of the endpoint, anything after \"/1\" must be specified. (required)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture delAsync(String path, RequestOptions requestOptions) throws AlgoliaRuntimeException {
    return this.delAsync(path, null, requestOptions);
  }

  /**
   * (asynchronously) This method allow you to send requests to the Algolia REST API.
   *
   * @param path Path of the endpoint, anything after \"/1\" must be specified. (required)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture delAsync(String path) throws AlgoliaRuntimeException {
    return this.delAsync(path, null, null);
  }

  /**
   * Delete an existing API key. The request must be authenticated with the admin API key.
   *
   * @param key API key. (required)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public DeleteApiKeyResponse deleteApiKey(String key, RequestOptions requestOptions) throws AlgoliaRuntimeException {
    return LaunderThrowable.await(deleteApiKeyAsync(key, requestOptions));
  }

  /**
   * Delete an existing API key. The request must be authenticated with the admin API key.
   *
   * @param key API key. (required)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public DeleteApiKeyResponse deleteApiKey(String key) throws AlgoliaRuntimeException {
    return this.deleteApiKey(key, null);
  }

  /**
   * (asynchronously) Delete an existing API key. The request must be authenticated with the admin
   * API key.
   *
   * @param key API key. (required)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture deleteApiKeyAsync(String key, RequestOptions requestOptions)
    throws AlgoliaRuntimeException {
    if (key == null) {
      throw new AlgoliaRuntimeException("Parameter `key` is required when calling `deleteApiKey`.");
    }

    HttpRequest request = HttpRequest.builder().setPath("/1/keys/{key}", key).setMethod("DELETE").build();

    return executeAsync(request, requestOptions, new TypeReference() {});
  }

  /**
   * (asynchronously) Delete an existing API key. The request must be authenticated with the admin
   * API key.
   *
   * @param key API key. (required)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture deleteApiKeyAsync(String key) throws AlgoliaRuntimeException {
    return this.deleteApiKeyAsync(key, null);
  }

  /**
   * This operation doesn't support all the query options, only its filters (numeric, facet, or tag)
   * and geo queries. It doesn't accept empty filters or queries.
   *
   * @param indexName Index on which to perform the request. (required)
   * @param deleteByParams (required)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public DeletedAtResponse deleteBy(String indexName, DeleteByParams deleteByParams, RequestOptions requestOptions)
    throws AlgoliaRuntimeException {
    return LaunderThrowable.await(deleteByAsync(indexName, deleteByParams, requestOptions));
  }

  /**
   * This operation doesn't support all the query options, only its filters (numeric, facet, or tag)
   * and geo queries. It doesn't accept empty filters or queries.
   *
   * @param indexName Index on which to perform the request. (required)
   * @param deleteByParams (required)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public DeletedAtResponse deleteBy(String indexName, DeleteByParams deleteByParams) throws AlgoliaRuntimeException {
    return this.deleteBy(indexName, deleteByParams, null);
  }

  /**
   * (asynchronously) This operation doesn't support all the query options, only its filters
   * (numeric, facet, or tag) and geo queries. It doesn't accept empty filters or queries.
   *
   * @param indexName Index on which to perform the request. (required)
   * @param deleteByParams (required)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture deleteByAsync(String indexName, DeleteByParams deleteByParams, RequestOptions requestOptions)
    throws AlgoliaRuntimeException {
    if (indexName == null) {
      throw new AlgoliaRuntimeException("Parameter `indexName` is required when calling `deleteBy`.");
    }

    if (deleteByParams == null) {
      throw new AlgoliaRuntimeException("Parameter `deleteByParams` is required when calling `deleteBy`.");
    }

    HttpRequest request = HttpRequest
      .builder()
      .setPath("/1/indexes/{indexName}/deleteByQuery", indexName)
      .setMethod("POST")
      .setBody(deleteByParams)
      .build();
    return executeAsync(request, requestOptions, new TypeReference() {});
  }

  /**
   * (asynchronously) This operation doesn't support all the query options, only its filters
   * (numeric, facet, or tag) and geo queries. It doesn't accept empty filters or queries.
   *
   * @param indexName Index on which to perform the request. (required)
   * @param deleteByParams (required)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture deleteByAsync(String indexName, DeleteByParams deleteByParams)
    throws AlgoliaRuntimeException {
    return this.deleteByAsync(indexName, deleteByParams, null);
  }

  /**
   * Delete an existing index.
   *
   * @param indexName Index on which to perform the request. (required)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public DeletedAtResponse deleteIndex(String indexName, RequestOptions requestOptions) throws AlgoliaRuntimeException {
    return LaunderThrowable.await(deleteIndexAsync(indexName, requestOptions));
  }

  /**
   * Delete an existing index.
   *
   * @param indexName Index on which to perform the request. (required)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public DeletedAtResponse deleteIndex(String indexName) throws AlgoliaRuntimeException {
    return this.deleteIndex(indexName, null);
  }

  /**
   * (asynchronously) Delete an existing index.
   *
   * @param indexName Index on which to perform the request. (required)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture deleteIndexAsync(String indexName, RequestOptions requestOptions)
    throws AlgoliaRuntimeException {
    if (indexName == null) {
      throw new AlgoliaRuntimeException("Parameter `indexName` is required when calling `deleteIndex`.");
    }

    HttpRequest request = HttpRequest.builder().setPath("/1/indexes/{indexName}", indexName).setMethod("DELETE").build();
    return executeAsync(request, requestOptions, new TypeReference() {});
  }

  /**
   * (asynchronously) Delete an existing index.
   *
   * @param indexName Index on which to perform the request. (required)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture deleteIndexAsync(String indexName) throws AlgoliaRuntimeException {
    return this.deleteIndexAsync(indexName, null);
  }

  /**
   * To delete a set of records matching a query, use the [`deleteByQuery`
   * operation](#tag/Records/operation/deleteBy) instead.
   *
   * @param indexName Index on which to perform the request. (required)
   * @param objectID Unique record (object) identifier. (required)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public DeletedAtResponse deleteObject(String indexName, String objectID, RequestOptions requestOptions) throws AlgoliaRuntimeException {
    return LaunderThrowable.await(deleteObjectAsync(indexName, objectID, requestOptions));
  }

  /**
   * To delete a set of records matching a query, use the [`deleteByQuery`
   * operation](#tag/Records/operation/deleteBy) instead.
   *
   * @param indexName Index on which to perform the request. (required)
   * @param objectID Unique record (object) identifier. (required)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public DeletedAtResponse deleteObject(String indexName, String objectID) throws AlgoliaRuntimeException {
    return this.deleteObject(indexName, objectID, null);
  }

  /**
   * (asynchronously) To delete a set of records matching a query, use the
   * [`deleteByQuery` operation](#tag/Records/operation/deleteBy) instead.
   *
   * @param indexName Index on which to perform the request. (required)
   * @param objectID Unique record (object) identifier. (required)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture deleteObjectAsync(String indexName, String objectID, RequestOptions requestOptions)
    throws AlgoliaRuntimeException {
    if (indexName == null) {
      throw new AlgoliaRuntimeException("Parameter `indexName` is required when calling `deleteObject`.");
    }

    if (objectID == null) {
      throw new AlgoliaRuntimeException("Parameter `objectID` is required when calling `deleteObject`.");
    }

    HttpRequest request = HttpRequest
      .builder()
      .setPath("/1/indexes/{indexName}/{objectID}", indexName, objectID)
      .setMethod("DELETE")
      .build();
    return executeAsync(request, requestOptions, new TypeReference() {});
  }

  /**
   * (asynchronously) To delete a set of records matching a query, use the
   * [`deleteByQuery` operation](#tag/Records/operation/deleteBy) instead.
   *
   * @param indexName Index on which to perform the request. (required)
   * @param objectID Unique record (object) identifier. (required)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture deleteObjectAsync(String indexName, String objectID) throws AlgoliaRuntimeException {
    return this.deleteObjectAsync(indexName, objectID, null);
  }

  /**
   * Delete a rule by its `objectID`. To find the `objectID` for rules, use the [`search`
   * operation](#tag/Rules/operation/searchRules).
   *
   * @param indexName Index on which to perform the request. (required)
   * @param objectID Unique identifier of a rule object. (required)
   * @param forwardToReplicas Indicates whether changed index settings are forwarded to the replica
   *     indices. (optional)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public UpdatedAtResponse deleteRule(String indexName, String objectID, Boolean forwardToReplicas, RequestOptions requestOptions)
    throws AlgoliaRuntimeException {
    return LaunderThrowable.await(deleteRuleAsync(indexName, objectID, forwardToReplicas, requestOptions));
  }

  /**
   * Delete a rule by its `objectID`. To find the `objectID` for rules, use the [`search`
   * operation](#tag/Rules/operation/searchRules).
   *
   * @param indexName Index on which to perform the request. (required)
   * @param objectID Unique identifier of a rule object. (required)
   * @param forwardToReplicas Indicates whether changed index settings are forwarded to the replica
   *     indices. (optional)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public UpdatedAtResponse deleteRule(String indexName, String objectID, Boolean forwardToReplicas) throws AlgoliaRuntimeException {
    return this.deleteRule(indexName, objectID, forwardToReplicas, null);
  }

  /**
   * Delete a rule by its `objectID`. To find the `objectID` for rules, use the [`search`
   * operation](#tag/Rules/operation/searchRules).
   *
   * @param indexName Index on which to perform the request. (required)
   * @param objectID Unique identifier of a rule object. (required)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public UpdatedAtResponse deleteRule(String indexName, String objectID, RequestOptions requestOptions) throws AlgoliaRuntimeException {
    return this.deleteRule(indexName, objectID, null, requestOptions);
  }

  /**
   * Delete a rule by its `objectID`. To find the `objectID` for rules, use the [`search`
   * operation](#tag/Rules/operation/searchRules).
   *
   * @param indexName Index on which to perform the request. (required)
   * @param objectID Unique identifier of a rule object. (required)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public UpdatedAtResponse deleteRule(String indexName, String objectID) throws AlgoliaRuntimeException {
    return this.deleteRule(indexName, objectID, null, null);
  }

  /**
   * (asynchronously) Delete a rule by its `objectID`. To find the `objectID`
   * for rules, use the [`search` operation](#tag/Rules/operation/searchRules).
   *
   * @param indexName Index on which to perform the request. (required)
   * @param objectID Unique identifier of a rule object. (required)
   * @param forwardToReplicas Indicates whether changed index settings are forwarded to the replica
   *     indices. (optional)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture deleteRuleAsync(
    String indexName,
    String objectID,
    Boolean forwardToReplicas,
    RequestOptions requestOptions
  ) throws AlgoliaRuntimeException {
    if (indexName == null) {
      throw new AlgoliaRuntimeException("Parameter `indexName` is required when calling `deleteRule`.");
    }

    if (objectID == null) {
      throw new AlgoliaRuntimeException("Parameter `objectID` is required when calling `deleteRule`.");
    }

    HttpRequest request = HttpRequest
      .builder()
      .setPath("/1/indexes/{indexName}/rules/{objectID}", indexName, objectID)
      .setMethod("DELETE")
      .addQueryParameter("forwardToReplicas", forwardToReplicas)
      .build();
    return executeAsync(request, requestOptions, new TypeReference() {});
  }

  /**
   * (asynchronously) Delete a rule by its `objectID`. To find the `objectID`
   * for rules, use the [`search` operation](#tag/Rules/operation/searchRules).
   *
   * @param indexName Index on which to perform the request. (required)
   * @param objectID Unique identifier of a rule object. (required)
   * @param forwardToReplicas Indicates whether changed index settings are forwarded to the replica
   *     indices. (optional)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture deleteRuleAsync(String indexName, String objectID, Boolean forwardToReplicas)
    throws AlgoliaRuntimeException {
    return this.deleteRuleAsync(indexName, objectID, forwardToReplicas, null);
  }

  /**
   * (asynchronously) Delete a rule by its `objectID`. To find the `objectID`
   * for rules, use the [`search` operation](#tag/Rules/operation/searchRules).
   *
   * @param indexName Index on which to perform the request. (required)
   * @param objectID Unique identifier of a rule object. (required)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture deleteRuleAsync(String indexName, String objectID, RequestOptions requestOptions)
    throws AlgoliaRuntimeException {
    return this.deleteRuleAsync(indexName, objectID, null, requestOptions);
  }

  /**
   * (asynchronously) Delete a rule by its `objectID`. To find the `objectID`
   * for rules, use the [`search` operation](#tag/Rules/operation/searchRules).
   *
   * @param indexName Index on which to perform the request. (required)
   * @param objectID Unique identifier of a rule object. (required)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture deleteRuleAsync(String indexName, String objectID) throws AlgoliaRuntimeException {
    return this.deleteRuleAsync(indexName, objectID, null, null);
  }

  /**
   * Remove a source from the list of allowed sources.
   *
   * @param source IP address range of the source. (required)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public DeleteSourceResponse deleteSource(String source, RequestOptions requestOptions) throws AlgoliaRuntimeException {
    return LaunderThrowable.await(deleteSourceAsync(source, requestOptions));
  }

  /**
   * Remove a source from the list of allowed sources.
   *
   * @param source IP address range of the source. (required)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public DeleteSourceResponse deleteSource(String source) throws AlgoliaRuntimeException {
    return this.deleteSource(source, null);
  }

  /**
   * (asynchronously) Remove a source from the list of allowed sources.
   *
   * @param source IP address range of the source. (required)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture deleteSourceAsync(String source, RequestOptions requestOptions)
    throws AlgoliaRuntimeException {
    if (source == null) {
      throw new AlgoliaRuntimeException("Parameter `source` is required when calling `deleteSource`.");
    }

    HttpRequest request = HttpRequest.builder().setPath("/1/security/sources/{source}", source).setMethod("DELETE").build();
    return executeAsync(request, requestOptions, new TypeReference() {});
  }

  /**
   * (asynchronously) Remove a source from the list of allowed sources.
   *
   * @param source IP address range of the source. (required)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture deleteSourceAsync(String source) throws AlgoliaRuntimeException {
    return this.deleteSourceAsync(source, null);
  }

  /**
   * Delete a synonym by its `objectID`. To find the object IDs of your synonyms, use the [`search`
   * operation](#tag/Synonyms/operation/searchSynonyms).
   *
   * @param indexName Index on which to perform the request. (required)
   * @param objectID Unique identifier of a synonym object. (required)
   * @param forwardToReplicas Indicates whether changed index settings are forwarded to the replica
   *     indices. (optional)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public DeletedAtResponse deleteSynonym(String indexName, String objectID, Boolean forwardToReplicas, RequestOptions requestOptions)
    throws AlgoliaRuntimeException {
    return LaunderThrowable.await(deleteSynonymAsync(indexName, objectID, forwardToReplicas, requestOptions));
  }

  /**
   * Delete a synonym by its `objectID`. To find the object IDs of your synonyms, use the [`search`
   * operation](#tag/Synonyms/operation/searchSynonyms).
   *
   * @param indexName Index on which to perform the request. (required)
   * @param objectID Unique identifier of a synonym object. (required)
   * @param forwardToReplicas Indicates whether changed index settings are forwarded to the replica
   *     indices. (optional)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public DeletedAtResponse deleteSynonym(String indexName, String objectID, Boolean forwardToReplicas) throws AlgoliaRuntimeException {
    return this.deleteSynonym(indexName, objectID, forwardToReplicas, null);
  }

  /**
   * Delete a synonym by its `objectID`. To find the object IDs of your synonyms, use the [`search`
   * operation](#tag/Synonyms/operation/searchSynonyms).
   *
   * @param indexName Index on which to perform the request. (required)
   * @param objectID Unique identifier of a synonym object. (required)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public DeletedAtResponse deleteSynonym(String indexName, String objectID, RequestOptions requestOptions) throws AlgoliaRuntimeException {
    return this.deleteSynonym(indexName, objectID, null, requestOptions);
  }

  /**
   * Delete a synonym by its `objectID`. To find the object IDs of your synonyms, use the [`search`
   * operation](#tag/Synonyms/operation/searchSynonyms).
   *
   * @param indexName Index on which to perform the request. (required)
   * @param objectID Unique identifier of a synonym object. (required)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public DeletedAtResponse deleteSynonym(String indexName, String objectID) throws AlgoliaRuntimeException {
    return this.deleteSynonym(indexName, objectID, null, null);
  }

  /**
   * (asynchronously) Delete a synonym by its `objectID`. To find the object IDs of your
   * synonyms, use the [`search` operation](#tag/Synonyms/operation/searchSynonyms).
   *
   * @param indexName Index on which to perform the request. (required)
   * @param objectID Unique identifier of a synonym object. (required)
   * @param forwardToReplicas Indicates whether changed index settings are forwarded to the replica
   *     indices. (optional)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture deleteSynonymAsync(
    String indexName,
    String objectID,
    Boolean forwardToReplicas,
    RequestOptions requestOptions
  ) throws AlgoliaRuntimeException {
    if (indexName == null) {
      throw new AlgoliaRuntimeException("Parameter `indexName` is required when calling `deleteSynonym`.");
    }

    if (objectID == null) {
      throw new AlgoliaRuntimeException("Parameter `objectID` is required when calling `deleteSynonym`.");
    }

    HttpRequest request = HttpRequest
      .builder()
      .setPath("/1/indexes/{indexName}/synonyms/{objectID}", indexName, objectID)
      .setMethod("DELETE")
      .addQueryParameter("forwardToReplicas", forwardToReplicas)
      .build();
    return executeAsync(request, requestOptions, new TypeReference() {});
  }

  /**
   * (asynchronously) Delete a synonym by its `objectID`. To find the object IDs of your
   * synonyms, use the [`search` operation](#tag/Synonyms/operation/searchSynonyms).
   *
   * @param indexName Index on which to perform the request. (required)
   * @param objectID Unique identifier of a synonym object. (required)
   * @param forwardToReplicas Indicates whether changed index settings are forwarded to the replica
   *     indices. (optional)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture deleteSynonymAsync(String indexName, String objectID, Boolean forwardToReplicas)
    throws AlgoliaRuntimeException {
    return this.deleteSynonymAsync(indexName, objectID, forwardToReplicas, null);
  }

  /**
   * (asynchronously) Delete a synonym by its `objectID`. To find the object IDs of your
   * synonyms, use the [`search` operation](#tag/Synonyms/operation/searchSynonyms).
   *
   * @param indexName Index on which to perform the request. (required)
   * @param objectID Unique identifier of a synonym object. (required)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture deleteSynonymAsync(String indexName, String objectID, RequestOptions requestOptions)
    throws AlgoliaRuntimeException {
    return this.deleteSynonymAsync(indexName, objectID, null, requestOptions);
  }

  /**
   * (asynchronously) Delete a synonym by its `objectID`. To find the object IDs of your
   * synonyms, use the [`search` operation](#tag/Synonyms/operation/searchSynonyms).
   *
   * @param indexName Index on which to perform the request. (required)
   * @param objectID Unique identifier of a synonym object. (required)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture deleteSynonymAsync(String indexName, String objectID) throws AlgoliaRuntimeException {
    return this.deleteSynonymAsync(indexName, objectID, null, null);
  }

  /**
   * This method allow you to send requests to the Algolia REST API.
   *
   * @param path Path of the endpoint, anything after \"/1\" must be specified. (required)
   * @param parameters Query parameters to apply to the current query. (optional)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public Object get(String path, Map parameters, RequestOptions requestOptions) throws AlgoliaRuntimeException {
    return LaunderThrowable.await(getAsync(path, parameters, requestOptions));
  }

  /**
   * This method allow you to send requests to the Algolia REST API.
   *
   * @param path Path of the endpoint, anything after \"/1\" must be specified. (required)
   * @param parameters Query parameters to apply to the current query. (optional)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public Object get(String path, Map parameters) throws AlgoliaRuntimeException {
    return this.get(path, parameters, null);
  }

  /**
   * This method allow you to send requests to the Algolia REST API.
   *
   * @param path Path of the endpoint, anything after \"/1\" must be specified. (required)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public Object get(String path, RequestOptions requestOptions) throws AlgoliaRuntimeException {
    return this.get(path, null, requestOptions);
  }

  /**
   * This method allow you to send requests to the Algolia REST API.
   *
   * @param path Path of the endpoint, anything after \"/1\" must be specified. (required)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public Object get(String path) throws AlgoliaRuntimeException {
    return this.get(path, null, null);
  }

  /**
   * (asynchronously) This method allow you to send requests to the Algolia REST API.
   *
   * @param path Path of the endpoint, anything after \"/1\" must be specified. (required)
   * @param parameters Query parameters to apply to the current query. (optional)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture getAsync(String path, Map parameters, RequestOptions requestOptions)
    throws AlgoliaRuntimeException {
    if (path == null) {
      throw new AlgoliaRuntimeException("Parameter `path` is required when calling `get`.");
    }

    HttpRequest request = HttpRequest.builder().setPathEncoded("/1{path}", path).setMethod("GET").addQueryParameters(parameters).build();
    return executeAsync(request, requestOptions, new TypeReference() {});
  }

  /**
   * (asynchronously) This method allow you to send requests to the Algolia REST API.
   *
   * @param path Path of the endpoint, anything after \"/1\" must be specified. (required)
   * @param parameters Query parameters to apply to the current query. (optional)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture getAsync(String path, Map parameters) throws AlgoliaRuntimeException {
    return this.getAsync(path, parameters, null);
  }

  /**
   * (asynchronously) This method allow you to send requests to the Algolia REST API.
   *
   * @param path Path of the endpoint, anything after \"/1\" must be specified. (required)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture getAsync(String path, RequestOptions requestOptions) throws AlgoliaRuntimeException {
    return this.getAsync(path, null, requestOptions);
  }

  /**
   * (asynchronously) This method allow you to send requests to the Algolia REST API.
   *
   * @param path Path of the endpoint, anything after \"/1\" must be specified. (required)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture getAsync(String path) throws AlgoliaRuntimeException {
    return this.getAsync(path, null, null);
  }

  /**
   * Get the permissions and restrictions of a specific API key. When authenticating with the admin
   * API key, you can request information for any of your application's keys. When authenticating
   * with other API keys, you can only retrieve information for that key.
   *
   * @param key API key. (required)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public GetApiKeyResponse getApiKey(String key, RequestOptions requestOptions) throws AlgoliaRuntimeException {
    return LaunderThrowable.await(getApiKeyAsync(key, requestOptions));
  }

  /**
   * Get the permissions and restrictions of a specific API key. When authenticating with the admin
   * API key, you can request information for any of your application's keys. When authenticating
   * with other API keys, you can only retrieve information for that key.
   *
   * @param key API key. (required)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public GetApiKeyResponse getApiKey(String key) throws AlgoliaRuntimeException {
    return this.getApiKey(key, null);
  }

  /**
   * (asynchronously) Get the permissions and restrictions of a specific API key. When
   * authenticating with the admin API key, you can request information for any of your
   * application's keys. When authenticating with other API keys, you can only retrieve
   * information for that key.
   *
   * @param key API key. (required)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture getApiKeyAsync(String key, RequestOptions requestOptions) throws AlgoliaRuntimeException {
    if (key == null) {
      throw new AlgoliaRuntimeException("Parameter `key` is required when calling `getApiKey`.");
    }

    HttpRequest request = HttpRequest.builder().setPath("/1/keys/{key}", key).setMethod("GET").build();

    return executeAsync(request, requestOptions, new TypeReference() {});
  }

  /**
   * (asynchronously) Get the permissions and restrictions of a specific API key. When
   * authenticating with the admin API key, you can request information for any of your
   * application's keys. When authenticating with other API keys, you can only retrieve
   * information for that key.
   *
   * @param key API key. (required)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture getApiKeyAsync(String key) throws AlgoliaRuntimeException {
    return this.getApiKeyAsync(key, null);
  }

  /**
   * Lists Algolia's [supported
   * languages](https://www.algolia.com/doc/guides/managing-results/optimize-search-results/handling-natural-languages-nlp/in-depth/supported-languages/)
   * and any customizations applied to each language's [stop
   * word](https://www.algolia.com/doc/guides/managing-results/optimize-search-results/handling-natural-languages-nlp/how-to/customize-stop-words/),
   * [plural](https://www.algolia.com/doc/guides/managing-results/optimize-search-results/handling-natural-languages-nlp/how-to/customize-plurals-and-other-declensions/),
   * and [segmentation
   * (compound)](https://www.algolia.com/doc/guides/managing-results/optimize-search-results/handling-natural-languages-nlp/how-to/customize-segmentation/)
   * features.
   *
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public Map getDictionaryLanguages(RequestOptions requestOptions) throws AlgoliaRuntimeException {
    return LaunderThrowable.await(getDictionaryLanguagesAsync(requestOptions));
  }

  /**
   * Lists Algolia's [supported
   * languages](https://www.algolia.com/doc/guides/managing-results/optimize-search-results/handling-natural-languages-nlp/in-depth/supported-languages/)
   * and any customizations applied to each language's [stop
   * word](https://www.algolia.com/doc/guides/managing-results/optimize-search-results/handling-natural-languages-nlp/how-to/customize-stop-words/),
   * [plural](https://www.algolia.com/doc/guides/managing-results/optimize-search-results/handling-natural-languages-nlp/how-to/customize-plurals-and-other-declensions/),
   * and [segmentation
   * (compound)](https://www.algolia.com/doc/guides/managing-results/optimize-search-results/handling-natural-languages-nlp/how-to/customize-segmentation/)
   * features.
   *
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public Map getDictionaryLanguages() throws AlgoliaRuntimeException {
    return this.getDictionaryLanguages(null);
  }

  /**
   * (asynchronously) Lists Algolia's [supported
   * languages](https://www.algolia.com/doc/guides/managing-results/optimize-search-results/handling-natural-languages-nlp/in-depth/supported-languages/)
   * and any customizations applied to each language's [stop
   * word](https://www.algolia.com/doc/guides/managing-results/optimize-search-results/handling-natural-languages-nlp/how-to/customize-stop-words/),
   * [plural](https://www.algolia.com/doc/guides/managing-results/optimize-search-results/handling-natural-languages-nlp/how-to/customize-plurals-and-other-declensions/),
   * and [segmentation
   * (compound)](https://www.algolia.com/doc/guides/managing-results/optimize-search-results/handling-natural-languages-nlp/how-to/customize-segmentation/)
   * features.
   *
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture> getDictionaryLanguagesAsync(RequestOptions requestOptions)
    throws AlgoliaRuntimeException {
    HttpRequest request = HttpRequest.builder().setPath("/1/dictionaries/*/languages").setMethod("GET").build();

    return executeAsync(request, requestOptions, new TypeReference>() {});
  }

  /**
   * (asynchronously) Lists Algolia's [supported
   * languages](https://www.algolia.com/doc/guides/managing-results/optimize-search-results/handling-natural-languages-nlp/in-depth/supported-languages/)
   * and any customizations applied to each language's [stop
   * word](https://www.algolia.com/doc/guides/managing-results/optimize-search-results/handling-natural-languages-nlp/how-to/customize-stop-words/),
   * [plural](https://www.algolia.com/doc/guides/managing-results/optimize-search-results/handling-natural-languages-nlp/how-to/customize-plurals-and-other-declensions/),
   * and [segmentation
   * (compound)](https://www.algolia.com/doc/guides/managing-results/optimize-search-results/handling-natural-languages-nlp/how-to/customize-segmentation/)
   * features.
   *
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture> getDictionaryLanguagesAsync() throws AlgoliaRuntimeException {
    return this.getDictionaryLanguagesAsync(null);
  }

  /**
   * Get the languages for which [stop words are turned
   * off](#tag/Dictionaries/operation/setDictionarySettings).
   *
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public GetDictionarySettingsResponse getDictionarySettings(RequestOptions requestOptions) throws AlgoliaRuntimeException {
    return LaunderThrowable.await(getDictionarySettingsAsync(requestOptions));
  }

  /**
   * Get the languages for which [stop words are turned
   * off](#tag/Dictionaries/operation/setDictionarySettings).
   *
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public GetDictionarySettingsResponse getDictionarySettings() throws AlgoliaRuntimeException {
    return this.getDictionarySettings(null);
  }

  /**
   * (asynchronously) Get the languages for which [stop words are turned
   * off](#tag/Dictionaries/operation/setDictionarySettings).
   *
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture getDictionarySettingsAsync(RequestOptions requestOptions)
    throws AlgoliaRuntimeException {
    HttpRequest request = HttpRequest.builder().setPath("/1/dictionaries/*/settings").setMethod("GET").build();

    return executeAsync(request, requestOptions, new TypeReference() {});
  }

  /**
   * (asynchronously) Get the languages for which [stop words are turned
   * off](#tag/Dictionaries/operation/setDictionarySettings).
   *
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture getDictionarySettingsAsync() throws AlgoliaRuntimeException {
    return this.getDictionarySettingsAsync(null);
  }

  /**
   * The request must be authenticated by an API key with the [`logs`
   * ACL](https://www.algolia.com/doc/guides/security/api-keys/#access-control-list-acl). Logs are
   * held for the last seven days. There's also a logging limit of 1,000 API calls per server. This
   * request counts towards your [operations
   * quota](https://support.algolia.com/hc/en-us/articles/4406981829777-How-does-Algolia-count-records-and-operations-)
   * but doesn't appear in the logs itself. > **Note**: To fetch the logs for a Distributed Search
   * Network (DSN) cluster, target the [DSN's
   * endpoint](https://www.algolia.com/doc/guides/scaling/distributed-search-network-dsn/#accessing-dsn-servers).
   *
   * @param offset First log entry to retrieve. Sorted by decreasing date with 0 being the most
   *     recent. (optional, default to 0)
   * @param length Maximum number of entries to retrieve. (optional, default to 10)
   * @param indexName Index for which log entries should be retrieved. When omitted, log entries are
   *     retrieved for all indices. (optional)
   * @param type Type of log entries to retrieve. When omitted, all log entries are retrieved.
   *     (optional, default to all)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public GetLogsResponse getLogs(Integer offset, Integer length, String indexName, LogType type, RequestOptions requestOptions)
    throws AlgoliaRuntimeException {
    return LaunderThrowable.await(getLogsAsync(offset, length, indexName, type, requestOptions));
  }

  /**
   * The request must be authenticated by an API key with the [`logs`
   * ACL](https://www.algolia.com/doc/guides/security/api-keys/#access-control-list-acl). Logs are
   * held for the last seven days. There's also a logging limit of 1,000 API calls per server. This
   * request counts towards your [operations
   * quota](https://support.algolia.com/hc/en-us/articles/4406981829777-How-does-Algolia-count-records-and-operations-)
   * but doesn't appear in the logs itself. > **Note**: To fetch the logs for a Distributed Search
   * Network (DSN) cluster, target the [DSN's
   * endpoint](https://www.algolia.com/doc/guides/scaling/distributed-search-network-dsn/#accessing-dsn-servers).
   *
   * @param offset First log entry to retrieve. Sorted by decreasing date with 0 being the most
   *     recent. (optional, default to 0)
   * @param length Maximum number of entries to retrieve. (optional, default to 10)
   * @param indexName Index for which log entries should be retrieved. When omitted, log entries are
   *     retrieved for all indices. (optional)
   * @param type Type of log entries to retrieve. When omitted, all log entries are retrieved.
   *     (optional, default to all)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public GetLogsResponse getLogs(Integer offset, Integer length, String indexName, LogType type) throws AlgoliaRuntimeException {
    return this.getLogs(offset, length, indexName, type, null);
  }

  /**
   * The request must be authenticated by an API key with the [`logs`
   * ACL](https://www.algolia.com/doc/guides/security/api-keys/#access-control-list-acl). Logs are
   * held for the last seven days. There's also a logging limit of 1,000 API calls per server. This
   * request counts towards your [operations
   * quota](https://support.algolia.com/hc/en-us/articles/4406981829777-How-does-Algolia-count-records-and-operations-)
   * but doesn't appear in the logs itself. > **Note**: To fetch the logs for a Distributed Search
   * Network (DSN) cluster, target the [DSN's
   * endpoint](https://www.algolia.com/doc/guides/scaling/distributed-search-network-dsn/#accessing-dsn-servers).
   *
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public GetLogsResponse getLogs(RequestOptions requestOptions) throws AlgoliaRuntimeException {
    return this.getLogs(null, null, null, null, requestOptions);
  }

  /**
   * The request must be authenticated by an API key with the [`logs`
   * ACL](https://www.algolia.com/doc/guides/security/api-keys/#access-control-list-acl). Logs are
   * held for the last seven days. There's also a logging limit of 1,000 API calls per server. This
   * request counts towards your [operations
   * quota](https://support.algolia.com/hc/en-us/articles/4406981829777-How-does-Algolia-count-records-and-operations-)
   * but doesn't appear in the logs itself. > **Note**: To fetch the logs for a Distributed Search
   * Network (DSN) cluster, target the [DSN's
   * endpoint](https://www.algolia.com/doc/guides/scaling/distributed-search-network-dsn/#accessing-dsn-servers).
   *
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public GetLogsResponse getLogs() throws AlgoliaRuntimeException {
    return this.getLogs(null, null, null, null, null);
  }

  /**
   * (asynchronously) The request must be authenticated by an API key with the [`logs`
   * ACL](https://www.algolia.com/doc/guides/security/api-keys/#access-control-list-acl). Logs are
   * held for the last seven days. There's also a logging limit of 1,000 API calls per server.
   * This request counts towards your [operations
   * quota](https://support.algolia.com/hc/en-us/articles/4406981829777-How-does-Algolia-count-records-and-operations-)
   * but doesn't appear in the logs itself. > **Note**: To fetch the logs for a Distributed
   * Search Network (DSN) cluster, target the [DSN's
   * endpoint](https://www.algolia.com/doc/guides/scaling/distributed-search-network-dsn/#accessing-dsn-servers).
   *
   * @param offset First log entry to retrieve. Sorted by decreasing date with 0 being the most
   *     recent. (optional, default to 0)
   * @param length Maximum number of entries to retrieve. (optional, default to 10)
   * @param indexName Index for which log entries should be retrieved. When omitted, log entries are
   *     retrieved for all indices. (optional)
   * @param type Type of log entries to retrieve. When omitted, all log entries are retrieved.
   *     (optional, default to all)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture getLogsAsync(
    Integer offset,
    Integer length,
    String indexName,
    LogType type,
    RequestOptions requestOptions
  ) throws AlgoliaRuntimeException {
    HttpRequest request = HttpRequest
      .builder()
      .setPath("/1/logs")
      .setMethod("GET")
      .addQueryParameter("offset", offset)
      .addQueryParameter("length", length)
      .addQueryParameter("indexName", indexName)
      .addQueryParameter("type", type)
      .build();
    return executeAsync(request, requestOptions, new TypeReference() {});
  }

  /**
   * (asynchronously) The request must be authenticated by an API key with the [`logs`
   * ACL](https://www.algolia.com/doc/guides/security/api-keys/#access-control-list-acl). Logs are
   * held for the last seven days. There's also a logging limit of 1,000 API calls per server.
   * This request counts towards your [operations
   * quota](https://support.algolia.com/hc/en-us/articles/4406981829777-How-does-Algolia-count-records-and-operations-)
   * but doesn't appear in the logs itself. > **Note**: To fetch the logs for a Distributed
   * Search Network (DSN) cluster, target the [DSN's
   * endpoint](https://www.algolia.com/doc/guides/scaling/distributed-search-network-dsn/#accessing-dsn-servers).
   *
   * @param offset First log entry to retrieve. Sorted by decreasing date with 0 being the most
   *     recent. (optional, default to 0)
   * @param length Maximum number of entries to retrieve. (optional, default to 10)
   * @param indexName Index for which log entries should be retrieved. When omitted, log entries are
   *     retrieved for all indices. (optional)
   * @param type Type of log entries to retrieve. When omitted, all log entries are retrieved.
   *     (optional, default to all)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture getLogsAsync(Integer offset, Integer length, String indexName, LogType type)
    throws AlgoliaRuntimeException {
    return this.getLogsAsync(offset, length, indexName, type, null);
  }

  /**
   * (asynchronously) The request must be authenticated by an API key with the [`logs`
   * ACL](https://www.algolia.com/doc/guides/security/api-keys/#access-control-list-acl). Logs are
   * held for the last seven days. There's also a logging limit of 1,000 API calls per server.
   * This request counts towards your [operations
   * quota](https://support.algolia.com/hc/en-us/articles/4406981829777-How-does-Algolia-count-records-and-operations-)
   * but doesn't appear in the logs itself. > **Note**: To fetch the logs for a Distributed
   * Search Network (DSN) cluster, target the [DSN's
   * endpoint](https://www.algolia.com/doc/guides/scaling/distributed-search-network-dsn/#accessing-dsn-servers).
   *
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture getLogsAsync(RequestOptions requestOptions) throws AlgoliaRuntimeException {
    return this.getLogsAsync(null, null, null, null, requestOptions);
  }

  /**
   * (asynchronously) The request must be authenticated by an API key with the [`logs`
   * ACL](https://www.algolia.com/doc/guides/security/api-keys/#access-control-list-acl). Logs are
   * held for the last seven days. There's also a logging limit of 1,000 API calls per server.
   * This request counts towards your [operations
   * quota](https://support.algolia.com/hc/en-us/articles/4406981829777-How-does-Algolia-count-records-and-operations-)
   * but doesn't appear in the logs itself. > **Note**: To fetch the logs for a Distributed
   * Search Network (DSN) cluster, target the [DSN's
   * endpoint](https://www.algolia.com/doc/guides/scaling/distributed-search-network-dsn/#accessing-dsn-servers).
   *
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture getLogsAsync() throws AlgoliaRuntimeException {
    return this.getLogsAsync(null, null, null, null, null);
  }

  /**
   * To get more than one record, use the [`objects` operation](#tag/Records/operation/getObjects).
   *
   * @param indexName Index on which to perform the request. (required)
   * @param objectID Unique record (object) identifier. (required)
   * @param attributesToRetrieve Attributes to include with the records in the response. This is
   *     useful to reduce the size of the API response. By default, all retrievable attributes are
   *     returned. `objectID` is always retrieved, even when not specified.
   *     [`unretrievableAttributes`](https://www.algolia.com/doc/api-reference/api-parameters/unretrievableAttributes/)
   *     won't be retrieved unless the request is authenticated with the admin API key. (optional)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public Map getObject(String indexName, String objectID, List attributesToRetrieve, RequestOptions requestOptions)
    throws AlgoliaRuntimeException {
    return LaunderThrowable.await(getObjectAsync(indexName, objectID, attributesToRetrieve, requestOptions));
  }

  /**
   * To get more than one record, use the [`objects` operation](#tag/Records/operation/getObjects).
   *
   * @param indexName Index on which to perform the request. (required)
   * @param objectID Unique record (object) identifier. (required)
   * @param attributesToRetrieve Attributes to include with the records in the response. This is
   *     useful to reduce the size of the API response. By default, all retrievable attributes are
   *     returned. `objectID` is always retrieved, even when not specified.
   *     [`unretrievableAttributes`](https://www.algolia.com/doc/api-reference/api-parameters/unretrievableAttributes/)
   *     won't be retrieved unless the request is authenticated with the admin API key. (optional)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public Map getObject(String indexName, String objectID, List attributesToRetrieve)
    throws AlgoliaRuntimeException {
    return this.getObject(indexName, objectID, attributesToRetrieve, null);
  }

  /**
   * To get more than one record, use the [`objects` operation](#tag/Records/operation/getObjects).
   *
   * @param indexName Index on which to perform the request. (required)
   * @param objectID Unique record (object) identifier. (required)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public Map getObject(String indexName, String objectID, RequestOptions requestOptions) throws AlgoliaRuntimeException {
    return this.getObject(indexName, objectID, null, requestOptions);
  }

  /**
   * To get more than one record, use the [`objects` operation](#tag/Records/operation/getObjects).
   *
   * @param indexName Index on which to perform the request. (required)
   * @param objectID Unique record (object) identifier. (required)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public Map getObject(String indexName, String objectID) throws AlgoliaRuntimeException {
    return this.getObject(indexName, objectID, null, null);
  }

  /**
   * (asynchronously) To get more than one record, use the [`objects`
   * operation](#tag/Records/operation/getObjects).
   *
   * @param indexName Index on which to perform the request. (required)
   * @param objectID Unique record (object) identifier. (required)
   * @param attributesToRetrieve Attributes to include with the records in the response. This is
   *     useful to reduce the size of the API response. By default, all retrievable attributes are
   *     returned. `objectID` is always retrieved, even when not specified.
   *     [`unretrievableAttributes`](https://www.algolia.com/doc/api-reference/api-parameters/unretrievableAttributes/)
   *     won't be retrieved unless the request is authenticated with the admin API key. (optional)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture> getObjectAsync(
    String indexName,
    String objectID,
    List attributesToRetrieve,
    RequestOptions requestOptions
  ) throws AlgoliaRuntimeException {
    if (indexName == null) {
      throw new AlgoliaRuntimeException("Parameter `indexName` is required when calling `getObject`.");
    }

    if (objectID == null) {
      throw new AlgoliaRuntimeException("Parameter `objectID` is required when calling `getObject`.");
    }

    HttpRequest request = HttpRequest
      .builder()
      .setPath("/1/indexes/{indexName}/{objectID}", indexName, objectID)
      .setMethod("GET")
      .addQueryParameter("attributesToRetrieve", attributesToRetrieve)
      .build();
    return executeAsync(request, requestOptions, new TypeReference>() {});
  }

  /**
   * (asynchronously) To get more than one record, use the [`objects`
   * operation](#tag/Records/operation/getObjects).
   *
   * @param indexName Index on which to perform the request. (required)
   * @param objectID Unique record (object) identifier. (required)
   * @param attributesToRetrieve Attributes to include with the records in the response. This is
   *     useful to reduce the size of the API response. By default, all retrievable attributes are
   *     returned. `objectID` is always retrieved, even when not specified.
   *     [`unretrievableAttributes`](https://www.algolia.com/doc/api-reference/api-parameters/unretrievableAttributes/)
   *     won't be retrieved unless the request is authenticated with the admin API key. (optional)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture> getObjectAsync(String indexName, String objectID, List attributesToRetrieve)
    throws AlgoliaRuntimeException {
    return this.getObjectAsync(indexName, objectID, attributesToRetrieve, null);
  }

  /**
   * (asynchronously) To get more than one record, use the [`objects`
   * operation](#tag/Records/operation/getObjects).
   *
   * @param indexName Index on which to perform the request. (required)
   * @param objectID Unique record (object) identifier. (required)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture> getObjectAsync(String indexName, String objectID, RequestOptions requestOptions)
    throws AlgoliaRuntimeException {
    return this.getObjectAsync(indexName, objectID, null, requestOptions);
  }

  /**
   * (asynchronously) To get more than one record, use the [`objects`
   * operation](#tag/Records/operation/getObjects).
   *
   * @param indexName Index on which to perform the request. (required)
   * @param objectID Unique record (object) identifier. (required)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture> getObjectAsync(String indexName, String objectID) throws AlgoliaRuntimeException {
    return this.getObjectAsync(indexName, objectID, null, null);
  }

  /**
   * Retrieve one or more records, potentially from different indices, in a single API operation.
   * Results will be received in the same order as the requests.
   *
   * @param getObjectsParams Request object. (required)
   * @param innerType The class held by the index, could be your custom class or {@link Object}.
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public  GetObjectsResponse getObjects(GetObjectsParams getObjectsParams, Class innerType, RequestOptions requestOptions)
    throws AlgoliaRuntimeException {
    return LaunderThrowable.await(getObjectsAsync(getObjectsParams, innerType, requestOptions));
  }

  /**
   * Retrieve one or more records, potentially from different indices, in a single API operation.
   * Results will be received in the same order as the requests.
   *
   * @param getObjectsParams Request object. (required)
   * @param innerType The class held by the index, could be your custom class or {@link Object}.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public  GetObjectsResponse getObjects(GetObjectsParams getObjectsParams, Class innerType) throws AlgoliaRuntimeException {
    return this.getObjects(getObjectsParams, innerType, null);
  }

  /**
   * (asynchronously) Retrieve one or more records, potentially from different indices, in a single
   * API operation. Results will be received in the same order as the requests.
   *
   * @param getObjectsParams Request object. (required)
   * @param innerType The class held by the index, could be your custom class or {@link Object}.
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public  CompletableFuture> getObjectsAsync(
    GetObjectsParams getObjectsParams,
    Class innerType,
    RequestOptions requestOptions
  ) throws AlgoliaRuntimeException {
    if (getObjectsParams == null) {
      throw new AlgoliaRuntimeException("Parameter `getObjectsParams` is required when calling `getObjects`.");
    }

    HttpRequest request = HttpRequest
      .builder()
      .setPath("/1/indexes/*/objects")
      .setMethod("POST")
      .setBody(getObjectsParams)
      .setRead(true)
      .build();
    return executeAsync(request, requestOptions, GetObjectsResponse.class, innerType);
  }

  /**
   * (asynchronously) Retrieve one or more records, potentially from different indices, in a single
   * API operation. Results will be received in the same order as the requests.
   *
   * @param getObjectsParams Request object. (required)
   * @param innerType The class held by the index, could be your custom class or {@link Object}.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public  CompletableFuture> getObjectsAsync(GetObjectsParams getObjectsParams, Class innerType)
    throws AlgoliaRuntimeException {
    return this.getObjectsAsync(getObjectsParams, innerType, null);
  }

  /**
   * Get a rule by its `objectID`. To find the `objectID` for rules, use the [`search`
   * operation](#tag/Rules/operation/searchRules).
   *
   * @param indexName Index on which to perform the request. (required)
   * @param objectID Unique identifier of a rule object. (required)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public Rule getRule(String indexName, String objectID, RequestOptions requestOptions) throws AlgoliaRuntimeException {
    return LaunderThrowable.await(getRuleAsync(indexName, objectID, requestOptions));
  }

  /**
   * Get a rule by its `objectID`. To find the `objectID` for rules, use the [`search`
   * operation](#tag/Rules/operation/searchRules).
   *
   * @param indexName Index on which to perform the request. (required)
   * @param objectID Unique identifier of a rule object. (required)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public Rule getRule(String indexName, String objectID) throws AlgoliaRuntimeException {
    return this.getRule(indexName, objectID, null);
  }

  /**
   * (asynchronously) Get a rule by its `objectID`. To find the `objectID` for
   * rules, use the [`search` operation](#tag/Rules/operation/searchRules).
   *
   * @param indexName Index on which to perform the request. (required)
   * @param objectID Unique identifier of a rule object. (required)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture getRuleAsync(String indexName, String objectID, RequestOptions requestOptions)
    throws AlgoliaRuntimeException {
    if (indexName == null) {
      throw new AlgoliaRuntimeException("Parameter `indexName` is required when calling `getRule`.");
    }

    if (objectID == null) {
      throw new AlgoliaRuntimeException("Parameter `objectID` is required when calling `getRule`.");
    }

    HttpRequest request = HttpRequest
      .builder()
      .setPath("/1/indexes/{indexName}/rules/{objectID}", indexName, objectID)
      .setMethod("GET")
      .build();
    return executeAsync(request, requestOptions, new TypeReference() {});
  }

  /**
   * (asynchronously) Get a rule by its `objectID`. To find the `objectID` for
   * rules, use the [`search` operation](#tag/Rules/operation/searchRules).
   *
   * @param indexName Index on which to perform the request. (required)
   * @param objectID Unique identifier of a rule object. (required)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture getRuleAsync(String indexName, String objectID) throws AlgoliaRuntimeException {
    return this.getRuleAsync(indexName, objectID, null);
  }

  /**
   * Return an object containing an index's [configuration
   * settings](https://www.algolia.com/doc/api-reference/settings-api-parameters/).
   *
   * @param indexName Index on which to perform the request. (required)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public IndexSettings getSettings(String indexName, RequestOptions requestOptions) throws AlgoliaRuntimeException {
    return LaunderThrowable.await(getSettingsAsync(indexName, requestOptions));
  }

  /**
   * Return an object containing an index's [configuration
   * settings](https://www.algolia.com/doc/api-reference/settings-api-parameters/).
   *
   * @param indexName Index on which to perform the request. (required)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public IndexSettings getSettings(String indexName) throws AlgoliaRuntimeException {
    return this.getSettings(indexName, null);
  }

  /**
   * (asynchronously) Return an object containing an index's [configuration
   * settings](https://www.algolia.com/doc/api-reference/settings-api-parameters/).
   *
   * @param indexName Index on which to perform the request. (required)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture getSettingsAsync(String indexName, RequestOptions requestOptions) throws AlgoliaRuntimeException {
    if (indexName == null) {
      throw new AlgoliaRuntimeException("Parameter `indexName` is required when calling `getSettings`.");
    }

    HttpRequest request = HttpRequest.builder().setPath("/1/indexes/{indexName}/settings", indexName).setMethod("GET").build();
    return executeAsync(request, requestOptions, new TypeReference() {});
  }

  /**
   * (asynchronously) Return an object containing an index's [configuration
   * settings](https://www.algolia.com/doc/api-reference/settings-api-parameters/).
   *
   * @param indexName Index on which to perform the request. (required)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture getSettingsAsync(String indexName) throws AlgoliaRuntimeException {
    return this.getSettingsAsync(indexName, null);
  }

  /**
   * Get all allowed sources (IP addresses).
   *
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public List getSources(RequestOptions requestOptions) throws AlgoliaRuntimeException {
    return LaunderThrowable.await(getSourcesAsync(requestOptions));
  }

  /**
   * Get all allowed sources (IP addresses).
   *
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public List getSources() throws AlgoliaRuntimeException {
    return this.getSources(null);
  }

  /**
   * (asynchronously) Get all allowed sources (IP addresses).
   *
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture> getSourcesAsync(RequestOptions requestOptions) throws AlgoliaRuntimeException {
    HttpRequest request = HttpRequest.builder().setPath("/1/security/sources").setMethod("GET").build();

    return executeAsync(request, requestOptions, new TypeReference>() {});
  }

  /**
   * (asynchronously) Get all allowed sources (IP addresses).
   *
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture> getSourcesAsync() throws AlgoliaRuntimeException {
    return this.getSourcesAsync(null);
  }

  /**
   * Get a syonym by its `objectID`. To find the object IDs for your synonyms, use the [`search`
   * operation](#tag/Synonyms/operation/searchSynonyms).
   *
   * @param indexName Index on which to perform the request. (required)
   * @param objectID Unique identifier of a synonym object. (required)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public SynonymHit getSynonym(String indexName, String objectID, RequestOptions requestOptions) throws AlgoliaRuntimeException {
    return LaunderThrowable.await(getSynonymAsync(indexName, objectID, requestOptions));
  }

  /**
   * Get a syonym by its `objectID`. To find the object IDs for your synonyms, use the [`search`
   * operation](#tag/Synonyms/operation/searchSynonyms).
   *
   * @param indexName Index on which to perform the request. (required)
   * @param objectID Unique identifier of a synonym object. (required)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public SynonymHit getSynonym(String indexName, String objectID) throws AlgoliaRuntimeException {
    return this.getSynonym(indexName, objectID, null);
  }

  /**
   * (asynchronously) Get a syonym by its `objectID`. To find the object IDs for your
   * synonyms, use the [`search` operation](#tag/Synonyms/operation/searchSynonyms).
   *
   * @param indexName Index on which to perform the request. (required)
   * @param objectID Unique identifier of a synonym object. (required)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture getSynonymAsync(String indexName, String objectID, RequestOptions requestOptions)
    throws AlgoliaRuntimeException {
    if (indexName == null) {
      throw new AlgoliaRuntimeException("Parameter `indexName` is required when calling `getSynonym`.");
    }

    if (objectID == null) {
      throw new AlgoliaRuntimeException("Parameter `objectID` is required when calling `getSynonym`.");
    }

    HttpRequest request = HttpRequest
      .builder()
      .setPath("/1/indexes/{indexName}/synonyms/{objectID}", indexName, objectID)
      .setMethod("GET")
      .build();
    return executeAsync(request, requestOptions, new TypeReference() {});
  }

  /**
   * (asynchronously) Get a syonym by its `objectID`. To find the object IDs for your
   * synonyms, use the [`search` operation](#tag/Synonyms/operation/searchSynonyms).
   *
   * @param indexName Index on which to perform the request. (required)
   * @param objectID Unique identifier of a synonym object. (required)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture getSynonymAsync(String indexName, String objectID) throws AlgoliaRuntimeException {
    return this.getSynonymAsync(indexName, objectID, null);
  }

  /**
   * Some operations, such as copying an index, will respond with a `taskID` value. Use this value
   * here to check the status of that task.
   *
   * @param indexName Index on which to perform the request. (required)
   * @param taskID Unique task identifier. (required)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public GetTaskResponse getTask(String indexName, Long taskID, RequestOptions requestOptions) throws AlgoliaRuntimeException {
    return LaunderThrowable.await(getTaskAsync(indexName, taskID, requestOptions));
  }

  /**
   * Some operations, such as copying an index, will respond with a `taskID` value. Use this value
   * here to check the status of that task.
   *
   * @param indexName Index on which to perform the request. (required)
   * @param taskID Unique task identifier. (required)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public GetTaskResponse getTask(String indexName, Long taskID) throws AlgoliaRuntimeException {
    return this.getTask(indexName, taskID, null);
  }

  /**
   * (asynchronously) Some operations, such as copying an index, will respond with a
   * `taskID` value. Use this value here to check the status of that task.
   *
   * @param indexName Index on which to perform the request. (required)
   * @param taskID Unique task identifier. (required)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture getTaskAsync(String indexName, Long taskID, RequestOptions requestOptions)
    throws AlgoliaRuntimeException {
    if (indexName == null) {
      throw new AlgoliaRuntimeException("Parameter `indexName` is required when calling `getTask`.");
    }

    if (taskID == null) {
      throw new AlgoliaRuntimeException("Parameter `taskID` is required when calling `getTask`.");
    }

    HttpRequest request = HttpRequest.builder().setPath("/1/indexes/{indexName}/task/{taskID}", indexName, taskID).setMethod("GET").build();
    return executeAsync(request, requestOptions, new TypeReference() {});
  }

  /**
   * (asynchronously) Some operations, such as copying an index, will respond with a
   * `taskID` value. Use this value here to check the status of that task.
   *
   * @param indexName Index on which to perform the request. (required)
   * @param taskID Unique task identifier. (required)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture getTaskAsync(String indexName, Long taskID) throws AlgoliaRuntimeException {
    return this.getTaskAsync(indexName, taskID, null);
  }

  /**
   * Get the IDs of the 10 users with the highest number of records per cluster. Since it can take
   * up to a few seconds to get the data from the different clusters, the response isn't real-time.
   *
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public GetTopUserIdsResponse getTopUserIds(RequestOptions requestOptions) throws AlgoliaRuntimeException {
    return LaunderThrowable.await(getTopUserIdsAsync(requestOptions));
  }

  /**
   * Get the IDs of the 10 users with the highest number of records per cluster. Since it can take
   * up to a few seconds to get the data from the different clusters, the response isn't real-time.
   *
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public GetTopUserIdsResponse getTopUserIds() throws AlgoliaRuntimeException {
    return this.getTopUserIds(null);
  }

  /**
   * (asynchronously) Get the IDs of the 10 users with the highest number of records per cluster.
   * Since it can take up to a few seconds to get the data from the different clusters, the response
   * isn't real-time.
   *
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture getTopUserIdsAsync(RequestOptions requestOptions) throws AlgoliaRuntimeException {
    HttpRequest request = HttpRequest.builder().setPath("/1/clusters/mapping/top").setMethod("GET").build();

    return executeAsync(request, requestOptions, new TypeReference() {});
  }

  /**
   * (asynchronously) Get the IDs of the 10 users with the highest number of records per cluster.
   * Since it can take up to a few seconds to get the data from the different clusters, the response
   * isn't real-time.
   *
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture getTopUserIdsAsync() throws AlgoliaRuntimeException {
    return this.getTopUserIdsAsync(null);
  }

  /**
   * Returns the userID data stored in the mapping. Since it can take up to a few seconds to get the
   * data from the different clusters, the response isn't real-time.
   *
   * @param userID userID to assign. (required)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public UserId getUserId(String userID, RequestOptions requestOptions) throws AlgoliaRuntimeException {
    return LaunderThrowable.await(getUserIdAsync(userID, requestOptions));
  }

  /**
   * Returns the userID data stored in the mapping. Since it can take up to a few seconds to get the
   * data from the different clusters, the response isn't real-time.
   *
   * @param userID userID to assign. (required)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public UserId getUserId(String userID) throws AlgoliaRuntimeException {
    return this.getUserId(userID, null);
  }

  /**
   * (asynchronously) Returns the userID data stored in the mapping. Since it can take up to a few
   * seconds to get the data from the different clusters, the response isn't real-time.
   *
   * @param userID userID to assign. (required)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture getUserIdAsync(String userID, RequestOptions requestOptions) throws AlgoliaRuntimeException {
    if (userID == null) {
      throw new AlgoliaRuntimeException("Parameter `userID` is required when calling `getUserId`.");
    }

    HttpRequest request = HttpRequest.builder().setPath("/1/clusters/mapping/{userID}", userID).setMethod("GET").build();
    return executeAsync(request, requestOptions, new TypeReference() {});
  }

  /**
   * (asynchronously) Returns the userID data stored in the mapping. Since it can take up to a few
   * seconds to get the data from the different clusters, the response isn't real-time.
   *
   * @param userID userID to assign. (required)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture getUserIdAsync(String userID) throws AlgoliaRuntimeException {
    return this.getUserIdAsync(userID, null);
  }

  /**
   * To determine when the time-consuming process of creating a large batch of users or migrating
   * users from one cluster to another is complete, this operation retrieves the status of the
   * process.
   *
   * @param getClusters Indicates whether to include the cluster's pending mapping state in the
   *     response. (optional)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public HasPendingMappingsResponse hasPendingMappings(Boolean getClusters, RequestOptions requestOptions) throws AlgoliaRuntimeException {
    return LaunderThrowable.await(hasPendingMappingsAsync(getClusters, requestOptions));
  }

  /**
   * To determine when the time-consuming process of creating a large batch of users or migrating
   * users from one cluster to another is complete, this operation retrieves the status of the
   * process.
   *
   * @param getClusters Indicates whether to include the cluster's pending mapping state in the
   *     response. (optional)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public HasPendingMappingsResponse hasPendingMappings(Boolean getClusters) throws AlgoliaRuntimeException {
    return this.hasPendingMappings(getClusters, null);
  }

  /**
   * To determine when the time-consuming process of creating a large batch of users or migrating
   * users from one cluster to another is complete, this operation retrieves the status of the
   * process.
   *
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public HasPendingMappingsResponse hasPendingMappings(RequestOptions requestOptions) throws AlgoliaRuntimeException {
    return this.hasPendingMappings(null, requestOptions);
  }

  /**
   * To determine when the time-consuming process of creating a large batch of users or migrating
   * users from one cluster to another is complete, this operation retrieves the status of the
   * process.
   *
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public HasPendingMappingsResponse hasPendingMappings() throws AlgoliaRuntimeException {
    return this.hasPendingMappings(null, null);
  }

  /**
   * (asynchronously) To determine when the time-consuming process of creating a large batch of
   * users or migrating users from one cluster to another is complete, this operation retrieves the
   * status of the process.
   *
   * @param getClusters Indicates whether to include the cluster's pending mapping state in the
   *     response. (optional)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture hasPendingMappingsAsync(Boolean getClusters, RequestOptions requestOptions)
    throws AlgoliaRuntimeException {
    HttpRequest request = HttpRequest
      .builder()
      .setPath("/1/clusters/mapping/pending")
      .setMethod("GET")
      .addQueryParameter("getClusters", getClusters)
      .build();
    return executeAsync(request, requestOptions, new TypeReference() {});
  }

  /**
   * (asynchronously) To determine when the time-consuming process of creating a large batch of
   * users or migrating users from one cluster to another is complete, this operation retrieves the
   * status of the process.
   *
   * @param getClusters Indicates whether to include the cluster's pending mapping state in the
   *     response. (optional)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture hasPendingMappingsAsync(Boolean getClusters) throws AlgoliaRuntimeException {
    return this.hasPendingMappingsAsync(getClusters, null);
  }

  /**
   * (asynchronously) To determine when the time-consuming process of creating a large batch of
   * users or migrating users from one cluster to another is complete, this operation retrieves the
   * status of the process.
   *
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture hasPendingMappingsAsync(RequestOptions requestOptions)
    throws AlgoliaRuntimeException {
    return this.hasPendingMappingsAsync(null, requestOptions);
  }

  /**
   * (asynchronously) To determine when the time-consuming process of creating a large batch of
   * users or migrating users from one cluster to another is complete, this operation retrieves the
   * status of the process.
   *
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture hasPendingMappingsAsync() throws AlgoliaRuntimeException {
    return this.hasPendingMappingsAsync(null, null);
  }

  /**
   * List all API keys associated with your Algolia application, including their permissions and
   * restrictions.
   *
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public ListApiKeysResponse listApiKeys(RequestOptions requestOptions) throws AlgoliaRuntimeException {
    return LaunderThrowable.await(listApiKeysAsync(requestOptions));
  }

  /**
   * List all API keys associated with your Algolia application, including their permissions and
   * restrictions.
   *
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public ListApiKeysResponse listApiKeys() throws AlgoliaRuntimeException {
    return this.listApiKeys(null);
  }

  /**
   * (asynchronously) List all API keys associated with your Algolia application, including their
   * permissions and restrictions.
   *
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture listApiKeysAsync(RequestOptions requestOptions) throws AlgoliaRuntimeException {
    HttpRequest request = HttpRequest.builder().setPath("/1/keys").setMethod("GET").build();

    return executeAsync(request, requestOptions, new TypeReference() {});
  }

  /**
   * (asynchronously) List all API keys associated with your Algolia application, including their
   * permissions and restrictions.
   *
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture listApiKeysAsync() throws AlgoliaRuntimeException {
    return this.listApiKeysAsync(null);
  }

  /**
   * List the available clusters in a multi-cluster setup.
   *
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public ListClustersResponse listClusters(RequestOptions requestOptions) throws AlgoliaRuntimeException {
    return LaunderThrowable.await(listClustersAsync(requestOptions));
  }

  /**
   * List the available clusters in a multi-cluster setup.
   *
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public ListClustersResponse listClusters() throws AlgoliaRuntimeException {
    return this.listClusters(null);
  }

  /**
   * (asynchronously) List the available clusters in a multi-cluster setup.
   *
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture listClustersAsync(RequestOptions requestOptions) throws AlgoliaRuntimeException {
    HttpRequest request = HttpRequest.builder().setPath("/1/clusters").setMethod("GET").build();

    return executeAsync(request, requestOptions, new TypeReference() {});
  }

  /**
   * (asynchronously) List the available clusters in a multi-cluster setup.
   *
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture listClustersAsync() throws AlgoliaRuntimeException {
    return this.listClustersAsync(null);
  }

  /**
   * List indices in an Algolia application.
   *
   * @param page Returns the requested page number. The page size is determined by the `hitsPerPage`
   *     parameter. You can see the number of available pages in the `nbPages` response attribute.
   *     When `page` is null, the API response is not paginated. (optional)
   * @param hitsPerPage Maximum number of hits per page. (optional, default to 100)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public ListIndicesResponse listIndices(Integer page, Integer hitsPerPage, RequestOptions requestOptions) throws AlgoliaRuntimeException {
    return LaunderThrowable.await(listIndicesAsync(page, hitsPerPage, requestOptions));
  }

  /**
   * List indices in an Algolia application.
   *
   * @param page Returns the requested page number. The page size is determined by the `hitsPerPage`
   *     parameter. You can see the number of available pages in the `nbPages` response attribute.
   *     When `page` is null, the API response is not paginated. (optional)
   * @param hitsPerPage Maximum number of hits per page. (optional, default to 100)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public ListIndicesResponse listIndices(Integer page, Integer hitsPerPage) throws AlgoliaRuntimeException {
    return this.listIndices(page, hitsPerPage, null);
  }

  /**
   * List indices in an Algolia application.
   *
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public ListIndicesResponse listIndices(RequestOptions requestOptions) throws AlgoliaRuntimeException {
    return this.listIndices(null, null, requestOptions);
  }

  /**
   * List indices in an Algolia application.
   *
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public ListIndicesResponse listIndices() throws AlgoliaRuntimeException {
    return this.listIndices(null, null, null);
  }

  /**
   * (asynchronously) List indices in an Algolia application.
   *
   * @param page Returns the requested page number. The page size is determined by the `hitsPerPage`
   *     parameter. You can see the number of available pages in the `nbPages` response attribute.
   *     When `page` is null, the API response is not paginated. (optional)
   * @param hitsPerPage Maximum number of hits per page. (optional, default to 100)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture listIndicesAsync(Integer page, Integer hitsPerPage, RequestOptions requestOptions)
    throws AlgoliaRuntimeException {
    HttpRequest request = HttpRequest
      .builder()
      .setPath("/1/indexes")
      .setMethod("GET")
      .addQueryParameter("page", page)
      .addQueryParameter("hitsPerPage", hitsPerPage)
      .build();
    return executeAsync(request, requestOptions, new TypeReference() {});
  }

  /**
   * (asynchronously) List indices in an Algolia application.
   *
   * @param page Returns the requested page number. The page size is determined by the `hitsPerPage`
   *     parameter. You can see the number of available pages in the `nbPages` response attribute.
   *     When `page` is null, the API response is not paginated. (optional)
   * @param hitsPerPage Maximum number of hits per page. (optional, default to 100)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture listIndicesAsync(Integer page, Integer hitsPerPage) throws AlgoliaRuntimeException {
    return this.listIndicesAsync(page, hitsPerPage, null);
  }

  /**
   * (asynchronously) List indices in an Algolia application.
   *
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture listIndicesAsync(RequestOptions requestOptions) throws AlgoliaRuntimeException {
    return this.listIndicesAsync(null, null, requestOptions);
  }

  /**
   * (asynchronously) List indices in an Algolia application.
   *
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture listIndicesAsync() throws AlgoliaRuntimeException {
    return this.listIndicesAsync(null, null, null);
  }

  /**
   * List the userIDs assigned to a multi-cluster application. Since it can take up to a few seconds
   * to get the data from the different clusters, the response isn't real-time.
   *
   * @param page Returns the requested page number. The page size is determined by the `hitsPerPage`
   *     parameter. You can see the number of available pages in the `nbPages` response attribute.
   *     When `page` is null, the API response is not paginated. (optional)
   * @param hitsPerPage Maximum number of hits per page. (optional, default to 100)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public ListUserIdsResponse listUserIds(Integer page, Integer hitsPerPage, RequestOptions requestOptions) throws AlgoliaRuntimeException {
    return LaunderThrowable.await(listUserIdsAsync(page, hitsPerPage, requestOptions));
  }

  /**
   * List the userIDs assigned to a multi-cluster application. Since it can take up to a few seconds
   * to get the data from the different clusters, the response isn't real-time.
   *
   * @param page Returns the requested page number. The page size is determined by the `hitsPerPage`
   *     parameter. You can see the number of available pages in the `nbPages` response attribute.
   *     When `page` is null, the API response is not paginated. (optional)
   * @param hitsPerPage Maximum number of hits per page. (optional, default to 100)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public ListUserIdsResponse listUserIds(Integer page, Integer hitsPerPage) throws AlgoliaRuntimeException {
    return this.listUserIds(page, hitsPerPage, null);
  }

  /**
   * List the userIDs assigned to a multi-cluster application. Since it can take up to a few seconds
   * to get the data from the different clusters, the response isn't real-time.
   *
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public ListUserIdsResponse listUserIds(RequestOptions requestOptions) throws AlgoliaRuntimeException {
    return this.listUserIds(null, null, requestOptions);
  }

  /**
   * List the userIDs assigned to a multi-cluster application. Since it can take up to a few seconds
   * to get the data from the different clusters, the response isn't real-time.
   *
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public ListUserIdsResponse listUserIds() throws AlgoliaRuntimeException {
    return this.listUserIds(null, null, null);
  }

  /**
   * (asynchronously) List the userIDs assigned to a multi-cluster application. Since it can take up
   * to a few seconds to get the data from the different clusters, the response isn't real-time.
   *
   * @param page Returns the requested page number. The page size is determined by the `hitsPerPage`
   *     parameter. You can see the number of available pages in the `nbPages` response attribute.
   *     When `page` is null, the API response is not paginated. (optional)
   * @param hitsPerPage Maximum number of hits per page. (optional, default to 100)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture listUserIdsAsync(Integer page, Integer hitsPerPage, RequestOptions requestOptions)
    throws AlgoliaRuntimeException {
    HttpRequest request = HttpRequest
      .builder()
      .setPath("/1/clusters/mapping")
      .setMethod("GET")
      .addQueryParameter("page", page)
      .addQueryParameter("hitsPerPage", hitsPerPage)
      .build();
    return executeAsync(request, requestOptions, new TypeReference() {});
  }

  /**
   * (asynchronously) List the userIDs assigned to a multi-cluster application. Since it can take up
   * to a few seconds to get the data from the different clusters, the response isn't real-time.
   *
   * @param page Returns the requested page number. The page size is determined by the `hitsPerPage`
   *     parameter. You can see the number of available pages in the `nbPages` response attribute.
   *     When `page` is null, the API response is not paginated. (optional)
   * @param hitsPerPage Maximum number of hits per page. (optional, default to 100)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture listUserIdsAsync(Integer page, Integer hitsPerPage) throws AlgoliaRuntimeException {
    return this.listUserIdsAsync(page, hitsPerPage, null);
  }

  /**
   * (asynchronously) List the userIDs assigned to a multi-cluster application. Since it can take up
   * to a few seconds to get the data from the different clusters, the response isn't real-time.
   *
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture listUserIdsAsync(RequestOptions requestOptions) throws AlgoliaRuntimeException {
    return this.listUserIdsAsync(null, null, requestOptions);
  }

  /**
   * (asynchronously) List the userIDs assigned to a multi-cluster application. Since it can take up
   * to a few seconds to get the data from the different clusters, the response isn't real-time.
   *
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture listUserIdsAsync() throws AlgoliaRuntimeException {
    return this.listUserIdsAsync(null, null, null);
  }

  /**
   * To reduce the time spent on network round trips, you can perform several write actions in a
   * single request. It's a multi-index version of the [`batch`
   * operation](#tag/Records/operation/batch). Actions are applied in the order they are specified.
   * The supported actions are equivalent to the individual operations of the same name.
   *
   * @param batchParams (required)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public MultipleBatchResponse multipleBatch(BatchParams batchParams, RequestOptions requestOptions) throws AlgoliaRuntimeException {
    return LaunderThrowable.await(multipleBatchAsync(batchParams, requestOptions));
  }

  /**
   * To reduce the time spent on network round trips, you can perform several write actions in a
   * single request. It's a multi-index version of the [`batch`
   * operation](#tag/Records/operation/batch). Actions are applied in the order they are specified.
   * The supported actions are equivalent to the individual operations of the same name.
   *
   * @param batchParams (required)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public MultipleBatchResponse multipleBatch(BatchParams batchParams) throws AlgoliaRuntimeException {
    return this.multipleBatch(batchParams, null);
  }

  /**
   * (asynchronously) To reduce the time spent on network round trips, you can perform several write
   * actions in a single request. It's a multi-index version of the [`batch`
   * operation](#tag/Records/operation/batch). Actions are applied in the order they are specified.
   * The supported actions are equivalent to the individual operations of the same name.
   *
   * @param batchParams (required)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture multipleBatchAsync(BatchParams batchParams, RequestOptions requestOptions)
    throws AlgoliaRuntimeException {
    if (batchParams == null) {
      throw new AlgoliaRuntimeException("Parameter `batchParams` is required when calling `multipleBatch`.");
    }

    HttpRequest request = HttpRequest.builder().setPath("/1/indexes/*/batch").setMethod("POST").setBody(batchParams).build();
    return executeAsync(request, requestOptions, new TypeReference() {});
  }

  /**
   * (asynchronously) To reduce the time spent on network round trips, you can perform several write
   * actions in a single request. It's a multi-index version of the [`batch`
   * operation](#tag/Records/operation/batch). Actions are applied in the order they are specified.
   * The supported actions are equivalent to the individual operations of the same name.
   *
   * @param batchParams (required)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture multipleBatchAsync(BatchParams batchParams) throws AlgoliaRuntimeException {
    return this.multipleBatchAsync(batchParams, null);
  }

  /**
   * This `operation`, _copy_ or _move_, will copy or move a source index's (`IndexName`) records,
   * settings, synonyms, and rules to a `destination` index. If the destination index exists, it
   * will be replaced, except for index-specific API keys and analytics data. If the destination
   * index doesn't exist, it will be created. The choice between moving or copying an index depends
   * on your needs. Choose: - **Move** to rename an index. - **Copy** to create a new index with the
   * same records and configuration as an existing one. > **Note**: When considering copying or
   * moving, be aware of the [rate
   * limitations](https://www.algolia.com/doc/guides/scaling/algolia-service-limits/#application-record-and-index-limits)
   * on these processes and the [impact on your analytics
   * data](https://www.algolia.com/doc/guides/sending-and-managing-data/manage-indices-and-apps/manage-indices/concepts/indices-analytics/).
   *
   * @param indexName Index on which to perform the request. (required)
   * @param operationIndexParams (required)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public UpdatedAtResponse operationIndex(String indexName, OperationIndexParams operationIndexParams, RequestOptions requestOptions)
    throws AlgoliaRuntimeException {
    return LaunderThrowable.await(operationIndexAsync(indexName, operationIndexParams, requestOptions));
  }

  /**
   * This `operation`, _copy_ or _move_, will copy or move a source index's (`IndexName`) records,
   * settings, synonyms, and rules to a `destination` index. If the destination index exists, it
   * will be replaced, except for index-specific API keys and analytics data. If the destination
   * index doesn't exist, it will be created. The choice between moving or copying an index depends
   * on your needs. Choose: - **Move** to rename an index. - **Copy** to create a new index with the
   * same records and configuration as an existing one. > **Note**: When considering copying or
   * moving, be aware of the [rate
   * limitations](https://www.algolia.com/doc/guides/scaling/algolia-service-limits/#application-record-and-index-limits)
   * on these processes and the [impact on your analytics
   * data](https://www.algolia.com/doc/guides/sending-and-managing-data/manage-indices-and-apps/manage-indices/concepts/indices-analytics/).
   *
   * @param indexName Index on which to perform the request. (required)
   * @param operationIndexParams (required)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public UpdatedAtResponse operationIndex(String indexName, OperationIndexParams operationIndexParams) throws AlgoliaRuntimeException {
    return this.operationIndex(indexName, operationIndexParams, null);
  }

  /**
   * (asynchronously) This `operation`, _copy_ or _move_, will copy or move a source
   * index's (`IndexName`) records, settings, synonyms, and rules to a
   * `destination` index. If the destination index exists, it will be replaced, except for
   * index-specific API keys and analytics data. If the destination index doesn't exist, it will
   * be created. The choice between moving or copying an index depends on your needs. Choose: -
   * **Move** to rename an index. - **Copy** to create a new index with the same records and
   * configuration as an existing one. > **Note**: When considering copying or moving, be aware
   * of the [rate
   * limitations](https://www.algolia.com/doc/guides/scaling/algolia-service-limits/#application-record-and-index-limits)
   * on these processes and the [impact on your analytics
   * data](https://www.algolia.com/doc/guides/sending-and-managing-data/manage-indices-and-apps/manage-indices/concepts/indices-analytics/).
   *
   * @param indexName Index on which to perform the request. (required)
   * @param operationIndexParams (required)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture operationIndexAsync(
    String indexName,
    OperationIndexParams operationIndexParams,
    RequestOptions requestOptions
  ) throws AlgoliaRuntimeException {
    if (indexName == null) {
      throw new AlgoliaRuntimeException("Parameter `indexName` is required when calling `operationIndex`.");
    }

    if (operationIndexParams == null) {
      throw new AlgoliaRuntimeException("Parameter `operationIndexParams` is required when calling `operationIndex`.");
    }

    HttpRequest request = HttpRequest
      .builder()
      .setPath("/1/indexes/{indexName}/operation", indexName)
      .setMethod("POST")
      .setBody(operationIndexParams)
      .build();
    return executeAsync(request, requestOptions, new TypeReference() {});
  }

  /**
   * (asynchronously) This `operation`, _copy_ or _move_, will copy or move a source
   * index's (`IndexName`) records, settings, synonyms, and rules to a
   * `destination` index. If the destination index exists, it will be replaced, except for
   * index-specific API keys and analytics data. If the destination index doesn't exist, it will
   * be created. The choice between moving or copying an index depends on your needs. Choose: -
   * **Move** to rename an index. - **Copy** to create a new index with the same records and
   * configuration as an existing one. > **Note**: When considering copying or moving, be aware
   * of the [rate
   * limitations](https://www.algolia.com/doc/guides/scaling/algolia-service-limits/#application-record-and-index-limits)
   * on these processes and the [impact on your analytics
   * data](https://www.algolia.com/doc/guides/sending-and-managing-data/manage-indices-and-apps/manage-indices/concepts/indices-analytics/).
   *
   * @param indexName Index on which to perform the request. (required)
   * @param operationIndexParams (required)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture operationIndexAsync(String indexName, OperationIndexParams operationIndexParams)
    throws AlgoliaRuntimeException {
    return this.operationIndexAsync(indexName, operationIndexParams, null);
  }

  /**
   * Add new attributes or update current ones in an existing record. You can use any first-level
   * attribute but not nested attributes. If you specify a [nested
   * attribute](https://www.algolia.com/doc/guides/sending-and-managing-data/prepare-your-data/how-to/creating-and-using-nested-attributes/),
   * the engine treats it as a replacement for its first-level ancestor.
   *
   * @param indexName Index on which to perform the request. (required)
   * @param objectID Unique record (object) identifier. (required)
   * @param attributesToUpdate Object with attributes to update. (required)
   * @param createIfNotExists Indicates whether to create a new record if it doesn't exist yet.
   *     (optional, default to true)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public UpdatedAtWithObjectIdResponse partialUpdateObject(
    String indexName,
    String objectID,
    Map attributesToUpdate,
    Boolean createIfNotExists,
    RequestOptions requestOptions
  ) throws AlgoliaRuntimeException {
    return LaunderThrowable.await(partialUpdateObjectAsync(indexName, objectID, attributesToUpdate, createIfNotExists, requestOptions));
  }

  /**
   * Add new attributes or update current ones in an existing record. You can use any first-level
   * attribute but not nested attributes. If you specify a [nested
   * attribute](https://www.algolia.com/doc/guides/sending-and-managing-data/prepare-your-data/how-to/creating-and-using-nested-attributes/),
   * the engine treats it as a replacement for its first-level ancestor.
   *
   * @param indexName Index on which to perform the request. (required)
   * @param objectID Unique record (object) identifier. (required)
   * @param attributesToUpdate Object with attributes to update. (required)
   * @param createIfNotExists Indicates whether to create a new record if it doesn't exist yet.
   *     (optional, default to true)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public UpdatedAtWithObjectIdResponse partialUpdateObject(
    String indexName,
    String objectID,
    Map attributesToUpdate,
    Boolean createIfNotExists
  ) throws AlgoliaRuntimeException {
    return this.partialUpdateObject(indexName, objectID, attributesToUpdate, createIfNotExists, null);
  }

  /**
   * Add new attributes or update current ones in an existing record. You can use any first-level
   * attribute but not nested attributes. If you specify a [nested
   * attribute](https://www.algolia.com/doc/guides/sending-and-managing-data/prepare-your-data/how-to/creating-and-using-nested-attributes/),
   * the engine treats it as a replacement for its first-level ancestor.
   *
   * @param indexName Index on which to perform the request. (required)
   * @param objectID Unique record (object) identifier. (required)
   * @param attributesToUpdate Object with attributes to update. (required)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public UpdatedAtWithObjectIdResponse partialUpdateObject(
    String indexName,
    String objectID,
    Map attributesToUpdate,
    RequestOptions requestOptions
  ) throws AlgoliaRuntimeException {
    return this.partialUpdateObject(indexName, objectID, attributesToUpdate, null, requestOptions);
  }

  /**
   * Add new attributes or update current ones in an existing record. You can use any first-level
   * attribute but not nested attributes. If you specify a [nested
   * attribute](https://www.algolia.com/doc/guides/sending-and-managing-data/prepare-your-data/how-to/creating-and-using-nested-attributes/),
   * the engine treats it as a replacement for its first-level ancestor.
   *
   * @param indexName Index on which to perform the request. (required)
   * @param objectID Unique record (object) identifier. (required)
   * @param attributesToUpdate Object with attributes to update. (required)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public UpdatedAtWithObjectIdResponse partialUpdateObject(
    String indexName,
    String objectID,
    Map attributesToUpdate
  ) throws AlgoliaRuntimeException {
    return this.partialUpdateObject(indexName, objectID, attributesToUpdate, null, null);
  }

  /**
   * (asynchronously) Add new attributes or update current ones in an existing record. You can use
   * any first-level attribute but not nested attributes. If you specify a [nested
   * attribute](https://www.algolia.com/doc/guides/sending-and-managing-data/prepare-your-data/how-to/creating-and-using-nested-attributes/),
   * the engine treats it as a replacement for its first-level ancestor.
   *
   * @param indexName Index on which to perform the request. (required)
   * @param objectID Unique record (object) identifier. (required)
   * @param attributesToUpdate Object with attributes to update. (required)
   * @param createIfNotExists Indicates whether to create a new record if it doesn't exist yet.
   *     (optional, default to true)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture partialUpdateObjectAsync(
    String indexName,
    String objectID,
    Map attributesToUpdate,
    Boolean createIfNotExists,
    RequestOptions requestOptions
  ) throws AlgoliaRuntimeException {
    if (indexName == null) {
      throw new AlgoliaRuntimeException("Parameter `indexName` is required when calling `partialUpdateObject`.");
    }

    if (objectID == null) {
      throw new AlgoliaRuntimeException("Parameter `objectID` is required when calling `partialUpdateObject`.");
    }

    if (attributesToUpdate == null) {
      throw new AlgoliaRuntimeException("Parameter `attributesToUpdate` is required when calling `partialUpdateObject`.");
    }

    HttpRequest request = HttpRequest
      .builder()
      .setPath("/1/indexes/{indexName}/{objectID}/partial", indexName, objectID)
      .setMethod("POST")
      .setBody(attributesToUpdate)
      .addQueryParameter("createIfNotExists", createIfNotExists)
      .build();
    return executeAsync(request, requestOptions, new TypeReference() {});
  }

  /**
   * (asynchronously) Add new attributes or update current ones in an existing record. You can use
   * any first-level attribute but not nested attributes. If you specify a [nested
   * attribute](https://www.algolia.com/doc/guides/sending-and-managing-data/prepare-your-data/how-to/creating-and-using-nested-attributes/),
   * the engine treats it as a replacement for its first-level ancestor.
   *
   * @param indexName Index on which to perform the request. (required)
   * @param objectID Unique record (object) identifier. (required)
   * @param attributesToUpdate Object with attributes to update. (required)
   * @param createIfNotExists Indicates whether to create a new record if it doesn't exist yet.
   *     (optional, default to true)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture partialUpdateObjectAsync(
    String indexName,
    String objectID,
    Map attributesToUpdate,
    Boolean createIfNotExists
  ) throws AlgoliaRuntimeException {
    return this.partialUpdateObjectAsync(indexName, objectID, attributesToUpdate, createIfNotExists, null);
  }

  /**
   * (asynchronously) Add new attributes or update current ones in an existing record. You can use
   * any first-level attribute but not nested attributes. If you specify a [nested
   * attribute](https://www.algolia.com/doc/guides/sending-and-managing-data/prepare-your-data/how-to/creating-and-using-nested-attributes/),
   * the engine treats it as a replacement for its first-level ancestor.
   *
   * @param indexName Index on which to perform the request. (required)
   * @param objectID Unique record (object) identifier. (required)
   * @param attributesToUpdate Object with attributes to update. (required)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture partialUpdateObjectAsync(
    String indexName,
    String objectID,
    Map attributesToUpdate,
    RequestOptions requestOptions
  ) throws AlgoliaRuntimeException {
    return this.partialUpdateObjectAsync(indexName, objectID, attributesToUpdate, null, requestOptions);
  }

  /**
   * (asynchronously) Add new attributes or update current ones in an existing record. You can use
   * any first-level attribute but not nested attributes. If you specify a [nested
   * attribute](https://www.algolia.com/doc/guides/sending-and-managing-data/prepare-your-data/how-to/creating-and-using-nested-attributes/),
   * the engine treats it as a replacement for its first-level ancestor.
   *
   * @param indexName Index on which to perform the request. (required)
   * @param objectID Unique record (object) identifier. (required)
   * @param attributesToUpdate Object with attributes to update. (required)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture partialUpdateObjectAsync(
    String indexName,
    String objectID,
    Map attributesToUpdate
  ) throws AlgoliaRuntimeException {
    return this.partialUpdateObjectAsync(indexName, objectID, attributesToUpdate, null, null);
  }

  /**
   * This method allow you to send requests to the Algolia REST API.
   *
   * @param path Path of the endpoint, anything after \"/1\" must be specified. (required)
   * @param parameters Query parameters to apply to the current query. (optional)
   * @param body Parameters to send with the custom request. (optional)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public Object post(String path, Map parameters, Object body, RequestOptions requestOptions)
    throws AlgoliaRuntimeException {
    return LaunderThrowable.await(postAsync(path, parameters, body, requestOptions));
  }

  /**
   * This method allow you to send requests to the Algolia REST API.
   *
   * @param path Path of the endpoint, anything after \"/1\" must be specified. (required)
   * @param parameters Query parameters to apply to the current query. (optional)
   * @param body Parameters to send with the custom request. (optional)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public Object post(String path, Map parameters, Object body) throws AlgoliaRuntimeException {
    return this.post(path, parameters, body, null);
  }

  /**
   * This method allow you to send requests to the Algolia REST API.
   *
   * @param path Path of the endpoint, anything after \"/1\" must be specified. (required)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public Object post(String path, RequestOptions requestOptions) throws AlgoliaRuntimeException {
    return this.post(path, null, null, requestOptions);
  }

  /**
   * This method allow you to send requests to the Algolia REST API.
   *
   * @param path Path of the endpoint, anything after \"/1\" must be specified. (required)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public Object post(String path) throws AlgoliaRuntimeException {
    return this.post(path, null, null, null);
  }

  /**
   * (asynchronously) This method allow you to send requests to the Algolia REST API.
   *
   * @param path Path of the endpoint, anything after \"/1\" must be specified. (required)
   * @param parameters Query parameters to apply to the current query. (optional)
   * @param body Parameters to send with the custom request. (optional)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture postAsync(String path, Map parameters, Object body, RequestOptions requestOptions)
    throws AlgoliaRuntimeException {
    if (path == null) {
      throw new AlgoliaRuntimeException("Parameter `path` is required when calling `post`.");
    }

    HttpRequest request = HttpRequest
      .builder()
      .setPathEncoded("/1{path}", path)
      .setMethod("POST")
      .setBody(body)
      .addQueryParameters(parameters)
      .build();
    return executeAsync(request, requestOptions, new TypeReference() {});
  }

  /**
   * (asynchronously) This method allow you to send requests to the Algolia REST API.
   *
   * @param path Path of the endpoint, anything after \"/1\" must be specified. (required)
   * @param parameters Query parameters to apply to the current query. (optional)
   * @param body Parameters to send with the custom request. (optional)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture postAsync(String path, Map parameters, Object body) throws AlgoliaRuntimeException {
    return this.postAsync(path, parameters, body, null);
  }

  /**
   * (asynchronously) This method allow you to send requests to the Algolia REST API.
   *
   * @param path Path of the endpoint, anything after \"/1\" must be specified. (required)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture postAsync(String path, RequestOptions requestOptions) throws AlgoliaRuntimeException {
    return this.postAsync(path, null, null, requestOptions);
  }

  /**
   * (asynchronously) This method allow you to send requests to the Algolia REST API.
   *
   * @param path Path of the endpoint, anything after \"/1\" must be specified. (required)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture postAsync(String path) throws AlgoliaRuntimeException {
    return this.postAsync(path, null, null, null);
  }

  /**
   * This method allow you to send requests to the Algolia REST API.
   *
   * @param path Path of the endpoint, anything after \"/1\" must be specified. (required)
   * @param parameters Query parameters to apply to the current query. (optional)
   * @param body Parameters to send with the custom request. (optional)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public Object put(String path, Map parameters, Object body, RequestOptions requestOptions)
    throws AlgoliaRuntimeException {
    return LaunderThrowable.await(putAsync(path, parameters, body, requestOptions));
  }

  /**
   * This method allow you to send requests to the Algolia REST API.
   *
   * @param path Path of the endpoint, anything after \"/1\" must be specified. (required)
   * @param parameters Query parameters to apply to the current query. (optional)
   * @param body Parameters to send with the custom request. (optional)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public Object put(String path, Map parameters, Object body) throws AlgoliaRuntimeException {
    return this.put(path, parameters, body, null);
  }

  /**
   * This method allow you to send requests to the Algolia REST API.
   *
   * @param path Path of the endpoint, anything after \"/1\" must be specified. (required)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public Object put(String path, RequestOptions requestOptions) throws AlgoliaRuntimeException {
    return this.put(path, null, null, requestOptions);
  }

  /**
   * This method allow you to send requests to the Algolia REST API.
   *
   * @param path Path of the endpoint, anything after \"/1\" must be specified. (required)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public Object put(String path) throws AlgoliaRuntimeException {
    return this.put(path, null, null, null);
  }

  /**
   * (asynchronously) This method allow you to send requests to the Algolia REST API.
   *
   * @param path Path of the endpoint, anything after \"/1\" must be specified. (required)
   * @param parameters Query parameters to apply to the current query. (optional)
   * @param body Parameters to send with the custom request. (optional)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture putAsync(String path, Map parameters, Object body, RequestOptions requestOptions)
    throws AlgoliaRuntimeException {
    if (path == null) {
      throw new AlgoliaRuntimeException("Parameter `path` is required when calling `put`.");
    }

    HttpRequest request = HttpRequest
      .builder()
      .setPathEncoded("/1{path}", path)
      .setMethod("PUT")
      .setBody(body)
      .addQueryParameters(parameters)
      .build();
    return executeAsync(request, requestOptions, new TypeReference() {});
  }

  /**
   * (asynchronously) This method allow you to send requests to the Algolia REST API.
   *
   * @param path Path of the endpoint, anything after \"/1\" must be specified. (required)
   * @param parameters Query parameters to apply to the current query. (optional)
   * @param body Parameters to send with the custom request. (optional)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture putAsync(String path, Map parameters, Object body) throws AlgoliaRuntimeException {
    return this.putAsync(path, parameters, body, null);
  }

  /**
   * (asynchronously) This method allow you to send requests to the Algolia REST API.
   *
   * @param path Path of the endpoint, anything after \"/1\" must be specified. (required)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture putAsync(String path, RequestOptions requestOptions) throws AlgoliaRuntimeException {
    return this.putAsync(path, null, null, requestOptions);
  }

  /**
   * (asynchronously) This method allow you to send requests to the Algolia REST API.
   *
   * @param path Path of the endpoint, anything after \"/1\" must be specified. (required)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture putAsync(String path) throws AlgoliaRuntimeException {
    return this.putAsync(path, null, null, null);
  }

  /**
   * Remove a userID and its associated data from the multi-clusters.
   *
   * @param userID userID to assign. (required)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public RemoveUserIdResponse removeUserId(String userID, RequestOptions requestOptions) throws AlgoliaRuntimeException {
    return LaunderThrowable.await(removeUserIdAsync(userID, requestOptions));
  }

  /**
   * Remove a userID and its associated data from the multi-clusters.
   *
   * @param userID userID to assign. (required)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public RemoveUserIdResponse removeUserId(String userID) throws AlgoliaRuntimeException {
    return this.removeUserId(userID, null);
  }

  /**
   * (asynchronously) Remove a userID and its associated data from the multi-clusters.
   *
   * @param userID userID to assign. (required)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture removeUserIdAsync(String userID, RequestOptions requestOptions)
    throws AlgoliaRuntimeException {
    if (userID == null) {
      throw new AlgoliaRuntimeException("Parameter `userID` is required when calling `removeUserId`.");
    }

    HttpRequest request = HttpRequest.builder().setPath("/1/clusters/mapping/{userID}", userID).setMethod("DELETE").build();
    return executeAsync(request, requestOptions, new TypeReference() {});
  }

  /**
   * (asynchronously) Remove a userID and its associated data from the multi-clusters.
   *
   * @param userID userID to assign. (required)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture removeUserIdAsync(String userID) throws AlgoliaRuntimeException {
    return this.removeUserIdAsync(userID, null);
  }

  /**
   * Replace all allowed sources.
   *
   * @param source Allowed sources. (required)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public ReplaceSourceResponse replaceSources(List source, RequestOptions requestOptions) throws AlgoliaRuntimeException {
    return LaunderThrowable.await(replaceSourcesAsync(source, requestOptions));
  }

  /**
   * Replace all allowed sources.
   *
   * @param source Allowed sources. (required)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public ReplaceSourceResponse replaceSources(List source) throws AlgoliaRuntimeException {
    return this.replaceSources(source, null);
  }

  /**
   * (asynchronously) Replace all allowed sources.
   *
   * @param source Allowed sources. (required)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture replaceSourcesAsync(List source, RequestOptions requestOptions)
    throws AlgoliaRuntimeException {
    if (source == null) {
      throw new AlgoliaRuntimeException("Parameter `source` is required when calling `replaceSources`.");
    }

    HttpRequest request = HttpRequest.builder().setPath("/1/security/sources").setMethod("PUT").setBody(source).build();
    return executeAsync(request, requestOptions, new TypeReference() {});
  }

  /**
   * (asynchronously) Replace all allowed sources.
   *
   * @param source Allowed sources. (required)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture replaceSourcesAsync(List source) throws AlgoliaRuntimeException {
    return this.replaceSourcesAsync(source, null);
  }

  /**
   * Restore a deleted API key, along with its associated permissions. The request must be
   * authenticated with the admin API key.
   *
   * @param key API key. (required)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public AddApiKeyResponse restoreApiKey(String key, RequestOptions requestOptions) throws AlgoliaRuntimeException {
    return LaunderThrowable.await(restoreApiKeyAsync(key, requestOptions));
  }

  /**
   * Restore a deleted API key, along with its associated permissions. The request must be
   * authenticated with the admin API key.
   *
   * @param key API key. (required)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public AddApiKeyResponse restoreApiKey(String key) throws AlgoliaRuntimeException {
    return this.restoreApiKey(key, null);
  }

  /**
   * (asynchronously) Restore a deleted API key, along with its associated permissions. The request
   * must be authenticated with the admin API key.
   *
   * @param key API key. (required)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture restoreApiKeyAsync(String key, RequestOptions requestOptions) throws AlgoliaRuntimeException {
    if (key == null) {
      throw new AlgoliaRuntimeException("Parameter `key` is required when calling `restoreApiKey`.");
    }

    HttpRequest request = HttpRequest.builder().setPath("/1/keys/{key}/restore", key).setMethod("POST").build();

    return executeAsync(request, requestOptions, new TypeReference() {});
  }

  /**
   * (asynchronously) Restore a deleted API key, along with its associated permissions. The request
   * must be authenticated with the admin API key.
   *
   * @param key API key. (required)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture restoreApiKeyAsync(String key) throws AlgoliaRuntimeException {
    return this.restoreApiKeyAsync(key, null);
  }

  /**
   * Add a record (object) to an index or replace it. If the record doesn't contain an `objectID`,
   * Algolia automatically adds it. If you use an existing `objectID`, the existing record is
   * replaced with the new one. To add multiple records to your index in a single API request, use
   * the [`batch` operation](#tag/Records/operation/batch).
   *
   * @param indexName Index on which to perform the request. (required)
   * @param body The Algolia record. (required)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public SaveObjectResponse saveObject(String indexName, Object body, RequestOptions requestOptions) throws AlgoliaRuntimeException {
    return LaunderThrowable.await(saveObjectAsync(indexName, body, requestOptions));
  }

  /**
   * Add a record (object) to an index or replace it. If the record doesn't contain an `objectID`,
   * Algolia automatically adds it. If you use an existing `objectID`, the existing record is
   * replaced with the new one. To add multiple records to your index in a single API request, use
   * the [`batch` operation](#tag/Records/operation/batch).
   *
   * @param indexName Index on which to perform the request. (required)
   * @param body The Algolia record. (required)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public SaveObjectResponse saveObject(String indexName, Object body) throws AlgoliaRuntimeException {
    return this.saveObject(indexName, body, null);
  }

  /**
   * (asynchronously) Add a record (object) to an index or replace it. If the record doesn't
   * contain an `objectID`, Algolia automatically adds it. If you use an existing
   * `objectID`, the existing record is replaced with the new one. To add multiple records
   * to your index in a single API request, use the [`batch`
   * operation](#tag/Records/operation/batch).
   *
   * @param indexName Index on which to perform the request. (required)
   * @param body The Algolia record. (required)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture saveObjectAsync(String indexName, Object body, RequestOptions requestOptions)
    throws AlgoliaRuntimeException {
    if (indexName == null) {
      throw new AlgoliaRuntimeException("Parameter `indexName` is required when calling `saveObject`.");
    }

    if (body == null) {
      throw new AlgoliaRuntimeException("Parameter `body` is required when calling `saveObject`.");
    }

    HttpRequest request = HttpRequest.builder().setPath("/1/indexes/{indexName}", indexName).setMethod("POST").setBody(body).build();
    return executeAsync(request, requestOptions, new TypeReference() {});
  }

  /**
   * (asynchronously) Add a record (object) to an index or replace it. If the record doesn't
   * contain an `objectID`, Algolia automatically adds it. If you use an existing
   * `objectID`, the existing record is replaced with the new one. To add multiple records
   * to your index in a single API request, use the [`batch`
   * operation](#tag/Records/operation/batch).
   *
   * @param indexName Index on which to perform the request. (required)
   * @param body The Algolia record. (required)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture saveObjectAsync(String indexName, Object body) throws AlgoliaRuntimeException {
    return this.saveObjectAsync(indexName, body, null);
  }

  /**
   * To create or update more than one rule, use the [`batch`
   * operation](#tag/Rules/operation/saveRules).
   *
   * @param indexName Index on which to perform the request. (required)
   * @param objectID Unique identifier of a rule object. (required)
   * @param rule (required)
   * @param forwardToReplicas Indicates whether changed index settings are forwarded to the replica
   *     indices. (optional)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public UpdatedRuleResponse saveRule(
    String indexName,
    String objectID,
    Rule rule,
    Boolean forwardToReplicas,
    RequestOptions requestOptions
  ) throws AlgoliaRuntimeException {
    return LaunderThrowable.await(saveRuleAsync(indexName, objectID, rule, forwardToReplicas, requestOptions));
  }

  /**
   * To create or update more than one rule, use the [`batch`
   * operation](#tag/Rules/operation/saveRules).
   *
   * @param indexName Index on which to perform the request. (required)
   * @param objectID Unique identifier of a rule object. (required)
   * @param rule (required)
   * @param forwardToReplicas Indicates whether changed index settings are forwarded to the replica
   *     indices. (optional)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public UpdatedRuleResponse saveRule(String indexName, String objectID, Rule rule, Boolean forwardToReplicas)
    throws AlgoliaRuntimeException {
    return this.saveRule(indexName, objectID, rule, forwardToReplicas, null);
  }

  /**
   * To create or update more than one rule, use the [`batch`
   * operation](#tag/Rules/operation/saveRules).
   *
   * @param indexName Index on which to perform the request. (required)
   * @param objectID Unique identifier of a rule object. (required)
   * @param rule (required)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public UpdatedRuleResponse saveRule(String indexName, String objectID, Rule rule, RequestOptions requestOptions)
    throws AlgoliaRuntimeException {
    return this.saveRule(indexName, objectID, rule, null, requestOptions);
  }

  /**
   * To create or update more than one rule, use the [`batch`
   * operation](#tag/Rules/operation/saveRules).
   *
   * @param indexName Index on which to perform the request. (required)
   * @param objectID Unique identifier of a rule object. (required)
   * @param rule (required)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public UpdatedRuleResponse saveRule(String indexName, String objectID, Rule rule) throws AlgoliaRuntimeException {
    return this.saveRule(indexName, objectID, rule, null, null);
  }

  /**
   * (asynchronously) To create or update more than one rule, use the [`batch`
   * operation](#tag/Rules/operation/saveRules).
   *
   * @param indexName Index on which to perform the request. (required)
   * @param objectID Unique identifier of a rule object. (required)
   * @param rule (required)
   * @param forwardToReplicas Indicates whether changed index settings are forwarded to the replica
   *     indices. (optional)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture saveRuleAsync(
    String indexName,
    String objectID,
    Rule rule,
    Boolean forwardToReplicas,
    RequestOptions requestOptions
  ) throws AlgoliaRuntimeException {
    if (indexName == null) {
      throw new AlgoliaRuntimeException("Parameter `indexName` is required when calling `saveRule`.");
    }

    if (objectID == null) {
      throw new AlgoliaRuntimeException("Parameter `objectID` is required when calling `saveRule`.");
    }

    if (rule == null) {
      throw new AlgoliaRuntimeException("Parameter `rule` is required when calling `saveRule`.");
    }

    HttpRequest request = HttpRequest
      .builder()
      .setPath("/1/indexes/{indexName}/rules/{objectID}", indexName, objectID)
      .setMethod("PUT")
      .setBody(rule)
      .addQueryParameter("forwardToReplicas", forwardToReplicas)
      .build();
    return executeAsync(request, requestOptions, new TypeReference() {});
  }

  /**
   * (asynchronously) To create or update more than one rule, use the [`batch`
   * operation](#tag/Rules/operation/saveRules).
   *
   * @param indexName Index on which to perform the request. (required)
   * @param objectID Unique identifier of a rule object. (required)
   * @param rule (required)
   * @param forwardToReplicas Indicates whether changed index settings are forwarded to the replica
   *     indices. (optional)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture saveRuleAsync(String indexName, String objectID, Rule rule, Boolean forwardToReplicas)
    throws AlgoliaRuntimeException {
    return this.saveRuleAsync(indexName, objectID, rule, forwardToReplicas, null);
  }

  /**
   * (asynchronously) To create or update more than one rule, use the [`batch`
   * operation](#tag/Rules/operation/saveRules).
   *
   * @param indexName Index on which to perform the request. (required)
   * @param objectID Unique identifier of a rule object. (required)
   * @param rule (required)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture saveRuleAsync(String indexName, String objectID, Rule rule, RequestOptions requestOptions)
    throws AlgoliaRuntimeException {
    return this.saveRuleAsync(indexName, objectID, rule, null, requestOptions);
  }

  /**
   * (asynchronously) To create or update more than one rule, use the [`batch`
   * operation](#tag/Rules/operation/saveRules).
   *
   * @param indexName Index on which to perform the request. (required)
   * @param objectID Unique identifier of a rule object. (required)
   * @param rule (required)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture saveRuleAsync(String indexName, String objectID, Rule rule) throws AlgoliaRuntimeException {
    return this.saveRuleAsync(indexName, objectID, rule, null, null);
  }

  /**
   * Create or update multiple rules.
   *
   * @param indexName Index on which to perform the request. (required)
   * @param rules (required)
   * @param forwardToReplicas Indicates whether changed index settings are forwarded to the replica
   *     indices. (optional)
   * @param clearExistingRules Indicates whether existing rules should be deleted before adding this
   *     batch. (optional)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public UpdatedAtResponse saveRules(
    String indexName,
    List rules,
    Boolean forwardToReplicas,
    Boolean clearExistingRules,
    RequestOptions requestOptions
  ) throws AlgoliaRuntimeException {
    return LaunderThrowable.await(saveRulesAsync(indexName, rules, forwardToReplicas, clearExistingRules, requestOptions));
  }

  /**
   * Create or update multiple rules.
   *
   * @param indexName Index on which to perform the request. (required)
   * @param rules (required)
   * @param forwardToReplicas Indicates whether changed index settings are forwarded to the replica
   *     indices. (optional)
   * @param clearExistingRules Indicates whether existing rules should be deleted before adding this
   *     batch. (optional)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public UpdatedAtResponse saveRules(String indexName, List rules, Boolean forwardToReplicas, Boolean clearExistingRules)
    throws AlgoliaRuntimeException {
    return this.saveRules(indexName, rules, forwardToReplicas, clearExistingRules, null);
  }

  /**
   * Create or update multiple rules.
   *
   * @param indexName Index on which to perform the request. (required)
   * @param rules (required)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public UpdatedAtResponse saveRules(String indexName, List rules, RequestOptions requestOptions) throws AlgoliaRuntimeException {
    return this.saveRules(indexName, rules, null, null, requestOptions);
  }

  /**
   * Create or update multiple rules.
   *
   * @param indexName Index on which to perform the request. (required)
   * @param rules (required)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public UpdatedAtResponse saveRules(String indexName, List rules) throws AlgoliaRuntimeException {
    return this.saveRules(indexName, rules, null, null, null);
  }

  /**
   * (asynchronously) Create or update multiple rules.
   *
   * @param indexName Index on which to perform the request. (required)
   * @param rules (required)
   * @param forwardToReplicas Indicates whether changed index settings are forwarded to the replica
   *     indices. (optional)
   * @param clearExistingRules Indicates whether existing rules should be deleted before adding this
   *     batch. (optional)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture saveRulesAsync(
    String indexName,
    List rules,
    Boolean forwardToReplicas,
    Boolean clearExistingRules,
    RequestOptions requestOptions
  ) throws AlgoliaRuntimeException {
    if (indexName == null) {
      throw new AlgoliaRuntimeException("Parameter `indexName` is required when calling `saveRules`.");
    }

    if (rules == null) {
      throw new AlgoliaRuntimeException("Parameter `rules` is required when calling `saveRules`.");
    }

    HttpRequest request = HttpRequest
      .builder()
      .setPath("/1/indexes/{indexName}/rules/batch", indexName)
      .setMethod("POST")
      .setBody(rules)
      .addQueryParameter("forwardToReplicas", forwardToReplicas)
      .addQueryParameter("clearExistingRules", clearExistingRules)
      .build();
    return executeAsync(request, requestOptions, new TypeReference() {});
  }

  /**
   * (asynchronously) Create or update multiple rules.
   *
   * @param indexName Index on which to perform the request. (required)
   * @param rules (required)
   * @param forwardToReplicas Indicates whether changed index settings are forwarded to the replica
   *     indices. (optional)
   * @param clearExistingRules Indicates whether existing rules should be deleted before adding this
   *     batch. (optional)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture saveRulesAsync(
    String indexName,
    List rules,
    Boolean forwardToReplicas,
    Boolean clearExistingRules
  ) throws AlgoliaRuntimeException {
    return this.saveRulesAsync(indexName, rules, forwardToReplicas, clearExistingRules, null);
  }

  /**
   * (asynchronously) Create or update multiple rules.
   *
   * @param indexName Index on which to perform the request. (required)
   * @param rules (required)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture saveRulesAsync(String indexName, List rules, RequestOptions requestOptions)
    throws AlgoliaRuntimeException {
    return this.saveRulesAsync(indexName, rules, null, null, requestOptions);
  }

  /**
   * (asynchronously) Create or update multiple rules.
   *
   * @param indexName Index on which to perform the request. (required)
   * @param rules (required)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture saveRulesAsync(String indexName, List rules) throws AlgoliaRuntimeException {
    return this.saveRulesAsync(indexName, rules, null, null, null);
  }

  /**
   * Add a
   * [synonym](https://www.algolia.com/doc/guides/managing-results/optimize-search-results/adding-synonyms/#the-different-types-of-synonyms)
   * to an index or replace it. If the synonym `objectID` doesn't exist, Algolia adds a new one. If
   * you use an existing synonym `objectID`, the existing synonym is replaced with the new one. To
   * add multiple synonyms in a single API request, use the [`batch`
   * operation](#tag/Synonyms/operation/saveSynonyms).
   *
   * @param indexName Index on which to perform the request. (required)
   * @param objectID Unique identifier of a synonym object. (required)
   * @param synonymHit (required)
   * @param forwardToReplicas Indicates whether changed index settings are forwarded to the replica
   *     indices. (optional)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public SaveSynonymResponse saveSynonym(
    String indexName,
    String objectID,
    SynonymHit synonymHit,
    Boolean forwardToReplicas,
    RequestOptions requestOptions
  ) throws AlgoliaRuntimeException {
    return LaunderThrowable.await(saveSynonymAsync(indexName, objectID, synonymHit, forwardToReplicas, requestOptions));
  }

  /**
   * Add a
   * [synonym](https://www.algolia.com/doc/guides/managing-results/optimize-search-results/adding-synonyms/#the-different-types-of-synonyms)
   * to an index or replace it. If the synonym `objectID` doesn't exist, Algolia adds a new one. If
   * you use an existing synonym `objectID`, the existing synonym is replaced with the new one. To
   * add multiple synonyms in a single API request, use the [`batch`
   * operation](#tag/Synonyms/operation/saveSynonyms).
   *
   * @param indexName Index on which to perform the request. (required)
   * @param objectID Unique identifier of a synonym object. (required)
   * @param synonymHit (required)
   * @param forwardToReplicas Indicates whether changed index settings are forwarded to the replica
   *     indices. (optional)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public SaveSynonymResponse saveSynonym(String indexName, String objectID, SynonymHit synonymHit, Boolean forwardToReplicas)
    throws AlgoliaRuntimeException {
    return this.saveSynonym(indexName, objectID, synonymHit, forwardToReplicas, null);
  }

  /**
   * Add a
   * [synonym](https://www.algolia.com/doc/guides/managing-results/optimize-search-results/adding-synonyms/#the-different-types-of-synonyms)
   * to an index or replace it. If the synonym `objectID` doesn't exist, Algolia adds a new one. If
   * you use an existing synonym `objectID`, the existing synonym is replaced with the new one. To
   * add multiple synonyms in a single API request, use the [`batch`
   * operation](#tag/Synonyms/operation/saveSynonyms).
   *
   * @param indexName Index on which to perform the request. (required)
   * @param objectID Unique identifier of a synonym object. (required)
   * @param synonymHit (required)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public SaveSynonymResponse saveSynonym(String indexName, String objectID, SynonymHit synonymHit, RequestOptions requestOptions)
    throws AlgoliaRuntimeException {
    return this.saveSynonym(indexName, objectID, synonymHit, null, requestOptions);
  }

  /**
   * Add a
   * [synonym](https://www.algolia.com/doc/guides/managing-results/optimize-search-results/adding-synonyms/#the-different-types-of-synonyms)
   * to an index or replace it. If the synonym `objectID` doesn't exist, Algolia adds a new one. If
   * you use an existing synonym `objectID`, the existing synonym is replaced with the new one. To
   * add multiple synonyms in a single API request, use the [`batch`
   * operation](#tag/Synonyms/operation/saveSynonyms).
   *
   * @param indexName Index on which to perform the request. (required)
   * @param objectID Unique identifier of a synonym object. (required)
   * @param synonymHit (required)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public SaveSynonymResponse saveSynonym(String indexName, String objectID, SynonymHit synonymHit) throws AlgoliaRuntimeException {
    return this.saveSynonym(indexName, objectID, synonymHit, null, null);
  }

  /**
   * (asynchronously) Add a
   * [synonym](https://www.algolia.com/doc/guides/managing-results/optimize-search-results/adding-synonyms/#the-different-types-of-synonyms)
   * to an index or replace it. If the synonym `objectID` doesn't exist, Algolia adds
   * a new one. If you use an existing synonym `objectID`, the existing synonym is
   * replaced with the new one. To add multiple synonyms in a single API request, use the
   * [`batch` operation](#tag/Synonyms/operation/saveSynonyms).
   *
   * @param indexName Index on which to perform the request. (required)
   * @param objectID Unique identifier of a synonym object. (required)
   * @param synonymHit (required)
   * @param forwardToReplicas Indicates whether changed index settings are forwarded to the replica
   *     indices. (optional)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture saveSynonymAsync(
    String indexName,
    String objectID,
    SynonymHit synonymHit,
    Boolean forwardToReplicas,
    RequestOptions requestOptions
  ) throws AlgoliaRuntimeException {
    if (indexName == null) {
      throw new AlgoliaRuntimeException("Parameter `indexName` is required when calling `saveSynonym`.");
    }

    if (objectID == null) {
      throw new AlgoliaRuntimeException("Parameter `objectID` is required when calling `saveSynonym`.");
    }

    if (synonymHit == null) {
      throw new AlgoliaRuntimeException("Parameter `synonymHit` is required when calling `saveSynonym`.");
    }

    HttpRequest request = HttpRequest
      .builder()
      .setPath("/1/indexes/{indexName}/synonyms/{objectID}", indexName, objectID)
      .setMethod("PUT")
      .setBody(synonymHit)
      .addQueryParameter("forwardToReplicas", forwardToReplicas)
      .build();
    return executeAsync(request, requestOptions, new TypeReference() {});
  }

  /**
   * (asynchronously) Add a
   * [synonym](https://www.algolia.com/doc/guides/managing-results/optimize-search-results/adding-synonyms/#the-different-types-of-synonyms)
   * to an index or replace it. If the synonym `objectID` doesn't exist, Algolia adds
   * a new one. If you use an existing synonym `objectID`, the existing synonym is
   * replaced with the new one. To add multiple synonyms in a single API request, use the
   * [`batch` operation](#tag/Synonyms/operation/saveSynonyms).
   *
   * @param indexName Index on which to perform the request. (required)
   * @param objectID Unique identifier of a synonym object. (required)
   * @param synonymHit (required)
   * @param forwardToReplicas Indicates whether changed index settings are forwarded to the replica
   *     indices. (optional)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture saveSynonymAsync(
    String indexName,
    String objectID,
    SynonymHit synonymHit,
    Boolean forwardToReplicas
  ) throws AlgoliaRuntimeException {
    return this.saveSynonymAsync(indexName, objectID, synonymHit, forwardToReplicas, null);
  }

  /**
   * (asynchronously) Add a
   * [synonym](https://www.algolia.com/doc/guides/managing-results/optimize-search-results/adding-synonyms/#the-different-types-of-synonyms)
   * to an index or replace it. If the synonym `objectID` doesn't exist, Algolia adds
   * a new one. If you use an existing synonym `objectID`, the existing synonym is
   * replaced with the new one. To add multiple synonyms in a single API request, use the
   * [`batch` operation](#tag/Synonyms/operation/saveSynonyms).
   *
   * @param indexName Index on which to perform the request. (required)
   * @param objectID Unique identifier of a synonym object. (required)
   * @param synonymHit (required)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture saveSynonymAsync(
    String indexName,
    String objectID,
    SynonymHit synonymHit,
    RequestOptions requestOptions
  ) throws AlgoliaRuntimeException {
    return this.saveSynonymAsync(indexName, objectID, synonymHit, null, requestOptions);
  }

  /**
   * (asynchronously) Add a
   * [synonym](https://www.algolia.com/doc/guides/managing-results/optimize-search-results/adding-synonyms/#the-different-types-of-synonyms)
   * to an index or replace it. If the synonym `objectID` doesn't exist, Algolia adds
   * a new one. If you use an existing synonym `objectID`, the existing synonym is
   * replaced with the new one. To add multiple synonyms in a single API request, use the
   * [`batch` operation](#tag/Synonyms/operation/saveSynonyms).
   *
   * @param indexName Index on which to perform the request. (required)
   * @param objectID Unique identifier of a synonym object. (required)
   * @param synonymHit (required)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture saveSynonymAsync(String indexName, String objectID, SynonymHit synonymHit)
    throws AlgoliaRuntimeException {
    return this.saveSynonymAsync(indexName, objectID, synonymHit, null, null);
  }

  /**
   * Create or update multiple synonyms.
   *
   * @param indexName Index on which to perform the request. (required)
   * @param synonymHit (required)
   * @param forwardToReplicas Indicates whether changed index settings are forwarded to the replica
   *     indices. (optional)
   * @param replaceExistingSynonyms Indicates whether to replace all synonyms in the index with the
   *     ones sent with this request. (optional)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public UpdatedAtResponse saveSynonyms(
    String indexName,
    List synonymHit,
    Boolean forwardToReplicas,
    Boolean replaceExistingSynonyms,
    RequestOptions requestOptions
  ) throws AlgoliaRuntimeException {
    return LaunderThrowable.await(saveSynonymsAsync(indexName, synonymHit, forwardToReplicas, replaceExistingSynonyms, requestOptions));
  }

  /**
   * Create or update multiple synonyms.
   *
   * @param indexName Index on which to perform the request. (required)
   * @param synonymHit (required)
   * @param forwardToReplicas Indicates whether changed index settings are forwarded to the replica
   *     indices. (optional)
   * @param replaceExistingSynonyms Indicates whether to replace all synonyms in the index with the
   *     ones sent with this request. (optional)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public UpdatedAtResponse saveSynonyms(
    String indexName,
    List synonymHit,
    Boolean forwardToReplicas,
    Boolean replaceExistingSynonyms
  ) throws AlgoliaRuntimeException {
    return this.saveSynonyms(indexName, synonymHit, forwardToReplicas, replaceExistingSynonyms, null);
  }

  /**
   * Create or update multiple synonyms.
   *
   * @param indexName Index on which to perform the request. (required)
   * @param synonymHit (required)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public UpdatedAtResponse saveSynonyms(String indexName, List synonymHit, RequestOptions requestOptions)
    throws AlgoliaRuntimeException {
    return this.saveSynonyms(indexName, synonymHit, null, null, requestOptions);
  }

  /**
   * Create or update multiple synonyms.
   *
   * @param indexName Index on which to perform the request. (required)
   * @param synonymHit (required)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public UpdatedAtResponse saveSynonyms(String indexName, List synonymHit) throws AlgoliaRuntimeException {
    return this.saveSynonyms(indexName, synonymHit, null, null, null);
  }

  /**
   * (asynchronously) Create or update multiple synonyms.
   *
   * @param indexName Index on which to perform the request. (required)
   * @param synonymHit (required)
   * @param forwardToReplicas Indicates whether changed index settings are forwarded to the replica
   *     indices. (optional)
   * @param replaceExistingSynonyms Indicates whether to replace all synonyms in the index with the
   *     ones sent with this request. (optional)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture saveSynonymsAsync(
    String indexName,
    List synonymHit,
    Boolean forwardToReplicas,
    Boolean replaceExistingSynonyms,
    RequestOptions requestOptions
  ) throws AlgoliaRuntimeException {
    if (indexName == null) {
      throw new AlgoliaRuntimeException("Parameter `indexName` is required when calling `saveSynonyms`.");
    }

    if (synonymHit == null) {
      throw new AlgoliaRuntimeException("Parameter `synonymHit` is required when calling `saveSynonyms`.");
    }

    HttpRequest request = HttpRequest
      .builder()
      .setPath("/1/indexes/{indexName}/synonyms/batch", indexName)
      .setMethod("POST")
      .setBody(synonymHit)
      .addQueryParameter("forwardToReplicas", forwardToReplicas)
      .addQueryParameter("replaceExistingSynonyms", replaceExistingSynonyms)
      .build();
    return executeAsync(request, requestOptions, new TypeReference() {});
  }

  /**
   * (asynchronously) Create or update multiple synonyms.
   *
   * @param indexName Index on which to perform the request. (required)
   * @param synonymHit (required)
   * @param forwardToReplicas Indicates whether changed index settings are forwarded to the replica
   *     indices. (optional)
   * @param replaceExistingSynonyms Indicates whether to replace all synonyms in the index with the
   *     ones sent with this request. (optional)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture saveSynonymsAsync(
    String indexName,
    List synonymHit,
    Boolean forwardToReplicas,
    Boolean replaceExistingSynonyms
  ) throws AlgoliaRuntimeException {
    return this.saveSynonymsAsync(indexName, synonymHit, forwardToReplicas, replaceExistingSynonyms, null);
  }

  /**
   * (asynchronously) Create or update multiple synonyms.
   *
   * @param indexName Index on which to perform the request. (required)
   * @param synonymHit (required)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture saveSynonymsAsync(
    String indexName,
    List synonymHit,
    RequestOptions requestOptions
  ) throws AlgoliaRuntimeException {
    return this.saveSynonymsAsync(indexName, synonymHit, null, null, requestOptions);
  }

  /**
   * (asynchronously) Create or update multiple synonyms.
   *
   * @param indexName Index on which to perform the request. (required)
   * @param synonymHit (required)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture saveSynonymsAsync(String indexName, List synonymHit)
    throws AlgoliaRuntimeException {
    return this.saveSynonymsAsync(indexName, synonymHit, null, null, null);
  }

  /**
   * Send multiple search queries to one or more indices.
   *
   * @param searchMethodParams Query requests and strategies. Results will be received in the same
   *     order as the queries. (required)
   * @param innerType The class held by the index, could be your custom class or {@link Object}.
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public  SearchResponses search(SearchMethodParams searchMethodParams, Class innerType, RequestOptions requestOptions)
    throws AlgoliaRuntimeException {
    return LaunderThrowable.await(searchAsync(searchMethodParams, innerType, requestOptions));
  }

  /**
   * Send multiple search queries to one or more indices.
   *
   * @param searchMethodParams Query requests and strategies. Results will be received in the same
   *     order as the queries. (required)
   * @param innerType The class held by the index, could be your custom class or {@link Object}.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public  SearchResponses search(SearchMethodParams searchMethodParams, Class innerType) throws AlgoliaRuntimeException {
    return this.search(searchMethodParams, innerType, null);
  }

  /**
   * (asynchronously) Send multiple search queries to one or more indices.
   *
   * @param searchMethodParams Query requests and strategies. Results will be received in the same
   *     order as the queries. (required)
   * @param innerType The class held by the index, could be your custom class or {@link Object}.
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public  CompletableFuture> searchAsync(
    SearchMethodParams searchMethodParams,
    Class innerType,
    RequestOptions requestOptions
  ) throws AlgoliaRuntimeException {
    if (searchMethodParams == null) {
      throw new AlgoliaRuntimeException("Parameter `searchMethodParams` is required when calling `search`.");
    }

    HttpRequest request = HttpRequest
      .builder()
      .setPath("/1/indexes/*/queries")
      .setMethod("POST")
      .setBody(searchMethodParams)
      .setRead(true)
      .build();
    return executeAsync(request, requestOptions, SearchResponses.class, innerType);
  }

  /**
   * (asynchronously) Send multiple search queries to one or more indices.
   *
   * @param searchMethodParams Query requests and strategies. Results will be received in the same
   *     order as the queries. (required)
   * @param innerType The class held by the index, could be your custom class or {@link Object}.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public  CompletableFuture> searchAsync(SearchMethodParams searchMethodParams, Class innerType)
    throws AlgoliaRuntimeException {
    return this.searchAsync(searchMethodParams, innerType, null);
  }

  /**
   * Search for standard and
   * [custom](https://www.algolia.com/doc/guides/managing-results/optimize-search-results/handling-natural-languages-nlp/how-to/customize-stop-words/)
   * entries in the [stop
   * words](https://www.algolia.com/doc/guides/managing-results/optimize-search-results/handling-natural-languages-nlp/how-to/customize-stop-words/),
   * [plurals](https://www.algolia.com/doc/guides/managing-results/optimize-search-results/handling-natural-languages-nlp/how-to/customize-plurals-and-other-declensions/),
   * or [segmentation
   * (compounds)](https://www.algolia.com/doc/guides/managing-results/optimize-search-results/handling-natural-languages-nlp/how-to/customize-segmentation/)
   * dictionaries.
   *
   * @param dictionaryName Dictionary to search in. (required)
   * @param searchDictionaryEntriesParams (required)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public UpdatedAtResponse searchDictionaryEntries(
    DictionaryType dictionaryName,
    SearchDictionaryEntriesParams searchDictionaryEntriesParams,
    RequestOptions requestOptions
  ) throws AlgoliaRuntimeException {
    return LaunderThrowable.await(searchDictionaryEntriesAsync(dictionaryName, searchDictionaryEntriesParams, requestOptions));
  }

  /**
   * Search for standard and
   * [custom](https://www.algolia.com/doc/guides/managing-results/optimize-search-results/handling-natural-languages-nlp/how-to/customize-stop-words/)
   * entries in the [stop
   * words](https://www.algolia.com/doc/guides/managing-results/optimize-search-results/handling-natural-languages-nlp/how-to/customize-stop-words/),
   * [plurals](https://www.algolia.com/doc/guides/managing-results/optimize-search-results/handling-natural-languages-nlp/how-to/customize-plurals-and-other-declensions/),
   * or [segmentation
   * (compounds)](https://www.algolia.com/doc/guides/managing-results/optimize-search-results/handling-natural-languages-nlp/how-to/customize-segmentation/)
   * dictionaries.
   *
   * @param dictionaryName Dictionary to search in. (required)
   * @param searchDictionaryEntriesParams (required)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public UpdatedAtResponse searchDictionaryEntries(
    DictionaryType dictionaryName,
    SearchDictionaryEntriesParams searchDictionaryEntriesParams
  ) throws AlgoliaRuntimeException {
    return this.searchDictionaryEntries(dictionaryName, searchDictionaryEntriesParams, null);
  }

  /**
   * (asynchronously) Search for standard and
   * [custom](https://www.algolia.com/doc/guides/managing-results/optimize-search-results/handling-natural-languages-nlp/how-to/customize-stop-words/)
   * entries in the [stop
   * words](https://www.algolia.com/doc/guides/managing-results/optimize-search-results/handling-natural-languages-nlp/how-to/customize-stop-words/),
   * [plurals](https://www.algolia.com/doc/guides/managing-results/optimize-search-results/handling-natural-languages-nlp/how-to/customize-plurals-and-other-declensions/),
   * or [segmentation
   * (compounds)](https://www.algolia.com/doc/guides/managing-results/optimize-search-results/handling-natural-languages-nlp/how-to/customize-segmentation/)
   * dictionaries.
   *
   * @param dictionaryName Dictionary to search in. (required)
   * @param searchDictionaryEntriesParams (required)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture searchDictionaryEntriesAsync(
    DictionaryType dictionaryName,
    SearchDictionaryEntriesParams searchDictionaryEntriesParams,
    RequestOptions requestOptions
  ) throws AlgoliaRuntimeException {
    if (dictionaryName == null) {
      throw new AlgoliaRuntimeException("Parameter `dictionaryName` is required when calling `searchDictionaryEntries`.");
    }

    if (searchDictionaryEntriesParams == null) {
      throw new AlgoliaRuntimeException(
        "Parameter `searchDictionaryEntriesParams` is required when calling" + " `searchDictionaryEntries`."
      );
    }

    HttpRequest request = HttpRequest
      .builder()
      .setPath("/1/dictionaries/{dictionaryName}/search", dictionaryName)
      .setMethod("POST")
      .setBody(searchDictionaryEntriesParams)
      .setRead(true)
      .build();
    return executeAsync(request, requestOptions, new TypeReference() {});
  }

  /**
   * (asynchronously) Search for standard and
   * [custom](https://www.algolia.com/doc/guides/managing-results/optimize-search-results/handling-natural-languages-nlp/how-to/customize-stop-words/)
   * entries in the [stop
   * words](https://www.algolia.com/doc/guides/managing-results/optimize-search-results/handling-natural-languages-nlp/how-to/customize-stop-words/),
   * [plurals](https://www.algolia.com/doc/guides/managing-results/optimize-search-results/handling-natural-languages-nlp/how-to/customize-plurals-and-other-declensions/),
   * or [segmentation
   * (compounds)](https://www.algolia.com/doc/guides/managing-results/optimize-search-results/handling-natural-languages-nlp/how-to/customize-segmentation/)
   * dictionaries.
   *
   * @param dictionaryName Dictionary to search in. (required)
   * @param searchDictionaryEntriesParams (required)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture searchDictionaryEntriesAsync(
    DictionaryType dictionaryName,
    SearchDictionaryEntriesParams searchDictionaryEntriesParams
  ) throws AlgoliaRuntimeException {
    return this.searchDictionaryEntriesAsync(dictionaryName, searchDictionaryEntriesParams, null);
  }

  /**
   * [Search for a facet's
   * values](https://www.algolia.com/doc/guides/managing-results/refine-results/faceting/#search-for-facet-values),
   * optionally restricting the returned values to those contained in records matching other search
   * criteria. > **Note**: Pagination isn't supported (`page` and `hitsPerPage` are ignored). By
   * default, the engine returns a maximum of 10 values but you can adjust this with `maxFacetHits`.
   *
   * @param indexName Index on which to perform the request. (required)
   * @param facetName Facet name. (required)
   * @param searchForFacetValuesRequest (optional)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public SearchForFacetValuesResponse searchForFacetValues(
    String indexName,
    String facetName,
    SearchForFacetValuesRequest searchForFacetValuesRequest,
    RequestOptions requestOptions
  ) throws AlgoliaRuntimeException {
    return LaunderThrowable.await(searchForFacetValuesAsync(indexName, facetName, searchForFacetValuesRequest, requestOptions));
  }

  /**
   * [Search for a facet's
   * values](https://www.algolia.com/doc/guides/managing-results/refine-results/faceting/#search-for-facet-values),
   * optionally restricting the returned values to those contained in records matching other search
   * criteria. > **Note**: Pagination isn't supported (`page` and `hitsPerPage` are ignored). By
   * default, the engine returns a maximum of 10 values but you can adjust this with `maxFacetHits`.
   *
   * @param indexName Index on which to perform the request. (required)
   * @param facetName Facet name. (required)
   * @param searchForFacetValuesRequest (optional)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public SearchForFacetValuesResponse searchForFacetValues(
    String indexName,
    String facetName,
    SearchForFacetValuesRequest searchForFacetValuesRequest
  ) throws AlgoliaRuntimeException {
    return this.searchForFacetValues(indexName, facetName, searchForFacetValuesRequest, null);
  }

  /**
   * [Search for a facet's
   * values](https://www.algolia.com/doc/guides/managing-results/refine-results/faceting/#search-for-facet-values),
   * optionally restricting the returned values to those contained in records matching other search
   * criteria. > **Note**: Pagination isn't supported (`page` and `hitsPerPage` are ignored). By
   * default, the engine returns a maximum of 10 values but you can adjust this with `maxFacetHits`.
   *
   * @param indexName Index on which to perform the request. (required)
   * @param facetName Facet name. (required)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public SearchForFacetValuesResponse searchForFacetValues(String indexName, String facetName, RequestOptions requestOptions)
    throws AlgoliaRuntimeException {
    return this.searchForFacetValues(indexName, facetName, null, requestOptions);
  }

  /**
   * [Search for a facet's
   * values](https://www.algolia.com/doc/guides/managing-results/refine-results/faceting/#search-for-facet-values),
   * optionally restricting the returned values to those contained in records matching other search
   * criteria. > **Note**: Pagination isn't supported (`page` and `hitsPerPage` are ignored). By
   * default, the engine returns a maximum of 10 values but you can adjust this with `maxFacetHits`.
   *
   * @param indexName Index on which to perform the request. (required)
   * @param facetName Facet name. (required)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public SearchForFacetValuesResponse searchForFacetValues(String indexName, String facetName) throws AlgoliaRuntimeException {
    return this.searchForFacetValues(indexName, facetName, null, null);
  }

  /**
   * (asynchronously) [Search for a facet's
   * values](https://www.algolia.com/doc/guides/managing-results/refine-results/faceting/#search-for-facet-values),
   * optionally restricting the returned values to those contained in records matching other search
   * criteria. > **Note**: Pagination isn't supported (`page` and
   * `hitsPerPage` are ignored). By default, the engine returns a maximum of 10 values but
   * you can adjust this with `maxFacetHits`.
   *
   * @param indexName Index on which to perform the request. (required)
   * @param facetName Facet name. (required)
   * @param searchForFacetValuesRequest (optional)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture searchForFacetValuesAsync(
    String indexName,
    String facetName,
    SearchForFacetValuesRequest searchForFacetValuesRequest,
    RequestOptions requestOptions
  ) throws AlgoliaRuntimeException {
    if (indexName == null) {
      throw new AlgoliaRuntimeException("Parameter `indexName` is required when calling `searchForFacetValues`.");
    }

    if (facetName == null) {
      throw new AlgoliaRuntimeException("Parameter `facetName` is required when calling `searchForFacetValues`.");
    }

    HttpRequest request = HttpRequest
      .builder()
      .setPath("/1/indexes/{indexName}/facets/{facetName}/query", indexName, facetName)
      .setMethod("POST")
      .setBody(searchForFacetValuesRequest)
      .setRead(true)
      .build();
    return executeAsync(request, requestOptions, new TypeReference() {});
  }

  /**
   * (asynchronously) [Search for a facet's
   * values](https://www.algolia.com/doc/guides/managing-results/refine-results/faceting/#search-for-facet-values),
   * optionally restricting the returned values to those contained in records matching other search
   * criteria. > **Note**: Pagination isn't supported (`page` and
   * `hitsPerPage` are ignored). By default, the engine returns a maximum of 10 values but
   * you can adjust this with `maxFacetHits`.
   *
   * @param indexName Index on which to perform the request. (required)
   * @param facetName Facet name. (required)
   * @param searchForFacetValuesRequest (optional)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture searchForFacetValuesAsync(
    String indexName,
    String facetName,
    SearchForFacetValuesRequest searchForFacetValuesRequest
  ) throws AlgoliaRuntimeException {
    return this.searchForFacetValuesAsync(indexName, facetName, searchForFacetValuesRequest, null);
  }

  /**
   * (asynchronously) [Search for a facet's
   * values](https://www.algolia.com/doc/guides/managing-results/refine-results/faceting/#search-for-facet-values),
   * optionally restricting the returned values to those contained in records matching other search
   * criteria. > **Note**: Pagination isn't supported (`page` and
   * `hitsPerPage` are ignored). By default, the engine returns a maximum of 10 values but
   * you can adjust this with `maxFacetHits`.
   *
   * @param indexName Index on which to perform the request. (required)
   * @param facetName Facet name. (required)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture searchForFacetValuesAsync(
    String indexName,
    String facetName,
    RequestOptions requestOptions
  ) throws AlgoliaRuntimeException {
    return this.searchForFacetValuesAsync(indexName, facetName, null, requestOptions);
  }

  /**
   * (asynchronously) [Search for a facet's
   * values](https://www.algolia.com/doc/guides/managing-results/refine-results/faceting/#search-for-facet-values),
   * optionally restricting the returned values to those contained in records matching other search
   * criteria. > **Note**: Pagination isn't supported (`page` and
   * `hitsPerPage` are ignored). By default, the engine returns a maximum of 10 values but
   * you can adjust this with `maxFacetHits`.
   *
   * @param indexName Index on which to perform the request. (required)
   * @param facetName Facet name. (required)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture searchForFacetValuesAsync(String indexName, String facetName)
    throws AlgoliaRuntimeException {
    return this.searchForFacetValuesAsync(indexName, facetName, null, null);
  }

  /**
   * Search for rules in your index. You can control the search with parameters. To list all rules,
   * send an empty request body.
   *
   * @param indexName Index on which to perform the request. (required)
   * @param searchRulesParams (optional)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public SearchRulesResponse searchRules(String indexName, SearchRulesParams searchRulesParams, RequestOptions requestOptions)
    throws AlgoliaRuntimeException {
    return LaunderThrowable.await(searchRulesAsync(indexName, searchRulesParams, requestOptions));
  }

  /**
   * Search for rules in your index. You can control the search with parameters. To list all rules,
   * send an empty request body.
   *
   * @param indexName Index on which to perform the request. (required)
   * @param searchRulesParams (optional)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public SearchRulesResponse searchRules(String indexName, SearchRulesParams searchRulesParams) throws AlgoliaRuntimeException {
    return this.searchRules(indexName, searchRulesParams, null);
  }

  /**
   * Search for rules in your index. You can control the search with parameters. To list all rules,
   * send an empty request body.
   *
   * @param indexName Index on which to perform the request. (required)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public SearchRulesResponse searchRules(String indexName, RequestOptions requestOptions) throws AlgoliaRuntimeException {
    return this.searchRules(indexName, null, requestOptions);
  }

  /**
   * Search for rules in your index. You can control the search with parameters. To list all rules,
   * send an empty request body.
   *
   * @param indexName Index on which to perform the request. (required)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public SearchRulesResponse searchRules(String indexName) throws AlgoliaRuntimeException {
    return this.searchRules(indexName, null, null);
  }

  /**
   * (asynchronously) Search for rules in your index. You can control the search with parameters. To
   * list all rules, send an empty request body.
   *
   * @param indexName Index on which to perform the request. (required)
   * @param searchRulesParams (optional)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture searchRulesAsync(
    String indexName,
    SearchRulesParams searchRulesParams,
    RequestOptions requestOptions
  ) throws AlgoliaRuntimeException {
    if (indexName == null) {
      throw new AlgoliaRuntimeException("Parameter `indexName` is required when calling `searchRules`.");
    }

    HttpRequest request = HttpRequest
      .builder()
      .setPath("/1/indexes/{indexName}/rules/search", indexName)
      .setMethod("POST")
      .setBody(searchRulesParams)
      .setRead(true)
      .build();
    return executeAsync(request, requestOptions, new TypeReference() {});
  }

  /**
   * (asynchronously) Search for rules in your index. You can control the search with parameters. To
   * list all rules, send an empty request body.
   *
   * @param indexName Index on which to perform the request. (required)
   * @param searchRulesParams (optional)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture searchRulesAsync(String indexName, SearchRulesParams searchRulesParams)
    throws AlgoliaRuntimeException {
    return this.searchRulesAsync(indexName, searchRulesParams, null);
  }

  /**
   * (asynchronously) Search for rules in your index. You can control the search with parameters. To
   * list all rules, send an empty request body.
   *
   * @param indexName Index on which to perform the request. (required)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture searchRulesAsync(String indexName, RequestOptions requestOptions)
    throws AlgoliaRuntimeException {
    return this.searchRulesAsync(indexName, null, requestOptions);
  }

  /**
   * (asynchronously) Search for rules in your index. You can control the search with parameters. To
   * list all rules, send an empty request body.
   *
   * @param indexName Index on which to perform the request. (required)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture searchRulesAsync(String indexName) throws AlgoliaRuntimeException {
    return this.searchRulesAsync(indexName, null, null);
  }

  /**
   * Return records that match the query.
   *
   * @param indexName Index on which to perform the request. (required)
   * @param searchParams (optional)
   * @param innerType The class held by the index, could be your custom class or {@link Object}.
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public  SearchResponse searchSingleIndex(
    String indexName,
    SearchParams searchParams,
    Class innerType,
    RequestOptions requestOptions
  ) throws AlgoliaRuntimeException {
    return LaunderThrowable.await(searchSingleIndexAsync(indexName, searchParams, innerType, requestOptions));
  }

  /**
   * Return records that match the query.
   *
   * @param indexName Index on which to perform the request. (required)
   * @param searchParams (optional)
   * @param innerType The class held by the index, could be your custom class or {@link Object}.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public  SearchResponse searchSingleIndex(String indexName, SearchParams searchParams, Class innerType)
    throws AlgoliaRuntimeException {
    return this.searchSingleIndex(indexName, searchParams, innerType, null);
  }

  /**
   * Return records that match the query.
   *
   * @param indexName Index on which to perform the request. (required)
   * @param innerType The class held by the index, could be your custom class or {@link Object}.
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public  SearchResponse searchSingleIndex(String indexName, Class innerType, RequestOptions requestOptions)
    throws AlgoliaRuntimeException {
    return this.searchSingleIndex(indexName, null, innerType, requestOptions);
  }

  /**
   * Return records that match the query.
   *
   * @param indexName Index on which to perform the request. (required)
   * @param innerType The class held by the index, could be your custom class or {@link Object}.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public  SearchResponse searchSingleIndex(String indexName, Class innerType) throws AlgoliaRuntimeException {
    return this.searchSingleIndex(indexName, null, innerType, null);
  }

  /**
   * (asynchronously) Return records that match the query.
   *
   * @param indexName Index on which to perform the request. (required)
   * @param searchParams (optional)
   * @param innerType The class held by the index, could be your custom class or {@link Object}.
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public  CompletableFuture> searchSingleIndexAsync(
    String indexName,
    SearchParams searchParams,
    Class innerType,
    RequestOptions requestOptions
  ) throws AlgoliaRuntimeException {
    if (indexName == null) {
      throw new AlgoliaRuntimeException("Parameter `indexName` is required when calling `searchSingleIndex`.");
    }

    HttpRequest request = HttpRequest
      .builder()
      .setPath("/1/indexes/{indexName}/query", indexName)
      .setMethod("POST")
      .setBody(searchParams)
      .setRead(true)
      .build();
    return executeAsync(request, requestOptions, SearchResponse.class, innerType);
  }

  /**
   * (asynchronously) Return records that match the query.
   *
   * @param indexName Index on which to perform the request. (required)
   * @param searchParams (optional)
   * @param innerType The class held by the index, could be your custom class or {@link Object}.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public  CompletableFuture> searchSingleIndexAsync(String indexName, SearchParams searchParams, Class innerType)
    throws AlgoliaRuntimeException {
    return this.searchSingleIndexAsync(indexName, searchParams, innerType, null);
  }

  /**
   * (asynchronously) Return records that match the query.
   *
   * @param indexName Index on which to perform the request. (required)
   * @param innerType The class held by the index, could be your custom class or {@link Object}.
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public  CompletableFuture> searchSingleIndexAsync(
    String indexName,
    Class innerType,
    RequestOptions requestOptions
  ) throws AlgoliaRuntimeException {
    return this.searchSingleIndexAsync(indexName, null, innerType, requestOptions);
  }

  /**
   * (asynchronously) Return records that match the query.
   *
   * @param indexName Index on which to perform the request. (required)
   * @param innerType The class held by the index, could be your custom class or {@link Object}.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public  CompletableFuture> searchSingleIndexAsync(String indexName, Class innerType)
    throws AlgoliaRuntimeException {
    return this.searchSingleIndexAsync(indexName, null, innerType, null);
  }

  /**
   * Search for synonyms in your index. You can control and filter the search with parameters. To
   * get all synonyms, send an empty request body.
   *
   * @param indexName Index on which to perform the request. (required)
   * @param type Search for specific [types of
   *     synonyms](https://www.algolia.com/doc/guides/managing-results/optimize-search-results/adding-synonyms/#the-different-types-of-synonyms).
   *     (optional)
   * @param page Returns the requested page number (the first page is 0). Page size is set by
   *     `hitsPerPage`. When null, there's no pagination. (optional, default to 0)
   * @param hitsPerPage Maximum number of hits per page. (optional, default to 100)
   * @param searchSynonymsParams Body of the `searchSynonyms` operation. (optional)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public SearchSynonymsResponse searchSynonyms(
    String indexName,
    SynonymType type,
    Integer page,
    Integer hitsPerPage,
    SearchSynonymsParams searchSynonymsParams,
    RequestOptions requestOptions
  ) throws AlgoliaRuntimeException {
    return LaunderThrowable.await(searchSynonymsAsync(indexName, type, page, hitsPerPage, searchSynonymsParams, requestOptions));
  }

  /**
   * Search for synonyms in your index. You can control and filter the search with parameters. To
   * get all synonyms, send an empty request body.
   *
   * @param indexName Index on which to perform the request. (required)
   * @param type Search for specific [types of
   *     synonyms](https://www.algolia.com/doc/guides/managing-results/optimize-search-results/adding-synonyms/#the-different-types-of-synonyms).
   *     (optional)
   * @param page Returns the requested page number (the first page is 0). Page size is set by
   *     `hitsPerPage`. When null, there's no pagination. (optional, default to 0)
   * @param hitsPerPage Maximum number of hits per page. (optional, default to 100)
   * @param searchSynonymsParams Body of the `searchSynonyms` operation. (optional)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public SearchSynonymsResponse searchSynonyms(
    String indexName,
    SynonymType type,
    Integer page,
    Integer hitsPerPage,
    SearchSynonymsParams searchSynonymsParams
  ) throws AlgoliaRuntimeException {
    return this.searchSynonyms(indexName, type, page, hitsPerPage, searchSynonymsParams, null);
  }

  /**
   * Search for synonyms in your index. You can control and filter the search with parameters. To
   * get all synonyms, send an empty request body.
   *
   * @param indexName Index on which to perform the request. (required)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public SearchSynonymsResponse searchSynonyms(String indexName, RequestOptions requestOptions) throws AlgoliaRuntimeException {
    return this.searchSynonyms(indexName, null, null, null, null, requestOptions);
  }

  /**
   * Search for synonyms in your index. You can control and filter the search with parameters. To
   * get all synonyms, send an empty request body.
   *
   * @param indexName Index on which to perform the request. (required)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public SearchSynonymsResponse searchSynonyms(String indexName) throws AlgoliaRuntimeException {
    return this.searchSynonyms(indexName, null, null, null, null, null);
  }

  /**
   * (asynchronously) Search for synonyms in your index. You can control and filter the search with
   * parameters. To get all synonyms, send an empty request body.
   *
   * @param indexName Index on which to perform the request. (required)
   * @param type Search for specific [types of
   *     synonyms](https://www.algolia.com/doc/guides/managing-results/optimize-search-results/adding-synonyms/#the-different-types-of-synonyms).
   *     (optional)
   * @param page Returns the requested page number (the first page is 0). Page size is set by
   *     `hitsPerPage`. When null, there's no pagination. (optional, default to 0)
   * @param hitsPerPage Maximum number of hits per page. (optional, default to 100)
   * @param searchSynonymsParams Body of the `searchSynonyms` operation. (optional)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture searchSynonymsAsync(
    String indexName,
    SynonymType type,
    Integer page,
    Integer hitsPerPage,
    SearchSynonymsParams searchSynonymsParams,
    RequestOptions requestOptions
  ) throws AlgoliaRuntimeException {
    if (indexName == null) {
      throw new AlgoliaRuntimeException("Parameter `indexName` is required when calling `searchSynonyms`.");
    }

    HttpRequest request = HttpRequest
      .builder()
      .setPath("/1/indexes/{indexName}/synonyms/search", indexName)
      .setMethod("POST")
      .setBody(searchSynonymsParams)
      .setRead(true)
      .addQueryParameter("type", type)
      .addQueryParameter("page", page)
      .addQueryParameter("hitsPerPage", hitsPerPage)
      .build();
    return executeAsync(request, requestOptions, new TypeReference() {});
  }

  /**
   * (asynchronously) Search for synonyms in your index. You can control and filter the search with
   * parameters. To get all synonyms, send an empty request body.
   *
   * @param indexName Index on which to perform the request. (required)
   * @param type Search for specific [types of
   *     synonyms](https://www.algolia.com/doc/guides/managing-results/optimize-search-results/adding-synonyms/#the-different-types-of-synonyms).
   *     (optional)
   * @param page Returns the requested page number (the first page is 0). Page size is set by
   *     `hitsPerPage`. When null, there's no pagination. (optional, default to 0)
   * @param hitsPerPage Maximum number of hits per page. (optional, default to 100)
   * @param searchSynonymsParams Body of the `searchSynonyms` operation. (optional)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture searchSynonymsAsync(
    String indexName,
    SynonymType type,
    Integer page,
    Integer hitsPerPage,
    SearchSynonymsParams searchSynonymsParams
  ) throws AlgoliaRuntimeException {
    return this.searchSynonymsAsync(indexName, type, page, hitsPerPage, searchSynonymsParams, null);
  }

  /**
   * (asynchronously) Search for synonyms in your index. You can control and filter the search with
   * parameters. To get all synonyms, send an empty request body.
   *
   * @param indexName Index on which to perform the request. (required)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture searchSynonymsAsync(String indexName, RequestOptions requestOptions)
    throws AlgoliaRuntimeException {
    return this.searchSynonymsAsync(indexName, null, null, null, null, requestOptions);
  }

  /**
   * (asynchronously) Search for synonyms in your index. You can control and filter the search with
   * parameters. To get all synonyms, send an empty request body.
   *
   * @param indexName Index on which to perform the request. (required)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture searchSynonymsAsync(String indexName) throws AlgoliaRuntimeException {
    return this.searchSynonymsAsync(indexName, null, null, null, null, null);
  }

  /**
   * Since it can take up to a few seconds to get the data from the different clusters, the response
   * isn't real-time. To ensure rapid updates, the user IDs index isn't built at the same time as
   * the mapping. Instead, it's built every 12 hours, at the same time as the update of user ID
   * usage. For example, if you add or move a user ID, the search will show an old value until the
   * next time the mapping is rebuilt (every 12 hours).
   *
   * @param searchUserIdsParams (required)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public SearchUserIdsResponse searchUserIds(SearchUserIdsParams searchUserIdsParams, RequestOptions requestOptions)
    throws AlgoliaRuntimeException {
    return LaunderThrowable.await(searchUserIdsAsync(searchUserIdsParams, requestOptions));
  }

  /**
   * Since it can take up to a few seconds to get the data from the different clusters, the response
   * isn't real-time. To ensure rapid updates, the user IDs index isn't built at the same time as
   * the mapping. Instead, it's built every 12 hours, at the same time as the update of user ID
   * usage. For example, if you add or move a user ID, the search will show an old value until the
   * next time the mapping is rebuilt (every 12 hours).
   *
   * @param searchUserIdsParams (required)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public SearchUserIdsResponse searchUserIds(SearchUserIdsParams searchUserIdsParams) throws AlgoliaRuntimeException {
    return this.searchUserIds(searchUserIdsParams, null);
  }

  /**
   * (asynchronously) Since it can take up to a few seconds to get the data from the different
   * clusters, the response isn't real-time. To ensure rapid updates, the user IDs index
   * isn't built at the same time as the mapping. Instead, it's built every 12 hours, at the
   * same time as the update of user ID usage. For example, if you add or move a user ID, the search
   * will show an old value until the next time the mapping is rebuilt (every 12 hours).
   *
   * @param searchUserIdsParams (required)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture searchUserIdsAsync(
    SearchUserIdsParams searchUserIdsParams,
    RequestOptions requestOptions
  ) throws AlgoliaRuntimeException {
    if (searchUserIdsParams == null) {
      throw new AlgoliaRuntimeException("Parameter `searchUserIdsParams` is required when calling `searchUserIds`.");
    }

    HttpRequest request = HttpRequest
      .builder()
      .setPath("/1/clusters/mapping/search")
      .setMethod("POST")
      .setBody(searchUserIdsParams)
      .setRead(true)
      .build();
    return executeAsync(request, requestOptions, new TypeReference() {});
  }

  /**
   * (asynchronously) Since it can take up to a few seconds to get the data from the different
   * clusters, the response isn't real-time. To ensure rapid updates, the user IDs index
   * isn't built at the same time as the mapping. Instead, it's built every 12 hours, at the
   * same time as the update of user ID usage. For example, if you add or move a user ID, the search
   * will show an old value until the next time the mapping is rebuilt (every 12 hours).
   *
   * @param searchUserIdsParams (required)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture searchUserIdsAsync(SearchUserIdsParams searchUserIdsParams)
    throws AlgoliaRuntimeException {
    return this.searchUserIdsAsync(searchUserIdsParams, null);
  }

  /**
   * Set stop word settings for a specific language.
   *
   * @param dictionarySettingsParams (required)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public UpdatedAtResponse setDictionarySettings(DictionarySettingsParams dictionarySettingsParams, RequestOptions requestOptions)
    throws AlgoliaRuntimeException {
    return LaunderThrowable.await(setDictionarySettingsAsync(dictionarySettingsParams, requestOptions));
  }

  /**
   * Set stop word settings for a specific language.
   *
   * @param dictionarySettingsParams (required)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public UpdatedAtResponse setDictionarySettings(DictionarySettingsParams dictionarySettingsParams) throws AlgoliaRuntimeException {
    return this.setDictionarySettings(dictionarySettingsParams, null);
  }

  /**
   * (asynchronously) Set stop word settings for a specific language.
   *
   * @param dictionarySettingsParams (required)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture setDictionarySettingsAsync(
    DictionarySettingsParams dictionarySettingsParams,
    RequestOptions requestOptions
  ) throws AlgoliaRuntimeException {
    if (dictionarySettingsParams == null) {
      throw new AlgoliaRuntimeException("Parameter `dictionarySettingsParams` is required when calling `setDictionarySettings`.");
    }

    HttpRequest request = HttpRequest
      .builder()
      .setPath("/1/dictionaries/*/settings")
      .setMethod("PUT")
      .setBody(dictionarySettingsParams)
      .build();
    return executeAsync(request, requestOptions, new TypeReference() {});
  }

  /**
   * (asynchronously) Set stop word settings for a specific language.
   *
   * @param dictionarySettingsParams (required)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture setDictionarySettingsAsync(DictionarySettingsParams dictionarySettingsParams)
    throws AlgoliaRuntimeException {
    return this.setDictionarySettingsAsync(dictionarySettingsParams, null);
  }

  /**
   * Update the specified [index
   * settings](https://www.algolia.com/doc/api-reference/settings-api-parameters/). Specifying null
   * for a setting resets it to its default value.
   *
   * @param indexName Index on which to perform the request. (required)
   * @param indexSettings (required)
   * @param forwardToReplicas Indicates whether changed index settings are forwarded to the replica
   *     indices. (optional)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public UpdatedAtResponse setSettings(
    String indexName,
    IndexSettings indexSettings,
    Boolean forwardToReplicas,
    RequestOptions requestOptions
  ) throws AlgoliaRuntimeException {
    return LaunderThrowable.await(setSettingsAsync(indexName, indexSettings, forwardToReplicas, requestOptions));
  }

  /**
   * Update the specified [index
   * settings](https://www.algolia.com/doc/api-reference/settings-api-parameters/). Specifying null
   * for a setting resets it to its default value.
   *
   * @param indexName Index on which to perform the request. (required)
   * @param indexSettings (required)
   * @param forwardToReplicas Indicates whether changed index settings are forwarded to the replica
   *     indices. (optional)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public UpdatedAtResponse setSettings(String indexName, IndexSettings indexSettings, Boolean forwardToReplicas)
    throws AlgoliaRuntimeException {
    return this.setSettings(indexName, indexSettings, forwardToReplicas, null);
  }

  /**
   * Update the specified [index
   * settings](https://www.algolia.com/doc/api-reference/settings-api-parameters/). Specifying null
   * for a setting resets it to its default value.
   *
   * @param indexName Index on which to perform the request. (required)
   * @param indexSettings (required)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public UpdatedAtResponse setSettings(String indexName, IndexSettings indexSettings, RequestOptions requestOptions)
    throws AlgoliaRuntimeException {
    return this.setSettings(indexName, indexSettings, null, requestOptions);
  }

  /**
   * Update the specified [index
   * settings](https://www.algolia.com/doc/api-reference/settings-api-parameters/). Specifying null
   * for a setting resets it to its default value.
   *
   * @param indexName Index on which to perform the request. (required)
   * @param indexSettings (required)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public UpdatedAtResponse setSettings(String indexName, IndexSettings indexSettings) throws AlgoliaRuntimeException {
    return this.setSettings(indexName, indexSettings, null, null);
  }

  /**
   * (asynchronously) Update the specified [index
   * settings](https://www.algolia.com/doc/api-reference/settings-api-parameters/). Specifying null
   * for a setting resets it to its default value.
   *
   * @param indexName Index on which to perform the request. (required)
   * @param indexSettings (required)
   * @param forwardToReplicas Indicates whether changed index settings are forwarded to the replica
   *     indices. (optional)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture setSettingsAsync(
    String indexName,
    IndexSettings indexSettings,
    Boolean forwardToReplicas,
    RequestOptions requestOptions
  ) throws AlgoliaRuntimeException {
    if (indexName == null) {
      throw new AlgoliaRuntimeException("Parameter `indexName` is required when calling `setSettings`.");
    }

    if (indexSettings == null) {
      throw new AlgoliaRuntimeException("Parameter `indexSettings` is required when calling `setSettings`.");
    }

    HttpRequest request = HttpRequest
      .builder()
      .setPath("/1/indexes/{indexName}/settings", indexName)
      .setMethod("PUT")
      .setBody(indexSettings)
      .addQueryParameter("forwardToReplicas", forwardToReplicas)
      .build();
    return executeAsync(request, requestOptions, new TypeReference() {});
  }

  /**
   * (asynchronously) Update the specified [index
   * settings](https://www.algolia.com/doc/api-reference/settings-api-parameters/). Specifying null
   * for a setting resets it to its default value.
   *
   * @param indexName Index on which to perform the request. (required)
   * @param indexSettings (required)
   * @param forwardToReplicas Indicates whether changed index settings are forwarded to the replica
   *     indices. (optional)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture setSettingsAsync(String indexName, IndexSettings indexSettings, Boolean forwardToReplicas)
    throws AlgoliaRuntimeException {
    return this.setSettingsAsync(indexName, indexSettings, forwardToReplicas, null);
  }

  /**
   * (asynchronously) Update the specified [index
   * settings](https://www.algolia.com/doc/api-reference/settings-api-parameters/). Specifying null
   * for a setting resets it to its default value.
   *
   * @param indexName Index on which to perform the request. (required)
   * @param indexSettings (required)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture setSettingsAsync(
    String indexName,
    IndexSettings indexSettings,
    RequestOptions requestOptions
  ) throws AlgoliaRuntimeException {
    return this.setSettingsAsync(indexName, indexSettings, null, requestOptions);
  }

  /**
   * (asynchronously) Update the specified [index
   * settings](https://www.algolia.com/doc/api-reference/settings-api-parameters/). Specifying null
   * for a setting resets it to its default value.
   *
   * @param indexName Index on which to perform the request. (required)
   * @param indexSettings (required)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture setSettingsAsync(String indexName, IndexSettings indexSettings)
    throws AlgoliaRuntimeException {
    return this.setSettingsAsync(indexName, indexSettings, null, null);
  }

  /**
   * Replace the permissions of an existing API key. Any unspecified parameter resets that
   * permission to its default value. The request must be authenticated with the admin API key.
   *
   * @param key API key. (required)
   * @param apiKey (required)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public UpdateApiKeyResponse updateApiKey(String key, ApiKey apiKey, RequestOptions requestOptions) throws AlgoliaRuntimeException {
    return LaunderThrowable.await(updateApiKeyAsync(key, apiKey, requestOptions));
  }

  /**
   * Replace the permissions of an existing API key. Any unspecified parameter resets that
   * permission to its default value. The request must be authenticated with the admin API key.
   *
   * @param key API key. (required)
   * @param apiKey (required)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public UpdateApiKeyResponse updateApiKey(String key, ApiKey apiKey) throws AlgoliaRuntimeException {
    return this.updateApiKey(key, apiKey, null);
  }

  /**
   * (asynchronously) Replace the permissions of an existing API key. Any unspecified parameter
   * resets that permission to its default value. The request must be authenticated with the admin
   * API key.
   *
   * @param key API key. (required)
   * @param apiKey (required)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture updateApiKeyAsync(String key, ApiKey apiKey, RequestOptions requestOptions)
    throws AlgoliaRuntimeException {
    if (key == null) {
      throw new AlgoliaRuntimeException("Parameter `key` is required when calling `updateApiKey`.");
    }

    if (apiKey == null) {
      throw new AlgoliaRuntimeException("Parameter `apiKey` is required when calling `updateApiKey`.");
    }

    HttpRequest request = HttpRequest.builder().setPath("/1/keys/{key}", key).setMethod("PUT").setBody(apiKey).build();
    return executeAsync(request, requestOptions, new TypeReference() {});
  }

  /**
   * (asynchronously) Replace the permissions of an existing API key. Any unspecified parameter
   * resets that permission to its default value. The request must be authenticated with the admin
   * API key.
   *
   * @param key API key. (required)
   * @param apiKey (required)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture updateApiKeyAsync(String key, ApiKey apiKey) throws AlgoliaRuntimeException {
    return this.updateApiKeyAsync(key, apiKey, null);
  }

  /**
   * Helper: Wait for a task to complete with `indexName` and `taskID`.
   *
   * @summary Wait for a task to complete.
   * @param indexName The `indexName` where the operation was performed.
   * @param taskID The `taskID` returned in the method response.
   * @param maxRetries The maximum number of retry. 50 by default. (optional)
   * @param timeout The function to decide how long to wait between retries. min(retries * 200,
   *     5000) by default. (optional)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions. (optional)
   */
  public void waitForTask(String indexName, Long taskID, int maxRetries, IntUnaryOperator timeout, RequestOptions requestOptions) {
    TaskUtils.retryUntil(
      () -> {
        return this.getTask(indexName, taskID, requestOptions);
      },
      (GetTaskResponse task) -> {
        return task.getStatus() == TaskStatus.PUBLISHED;
      },
      maxRetries,
      timeout
    );
  }

  /**
   * Helper: Wait for a task to complete with `indexName` and `taskID`.
   *
   * @summary Wait for a task to complete.
   * @param indexName The `indexName` where the operation was performed.
   * @param taskID The `taskID` returned in the method response.
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions. (optional)
   */
  public void waitForTask(String indexName, Long taskID, RequestOptions requestOptions) {
    this.waitForTask(indexName, taskID, TaskUtils.DEFAULT_MAX_RETRIES, TaskUtils.DEFAULT_TIMEOUT, requestOptions);
  }

  /**
   * Helper: Wait for a task to complete with `indexName` and `taskID`.
   *
   * @summary Wait for a task to complete.
   * @param indexName The `indexName` where the operation was performed.
   * @param taskID The `taskID` returned in the method response.
   * @param maxRetries The maximum number of retry. 50 by default. (optional)
   * @param timeout The function to decide how long to wait between retries. min(retries * 200,
   *     5000) by default. (optional)
   */
  public void waitForTask(String indexName, Long taskID, int maxRetries, IntUnaryOperator timeout) {
    this.waitForTask(indexName, taskID, maxRetries, timeout, null);
  }

  /**
   * Helper: Wait for a task to complete with `indexName` and `taskID`.
   *
   * @summary Wait for a task to complete.
   * @param indexName The `indexName` where the operation was performed.
   * @param taskID The `taskID` returned in the method response.
   */
  public void waitForTask(String indexName, Long taskID) {
    this.waitForTask(indexName, taskID, TaskUtils.DEFAULT_MAX_RETRIES, TaskUtils.DEFAULT_TIMEOUT, null);
  }

  /**
   * Helper: Wait for an API key to be added, updated or deleted based on a given `operation`.
   *
   * @summary Wait for an API key task to be processed.
   * @param operation The `operation` that was done on a `key`.
   * @param key The `key` that has been added, deleted or updated.
   * @param apiKey Necessary to know if an `update` operation has been processed, compare fields of
   *     the response with it.
   * @param maxRetries The maximum number of retry. 50 by default. (optional)
   * @param timeout The function to decide how long to wait between retries. min(retries * 200,
   *     5000) by default. (optional)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions. (optional)
   */
  public GetApiKeyResponse waitForApiKey(
    ApiKeyOperation operation,
    String key,
    ApiKey apiKey,
    int maxRetries,
    IntUnaryOperator timeout,
    RequestOptions requestOptions
  ) {
    if (operation == ApiKeyOperation.UPDATE) {
      if (apiKey == null) {
        throw new AlgoliaRuntimeException("`apiKey` is required when waiting for an `update` operation.");
      }

      // when updating an api key, we poll the api until we receive a different key
      return TaskUtils.retryUntil(
        () -> {
          return this.getApiKey(key, requestOptions);
        },
        (GetApiKeyResponse respKey) -> {
          // we need to convert to an ApiKey object to use the `equals` method
          ApiKey sameType = new ApiKey()
            .setAcl(respKey.getAcl())
            .setDescription(respKey.getDescription())
            .setIndexes(respKey.getIndexes())
            .setMaxHitsPerQuery(respKey.getMaxHitsPerQuery())
            .setMaxQueriesPerIPPerHour(respKey.getMaxQueriesPerIPPerHour())
            .setQueryParameters(respKey.getQueryParameters())
            .setReferers(respKey.getReferers())
            .setValidity(respKey.getValidity());

          return apiKey.equals(sameType);
        },
        maxRetries,
        timeout
      );
    }

    // bypass lambda restriction to modify final object
    final GetApiKeyResponse[] addedKey = new GetApiKeyResponse[] { null };

    // check the status of the getApiKey method
    TaskUtils.retryUntil(
      () -> {
        try {
          addedKey[0] = this.getApiKey(key, requestOptions);
          // magic number to signify we found the key
          return -2;
        } catch (AlgoliaApiException e) {
          return e.getStatusCode();
        }
      },
      (Integer status) -> {
        switch (operation) {
          case ADD:
            // stop either when the key is created or when we don't receive 404
            return status == -2 || status != 404;
          case DELETE:
            // stop when the key is not found
            return status == 404;
          default:
            // continue
            return false;
        }
      },
      maxRetries,
      timeout
    );

    return addedKey[0];
  }

  /**
   * Helper: Wait for an API key to be added, updated or deleted based on a given `operation`.
   *
   * @summary Wait for an API key task to be processed.
   * @param operation The `operation` that was done on a `key`. (ADD or DELETE only)
   * @param key The `key` that has been added, deleted or updated.
   * @param maxRetries The maximum number of retry. 50 by default. (optional)
   * @param timeout The function to decide how long to wait between retries. min(retries * 200,
   *     5000) by default. (optional)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions. (optional)
   */
  public GetApiKeyResponse waitForApiKey(
    ApiKeyOperation operation,
    String key,
    int maxRetries,
    IntUnaryOperator timeout,
    RequestOptions requestOptions
  ) {
    return this.waitForApiKey(operation, key, null, maxRetries, timeout, requestOptions);
  }

  /**
   * Helper: Wait for an API key to be added, updated or deleted based on a given `operation`.
   *
   * @summary Wait for an API key task to be processed.
   * @param operation The `operation` that was done on a `key`.
   * @param key The `key` that has been added, deleted or updated.
   * @param apiKey Necessary to know if an `update` operation has been processed, compare fields of
   *     the response with it.
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions. (optional)
   */
  public GetApiKeyResponse waitForApiKey(ApiKeyOperation operation, String key, ApiKey apiKey, RequestOptions requestOptions) {
    return this.waitForApiKey(operation, key, apiKey, TaskUtils.DEFAULT_MAX_RETRIES, TaskUtils.DEFAULT_TIMEOUT, requestOptions);
  }

  /**
   * Helper: Wait for an API key to be added, updated or deleted based on a given `operation`.
   *
   * @summary Wait for an API key task to be processed.
   * @param operation The `operation` that was done on a `key`. (ADD or DELETE only)
   * @param key The `key` that has been added, deleted or updated.
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions. (optional)
   */
  public GetApiKeyResponse waitForApiKey(ApiKeyOperation operation, String key, RequestOptions requestOptions) {
    return this.waitForApiKey(operation, key, null, TaskUtils.DEFAULT_MAX_RETRIES, TaskUtils.DEFAULT_TIMEOUT, requestOptions);
  }

  /**
   * Helper: Wait for an API key to be added, updated or deleted based on a given `operation`.
   *
   * @summary Wait for an API key task to be processed.
   * @param operation The `operation` that was done on a `key`.
   * @param key The `key` that has been added, deleted or updated.
   * @param apiKey Necessary to know if an `update` operation has been processed, compare fields of
   *     the response with it.
   * @param maxRetries The maximum number of retry. 50 by default. (optional)
   * @param timeout The function to decide how long to wait between retries. min(retries * 200,
   *     5000) by default. (optional)
   */
  public GetApiKeyResponse waitForApiKey(ApiKeyOperation operation, String key, ApiKey apiKey, int maxRetries, IntUnaryOperator timeout) {
    return this.waitForApiKey(operation, key, apiKey, maxRetries, timeout, null);
  }

  /**
   * Helper: Wait for an API key to be added, updated or deleted based on a given `operation`.
   *
   * @summary Wait for an API key task to be processed.
   * @param operation The `operation` that was done on a `key`. (ADD or DELETE only)
   * @param key The `key` that has been added, deleted or updated.
   * @param maxRetries The maximum number of retry. 50 by default. (optional)
   * @param timeout The function to decide how long to wait between retries. min(retries * 200,
   *     5000) by default. (optional)
   */
  public GetApiKeyResponse waitForApiKey(ApiKeyOperation operation, String key, int maxRetries, IntUnaryOperator timeout) {
    return this.waitForApiKey(operation, key, null, maxRetries, timeout, null);
  }

  /**
   * Helper: Wait for an API key to be added, updated or deleted based on a given `operation`.
   *
   * @summary Wait for an API key task to be processed.
   * @param operation The `operation` that was done on a `key`.
   * @param key The `key` that has been added, deleted or updated.
   * @param apiKey Necessary to know if an `update` operation has been processed, compare fields of
   *     the response with it.
   */
  public GetApiKeyResponse waitForApiKey(ApiKeyOperation operation, String key, ApiKey apiKey) {
    return this.waitForApiKey(operation, key, apiKey, TaskUtils.DEFAULT_MAX_RETRIES, TaskUtils.DEFAULT_TIMEOUT, null);
  }

  /**
   * Helper: Wait for an API key to be added, updated or deleted based on a given `operation`.
   *
   * @summary Wait for an API key task to be processed.
   * @param operation The `operation` that was done on a `key`. (ADD or DELETE only)
   * @param key The `key` that has been added, deleted or updated.
   */
  public GetApiKeyResponse waitForApiKey(ApiKeyOperation operation, String key) {
    return this.waitForApiKey(operation, key, null, TaskUtils.DEFAULT_MAX_RETRIES, TaskUtils.DEFAULT_TIMEOUT, null);
  }

  /**
   * Helper: Returns an iterator on top of the `browse` method.
   *
   * @summary Returns an iterator on `browse`.
   * @param indexName The index in which to perform the request.
   * @param params The `browse` parameters.
   * @param innerType The class held by the index, could be your custom class or {@link Object}.
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions. (optional)
   */
  public  Iterable browseObjects(String indexName, BrowseParamsObject params, Class innerType, RequestOptions requestOptions) {
    final Holder currentCursor = new Holder<>();

    return AlgoliaIterableHelper.createIterable(
      () -> {
        BrowseResponse response = this.browse(indexName, BrowseParams.of(params), innerType, requestOptions);
        params.setCursor(response.getCursor());
        currentCursor.value = response.getCursor();
        return response.getHits().iterator();
      },
      () -> {
        return currentCursor.value != null;
      }
    );
  }

  /**
   * Helper: Returns an iterator on top of the `browse` method.
   *
   * @summary Returns an iterator on `browse`.
   * @param indexName The index in which to perform the request.
   * @param params The `browse` parameters.
   * @param innerType The class held by the index, could be your custom class or {@link Object}.
   */
  public  Iterable browseObjects(String indexName, BrowseParamsObject params, Class innerType) {
    return browseObjects(indexName, params, innerType, null);
  }

  /**
   * Helper: Returns an iterator on top of the `searchSynonyms` method.
   *
   * @summary Returns an iterator on `searchSynonyms`.
   * @param indexName The index in which to perform the request.
   * @param type The synonym type. (optional)
   * @param params The `searchSynonyms` parameters. (optional)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions. (optional)
   */
  public Iterable browseSynonyms(
    String indexName,
    SynonymType type,
    SearchSynonymsParams params,
    RequestOptions requestOptions
  ) {
    final Holder currentPage = new Holder<>(0);
    final int hitsPerPage = 1000;

    return AlgoliaIterableHelper.createIterable(
      () -> {
        SearchSynonymsResponse response = this.searchSynonyms(indexName, type, currentPage.value, hitsPerPage, params, requestOptions);
        currentPage.value = response.getNbHits() < hitsPerPage ? null : currentPage.value + 1;
        return response.getHits().iterator();
      },
      () -> {
        return currentPage.value != null;
      }
    );
  }

  /**
   * Helper: Returns an iterator on top of the `searchSynonyms` method.
   *
   * @summary Returns an iterator on `searchSynonyms`.
   * @param indexName The index in which to perform the request.
   * @param type The synonym type. (optional)
   * @param params The `searchSynonyms` parameters .(optional)
   */
  public Iterable browseSynonyms(String indexName, SynonymType type, SearchSynonymsParams params) {
    return browseSynonyms(indexName, type, params, null);
  }

  /**
   * Helper: Returns an iterator on top of the `searchSynonyms` method.
   *
   * @summary Returns an iterator on `searchSynonyms`.
   * @param indexName The index in which to perform the request.
   */
  public Iterable browseSynonyms(String indexName) {
    return browseSynonyms(indexName, null, null, null);
  }

  /**
   * Helper: Returns an iterator on top of the `searchRules` method.
   *
   * @summary Returns an iterator on `searchRules`.
   * @param indexName The index in which to perform the request.
   * @param params The `searchRules` parameters. (optional)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions. (optional)
   */
  public Iterable browseRules(String indexName, SearchRulesParams params, RequestOptions requestOptions) {
    final Holder currentPage = new Holder<>(0);
    final int hitsPerPage = 1000;
    params.setHitsPerPage(hitsPerPage);

    return AlgoliaIterableHelper.createIterable(
      () -> {
        SearchRulesResponse response = this.searchRules(indexName, params.setPage(currentPage.value), requestOptions);
        currentPage.value = response.getNbHits() < hitsPerPage ? null : currentPage.value + 1;
        return response.getHits().iterator();
      },
      () -> {
        return currentPage.value != null;
      }
    );
  }

  /**
   * Helper: Returns an iterator on top of the `searchRules` method.
   *
   * @summary Returns an iterator on `searchRules`.
   * @param indexName The index in which to perform the request.
   * @param params The `searchRules` parameters. (optional)
   */
  public Iterable browseRules(String indexName, SearchRulesParams params) {
    return browseRules(indexName, params, null);
  }

  /**
   * Helper: Returns an iterator on top of the `searchRules` method.
   *
   * @summary Returns an iterator on `searchRules`.
   * @param indexName The index in which to perform the request.
   */
  public Iterable browseRules(String indexName) {
    return browseRules(indexName, null, null);
  }

  /**
   * (asynchronously) Send multiple search queries to one or more indices.
   *
   * @param searchMethodParams Query requests and strategies. Results will be received in the same
   *     order as the queries. (required)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture> searchAsync(SearchMethodParams searchMethodParams, RequestOptions requestOptions)
    throws AlgoliaRuntimeException {
    return this.searchAsync(searchMethodParams, Object.class, requestOptions);
  }

  /**
   * (asynchronously) Send multiple search queries to one or more indices.
   *
   * @param searchMethodParams Query requests and strategies. Results will be received in the same
   *     order as the queries. (required)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public CompletableFuture> searchAsync(SearchMethodParams searchMethodParams) throws AlgoliaRuntimeException {
    return this.searchAsync(searchMethodParams, Object.class, null);
  }

  /**
   * Send multiple search queries to one or more indices.
   *
   * @param searchMethodParams Query requests and strategies. Results will be received in the same
   *     order as the queries. (required)
   * @param requestOptions The requestOptions to send along with the query, they will be merged with
   *     the transporter requestOptions.
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public SearchResponses search(SearchMethodParams searchMethodParams, RequestOptions requestOptions)
    throws AlgoliaRuntimeException {
    return this.search(searchMethodParams, Object.class, requestOptions);
  }

  /**
   * Send multiple search queries to one or more indices.
   *
   * @param searchMethodParams Query requests and strategies. Results will be received in the same
   *     order as the queries. (required)
   * @throws AlgoliaRuntimeException If it fails to process the API call
   */
  public SearchResponses search(SearchMethodParams searchMethodParams) throws AlgoliaRuntimeException {
    return this.search(searchMethodParams, Object.class, null);
  }
}