private void IndexExists(string indexName)
 {
     if (LowLevelClient.IndicesExists <string>(indexName).HttpStatusCode == 404)
     {
         throw new IndexNotAvailableException($"{indexName} index doesn't exist");
     }
 }
        /// <summary>
        /// Drops an index using by call the asyncronus Delete Index API.
        /// https://www.elastic.co/guide/en/elasticsearch/reference/5.4/indices-delete-index.html
        /// </summary>
        /// <typeparam name="TPoco">Has to Implement the IElasticPoco interface</typeparam>
        /// <param name="query">DropQuery object</param>
        public async Task ExecuteDropAsync(Drop query)
        {
            var response = await LowLevelClient.IndicesDeleteAsync <string>(query.IndexName);

            if (!response.Success)
            {
                throw response.OriginalException ?? new Exception($"Unsuccessful Elastic Request: {response.DebugInformation}");
            }
        }
        /// <summary>
        /// Executes an asyncronus IndexQuery using the Index API which creates a new document in the index.
        /// https://www.elastic.co/guide/en/elasticsearch/reference/5.4/docs-index_.html
        /// </summary>
        /// <param name="query">IndexQuery object</param>
        public async Task ExecuteIndexAsync(Index query)
        {
            var statement = Generator.Generate(query);
            var response  = !string.IsNullOrEmpty(query.Poco.Id) ?
                            LowLevelClient.IndexAsync <string>(query.IndexName, query.TypeName, query.Poco.Id, statement) :
                            LowLevelClient.IndexAsync <string>(query.IndexName, query.TypeName, statement);

            ProcessIndexResponse(query, await response);
        }
        /// <summary>
        /// Executes an asyncronus SearchQuery using the Search API and returns a list of generic pocos.
        /// https://www.elastic.co/guide/en/elasticsearch/reference/5.4/_the_search_api.html
        /// </summary>
        /// <typeparam name="TPoco">Has to Implement the IElasticPoco interface</typeparam>
        /// <param name="searchQuery">SearchQuery object.</param>
        /// <returns>IEnumerable<TPoco></returns>
        public async Task <IEnumerable <TPoco> > ExecuteSearchAsync <TPoco>(IExecutableSearchQuery <TPoco> searchQuery)
            where TPoco : IElasticPoco
        {
            var query = searchQuery as SearchQuery <TPoco>;

            IndexExists(query.IndexName);

            return(ProcessSeachResponse <TPoco>(await LowLevelClient.SearchAsync <string>(query.IndexName, Generator.Generate(query))));
        }
        /// <summary>
        /// Executes a bulk statement using the asyncronus Bulk API
        /// https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-bulk.html
        /// </summary>
        /// <param name="bulkQuery"></param>
        /// <returns></returns>
        public async Task ExecuteBulkAsync(Bulk bulkQuery)
        {
            var statement = Generator.Generate(bulkQuery);
            var response  = await LowLevelClient.BulkAsync <string>(bulkQuery.IndexName, statement);

            if (!response.Success)
            {
                throw response.OriginalException ?? new Exception($"Unsuccessful Elastic Request: {response.DebugInformation}");
            }
        }
        /// <summary>
        /// Executes an asyncronus UpdateQuery using the Update API and updates a document identified by the Id.
        /// https://www.elastic.co/guide/en/elasticsearch/reference/5.4/docs-update.html
        /// </summary>
        /// <typeparam name="TPoco">Has to Implement the IElasticPoco interface</typeparam>
        /// <param name="query">UpdateQuery object</param>
        public async Task ExecuteUpdateAsync(Update query)
        {
            var statement = Generator.Generate(query);
            var response  = await LowLevelClient.UpdateAsync <string>(query.IndexName, query.TypeName, query.Poco.Id, statement);

            if (!response.Success)
            {
                throw response.OriginalException ?? new Exception($"Unsuccessful Elastic Request: {response.DebugInformation}");
            }
        }
        /// <summary>
        /// Executes a  get API call to get a typed JSON document from the index based on its id.
        /// https://www.elastic.co/guide/en/elasticsearch/reference/5.4/docs-get.html
        /// </summary>
        /// <typeparam name="TPoco"></typeparam>
        /// <param name="getQuery"></param>
        /// <returns></returns>
        public TPoco ExecuteGet <TPoco>(GetQuery <TPoco> getQuery)
            where TPoco : IElasticPoco
        {
            IndexExists(getQuery.IndexName);
            var response = LowLevelClient.Get <string>(getQuery.IndexName, getQuery.TypeName, getQuery.Id.ToString());

            if (!response.Success)
            {
                throw response.OriginalException ?? new Exception($"Unsuccessful Elastic Request: {response.DebugInformation}");
            }
            var data = JObject.Parse(response.Body)?.First;

            return(MapResponseToPoco <TPoco>(data));
        }
        /// <summary>
        /// Executes an asyncronus DeleteQuery using the Delete API and removes a document from the associated index.
        /// https://www.elastic.co/guide/en/elasticsearch/reference/5.4/docs-delete.html
        /// </summary>
        /// <typeparam name="TPoco">Has to Implement the IElasticPoco interface</typeparam>
        /// <param name="query">DeleteQuery object</param>
        /// <returns>Returnes the number of effected documents.</returns>
        public async Task <int> ExecuteDeleteAsync <TPoco>(IDeleteExecutable <TPoco> deleteQuery)
            where TPoco : IElasticPoco
        {
            var query = deleteQuery as DeleteQuery <TPoco>;

            if (query == null)
            {
                throw new Exception("Invalid delete request!");
            }

            var statement = Generator.Generate(query);
            var response  = !string.IsNullOrEmpty(query?.Poco.Id) ?
                            LowLevelClient.DeleteAsync <string>(query.IndexName, query.TypeName, query.Poco.Id) :
                            LowLevelClient.DeleteByQueryAsync <string>(query.IndexName, statement);

            return(ProcessDeleteResponse(await response));
        }