|
1 | 1 | import { logger } from '@jetstream/shared/client-logger'; |
2 | 2 | import { describeSObject, queryAll, queryAllUsingOffset } from '@jetstream/shared/data'; |
3 | 3 | import { tracker } from '@jetstream/shared/ui-utils'; |
4 | | -import { getErrorMessage, groupByFlat } from '@jetstream/shared/utils'; |
| 4 | +import { getErrorMessage, groupByFlat, splitArrayToMaxSize } from '@jetstream/shared/utils'; |
5 | 5 | import { |
6 | 6 | EntityParticlePermissionsRecord, |
7 | 7 | FieldPermissionDefinitionMap, |
@@ -133,21 +133,28 @@ export function usePermissionRecords(selectedOrg: SalesforceOrgUi, sobjects: str |
133 | 133 | }; |
134 | 134 | } |
135 | 135 |
|
| 136 | +/** |
| 137 | + * Number of queries to run concurrently. Offset-paged queries (EntityParticle) are split into many small batches to stay |
| 138 | + * under Salesforce's OFFSET cap, so we run them in bounded waves rather than sequentially to keep large selections fast. |
| 139 | + */ |
| 140 | +const QUERY_CONCURRENCY = 5; |
| 141 | + |
136 | 142 | // This could be eligible to pull into generic method for expanded use |
137 | 143 | async function queryAndCombineResults<T>( |
138 | 144 | selectedOrg: SalesforceOrgUi, |
139 | 145 | queries: string[], |
140 | 146 | useOffset = false, |
141 | 147 | isTooling = false, |
142 | 148 | ): Promise<T[]> { |
143 | | - let output: T[] = []; |
144 | | - for (const currQuery of queries) { |
145 | | - if (useOffset) { |
146 | | - const { queryResults } = await queryAllUsingOffset<T>(selectedOrg, currQuery, isTooling); |
147 | | - output = output.concat(queryResults.records); |
148 | | - } else { |
149 | | - const { queryResults } = await queryAll<T>(selectedOrg, currQuery, isTooling); |
150 | | - output = output.concat(queryResults.records); |
| 149 | + const runQuery = (currQuery: string) => |
| 150 | + useOffset ? queryAllUsingOffset<T>(selectedOrg, currQuery, isTooling) : queryAll<T>(selectedOrg, currQuery, isTooling); |
| 151 | + |
| 152 | + const output: T[] = []; |
| 153 | + // Results are keyed/grouped downstream, so ordering does not matter - run each wave concurrently |
| 154 | + for (const wave of splitArrayToMaxSize(queries, QUERY_CONCURRENCY)) { |
| 155 | + const waveResults = await Promise.all(wave.map(runQuery)); |
| 156 | + for (const { queryResults } of waveResults) { |
| 157 | + output.push(...queryResults.records); |
151 | 158 | } |
152 | 159 | } |
153 | 160 | return output; |
|
0 commit comments