in src/Microsoft.Health.Fhir.Core/Features/Search/SearchService.cs [69:180]
public async Task<SearchResult> SearchHistoryAsync(
string resourceType,
string resourceId,
PartialDateTime at,
PartialDateTime since,
PartialDateTime before,
int? count,
string continuationToken,
CancellationToken cancellationToken)
{
var queryParameters = new List<Tuple<string, string>>();
if (at != null)
{
if (since != null)
{
// _at and _since cannot be both specified.
throw new InvalidSearchOperationException(
string.Format(
CultureInfo.InvariantCulture,
Core.Resources.AtCannotBeSpecifiedWithBeforeOrSince,
KnownQueryParameterNames.At,
KnownQueryParameterNames.Since));
}
if (before != null)
{
// _at and _since cannot be both specified.
throw new InvalidSearchOperationException(
string.Format(
CultureInfo.InvariantCulture,
Core.Resources.AtCannotBeSpecifiedWithBeforeOrSince,
KnownQueryParameterNames.At,
KnownQueryParameterNames.Before));
}
}
if (before != null)
{
var beforeOffset = before.ToDateTimeOffset(
defaultMonth: 1,
defaultDaySelector: (year, month) => 1,
defaultHour: 0,
defaultMinute: 0,
defaultSecond: 0,
defaultFraction: 0.0000000m,
defaultUtcOffset: TimeSpan.Zero).ToUniversalTime();
if (beforeOffset.CompareTo(Clock.UtcNow) > 0)
{
// you cannot specify a value for _before in the future
throw new InvalidSearchOperationException(
string.Format(
CultureInfo.InvariantCulture,
Core.Resources.HistoryParameterBeforeCannotBeFuture,
KnownQueryParameterNames.Before));
}
}
bool searchByResourceId = !string.IsNullOrEmpty(resourceId);
if (searchByResourceId)
{
queryParameters.Add(Tuple.Create(SearchParameterNames.Id, resourceId));
}
if (!string.IsNullOrEmpty(continuationToken))
{
queryParameters.Add(Tuple.Create(KnownQueryParameterNames.ContinuationToken, continuationToken));
}
if (at != null)
{
queryParameters.Add(Tuple.Create(KnownQueryParameterNames.At, at.ToString()));
}
else
{
if (since != null)
{
queryParameters.Add(Tuple.Create(SearchParameterNames.LastUpdated, $"ge{since}"));
}
if (before != null)
{
queryParameters.Add(Tuple.Create(SearchParameterNames.LastUpdated, $"lt{before}"));
}
}
if (count.HasValue && count > 0)
{
queryParameters.Add(Tuple.Create(KnownQueryParameterNames.Count, count.ToString()));
}
SearchOptions searchOptions = _searchOptionsFactory.Create(resourceType, queryParameters);
SearchResult searchResult = await SearchHistoryInternalAsync(searchOptions, cancellationToken);
// If no results are returned from the _history search
// determine if the resource actually exists or if the results were just filtered out.
// The 'deleted' state has no effect because history will return deleted resources
if (searchByResourceId && searchResult.Results.Any() == false)
{
var resource = await _fhirDataStore.GetAsync(new ResourceKey(resourceType, resourceId), cancellationToken);
if (resource == null)
{
throw new ResourceNotFoundException(string.Format(Core.Resources.ResourceNotFoundById, resourceType, resourceId));
}
}
return searchResult;
}