Beispiel #1
0
        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);
        }