Skip to content

Commit 709d65f

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 6d1c19f commit 709d65f

File tree

2 files changed

+128
-72
lines changed

2 files changed

+128
-72
lines changed

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

Lines changed: 110 additions & 67 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()
@@ -50,47 +52,37 @@ export class SearchFlowByFiltersStrategy implements FlowSearchStrategy {
5052
// to be able to sort the flows using the entity
5153
const isSortByEntity = orderBy && orderBy.entity !== 'flow';
5254
let sortByFlowIDsSet = new Set<string>();
55+
let sortByFlowIDsPromise: Promise<UniqueFlowEntity[]> = Promise.resolve([]);
5356
const orderByForFlow = mapFlowOrderBy(orderBy);
5457

5558
// Fetch sorted flow IDs only for the filtered subset instead of the whole table
5659
if (isSortByEntity) {
5760
// Get entity-sorted IDs then intersect with filtered subset
58-
const sortByFlowIDs = await this.flowService.getFlowIDsFromEntity(
61+
sortByFlowIDsPromise = this.flowService.getFlowIDsFromEntity(
5962
models,
6063
orderBy
6164
);
62-
sortByFlowIDsSet = new Set(
63-
[...sortByFlowIDs].map((o) => `${o.id}:${o.versionID}`)
64-
);
6565
} else {
6666
// Let the DB sort only the filtered IDs
67-
const sortByFlowIDs = await this.flowService.getFlows({
67+
sortByFlowIDsPromise = this.flowService.getFlows({
6868
models,
6969
orderBy: orderByForFlow,
7070
});
71-
sortByFlowIDsSet = new Set(
72-
[...sortByFlowIDs].map((o) => `${o.id}:${o.versionID}`)
73-
);
7471
}
7572
// We need to fetch the flowIDs by the nestedFlowFilters
7673
// if there are any
7774
const isFilterByNestedFilters = nestedFlowFilters !== undefined;
7875
let flowIDsFromNestedFlowFiltersSet = new Set<string>();
79-
76+
let flowsFromNestedFiltersPromise: Promise<FlowIdSearchStrategyResponse> =
77+
Promise.resolve({ flows: [] });
78+
let didFlowsFromNestedFiltersPromiseCreated = false;
8079
if (isFilterByNestedFilters) {
81-
const { flows }: FlowIdSearchStrategyResponse =
82-
await this.getFlowIdsFromNestedFlowFilters.search({
80+
flowsFromNestedFiltersPromise =
81+
this.getFlowIdsFromNestedFlowFilters.search({
8382
models,
8483
nestedFlowFilters,
8584
});
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-
);
85+
didFlowsFromNestedFiltersPromiseCreated = true;
9486
}
9587

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

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

107102
if (isFilterByCategory) {
108-
const { flows }: FlowIdSearchStrategyResponse =
109-
await this.getFlowIdsFromCategoryConditions.search({
103+
flowsFromCategoryFiltersPromise =
104+
this.getFlowIdsFromCategoryConditions.search({
110105
models,
111106
flowCategoryConditions: flowCategoryFilters ?? [],
112107
shortcutFilters,
113108
});
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-
);
109+
didFlowsFromCategoryFiltersPromiseCreated = true;
123110
}
124111

125112
// After that, if we need to filter by flowObjects
126113
// Obtain the flowIDs from the flowObjects
127114
const isFilterByFlowObjects = flowObjectFilters?.length > 0;
128115

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

131122
if (isFilterByFlowObjects) {
132123
// Firts step is to map the filters to the FlowObjectFiltersGrouped
133124
// To allow doing inclusive filtering between filters of the same type+direction
134125
// But exclusive filtering between filters of different type+direction
135-
const flowObjectFiltersGrouped =
126+
flowObjectFiltersGrouped =
136127
mapFlowFiltersToFlowObjectFiltersGrouped(flowObjectFilters);
137128

138-
const { flows: flowsFromObjectFilters }: FlowIdSearchStrategyResponse =
139-
await this.getFlowIdsFromObjectConditions.search({
129+
flowsFromObjectFiltersPromise =
130+
this.getFlowIdsFromObjectConditions.search({
140131
models,
141132
flowObjectFilterGrouped: flowObjectFiltersGrouped,
142133
});
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-
);
134+
didFlowsFromObjectFiltersPromiseCreated = true;
167135
}
168136

169137
// Lastly, we need to check if we need to filter by flow
@@ -173,6 +141,9 @@ export class SearchFlowByFiltersStrategy implements FlowSearchStrategy {
173141
const isFilterByFlowStatus = statusFilter !== undefined;
174142

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

177148
if (isFilterByFlow || isFilterByFlowStatus) {
178149
let flowConditions: FlowWhere = prepareFlowConditions(flowFilters);
@@ -182,21 +153,90 @@ export class SearchFlowByFiltersStrategy implements FlowSearchStrategy {
182153
statusFilter
183154
);
184155

185-
const flows: UniqueFlowEntity[] = await this.flowService.getFlows({
156+
flowsFromFlowFiltersPromise = this.flowService.getFlows({
186157
models,
187158
conditions: flowConditions,
188159
});
160+
didFlowsFromFlowFiltersPromiseCreated = true;
161+
}
189162

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-
}
163+
// Now we need to wait for all the promises to be resolved
164+
const [
165+
flowsFromCategoryFilters,
166+
flowsFromNestedFilters,
167+
flowsFromObjectFilters,
168+
flowsFromFlowFilters,
169+
sortByFlowIDs,
170+
] = await Promise.all([
171+
flowsFromCategoryFiltersPromise,
172+
flowsFromNestedFiltersPromise,
173+
flowsFromObjectFiltersPromise,
174+
flowsFromFlowFiltersPromise,
175+
sortByFlowIDsPromise,
176+
]);
194177

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

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

221264
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)