From 270abdc7afc6817397913e4a4d78c005dac7ed18 Mon Sep 17 00:00:00 2001 From: Jason Kulatunga Date: Thu, 22 Sep 2022 22:32:20 -0700 Subject: [PATCH] adding a generalpurpose GetResourceBundle method. adding tests for cerner. --- backend/pkg/hub/internal/fhir/aetna/client.go | 10 +--- .../hub/internal/fhir/base/fhir401_client.go | 18 +++++-- .../pkg/hub/internal/fhir/cerner/client.go | 54 ++++++++++++++----- .../hub/internal/fhir/cerner/client_test.go | 48 +++++++++++++++++ 4 files changed, 104 insertions(+), 26 deletions(-) create mode 100644 backend/pkg/hub/internal/fhir/cerner/client_test.go diff --git a/backend/pkg/hub/internal/fhir/aetna/client.go b/backend/pkg/hub/internal/fhir/aetna/client.go index 696a40cf..8e350d16 100644 --- a/backend/pkg/hub/internal/fhir/aetna/client.go +++ b/backend/pkg/hub/internal/fhir/aetna/client.go @@ -6,7 +6,6 @@ import ( "github.com/fastenhealth/fastenhealth-onprem/backend/pkg/database" "github.com/fastenhealth/fastenhealth-onprem/backend/pkg/hub/internal/fhir/base" "github.com/fastenhealth/fastenhealth-onprem/backend/pkg/models" - "github.com/fastenhealth/gofhir-models/fhir401" "github.com/sirupsen/logrus" "net/http" ) @@ -23,17 +22,10 @@ func NewClient(ctx context.Context, appConfig config.Interface, globalLogger log } //Overrides -func (c AetnaClient) GetPatientBundle(patientId string) (fhir401.Bundle, error) { - - bundle := fhir401.Bundle{} - err := c.GetRequest("Patient", &bundle) - return bundle, err - -} func (c AetnaClient) SyncAll(db database.DatabaseRepository) error { - bundle, err := c.GetPatientBundle(c.Source.PatientId) + bundle, err := c.GetResourceBundle("Patient") if err != nil { c.Logger.Infof("An error occurred while getting patient bundle %s", c.Source.PatientId) return err diff --git a/backend/pkg/hub/internal/fhir/base/fhir401_client.go b/backend/pkg/hub/internal/fhir/base/fhir401_client.go index 84ff4674..b278e436 100644 --- a/backend/pkg/hub/internal/fhir/base/fhir401_client.go +++ b/backend/pkg/hub/internal/fhir/base/fhir401_client.go @@ -27,25 +27,28 @@ func NewFHIR401Client(ctx context.Context, appConfig config.Interface, globalLog //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // FHIR //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -func (c *FHIR401Client) GetPatientBundle(patientId string) (fhir401.Bundle, error) { +func (c *FHIR401Client) GetResourceBundle(relativeResourcePath string) (fhir401.Bundle, error) { // https://www.hl7.org/fhir/patient-operation-everything.html bundle := fhir401.Bundle{} - err := c.GetRequest(fmt.Sprintf("Patient/%s/$everything", patientId), &bundle) + err := c.GetRequest(relativeResourcePath, &bundle) if err != nil { return bundle, err } var next string + var prev string var self string for _, link := range bundle.Link { if link.Relation == "next" { next = link.Url } else if link.Relation == "self" { self = link.Url + } else if link.Relation == "previous" { + prev = link.Url } } - for len(next) > 0 && next != self { + for len(next) > 0 && next != self && next != prev { c.Logger.Debugf("Paginated request => %s", next) nextBundle := fhir401.Bundle{} err := c.GetRequest(next, &nextBundle) @@ -54,13 +57,16 @@ func (c *FHIR401Client) GetPatientBundle(patientId string) (fhir401.Bundle, erro } bundle.Entry = append(bundle.Entry, nextBundle.Entry...) - next = "" //reset the next pointer + next = "" //reset the pointers self = "" + prev = "" for _, link := range nextBundle.Link { if link.Relation == "next" { next = link.Url } else if link.Relation == "self" { self = link.Url + } else if link.Relation == "previous" { + prev = link.Url } } } @@ -69,6 +75,10 @@ func (c *FHIR401Client) GetPatientBundle(patientId string) (fhir401.Bundle, erro } +func (c *FHIR401Client) GetPatientBundle(patientId string) (fhir401.Bundle, error) { + return c.GetResourceBundle(fmt.Sprintf("Patient/%s/$everything", patientId)) +} + func (c *FHIR401Client) GetPatient(patientId string) (fhir401.Patient, error) { patient := fhir401.Patient{} diff --git a/backend/pkg/hub/internal/fhir/cerner/client.go b/backend/pkg/hub/internal/fhir/cerner/client.go index d6314b89..bf031f68 100644 --- a/backend/pkg/hub/internal/fhir/cerner/client.go +++ b/backend/pkg/hub/internal/fhir/cerner/client.go @@ -2,6 +2,7 @@ package cerner import ( "context" + "fmt" "github.com/fastenhealth/fastenhealth-onprem/backend/pkg/config" "github.com/fastenhealth/fastenhealth-onprem/backend/pkg/database" "github.com/fastenhealth/fastenhealth-onprem/backend/pkg/hub/internal/fhir/base" @@ -23,23 +24,50 @@ func NewClient(ctx context.Context, appConfig config.Interface, globalLogger log func (c CernerClient) SyncAll(db database.DatabaseRepository) error { - bundle, err := c.GetPatientBundle(c.Source.PatientId) - if err != nil { - return err + supportedResources := []string{ + "AllergyIntolerance", + "CarePlan", + "CareTeam", + "Condition", + "Consent", + "Device", + "Encounter", + "FamilyMemberHistory", + "Goal", + "Immunization", + "InsurancePlan", + "MedicationRequest", + "NutritionOrder", + "Observation", + "Person", + "Procedure", + "Provenance", + "Questionnaire", + "QuestionnaireResponse", + "RelatedPerson", + "Schedule", + "ServiceRequest", + "Slot", } - - wrappedResourceModels, err := c.ProcessBundle(bundle) - if err != nil { - c.Logger.Infof("An error occurred while processing patient bundle %s", c.Source.PatientId) - return err - } - //todo, create the resources in dependency order - - for _, apiModel := range wrappedResourceModels { - err = db.UpsertResource(context.Background(), apiModel) + for _, resourceType := range supportedResources { + bundle, err := c.GetResourceBundle(fmt.Sprintf("%s?patient=%s", resourceType, c.Source.PatientId)) if err != nil { + continue //TODO: skippping failures in the resource retrival + } + wrappedResourceModels, err := c.ProcessBundle(bundle) + if err != nil { + c.Logger.Infof("An error occurred while processing %s bundle %s", resourceType, c.Source.PatientId) return err } + //todo, create the resources in dependency order + + for _, apiModel := range wrappedResourceModels { + err = db.UpsertResource(context.Background(), apiModel) + if err != nil { + return err + } + } } + return nil } diff --git a/backend/pkg/hub/internal/fhir/cerner/client_test.go b/backend/pkg/hub/internal/fhir/cerner/client_test.go new file mode 100644 index 00000000..3e706b3f --- /dev/null +++ b/backend/pkg/hub/internal/fhir/cerner/client_test.go @@ -0,0 +1,48 @@ +package cerner + +import ( + "context" + mock_config "github.com/fastenhealth/fastenhealth-onprem/backend/pkg/config/mock" + "github.com/fastenhealth/fastenhealth-onprem/backend/pkg/database" + "github.com/fastenhealth/fastenhealth-onprem/backend/pkg/hub/internal/fhir/base" + "github.com/fastenhealth/fastenhealth-onprem/backend/pkg/models" + "github.com/golang/mock/gomock" + "github.com/sirupsen/logrus" + "github.com/stretchr/testify/require" + "io/ioutil" + "os" + "testing" +) + +func TestCernerClient_SyncAll(t *testing.T) { + t.Parallel() + //setup + mockCtrl := gomock.NewController(t) + defer mockCtrl.Finish() + fakeConfig := mock_config.NewMockInterface(mockCtrl) + + testDatabase, err := ioutil.TempFile("testdata", "fasten.db") + require.NoError(t, err) + defer os.Remove(testDatabase.Name()) + fakeConfig.EXPECT().GetString("web.database.location").AnyTimes().Return(testDatabase.Name()) + testLogger := logrus.WithFields(logrus.Fields{ + "type": "test", + }) + httpClient := base.OAuthVcrSetup(t, false) + client, _, err := NewClient(context.Background(), fakeConfig, testLogger, models.Source{ + SourceType: "cerner", + PatientId: "12724066", + ApiEndpointBaseUrl: "https://fhir-myrecord.cerner.com/r4/ec2458f2-1e24-41c8-b71b-0e701af7583d", + ClientId: "89efc22c-e879-4c02-a423-c3b98a0117a3", + }, httpClient) + + db, err := database.NewRepository(fakeConfig, testLogger) + require.NoError(t, err) + + //test + err = client.SyncAll(db) + require.NoError(t, err) + + //assert + require.NoError(t, err) +}