Skip to content

Commit

Permalink
refactor: fetch risk assessment 'risk level'
Browse files Browse the repository at this point in the history
- Gets the patients risk level with the provided encounter id and the type of screening

Signed-off-by: Kathurima Kimathi <kathurimakimathi415@gmail.com>
  • Loading branch information
KathurimaKimathi committed Feb 14, 2024
1 parent 1294108 commit 9adb0f5
Show file tree
Hide file tree
Showing 8 changed files with 147 additions and 37 deletions.
65 changes: 65 additions & 0 deletions pkg/clinical/domain/complex_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -3126,3 +3126,68 @@ func (e *DiagnosticReportStatusEnum) UnmarshalGQL(v interface{}) error {
func (e DiagnosticReportStatusEnum) MarshalGQL(w io.Writer) {
fmt.Fprint(w, strconv.Quote(e.String()))
}

// ScreeningTypeEnum is used to define the type of Screening
type ScreeningTypeEnum string

const (
// CervicalCancerScreeningTypeEnum is cervical Screening type
CervicalCancerScreeningTypeEnum ScreeningTypeEnum = "CERVICAL_CANCER_SCREENING"

// BreastCancerScreeningTypeEnum is represents the breast Screening type
BreastCancerScreeningTypeEnum ScreeningTypeEnum = "BREAST_CANCER_SCREENING"
)

// AllScreeningTypeEnum is a list of all possible Screening types
var AllScreeningTypeEnum = []ScreeningTypeEnum{
CervicalCancerScreeningTypeEnum,
BreastCancerScreeningTypeEnum,
}

// IsValid ...
func (e ScreeningTypeEnum) IsValid() bool {
switch e {
case CervicalCancerScreeningTypeEnum,
BreastCancerScreeningTypeEnum:
return true
}

return false
}

// String ...
func (e ScreeningTypeEnum) String() string {
return string(e)
}

// UnmarshalGQL ...
func (e *ScreeningTypeEnum) UnmarshalGQL(v interface{}) error {
str, ok := v.(string)
if !ok {
return fmt.Errorf("enums must be strings")
}

*e = ScreeningTypeEnum(str)
if !e.IsValid() {
return fmt.Errorf("%s is not a valid Screening type enum", str)
}

return nil
}

// MarshalGQL writes the Screening type to the supplied writer as a quoted string
func (e ScreeningTypeEnum) MarshalGQL(w io.Writer) {
fmt.Fprint(w, strconv.Quote(e.String()))
}

// Text returns a human friendly representation of the screening type
func (screeningType ScreeningTypeEnum) Text() string {
switch screeningType {
case BreastCancerScreeningTypeEnum:
return "Breast Cancer Screening"
case CervicalCancerScreeningTypeEnum:
return "Cervical Cancer Screening"
}

return "unknown screening type"
}
2 changes: 1 addition & 1 deletion pkg/clinical/presentation/graph/clinical.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ extend type Query {
pagination: Pagination!
): QuestionnaireConnection!

getQuestionnaireResponseRiskLevel(questionnaireResponseID: String!): String!
getQuestionnaireResponseRiskLevel(encounterID: String!, screeningType: ScreeningTypeEnum!): String!
}

