Skip to content

Commit

Permalink
feat: search for prevalence patients and some perf improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
9sneha-n committed May 23, 2024
1 parent d634b0f commit 5826dd9
Show file tree
Hide file tree
Showing 12 changed files with 172 additions and 15 deletions.
13 changes: 9 additions & 4 deletions src/CompositionRoot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,13 @@ import { ModuleD2Repository } from "./data/repositories/ModuleD2Repository";
import { DataStoreClient } from "./data/DataStoreClient";
import { ModulesTestRepository } from "./data/repositories/testRepositories/ModuleTestRepository";
import { GetSurveyUseCase } from "./domain/usecases/GetSurveyUseCase";
import { GetFilteredPatientsUseCase } from "./domain/usecases/GetFilteredPatientsUseCase";
import { GetFilteredPPSPatientsUseCase } from "./domain/usecases/GetFilteredPPSPatientsUseCase";
import { SurveyRepository } from "./domain/repositories/SurveyRepository";
import { UserD2Repository } from "./data/repositories/UserD2Repository";
import { SurveyD2Repository } from "./data/repositories/SurveyFormD2Repository";
import { SurveyTestRepository } from "./data/repositories/testRepositories/SurveyFormTestRepository";
import { SaveFormDataUseCase } from "./domain/usecases/SaveFormDataUseCase";
import { GetPaginatedPatientSurveysUseCase } from "./domain/usecases/GetPaginatedPatientSurveysUseCase";
import { GetPaginatedSurveysUseCase } from "./domain/usecases/GetPaginatedSurveysUseCase";
import { GetPopulatedSurveyUseCase } from "./domain/usecases/GetPopulatedSurveyUseCase";
import { NonAdminUserTestRepository } from "./data/repositories/testRepositories/NonAdminUserTestRepository";
import { DeleteSurveyUseCase } from "./domain/usecases/DeleteSurveyUseCase";
Expand All @@ -38,6 +38,7 @@ import { GetASTGuidelinesUseCase } from "./domain/usecases/GetASTGuidelinesUseCa
import { ASTGuidelinesD2Repository } from "./data/repositories/ASTGuidelinesD2Repository";
import { ASTGuidelinesTestRepository } from "./data/repositories/testRepositories/ASTGuidelinesTestRepository";
import { RemoveRepeatableProgramStageUseCase } from "./domain/usecases/RemoveRepeatableProgramStageUseCase";
import { GetFilteredPrevalencePatientsUseCase } from "./domain/usecases/GetFilteredPrevalencePatientsUseCase";

export type CompositionRoot = ReturnType<typeof getCompositionRoot>;

