Skip to content

Commit

Permalink
getCaseByDocketNumber-dxox-experiment: fix mocks
Browse files Browse the repository at this point in the history
  • Loading branch information
Mwindo committed Dec 12, 2024
1 parent 81d5e84 commit 35487f9
Show file tree
Hide file tree
Showing 4 changed files with 130 additions and 152 deletions.
24 changes: 14 additions & 10 deletions web-api/src/persistence/dynamo/cases/getCaseByDocketNumber.test.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
import '@web-api/persistence/postgres/caseCorrespondences/mocks.jest';
import '@web-api/persistence/postgres/cases/mocks.jest';
import '@web-api/persistence/postgres/workitems/mocks.jest';
import {
CASE_STATUS_TYPES,
ROLES,
} from '../../../../../shared/src/business/entities/EntityConstants';
import { applicationContext } from '../../../../../shared/src/business/test/createTestApplicationContext';
import { calculateDate } from '@shared/business/utilities/DateHandler';
import { caseCorrespondenceEntity } from '@web-api/persistence/postgres/caseCorrespondences/mapper';
import { getCaseByDocketNumber } from './getCaseByDocketNumber';
import { getCaseCorrespondenceByDocketNumber as getCaseCorrespondenceByDocketNumberMock } from '@web-api/persistence/postgres/caseCorrespondences/getCaseCorrespondenceByDocketNumber';
import { getCaseByDocketNumberPostgres as getCaseByDocketNumberPostgresMock } from '@web-api/persistence/postgres/cases/getCaseByDocketNumber';

const getCaseCorrespondenceByDocketNumber =
getCaseCorrespondenceByDocketNumberMock as jest.Mock;
const getCaseByDocketNumberPostgres =
getCaseByDocketNumberPostgresMock as jest.Mock;

