public async Task <UpsertOutcome> UpsertAsync(
            ResourceWrapper resource,
            WeakETag weakETag,
            bool allowCreate,
            bool keepHistory,
            CancellationToken cancellationToken)
        {
            EnsureArg.IsNotNull(resource, nameof(resource));

            var cosmosWrapper = new FhirCosmosResourceWrapper(resource);

            try
            {
                _logger.LogDebug($"Upserting {resource.ResourceTypeName}/{resource.ResourceId}, ETag: \"{weakETag?.VersionId}\", AllowCreate: {allowCreate}, KeepHistory: {keepHistory}");

                UpsertWithHistoryModel response = await _retryExceptionPolicyFactory.CreateRetryPolicy().ExecuteAsync(
                    async ct => await _upsertWithHistoryProc.Execute(
                        _containerScope.Value.Scripts,
                        cosmosWrapper,
                        weakETag?.VersionId,
                        allowCreate,
                        keepHistory,
                        ct),
                    cancellationToken);

                return(new UpsertOutcome(response.Wrapper, response.OutcomeType));
            }
            catch (CosmosException exception)
            {
                switch (exception.GetSubStatusCode())
                {
                case HttpStatusCode.PreconditionFailed:
                    throw new PreconditionFailedException(string.Format(Core.Resources.ResourceVersionConflict, weakETag?.VersionId));

                case HttpStatusCode.NotFound:
                    if (cosmosWrapper.IsDeleted)
                    {
                        return(null);
                    }

                    if (weakETag != null)
                    {
                        throw new ResourceNotFoundException(string.Format(Core.Resources.ResourceNotFoundByIdAndVersion, resource.ResourceTypeName, resource.ResourceId, weakETag.VersionId));
                    }
                    else if (!allowCreate)
                    {
                        throw new MethodNotAllowedException(Core.Resources.ResourceCreationNotAllowed);
                    }

                    break;

                case HttpStatusCode.ServiceUnavailable:
                    throw new ServiceUnavailableException();
                }

                _logger.LogError(exception, "Unhandled Document Client Exception");

                throw;
            }
        }
        public async Task <UpsertOutcome> UpsertAsync(
            ResourceWrapper resource,
            WeakETag weakETag,
            bool allowCreate,
            bool keepHistory,
            CancellationToken cancellationToken)
        {
            EnsureArg.IsNotNull(resource, nameof(resource));

            var cosmosWrapper = new FhirCosmosResourceWrapper(resource);

            try
            {
                _logger.LogDebug($"Upserting {resource.ResourceTypeName}/{resource.ResourceId}, ETag: \"{weakETag?.VersionId}\", AllowCreate: {allowCreate}, KeepHistory: {keepHistory}");

                UpsertWithHistoryModel response = await _retryExceptionPolicyFactory.CreateRetryPolicy().ExecuteAsync(
                    async ct => await _upsertWithHistoryProc.Execute(
                        _documentClient,
                        _collectionUri,
                        cosmosWrapper,
                        weakETag?.VersionId,
                        allowCreate,
                        keepHistory,
                        ct),
                    cancellationToken);

                return(new UpsertOutcome(response.Wrapper, response.OutcomeType));
            }
            catch (DocumentClientException dce)
            {
                // All errors from a sp (e.g. "pre-condition") come back as a "BadRequest"

                // The ETag does not match the ETag in the document DB database.
                if (dce.Error?.Message?.Contains(GetValue(HttpStatusCode.PreconditionFailed), StringComparison.Ordinal) == true)
                {
                    throw new ResourceConflictException(weakETag);
                }
                else if (dce.Error?.Message?.Contains(GetValue(HttpStatusCode.NotFound), StringComparison.Ordinal) == true)
                {
                    if (weakETag != null)
                    {
                        throw new ResourceConflictException(weakETag);
                    }
                    else if (!allowCreate)
                    {
                        throw new MethodNotAllowedException(Core.Resources.ResourceCreationNotAllowed);
                    }
                }
                else if (dce.Error?.Message?.Contains(GetValue(HttpStatusCode.ServiceUnavailable), StringComparison.Ordinal) == true)
                {
                    throw new ServiceUnavailableException();
                }

                _logger.LogError(dce, "Unhandled Document Client Exception");

                throw;
            }
        }
        public async Task <ResourceWrapper> UpdateSearchIndexForResourceAsync(ResourceWrapper resourceWrapper, WeakETag weakETag, CancellationToken cancellationToken)
        {
            EnsureArg.IsNotNull(resourceWrapper, nameof(resourceWrapper));
            EnsureArg.IsNotNull(weakETag, nameof(weakETag));

            var cosmosWrapper = new FhirCosmosResourceWrapper(resourceWrapper);

            try
            {
                _logger.LogDebug($"Replacing {resourceWrapper.ResourceTypeName}/{resourceWrapper.ResourceId}, ETag: \"{weakETag.VersionId}\"");

                FhirCosmosResourceWrapper response = await _retryExceptionPolicyFactory.CreateRetryPolicy().ExecuteAsync(
                    async ct => await _replaceSingleResource.Execute(
                        _containerScope.Value.Scripts,
                        cosmosWrapper,
                        weakETag.VersionId,
                        ct),
                    cancellationToken);

                return(response);
            }
            catch (CosmosException exception)
            {
                // Check GetSubStatusCode documentation for why we need to get that instead of the status code.
                switch (exception.GetSubStatusCode())
                {
                case HttpStatusCode.PreconditionFailed:
                    throw new PreconditionFailedException(string.Format(Core.Resources.ResourceVersionConflict, weakETag));

                case HttpStatusCode.NotFound:
                    throw new ResourceNotFoundException(string.Format(
                                                            Core.Resources.ResourceNotFoundByIdAndVersion,
                                                            resourceWrapper.ResourceTypeName,
                                                            resourceWrapper.ResourceId,
                                                            weakETag));

                case HttpStatusCode.ServiceUnavailable:
                    throw new ServiceUnavailableException();
                }

                _logger.LogError(exception, "Unhandled Document Client Exception");
                throw;
            }
        }
        public async Task <ResourceWrapper> UpdateSearchIndexForResourceAsync(ResourceWrapper resourceWrapper, string eTag, CancellationToken cancellationToken)
        {
            EnsureArg.IsNotNull(resourceWrapper, nameof(resourceWrapper));
            EnsureArg.IsNotNullOrWhiteSpace(eTag, nameof(eTag));

            var cosmosWrapper = new FhirCosmosResourceWrapper(resourceWrapper);
            ItemRequestOptions requestOptions = new ItemRequestOptions()
            {
                IfMatchEtag = eTag,
            };

            try
            {
                ItemResponse <FhirCosmosResourceWrapper> response = await _containerScope.Value.ReplaceItemAsync(
                    cosmosWrapper,
                    cosmosWrapper.ResourceId,
                    new PartitionKey(cosmosWrapper.PartitionKey),
                    requestOptions,
                    cancellationToken);

                return(response.Resource);
            }
            catch (CosmosException exception)
            {
                switch (exception.StatusCode)
                {
                case HttpStatusCode.PreconditionFailed:
                    throw new PreconditionFailedException(string.Format(Core.Resources.ResourceVersionConflict, eTag));

                case HttpStatusCode.NotFound:
                    throw new ResourceNotFoundException(string.Format(
                                                            Core.Resources.ResourceNotFoundByIdAndVersion,
                                                            resourceWrapper.ResourceTypeName,
                                                            resourceWrapper.ResourceId,
                                                            eTag));

                case HttpStatusCode.ServiceUnavailable:
                    throw new ServiceUnavailableException();
                }

                _logger.LogError(exception, "Unhandled Document Client Exception");
                throw;
            }
        }