Beispiel #1
0
        private ResourceElement CreateBundle(SearchResult result, Bundle.BundleType type, Func <SearchResultEntry, Bundle.EntryComponent> selectionFunction)
        {
            EnsureArg.IsNotNull(result, nameof(result));

            // Create the bundle from the result.
            var bundle = new Bundle();

            if (_fhirRequestContextAccessor.FhirRequestContext.BundleIssues.Any())
            {
                var operationOutcome = new OperationOutcome
                {
                    Issue = new List <OperationOutcome.IssueComponent>(_fhirRequestContextAccessor.FhirRequestContext.BundleIssues.Select(x => x.ToPoco())),
                };

                bundle.Entry.Add(new Bundle.EntryComponent
                {
                    Resource = operationOutcome,
                    Search   = new Bundle.SearchComponent
                    {
                        Mode = Bundle.SearchEntryMode.Outcome,
                    },
                });
            }

            IEnumerable <Bundle.EntryComponent> entries = result.Results.Select(selectionFunction);

            bundle.Entry.AddRange(entries);

            if (result.ContinuationToken != null)
            {
                bundle.NextLink = _urlResolver.ResolveRouteUrl(
                    result.UnsupportedSearchParameters,
                    result.UnsupportedSortingParameters,
                    Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(result.ContinuationToken)),
                    true);
            }

            if (result.Partial)
            {
                // if the query resulted in a partial indication, add appropriate outcome
                // as an entry
                var resource = new OperationOutcome();
                resource.Issue = new List <OperationOutcome.IssueComponent>();
                resource.Issue.Add(new OperationOutcome.IssueComponent
                {
                    Severity    = OperationOutcome.IssueSeverity.Warning,
                    Code        = OperationOutcome.IssueType.Incomplete,
                    Diagnostics = Core.Resources.TruncatedIncludeMessage,
                });

                bundle.Entry.Add(new Bundle.EntryComponent()
                {
                    Resource = resource,
                    Search   = new Bundle.SearchComponent
                    {
                        Mode = Bundle.SearchEntryMode.Outcome,
                    },
                });
            }

            // Add the self link to indicate which search parameters were used.
            bundle.SelfLink = _urlResolver.ResolveRouteUrl(result.UnsupportedSearchParameters, result.UnsupportedSortingParameters);

            bundle.Id    = _fhirRequestContextAccessor.FhirRequestContext.CorrelationId;
            bundle.Type  = type;
            bundle.Total = result?.TotalCount;
            bundle.Meta  = new Meta
            {
                LastUpdated = Clock.UtcNow,
            };

            return(bundle.ToResourceElement());
        }
Beispiel #2
0
        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(SearchParameterNames.LastUpdated, 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);
        }