public async Task ProcessBundles() { var optionsBuilder = new DbContextOptionsBuilder <AgsContext>(); optionsBuilder.UseSqlServer(AgsDbConnection); using (var context = new AgsContext(optionsBuilder.Options)) { if (Attributes == null) { var attributeList = await context.Agsattributes.ToListAsync(); Attributes = new Dictionary <int, string>(attributeList.Count); attributeList.ForEach(x => Attributes.Add(x.AttributeId, x.Name)); } ProcessDiagnosticReports(context); } }
private void ProcessDiagnosticReports(AgsContext context) { var client = new FhirClient(this.FhirBaseUrl); var reports = (Bundle)client.Get("DiagnosticReport"); int reportCounter = 0; while (reports != null) { if (reports.Entry == null || reports.Entry.Count == 0) { Console.WriteLine("Null or empty list of DiagnosticReport resources returned by FHIR server"); return; } Console.WriteLine("Processing bundle of {0} reports", reports.Entry.Count); foreach (var entry in reports.Entry) { var resource = entry.Resource; var reportResource = resource as DiagnosticReport; if (resource.ResourceType != ResourceType.DiagnosticReport) { throw new FHIRGenomicsException(string.Format("We received a {0} resource where we expected a DiagnosticReport", resource.ResourceType)); } else if (reportResource == null) { throw new FHIRGenomicsException(string.Format("Unable to cast resource ID {0} as a DiagnosticReport", resource.Id)); } if (!ResourceHasProfile(reportResource, Constants.GenomicsProfile.DiagnosticReport)) { throw new FHIRGenomicsException("The expected FHIR profile was not specified for the DiagnosticReport"); } ProcessDiagnosticReport(reportResource, context); reportCounter++; } reports = (Bundle)client.Continue(reports); } context.SaveChanges(); Console.WriteLine("Processed {0} reports", reportCounter); }
//private async Task ProcessPatients(AgsContext context) //{ // var patients = await GetAllResources("Patient"); // if (patients == null || patients.Entry == null || patients.Entry.Count == 0) { // Console.WriteLine("Null or empty list of Patient resources returned by FHIR server"); // return; // } // Console.WriteLine("PROCESSING {0} PATIENTS", patients.Entry.Count); // Console.WriteLine("-----------------------"); // foreach (var entry in patients.Entry) { // var resource = entry.Resource; // var patientResource = resource as Patient; // if (resource.ResourceType != ResourceType.Patient) { // throw new FHIRGenomicsException(string.Format("We received a {0} resource where we expected a Patient", resource.ResourceType)); // } else if (patientResource == null) { // throw new FHIRGenomicsException(string.Format("Unable to cast resource ID {0} as a Patient", resource.Id)); // } // ProcessPatient(patientResource, context); // } //} private void ProcessPatient(Patient patientResource, AgsContext context) { var firstName = ""; var lastName = ""; if (patientResource.Name == null || patientResource.Name.Count == 0) { Console.WriteLine("{0} has no Name entries - using default of 'Patient {0}'", patientResource.Id); firstName = "Patient"; lastName = patientResource.Id; } else { if (patientResource.Name.Count > 1) { Console.WriteLine("{0} has {1} Name entries - using the first entry only", patientResource.Id, patientResource.Name.Count); } HumanName name = patientResource.Name[0]; firstName = string.Join(" ", name.Given); lastName = name.Family; } var gender = "U"; var genderElement = patientResource.Extension.Find(x => x.Url.Equals("http://hl7.org/fhir/us/core/StructureDefinition/us-core-birthsex", StringComparison.CurrentCultureIgnoreCase)); if (genderElement != null) { gender = genderElement.Value.ToString(); } DateTime?dateOfBirth = null; if (patientResource.BirthDateElement == null) { Console.WriteLine("No DOB for Patient {0}", patientResource.Id); } else { #pragma warning disable CS0618 // Type or member is obsolete dateOfBirth = patientResource.BirthDateElement.ToDateTime(); #pragma warning restore CS0618 // Type or member is obsolete } var mrn = ""; if (patientResource.Identifier == null || patientResource.Identifier.Count == 0) { Console.WriteLine("Patinet {0} has no identifier entries", patientResource.Id); } else { Identifier id = patientResource.Identifier.Find(x => x.System.Equals("https://emerge.mc.vanderbilt.edu/", StringComparison.CurrentCultureIgnoreCase)); if (patientResource.Identifier.Count > 1) { Console.WriteLine("Patient {0} had {1} identifiers. We will use the first eMERGE associated entry of {2}", patientResource.Id, patientResource.Identifier.Count, id.Value); } mrn = id.Value; } var patient = new Agspatients(); patient.FirstName = firstName; patient.LastName = lastName; patient.BirthDate = dateOfBirth; patient.Gender = gender; patient.Mrn = mrn; context.Agspatients.Add(patient); }
private void ProcessDiagnosticReport(DiagnosticReport report, AgsContext context) { var client = new FhirClient(this.FhirBaseUrl); // The result collection contains observations, including a Grouper type observation that will hold PGx results. // There can be >1 Grouper, so we need to do a little more investigation (peeking at the first observation type) // to see if it's really the one we want. var pgxObservations = new List <Observation>(); foreach (var result in report.Result) { var observation = client.Read <Observation>(result.Url); if (!ResourceHasProfile(observation, Constants.GenomicsProfile.Grouper)) { continue; } foreach (var member in observation.HasMember) { var memberResource = client.Read <Observation>(member.Url); if (memberResource == null || !ResourceHasProfile(memberResource, PgxObservationProfiles)) { pgxObservations.Clear(); break; } pgxObservations.Add(memberResource); } // If we have any PGx observations at this point, we must have found the right grouper. We can stop // processing since we have found what we're looking for. if (pgxObservations.Count > 0) { break; } } // Now that we're out of the loop, confirm or refute the assumption that all of our results should have // a PGx grouper that contains PGx results. If we didn't find one, halt the program. if (pgxObservations.Count == 0) { throw new FHIRGenomicsException("No grouper containing PGx-related Observation resources was found"); } // Get the patient Patient patient = client.Read <Patient>(report.Subject.Url); if (patient == null) { throw new FHIRGenomicsException("Unable to find the patient associated with this DiagnosticReport"); } ProcessPatient(patient, context); AgsresultMessages message = new AgsresultMessages { Sender = "HGSC", Format = "FHIR", ReceivedOn = DateTime.Now, ProcessedOn = DateTime.Now, Status = "Processed" }; context.AgsresultMessages.Add(message); AgsresultAttributes sample = NewResultAttribute(Constants.Attribute.Sample); sample.Value = string.Empty; message.AgsresultAttributes.Add(sample); context.SaveChanges(); if (report.Status.HasValue) { AgsresultAttributes status = NewResultAttribute(Constants.Attribute.Status, sample.ResultAttributeId); status.Value = report.Status.Value.ToString(); message.AgsresultAttributes.Add(status); } AgsresultAttributes createdOn = NewResultAttribute(Constants.Attribute.CreatedOn, sample.ResultAttributeId); createdOn.Value = DateTime.Now.ToShortDateString(); message.AgsresultAttributes.Add(createdOn); var specimens = report.Specimen; if (specimens == null || specimens.Count == 0) { throw new FHIRGenomicsException("No specimen was found for this DiagnosticReport"); } else if (specimens.Count != 1) { throw new FHIRGenomicsException(string.Format("We are expecting exactly 1 specimen for this DiagnosticReport, but found {0}", specimens.Count)); } var specimen = (Specimen)client.Get(specimens[0].Url); AgsresultAttributes sampleType = NewResultAttribute(Constants.Attribute.SampleType, sample.ResultAttributeId); sampleType.Value = specimen.Type.Coding[0].Display; message.AgsresultAttributes.Add(sampleType); AgsresultAttributes accession = NewResultAttribute(Constants.Attribute.LabAccession, sample.ResultAttributeId); accession.Value = report.Identifier.Find(x => x.System.Equals(Constants.CodeSystem.HGSC)).Value; message.AgsresultAttributes.Add(accession); var interpreters = report.ResultsInterpreter; if (interpreters == null || interpreters.Count == 0) { throw new FHIRGenomicsException("We expected at least one signer (ResultsInterpreter) for this DiagnosticReport, but found 0"); } foreach (var interpreter in interpreters) { AgsresultAttributes interpreterAttr = NewResultAttribute(Constants.Attribute.SignedBy, sample.ResultAttributeId); var role = (PractitionerRole)client.Get(interpreter.Url); var practitioner = (Practitioner)client.Get(role.Practitioner.Url); interpreterAttr.Value = FormatName(practitioner.Name); message.AgsresultAttributes.Add(interpreterAttr); } var serviceRequest = (ServiceRequest)client.Get(report.BasedOn[0].Url); if (!ResourceHasProfile(serviceRequest, Constants.GenomicsProfile.ServiceRequest)) { throw new FHIRGenomicsException("The ServiceRequest profile did not match the Genomics IG profile"); } Coding indicationCoding = null; foreach (var reasonCode in serviceRequest.ReasonCode) { indicationCoding = reasonCode.Coding.Find(x => x.System.Equals(Constants.CodeSystem.GeneInsight)); if (indicationCoding != null) { break; } } if (indicationCoding == null) { throw new FHIRGenomicsException("Unable to find a valid reason for testing within the ServiceRequest"); } AgsresultAttributes testIndication = NewResultAttribute(Constants.Attribute.TestIndication, sample.ResultAttributeId); testIndication.Value = indicationCoding.Display; message.AgsresultAttributes.Add(testIndication); Coding requestCoding = serviceRequest.Code.Coding.Find(x => x.System.Equals(Constants.CodeSystem.BaylorLabTestCodes)); if (requestCoding == null) { throw new FHIRGenomicsException("Unable to find a valid code for the ServiceRequest"); } AgsresultAttributes assayTest = NewResultAttribute(Constants.Attribute.AssayTestCode, sample.ResultAttributeId); assayTest.Value = requestCoding.Display; message.AgsresultAttributes.Add(assayTest); AgsresultAttributes observedOn = NewResultAttribute(Constants.Attribute.ObservedOn, sample.ResultAttributeId); observedOn.Value = serviceRequest.AuthoredOn; message.AgsresultAttributes.Add(observedOn); AgsresultAttributes receivedOn = NewResultAttribute(Constants.Attribute.ReceivedOn, sample.ResultAttributeId); receivedOn.Value = specimen.ReceivedTime; message.AgsresultAttributes.Add(receivedOn); AgsresultAttributes collectedOn = NewResultAttribute(Constants.Attribute.CollectionDate, sample.ResultAttributeId); collectedOn.Value = ((FhirDateTime)specimen.Collection.Collected).ToString(); message.AgsresultAttributes.Add(collectedOn); //var tmp = client.SearchById("PlanDefinition", serviceRequest.InstantiatesCanonical.First()); //var tmp2 = client.SearchById("PlanDefinition", serviceRequest.InstantiatesCanonical.First().Replace("urn:uuid:", "")); //var planDefinition = (PlanDefinition)client.Get(serviceRequest.InstantiatesCanonical.First()); //if (planDefinition == null) { // throw new FHIRGenomicsException("Failed to retrieve a PlanDefinition resource from the ServiceRequest"); //} //var methodBuilder = new StringBuilder(); //foreach (var action in planDefinition.Action) { // methodBuilder.AppendLine(action.Description); //} //AgsresultAttributes method = NewResultAttribute(Constants.Attribute.MethodDescription, sample.ResultAttributeId); //method.Value = methodBuilder.ToString(); //message.AgsresultAttributes.Add(method); context.SaveChanges(); foreach (var pgxObservation in pgxObservations) { AgsresultAttributes pgxResult = NewResultAttribute(Constants.Attribute.PGxResult, sample.ResultAttributeId); pgxResult.Value = string.Empty; message.AgsresultAttributes.Add(pgxResult); context.SaveChanges(); if (pgxObservation.DerivedFrom == null) { throw new FHIRGenomicsException("Expected exactly one DerivedFrom entry, but none were found"); } foreach (var geneDerivation in pgxObservation.DerivedFrom) { var geneObservation = (Observation)client.Get(geneDerivation.Url); AgsresultAttributes gene = NewResultAttribute(Constants.Attribute.GeneSymbol, pgxResult.ResultAttributeId); gene.Value = ((CodeableConcept)geneObservation.Component[0].Value).Coding[0].Display; message.AgsresultAttributes.Add(gene); AgsresultAttributes diplotype = NewResultAttribute(Constants.Attribute.PGxDiplotype, pgxResult.ResultAttributeId); diplotype.Value = ((CodeableConcept)geneObservation.Value).Text; message.AgsresultAttributes.Add(diplotype); } AgsresultAttributes phenotype = NewResultAttribute(Constants.Attribute.PGxPhenotype, pgxResult.ResultAttributeId); var pgxPhenotypeConcept = ((CodeableConcept)pgxObservation.Value); if (((CodeableConcept)pgxObservation.Value).Coding.Count == 0) { phenotype.Value = pgxPhenotypeConcept.Text; } else { phenotype.Value = pgxPhenotypeConcept.Coding[0].Display; } message.AgsresultAttributes.Add(phenotype); AgsresultAttributes variantInterpretation = NewResultAttribute(Constants.Attribute.VariantInterpretation, pgxResult.ResultAttributeId); variantInterpretation.Value = pgxObservation.GetExtensionValue <Element>(Constants.HGSCExtension.InterpretationSummaryText).ToString(); message.AgsresultAttributes.Add(variantInterpretation); foreach (var pgxMed in pgxObservation.Component) { AgsresultAttributes pgxMedication = NewResultAttribute(Constants.Attribute.PGxAssociatedMedication, pgxResult.ResultAttributeId); pgxMedication.Value = ((CodeableConcept)pgxMed.Value).Coding[0].Display; message.AgsresultAttributes.Add(pgxMedication); context.SaveChanges(); AgsresultAttributes pgxRecommendation = NewResultAttribute(Constants.Attribute.PGxAssociatedRecommendation, pgxMedication.ResultAttributeId); pgxRecommendation.Value = pgxMed.GetExtensionValue <RelatedArtifact>(Constants.HGSCExtension.RelatedArtifact).Url; message.AgsresultAttributes.Add(pgxRecommendation); } context.SaveChanges(); } }