describe('getCaseByDocketNumber', () => {
beforeEach(() => {
(getCaseCorrespondenceByDocketNumber as jest.Mock).mockResolvedValue([]);
getCaseByDocketNumberPostgres.mockResolvedValue([]);
});

it('should return data as received from persistence', async () => {
Expand Down Expand Up @@ -50,19 +50,21 @@ describe('getCaseByDocketNumber', () => {
});

it('should return case and its associated data', async () => {
getCaseCorrespondenceByDocketNumber.mockResolvedValue([
caseCorrespondenceEntity({
getCaseByDocketNumberPostgres.mockResolvedValue([
{
archived: false,
correspondenceId: 'abc-124',
docketNumber: '123-20',
filingDate: calculateDate({ dateString: '2024-11-06T21:05:08.191Z' }),
}),
caseCorrespondenceEntity({
},
{
archived: true,
correspondenceId: 'abc-123',
docketNumber: '123-20',
filingDate: calculateDate({
dateString: '2024-11-06T21:05:08.191Z',
}),
}),
},
]);

applicationContext.getDocumentClient().query.mockResolvedValue({
Expand Down Expand Up @@ -121,6 +123,7 @@ describe('getCaseByDocketNumber', () => {
{
archived: true,
correspondenceId: 'abc-123',
docketNumber: '123-20',
entityName: 'Correspondence',
filingDate: '2024-11-06T21:05:08.191Z',
},
Expand All @@ -137,6 +140,7 @@ describe('getCaseByDocketNumber', () => {
{
archived: false,
correspondenceId: 'abc-124',
docketNumber: '123-20',
entityName: 'Correspondence',
filingDate: '2024-11-06T21:05:08.191Z',
},
Expand Down
222 changes: 100 additions & 122 deletions web-api/src/persistence/dynamo/cases/getCaseByDocketNumber.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {
isCaseItem,
} from '../helpers/aggregateCaseItems';
import { caseCorrespondenceEntity } from '@web-api/persistence/postgres/caseCorrespondences/mapper';
import { getDbReader } from '@web-api/database';
import { getCaseByDocketNumberPostgres } from '@web-api/persistence/postgres/cases/getCaseByDocketNumber';
import { purgeDynamoKeys } from '@web-api/persistence/dynamo/helpers/purgeDynamoKeys';
import { queryFull } from '../../dynamodbClientService';
import { workItemEntity } from '@web-api/persistence/postgres/workitems/mapper';
Expand All @@ -24,141 +24,119 @@ export const getCaseByDocketNumber = async ({
docketNumber: string;
includeConsolidatedCases?: boolean;
}): Promise<RawCase> => {
try {
const caseItems = await queryFull({
ExpressionAttributeNames: {
'#pk': 'pk',
},
ExpressionAttributeValues: {
':pk': `case|${docketNumber}`,
},
KeyConditionExpression: '#pk = :pk',
applicationContext,
});
const caseItems = await queryFull({
ExpressionAttributeNames: {
'#pk': 'pk',
},
ExpressionAttributeValues: {
':pk': `case|${docketNumber}`,
},
KeyConditionExpression: '#pk = :pk',
applicationContext,
});

/*
/*
We have roughly three options to get all data associated with a case:
1) Separate queries for each aspect of a case. This is easier to understand but introduces network latency.
2) One big query with json aggregation to handle duplication across joins. This reduces network latency and reduces code here but makes for a complex query.
3) One big query that relies on code here to handle duplication across joins. This reduces network latency but means we have to run code to clean the data.
(Bonus 4: We introduce a finer-grained way of asking for exactly what case data is needed rather than getting it all by default.)
Below, we do 3.
*/
const postgresCaseData = await getDbReader(reader => {
return reader
.selectFrom('dwCase as c')
.leftJoin('dwWorkItem as d', 'd.docketNumber', 'c.docketNumber')
.leftJoin(
'dwCaseCorrespondence as co',
'c.docketNumber',
'co.docketNumber',
)
.where('c.docketNumber', '=', docketNumber)
.selectAll()
.select('c.docketNumber')
.execute();
});

const workItemsMap = new Map<string, any>();
const correspondencesMap = new Map<string, any>();
const postgresCaseData =
(await getCaseByDocketNumberPostgres(docketNumber)) || [];

for (const row of postgresCaseData) {
if (row.workItemId && !workItemsMap.has(row.workItemId)) {
workItemsMap.set(
row.workItemId,
workItemEntity({
assigneeId: row.assigneeId,
assigneeName: row.assigneeName,
associatedJudge: row.associatedJudge,
associatedJudgeId: row.associatedJudgeId,
caption: row.caption,
caseIsInProgress: row.caseIsInProgress,
completedAt: row.completedAt,
completedBy: row.completedBy,
completedByUserId: row.completedByUserId,
completedMessage: row.completedMessage,
createdAt: row.createdAt,
docketEntry: row.docketEntry,
docketNumber,
hideFromPendingMessages: row.hideFromPendingMessages,
highPriority: row.highPriority,
inProgress: row.inProgress,
isInitializeCase: row.isInitializeCase,
isRead: row.isRead,
section: row.section,
sentBy: row.sentBy,
sentBySection: row.sentBySection,
sentByUserId: row.sentByUserId,
updatedAt: row.updatedAt,
workItemId: row.workItemId,
}),
);
}
const workItemsMap = new Map<string, any>();
const correspondencesMap = new Map<string, any>();

if (
row.correspondenceId &&
!correspondencesMap.has(row.correspondenceId)
) {
correspondencesMap.set(
row.correspondenceId,
caseCorrespondenceEntity({
archived: row.archived,
correspondenceId: row.correspondenceId,
docketNumber,
documentTitle: row.documentTitle,
filedBy: row.filedBy,
filingDate: row.filingDate,
userId: row.userId,
}),
);
}
for (const row of postgresCaseData) {
if (row.workItemId && !workItemsMap.has(row.workItemId)) {
workItemsMap.set(
row.workItemId,
workItemEntity({
assigneeId: row.assigneeId,
assigneeName: row.assigneeName,
associatedJudge: row.associatedJudge,
associatedJudgeId: row.associatedJudgeId,
caption: row.caption,
caseIsInProgress: row.caseIsInProgress,
completedAt: row.completedAt,
completedBy: row.completedBy,
completedByUserId: row.completedByUserId,
completedMessage: row.completedMessage,
createdAt: row.createdAt,
docketEntry: row.docketEntry,
docketNumber,
hideFromPendingMessages: row.hideFromPendingMessages,
highPriority: row.highPriority,
inProgress: row.inProgress,
isInitializeCase: row.isInitializeCase,
isRead: row.isRead,
section: row.section,
sentBy: row.sentBy,
sentBySection: row.sentBySection,
sentByUserId: row.sentByUserId,
updatedAt: row.updatedAt,
workItemId: row.workItemId,
}),
);
}

const workItems = Array.from(workItemsMap.values());
const correspondences = Array.from(correspondencesMap.values());

const leadDocketNumber = caseItems.find(
(caseItem): caseItem is CaseRecord => isCaseItem(caseItem),
)?.leadDocketNumber;
let consolidatedCases: RawConsolidatedCaseSummary[] = [];
if (leadDocketNumber && includeConsolidatedCases) {
const consolidatedCaseItems = await queryFull<
| IrsPractitionerOnCaseRecord
| PrivatePractitionerOnCaseRecord
| CaseRecord
>({
ExpressionAttributeNames: {
'#gsi1pk': 'gsi1pk',
},
ExpressionAttributeValues: {
':gsi1pk': `leadCase|${leadDocketNumber}`,
},
IndexName: 'gsi1',
KeyConditionExpression: '#gsi1pk = :gsi1pk',
applicationContext,
});

consolidatedCases = aggregateConsolidatedCaseItems(consolidatedCaseItems);
if (row.correspondenceId && !correspondencesMap.has(row.correspondenceId)) {
correspondencesMap.set(
row.correspondenceId,
caseCorrespondenceEntity({
archived: row.archived,
correspondenceId: row.correspondenceId,
docketNumber,
documentTitle: row.documentTitle,
filedBy: row.filedBy,
filingDate: row.filingDate,
userId: row.userId,
}),
);
}
}

const workItems = Array.from(workItemsMap.values());
const correspondences = Array.from(correspondencesMap.values());

return purgeDynamoKeys({
...aggregateCaseItems([
...caseItems,
...correspondences.map(correspondenceItem => ({
...correspondenceItem,
pk: `case|${docketNumber}`,
sk: `correspondence|${correspondenceItem.correspondenceId}`,
})),
...workItems.map(workItem => ({
...workItem,
pk: `case|${docketNumber}`,
sk: `work-item|${workItem.workItemId}`,
})),
]),
consolidatedCases,
const leadDocketNumber = caseItems.find((caseItem): caseItem is CaseRecord =>
isCaseItem(caseItem),
)?.leadDocketNumber;
let consolidatedCases: RawConsolidatedCaseSummary[] = [];
if (leadDocketNumber && includeConsolidatedCases) {
const consolidatedCaseItems = await queryFull<
IrsPractitionerOnCaseRecord | PrivatePractitionerOnCaseRecord | CaseRecord
>({
ExpressionAttributeNames: {
'#gsi1pk': 'gsi1pk',
},
ExpressionAttributeValues: {
':gsi1pk': `leadCase|${leadDocketNumber}`,
},
IndexName: 'gsi1',
KeyConditionExpression: '#gsi1pk = :gsi1pk',
applicationContext,
});
} catch (e) {
console.log(e);

consolidatedCases = aggregateConsolidatedCaseItems(consolidatedCaseItems);
}
return {} as RawCase;

return purgeDynamoKeys({
...aggregateCaseItems([
...caseItems,
...correspondences.map(correspondenceItem => ({
...correspondenceItem,
pk: `case|${docketNumber}`,
sk: `correspondence|${correspondenceItem.correspondenceId}`,
})),
...workItems.map(workItem => ({
...workItem,
pk: `case|${docketNumber}`,
sk: `work-item|${workItem.workItemId}`,
})),
]),
consolidatedCases,
});
};
34 changes: 15 additions & 19 deletions web-api/src/persistence/postgres/cases/getCaseByDocketNumber.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,19 @@
import { Case } from '@shared/business/entities/cases/Case';
import { getDbReader } from '@web-api/database';

export const getCaseByDocketNumber = async ({
docketNumber,
}: {
docketNumber: string;
}): Promise<Case | undefined> => {
const caseResult = await getDbReader(reader =>
reader
.selectFrom('dwCase')
.where('docketNumber', '=', docketNumber)
.selectAll()
.executeTakeFirst(),
);

return caseResult
? new Case(
{ ...caseResult, associatedJudge: null },
{ authorizedUser: undefined },
// Named getCaseByDocketNumberPostgres until the Dynamo getCaseByDocketNumber is removed
export const getCaseByDocketNumberPostgres = async (docketNumber: string) => {
return await getDbReader(reader => {
return reader
.selectFrom('dwCase as c')
.leftJoin('dwWorkItem as d', 'd.docketNumber', 'c.docketNumber')
.leftJoin(
'dwCaseCorrespondence as co',
'c.docketNumber',
'co.docketNumber',
)
: undefined;
.where('c.docketNumber', '=', docketNumber)
.selectAll()
.select('c.docketNumber')
.execute();
});
};
2 changes: 1 addition & 1 deletion web-api/src/persistence/postgres/cases/mocks.jest.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { mockFactory } from '@shared/test/mockFactory';

jest.mock('@web-api/persistence/postgres/cases/getCaseByDocketNumber', () =>
mockFactory('getCaseByDocketNumber'),
mockFactory('getCaseByDocketNumberPostgres'),
);

jest.mock('@web-api/persistence/postgres/cases/upsertCase', () =>
Expand Down

0 comments on commit 35487f9

Please sign in to comment.