in src/Microsoft.Health.Fhir.Shared.Core/Features/Operations/Everything/PatientEverythingService.cs [89:202]
public async Task<SearchResult> SearchAsync(
string resourceId,
PartialDateTime start,
PartialDateTime end,
PartialDateTime since,
string type,
string continuationToken,
CancellationToken cancellationToken)
{
EverythingOperationContinuationToken token = string.IsNullOrEmpty(continuationToken)
? new EverythingOperationContinuationToken()
: EverythingOperationContinuationToken.FromJson(ContinuationTokenConverter.Decode(continuationToken));
if (token == null || token.Phase < 0 || token.Phase > 3)
{
throw new BadRequestException(Core.Resources.InvalidContinuationToken);
}
SearchResult searchResult;
string encodedInternalContinuationToken = string.IsNullOrEmpty(token.InternalContinuationToken)
? null
: ContinuationTokenConverter.Encode(token.InternalContinuationToken);
IReadOnlyList<string> types = string.IsNullOrEmpty(type) ? new List<string>() : type.SplitByOrSeparator();
// We will need to store the id of the patient that links to this one if we are processing a "seealso" link
var parentPatientId = resourceId;
// If we are currently processing a "seealso" link, set the resource id to the id of the link.
resourceId = token.IsProcessingSeeAlsoLink ? token.CurrentSeeAlsoLinkId : resourceId;
var phase = token.Phase;
switch (phase)
{
// Phase 0 gets the patient and any resources it references directly.
case 0:
searchResult = await SearchIncludes(resourceId, parentPatientId, since, types, token, cancellationToken);
if (!searchResult.Results.Any())
{
phase = 1;
goto case 1;
}
break;
// Phase 1 gets the resources in the patient's compartment that have date/time values.
case 1:
// If both start and end are null, we can just perform a regular compartment search in Phase 2.
if (start == null && end == null)
{
phase = 2;
goto case 2;
}
searchResult = await SearchCompartmentWithDate(resourceId, start, end, since, types, encodedInternalContinuationToken, cancellationToken);
if (!searchResult.Results.Any())
{
phase = 2;
goto case 2;
}
break;
// Phase 2 gets the resources in the patient's compartment that do not have date/time values.
case 2:
searchResult = start == null && end == null
? await SearchCompartment(resourceId, parentPatientId, since, types, encodedInternalContinuationToken, token, cancellationToken)
: await SearchCompartmentWithoutDate(resourceId, parentPatientId, since, types, encodedInternalContinuationToken, token, cancellationToken);
if (!searchResult.Results.Any())
{
phase = 3;
goto case 3;
}
break;
// Phase 3 gets the patient's devices.
case 3:
searchResult = await SearchRevinclude(resourceId, since, types, encodedInternalContinuationToken, cancellationToken);
break;
default:
throw new EverythingOperationException(string.Format(Core.Resources.InvalidEverythingOperationPhase, phase), HttpStatusCode.BadRequest);
}
string nextContinuationToken;
if (searchResult.ContinuationToken != null)
{
// Keep processing the remaining results for the current phase.
token.InternalContinuationToken = searchResult.ContinuationToken;
nextContinuationToken = token.ToJson();
}
else if (phase < 3)
{
token.Phase = phase + 1;
token.InternalContinuationToken = null;
nextContinuationToken = token.ToJson();
}
else
{
nextContinuationToken = await CheckForNextSeeAlsoLinkAndSetToken(parentPatientId, token, cancellationToken);
// If the last phase returned no results and there are links to process
if (!searchResult.Results.Any() && nextContinuationToken != null)
{
// Run patient $everything on links.
return await SearchAsync(parentPatientId, start, end, since, type, ContinuationTokenConverter.Encode(nextContinuationToken), cancellationToken);
}
}
return new SearchResult(searchResult.Results, nextContinuationToken, searchResult.SortOrder, searchResult.UnsupportedSearchParameters);
}