Skip to content

Commit f29772f

Browse files
committed
More checks for utilities
1 parent 07c1b2a commit f29772f

File tree

3 files changed

+51
-10
lines changed

3 files changed

+51
-10
lines changed

packages/federation/src/supergraph.ts

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ import {
7070
visitWithTypeInfo,
7171
} from 'graphql';
7272
import {
73+
extractPercentageFromLabel,
7374
filterInternalFieldsAndTypes,
7475
getArgsFromKeysForFederation,
7576
getCacheKeyFnFromKey,
@@ -1297,16 +1298,8 @@ export function getStitchingOptionsFromSupergraphSdl(
12971298
}
12981299

12991300
const label = fieldInfo.label;
1300-
// Extract 10 from percent(10) for example
1301-
const percentRegexp = /^percent\((\d+(?:\.\d+)?)\)$/;
1302-
const match = percentRegexp.exec(label);
1303-
if (match) {
1304-
const percent = Number(match[1]);
1305-
if (percent < 0 || percent > 100) {
1306-
throw new Error(
1307-
`Invalid progressive override percent value for field ${typeName}.${fieldInfo.field} in subgraph ${subgraphName}: ${label}`,
1308-
);
1309-
}
1301+
const percent = extractPercentageFromLabel(label);
1302+
if (percent != null) {
13101303
const possibility = percent / 100;
13111304
fieldConfig.override = () =>
13121305
progressiveOverridePossibilityHandler(possibility);

packages/federation/src/utils.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,3 +250,25 @@ export const progressiveOverridePossibilityHandler = (possibility: number) => {
250250
const rng = Math.random();
251251
return rng < possibility;
252252
};
253+
254+
export function extractPercentageFromLabel(label: string): number | undefined {
255+
if (label.startsWith('percent(') && label.endsWith(')')) {
256+
const regexp = /^percent\((\d+(?:\.\d+)?)\)$/;
257+
const match = regexp.exec(label);
258+
const percentageStr = match?.[1];
259+
if (!percentageStr) {
260+
throw new Error(`Expected a number in percent(x), got: ${label}`);
261+
}
262+
const parsedFloat = parseFloat(percentageStr);
263+
if (isNaN(parsedFloat)) {
264+
throw new Error(`Could not parse percentage value from label: ${label}`);
265+
}
266+
if (parsedFloat < 0 || parsedFloat > 100) {
267+
throw new Error(
268+
`Expected a percentage value between 0 and 100, got ${parsedFloat}`,
269+
);
270+
}
271+
return parsedFloat;
272+
}
273+
return undefined;
274+
}

packages/federation/tests/progressive-override.test.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { normalizedExecutor } from '@graphql-tools/executor';
33
import { parse } from 'graphql';
44
import { describe, expect, it } from 'vitest';
55
import { getStitchedSchemaFromLocalSchemas } from './getStitchedSchemaFromLocalSchemas';
6+
import { extractPercentageFromLabel } from '@graphql-tools/federation';
67

78
describe('Progressive Override', () => {
89
describe('Label processing', () => {
@@ -287,4 +288,29 @@ describe('Progressive Override', () => {
287288
});
288289
});
289290
});
291+
describe('percent(x) parsing', () => {
292+
it('support integers', () => {
293+
expect(extractPercentageFromLabel('percent(10)')).toBe(10);
294+
});
295+
it('support floats', () => {
296+
expect(extractPercentageFromLabel('percent(12.5)')).toBe(12.5);
297+
});
298+
it('returns undefined for non-matching labels', () => {
299+
expect(extractPercentageFromLabel('custom_label')).toBeUndefined();
300+
expect(extractPercentageFromLabel('percentile(10)')).toBeUndefined();
301+
});
302+
it('throws for out-of-bound numbers', () => {
303+
expect(() => extractPercentageFromLabel('percent(150)')).toThrowError(
304+
'Expected a percentage value between 0 and 100, got 150',
305+
);
306+
});
307+
it('throws for malformed percent labels', () => {
308+
expect(() => extractPercentageFromLabel('percent()')).toThrowError(
309+
'Expected a number in percent(x), got: percent()',
310+
);
311+
expect(() => extractPercentageFromLabel('percent(foo)')).toThrowError(
312+
'Expected a number in percent(x), got: percent(foo)',
313+
);
314+
});
315+
});
290316
});

0 commit comments

Comments
 (0)