Skip to content

Commit 991c57f

Browse files
committed
Store promises for other entities filters
This allow to handle all request at the same time Which helps with the time-performance of the endpoint
1 parent e2f4cf7 commit 991c57f

File tree

2 files changed

+128
-73
lines changed

2 files changed

+128
-73
lines changed

src/domain-services/flows/strategy/impl/search-flow-by-filters-strategy-impl.ts

Lines changed: 110 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { Service } from 'typedi';
2+
import { FlowObjectFilterGrouped } from '../../../flow-object/model';
23
import { FlowService } from '../../flow-service';
34
import type { FlowWhere, UniqueFlowEntity } from '../../model';
45
import type {
@@ -18,6 +19,7 @@ import {
1819
parseFlowIdVersionSet,
1920
prepareFlowConditions,
2021
prepareFlowStatusConditions,
22+
stringifyFlowIdVersionArray,
2123
} from './utils';
2224

2325
@Service()
@@ -49,48 +51,37 @@ export class SearchFlowByFiltersStrategy implements FlowSearchStrategy {
4951
// obtain the entities relation to the flow
5052
// to be able to sort the flows using the entity
5153
const isSortByEntity = orderBy && orderBy.entity !== 'flow';
52-
let sortByFlowIDsSet = new Set<string>();
54+
let sortByFlowIDsPromise: Promise<UniqueFlowEntity[]> = Promise.resolve([]);
5355
const orderByForFlow = mapFlowOrderBy(orderBy);
5456

5557
// Fetch sorted flow IDs only for the filtered subset instead of the whole table
5658
if (isSortByEntity) {
5759
// Get entity-sorted IDs then intersect with filtered subset
58-
const sortByFlowIDs = await this.flowService.getFlowIDsFromEntity(
60+
sortByFlowIDsPromise = this.flowService.getFlowIDsFromEntity(
5961
models,
6062
orderBy
6163
);
62-
sortByFlowIDsSet = new Set(
63-
[...sortByFlowIDs].map((o) => `${o.id}:${o.versionID}`)
64-
);
6564
} else {
6665
// Let the DB sort only the filtered IDs
67-
const sortByFlowIDs = await this.flowService.getFlows({
66+
sortByFlowIDsPromise = this.flowService.getFlows({
6867
models,
6968
orderBy: orderByForFlow,
7069
});
71-
sortByFlowIDsSet = new Set(
72-
[...sortByFlowIDs].map((o) => `${o.id}:${o.versionID}`)
73-
);
7470
}
7571
// We need to fetch the flowIDs by the nestedFlowFilters
7672
// if there are any
7773
const isFilterByNestedFilters = nestedFlowFilters !== undefined;
7874
let flowIDsFromNestedFlowFiltersSet = new Set<string>();
79-
75+
let flowsFromNestedFiltersPromise: Promise<FlowIdSearchStrategyResponse> =
76+
Promise.resolve({ flows: [] });
77+
let didFlowsFromNestedFiltersPromiseCreated = false;
8078
if (isFilterByNestedFilters) {
81-
const { flows }: FlowIdSearchStrategyResponse =
82-
await this.getFlowIdsFromNestedFlowFilters.search({
79+
flowsFromNestedFiltersPromise =
80+
this.getFlowIdsFromNestedFlowFilters.search({
8381
models,
8482
nestedFlowFilters,
8583
});
86-
87-
// If after this filter we have no flows, we can return an empty array
88-
if (flows.length === 0) {
89-
return { flows: [], count: 0 };
90-
}
91-
flowIDsFromNestedFlowFiltersSet = new Set(
92-
[...flows].map((o) => `${o.id}:${o.versionID}`)
93-
);
84+
didFlowsFromNestedFiltersPromiseCreated = true;
9485
}
9586

9687
// Now we need to check if we need to filter by category
@@ -103,67 +94,43 @@ export class SearchFlowByFiltersStrategy implements FlowSearchStrategy {
10394
isSearchByCategoryShotcut || flowCategoryFilters?.length > 0;
10495

10596
let flowIDsFromCategoryFiltersSet = new Set<string>();
97+
let flowsFromCategoryFiltersPromise: Promise<FlowIdSearchStrategyResponse> =
98+
Promise.resolve({ flows: [] });
99+
let didFlowsFromCategoryFiltersPromiseCreated = false;
106100

107101
if (isFilterByCategory) {
108-
const { flows }: FlowIdSearchStrategyResponse =
109-
await this.getFlowIdsFromCategoryConditions.search({
102+
flowsFromCategoryFiltersPromise =
103+
this.getFlowIdsFromCategoryConditions.search({
110104
models,
111105
flowCategoryConditions: flowCategoryFilters ?? [],
112106
shortcutFilters,
113107
});
114-
115-
// If after this filter we have no flows, we can return an empty array
116-
if (flows.length === 0) {
117-
return { flows: [], count: 0 };
118-
}
119-
120-
flowIDsFromCategoryFiltersSet = new Set(
121-
[...flows].map((o) => `${o.id}:${o.versionID}`)
122-
);
108+
didFlowsFromCategoryFiltersPromiseCreated = true;
123109
}
124110

125111
// After that, if we need to filter by flowObjects
126112
// Obtain the flowIDs from the flowObjects
127113
const isFilterByFlowObjects = flowObjectFilters?.length > 0;
128114

129115
let flowIDsFromObjectFiltersSet = new Set<string>();
116+
let flowsFromObjectFiltersPromise: Promise<FlowIdSearchStrategyResponse> =
117+
Promise.resolve({ flows: [] });
118+
let didFlowsFromObjectFiltersPromiseCreated = false;
119+
let flowObjectFiltersGrouped: FlowObjectFilterGrouped | null = null;
130120

131121
if (isFilterByFlowObjects) {
132122
// Firts step is to map the filters to the FlowObjectFiltersGrouped
133123
// To allow doing inclusive filtering between filters of the same type+direction
134124
// But exclusive filtering between filters of different type+direction
135-
const flowObjectFiltersGrouped =
125+
flowObjectFiltersGrouped =
136126
mapFlowFiltersToFlowObjectFiltersGrouped(flowObjectFilters);
137127

138-
const { flows: flowsFromObjectFilters }: FlowIdSearchStrategyResponse =
139-
await this.getFlowIdsFromObjectConditions.search({
128+
flowsFromObjectFiltersPromise =
129+
this.getFlowIdsFromObjectConditions.search({
140130
models,
141131
flowObjectFilterGrouped: flowObjectFiltersGrouped,
142132
});
143-
144-
// If after this filter we have no flows, we can return an empty array
145-
if (flowsFromObjectFilters.length === 0) {
146-
return { flows: [], count: 0 };
147-
}
148-
149-
// If 'includeChildrenOfParkedFlows' is defined and true
150-
// we need to obtain the flowIDs from the childs whose parent flows are parked
151-
if (shouldIncludeChildrenOfParkedFlows) {
152-
// We need to obtain the flowIDs from the childs whose parent flows are parked
153-
const childs =
154-
await this.flowService.getParkedParentFlowsByFlowObjectFilter(
155-
models,
156-
flowObjectFiltersGrouped
157-
);
158-
159-
for (const child of childs) {
160-
flowsFromObjectFilters.push(child);
161-
}
162-
}
163-
164-
flowIDsFromObjectFiltersSet = new Set(
165-
[...flowsFromObjectFilters].map((o) => `${o.id}:${o.versionID}`)
166-
);
133+
didFlowsFromObjectFiltersPromiseCreated = true;
167134
}
168135

169136
// Lastly, we need to check if we need to filter by flow
@@ -173,6 +140,9 @@ export class SearchFlowByFiltersStrategy implements FlowSearchStrategy {
173140
const isFilterByFlowStatus = statusFilter !== undefined;
174141

175142
let flowIDsFromFlowFiltersSet = new Set<string>();
143+
let flowsFromFlowFiltersPromise: Promise<UniqueFlowEntity[]> =
144+
Promise.resolve([]);
145+
let didFlowsFromFlowFiltersPromiseCreated = false;
176146

177147
if (isFilterByFlow || isFilterByFlowStatus) {
178148
let flowConditions: FlowWhere = prepareFlowConditions(flowFilters);
@@ -182,21 +152,90 @@ export class SearchFlowByFiltersStrategy implements FlowSearchStrategy {
182152
statusFilter
183153
);
184154

185-
const flows: UniqueFlowEntity[] = await this.flowService.getFlows({
155+
flowsFromFlowFiltersPromise = this.flowService.getFlows({
186156
models,
187157
conditions: flowConditions,
188158
});
159+
didFlowsFromFlowFiltersPromiseCreated = true;
160+
}
189161

190-
// If after this filter we have no flows, we can return an empty array
191-
if (flows.length === 0) {
192-
return { flows: [], count: 0 };
193-
}
162+
// Now we need to wait for all the promises to be resolved
163+
const [
164+
flowsFromCategoryFilters,
165+
flowsFromNestedFilters,
166+
flowsFromObjectFilters,
167+
flowsFromFlowFilters,
168+
sortByFlowIDs,
169+
] = await Promise.all([
170+
flowsFromCategoryFiltersPromise,
171+
flowsFromNestedFiltersPromise,
172+
flowsFromObjectFiltersPromise,
173+
flowsFromFlowFiltersPromise,
174+
sortByFlowIDsPromise,
175+
]);
194176

195-
flowIDsFromFlowFiltersSet = new Set(
196-
[...flows].map((o) => `${o.id}:${o.versionID}`)
197-
);
177+
// First check if we have created the promises
178+
// and if so, check if the flows are empty
179+
// If they are empty, we can return an empty array
180+
// and a count of 0
181+
if (
182+
didFlowsFromNestedFiltersPromiseCreated &&
183+
flowsFromNestedFilters.flows.length === 0
184+
) {
185+
return { flows: [], count: 0 };
198186
}
199187

188+
if (
189+
didFlowsFromCategoryFiltersPromiseCreated &&
190+
flowsFromCategoryFilters.flows.length === 0
191+
) {
192+
return { flows: [], count: 0 };
193+
}
194+
if (
195+
didFlowsFromObjectFiltersPromiseCreated &&
196+
flowsFromObjectFilters.flows.length === 0
197+
) {
198+
return { flows: [], count: 0 };
199+
}
200+
201+
if (
202+
didFlowsFromFlowFiltersPromiseCreated &&
203+
flowsFromFlowFilters.length === 0
204+
) {
205+
return { flows: [], count: 0 };
206+
}
207+
208+
// Now we need to obtain the flowIDs from the flows filtering promises
209+
flowIDsFromNestedFlowFiltersSet = stringifyFlowIdVersionArray(
210+
flowsFromNestedFilters.flows
211+
);
212+
flowIDsFromCategoryFiltersSet = stringifyFlowIdVersionArray(
213+
flowsFromCategoryFilters.flows
214+
);
215+
216+
// If 'includeChildrenOfParkedFlows' is defined and true
217+
// we need to obtain the flowIDs from the childs whose parent flows are parked
218+
// if (shouldIncludeChildrenOfParkedFlows) {
219+
// We need to obtain the flowIDs from the childs whose parent flows are parked
220+
if (shouldIncludeChildrenOfParkedFlows && flowObjectFiltersGrouped) {
221+
const childs =
222+
await this.flowService.getParkedParentFlowsByFlowObjectFilter(
223+
models,
224+
flowObjectFiltersGrouped
225+
);
226+
227+
for (const child of childs) {
228+
flowsFromObjectFilters.flows.push(child);
229+
}
230+
}
231+
flowIDsFromObjectFiltersSet = stringifyFlowIdVersionArray(
232+
flowsFromObjectFilters.flows
233+
);
234+
flowIDsFromFlowFiltersSet =
235+
stringifyFlowIdVersionArray(flowsFromFlowFilters);
236+
// Lastly, we need to obtain the flowIDs from the sortByFlowIDs
237+
const sortByFlowIDsSet = stringifyFlowIdVersionArray(sortByFlowIDs);
238+
200239
// We need to intersect the flowIDs from the flowObjects, flowCategoryFilters and flowFilters
201240
// to obtain the flowIDs that match all the filters
202241
const intersectedFlows: Set<string> = intersectSets(
@@ -209,13 +248,16 @@ export class SearchFlowByFiltersStrategy implements FlowSearchStrategy {
209248
if (intersectedFlows.size === 0) {
210249
return { flows: [], count: 0 };
211250
}
212-
251+
213252
// The method Set.prototype.intersection(...) compares the bigger set with the smaller one
214253
// and returns the smaller one, so we need to do the opposite
215254
// More likely the `sortedFlows` will be smaller than the `intersectedFlows`,
216255
// since `intersectedFlows` is the intersection of all the filters
217256
// so we need to reverse the list of `sortedFlows`
218-
const sortedFlows: Set<string> = intersectSets(intersectedFlows, sortByFlowIDsSet);
257+
const sortedFlows: Set<string> = intersectSets(
258+
intersectedFlows,
259+
sortByFlowIDsSet
260+
);
219261
const parsedSortedFlows = parseFlowIdVersionSet(sortedFlows).reverse();
220262

221263
const count = sortedFlows.size;

src/domain-services/flows/strategy/impl/utils.ts

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { type Database } from '@unocha/hpc-api-core/src/db';
2+
import { type FlowId } from '@unocha/hpc-api-core/src/db/models/flow';
23
import { Cond, Op } from '@unocha/hpc-api-core/src/db/util/conditions';
34
import type { InstanceDataOf } from '@unocha/hpc-api-core/src/db/util/model-definition';
45
import { type InstanceOfModel } from '@unocha/hpc-api-core/src/db/util/types';
@@ -26,7 +27,6 @@ import type {
2627
FlowWhere,
2728
UniqueFlowEntity,
2829
} from '../../model';
29-
import { type FlowId } from '@unocha/hpc-api-core/src/db/models/flow';
3030

3131
export const sortingColumnMapping: Map<string, string> = new Map<
3232
string,
@@ -438,13 +438,26 @@ export const buildOrderBy = (
438438
* Converts a Set of "id:versionID" strings into the array
439439
* of UniqueFlowEntity objects your existing search method expects.
440440
*/
441-
export const parseFlowIdVersionSet = (idVersionSet: Set<string>): UniqueFlowEntity[] => {
441+
export const parseFlowIdVersionSet = (
442+
idVersionSet: Set<string>
443+
): UniqueFlowEntity[] => {
442444
return [...idVersionSet].map((entry) => {
443445
const [idStr, versionStr] = entry.split(':');
444446
const id: FlowId = createBrandedValue(Number(idStr));
445-
return ({
447+
return {
446448
id,
447449
versionID: versionStr !== undefined ? Number(versionStr) : 0,
448-
}) satisfies UniqueFlowEntity;
450+
} satisfies UniqueFlowEntity;
449451
});
450-
}
452+
};
453+
454+
/**
455+
* Converts an array of UniqueFlowEntity objects into a Set of "id:versionID" strings.
456+
*/
457+
export const stringifyFlowIdVersionArray = (
458+
flowEntities: UniqueFlowEntity[]
459+
): Set<string> => {
460+
return new Set(
461+
flowEntities.map((entity) => `${entity.id}:${entity.versionID}`)
462+
);
463+
};

0 commit comments

Comments
 (0)