Skip to content

Commit

Permalink
Merge pull request #1695 from bcgov/feature/ALCS-1881
Browse files Browse the repository at this point in the history
Inbox Search and Code DRY up
  • Loading branch information
dhaselhan authored May 22, 2024
2 parents 4d37d58 + 7a67b8e commit e79f6f8
Show file tree
Hide file tree
Showing 32 changed files with 1,343 additions and 1,643 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ describe('ApplicationAdvancedSearchService', () => {
expect(mockQuery.where).toHaveBeenCalledTimes(2);
});

it('should call compileApplicationSearchQuery method correctly', async () => {
it('should call searchForFileNumbers method correctly', async () => {
const searchForFileNumbersSpy = jest
.spyOn(service as any, 'searchForFileNumbers')
.mockResolvedValue(new Set(['100000']));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,14 @@ import { RedisService } from '@app/common/redis/redis.service';
import { Injectable, Logger } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import * as hash from 'object-hash';
import { Brackets, QueryRunner, Repository } from 'typeorm';
import { ApplicationOwner } from '../../../portal/application-submission/application-owner/application-owner.entity';
import { ApplicationParcel } from '../../../portal/application-submission/application-parcel/application-parcel.entity';
import { QueryRunner, Repository } from 'typeorm';
import { ApplicationSubmission } from '../../../portal/application-submission/application-submission.entity';
import {
getNextDayToPacific,
getStartOfDayToPacific,
} from '../../../utils/pacific-date-time-helper';
import { formatStringToPostgresSearchStringArrayWithWildCard } from '../../../utils/search-helper';
import { intersectSets } from '../../../utils/set-helper';
import { ApplicationDecisionComponent } from '../../application-decision/application-decision-v2/application-decision/component/application-decision-component.entity';
import { APP_SEARCH_FILTERS } from '../../../utils/search/application-search-filters';
import { processSearchPromises } from '../../../utils/search/search-intersection';
import { ApplicationDecision } from '../../application-decision/application-decision.entity';
import { Application } from '../../application/application.entity';
import { LocalGovernment } from '../../local-government/local-government.entity';
Expand Down Expand Up @@ -121,39 +118,64 @@ export class ApplicationAdvancedSearchService {
const promises: Promise<{ fileNumber: string }[]>[] = [];

if (searchDto.fileNumber) {
this.addFileNumberResults(searchDto, promises);
const promise = APP_SEARCH_FILTERS.addFileNumberResults(
searchDto,
this.applicationRepository,
);
promises.push(promise);
}

if (searchDto.legacyId) {
this.addLegacyIDResults(searchDto, promises);
}

if (searchDto.portalStatusCodes && searchDto.portalStatusCodes.length > 0) {
this.addPortalStatusResults(searchDto, promises);
const promise = APP_SEARCH_FILTERS.addPortalStatusResults(
searchDto,
this.applicationSubmissionRepository,
);
promises.push(promise);
}

if (searchDto.governmentName) {
await this.addGovernmentResults(searchDto, promises);
const promise = APP_SEARCH_FILTERS.addGovernmentResults(
searchDto,
this.applicationRepository,
this.governmentRepository,
);
promises.push(promise);
}

if (searchDto.regionCode) {
this.addRegionResults(searchDto, promises);
}

if (searchDto.name) {
this.addNameResults(searchDto, promises);
const promise = APP_SEARCH_FILTERS.addNameResults(
searchDto,
this.applicationSubmissionRepository,
);
promises.push(promise);
}

if (searchDto.pid || searchDto.civicAddress) {
this.addParcelResults(searchDto, promises);
const promise = APP_SEARCH_FILTERS.addParcelResults(
searchDto,
this.applicationSubmissionRepository,
);
promises.push(promise);
}

if (searchDto.resolutionNumber || searchDto.resolutionYear) {
this.addDecisionResolutionResults(searchDto, promises);
}

if (searchDto.fileTypes.length > 0) {
this.addFileTypeResults(searchDto, promises);
const promise = APP_SEARCH_FILTERS.addFileTypeResults(
searchDto,
this.applicationRepository,
);
promises.push(promise);
}

if (searchDto.dateSubmittedFrom || searchDto.dateSubmittedTo) {
Expand All @@ -164,43 +186,15 @@ export class ApplicationAdvancedSearchService {
this.addDecisionDateResults(searchDto, promises);
}

//Intersect Sets
const t0 = performance.now();
const queryResults = await Promise.all(promises);

const allIds: Set<string>[] = [];
for (const result of queryResults) {
const fileNumbers = new Set<string>();
result.forEach((currentValue) => {
fileNumbers.add(currentValue.fileNumber);
});
allIds.push(fileNumbers);
}

const finalResult = intersectSets(allIds);

const finalResult = await processSearchPromises(promises);
const t1 = performance.now();
this.logger.debug(
`ALCS Application pre-search search took ${t1 - t0} milliseconds.`,
);
return finalResult;
}

private addFileNumberResults(
searchDto: SearchRequestDto,
promises: Promise<{ fileNumber: string }[]>[],
) {
const promise = this.applicationRepository.find({
where: {
fileNumber: searchDto.fileNumber,
},
select: {
fileNumber: true,
},
});
promises.push(promise);
}

private addLegacyIDResults(
searchDto: SearchRequestDto,
promises: Promise<{ fileNumber: string }[]>[],
Expand All @@ -216,42 +210,6 @@ export class ApplicationAdvancedSearchService {
promises.push(promise);
}

private addPortalStatusResults(
searchDto: SearchRequestDto,
promises: Promise<{ fileNumber: string }[]>[],
) {
const promise = this.applicationSubmissionRepository
.createQueryBuilder('appSubs')
.select('appSubs.fileNumber')
.where(
"alcs.get_current_status_for_application_submission_by_uuid(appSubs.uuid) ->> 'status_type_code' IN (:...statusCodes)",
{
statusCodes: searchDto.portalStatusCodes,
},
)
.getMany();
promises.push(promise);
}

private async addGovernmentResults(
searchDto: SearchRequestDto,
promises: Promise<{ fileNumber: string }[]>[],
) {
const government = await this.governmentRepository.findOneByOrFail({
name: searchDto.governmentName,
});

const promise = this.applicationRepository.find({
where: {
localGovernmentUuid: government.uuid,
},
select: {
fileNumber: true,
},
});
promises.push(promise);
}

private addRegionResults(
searchDto: SearchRequestDto,
promises: Promise<{ fileNumber: string }[]>[],
Expand All @@ -267,73 +225,6 @@ export class ApplicationAdvancedSearchService {
promises.push(promise);
}

private addNameResults(
searchDto: SearchRequestDto,
promises: Promise<{ fileNumber: string }[]>[],
) {
const formattedSearchString =
formatStringToPostgresSearchStringArrayWithWildCard(searchDto.name!);
const promise = this.applicationSubmissionRepository
.createQueryBuilder('appSub')
.select('appSub.fileNumber')
.leftJoin(
ApplicationOwner,
'application_owner',
'application_owner.application_submission_uuid = appSub.uuid',
)
.andWhere(
new Brackets((qb) =>
qb
.where(
"LOWER(application_owner.first_name || ' ' || application_owner.last_name) LIKE ANY (:names)",
{
names: formattedSearchString,
},
)
.orWhere('LOWER(application_owner.first_name) LIKE ANY (:names)', {
names: formattedSearchString,
})
.orWhere('LOWER(application_owner.last_name) LIKE ANY (:names)', {
names: formattedSearchString,
})
.orWhere(
'LOWER(application_owner.organization_name) LIKE ANY (:names)',
{
names: formattedSearchString,
},
),
),
)
.getMany();
promises.push(promise);
}

private addParcelResults(
searchDto: SearchRequestDto,
promises: Promise<{ fileNumber: string }[]>[],
) {
const query = this.applicationSubmissionRepository
.createQueryBuilder('appSub')
.select('appSub.fileNumber')
.leftJoin(
ApplicationParcel,
'parcel',
'parcel.application_submission_uuid = appSub.uuid',
);

if (searchDto.pid) {
query.andWhere('parcel.pid = :pid', { pid: searchDto.pid });
}

if (searchDto.civicAddress) {
query.andWhere('LOWER(parcel.civic_address) like LOWER(:civic_address)', {
civic_address: `%${searchDto.civicAddress}%`.toLowerCase(),
});
}

promises.push(query.getMany());
}

private addDecisionResolutionResults(
searchDto: SearchRequestDto,
promises: Promise<{ fileNumber: string }[]>[],
Expand Down Expand Up @@ -361,36 +252,6 @@ export class ApplicationAdvancedSearchService {
promises.push(query.getMany());
}

private addFileTypeResults(
searchDto: SearchRequestDto,
promises: Promise<{ fileNumber: string }[]>[],
) {
const query = this.applicationRepository
.createQueryBuilder('app')
.select('app.fileNumber')
.leftJoin(
ApplicationDecision,
'decision',
'decision.application_uuid = "app"."uuid" AND decision.is_draft = FALSE',
)
.leftJoin(
ApplicationDecisionComponent,
'decisionComponent',
'decisionComponent.application_decision_uuid = decision.uuid',
)
.where('app.type_code IN (:...typeCodes)', {
typeCodes: searchDto.fileTypes,
})
.orWhere(
'decisionComponent.application_decision_component_type_code IN (:...typeCodes)',
{
typeCodes: searchDto.fileTypes,
},
);

promises.push(query.getMany());
}

private addSubmittedDateResults(
searchDto: SearchRequestDto,
promises: Promise<{ fileNumber: string }[]>[],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ describe('InquiryAdvancedSearchService', () => {
pageSize: 10,
sortField: 'applicant',
sortDirection: 'ASC',
portalStatusCodes: [],
};

let mockQuery: any = {};
Expand All @@ -55,6 +56,11 @@ describe('InquiryAdvancedSearchService', () => {
mockQuery = createMockQuery();
mockQueryRunner = createMock();

mockRedisService.getClient.mockReturnValue({
get: async () => null,
setEx: async () => null,
} as any);

const module: TestingModule = await Test.createTestingModule({
providers: [
InquiryAdvancedSearchService,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { InjectRepository } from '@nestjs/typeorm';
import * as hash from 'object-hash';
import { QueryRunner, Repository } from 'typeorm';
import { formatStringToPostgresSearchStringArrayWithWildCard } from '../../../utils/search-helper';
import { intersectSets } from '../../../utils/set-helper';
import { processSearchPromises } from '../../../utils/search/search-intersection';
import { InquiryParcel } from '../../inquiry/inquiry-parcel/inquiry-parcel.entity';
import { Inquiry } from '../../inquiry/inquiry.entity';
import { LocalGovernment } from '../../local-government/local-government.entity';
Expand Down Expand Up @@ -143,21 +143,8 @@ export class InquiryAdvancedSearchService {
this.addFileTypeResults(searchDto, promises);
}

//Intersect Sets
const t0 = performance.now();
const queryResults = await Promise.all(promises);

const allIds: Set<string>[] = [];
for (const result of queryResults) {
const fileNumbers = new Set<string>();
result.forEach((currentValue) => {
fileNumbers.add(currentValue.fileNumber);
});
allIds.push(fileNumbers);
}

const finalResult = intersectSets(allIds);

const finalResult = await processSearchPromises(promises);
const t1 = performance.now();
this.logger.debug(
`ALCS Inquiry pre-search search took ${t1 - t0} milliseconds.`,
Expand Down
Loading

0 comments on commit e79f6f8

Please sign in to comment.