extend type Mutation {
Expand Down
5 changes: 3 additions & 2 deletions pkg/clinical/presentation/graph/clinical.resolvers.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions pkg/clinical/presentation/graph/enums.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -121,3 +121,8 @@ enum QuantityComparatorEnum{
enum QuestionnaireResponseStatusEnum{
completed
}

enum ScreeningTypeEnum{
BREAST_CANCER_SCREENING
CERVICAL_CANCER_SCREENING
}
42 changes: 33 additions & 9 deletions pkg/clinical/presentation/graph/generated/generated.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

28 changes: 19 additions & 9 deletions pkg/clinical/usecases/clinical/questionnaire_response.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ func (u *UseCasesClinicalImpl) CreateQuestionnaireResponse(ctx context.Context,
return "", fmt.Errorf("cannot create a questionnaire response in a finished encounter")
}

// TODO: Ensure user cannot submit the same risk assessment twice in the same encounter

patientID := encounter.Resource.Subject.ID
patientReference := fmt.Sprintf("Patient/%s", *patientID)

Expand Down Expand Up @@ -141,6 +143,7 @@ func (u *UseCasesClinicalImpl) generateQuestionnaireReviewSummary(
questionnaireResponseID,
common.HighRiskCIELCode,
"High Risk",
domain.CervicalCancerScreeningTypeEnum.Text(), // TODO: This is TEMPORARY. A follow up PR is to follow supplying the value from params
)
if err != nil {
return "", err
Expand All @@ -153,6 +156,7 @@ func (u *UseCasesClinicalImpl) generateQuestionnaireReviewSummary(
questionnaireResponseID,
common.LowRiskCIELCode,
"Low Risk",
domain.CervicalCancerScreeningTypeEnum.Text(),
)
if err != nil {
return "", err
Expand All @@ -168,8 +172,8 @@ func (u *UseCasesClinicalImpl) generateQuestionnaireReviewSummary(
func (u *UseCasesClinicalImpl) recordRiskAssessment(
ctx context.Context,
encounter *domain.FHIREncounterRelayPayload,
questionnaireResponseID string,
outcomeCode, outcomeDisplay string,
questionnaireResponseID, outcomeCode string,
outcomeDisplay, usageContext string,
) (string, error) {
CIELTerminologySystem := scalarutils.URI(common.CIELTerminologySystem)
codingCode := scalarutils.Code(outcomeCode)
Expand All @@ -194,6 +198,7 @@ func (u *UseCasesClinicalImpl) recordRiskAssessment(

instant := scalarutils.Instant(time.Now().Format(time.RFC3339))

textStatus := domain.NarrativeStatusEnumAdditional
riskAssessment := domain.FHIRRiskAssessmentInput{
Status: domain.ObservationStatusEnumFinal,
Code: &domain.FHIRCodeableConceptInput{},
Expand All @@ -218,6 +223,10 @@ func (u *UseCasesClinicalImpl) recordRiskAssessment(
Reference: &questionnaireResponseReference,
},
},
Text: &domain.FHIRNarrativeInput{
Status: &textStatus,
Div: scalarutils.XHTML(usageContext),
},
}

tags, err := u.GetTenantMetaTags(ctx)
Expand All @@ -241,20 +250,21 @@ func (u *UseCasesClinicalImpl) recordRiskAssessment(

// GetQuestionnaireResponseRiskLevel fetches the risk level associated with a questionnaire response. This is based off the scoring
// of the questionnaire response. Outcome: High Risk / Low Risk
func (u *UseCasesClinicalImpl) GetQuestionnaireResponseRiskLevel(ctx context.Context, questionnaireResponseID string) (string, error) {
questionnaireResponse, err := u.infrastructure.FHIR.GetFHIRQuestionnaireResponse(ctx, questionnaireResponseID)
func (u *UseCasesClinicalImpl) GetQuestionnaireResponseRiskLevel(ctx context.Context, encounterID string, screeningType domain.ScreeningTypeEnum) (string, error) {
encounter, err := u.infrastructure.FHIR.GetFHIREncounter(ctx, encounterID)
if err != nil {
return "", err
}

encounterReference := questionnaireResponse.Resource.Encounter.Reference
patientReference := questionnaireResponse.Resource.Source.Reference
patientID := encounter.Resource.Subject.ID
encounterReference := fmt.Sprintf("Encounter/%s", *encounter.Resource.ID)
patientReference := fmt.Sprintf("Patient/%s", *patientID)

riskAssessmentSearchParams := map[string]interface{}{
"patient": *patientReference,
"encounter": *encounterReference,
"patient": patientReference,
"encounter": encounterReference,
"_text": screeningType.Text(),
"_sort": "date",
"_count": "1",
}

identifiers, err := u.infrastructure.BaseExtension.GetTenantIdentifiers(ctx)
Expand Down
35 changes: 20 additions & 15 deletions pkg/clinical/usecases/clinical/questionnaire_response_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -360,8 +360,9 @@ func TestUseCasesClinicalImpl_CreateQuestionnaireResponse(t *testing.T) {
func TestUseCasesClinicalImpl_GetQuestionnaireResponseRiskLevel(t *testing.T) {
ctx := context.Background()
type args struct {
ctx context.Context
questionnaireResponseID string
ctx context.Context
encounterID string
screeningType domain.ScreeningTypeEnum
}
tests := []struct {
name string
Expand All @@ -372,32 +373,36 @@ func TestUseCasesClinicalImpl_GetQuestionnaireResponseRiskLevel(t *testing.T) {
{
name: "Happy Case - Successfully get risk level",
args: args{
ctx: ctx,
questionnaireResponseID: gofakeit.UUID(),
ctx: ctx,
encounterID: gofakeit.UUID(),
screeningType: domain.CervicalCancerScreeningTypeEnum,
},
wantErr: false,
},
{
name: "Sad Case - Fail to get fhir questionnaire response",
name: "Sad Case - Fail to get fhir encounter",
args: args{
ctx: ctx,
questionnaireResponseID: gofakeit.UUID(),
ctx: ctx,
encounterID: gofakeit.UUID(),
screeningType: domain.CervicalCancerScreeningTypeEnum,
},
wantErr: true,
},
{
name: "Sad Case - Fail to get tenant identifiers",
args: args{
ctx: ctx,
questionnaireResponseID: gofakeit.UUID(),
ctx: ctx,
encounterID: gofakeit.UUID(),
screeningType: domain.CervicalCancerScreeningTypeEnum,
},
wantErr: true,
},
{
name: "Sad Case - Fail to search risk assessment",
args: args{
ctx: ctx,
questionnaireResponseID: gofakeit.UUID(),
ctx: ctx,
encounterID: gofakeit.UUID(),
screeningType: domain.CervicalCancerScreeningTypeEnum,
},
wantErr: true,
},
Expand All @@ -414,9 +419,9 @@ func TestUseCasesClinicalImpl_GetQuestionnaireResponseRiskLevel(t *testing.T) {
infra := infrastructure.NewInfrastructureInteractor(fakeExt, fakeFHIR, fakeOCL, fakeUpload, fakePubSub)
u := clinicalUsecase.NewUseCasesClinicalImpl(infra)

if tt.name == "Sad Case - Fail to get fhir questionnaire response" {
fakeFHIR.MockGetFHIRQuestionnaireResponseFn = func(ctx context.Context, id string) (*domain.FHIRQuestionnaireResponseRelayPayload, error) {
return nil, fmt.Errorf("failed to get questionnaire response")
if tt.name == "Sad Case - Fail to get fhir encounter" {
fakeFHIR.MockGetFHIREncounterFn = func(ctx context.Context, id string) (*domain.FHIREncounterRelayPayload, error) {
return nil, fmt.Errorf("failed to get encounter")
}
}

Expand All @@ -432,7 +437,7 @@ func TestUseCasesClinicalImpl_GetQuestionnaireResponseRiskLevel(t *testing.T) {
}
}

got, err := u.GetQuestionnaireResponseRiskLevel(tt.args.ctx, tt.args.questionnaireResponseID)
got, err := u.GetQuestionnaireResponseRiskLevel(tt.args.ctx, tt.args.encounterID, tt.args.screeningType)
if (err != nil) != tt.wantErr {
t.Errorf("UseCasesClinicalImpl.GetQuestionnaireResponseRiskLevel() error = %v, wantErr %v", err, tt.wantErr)
return
Expand Down
2 changes: 1 addition & 1 deletion pkg/clinical/usecases/usecases.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ type Clinical interface {
ListQuestionnaires(ctx context.Context, searchParam *string, pagination *dto.Pagination) (*dto.QuestionnaireConnection, error)
RecordConsent(ctx context.Context, input dto.ConsentInput) (*dto.ConsentOutput, error)

GetQuestionnaireResponseRiskLevel(ctx context.Context, questionnaireResponseID string) (string, error)
GetQuestionnaireResponseRiskLevel(ctx context.Context, encounterID string, screeningType domain.ScreeningTypeEnum) (string, error)
RecordMammographyResult(ctx context.Context, input dto.DiagnosticReportInput) (*dto.DiagnosticReport, error)
}

Expand Down

0 comments on commit 9adb0f5

Please sign in to comment.