fixing composite unique index (when embedded the index is not unique).
creating a lookup table for retrieving Resource references (and generated UUIDs). Adding organization processing.
This commit is contained in:
parent
9902daa75d
commit
79755d8e8b
|
@ -9,8 +9,9 @@ type DatabaseRepository interface {
|
|||
Close() error
|
||||
GetCurrentUser() models.User
|
||||
|
||||
UpsertProfile(ctx context.Context, profile models.Profile) error
|
||||
UpsertProfile(context.Context, *models.Profile) error
|
||||
UpsertOrganziation(context.Context, *models.Organization) error
|
||||
|
||||
CreateSource(ctx context.Context, providerCreds *models.Source) error
|
||||
GetSources(ctx context.Context) ([]models.Source, error)
|
||||
CreateSource(context.Context, *models.Source) error
|
||||
GetSources(context.Context) ([]models.Source, error)
|
||||
}
|
||||
|
|
|
@ -47,6 +47,7 @@ func NewRepository(appConfig config.Interface, globalLogger logrus.FieldLogger)
|
|||
&models.User{},
|
||||
&models.Source{},
|
||||
&models.Profile{},
|
||||
&models.Organization{},
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Failed to automigrate! - %v", err)
|
||||
|
@ -86,15 +87,28 @@ func (sr *sqliteRepository) GetCurrentUser() models.User {
|
|||
}
|
||||
|
||||
// UpsertSourceResource Create or Update record in database
|
||||
func (sr *sqliteRepository) UpsertProfile(ctx context.Context, profile models.Profile) error {
|
||||
if sr.gormClient.Debug().WithContext(ctx).Model(&profile).
|
||||
func (sr *sqliteRepository) UpsertProfile(ctx context.Context, profile *models.Profile) error {
|
||||
if sr.gormClient.Debug().WithContext(ctx).Model(profile).
|
||||
Where(models.OriginBase{
|
||||
SourceID: profile.GetSourceID(),
|
||||
SourceResourceID: profile.GetSourceResourceID(),
|
||||
SourceResourceType: profile.GetSourceResourceType(), //TODO: and UpdatedAt > old UpdatedAt
|
||||
}).Updates(&profile).RowsAffected == 0 {
|
||||
}).Updates(profile).RowsAffected == 0 {
|
||||
sr.logger.Infof("profile does not exist, creating: %s %s %s", profile.GetSourceID(), profile.GetSourceResourceID(), profile.GetSourceResourceType())
|
||||
return sr.gormClient.Debug().Create(&profile).Error
|
||||
return sr.gormClient.Debug().Create(profile).Error
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (sr *sqliteRepository) UpsertOrganziation(ctx context.Context, org *models.Organization) error {
|
||||
if sr.gormClient.Debug().WithContext(ctx).Model(org).
|
||||
Where(models.OriginBase{
|
||||
SourceID: org.GetSourceID(),
|
||||
SourceResourceID: org.GetSourceResourceID(),
|
||||
SourceResourceType: org.GetSourceResourceType(), //TODO: and UpdatedAt > old UpdatedAt
|
||||
}).Updates(org).RowsAffected == 0 {
|
||||
sr.logger.Infof("org does not exist, creating: %s %s %s", org.GetSourceID(), org.GetSourceResourceID(), org.GetSourceResourceType())
|
||||
return sr.gormClient.Debug().Create(org).Error
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -107,3 +107,39 @@ func (c *FHIR401Client) ProcessPatients(patients []fhir401.Patient) ([]models.Pr
|
|||
|
||||
return profiles, nil
|
||||
}
|
||||
|
||||
func (c *FHIR401Client) ProcessOrganizations(orgs []fhir401.Organization) ([]models.Organization, error) {
|
||||
apiOrganizations := []models.Organization{}
|
||||
for _, org := range orgs {
|
||||
apiOrganization := models.Organization{
|
||||
OriginBase: models.OriginBase{
|
||||
ModelBase: models.ModelBase{},
|
||||
UserID: c.Source.UserID,
|
||||
SourceID: c.Source.ID,
|
||||
SourceResourceID: *org.Id,
|
||||
SourceResourceType: fhir401.ResourceTypeOrganization.Code(),
|
||||
},
|
||||
Address: models.Address{},
|
||||
}
|
||||
|
||||
if org.Meta != nil && org.Meta.LastUpdated != nil {
|
||||
if parsed, err := time.Parse(time.RFC3339, *org.Meta.LastUpdated); err == nil {
|
||||
apiOrganization.UpdatedAt = parsed
|
||||
}
|
||||
}
|
||||
|
||||
if org.Address != nil && len(org.Address) > 0 {
|
||||
itemAddress := org.Address[0]
|
||||
apiOrganization.Address.City = itemAddress.City
|
||||
apiOrganization.Address.Country = itemAddress.Country
|
||||
apiOrganization.Address.State = itemAddress.State
|
||||
apiOrganization.Address.Street = itemAddress.Line
|
||||
apiOrganization.Address.Zip = itemAddress.PostalCode
|
||||
}
|
||||
apiOrganization.Name = org.Name
|
||||
apiOrganization.Active = org.Active
|
||||
|
||||
apiOrganizations = append(apiOrganizations, apiOrganization)
|
||||
}
|
||||
return apiOrganizations, nil
|
||||
}
|
||||
|
|
|
@ -2,12 +2,14 @@ package cigna
|
|||
|
||||
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"
|
||||
"github.com/fastenhealth/fastenhealth-onprem/backend/pkg/models"
|
||||
"github.com/fastenhealth/gofhir-models/fhir401"
|
||||
fhirutils "github.com/fastenhealth/gofhir-models/fhir401/utils"
|
||||
"github.com/google/uuid"
|
||||
"github.com/sirupsen/logrus"
|
||||
"net/http"
|
||||
)
|
||||
|
@ -36,6 +38,8 @@ func (c CignaClient) SyncAll(db database.DatabaseRepository) error {
|
|||
resources = append(resources, resource)
|
||||
}
|
||||
|
||||
resourceRefLookup := map[string]uuid.UUID{}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Patient
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
@ -45,17 +49,35 @@ func (c CignaClient) SyncAll(db database.DatabaseRepository) error {
|
|||
patientResources = append(patientResources, patient)
|
||||
}
|
||||
}
|
||||
patientProfiles, err := c.ProcessPatients(patientResources)
|
||||
for _, profile := range patientProfiles {
|
||||
err = db.UpsertProfile(context.Background(), profile)
|
||||
apiProfiles, err := c.ProcessPatients(patientResources)
|
||||
for _, profile := range apiProfiles {
|
||||
err = db.UpsertProfile(context.Background(), &profile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
//add upserted resource uuids to lookup
|
||||
resourceRefLookup[fmt.Sprintf("%s/%s", profile.SourceResourceType, profile.SourceResourceID)] = profile.ID
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Patient
|
||||
// Organization
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
organizations := []fhir401.Organization{}
|
||||
for _, resource := range resources {
|
||||
if org, isOrganization := resource.(fhir401.Organization); isOrganization {
|
||||
organizations = append(organizations, org)
|
||||
}
|
||||
}
|
||||
apiOrgs, err := c.ProcessOrganizations(organizations)
|
||||
for _, apiOrg := range apiOrgs {
|
||||
err = db.UpsertOrganziation(context.Background(), &apiOrg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
//add upserted resource uuids to lookup
|
||||
resourceRefLookup[fmt.Sprintf("%s/%s", apiOrg.SourceResourceType, apiOrg.SourceResourceID)] = apiOrg.ID
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -26,10 +26,10 @@ type OriginBase struct {
|
|||
UserID uuid.UUID `json:"user_id"`
|
||||
|
||||
Source Source `json:"source" gorm:"-"`
|
||||
SourceID uuid.UUID `json:"source_id" gorm:"not null;uniqueIndex:idx_source_resource_id"`
|
||||
SourceID uuid.UUID `json:"source_id" gorm:"not null;index:,unique,composite:source_resource_id"`
|
||||
|
||||
SourceResourceType string `json:"source_resource_type" gorm:"not null;uniqueIndex:idx_source_resource_id"`
|
||||
SourceResourceID string `json:"source_resource_id" gorm:"not null;uniqueIndex:idx_source_resource_id"`
|
||||
SourceResourceType string `json:"source_resource_type" gorm:"not null;index:,unique,composite:source_resource_id"`
|
||||
SourceResourceID string `json:"source_resource_id" gorm:"not null;index:,unique,composite:source_resource_id"`
|
||||
}
|
||||
|
||||
func (o OriginBase) GetSourceID() uuid.UUID {
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
package models
|
||||
|
||||
import "time"
|
||||
|
||||
// https://reference.humanapi.co/reference/encounters
|
||||
type Encounter struct {
|
||||
OriginBase
|
||||
|
||||
DateTime time.Time `json:"time,omitempty"` //dateTime Date (optional) The date of the encounter
|
||||
VisitType *string `json:"visitType,omitempty"` // visitType String (optional) The type of visit
|
||||
Provider Provider `json:"provider,omitempty" gorm:"serializer:json;default:'{}'"` // provider Object (optional) The provider for the encounter (see provider object)
|
||||
//Prescriptions []Prescription `json:"prescriptions,omitempty"` // prescriptions Array[Object] (optional) A list of prescriptions provided during the encounter (see link object)
|
||||
//Diagnoses []Diagnosis `json:"diagnoses,omitempty"` // diagnoses Array[Object] (optional) A list of diagnoses for the encounter where object contains a "name" field e.g. *[{"name": "Sacroiliac dysfunction"}, {"name": "Bilateral hand pain"}]
|
||||
//vitals Object (optional) Vitals captured during the encounter (e.g. {"temperature" : 95.2 [degF]","weight" : 180 [lb_av]","height" : "69 [in_us]"})
|
||||
//vitalSigns Array[Object] (optional) A list of vital signs from the encounter (see link object)
|
||||
Reasons []string `json:"reasons,omitempty"` // reasons Array[String] (optional) A list of reasons for the encounter (e.g. [‘Follow-up’, 'Consult’, 'DYSPHONIA', 'Back Pain’])
|
||||
Orders []Order `json:"orders,omitempty" gorm:"serializer:json;default:'{}'"` // orders Array[Object] (optional) A list of medication orders for the patient (see orders object)
|
||||
//testResults Array[Object] (optional) A list of test results for the patient (see link object)
|
||||
//plansOfCare Array[Object] (optional) A list of plans of care from the encounter (see link object)
|
||||
//medications Array[Object] (optional) A list of medications used by the patient. Objects in array can have some or many of the properties of medications. Common properties are "name", "productName", "startDate", "endDate", "instructions".
|
||||
FollowUpInstructions *string `json:"followUpInstructions,omitempty"` // followUpInstructions String (optional) Follow-up instructions
|
||||
//Organization Organization `json:"organization,omitempty"` // organization Object (optional) (See organizations object)
|
||||
//codes Array[Object] (optional) (See codes)
|
||||
}
|
||||
|
||||
type Order struct {
|
||||
Name *string `json:"name,omitempty"` // name String (optional) The name of the order
|
||||
CodeType *string `json:"codeType,omitempty"` // codeType String (optional) The code type of the order (e.g. “CPT( R )”, “Custom”)
|
||||
ExpectedDate time.Time `json:"expectedDate,omitempty"` // expectedDate Date (optional) The date the order is expected
|
||||
ExpireDate time.Time `json:"expireDate,omitempty"` // expireDate Date (optional) The date the order expires
|
||||
ProcedureCode *string `json:"procedureCode,omitempty"` // procedureCode String (optional) The procedure code of the order
|
||||
OrderType *string `json:"type,omitempty"` // type String (optional) The type of the order (e.g. “Lab”, “Procedures”)
|
||||
//Name string `codes:"codes,omitempty"` // codes Array[Object] (optional) (See codes)
|
||||
}
|
||||
|
||||
type Provider struct {
|
||||
Name *string `json:"name,omitempty"` //name String (optional) Name of the provider
|
||||
DepartmentName *string `json:"departmentName,omitempty"` //departmentName String (optional) Name of the provider department
|
||||
Address *string `json:"address,omitempty"` //address String (optional) Address of the provider
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
package models
|
||||
|
||||
type Organization struct {
|
||||
OriginBase
|
||||
|
||||
Name *string `json:"name,omitempty"` //name String (optional) The name of the organization
|
||||
Address Address `json:"address,omitempty" gorm:"serializer:json;default:'{}'"` //address String (optional) Address of the provider
|
||||
Active *bool `json:"active,omitempty"`
|
||||
}
|
Loading…
Reference in New Issue