/// <inheritdoc/> public async Task ProcessAsync(ChangeFeedEntry changeFeedEntry, CancellationToken cancellationToken) { EnsureArg.IsNotNull(changeFeedEntry, nameof(changeFeedEntry)); // Create a context used throughout this process. var context = new FhirTransactionContext(changeFeedEntry); // Prepare all required objects for the transaction. foreach (IFhirTransactionPipelineStep pipeline in _fhirTransactionPipelines) { await pipeline.PrepareRequestAsync(context, cancellationToken); } // Check to see if any resource needs to be created/updated. var bundle = new Bundle() { Type = Bundle.BundleType.Transaction, }; var usedPropertyAccessors = new List <FhirTransactionRequestResponsePropertyAccessor>(_requestResponsePropertyAccessors.Count); foreach (FhirTransactionRequestResponsePropertyAccessor propertyAccessor in _requestResponsePropertyAccessors) { FhirTransactionRequestEntry requestEntry = propertyAccessor.RequestEntryGetter(context.Request); if (requestEntry == null || requestEntry.RequestMode == FhirTransactionRequestMode.None) { // No associated request, skip it. continue; } // There is a associated request, add to the list so it gets processed. usedPropertyAccessors.Add(propertyAccessor); bundle.Entry.Add(CreateRequestBundleEntryComponent(requestEntry)); } if (!bundle.Entry.Any()) { // Nothing to update. return; } // Execute the transaction. Bundle responseBundle = await _fhirTransactionExecutor.ExecuteTransactionAsync(bundle, cancellationToken); // Process the response. for (int i = 0; i < usedPropertyAccessors.Count; i++) { FhirTransactionResponseEntry responseEntry = CreateResponseEntry(responseBundle.Entry[i]); usedPropertyAccessors[i].ResponseEntrySetter(context.Response, responseEntry); } // Execute any additional checks of the response. foreach (IFhirTransactionPipelineStep pipeline in _fhirTransactionPipelines) { pipeline.ProcessResponse(context); }
public async Task GivenAResourceToProcess_WhenProcessed_ThenTransactionShouldBeExecuted(FhirTransactionRequestMode requestMode) { // Setup the pipeline step to simulate creating/updating patient. var patientRequest = new FhirTransactionRequestEntry( requestMode, new Bundle.RequestComponent(), new ClientResourceId(), new Patient()); var pipelineStep = new MockFhirTransactionPipelineStep() { OnPrepareRequestAsyncCalled = (context, cancellationToken) => { context.Request.Patient = patientRequest; Assert.Equal(DefaultCancellationToken, cancellationToken); }, }; _fhirTransactionPipelineSteps.Add(pipelineStep); // Setup the transaction executor to return response. var responseBundle = new Bundle(); var responseEntry = new Bundle.EntryComponent() { Response = new Bundle.ResponseComponent(), Resource = new Patient(), }; responseBundle.Entry.Add(responseEntry); _fhirTransactionExecutor.ExecuteTransactionAsync( Arg.Any <Bundle>(), DefaultCancellationToken) .Returns(call => { // Make sure the request bundle is correct. Bundle requestBundle = call.ArgAt <Bundle>(0); Assert.NotNull(requestBundle); Assert.Equal(Bundle.BundleType.Transaction, requestBundle.Type); Assert.Collection( requestBundle.Entry, entry => { Assert.Equal(patientRequest.ResourceId.ToString(), entry.FullUrl); Assert.Equal(patientRequest.Request, entry.Request); Assert.Equal(patientRequest.Resource, entry.Resource); }); return(responseBundle); }); // Process await _fhirTransactionPipeline.ProcessAsync(ChangeFeedGenerator.Generate(), DefaultCancellationToken); // The response should have been processed. Assert.NotNull(_capturedFhirTransactionContext); FhirTransactionResponseEntry patientResponse = _capturedFhirTransactionContext.Response.Patient; Assert.NotNull(patientResponse); Assert.Equal(responseEntry.Response, patientResponse.Response); Assert.Equal(responseEntry.Resource, patientResponse.Resource); }
/// <inheritdoc/> public async Task ProcessAsync(ChangeFeedEntry changeFeedEntry, CancellationToken cancellationToken) { EnsureArg.IsNotNull(changeFeedEntry, nameof(changeFeedEntry)); // Create a context used throughout this process. var context = new FhirTransactionContext(changeFeedEntry); // Prepare all required objects for the transaction. foreach (IFhirTransactionPipelineStep pipeline in _fhirTransactionPipelines) { await pipeline.PrepareRequestAsync(context, cancellationToken); } // Check to see if any resource needs to be created/updated. var bundle = new Bundle() { Type = Bundle.BundleType.Transaction, }; var usedPropertyAccessors = new List <(FhirTransactionRequestResponsePropertyAccessor Accessor, int Count)>(_requestResponsePropertyAccessors.Count); foreach (FhirTransactionRequestResponsePropertyAccessor propertyAccessor in _requestResponsePropertyAccessors) { List <FhirTransactionRequestEntry> requestEntries = propertyAccessor.RequestEntryGetter(context.Request)?.ToList(); if (requestEntries == null || requestEntries.Count == 0) { continue; } int useCount = 0; foreach (FhirTransactionRequestEntry requestEntry in requestEntries) { if (requestEntry == null || requestEntry.RequestMode == FhirTransactionRequestMode.None) { // No associated request, skip it. continue; } // There is a associated request, add to the list so it gets processed. bundle.Entry.Add(CreateRequestBundleEntryComponent(requestEntry)); useCount++; } usedPropertyAccessors.Add((propertyAccessor, useCount)); } if (bundle.Entry.Count == 0) { // Nothing to update. return; } // Execute the transaction. Bundle responseBundle = await _fhirTransactionExecutor.ExecuteTransactionAsync(bundle, cancellationToken); // Process the response. int processedResponseItems = 0; foreach ((FhirTransactionRequestResponsePropertyAccessor accessor, int count) in usedPropertyAccessors.Where(x => x.Count > 0)) { var responseEntries = new List <FhirTransactionResponseEntry>(); for (int j = 0; j < count; j++) { FhirTransactionResponseEntry responseEntry = CreateResponseEntry(responseBundle.Entry[processedResponseItems + j]); responseEntries.Add(responseEntry); } processedResponseItems += count; accessor.ResponseEntrySetter(context.Response, responseEntries); } // Execute any additional checks of the response. foreach (IFhirTransactionPipelineStep pipeline in _fhirTransactionPipelines) { pipeline.ProcessResponse(context); }