protected override async Task <SearchResult> SearchInternalAsync( SearchOptions searchOptions, CancellationToken cancellationToken) { // pull out the _include and _revinclude expressions. bool hasIncludeOrRevIncludeExpressions = ExtractIncludeExpressions( searchOptions.Expression, out Expression expressionWithoutIncludes, out IReadOnlyList <IncludeExpression> includeExpressions, out IReadOnlyList <IncludeExpression> revIncludeExpressions); if (hasIncludeOrRevIncludeExpressions) { // we're going to mutate searchOptions, so clone it first so the caller of this method does not see the changes. searchOptions = searchOptions.Clone(); searchOptions.Expression = expressionWithoutIncludes; if (includeExpressions.Any(e => e.Iterate) || revIncludeExpressions.Any(e => e.Iterate)) { // We haven't implemented this yet. throw new BadRequestException(Resources.IncludeIterateNotSupported); } } if (searchOptions.CountOnly) { int count = await ExecuteCountSearchAsync( _queryBuilder.BuildSqlQuerySpec(searchOptions, includes: Array.Empty <IncludeExpression>()), cancellationToken); return(new SearchResult(count, searchOptions.UnsupportedSearchParams)); } (IReadOnlyList <FhirCosmosResourceWrapper> results, string continuationToken) = await ExecuteSearchAsync <FhirCosmosResourceWrapper>( _queryBuilder.BuildSqlQuerySpec(searchOptions, includeExpressions), searchOptions, searchOptions.CountOnly?null : searchOptions.ContinuationToken, cancellationToken); (IList <FhirCosmosResourceWrapper> includes, bool includesTruncated) = await PerformIncludeQueries(results, includeExpressions, revIncludeExpressions, searchOptions.IncludeCount, cancellationToken); SearchResult searchResult = CreateSearchResult( searchOptions, results.Select(m => new SearchResultEntry(m, SearchEntryMode.Match)).Concat(includes.Select(i => new SearchResultEntry(i, SearchEntryMode.Include))), continuationToken, includesTruncated); if (searchOptions.IncludeTotal == TotalType.Accurate) { Debug.Assert(!searchOptions.CountOnly, "We should not be computing the total of a CountOnly search."); searchOptions = searchOptions.Clone(); // If this is the first page and there aren't any more pages if (searchOptions.ContinuationToken == null && continuationToken == null) { // Count the results on the page. searchResult.TotalCount = results.Count; } else { // Otherwise, indicate that we'd like to get the count searchOptions.CountOnly = true; // And perform a second read. searchResult.TotalCount = await ExecuteCountSearchAsync( _queryBuilder.BuildSqlQuerySpec(searchOptions, includes: Array.Empty <IncludeExpression>()), cancellationToken); } } return(searchResult); }