diff --git a/pkg/clinical/application/dto/allergy_output.go b/pkg/clinical/application/dto/allergy_output.go index 671bf551..1a3951d4 100644 --- a/pkg/clinical/application/dto/allergy_output.go +++ b/pkg/clinical/application/dto/allergy_output.go @@ -36,7 +36,7 @@ type AllergyConnection struct { PageInfo PageInfo } -// CreateConditionConnection creates a connection that follows the GraphQl Cursor Connection Specification +// CreateAllergyConnection creates a connection that follows the GraphQl Cursor Connection Specification func CreateAllergyConnection(allergies []*Allergy, pageInfo PageInfo, total int) AllergyConnection { connection := AllergyConnection{ TotalCount: total, diff --git a/pkg/clinical/application/dto/composition_output.go b/pkg/clinical/application/dto/composition_output.go index 170b89e5..4c13bd0d 100644 --- a/pkg/clinical/application/dto/composition_output.go +++ b/pkg/clinical/application/dto/composition_output.go @@ -30,7 +30,7 @@ type CompositionConnection struct { PageInfo PageInfo } -// CreateConditionConnection creates a connection that follows the GraphQl Cursor Connection Specification +// CreateCompositionConnection creates a connection that follows the GraphQl Cursor Connection Specification func CreateCompositionConnection(compositions []Composition, pageInfo PageInfo, total int) CompositionConnection { connection := CompositionConnection{ TotalCount: total, diff --git a/pkg/clinical/application/dto/observation_output.go b/pkg/clinical/application/dto/observation_output.go index 2ac6281b..40df725a 100644 --- a/pkg/clinical/application/dto/observation_output.go +++ b/pkg/clinical/application/dto/observation_output.go @@ -24,7 +24,7 @@ type ObservationConnection struct { PageInfo PageInfo } -// CreateConditionConnection creates a connection that follows the GraphQl Cursor Connection Specification +// CreateObservationConnection creates a connection that follows the GraphQl Cursor Connection Specification func CreateObservationConnection(observations []*Observation, pageInfo PageInfo, total int) ObservationConnection { connection := ObservationConnection{ TotalCount: total, diff --git a/pkg/clinical/domain/composition.go b/pkg/clinical/domain/composition.go index 4f43a20a..dbd11f41 100644 --- a/pkg/clinical/domain/composition.go +++ b/pkg/clinical/domain/composition.go @@ -300,6 +300,16 @@ type FHIRCompositionRelayEdge struct { Node *FHIRComposition `json:"node,omitempty"` } +// PagedFHIRComposition ... +type PagedFHIRComposition struct { + Compositions []FHIRComposition + HasNextPage bool + NextCursor string + HasPreviousPage bool + PreviousCursor string + TotalCount int +} + // FHIRCompositionRelayPayload is used to return single instances of Composition type FHIRCompositionRelayPayload struct { Resource *FHIRComposition `json:"resource,omitempty"` diff --git a/pkg/clinical/infrastructure/datastore/cloudhealthcare/fhir.go b/pkg/clinical/infrastructure/datastore/cloudhealthcare/fhir.go index 3af94ba3..cf8a5e91 100644 --- a/pkg/clinical/infrastructure/datastore/cloudhealthcare/fhir.go +++ b/pkg/clinical/infrastructure/datastore/cloudhealthcare/fhir.go @@ -813,14 +813,21 @@ func (fh StoreImpl) UpdateFHIRAllergyIntolerance(_ context.Context, input domain } // SearchFHIRComposition provides a search API for FHIRComposition -func (fh StoreImpl) SearchFHIRComposition(_ context.Context, params map[string]interface{}, tenant dto.TenantIdentifiers, pagination dto.Pagination) (*domain.FHIRCompositionRelayConnection, error) { - output := domain.FHIRCompositionRelayConnection{} - +func (fh StoreImpl) SearchFHIRComposition(_ context.Context, params map[string]interface{}, tenant dto.TenantIdentifiers, pagination dto.Pagination) (*domain.PagedFHIRComposition, error) { resources, err := fh.Dataset.SearchFHIRResource(compositionResourceType, params, tenant, pagination) if err != nil { return nil, err } + output := domain.PagedFHIRComposition{ + Compositions: []domain.FHIRComposition{}, + HasNextPage: resources.HasNextPage, + NextCursor: resources.NextCursor, + HasPreviousPage: resources.HasPreviousPage, + PreviousCursor: resources.PreviousCursor, + TotalCount: resources.TotalCount, + } + for _, result := range resources.Resources { var resource domain.FHIRComposition @@ -835,9 +842,7 @@ func (fh StoreImpl) SearchFHIRComposition(_ context.Context, params map[string]i "server error: Unable to unmarshal %s: %w", compositionResourceType, err) } - output.Edges = append(output.Edges, &domain.FHIRCompositionRelayEdge{ - Node: &resource, - }) + output.Compositions = append(output.Compositions, resource) } return &output, nil diff --git a/pkg/clinical/infrastructure/datastore/cloudhealthcare/mock/fhir_mock.go b/pkg/clinical/infrastructure/datastore/cloudhealthcare/mock/fhir_mock.go index 23df8fbc..0e555ead 100644 --- a/pkg/clinical/infrastructure/datastore/cloudhealthcare/mock/fhir_mock.go +++ b/pkg/clinical/infrastructure/datastore/cloudhealthcare/mock/fhir_mock.go @@ -45,7 +45,7 @@ type FHIRMock struct { MockSearchFHIRAllergyIntoleranceFn func(ctx context.Context, params map[string]interface{}, tenant dto.TenantIdentifiers, pagination dto.Pagination) (*domain.PagedFHIRAllergy, error) MockCreateFHIRAllergyIntoleranceFn func(ctx context.Context, input domain.FHIRAllergyIntoleranceInput) (*domain.FHIRAllergyIntoleranceRelayPayload, error) MockUpdateFHIRAllergyIntoleranceFn func(ctx context.Context, input domain.FHIRAllergyIntoleranceInput) (*domain.FHIRAllergyIntoleranceRelayPayload, error) - MockSearchFHIRCompositionFn func(ctx context.Context, params map[string]interface{}, tenant dto.TenantIdentifiers, pagination dto.Pagination) (*domain.FHIRCompositionRelayConnection, error) + MockSearchFHIRCompositionFn func(ctx context.Context, params map[string]interface{}, tenant dto.TenantIdentifiers, pagination dto.Pagination) (*domain.PagedFHIRComposition, error) MockCreateFHIRCompositionFn func(ctx context.Context, input domain.FHIRCompositionInput) (*domain.FHIRCompositionRelayPayload, error) MockUpdateFHIRCompositionFn func(ctx context.Context, input domain.FHIRCompositionInput) (*domain.FHIRCompositionRelayPayload, error) MockDeleteFHIRCompositionFn func(ctx context.Context, id string) (bool, error) @@ -649,8 +649,112 @@ func NewFHIRMock() *FHIRMock { MockUpdateFHIRAllergyIntoleranceFn: func(ctx context.Context, input domain.FHIRAllergyIntoleranceInput) (*domain.FHIRAllergyIntoleranceRelayPayload, error) { return &domain.FHIRAllergyIntoleranceRelayPayload{}, nil }, - MockSearchFHIRCompositionFn: func(ctx context.Context, params map[string]interface{}, tenant dto.TenantIdentifiers, pagination dto.Pagination) (*domain.FHIRCompositionRelayConnection, error) { - return &domain.FHIRCompositionRelayConnection{}, nil + MockSearchFHIRCompositionFn: func(ctx context.Context, params map[string]interface{}, tenant dto.TenantIdentifiers, pagination dto.Pagination) (*domain.PagedFHIRComposition, error) { + id := gofakeit.UUID() + compositionTitle := gofakeit.Name() + "assessment note" + typeSystem := scalarutils.URI("http://hl7.org/fhir/ValueSet/doc-typecodes") + categorySystem := scalarutils.URI("http://hl7.org/fhir/ValueSet/referenced-item-category") + category := "Assessment + plan" + compositionType := "Progress note" + compositionCategory := "Treatment Plan" + compositionStatus := "active" + note := scalarutils.Markdown("Fever Fever") + PatientRef := "Patient/" + uuid.NewString() + patientType := "Patient" + organizationRef := "Organization/" + uuid.NewString() + compositionSectionTextStatus := "generated" + + composition := domain.FHIRComposition{ + ID: &id, + Text: &domain.FHIRNarrative{ + ID: &id, + Status: (*domain.NarrativeStatusEnum)(&compositionSectionTextStatus), + Div: scalarutils.XHTML(note), + }, + Identifier: &domain.FHIRIdentifier{}, + Status: (*domain.CompositionStatusEnum)(&compositionStatus), + Type: &domain.FHIRCodeableConcept{ + ID: new(string), + Coding: []*domain.FHIRCoding{ + { + ID: &id, + System: &typeSystem, + Code: scalarutils.Code(string(common.LOINCProgressNoteCode)), + Display: compositionType, + }, + }, + Text: compositionType, + }, + Category: []*domain.FHIRCodeableConcept{ + { + ID: new(string), + Coding: []*domain.FHIRCoding{ + { + ID: &id, + System: &categorySystem, + Version: new(string), + Code: scalarutils.Code(string(common.LOINCAssessmentPlanCode)), + Display: category, + }, + }, + Text: compositionCategory, + }, + }, + Subject: &domain.FHIRReference{ + ID: &id, + Reference: &PatientRef, + Type: (*scalarutils.URI)(&patientType), + }, + Encounter: &domain.FHIRReference{ + ID: &id, + }, + Date: &scalarutils.Date{ + Year: 2023, + Month: 9, + Day: 25, + }, + Author: []*domain.FHIRReference{ + { + Reference: &organizationRef, + }, + }, + Title: &compositionTitle, + Section: []*domain.FHIRCompositionSection{ + { + ID: &id, + Title: &compositionCategory, + Code: &domain.FHIRCodeableConceptInput{ + ID: new(string), + Coding: []*domain.FHIRCodingInput{ + { + ID: &id, + System: &categorySystem, + Version: new(string), + Code: scalarutils.Code(string(common.LOINCAssessmentPlanCode)), + Display: category, + }, + }, + Text: "Assessment + plan", + }, + Author: []*domain.FHIRReference{ + { + Reference: new(string), + }, + }, + Text: &domain.FHIRNarrative{ + ID: &id, + Status: (*domain.NarrativeStatusEnum)(&compositionSectionTextStatus), + Div: scalarutils.XHTML(note), + }, + }, + }, + } + + return &domain.PagedFHIRComposition{ + Compositions: []domain.FHIRComposition{composition}, + HasNextPage: false, + HasPreviousPage: false, + }, nil }, MockCreateFHIRCompositionFn: func(ctx context.Context, input domain.FHIRCompositionInput) (*domain.FHIRCompositionRelayPayload, error) { UUID := uuid.New().String() @@ -1414,7 +1518,7 @@ func (fh *FHIRMock) UpdateFHIRAllergyIntolerance(ctx context.Context, input doma } // SearchFHIRComposition is a mock implementation of SearchFHIRComposition method -func (fh *FHIRMock) SearchFHIRComposition(ctx context.Context, params map[string]interface{}, tenant dto.TenantIdentifiers, pagination dto.Pagination) (*domain.FHIRCompositionRelayConnection, error) { +func (fh *FHIRMock) SearchFHIRComposition(ctx context.Context, params map[string]interface{}, tenant dto.TenantIdentifiers, pagination dto.Pagination) (*domain.PagedFHIRComposition, error) { return fh.MockSearchFHIRCompositionFn(ctx, params, tenant, pagination) } diff --git a/pkg/clinical/presentation/graph/clinical.graphql b/pkg/clinical/presentation/graph/clinical.graphql index 04e51b9f..e82f925a 100644 --- a/pkg/clinical/presentation/graph/clinical.graphql +++ b/pkg/clinical/presentation/graph/clinical.graphql @@ -10,6 +10,12 @@ extend type Query { pagination: Pagination! ): ConditionConnection + # Compositions + listPatientCompositions( + patientID: ID! + pagination: Pagination! + ): CompositionConnection + # Encounter listPatientEncounters( patientID: String! diff --git a/pkg/clinical/presentation/graph/clinical.resolvers.go b/pkg/clinical/presentation/graph/clinical.resolvers.go index fba9334d..b29a8074 100644 --- a/pkg/clinical/presentation/graph/clinical.resolvers.go +++ b/pkg/clinical/presentation/graph/clinical.resolvers.go @@ -187,6 +187,12 @@ func (r *queryResolver) ListPatientConditions(ctx context.Context, patientID str return r.usecases.ListPatientConditions(ctx, patientID, pagination) } +// ListPatientCompositions is the resolver for the listPatientCompositions field. +func (r *queryResolver) ListPatientCompositions(ctx context.Context, patientID string, pagination dto.Pagination) (*dto.CompositionConnection, error) { + r.CheckDependencies() + return r.usecases.ListPatientCompositions(ctx, patientID, pagination) +} + // ListPatientEncounters is the resolver for the listPatientEncounters field. func (r *queryResolver) ListPatientEncounters(ctx context.Context, patientID string, pagination dto.Pagination) (*dto.EncounterConnection, error) { r.CheckDependencies() diff --git a/pkg/clinical/presentation/graph/generated/generated.go b/pkg/clinical/presentation/graph/generated/generated.go index db162d6a..7c0f5633 100644 --- a/pkg/clinical/presentation/graph/generated/generated.go +++ b/pkg/clinical/presentation/graph/generated/generated.go @@ -79,6 +79,17 @@ type ComplexityRoot struct { Type func(childComplexity int) int } + CompositionConnection struct { + Edges func(childComplexity int) int + PageInfo func(childComplexity int) int + TotalCount func(childComplexity int) int + } + + CompositionEdge struct { + Cursor func(childComplexity int) int + Node func(childComplexity int) int + } + Condition struct { Category func(childComplexity int) int Code func(childComplexity int) int @@ -256,6 +267,7 @@ type ComplexityRoot struct { GetPatientViralLoad func(childComplexity int, patientID string, pagination dto.Pagination) int GetPatientWeightEntries func(childComplexity int, patientID string, pagination dto.Pagination) int ListPatientAllergies func(childComplexity int, patientID string, pagination dto.Pagination) int + ListPatientCompositions func(childComplexity int, patientID string, pagination dto.Pagination) int ListPatientConditions func(childComplexity int, patientID string, pagination dto.Pagination) int ListPatientEncounters func(childComplexity int, patientID string, pagination dto.Pagination) int ListPatientMedia func(childComplexity int, patientID string, pagination dto.Pagination) int @@ -335,6 +347,7 @@ type QueryResolver interface { GetMedicalData(ctx context.Context, patientID string) (*dto.MedicalData, error) GetEpisodeOfCare(ctx context.Context, id string) (*dto.EpisodeOfCare, error) ListPatientConditions(ctx context.Context, patientID string, pagination dto.Pagination) (*dto.ConditionConnection, error) + ListPatientCompositions(ctx context.Context, patientID string, pagination dto.Pagination) (*dto.CompositionConnection, error) ListPatientEncounters(ctx context.Context, patientID string, pagination dto.Pagination) (*dto.EncounterConnection, error) GetPatientTemperatureEntries(ctx context.Context, patientID string, pagination dto.Pagination) (*dto.ObservationConnection, error) GetPatientBloodPressureEntries(ctx context.Context, patientID string, pagination dto.Pagination) (*dto.ObservationConnection, error) @@ -510,6 +523,41 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.Composition.Type(childComplexity), true + case "CompositionConnection.edges": + if e.complexity.CompositionConnection.Edges == nil { + break + } + + return e.complexity.CompositionConnection.Edges(childComplexity), true + + case "CompositionConnection.pageInfo": + if e.complexity.CompositionConnection.PageInfo == nil { + break + } + + return e.complexity.CompositionConnection.PageInfo(childComplexity), true + + case "CompositionConnection.totalCount": + if e.complexity.CompositionConnection.TotalCount == nil { + break + } + + return e.complexity.CompositionConnection.TotalCount(childComplexity), true + + case "CompositionEdge.cursor": + if e.complexity.CompositionEdge.Cursor == nil { + break + } + + return e.complexity.CompositionEdge.Cursor(childComplexity), true + + case "CompositionEdge.node": + if e.complexity.CompositionEdge.Node == nil { + break + } + + return e.complexity.CompositionEdge.Node(childComplexity), true + case "Condition.category": if e.complexity.Condition.Category == nil { break @@ -1532,6 +1580,18 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.Query.ListPatientAllergies(childComplexity, args["patientID"].(string), args["pagination"].(dto.Pagination)), true + case "Query.listPatientCompositions": + if e.complexity.Query.ListPatientCompositions == nil { + break + } + + args, err := ec.field_Query_listPatientCompositions_args(context.TODO(), rawArgs) + if err != nil { + return 0, false + } + + return e.complexity.Query.ListPatientCompositions(childComplexity, args["patientID"].(string), args["pagination"].(dto.Pagination)), true + case "Query.listPatientConditions": if e.complexity.Query.ListPatientConditions == nil { break @@ -1869,6 +1929,12 @@ var sources = []*ast.Source{ pagination: Pagination! ): ConditionConnection + # Compositions + listPatientCompositions( + patientID: ID! + pagination: Pagination! + ): CompositionConnection + # Encounter listPatientEncounters( patientID: String! @@ -2409,6 +2475,17 @@ type Composition { patientID: String encounterID: String } + +type CompositionEdge { + node: Composition + cursor: String +} + +type CompositionConnection { + totalCount: Int + edges: [CompositionEdge] + pageInfo: PageInfo +} `, BuiltIn: false}, {Name: "../../../../../federation/directives.graphql", Input: ` directive @key(fields: _FieldSet!) repeatable on OBJECT | INTERFACE @@ -3233,6 +3310,30 @@ func (ec *executionContext) field_Query_listPatientAllergies_args(ctx context.Co return args, nil } +func (ec *executionContext) field_Query_listPatientCompositions_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { + var err error + args := map[string]interface{}{} + var arg0 string + if tmp, ok := rawArgs["patientID"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("patientID")) + arg0, err = ec.unmarshalNID2string(ctx, tmp) + if err != nil { + return nil, err + } + } + args["patientID"] = arg0 + var arg1 dto.Pagination + if tmp, ok := rawArgs["pagination"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("pagination")) + arg1, err = ec.unmarshalNPagination2githubᚗcomᚋsavannahghiᚋclinicalᚋpkgᚋclinicalᚋapplicationᚋdtoᚐPagination(ctx, tmp) + if err != nil { + return nil, err + } + } + args["pagination"] = arg1 + return args, nil +} + func (ec *executionContext) field_Query_listPatientConditions_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { var err error args := map[string]interface{}{} @@ -4265,6 +4366,245 @@ func (ec *executionContext) fieldContext_Composition_encounterID(ctx context.Con return fc, nil } +func (ec *executionContext) _CompositionConnection_totalCount(ctx context.Context, field graphql.CollectedField, obj *dto.CompositionConnection) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_CompositionConnection_totalCount(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.TotalCount, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(int) + fc.Result = res + return ec.marshalOInt2int(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_CompositionConnection_totalCount(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "CompositionConnection", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type Int does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _CompositionConnection_edges(ctx context.Context, field graphql.CollectedField, obj *dto.CompositionConnection) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_CompositionConnection_edges(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Edges, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.([]dto.CompositionEdge) + fc.Result = res + return ec.marshalOCompositionEdge2ᚕgithubᚗcomᚋsavannahghiᚋclinicalᚋpkgᚋclinicalᚋapplicationᚋdtoᚐCompositionEdge(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_CompositionConnection_edges(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "CompositionConnection", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "node": + return ec.fieldContext_CompositionEdge_node(ctx, field) + case "cursor": + return ec.fieldContext_CompositionEdge_cursor(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type CompositionEdge", field.Name) + }, + } + return fc, nil +} + +func (ec *executionContext) _CompositionConnection_pageInfo(ctx context.Context, field graphql.CollectedField, obj *dto.CompositionConnection) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_CompositionConnection_pageInfo(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.PageInfo, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(dto.PageInfo) + fc.Result = res + return ec.marshalOPageInfo2githubᚗcomᚋsavannahghiᚋclinicalᚋpkgᚋclinicalᚋapplicationᚋdtoᚐPageInfo(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_CompositionConnection_pageInfo(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "CompositionConnection", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "hasNextPage": + return ec.fieldContext_PageInfo_hasNextPage(ctx, field) + case "startCursor": + return ec.fieldContext_PageInfo_startCursor(ctx, field) + case "hasPreviousPage": + return ec.fieldContext_PageInfo_hasPreviousPage(ctx, field) + case "endCursor": + return ec.fieldContext_PageInfo_endCursor(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type PageInfo", field.Name) + }, + } + return fc, nil +} + +func (ec *executionContext) _CompositionEdge_node(ctx context.Context, field graphql.CollectedField, obj *dto.CompositionEdge) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_CompositionEdge_node(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Node, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(dto.Composition) + fc.Result = res + return ec.marshalOComposition2githubᚗcomᚋsavannahghiᚋclinicalᚋpkgᚋclinicalᚋapplicationᚋdtoᚐComposition(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_CompositionEdge_node(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "CompositionEdge", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "id": + return ec.fieldContext_Composition_id(ctx, field) + case "text": + return ec.fieldContext_Composition_text(ctx, field) + case "type": + return ec.fieldContext_Composition_type(ctx, field) + case "category": + return ec.fieldContext_Composition_category(ctx, field) + case "status": + return ec.fieldContext_Composition_status(ctx, field) + case "date": + return ec.fieldContext_Composition_date(ctx, field) + case "patientID": + return ec.fieldContext_Composition_patientID(ctx, field) + case "encounterID": + return ec.fieldContext_Composition_encounterID(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type Composition", field.Name) + }, + } + return fc, nil +} + +func (ec *executionContext) _CompositionEdge_cursor(ctx context.Context, field graphql.CollectedField, obj *dto.CompositionEdge) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_CompositionEdge_cursor(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Cursor, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalOString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_CompositionEdge_cursor(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "CompositionEdge", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + func (ec *executionContext) _Condition_id(ctx context.Context, field graphql.CollectedField, obj *dto.Condition) (ret graphql.Marshaler) { fc, err := ec.fieldContext_Condition_id(ctx, field) if err != nil { @@ -9561,6 +9901,66 @@ func (ec *executionContext) fieldContext_Query_listPatientConditions(ctx context return fc, nil } +func (ec *executionContext) _Query_listPatientCompositions(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Query_listPatientCompositions(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Query().ListPatientCompositions(rctx, fc.Args["patientID"].(string), fc.Args["pagination"].(dto.Pagination)) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*dto.CompositionConnection) + fc.Result = res + return ec.marshalOCompositionConnection2ᚖgithubᚗcomᚋsavannahghiᚋclinicalᚋpkgᚋclinicalᚋapplicationᚋdtoᚐCompositionConnection(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Query_listPatientCompositions(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Query", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "totalCount": + return ec.fieldContext_CompositionConnection_totalCount(ctx, field) + case "edges": + return ec.fieldContext_CompositionConnection_edges(ctx, field) + case "pageInfo": + return ec.fieldContext_CompositionConnection_pageInfo(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type CompositionConnection", field.Name) + }, + } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Query_listPatientCompositions_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil +} + func (ec *executionContext) _Query_listPatientEncounters(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { fc, err := ec.fieldContext_Query_listPatientEncounters(ctx, field) if err != nil { @@ -14373,6 +14773,84 @@ func (ec *executionContext) _Composition(ctx context.Context, sel ast.SelectionS return out } +var compositionConnectionImplementors = []string{"CompositionConnection"} + +func (ec *executionContext) _CompositionConnection(ctx context.Context, sel ast.SelectionSet, obj *dto.CompositionConnection) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, compositionConnectionImplementors) + + out := graphql.NewFieldSet(fields) + deferred := make(map[string]*graphql.FieldSet) + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("CompositionConnection") + case "totalCount": + out.Values[i] = ec._CompositionConnection_totalCount(ctx, field, obj) + case "edges": + out.Values[i] = ec._CompositionConnection_edges(ctx, field, obj) + case "pageInfo": + out.Values[i] = ec._CompositionConnection_pageInfo(ctx, field, obj) + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch(ctx) + if out.Invalids > 0 { + return graphql.Null + } + + atomic.AddInt32(&ec.deferred, int32(len(deferred))) + + for label, dfs := range deferred { + ec.processDeferredGroup(graphql.DeferredGroup{ + Label: label, + Path: graphql.GetPath(ctx), + FieldSet: dfs, + Context: ctx, + }) + } + + return out +} + +var compositionEdgeImplementors = []string{"CompositionEdge"} + +func (ec *executionContext) _CompositionEdge(ctx context.Context, sel ast.SelectionSet, obj *dto.CompositionEdge) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, compositionEdgeImplementors) + + out := graphql.NewFieldSet(fields) + deferred := make(map[string]*graphql.FieldSet) + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("CompositionEdge") + case "node": + out.Values[i] = ec._CompositionEdge_node(ctx, field, obj) + case "cursor": + out.Values[i] = ec._CompositionEdge_cursor(ctx, field, obj) + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch(ctx) + if out.Invalids > 0 { + return graphql.Null + } + + atomic.AddInt32(&ec.deferred, int32(len(deferred))) + + for label, dfs := range deferred { + ec.processDeferredGroup(graphql.DeferredGroup{ + Label: label, + Path: graphql.GetPath(ctx), + FieldSet: dfs, + Context: ctx, + }) + } + + return out +} + var conditionImplementors = []string{"Condition"} func (ec *executionContext) _Condition(ctx context.Context, sel ast.SelectionSet, obj *dto.Condition) graphql.Marshaler { @@ -15553,6 +16031,25 @@ func (ec *executionContext) _Query(ctx context.Context, sel ast.SelectionSet) gr func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) } + out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return rrm(innerCtx) }) + case "listPatientCompositions": + field := field + + innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._Query_listPatientCompositions(ctx, field) + return res + } + + rrm := func(ctx context.Context) graphql.Marshaler { + return ec.OperationContext.RootResolverMiddleware(ctx, + func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) + } + out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return rrm(innerCtx) }) case "listPatientEncounters": field := field @@ -17407,6 +17904,62 @@ func (ec *executionContext) marshalOBoolean2ᚖbool(ctx context.Context, sel ast return res } +func (ec *executionContext) marshalOComposition2githubᚗcomᚋsavannahghiᚋclinicalᚋpkgᚋclinicalᚋapplicationᚋdtoᚐComposition(ctx context.Context, sel ast.SelectionSet, v dto.Composition) graphql.Marshaler { + return ec._Composition(ctx, sel, &v) +} + +func (ec *executionContext) marshalOCompositionConnection2ᚖgithubᚗcomᚋsavannahghiᚋclinicalᚋpkgᚋclinicalᚋapplicationᚋdtoᚐCompositionConnection(ctx context.Context, sel ast.SelectionSet, v *dto.CompositionConnection) graphql.Marshaler { + if v == nil { + return graphql.Null + } + return ec._CompositionConnection(ctx, sel, v) +} + +func (ec *executionContext) marshalOCompositionEdge2githubᚗcomᚋsavannahghiᚋclinicalᚋpkgᚋclinicalᚋapplicationᚋdtoᚐCompositionEdge(ctx context.Context, sel ast.SelectionSet, v dto.CompositionEdge) graphql.Marshaler { + return ec._CompositionEdge(ctx, sel, &v) +} + +func (ec *executionContext) marshalOCompositionEdge2ᚕgithubᚗcomᚋsavannahghiᚋclinicalᚋpkgᚋclinicalᚋapplicationᚋdtoᚐCompositionEdge(ctx context.Context, sel ast.SelectionSet, v []dto.CompositionEdge) graphql.Marshaler { + if v == nil { + return graphql.Null + } + ret := make(graphql.Array, len(v)) + var wg sync.WaitGroup + isLen1 := len(v) == 1 + if !isLen1 { + wg.Add(len(v)) + } + for i := range v { + i := i + fc := &graphql.FieldContext{ + Index: &i, + Result: &v[i], + } + ctx := graphql.WithFieldContext(ctx, fc) + f := func(i int) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = nil + } + }() + if !isLen1 { + defer wg.Done() + } + ret[i] = ec.marshalOCompositionEdge2githubᚗcomᚋsavannahghiᚋclinicalᚋpkgᚋclinicalᚋapplicationᚋdtoᚐCompositionEdge(ctx, sel, v[i]) + } + if isLen1 { + f(i) + } else { + go f(i) + } + + } + wg.Wait() + + return ret +} + func (ec *executionContext) marshalOCondition2githubᚗcomᚋsavannahghiᚋclinicalᚋpkgᚋclinicalᚋapplicationᚋdtoᚐCondition(ctx context.Context, sel ast.SelectionSet, v dto.Condition) graphql.Marshaler { return ec._Condition(ctx, sel, &v) } diff --git a/pkg/clinical/presentation/graph/types.graphql b/pkg/clinical/presentation/graph/types.graphql index 52d18c95..3cec7b63 100644 --- a/pkg/clinical/presentation/graph/types.graphql +++ b/pkg/clinical/presentation/graph/types.graphql @@ -200,3 +200,14 @@ type Composition { patientID: String encounterID: String } + +type CompositionEdge { + node: Composition + cursor: String +} + +type CompositionConnection { + totalCount: Int + edges: [CompositionEdge] + pageInfo: PageInfo +} diff --git a/pkg/clinical/repository/repository.go b/pkg/clinical/repository/repository.go index 5862b951..c26ebedd 100644 --- a/pkg/clinical/repository/repository.go +++ b/pkg/clinical/repository/repository.go @@ -89,7 +89,7 @@ type FHIREncounter interface { PatchFHIREncounter(ctx context.Context, encounterID string, input domain.FHIREncounterInput) (*domain.FHIREncounter, error) } type FHIRComposition interface { - SearchFHIRComposition(ctx context.Context, params map[string]interface{}, tenant dto.TenantIdentifiers, pagination dto.Pagination) (*domain.FHIRCompositionRelayConnection, error) + SearchFHIRComposition(ctx context.Context, params map[string]interface{}, tenant dto.TenantIdentifiers, pagination dto.Pagination) (*domain.PagedFHIRComposition, error) CreateFHIRComposition(ctx context.Context, input domain.FHIRCompositionInput) (*domain.FHIRCompositionRelayPayload, error) UpdateFHIRComposition(ctx context.Context, input domain.FHIRCompositionInput) (*domain.FHIRCompositionRelayPayload, error) DeleteFHIRComposition(ctx context.Context, id string) (bool, error) diff --git a/pkg/clinical/usecases/clinical/composition.go b/pkg/clinical/usecases/clinical/composition.go index 6077ed6f..ba020eb9 100644 --- a/pkg/clinical/usecases/clinical/composition.go +++ b/pkg/clinical/usecases/clinical/composition.go @@ -141,6 +141,15 @@ func (c *UseCasesClinicalImpl) CreateComposition(ctx context.Context, input dto. }, } + tags, err := c.GetTenantMetaTags(ctx) + if err != nil { + return nil, err + } + + compositionInput.Meta = domain.FHIRMetaInput{ + Tag: tags, + } + composition, err := c.infrastructure.FHIR.CreateFHIRComposition(ctx, compositionInput) if err != nil { return nil, err @@ -163,3 +172,55 @@ func mapFHIRCompositionToCompositionDTO(composition domain.FHIRComposition) *dto return &output } + +// ListPatientCompositions lists a patient's compositions +func (c UseCasesClinicalImpl) ListPatientCompositions(ctx context.Context, patientID string, pagination dto.Pagination) (*dto.CompositionConnection, error) { + _, err := uuid.Parse(patientID) + if err != nil { + return nil, fmt.Errorf("invalid patient id: %s", patientID) + } + + err = pagination.Validate() + if err != nil { + return nil, err + } + + identifiers, err := c.infrastructure.BaseExtension.GetTenantIdentifiers(ctx) + if err != nil { + return nil, fmt.Errorf("failed to get tenant identifiers from context: %w", err) + } + + patient, err := c.infrastructure.FHIR.GetFHIRPatient(ctx, patientID) + if err != nil { + return nil, err + } + + patientRef := fmt.Sprintf("Patient/%s", *patient.Resource.ID) + params := map[string]interface{}{ + "subject": patientRef, + "_sort": "date", + } + + compositionsResponse, err := c.infrastructure.FHIR.SearchFHIRComposition(ctx, params, *identifiers, pagination) + if err != nil { + return nil, err + } + + compositions := []dto.Composition{} + + for _, resource := range compositionsResponse.Compositions { + composition := mapFHIRCompositionToCompositionDTO(resource) + compositions = append(compositions, *composition) + } + + pageInfo := dto.PageInfo{ + HasNextPage: compositionsResponse.HasNextPage, + EndCursor: &compositionsResponse.NextCursor, + HasPreviousPage: compositionsResponse.HasPreviousPage, + StartCursor: &compositionsResponse.PreviousCursor, + } + + connection := dto.CreateCompositionConnection(compositions, pageInfo, compositionsResponse.TotalCount) + + return &connection, nil +} diff --git a/pkg/clinical/usecases/clinical/composition_test.go b/pkg/clinical/usecases/clinical/composition_test.go index e4f6fb12..dedc67e6 100644 --- a/pkg/clinical/usecases/clinical/composition_test.go +++ b/pkg/clinical/usecases/clinical/composition_test.go @@ -114,6 +114,20 @@ func TestUseCasesClinicalImpl_CreateComposition(t *testing.T) { }, wantErr: true, }, + { + name: "sad case: failed to create composition", + args: args{ + ctx: context.Background(), + input: dto.CompositionInput{ + EncounterID: gofakeit.UUID(), + Type: dto.ProgressNote, + Category: dto.AssessmentAndPlan, + Status: "final", + Note: "Patient is deteriorating", + }, + }, + wantErr: true, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -292,6 +306,12 @@ func TestUseCasesClinicalImpl_CreateComposition(t *testing.T) { } } + if tt.name == "sad case: failed to create composition" { + fakeFHIR.MockCreateFHIRCompositionFn = func(ctx context.Context, input domain.FHIRCompositionInput) (*domain.FHIRCompositionRelayPayload, error) { + return nil, fmt.Errorf("an error occurred") + } + } + _, err := c.CreateComposition(tt.args.ctx, tt.args.input) if (err != nil) != tt.wantErr { t.Errorf("UseCasesClinicalImpl.CreateComposition() error = %v, wantErr %v", err, tt.wantErr) @@ -300,3 +320,120 @@ func TestUseCasesClinicalImpl_CreateComposition(t *testing.T) { }) } } + +func TestUseCasesClinicalImpl_ListPatientCompositions(t *testing.T) { + first := 3 + type args struct { + ctx context.Context + patientID string + pagination dto.Pagination + } + tests := []struct { + name string + args args + wantErr bool + }{ + { + name: "happy case: list compositions", + args: args{ + ctx: context.Background(), + patientID: gofakeit.UUID(), + pagination: dto.Pagination{}, + }, + wantErr: false, + }, + { + name: "sad case: invalid patient id", + args: args{ + ctx: context.Background(), + patientID: "invalid", + pagination: dto.Pagination{}, + }, + wantErr: true, + }, + { + name: "Sad Case - invalid pagination", + args: args{ + ctx: context.Background(), + patientID: uuid.New().String(), + pagination: dto.Pagination{ + First: &first, + Last: &first, + }, + }, + wantErr: true, + }, + { + name: "sad case: fail to get identifiers", + args: args{ + ctx: context.Background(), + patientID: gofakeit.UUID(), + pagination: dto.Pagination{}, + }, + wantErr: true, + }, + { + name: "sad case: fail to get patient", + args: args{ + ctx: context.Background(), + patientID: gofakeit.UUID(), + pagination: dto.Pagination{}, + }, + wantErr: true, + }, + { + name: "sad case: fail to search composition", + args: args{ + ctx: context.Background(), + patientID: gofakeit.UUID(), + pagination: dto.Pagination{}, + }, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + fakeExt := fakeExtMock.NewFakeBaseExtensionMock() + fakeFHIR := fakeFHIRMock.NewFHIRMock() + fakeOCL := fakeOCLMock.NewFakeOCLMock() + fakeUpload := fakeUploadMock.NewFakeUploadMock() + fakePubSub := fakePubSubMock.NewPubSubServiceMock() + + infra := infrastructure.NewInfrastructureInteractor(fakeExt, fakeFHIR, fakeOCL, fakeUpload, fakePubSub) + c := clinicalUsecase.NewUseCasesClinicalImpl(infra) + + if tt.name == "sad case: fail to get identifiers" { + fakeExt.MockGetTenantIdentifiersFn = func(ctx context.Context) (*dto.TenantIdentifiers, error) { + return nil, fmt.Errorf("failed to get identifiers") + } + } + + if tt.name == "sad case: fail to get patient" { + fakeFHIR.MockGetFHIRPatientFn = func(ctx context.Context, id string) (*domain.FHIRPatientRelayPayload, error) { + return nil, fmt.Errorf("failed to get patient") + } + } + + if tt.name == "sad case: fail to get identifiers" { + fakeExt.MockGetTenantIdentifiersFn = func(ctx context.Context) (*dto.TenantIdentifiers, error) { + return nil, fmt.Errorf("failed to get identifiers") + } + } + + if tt.name == "sad case: fail to search composition" { + fakeFHIR.MockSearchFHIRCompositionFn = func(ctx context.Context, params map[string]interface{}, tenant dto.TenantIdentifiers, pagination dto.Pagination) (*domain.PagedFHIRComposition, error) { + return nil, fmt.Errorf("failed to find condition") + } + } + got, err := c.ListPatientCompositions(tt.args.ctx, tt.args.patientID, tt.args.pagination) + if (err != nil) != tt.wantErr { + t.Errorf("ListPatientCompositions() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !tt.wantErr && got == nil { + t.Errorf("expected a value to be returned, got: %v", got) + return + } + }) + } +} diff --git a/pkg/clinical/usecases/clinical/condition_test.go b/pkg/clinical/usecases/clinical/condition_test.go index a705ae09..ea88f264 100644 --- a/pkg/clinical/usecases/clinical/condition_test.go +++ b/pkg/clinical/usecases/clinical/condition_test.go @@ -171,6 +171,26 @@ func TestUseCasesClinicalImpl_CreateCondition(t *testing.T) { }, wantErr: true, }, + { + name: "sad case: failed to create condition", + args: args{ + ctx: context.Background(), + input: dto.ConditionInput{ + Code: "386661006", + System: "SNOMED", + Status: dto.ConditionStatusActive, + Category: dto.ConditionCategoryProblemList, + EncounterID: gofakeit.UUID(), + Note: "Fever Fever", + OnsetDate: &scalarutils.Date{ + Year: 2022, + Month: 12, + Day: 12, + }, + }, + }, + wantErr: true, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -411,53 +431,6 @@ func TestUseCasesClinicalImpl_CreateCondition(t *testing.T) { } } - if tt.name == "sad case: fail to create condition" { - fakeFHIR.MockGetFHIRPatientFn = func(ctx context.Context, id string) (*domain.FHIRPatientRelayPayload, error) { - UUID := gofakeit.UUID() - genderMale := "male" - return &domain.FHIRPatientRelayPayload{ - Resource: &domain.FHIRPatient{ - ID: &UUID, - Text: &domain.FHIRNarrative{}, - Identifier: []*domain.FHIRIdentifier{}, - Active: new(bool), - Name: []*domain.FHIRHumanName{ - { - ID: new(string), - Use: "", - Text: "Test", - Family: new(string), - Given: []*string{}, - Prefix: []*string{}, - Suffix: []*string{}, - Period: &domain.FHIRPeriod{}, - }, - }, - Telecom: []*domain.FHIRContactPoint{}, - Gender: (*domain.PatientGenderEnum)(&genderMale), - BirthDate: &scalarutils.Date{}, - DeceasedBoolean: new(bool), - DeceasedDateTime: &scalarutils.Date{}, - Address: []*domain.FHIRAddress{}, - MaritalStatus: &domain.FHIRCodeableConcept{}, - MultipleBirthBoolean: new(bool), - MultipleBirthInteger: new(string), - Photo: []*domain.FHIRAttachment{}, - Contact: []*domain.FHIRPatientContact{}, - Communication: []*domain.FHIRPatientCommunication{}, - GeneralPractitioner: []*domain.FHIRReference{}, - ManagingOrganization: &domain.FHIRReference{}, - Link: []*domain.FHIRPatientLink{}, - Meta: &domain.FHIRMeta{}, - Extension: []*domain.FHIRExtension{}, - }, - }, nil - } - fakeFHIR.MockCreateFHIRConditionFn = func(ctx context.Context, input domain.FHIRConditionInput) (*domain.FHIRConditionRelayPayload, error) { - return nil, fmt.Errorf("failed to create condition") - } - } - if tt.name == "sad case: fail in completed encounter" { finished := domain.EncounterStatusEnumFinished fakeFHIR.MockGetFHIREncounterFn = func(ctx context.Context, id string) (*domain.FHIREncounterRelayPayload, error) { @@ -470,9 +443,16 @@ func TestUseCasesClinicalImpl_CreateCondition(t *testing.T) { }, nil } } + + if tt.name == "sad case: failed to create condition" { + fakeFHIR.MockCreateFHIRConditionFn = func(ctx context.Context, input domain.FHIRConditionInput) (*domain.FHIRConditionRelayPayload, error) { + return nil, fmt.Errorf("an error occurred") + } + } + _, err := c.CreateCondition(tt.args.ctx, tt.args.input) if (err != nil) != tt.wantErr { - t.Errorf("CreateCondition() error = %v, wantErr %v", err, tt.wantErr) + t.Errorf("UseCasesClinicalImpl.CreateCondition() error = %v, wantErr %v", err, tt.wantErr) } }) } diff --git a/pkg/clinical/usecases/usecases.go b/pkg/clinical/usecases/usecases.go index 9292302f..38ce2938 100644 --- a/pkg/clinical/usecases/usecases.go +++ b/pkg/clinical/usecases/usecases.go @@ -79,7 +79,9 @@ type Clinical interface { UploadMedia(ctx context.Context, encounterID string, file io.Reader, contentType string) (*dto.Media, error) ListPatientMedia(ctx context.Context, patientID string, pagination dto.Pagination) (*dto.MediaConnection, error) + CreateComposition(ctx context.Context, input dto.CompositionInput) (*dto.Composition, error) + ListPatientCompositions(ctx context.Context, patientID string, pagination dto.Pagination) (*dto.CompositionConnection, error) } // Interactor is an implementation of the usecases interface