-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add 'search-flow-by-filters-strategy' implementation
Nested strategies to find flowIDs from different filters Merge 5de9ca3
- Loading branch information
Showing
5 changed files
with
553 additions
and
0 deletions.
There are no files selected for viewing
21 changes: 21 additions & 0 deletions
21
src/domain-services/flows/strategy/flowID-search-strategy.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
import { type Database } from '@unocha/hpc-api-core/src/db'; | ||
import { type ShortcutCategoryFilter } from '../../categories/model'; | ||
import { type FlowObjectFilterGrouped } from '../../flow-object/model'; | ||
import { type FlowCategory, type NestedFlowFilters } from '../graphql/args'; | ||
import { type UniqueFlowEntity } from '../model'; | ||
|
||
export interface FlowIdSearchStrategyResponse { | ||
flows: UniqueFlowEntity[]; | ||
} | ||
|
||
export interface FlowIdSearchStrategyArgs { | ||
models: Database; | ||
flowObjectFilterGrouped?: FlowObjectFilterGrouped; | ||
flowCategoryConditions?: FlowCategory[]; | ||
nestedFlowFilters?: NestedFlowFilters; | ||
shortcutFilters?: ShortcutCategoryFilter[] | null; | ||
} | ||
|
||
export interface FlowIDSearchStrategy { | ||
search(args: FlowIdSearchStrategyArgs): Promise<FlowIdSearchStrategyResponse>; | ||
} |
100 changes: 100 additions & 0 deletions
100
...domain-services/flows/strategy/impl/get-flowIds-flow-category-conditions-strategy-impl.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
import { type Database } from '@unocha/hpc-api-core/src/db'; | ||
import { type CategoryId } from '@unocha/hpc-api-core/src/db/models/category'; | ||
import { | ||
Op, | ||
type Condition, | ||
} from '@unocha/hpc-api-core/src/db/util/conditions'; | ||
import { type InstanceOfModel } from '@unocha/hpc-api-core/src/db/util/types'; | ||
import { createBrandedValue } from '@unocha/hpc-api-core/src/util/types'; | ||
import { Service } from 'typedi'; | ||
import { FlowService } from '../../flow-service'; | ||
import type { UniqueFlowEntity } from '../../model'; | ||
import { | ||
type FlowIDSearchStrategy, | ||
type FlowIdSearchStrategyArgs, | ||
type FlowIdSearchStrategyResponse, | ||
} from '../flowID-search-strategy'; | ||
import { mapFlowCategoryConditionsToWhereClause } from './utils'; | ||
|
||
@Service() | ||
export class GetFlowIdsFromCategoryConditionsStrategyImpl | ||
implements FlowIDSearchStrategy | ||
{ | ||
constructor(private readonly flowService: FlowService) {} | ||
|
||
async search( | ||
args: FlowIdSearchStrategyArgs | ||
): Promise<FlowIdSearchStrategyResponse> { | ||
const { models, flowCategoryConditions, shortcutFilters } = args; | ||
|
||
let categoriesIds: CategoryId[] = []; | ||
|
||
let whereClause = null; | ||
if (flowCategoryConditions) { | ||
whereClause = mapFlowCategoryConditionsToWhereClause( | ||
flowCategoryConditions | ||
); | ||
} | ||
if (whereClause) { | ||
const categories = await models.category.find({ | ||
where: whereClause, | ||
}); | ||
|
||
categoriesIds = categories.map((category) => category.id); | ||
} | ||
|
||
// Add category IDs from shortcut filter | ||
// to the list of category IDs IN or NOT_IN | ||
const categoriesIdsFromShortcutFilterIN: CategoryId[] = []; | ||
const categoriesIdsFromShortcutFilterNOTIN: CategoryId[] = []; | ||
|
||
if (shortcutFilters) { | ||
for (const shortcut of shortcutFilters) { | ||
if (shortcut.operation === Op.IN) { | ||
categoriesIdsFromShortcutFilterIN.push( | ||
createBrandedValue(shortcut.id) | ||
); | ||
} else { | ||
categoriesIdsFromShortcutFilterNOTIN.push( | ||
createBrandedValue(shortcut.id) | ||
); | ||
} | ||
} | ||
} | ||
|
||
// Search categoriesRef with categoriesID IN and categoriesIdsFromShortcutFilterIN | ||
// and categoriesIdsFromShortcutFilterNOTIN | ||
const where: Condition<InstanceOfModel<Database['categoryRef']>> = { | ||
objectType: 'flow', | ||
}; | ||
|
||
if (categoriesIdsFromShortcutFilterNOTIN.length > 0) { | ||
where['categoryID'] = { | ||
[Op.NOT_IN]: categoriesIdsFromShortcutFilterNOTIN, | ||
}; | ||
} | ||
|
||
const categoriesIDsIN = [ | ||
...categoriesIds, | ||
...categoriesIdsFromShortcutFilterIN, | ||
]; | ||
|
||
if (categoriesIDsIN.length > 0) { | ||
where['categoryID'] = { [Op.IN]: categoriesIDsIN }; | ||
} | ||
|
||
const categoriesRef = await models.categoryRef.find({ | ||
where, | ||
distinct: ['objectID', 'versionID'], | ||
}); | ||
|
||
// Map categoryRef to UniqueFlowEntity (flowId and versionID) | ||
const flowIDsFromCategoryRef: UniqueFlowEntity[] = categoriesRef.map( | ||
(catRef) => ({ | ||
id: createBrandedValue(catRef.objectID), | ||
versionID: catRef.versionID, | ||
}) | ||
); | ||
return { flows: flowIDsFromCategoryRef }; | ||
} | ||
} |
102 changes: 102 additions & 0 deletions
102
...n-services/flows/strategy/impl/get-flowIds-flow-from-nested-flow-filters-strategy-impl.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
import { Service } from 'typedi'; | ||
import { ExternalReferenceService } from '../../../external-reference/external-reference-service'; | ||
import { LegacyService } from '../../../legacy/legacy-service'; | ||
import { ReportDetailService } from '../../../report-details/report-detail-service'; | ||
import { FlowService } from '../../flow-service'; | ||
import type { UniqueFlowEntity } from '../../model'; | ||
import { | ||
type FlowIDSearchStrategy, | ||
type FlowIdSearchStrategyArgs, | ||
type FlowIdSearchStrategyResponse, | ||
} from '../flowID-search-strategy'; | ||
import { intersectUniqueFlowEntities } from './utils'; | ||
|
||
@Service() | ||
export class GetFlowIdsFromNestedFlowFiltersStrategyImpl | ||
implements FlowIDSearchStrategy | ||
{ | ||
constructor( | ||
private readonly reportDetailService: ReportDetailService, | ||
private readonly legacyService: LegacyService, | ||
private readonly externalRefenceService: ExternalReferenceService, | ||
private readonly flowService: FlowService | ||
) {} | ||
|
||
async search( | ||
args: FlowIdSearchStrategyArgs | ||
): Promise<FlowIdSearchStrategyResponse> { | ||
const { models, nestedFlowFilters } = args; | ||
|
||
let flowsReporterReferenceCode: UniqueFlowEntity[] = []; | ||
let flowsSourceSystemId: UniqueFlowEntity[] = []; | ||
let flowsSystemId: UniqueFlowEntity[] = []; | ||
const flowsLegacyId: UniqueFlowEntity[] = []; | ||
|
||
// Get the flowIDs using 'reporterReferenceCode' | ||
if (nestedFlowFilters?.reporterRefCode) { | ||
flowsReporterReferenceCode = | ||
await this.reportDetailService.getUniqueFlowIDsFromReportDetailsByReporterReferenceCode( | ||
models, | ||
nestedFlowFilters.reporterRefCode | ||
); | ||
} | ||
|
||
// Get the flowIDs using 'sourceSystemID' from 'reportDetail' | ||
if (nestedFlowFilters?.sourceSystemID) { | ||
flowsSourceSystemId = | ||
await this.reportDetailService.getUniqueFlowIDsFromReportDetailsBySourceSystemID( | ||
models, | ||
nestedFlowFilters.sourceSystemID | ||
); | ||
} | ||
|
||
// Get the flowIDs using 'systemID' from 'externalRefecence' | ||
if (nestedFlowFilters?.systemID) { | ||
flowsSystemId = | ||
await this.externalRefenceService.getUniqueFlowIDsBySystemID( | ||
models, | ||
nestedFlowFilters.systemID | ||
); | ||
} | ||
|
||
// Get the flowIDs using 'legacyID' | ||
if (nestedFlowFilters?.legacyID) { | ||
const flowID = await this.legacyService.getFlowIdFromLegacyId( | ||
models, | ||
nestedFlowFilters.legacyID | ||
); | ||
|
||
if (flowID) { | ||
flowsLegacyId.push({ | ||
id: flowID, | ||
versionID: 1, | ||
}); | ||
} | ||
} | ||
|
||
// Intersect the flowIDs from the nestedFlowFilters | ||
const flowIDsFromNestedFlowFilters: UniqueFlowEntity[] = | ||
intersectUniqueFlowEntities( | ||
flowsReporterReferenceCode, | ||
flowsSourceSystemId, | ||
flowsSystemId, | ||
flowsLegacyId | ||
); | ||
|
||
if (flowIDsFromNestedFlowFilters.length === 0) { | ||
return { flows: [] }; | ||
} | ||
// Once gathered and disjoined the flowIDs from the nestedFlowFilters | ||
// Look after this uniqueFlows in the flow table | ||
const flows = await this.flowService.progresiveSearch( | ||
models, | ||
flowIDsFromNestedFlowFilters, | ||
1000, | ||
0, | ||
false, // Stop when we have the limit | ||
[] | ||
); | ||
|
||
return { flows }; | ||
} | ||
} |
57 changes: 57 additions & 0 deletions
57
src/domain-services/flows/strategy/impl/get-flowIds-flow-object-conditions-strategy-impl.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
import { Op } from '@unocha/hpc-api-core/src/db/util/conditions'; | ||
import { Service } from 'typedi'; | ||
import { type UniqueFlowEntity } from '../../model'; | ||
import { | ||
type FlowIDSearchStrategy, | ||
type FlowIdSearchStrategyArgs, | ||
type FlowIdSearchStrategyResponse, | ||
} from '../flowID-search-strategy'; | ||
import { intersectUniqueFlowEntities } from './utils'; | ||
|
||
@Service() | ||
export class GetFlowIdsFromObjectConditionsStrategyImpl | ||
implements FlowIDSearchStrategy | ||
{ | ||
constructor() {} | ||
|
||
async search( | ||
args: FlowIdSearchStrategyArgs | ||
): Promise<FlowIdSearchStrategyResponse> { | ||
const { flowObjectFilterGrouped, models } = args; | ||
|
||
if (!flowObjectFilterGrouped) { | ||
return { flows: [] }; | ||
} | ||
|
||
let intersectedFlows: UniqueFlowEntity[] = []; | ||
|
||
for (const [flowObjectType, group] of flowObjectFilterGrouped.entries()) { | ||
for (const [direction, ids] of group.entries()) { | ||
const condition = { | ||
objectType: flowObjectType, | ||
refDirection: direction, | ||
objectID: { [Op.IN]: ids }, | ||
}; | ||
const flowObjectsFound = await models.flowObject.find({ | ||
where: condition, | ||
}); | ||
|
||
const uniqueFlowObjectsEntities: UniqueFlowEntity[] = | ||
flowObjectsFound.map( | ||
(flowObject) => | ||
({ | ||
id: flowObject.flowID, | ||
versionID: flowObject.versionID, | ||
}) satisfies UniqueFlowEntity | ||
); | ||
|
||
intersectedFlows = intersectUniqueFlowEntities( | ||
intersectedFlows, | ||
uniqueFlowObjectsEntities | ||
); | ||
} | ||
} | ||
|
||
return { flows: intersectedFlows }; | ||
} | ||
} |
Oops, something went wrong.