Skip to content

Commit

Permalink
Refactor how we parse, save, retrieve, and display RR Conditions and …
Browse files Browse the repository at this point in the history
…Summaries (#2875)

* update parsing schemas to properly grab RR info

* save loop for conditions and rule summaries working in postgres

* update comments

* update listEcrDataService and tests to retrieve conditions and summaries as arrays

* wip

* wip

* concatenate string arrays with newlines for ecr library display

* update snapshot test

* update tests with new qeury

* remove extra fields from BundleMetadata type

* change parameter type

* play with typing to make turbo build happy

* play with typing to make turbo build happy

* play with typing to make turbo build happy

* fix scoping issue with variable

* address comments

* change conditions display to a UL update tests

* cleanup random extras
  • Loading branch information
gordonfarrell authored Nov 13, 2024
1 parent c5f04ef commit ebbc188
Show file tree
Hide file tree
Showing 13 changed files with 740 additions and 199 deletions.
18 changes: 1 addition & 17 deletions containers/ecr-viewer/cypress/assets/data.sql

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -422,45 +422,51 @@ export const saveMetadataToPostgres = async (
) => {
const { ParameterizedQuery: PQ } = pgPromise;

if (process.env.METADATA_DATABASE_SCHEMA == "extended") {
return NextResponse.json(
{
message:
"Only the default metadata schema is implemented for Postgres.",
},
{ status: 501 },
);
}
const saveToEcrData = new PQ({
text: "INSERT INTO ecr_data (eICR_ID,patient_name_last,patient_name_first,patient_birth_date,data_source,report_date) VALUES ($1, $2, $3, $4, $5, $6) RETURNING eICR_ID",
values: [
ecrId,
metadata.last_name,
metadata.first_name,
metadata.birth_date,
"DB",
metadata.report_date,
],
});
try {
// Start transaction
await database.tx(async (t) => {
// Insert main ECR metadata
const saveToEcrData = new PQ({
text: "INSERT INTO ecr_data (eICR_ID, patient_name_last, patient_name_first, patient_birth_date, data_source, report_date) VALUES ($1, $2, $3, $4, $5, $6) RETURNING eICR_ID",
values: [
ecrId,
metadata.last_name,
metadata.first_name,
metadata.birth_date,
"DB",
metadata.report_date,
],
});

const saveRRConditions = new PQ({
text: "INSERT INTO ecr_rr_conditions (uuid, eICR_ID, condition) VALUES (uuid_generate_v4(), $1, $2) RETURNING uuid",
values: [ecrId, metadata.reportable_condition],
});
const ecrData = await t.one(saveToEcrData);

try {
const saveECR = await database.one(saveToEcrData);
const savedRRCondition = await database.one(saveRRConditions);
// Loop through each condition/rule object in rr array
if (metadata.rr && metadata.rr.length > 0) {
for (const rrItem of metadata.rr) {
// Insert condition into ecr_rr_conditions
const saveRRConditions = new PQ({
text: "INSERT INTO ecr_rr_conditions (uuid, eICR_ID, condition) VALUES (uuid_generate_v4(), $1, $2) RETURNING uuid",
values: [ecrId, rrItem.condition],
});

const saveRRSummary = new PQ({
text: "INSERT INTO ecr_rr_rule_summaries (uuid, ecr_rr_conditions_id,rule_summary) VALUES (uuid_generate_v4(), $1, $2)",
values: [savedRRCondition.uuid, metadata.rule_summary],
});
const savedRRCondition = await t.one(saveRRConditions);

// Insert associated rule summary into ecr_rr_rule_summaries
const saveRRSummary = new PQ({
text: "INSERT INTO ecr_rr_rule_summaries (uuid, ecr_rr_conditions_id, rule_summary) VALUES (uuid_generate_v4(), $1, $2)",
values: [savedRRCondition.uuid, rrItem.rule_summaries],
});

await database.none(saveRRSummary);
await t.none(saveRRSummary);
}

return ecrData;
}
});

// On successful transaction, return response
return NextResponse.json(
{ message: "Success. Saved metadata to database: " + saveECR.eICR_ID },
{ message: "Success. Saved metadata to database: " + ecrId },
{ status: 200 },
);
} catch (error: any) {
Expand Down
3 changes: 1 addition & 2 deletions containers/ecr-viewer/src/app/api/save-fhir-data/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,6 @@ export interface BundleMetadata {
first_name: string;
birth_date: string;
data_source: string;
reportable_condition: string;
rule_summary: string;
rr: RR[] | undefined;
report_date: string;
}
17 changes: 9 additions & 8 deletions containers/ecr-viewer/src/app/api/services/listEcrDataService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ export type EcrMetadataModel = {
patient_name_first: string;
patient_name_last: string;
patient_birth_date: Date;
condition: string;
rule_summary: string;
conditions: string[];
rule_summaries: string[];
report_date: Date;
date_created: Date;
};
Expand All @@ -24,8 +24,8 @@ export type EcrDisplay = {
patient_first_name: string;
patient_last_name: string;
patient_date_of_birth: string | undefined;
reportable_condition: string;
rule_summary: string;
reportable_conditions: string[];
rule_summaries: string[];
patient_report_date: string;
date_created: string;
};
Expand All @@ -46,14 +46,15 @@ export async function listEcrData(
searchTerm?: string,
): Promise<EcrDisplay[]> {
const list = await database.manyOrNone<EcrMetadataModel>(
"SELECT ed.eICR_ID, ed.patient_name_first, ed.patient_name_last, ed.patient_birth_date, ed.date_created, ed.report_date, erc.condition, ers.rule_summary, ed.report_date FROM ecr_data ed LEFT JOIN ecr_rr_conditions erc ON ed.eICR_ID = erc.eICR_ID LEFT JOIN ecr_rr_rule_summaries ers ON erc.uuid = ers.ecr_rr_conditions_id where $[whereClause] $[sortStatement] OFFSET $[startIndex] ROWS FETCH NEXT $[itemsPerPage] ROWS ONLY",
"SELECT ed.eICR_ID, ed.patient_name_first, ed.patient_name_last, ed.patient_birth_date, ed.date_created, ed.report_date, ed.report_date, ARRAY_AGG(DISTINCT erc.condition) AS conditions, ARRAY_AGG(DISTINCT ers.rule_summary) AS rule_summaries FROM ecr_data ed LEFT JOIN ecr_rr_conditions erc ON ed.eICR_ID = erc.eICR_ID LEFT JOIN ecr_rr_rule_summaries ers ON erc.uuid = ers.ecr_rr_conditions_id where $[whereClause] GROUP BY ed.eICR_ID, ed.patient_name_first, ed.patient_name_last, ed.patient_birth_date, ed.date_created, ed.report_date $[sortStatement] OFFSET $[startIndex] ROWS FETCH NEXT $[itemsPerPage] ROWS ONLY",
{
whereClause: generateSearchStatement(searchTerm),
startIndex,
itemsPerPage,
sortStatement: generateSortStatement(sortColumn, sortDirection),
},
);

return processMetadata(list);
}

Expand All @@ -73,8 +74,8 @@ export const processMetadata = (
patient_date_of_birth: object.patient_birth_date
? formatDate(new Date(object.patient_birth_date!).toISOString())
: "",
reportable_condition: object.condition || "",
rule_summary: object.rule_summary || "",
reportable_conditions: object.conditions || [],
rule_summaries: object.rule_summaries || [],
date_created: object.date_created
? convertUTCToLocalString(
formatDateTime(new Date(object.date_created!).toISOString()),
Expand Down Expand Up @@ -106,7 +107,7 @@ export const getTotalEcrCount = async (

/**
* A custom type format for search statement
* @param searchTerm - Optiaonl search term used to filter
* @param searchTerm - Optional search term used to filter
* @returns custom type format object for use by pg-promise
*/
export const generateSearchStatement = (searchTerm?: string) => ({
Expand Down
118 changes: 58 additions & 60 deletions containers/ecr-viewer/src/app/api/tests/listEcrDataService.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@ import {
generateSearchStatement,
} from "@/app/api/services/listEcrDataService";
import { database } from "../services/db";
import {
convertUTCToLocalString,
formatDate,
formatDateTime,
} from "../../services/formatService";

describe("listEcrDataService", () => {
describe("process Metadata", () => {
Expand All @@ -19,77 +24,70 @@ describe("listEcrDataService", () => {
});

it("should map each object in responseBody to the correct output structure", () => {
const date1 = new Date();
const date2 = new Date();
const date3 = new Date();

const responseBody: EcrMetadataModel[] = [
{
eicr_id: "ecr1",
date_created: new Date(),
date_created: date1,
patient_name_first: "Test",
patient_name_last: "Person",
patient_birth_date: new Date(),
report_date: new Date(),
condition: "Long",
rule_summary: "Longer",
patient_birth_date: date2,
report_date: date3,
conditions: ["Long"],
rule_summaries: ["Longer"],
data_source: "DB",
data: "",
data_link: "",
},
{
eicr_id: "ecr2",
date_created: new Date(),
date_created: date1,
patient_name_first: "Another",
patient_name_last: "Test",
patient_birth_date: new Date(),
report_date: new Date(),
condition: "Stuff",
rule_summary: "Other stuff",
patient_birth_date: date2,
report_date: date3,
conditions: ["Stuff"],
rule_summaries: ["Other stuff", "Even more stuff"],
data_source: "DB",
data: "",
data_link: "",
},
];

const expected: (
| EcrDisplay
| {
rule_summary: any;
ecrId: string;
patient_report_date: any;
date_created: any;
reportable_condition: any;
patient_last_name: any;
patient_date_of_birth: any;
patient_first_name: any;
}
| {
rule_summary: string;
ecrId: string;
patient_report_date: string;
date_created: any;
reportable_condition: string;
patient_last_name: string;
patient_date_of_birth: string;
patient_first_name: string;
}
)[] = [
const expected: EcrDisplay[] = [
{
ecrId: "ecr1",
date_created: expect.any(String),
patient_first_name: expect.any(String),
patient_last_name: expect.any(String),
patient_date_of_birth: expect.any(String),
patient_report_date: expect.any(String),
reportable_condition: expect.any(String),
rule_summary: expect.any(String),
date_created: convertUTCToLocalString(
formatDateTime(date1.toISOString()),
),
patient_first_name: "Test",
patient_last_name: "Person",
patient_date_of_birth: formatDate(date2.toISOString()),
patient_report_date: convertUTCToLocalString(
formatDateTime(date3.toISOString()),
),
reportable_conditions: expect.arrayContaining(["Long"]),
rule_summaries: expect.arrayContaining(["Longer"]),
},
{
ecrId: "ecr2",
date_created: expect.any(String),
patient_first_name: expect.any(String),
patient_last_name: expect.any(String),
patient_date_of_birth: expect.any(String),
patient_report_date: expect.any(String),
reportable_condition: expect.any(String),
rule_summary: expect.any(String),
date_created: convertUTCToLocalString(
formatDateTime(date1.toISOString()),
),
patient_first_name: "Another",
patient_last_name: "Test",
patient_date_of_birth: formatDate(date2.toISOString()),
patient_report_date: convertUTCToLocalString(
formatDateTime(date3.toISOString()),
),
reportable_conditions: expect.arrayContaining(["Stuff"]),
rule_summaries: expect.arrayContaining([
"Other stuff",
"Even more stuff",
]),
},
];
const result = processMetadata(responseBody);
Expand All @@ -113,7 +111,7 @@ describe("listEcrDataService", () => {
);
expect(database.manyOrNone).toHaveBeenCalledOnce();
expect(database.manyOrNone).toHaveBeenCalledWith(
"SELECT ed.eICR_ID, ed.patient_name_first, ed.patient_name_last, ed.patient_birth_date, ed.date_created, ed.report_date, erc.condition, ers.rule_summary, ed.report_date FROM ecr_data ed LEFT JOIN ecr_rr_conditions erc ON ed.eICR_ID = erc.eICR_ID LEFT JOIN ecr_rr_rule_summaries ers ON erc.uuid = ers.ecr_rr_conditions_id where $[whereClause] $[sortStatement] OFFSET $[startIndex] ROWS FETCH NEXT $[itemsPerPage] ROWS ONLY",
"SELECT ed.eICR_ID, ed.patient_name_first, ed.patient_name_last, ed.patient_birth_date, ed.date_created, ed.report_date, ed.report_date, ARRAY_AGG(DISTINCT erc.condition) AS conditions, ARRAY_AGG(DISTINCT ers.rule_summary) AS rule_summaries FROM ecr_data ed LEFT JOIN ecr_rr_conditions erc ON ed.eICR_ID = erc.eICR_ID LEFT JOIN ecr_rr_rule_summaries ers ON erc.uuid = ers.ecr_rr_conditions_id where $[whereClause] GROUP BY ed.eICR_ID, ed.patient_name_first, ed.patient_name_last, ed.patient_birth_date, ed.date_created, ed.report_date $[sortStatement] OFFSET $[startIndex] ROWS FETCH NEXT $[itemsPerPage] ROWS ONLY",
{
whereClause: expect.any(Object),
startIndex,
Expand All @@ -134,8 +132,8 @@ describe("listEcrDataService", () => {
patient_name_first: "Billy",
patient_name_last: "Bob",
report_date: new Date("06/21/2024 8:00 AM EDT"),
condition: "stuff",
rule_summary: "yup",
conditions: ["super ebola", "double ebola"],
rule_summaries: ["watch out for super ebola"],
data: "",
data_link: "",
data_source: "DB",
Expand All @@ -156,7 +154,7 @@ describe("listEcrDataService", () => {

expect(database.manyOrNone).toHaveBeenCalledOnce();
expect(database.manyOrNone).toHaveBeenCalledWith(
"SELECT ed.eICR_ID, ed.patient_name_first, ed.patient_name_last, ed.patient_birth_date, ed.date_created, ed.report_date, erc.condition, ers.rule_summary, ed.report_date FROM ecr_data ed LEFT JOIN ecr_rr_conditions erc ON ed.eICR_ID = erc.eICR_ID LEFT JOIN ecr_rr_rule_summaries ers ON erc.uuid = ers.ecr_rr_conditions_id where $[whereClause] $[sortStatement] OFFSET $[startIndex] ROWS FETCH NEXT $[itemsPerPage] ROWS ONLY",
"SELECT ed.eICR_ID, ed.patient_name_first, ed.patient_name_last, ed.patient_birth_date, ed.date_created, ed.report_date, ed.report_date, ARRAY_AGG(DISTINCT erc.condition) AS conditions, ARRAY_AGG(DISTINCT ers.rule_summary) AS rule_summaries FROM ecr_data ed LEFT JOIN ecr_rr_conditions erc ON ed.eICR_ID = erc.eICR_ID LEFT JOIN ecr_rr_rule_summaries ers ON erc.uuid = ers.ecr_rr_conditions_id where $[whereClause] GROUP BY ed.eICR_ID, ed.patient_name_first, ed.patient_name_last, ed.patient_birth_date, ed.date_created, ed.report_date $[sortStatement] OFFSET $[startIndex] ROWS FETCH NEXT $[itemsPerPage] ROWS ONLY",
{
whereClause: expect.any(Object),
startIndex,
Expand All @@ -172,8 +170,8 @@ describe("listEcrDataService", () => {
patient_first_name: "Billy",
patient_last_name: "Bob",
patient_report_date: "06/21/2024 8:00 AM EDT",
reportable_condition: "stuff",
rule_summary: "yup",
reportable_conditions: ["super ebola", "double ebola"],
rule_summaries: ["watch out for super ebola"],
},
]);
});
Expand All @@ -188,8 +186,8 @@ describe("listEcrDataService", () => {
patient_name_last: "lnam",
patient_birth_date: new Date("1990-01-01T05:00:00.000Z"),
report_date: new Date("2024-06-20T04:00:00.000Z"),
condition: "sick",
rule_summary: "stuff",
conditions: ["sick", "tired"],
rule_summaries: ["stuff", "disease discovered"],
data: "",
data_link: "",
data_source: "DB",
Expand All @@ -209,7 +207,7 @@ describe("listEcrDataService", () => {
);
expect(database.manyOrNone).toHaveBeenCalledOnce();
expect(database.manyOrNone).toHaveBeenCalledWith(
"SELECT ed.eICR_ID, ed.patient_name_first, ed.patient_name_last, ed.patient_birth_date, ed.date_created, ed.report_date, erc.condition, ers.rule_summary, ed.report_date FROM ecr_data ed LEFT JOIN ecr_rr_conditions erc ON ed.eICR_ID = erc.eICR_ID LEFT JOIN ecr_rr_rule_summaries ers ON erc.uuid = ers.ecr_rr_conditions_id where $[whereClause] $[sortStatement] OFFSET $[startIndex] ROWS FETCH NEXT $[itemsPerPage] ROWS ONLY",
"SELECT ed.eICR_ID, ed.patient_name_first, ed.patient_name_last, ed.patient_birth_date, ed.date_created, ed.report_date, ed.report_date, ARRAY_AGG(DISTINCT erc.condition) AS conditions, ARRAY_AGG(DISTINCT ers.rule_summary) AS rule_summaries FROM ecr_data ed LEFT JOIN ecr_rr_conditions erc ON ed.eICR_ID = erc.eICR_ID LEFT JOIN ecr_rr_rule_summaries ers ON erc.uuid = ers.ecr_rr_conditions_id where $[whereClause] GROUP BY ed.eICR_ID, ed.patient_name_first, ed.patient_name_last, ed.patient_birth_date, ed.date_created, ed.report_date $[sortStatement] OFFSET $[startIndex] ROWS FETCH NEXT $[itemsPerPage] ROWS ONLY",
{
whereClause: expect.any(Object),
startIndex,
Expand All @@ -225,8 +223,8 @@ describe("listEcrDataService", () => {
patient_first_name: "boy",
patient_last_name: "lnam",
patient_report_date: "06/20/2024 12:00 AM EDT",
reportable_condition: "sick",
rule_summary: "stuff",
reportable_conditions: ["sick", "tired"],
rule_summaries: ["stuff", "disease discovered"],
},
]);
});
Expand All @@ -247,7 +245,7 @@ describe("listEcrDataService", () => {
);
expect(database.manyOrNone).toHaveBeenCalledOnce();
expect(database.manyOrNone).toHaveBeenCalledWith(
"SELECT ed.eICR_ID, ed.patient_name_first, ed.patient_name_last, ed.patient_birth_date, ed.date_created, ed.report_date, erc.condition, ers.rule_summary, ed.report_date FROM ecr_data ed LEFT JOIN ecr_rr_conditions erc ON ed.eICR_ID = erc.eICR_ID LEFT JOIN ecr_rr_rule_summaries ers ON erc.uuid = ers.ecr_rr_conditions_id where $[whereClause] $[sortStatement] OFFSET $[startIndex] ROWS FETCH NEXT $[itemsPerPage] ROWS ONLY",
"SELECT ed.eICR_ID, ed.patient_name_first, ed.patient_name_last, ed.patient_birth_date, ed.date_created, ed.report_date, ed.report_date, ARRAY_AGG(DISTINCT erc.condition) AS conditions, ARRAY_AGG(DISTINCT ers.rule_summary) AS rule_summaries FROM ecr_data ed LEFT JOIN ecr_rr_conditions erc ON ed.eICR_ID = erc.eICR_ID LEFT JOIN ecr_rr_rule_summaries ers ON erc.uuid = ers.ecr_rr_conditions_id where $[whereClause] GROUP BY ed.eICR_ID, ed.patient_name_first, ed.patient_name_last, ed.patient_birth_date, ed.date_created, ed.report_date $[sortStatement] OFFSET $[startIndex] ROWS FETCH NEXT $[itemsPerPage] ROWS ONLY",
{
whereClause: expect.any(Object),
startIndex,
Expand All @@ -273,7 +271,7 @@ describe("listEcrDataService", () => {
);
expect(database.manyOrNone).toHaveBeenCalledOnce();
expect(database.manyOrNone).toHaveBeenCalledWith(
"SELECT ed.eICR_ID, ed.patient_name_first, ed.patient_name_last, ed.patient_birth_date, ed.date_created, ed.report_date, erc.condition, ers.rule_summary, ed.report_date FROM ecr_data ed LEFT JOIN ecr_rr_conditions erc ON ed.eICR_ID = erc.eICR_ID LEFT JOIN ecr_rr_rule_summaries ers ON erc.uuid = ers.ecr_rr_conditions_id where $[whereClause] $[sortStatement] OFFSET $[startIndex] ROWS FETCH NEXT $[itemsPerPage] ROWS ONLY",
"SELECT ed.eICR_ID, ed.patient_name_first, ed.patient_name_last, ed.patient_birth_date, ed.date_created, ed.report_date, ed.report_date, ARRAY_AGG(DISTINCT erc.condition) AS conditions, ARRAY_AGG(DISTINCT ers.rule_summary) AS rule_summaries FROM ecr_data ed LEFT JOIN ecr_rr_conditions erc ON ed.eICR_ID = erc.eICR_ID LEFT JOIN ecr_rr_rule_summaries ers ON erc.uuid = ers.ecr_rr_conditions_id where $[whereClause] GROUP BY ed.eICR_ID, ed.patient_name_first, ed.patient_name_last, ed.patient_birth_date, ed.date_created, ed.report_date $[sortStatement] OFFSET $[startIndex] ROWS FETCH NEXT $[itemsPerPage] ROWS ONLY",
{
whereClause: expect.any(Object),
startIndex,
Expand Down
Loading

0 comments on commit ebbc188

Please sign in to comment.