public virtual async Task <FindResults <TResult> > FindAsAsync <TResult>(IRepositoryQuery query, ICommandOptions options = null) where TResult : class, new() { options = ConfigureOptions(options.As <T>()); bool useSnapshotPaging = options.ShouldUseSnapshotPaging(); // don't use caching with snapshot paging. bool allowCaching = IsCacheEnabled && useSnapshotPaging == false; await OnBeforeQueryAsync(query, options, typeof(TResult)).AnyContext(); await RefreshForConsistency(query, options).AnyContext(); async Task <FindResults <TResult> > GetNextPageFunc(FindResults <TResult> r) { var previousResults = r; if (previousResults == null) { throw new ArgumentException(nameof(r)); } string scrollId = previousResults.GetScrollId(); if (!String.IsNullOrEmpty(scrollId)) { var scrollResponse = await _client.ScrollAsync <TResult>(options.GetSnapshotLifetime(), scrollId).AnyContext(); _logger.LogRequest(scrollResponse, options.GetQueryLogLevel()); var results = scrollResponse.ToFindResults(); results.Page = previousResults.Page + 1; results.HasMore = scrollResponse.Hits.Count >= options.GetLimit() || scrollResponse.Hits.Count >= options.GetMaxLimit(); // clear the scroll if (!results.HasMore) { await _client.ClearScrollAsync(s => s.ScrollId(scrollId)); } return(results); } if (options.ShouldUseSearchAfterPaging()) { options.SearchAfterToken(previousResults.GetSearchAfterToken()); } if (options == null) { return(new FindResults <TResult>()); } options?.PageNumber(!options.HasPageNumber() ? 2 : options.GetPage() + 1); return(await FindAsAsync <TResult>(query, options).AnyContext()); } string cacheSuffix = options?.HasPageLimit() == true?String.Concat(options.GetPage().ToString(), ":", options.GetLimit().ToString()) : null; FindResults <TResult> result; if (allowCaching) { result = await GetCachedQueryResultAsync <FindResults <TResult> >(options, cacheSuffix : cacheSuffix).AnyContext(); if (result != null) { ((IGetNextPage <TResult>)result).GetNextPageFunc = async r => await GetNextPageFunc(r).AnyContext(); return(result); } } ISearchResponse <TResult> response; if (useSnapshotPaging == false || !options.HasSnapshotScrollId()) { var searchDescriptor = await CreateSearchDescriptorAsync(query, options).AnyContext(); if (useSnapshotPaging) { searchDescriptor.Scroll(options.GetSnapshotLifetime()); } if (query.ShouldOnlyHaveIds()) { searchDescriptor.Source(false); } response = await _client.SearchAsync <TResult>(searchDescriptor).AnyContext(); } else { response = await _client.ScrollAsync <TResult>(options.GetSnapshotLifetime(), options.GetSnapshotScrollId()).AnyContext(); } if (response.IsValid) { _logger.LogRequest(response, options.GetQueryLogLevel()); } else { if (response.ApiCall.HttpStatusCode.GetValueOrDefault() == 404) { return(new FindResults <TResult>()); } _logger.LogErrorRequest(response, "Error while searching"); throw new ApplicationException(response.GetErrorMessage(), response.OriginalException); } if (useSnapshotPaging) { result = response.ToFindResults(); result.HasMore = response.Hits.Count >= options.GetLimit(); // clear the scroll if (!result.HasMore) { var scrollId = result.GetScrollId(); if (!String.IsNullOrEmpty(scrollId)) { await _client.ClearScrollAsync(s => s.ScrollId(result.GetScrollId())); } } ((IGetNextPage <TResult>)result).GetNextPageFunc = GetNextPageFunc; } else { int limit = options.GetLimit(); result = response.ToFindResults(limit); result.HasMore = response.Hits.Count > limit || response.Hits.Count >= options.GetMaxLimit(); ((IGetNextPage <TResult>)result).GetNextPageFunc = GetNextPageFunc; } if (options.HasSearchAfter()) { result.SetSearchBeforeToken(); if (result.HasMore) { result.SetSearchAfterToken(); } } else if (options.HasSearchBefore()) { // reverse results bool hasMore = result.HasMore; result = new FindResults <TResult>(result.Hits.Reverse(), result.Total, result.Aggregations.ToDictionary(k => k.Key, v => v.Value), GetNextPageFunc, result.Data.ToDictionary(k => k.Key, v => v.Value)); result.HasMore = hasMore; result.SetSearchAfterToken(); if (result.HasMore) { result.SetSearchBeforeToken(); } } else if (result.HasMore) { result.SetSearchAfterToken(); } result.Page = options.GetPage(); if (!allowCaching) { return(result); } var nextPageFunc = ((IGetNextPage <TResult>)result).GetNextPageFunc; ((IGetNextPage <TResult>)result).GetNextPageFunc = null; await SetCachedQueryResultAsync(options, result, cacheSuffix : cacheSuffix).AnyContext(); ((IGetNextPage <TResult>)result).GetNextPageFunc = nextPageFunc; return(result); }