Skip to content

Commit e31c7c1

Browse files
committed
fix: reduce number of objects included in query
Resolves: Maximum SOQL offset allowed for apiName EntityParticle is 2000 Refs: BetterStack errors: f22afe5182d157e587c32e57fd8dcb5c20cf85514ecf883872e53ec482ee7f21 7bc67189cb1435c486c7c769eaf637567e79be6eda21d1ff5396565d29f4e34c f95a65ad60faacbaee215aaa70d06cfc1775b5027958ef453c192f5ec421e589
1 parent 0e57f0a commit e31c7c1

2 files changed

Lines changed: 23 additions & 10 deletions

File tree

libs/features/manage-permissions/src/usePermissionRecords.tsx

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { logger } from '@jetstream/shared/client-logger';
22
import { describeSObject, queryAll, queryAllUsingOffset } from '@jetstream/shared/data';
33
import { tracker } from '@jetstream/shared/ui-utils';
4-
import { getErrorMessage, groupByFlat } from '@jetstream/shared/utils';
4+
import { getErrorMessage, groupByFlat, splitArrayToMaxSize } from '@jetstream/shared/utils';
55
import {
66
EntityParticlePermissionsRecord,
77
FieldPermissionDefinitionMap,
@@ -133,21 +133,28 @@ export function usePermissionRecords(selectedOrg: SalesforceOrgUi, sobjects: str
133133
};
134134
}
135135

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+
136142
// This could be eligible to pull into generic method for expanded use
137143
async function queryAndCombineResults<T>(
138144
selectedOrg: SalesforceOrgUi,
139145
queries: string[],
140146
useOffset = false,
141147
isTooling = false,
142148
): 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);
151158
}
152159
}
153160
return output;

libs/features/manage-permissions/src/utils/permission-manager-utils.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,12 @@ import { Query, WhereClause, composeQuery, getField } from '@jetstreamapp/soql-p
3232

3333
const MAX_OBJ_IN_QUERY = 100;
3434

35+
/**
36+
* EntityParticle does not support queryMore, so we page it using OFFSET, which Salesforce caps at 2000 for this object.
37+
* Keep the objects really small to avoid hitting the 2000 limit
38+
*/
39+
const MAX_OBJ_IN_PERMISSIONABLE_FIELDS_QUERY = 2;
40+
3541
export function filterPermissionsSobjects(sobject: DescribeGlobalSObjectResult | null) {
3642
if (!sobject) {
3743
return false;
@@ -569,7 +575,7 @@ export function permissionsHaveError<T extends PermissionDefinitionMap>(permissi
569575
* @returns query for all permissionable fields
570576
*/
571577
export function getQueryForAllPermissionableFields(allSobjects: string[]): string[] {
572-
const queries = splitArrayToMaxSize(allSobjects, MAX_OBJ_IN_QUERY).map((sobjects) => {
578+
const queries = splitArrayToMaxSize(allSobjects, MAX_OBJ_IN_PERMISSIONABLE_FIELDS_QUERY).map((sobjects) => {
573579
return composeQuery({
574580
fields: [
575581
getField('QualifiedApiName'),

0 commit comments

Comments
 (0)