Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

replace use_cases with queries from the query table #297

Merged
merged 13 commits into from
Jan 21, 2025
10 changes: 7 additions & 3 deletions query-connector/e2e/alternate_queries.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,9 @@ test.describe("alternate queries with the Query Connector", () => {
await expect(
page.getByRole("heading", { name: PAGE_TITLES["select-query"].title }),
).toBeVisible();
await page.getByTestId("Select").selectOption("chlamydia");
await page
.getByTestId("Select")
.selectOption("Chlamydia case investigation");
await page.getByRole("button", { name: "Submit" }).click();
await expect(page.getByText("Loading")).toHaveCount(0, { timeout: 10000 });

Expand Down Expand Up @@ -65,7 +67,7 @@ test.describe("alternate queries with the Query Connector", () => {
await expect(
page.getByRole("heading", { name: "Select a query" }),
).toBeVisible();
await page.getByTestId("Select").selectOption("cancer");
await page.getByTestId("Select").selectOption("Cancer case investigation");
await page.getByRole("button", { name: "Submit" }).click();
await expect(page.getByText("Loading")).toHaveCount(0, { timeout: 10000 });

Expand All @@ -88,7 +90,9 @@ test.describe("alternate queries with the Query Connector", () => {
await page.getByRole("button", { name: "Search for patient" }).click();
await expect(page.getByText("Loading")).toHaveCount(0, { timeout: 10000 });
await page.getByRole("link", { name: "Select patient" }).click();
await page.getByTestId("Select").selectOption("chlamydia");
await page
.getByTestId("Select")
.selectOption("Chlamydia case investigation");
await page.getByRole("button", { name: "Submit" }).click();
await expect(page.getByText("Loading")).toHaveCount(0, { timeout: 10000 });

Expand Down
4 changes: 3 additions & 1 deletion query-connector/e2e/customize_query.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,9 @@ test.describe("querying with the Query Connector", () => {
await expect(
page.getByRole("heading", { name: "Select a query" }),
).toBeVisible();
await page.getByTestId("Select").selectOption("chlamydia");
await page
.getByTestId("Select")
.selectOption("Chlamydia case investigation");

await page.getByRole("button", { name: "Customize Query" }).click();
await expect(
Expand Down
4 changes: 3 additions & 1 deletion query-connector/e2e/query_workflow.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,9 @@ test.describe("querying with the Query Connector", () => {
await expect(
page.getByRole("heading", { name: "Select a query" }),
).toBeVisible();
await page.getByTestId("Select").selectOption("chlamydia");
await page
.getByTestId("Select")
.selectOption("Chlamydia case investigation");

// For some reason only in Chromium (ie not in firefox / webkit) there were
// issues connecting to the database for the cancer use case, which was resulting
Expand Down
66 changes: 38 additions & 28 deletions query-connector/src/app/api/query/route.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,26 @@
import { NextResponse, NextRequest } from "next/server";
import {
UseCaseQuery,
UseCaseQueryRequest,
makeFhirQuery,
QueryRequest,
QueryResponse,
createBundle,
APIQueryResponse,
} from "../../query-service";
import { parsePatientDemographics } from "./parsing-service";
import {
USE_CASES,
USE_CASE_DETAILS,
INVALID_FHIR_SERVERS,
INVALID_USE_CASE,
INVALID_QUERY,
RESPONSE_BODY_IS_NOT_PATIENT_RESOURCE,
MISSING_API_QUERY_PARAM,
MISSING_PATIENT_IDENTIFIERS,
USE_CASE_DETAILS,
USE_CASES,
} from "../../constants";

import { handleRequestError } from "./error-handling-service";
import {
getFhirServerNames,
getSavedQueryByName,
} from "@/app/database-service";
import { getFhirServerNames } from "@/app/database-service";
import { unnestValueSetsFromQuery } from "@/app/utils";
import { getSavedQueryById } from "@/app/backend/query-building";

/**
* Health check for TEFCA Viewer
Expand All @@ -33,11 +31,11 @@ export async function GET() {
}

/**
* Handles a POST request to query a given FHIR server for a given use case. The
* use_case and fhir_server are provided as query parameters in the request URL. The
* Handles a POST request to query a given FHIR server for a given query. The
* id and fhir_server are provided as query parameters in the request URL. The
* request body contains the FHIR patient resource to be queried.
* @param request - The incoming Next.js request object.
* @returns Response with UseCaseResponse.
* @returns Response with QueryResponse.
*/
export async function POST(request: NextRequest) {
let requestBody;
Expand Down Expand Up @@ -72,31 +70,34 @@ export async function POST(request: NextRequest) {
return NextResponse.json(OperationOutcome);
}

// Extract use_case and fhir_server from nextUrl
// Extract id and fhir_server from nextUrl
const params = request.nextUrl.searchParams;
const use_case = params.get("use_case");
//deprecated, prefer id
const use_case_param = params.get("use_case");
const id_param = params.get("id");
const fhir_server = params.get("fhir_server");
const fhirServers = await getFhirServerNames();

if (!use_case || !fhir_server) {
const id = id_param ? id_param : mapDeprecatedUseCaseToId(use_case_param);

if (!id || !fhir_server) {
const OperationOutcome = await handleRequestError(MISSING_API_QUERY_PARAM);
return NextResponse.json(OperationOutcome);
} else if (!Object.keys(USE_CASE_DETAILS).includes(use_case)) {
const OperationOutcome = await handleRequestError(INVALID_USE_CASE);
return NextResponse.json(OperationOutcome);
} else if (!Object.values(fhirServers).includes(fhir_server)) {
const OperationOutcome = await handleRequestError(INVALID_FHIR_SERVERS);
return NextResponse.json(OperationOutcome);
}

// Lookup default parameters for particular use-case search
const queryName = USE_CASE_DETAILS[use_case as USE_CASES].queryName;
const queryResults = await getSavedQueryByName(queryName);
const valueSets = unnestValueSetsFromQuery(queryResults);
const queryResults = await getSavedQueryById(id);

// Add params & patient identifiers to UseCaseRequest
const UseCaseRequest: UseCaseQueryRequest = {
use_case: use_case as USE_CASES,
if (queryResults.length === 0) {
const OperationOutcome = await handleRequestError(INVALID_QUERY);
return NextResponse.json(OperationOutcome);
}

// Add params & patient identifiers to QueryName
const QueryRequest: QueryRequest = {
query_name: queryResults[0].query_name,
fhir_server: fhir_server,
...(PatientIdentifiers.first_name && {
first_name: PatientIdentifiers.first_name,
Expand All @@ -109,13 +110,22 @@ export async function POST(request: NextRequest) {
...(PatientIdentifiers.phone && { phone: PatientIdentifiers.phone }),
};

const UseCaseQueryResponse: QueryResponse = await UseCaseQuery(
UseCaseRequest,
const valueSets = unnestValueSetsFromQuery(queryResults);

const QueryResponse: QueryResponse = await makeFhirQuery(
QueryRequest,
valueSets,
);

// Bundle data
const bundle: APIQueryResponse = await createBundle(UseCaseQueryResponse);
const bundle: APIQueryResponse = await createBundle(QueryResponse);

return NextResponse.json(bundle);
}

function mapDeprecatedUseCaseToId(use_case: string | null) {
if (use_case === null) return null;
const potentialUseCaseMatch = USE_CASE_DETAILS[use_case as USE_CASES];
const queryId = potentialUseCaseMatch?.id ?? null;
return queryId;
}
Loading
Loading