Expand Down Expand Up @@ -74,11 +75,15 @@ function getCompositionRoot(repositories: Repositories) {
repositories.astGuidelinesRepository
),
getSurveys: new GetAllSurveysUseCase(repositories.surveyFormRepository),
getFilteredPatients: new GetFilteredPatientsUseCase(
getFilteredPPSPatients: new GetFilteredPPSPatientsUseCase(
repositories.paginatedSurveyRepository,
repositories.surveyFormRepository
),
getPaginatedSurveys: new GetPaginatedPatientSurveysUseCase(
getFilteredPrevalencePatients: new GetFilteredPrevalencePatientsUseCase(
repositories.paginatedSurveyRepository,
repositories.surveyFormRepository
),
getPaginatedSurveys: new GetPaginatedSurveysUseCase(
repositories.paginatedSurveyRepository,
repositories.surveyFormRepository
),
Expand Down
33 changes: 33 additions & 0 deletions src/data/repositories/PaginatedSurveyD2Repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@ import { PaginatedSurveyRepository } from "../../domain/repositories/PaginatedSu
import { PaginatedReponse } from "../../domain/entities/TablePagination";
import { getParentDataElementForProgram, isTrackerProgram } from "../utils/surveyProgramHelper";
import {
AMR_SURVEYS_PREVALENCE_TEA_SURVEY_ID_CRF,
AMR_SURVEYS_PREVALENCE_TEA_UNIQUE_PATIENT_ID,
PPS_PATIENT_REGISTER_ID,
PREVALENCE_CASE_REPORT_FORM_ID,
SURVEY_PATIENT_CODE_DATAELEMENT_ID,
SURVEY_PATIENT_ID_DATAELEMENT_ID,
WARD_ID_DATAELEMENT_ID,
Expand Down Expand Up @@ -188,6 +191,36 @@ export class PaginatedSurveyD2Repository implements PaginatedSurveyRepository {
});
}

getFilteredPrevalencePatientSurveysByPatientId(
keyword: string,
orgUnitId: Id,
parentId: Id
): FutureData<PaginatedReponse<Survey[]>> {
return apiToFuture(
this.api.tracker.trackedEntities.get({
fields: { attributes: true, enrollments: true, trackedEntity: true, orgUnit: true },
program: PREVALENCE_CASE_REPORT_FORM_ID,
orgUnit: orgUnitId,
pageSize: 10,
totalPages: true,
filter: ` ${AMR_SURVEYS_PREVALENCE_TEA_UNIQUE_PATIENT_ID}:like:${keyword}, ${AMR_SURVEYS_PREVALENCE_TEA_SURVEY_ID_CRF}:eq:${parentId}`,
})
).flatMap(trackedEntities => {
const surveys = mapTrackedEntityToSurvey(trackedEntities, "PrevalenceCaseReportForm");

const paginatedSurveys: PaginatedReponse<Survey[]> = {
pager: {
page: trackedEntities.page,
pageSize: trackedEntities.pageSize,
total: trackedEntities.total,
},
objects: surveys,
};

return Future.success(paginatedSurveys);
});
}

getPaginatedSurveyChildCount(
parentProgram: Id,
orgUnitId: Id,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,13 @@ import { FutureData } from "../../api-futures";
import { SurveyChildCountType } from "../../utils/surveyChildCountHelper";

export class PaginatedSurveyTestRepository implements PaginatedSurveyRepository {
getFilteredPrevalencePatientSurveysByPatientId(
keyword: string,
orgUnitId: string,
parentId: string
): FutureData<PaginatedReponse<Survey[]>> {
throw new Error("Method not implemented.");
}
getFilteredPPSPatientByPatientCodeSurveys(
keyword: string,
orgUnitId: string,
Expand Down
12 changes: 10 additions & 2 deletions src/domain/entities/Questionnaire/Questionnaire.ts
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,12 @@ export class Questionnaire {

const updatedQuestionnaire = allQsInQuestionnaire.reduce(
(questionnaireAcc, question) => {
return this.updateQuestionnaire(questionnaireAcc, question, question.stageId);
return this.updateQuestionnaire(
questionnaireAcc,
question,
question.stageId,
true
);
},
questionnaire
);
Expand Down Expand Up @@ -240,7 +245,8 @@ export class Questionnaire {
static updateQuestionnaire(
questionnaire: Questionnaire,
updatedQuestion: Question,
stageId?: string
stageId?: string,
initialLoad = false
): Questionnaire {
//For the updated question, get all rules that are applicable
const allQsInQuestionnaire = questionnaire.stages.flatMap((stage: QuestionnaireStage) => {
Expand All @@ -255,6 +261,8 @@ export class Questionnaire {
allQsInQuestionnaire
);

if (initialLoad && applicableRules.length === 0) return questionnaire;

const isEntityQuestionUpdated = questionnaire.entity?.questions.find(
question => question.id === updatedQuestion.id
);
Expand Down
2 changes: 0 additions & 2 deletions src/domain/entities/Questionnaire/QuestionnaireRules.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,10 +115,8 @@ const handleRuleFunctions = (condition: string): boolean => {
if (match) {
const innerString = match[1];
if (innerString?.trim() === "") {
console.debug('The string between "fn:hasValue(" and ")" is empty.');
return false;
} else {
console.debug(`The string between "fn:hasValue(" and ")" is: ${innerString}`);
return true;
}
} else return false;
Expand Down
5 changes: 5 additions & 0 deletions src/domain/repositories/PaginatedSurveyRepository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@ export interface PaginatedSurveyRepository {
orgUnitId: Id,
parentId: Id
): FutureData<PaginatedReponse<Survey[]>>;
getFilteredPrevalencePatientSurveysByPatientId(
keyword: string,
orgUnitId: Id,
parentId: Id
): FutureData<PaginatedReponse<Survey[]>>;
getPaginatedSurveyChildCount(
parentProgram: Id,
orgUnitId: Id,
Expand Down
2 changes: 1 addition & 1 deletion src/domain/usecases/GetAllSurveysUseCase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ export class GetAllSurveysUseCase {
});
});

return Future.sequential(surveysWithName);
return Future.parallel(surveysWithName, { concurrency: 5 });
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { PaginatedSurveyRepository } from "../repositories/PaginatedSurveyReposi
import { SurveyRepository } from "../repositories/SurveyRepository";
import { getPaginatedSurveysWithParentName } from "../utils/surveyParentNameHelper";

export class GetFilteredPatientsUseCase {
export class GetFilteredPPSPatientsUseCase {
constructor(
private paginatedSurveyRepo: PaginatedSurveyRepository,
private surveyReporsitory: SurveyRepository
Expand Down
65 changes: 65 additions & 0 deletions src/domain/usecases/GetFilteredPrevalencePatientsUseCase.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import { Id } from "@eyeseetea/d2-api";
import { FutureData } from "../../data/api-futures";
import { Survey, SurveyBase } from "../entities/Survey";
import { PaginatedReponse } from "../entities/TablePagination";
import { PaginatedSurveyRepository } from "../repositories/PaginatedSurveyRepository";
import { SurveyRepository } from "../repositories/SurveyRepository";
import { Future } from "../entities/generic/Future";
import { getChildCount } from "../utils/getChildCountHelper";

export class GetFilteredPrevalencePatientsUseCase {
constructor(
private paginatedSurveyRepo: PaginatedSurveyRepository,
private surveyReporsitory: SurveyRepository
) {}

public execute(
keyword: string,
orgUnitId: Id,
parentId: Id
): FutureData<PaginatedReponse<Survey[]>> {
return this.paginatedSurveyRepo
.getFilteredPrevalencePatientSurveysByPatientId(keyword, orgUnitId, parentId)
.flatMap(filteredSurveys => {
const surveysWithName = filteredSurveys.objects.map(survey => {
return Future.join2(
this.surveyReporsitory.getSurveyNameAndASTGuidelineFromId(
survey.rootSurvey.id,
survey.surveyFormType
),
getChildCount({
surveyFormType: "PrevalenceCaseReportForm",
orgUnitId: survey.assignedOrgUnit.id,
parentSurveyId: survey.rootSurvey.id,
secondaryparentId: survey.id,
surveyReporsitory: this.paginatedSurveyRepo,
})
).map(([parentDetails, childCount]): Survey => {
const newRootSurvey: SurveyBase = {
surveyType: survey.rootSurvey.surveyType,
id: survey.rootSurvey.id,
name:
survey.rootSurvey.name === ""
? parentDetails.name
: survey.rootSurvey.name,
};

const updatedSurvey: Survey = {
...survey,
rootSurvey: newRootSurvey,
childCount: childCount,
};
return updatedSurvey;
});
});

return Future.parallel(surveysWithName, { concurrency: 5 }).map(updatedSurveys => {
const paginatedSurveys: PaginatedReponse<Survey[]> = {
pager: filteredSurveys.pager,
objects: updatedSurveys,
};
return paginatedSurveys;
});
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,7 @@ import _ from "../entities/generic/Collection";
import { getChildCount } from "../utils/getChildCountHelper";
import { Future } from "../entities/generic/Future";

//This use case fetched only patient surveys for both Prevalence and PPS modules
export class GetPaginatedPatientSurveysUseCase {
export class GetPaginatedSurveysUseCase {
constructor(
private paginatedSurveyRepo: PaginatedSurveyRepository,
private surveyReporsitory: SurveyRepository
Expand Down Expand Up @@ -68,7 +67,7 @@ export class GetPaginatedPatientSurveysUseCase {
});
});

return Future.sequential(surveysWithName).map(updatedSurveys => {
return Future.parallel(surveysWithName, { concurrency: 5 }).map(updatedSurveys => {
const paginatedSurveys: PaginatedReponse<Survey[]> = {
pager: surveys.pager,
objects: updatedSurveys,
Expand Down
13 changes: 13 additions & 0 deletions src/webapp/components/survey-list/SurveyList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,19 @@ export const SurveyList: React.FC<SurveyListProps> = ({ surveyFormType }) => {
/>
</>
)}
{surveyFormType === "PrevalenceCaseReportForm" && (
<>
<TextField
label={i18n.t("Search Patient ID")}
helperText={i18n.t("Filter by patient id")}
value={patientIdSearchKeyword}
onChange={e =>
setPatientIdSearchKeyword(e.target.value)
}
onKeyDown={handlePatientIdSearch}
/>
</>
)}
<Button
variant="contained"
color="primary"
Expand Down
28 changes: 26 additions & 2 deletions src/webapp/components/survey-list/hook/usePatientSearch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,12 @@ export const usePatientSearch = (
setTotal: Dispatch<SetStateAction<number | undefined>>
) => {
const { compositionRoot } = useAppContext();
const { currentHospitalForm, currentWardRegister } = useCurrentSurveys();
const {
currentHospitalForm,
currentWardRegister,
currentFacilityLevelForm,
currentPrevalenceSurveyForm,
} = useCurrentSurveys();
const snackbar = useSnackbar();

const [patientIdSearchKeyword, setPatientIdSearchKeyword] = useState("");
Expand Down Expand Up @@ -46,7 +51,7 @@ export const usePatientSearch = (
searchBy === "patientId" ? patientIdSearchKeyword : patientCodeSearchKeyword;
if (surveyFormType === "PPSPatientRegister" && searchKeyword) {
setIsLoading(true);
compositionRoot.surveys.getFilteredPatients
compositionRoot.surveys.getFilteredPPSPatients
.execute(
searchKeyword,
currentHospitalForm?.orgUnitId ?? "",
Expand All @@ -64,6 +69,25 @@ export const usePatientSearch = (
setIsLoading(false);
}
);
} else if (surveyFormType === "PrevalenceCaseReportForm" && searchKeyword) {
setIsLoading(true);
compositionRoot.surveys.getFilteredPrevalencePatients
.execute(
searchKeyword,
currentFacilityLevelForm?.orgUnitId ?? "",
currentPrevalenceSurveyForm?.id ?? ""
)
.run(
response => {
setSearchResultSurveys(response.objects);
setTotal(response.pager.total);
setIsLoading(false);
},
() => {
snackbar.error(i18n.t("Error fetching surveys"));
setIsLoading(false);
}
);
}
};

Expand Down

0 comments on commit 5826dd9

Please sign in to comment.