Skip to content

Commit

Permalink
refactor: patient everything pagination
Browse files Browse the repository at this point in the history
Signed-off-by: Kathurima Kimathi <kathurimakimathi415@gmail.com>
  • Loading branch information
KathurimaKimathi committed Mar 14, 2024
1 parent e1580c5 commit c4951a8
Show file tree
Hide file tree
Showing 10 changed files with 290 additions and 151 deletions.
7 changes: 7 additions & 0 deletions pkg/clinical/application/dto/output.go
Original file line number Diff line number Diff line change
Expand Up @@ -160,3 +160,10 @@ type Section struct {
type ConsentOutput struct {
Status *ConsentStatusEnum `json:"status"`
}

// PatientEverythingConnection return a paginated collection of patient information
type PatientEverythingConnection struct {
TotalCount int `json:"totalCount,omitempty"`
Edges []map[string]interface{} `json:"edges,omitempty"`
PageInfo PageInfo `json:"pageInfo,omitempty"`
}
133 changes: 129 additions & 4 deletions pkg/clinical/infrastructure/datastore/cloudhealthcare/fhir.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"encoding/json"
"fmt"
"net/url"
"time"

"github.com/mitchellh/mapstructure"
Expand Down Expand Up @@ -1895,18 +1896,142 @@ func (fh StoreImpl) CreateFHIRDiagnosticReport(_ context.Context, input *domain.
}

// GetFHIRPatientEverything is used to retrieve all patient related information
func (fh StoreImpl) GetFHIRPatientEverything(ctx context.Context, id string, params map[string]interface{}) (map[string]interface{}, error) {
func (fh StoreImpl) GetFHIRPatientEverything(ctx context.Context, id string, params map[string]interface{}) (*domain.PagedFHIRResource, error) {
patientEverythingBs, err := fh.Dataset.GetFHIRPatientAllData(id, params)
if err != nil {
return nil, fmt.Errorf("unable to get patient's compartment: %w", err)
}

var patientEverything map[string]interface{}
respMap := make(map[string]interface{})

err = json.Unmarshal(patientEverythingBs, &patientEverything)
err = json.Unmarshal(patientEverythingBs, &respMap)
if err != nil {
return nil, fmt.Errorf("unable to unmarshal patient everything")
}

return patientEverything, nil
mandatoryKeys := []string{"resourceType", "type", "total", "link"}
for _, k := range mandatoryKeys {
_, found := respMap[k]
if !found {
return nil, fmt.Errorf("server error: mandatory search result key %s not found", k)
}
}

resourceType, ok := respMap["resourceType"].(string)
if !ok {
return nil, fmt.Errorf("server error: the resourceType is not a string")
}

if resourceType != "Bundle" {
return nil, fmt.Errorf(
"server error: the resourceType value is not 'Bundle' as expected")
}

resultType, ok := respMap["type"].(string)
if !ok {
return nil, fmt.Errorf("server error: the search result type value is not a string")
}

if resultType != "searchset" {
return nil, fmt.Errorf("server error: the type value is not 'searchset' as expected")
}

response := domain.PagedFHIRResource{
Resources: []map[string]interface{}{},
HasNextPage: false,
NextCursor: "",
HasPreviousPage: false,
PreviousCursor: "",
TotalCount: 0,
}

response.TotalCount = int(respMap["total"].(float64))

respEntries := respMap["entry"]
if respEntries == nil {
return &response, nil
}

entries, ok := respEntries.([]interface{})
if !ok {
return nil, fmt.Errorf(
"server error: entries is not a list of maps, it is: %T", respEntries)
}

for _, en := range entries {
entry, ok := en.(map[string]interface{})
if !ok {
return nil, fmt.Errorf(
"server error: expected each entry to be map, they are %T instead", en)
}

expectedKeys := []string{"fullUrl", "resource"}
for _, k := range expectedKeys {
_, found := entry[k]
if !found {
return nil, fmt.Errorf("server error: FHIR search entry does not have key '%s'", k)
}
}

resource, ok := entry["resource"].(map[string]interface{})
if !ok {
return nil, fmt.Errorf("server error: result entry %#v is not a map", entry["resource"])
}

response.Resources = append(response.Resources, resource)
}

linksEntries := respMap["link"]
if linksEntries == nil {
return &response, nil
}

links, ok := linksEntries.([]interface{})
if !ok {
return nil, fmt.Errorf(
"server error: entries is not a list of maps, it is: %T", linksEntries)
}

for _, en := range links {
link, ok := en.(map[string]interface{})
if !ok {
return nil, fmt.Errorf(
"server error: expected each link to be map, they are %T instead", en)
}

if link["relation"].(string) == "next" {
u, err := url.Parse(link["url"].(string))
if err != nil {
return nil, fmt.Errorf("server error: cannot parse url in link: %w", err)
}

params, err := url.ParseQuery(u.RawQuery)
if err != nil {
return nil, fmt.Errorf("server error: cannot parse url params in link: %w", err)
}

cursor := params["_page_token"][0]

response.HasNextPage = true
response.NextCursor = cursor

} else if link["relation"].(string) == "previous" {

Check failure on line 2018 in pkg/clinical/infrastructure/datastore/cloudhealthcare/fhir.go

View workflow job for this annotation

GitHub Actions / golangci (1.19.x, ubuntu-latest)

block should not end with a whitespace (or comment) (wsl)
u, err := url.Parse(link["url"].(string))
if err != nil {
return nil, fmt.Errorf("server error: cannot parse url in link: %w", err)
}

params, err := url.ParseQuery(u.RawQuery)
if err != nil {
return nil, fmt.Errorf("server error: cannot parse url params in link: %w", err)
}

cursor := params["_page_token"][0]

response.HasPreviousPage = true
response.PreviousCursor = cursor
}
}

return &response, nil
}
142 changes: 119 additions & 23 deletions pkg/clinical/infrastructure/datastore/cloudhealthcare/fhir_unit_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5008,6 +5008,30 @@ func TestStoreImpl_GetFHIRPatientEverything(t *testing.T) {
},
wantErr: true,
},
{
name: "Sad case: mandatory resource keys not found",
args: args{
ctx: context.Background(),
id: "1",
},
wantErr: true,
},
{
name: "Sad case: resourceType is not bundle",
args: args{
ctx: context.Background(),
id: "1",
},
wantErr: true,
},
{
name: "Sad case: type is not searchset",
args: args{
ctx: context.Background(),
id: "1",
},
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
Expand All @@ -5019,72 +5043,144 @@ func TestStoreImpl_GetFHIRPatientEverything(t *testing.T) {
data := map[string]interface{}{
"entry": []map[string]interface{}{
{
"fullUrl": "http://localhost",
"resource": map[string]interface{}{
"resourceType": "EpisodeOfCare",
"id": gofakeit.UUID(),
},
},
{
"fullUrl": "http://localhost",
"resource": map[string]interface{}{
"resourceType": "Observation",
"id": gofakeit.UUID(),
},
},
{
"fullUrl": "http://localhost",
"resource": map[string]interface{}{
"resourceType": "AllergyIntolerance",
"id": gofakeit.UUID(),
},
},
},
"type": "searchset",
"resourceType": "Bundle",
"total": 10,
"link": []map[string]interface{}{
{
"resource": map[string]interface{}{
"resourceType": "ServiceRequest",
"id": gofakeit.UUID(),
},
"relation": "next",
"url": "https://healthcare.googleapis.com/v1/projects/?_page_token=CSDDDSSJJ",
},
{
"resource": map[string]interface{}{
"resourceType": "MedicationRequest",
"id": gofakeit.UUID(),
},
"relation": "previous",
"url": "https://healthcare.googleapis.com/v1/projects/?_page_token=CSDDDSSJJ",
},
},
}

bs, err := json.Marshal(data)
if err != nil {
return nil, err
}

return bs, err
}
}
if tt.name == "Sad case: mandatory resource keys not found" {
dataset.MockGetFHIRPatientAllDataFn = func(fhirResourceID string, params map[string]interface{}) ([]byte, error) {
data := map[string]interface{}{
"entry": []map[string]interface{}{
{
"fullUrl": "http://localhost",
"resource": map[string]interface{}{
"resourceType": "Condition",
"resourceType": "EpisodeOfCare",
"id": gofakeit.UUID(),
},
},
},
"type": "searchset",
"total": 10,
"link": []map[string]interface{}{
{
"resource": map[string]interface{}{
"resourceType": "Encounter",
"id": gofakeit.UUID(),
},
"relation": "next",
"url": "https://healthcare.googleapis.com/v1/projects/?_page_token=CSDDDSSJJ",
},
{
"resource": map[string]interface{}{
"resourceType": "Composition",
"id": gofakeit.UUID(),
},
"relation": "previous",
"url": "https://healthcare.googleapis.com/v1/projects/?_page_token=CSDDDSSJJ",
},
},
}

bs, err := json.Marshal(data)
if err != nil {
return nil, err
}

return bs, err
}
}
if tt.name == "Sad case: resourceType is not bundle" {
dataset.MockGetFHIRPatientAllDataFn = func(fhirResourceID string, params map[string]interface{}) ([]byte, error) {
data := map[string]interface{}{
"entry": []map[string]interface{}{
{
"fullUrl": "http://localhost",
"resource": map[string]interface{}{
"resourceType": "MedicationStatement",
"resourceType": "EpisodeOfCare",
"id": gofakeit.UUID(),
},
},
},
"type": "searchset",
"resourceType": "Buundle",
"total": 10,
"link": []map[string]interface{}{
{
"resource": map[string]interface{}{
"resourceType": "Medication",
"id": gofakeit.UUID(),
},
"relation": "next",
"url": "https://healthcare.googleapis.com/v1/projects/?_page_token=CSDDDSSJJ",
},
{
"relation": "previous",
"url": "https://healthcare.googleapis.com/v1/projects/?_page_token=CSDDDSSJJ",
},
},
}

bs, err := json.Marshal(data)
if err != nil {
return nil, err
}

return bs, err
}
}
if tt.name == "Sad case: type is not searchset" {
dataset.MockGetFHIRPatientAllDataFn = func(fhirResourceID string, params map[string]interface{}) ([]byte, error) {
data := map[string]interface{}{
"entry": []map[string]interface{}{
{
"fullUrl": "http://localhost",
"resource": map[string]interface{}{
"resourceType": "Patient",
"resourceType": "EpisodeOfCare",
"id": gofakeit.UUID(),
},
},
},
"type": "searchseet",
"resourceType": "Bundle",
"total": 10,
"link": []map[string]interface{}{
{
"relation": "next",
"url": "https://healthcare.googleapis.com/v1/projects/?_page_token=CSDDDSSJJ",
},
{
"relation": "previous",
"url": "https://healthcare.googleapis.com/v1/projects/?_page_token=CSDDDSSJJ",
},
},
}

bs, err := json.Marshal(data)
Expand Down
Loading

0 comments on commit c4951a8

Please sign in to comment.