public static int GetSkip(this ICommandOptions options) { if (!options.HasPageLimit() && !options.HasPageNumber()) { return(0); } int limit = options.GetLimit(); int page = options.GetPage(); int skip = (page - 1) * limit; if (skip < 0) { skip = 0; } return(skip); }
public static bool ShouldUseSkip(this ICommandOptions options) { return(options.HasPageLimit() && options.GetPage() > 1); }
public async Task <FindResults <TResult> > FindAsAsync <TResult>(IRepositoryQuery query, ICommandOptions options = null) where TResult : class, new() { if (query == null) { query = new RepositoryQuery(); } bool useSnapshotPaging = options.ShouldUseSnapshotPaging(); // don't use caching with snapshot paging. bool allowCaching = IsCacheEnabled && useSnapshotPaging == false; options = ConfigureOptions(options); await OnBeforeQueryAsync(query, options, typeof(TResult)).AnyContext(); Func <FindResults <TResult>, Task <FindResults <TResult> > > getNextPageFunc = async r => { var previousResults = r; if (previousResults == null) { throw new ArgumentException(nameof(r)); } if (!String.IsNullOrEmpty(previousResults.GetScrollId())) { var scrollResponse = await _client.ScrollAsync <TResult>(options.GetSnapshotLifetime(), previousResults.GetScrollId()).AnyContext(); _logger.Trace(() => scrollResponse.GetRequest()); var results = scrollResponse.ToFindResults(); results.Page = previousResults.Page + 1; results.HasMore = scrollResponse.Hits.Count() >= options.GetLimit(); return(results); } 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 = null; if (useSnapshotPaging == false || !options.HasSnapshotScrollId()) { var searchDescriptor = await CreateSearchDescriptorAsync(query, options).AnyContext(); if (useSnapshotPaging) { searchDescriptor.Scroll(options.GetSnapshotLifetime()); } response = await _client.SearchAsync <TResult>(searchDescriptor).AnyContext(); } else { response = await _client.ScrollAsync <TResult>(options.GetSnapshotLifetime(), options.GetSnapshotScrollId()).AnyContext(); } _logger.Trace(() => response.GetRequest()); if (!response.IsValid) { if (response.ApiCall.HttpStatusCode.GetValueOrDefault() == 404) { return(new FindResults <TResult>()); } string message = response.GetErrorMessage(); _logger.Error().Exception(response.OriginalException).Message(message).Property("request", response.GetRequest()).Write(); throw new ApplicationException(message, response.OriginalException); } if (useSnapshotPaging) { result = response.ToFindResults(); // TODO: Is there a better way to figure out if you are done scrolling? result.HasMore = response.Hits.Count() >= options.GetLimit(); ((IGetNextPage <TResult>)result).GetNextPageFunc = getNextPageFunc; } else if (options.HasPageLimit() == true) { result = response.ToFindResults(options.GetLimit()); result.HasMore = response.Hits.Count() > options.GetLimit(); ((IGetNextPage <TResult>)result).GetNextPageFunc = getNextPageFunc; } else { result = response.ToFindResults(); } 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); }
public virtual async Task <FindResults <TResult> > FindAsAsync <TResult>(IRepositoryQuery query, ICommandOptions options = null) where TResult : class, new() { if (query == null) { query = new RepositoryQuery(); } bool useSnapshotPaging = options.ShouldUseSnapshotPaging(); // don't use caching with snapshot paging. bool allowCaching = IsCacheEnabled && useSnapshotPaging == false; options = ConfigureOptions(options); await OnBeforeQueryAsync(query, options, typeof(TResult)).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(); if (_logger.IsEnabled(Microsoft.Extensions.Logging.LogLevel.Trace)) { _logger.LogTrace(scrollResponse.GetRequest()); } var results = scrollResponse.ToFindResults(); results.Page = previousResults.Page + 1; results.HasMore = scrollResponse.Hits.Count >= options.GetLimit(); return(results); } if (options.ShouldUseSearchAfterPaging()) { var lastDocument = previousResults.Documents.LastOrDefault(); if (lastDocument != null) { var searchAfterValues = new List <object>(); var sorts = query.GetSorts(); if (sorts.Count > 0) { foreach (var sort in query.GetSorts()) { if (sort.SortKey.Property?.DeclaringType == lastDocument.GetType()) { searchAfterValues.Add(sort.SortKey.Property.GetValue(lastDocument)); } else if (typeof(TResult) == typeof(T) && sort.SortKey.Expression is Expression <Func <T, object> > valueGetterExpression) { var valueGetter = valueGetterExpression.Compile(); var typedLastDocument = lastDocument as T; if (typedLastDocument != null) { var value = valueGetter.Invoke(typedLastDocument); searchAfterValues.Add(value); } } else if (sort.SortKey.Name != null) { var propertyInfo = lastDocument.GetType().GetProperty(sort.SortKey.Name); if (propertyInfo != null) { searchAfterValues.Add(propertyInfo.GetValue(lastDocument)); } } else { // TODO: going to to need to take the Expression and pull the string name from it } } } else if (lastDocument is IIdentity lastDocumentId) { searchAfterValues.Add(lastDocumentId.Id); } if (searchAfterValues.Count > 0) { options.SearchAfter(searchAfterValues.ToArray()); } else { throw new ArgumentException("Unable to automatically calculate values for SearchAfterPaging."); } } } 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()); } response = await _client.SearchAsync <TResult>(searchDescriptor).AnyContext(); } else { response = await _client.ScrollAsync <TResult>(options.GetSnapshotLifetime(), options.GetSnapshotScrollId()).AnyContext(); } if (_logger.IsEnabled(Microsoft.Extensions.Logging.LogLevel.Trace)) { _logger.LogTrace(response.GetRequest()); } if (!response.IsValid) { if (response.ApiCall.HttpStatusCode.GetValueOrDefault() == 404) { return(new FindResults <TResult>()); } string message = response.GetErrorMessage(); _logger.LogError(response.OriginalException, message); throw new ApplicationException(message, response.OriginalException); } if (useSnapshotPaging) { result = response.ToFindResults(); result.HasMore = response.Hits.Count >= options.GetLimit(); ((IGetNextPage <TResult>)result).GetNextPageFunc = GetNextPageFunc; } else if (options.HasPageLimit()) { int limit = options.GetLimit(); result = response.ToFindResults(limit); result.HasMore = response.Hits.Count > limit; ((IGetNextPage <TResult>)result).GetNextPageFunc = GetNextPageFunc; } else { result = response.ToFindResults(); } 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); }
public virtual async Task <FindResults <TResult> > FindAsAsync <TResult>(IRepositoryQuery query, ICommandOptions options = null) where TResult : class, new() { if (query == null) { query = new RepositoryQuery(); } bool useSnapshotPaging = options.ShouldUseSnapshotPaging(); // don't use caching with snapshot paging. bool allowCaching = IsCacheEnabled && useSnapshotPaging == false; options = ConfigureOptions(options); await OnBeforeQueryAsync(query, options, typeof(TResult)).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(); if (_logger.IsEnabled(Microsoft.Extensions.Logging.LogLevel.Trace)) { _logger.LogTrace(scrollResponse.GetRequest()); } var results = scrollResponse.ToFindResults(); results.Page = previousResults.Page + 1; results.HasMore = scrollResponse.Hits.Count >= options.GetLimit(); return(results); } 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()); } response = await _client.SearchAsync <TResult>(searchDescriptor).AnyContext(); } else { response = await _client.ScrollAsync <TResult>(options.GetSnapshotLifetime(), options.GetSnapshotScrollId()).AnyContext(); } if (_logger.IsEnabled(Microsoft.Extensions.Logging.LogLevel.Trace)) { _logger.LogTrace(response.GetRequest()); } if (!response.IsValid) { if (response.ApiCall.HttpStatusCode.GetValueOrDefault() == 404) { return(new FindResults <TResult>()); } string message = response.GetErrorMessage(); _logger.LogError(response.OriginalException, message); throw new ApplicationException(message, response.OriginalException); } if (useSnapshotPaging) { result = response.ToFindResults(); result.HasMore = response.Hits.Count >= options.GetLimit(); ((IGetNextPage <TResult>)result).GetNextPageFunc = GetNextPageFunc; } else if (options.HasPageLimit()) { int limit = options.GetLimit(); result = response.ToFindResults(limit); result.HasMore = response.Hits.Count > limit; ((IGetNextPage <TResult>)result).GetNextPageFunc = GetNextPageFunc; } else { result = response.ToFindResults(); } 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); }
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); }