Skip to content

Commit cda078c

Browse files
authored
Better handling of wrapped types in list size validations (#3157)
Better handling of wrapped types in list size validations
1 parent e1e2605 commit cda078c

File tree

2 files changed

+40
-9
lines changed

2 files changed

+40
-9
lines changed

internals-js/src/__tests__/subgraphValidation.test.ts

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1584,8 +1584,16 @@ describe('@listSize', () => {
15841584
@link(url: "https://specs.apollo.dev/cost/v0.1", import: ["@listSize"])
15851585
15861586
type Query {
1587-
sliced(first: String, second: Int, third: Int!): [String]
1588-
@listSize(slicingArguments: ["first", "second", "third"])
1587+
sliced(
1588+
first: String
1589+
second: Int
1590+
third: Int!
1591+
fourth: [Int]
1592+
fifth: [Int]!
1593+
): [String]
1594+
@listSize(
1595+
slicingArguments: ["first", "second", "third", "fourth", "fifth"]
1596+
)
15891597
}
15901598
`;
15911599

@@ -1594,6 +1602,14 @@ describe('@listSize', () => {
15941602
'LIST_SIZE_INVALID_SLICING_ARGUMENT',
15951603
`[S] Slicing argument "Query.sliced(first:)" must be Int or Int!`,
15961604
],
1605+
[
1606+
'LIST_SIZE_INVALID_SLICING_ARGUMENT',
1607+
`[S] Slicing argument "Query.sliced(fourth:)" must be Int or Int!`,
1608+
],
1609+
[
1610+
'LIST_SIZE_INVALID_SLICING_ARGUMENT',
1611+
`[S] Slicing argument "Query.sliced(fifth:)" must be Int or Int!`,
1612+
],
15971613
]);
15981614
});
15991615

@@ -1620,7 +1636,7 @@ describe('@listSize', () => {
16201636
expect(buildForErrors(doc)).toStrictEqual([
16211637
[
16221638
'LIST_SIZE_INVALID_SIZED_FIELD',
1623-
`[S] Sized fields cannot be used because "Int" is not an object type`,
1639+
`[S] Sized fields cannot be used because "Int" is not a composite type`,
16241640
],
16251641
]);
16261642
});
@@ -1653,10 +1669,16 @@ describe('@listSize', () => {
16531669
@link(url: "https://specs.apollo.dev/cost/v0.1", import: ["@listSize"])
16541670
16551671
type Query {
1656-
a: A @listSize(assumedSize: 5, sizedFields: ["notList"])
1672+
a: A
1673+
@listSize(
1674+
assumedSize: 5
1675+
sizedFields: ["list", "nonNullList", "notList"]
1676+
)
16571677
}
16581678
16591679
type A {
1680+
list: [String]
1681+
nonNullList: [String]!
16601682
notList: String
16611683
}
16621684
`;

internals-js/src/federation.ts

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,9 @@ import {
3737
isWrapperType,
3838
possibleRuntimeTypes,
3939
isIntType,
40+
Type,
4041
} from "./definitions";
41-
import { assert, MultiMap, printHumanReadableList, OrderedMap, mapValues, assertUnreachable, isDefined } from "./utils";
42+
import { assert, MultiMap, printHumanReadableList, OrderedMap, mapValues, assertUnreachable } from "./utils";
4243
import { SDLValidationRule } from "graphql/validation/ValidationContext";
4344
import { specifiedSDLRules } from "graphql/validation/specifiedRules";
4445
import {
@@ -1097,14 +1098,18 @@ function validateAssumedSizeNotNegative(
10971098
// We omit this check to keep the validations to those that will otherwise cause runtime failures.
10981099
//
10991100
// With all that said, assumed size should not be negative.
1100-
if (isDefined(assumedSize) && assumedSize < 0) {
1101+
if (assumedSize !== undefined && assumedSize !== null && assumedSize < 0) {
11011102
errorCollector.push(ERRORS.LIST_SIZE_INVALID_ASSUMED_SIZE.err(
11021103
`Assumed size of "${parent.coordinate}" cannot be negative`,
11031104
{ nodes: sourceASTs(application, parent) },
11041105
));
11051106
}
11061107
}
11071108

1109+
function isNonNullIntType(ty: Type): boolean {
1110+
return isNonNullType(ty) && isIntType(ty.ofType)
1111+
}
1112+
11081113
function validateSlicingArgumentsAreValidIntegers(
11091114
application: Directive<SchemaElement<any, any>, ListSizeDirectiveArguments>,
11101115
parent: FieldDefinition<CompositeType>,
@@ -1120,7 +1125,7 @@ function validateSlicingArgumentsAreValidIntegers(
11201125
`Slicing argument "${slicingArgumentName}" is not an argument of "${parent.coordinate}"`,
11211126
{ nodes: sourceASTs(application, parent) }
11221127
));
1123-
} else if (!isIntType(slicingArgument.type) && !(isNonNullType(slicingArgument.type) && isIntType(slicingArgument.type.baseType()))) {
1128+
} else if (!isIntType(slicingArgument.type) && !isNonNullIntType(slicingArgument.type)) {
11241129
// Slicing arguments must be Int or Int!
11251130
errorCollector.push(ERRORS.LIST_SIZE_INVALID_SLICING_ARGUMENT.err(
11261131
`Slicing argument "${slicingArgument.coordinate}" must be Int or Int!`,
@@ -1130,6 +1135,10 @@ function validateSlicingArgumentsAreValidIntegers(
11301135
}
11311136
}
11321137

1138+
function isNonNullListType(ty: Type): boolean {
1139+
return isNonNullType(ty) && isListType(ty.ofType)
1140+
}
1141+
11331142
function validateSizedFieldsAreValidLists(
11341143
application: Directive<SchemaElement<any, any>, ListSizeDirectiveArguments>,
11351144
parent: FieldDefinition<CompositeType>,
@@ -1141,7 +1150,7 @@ function validateSizedFieldsAreValidLists(
11411150
if (!parent.type || !isCompositeType(parent.type)) {
11421151
// The output type must have fields
11431152
errorCollector.push(ERRORS.LIST_SIZE_INVALID_SIZED_FIELD.err(
1144-
`Sized fields cannot be used because "${parent.type}" is not an object type`,
1153+
`Sized fields cannot be used because "${parent.type}" is not a composite type`,
11451154
{ nodes: sourceASTs(application, parent)}
11461155
));
11471156
} else {
@@ -1153,7 +1162,7 @@ function validateSizedFieldsAreValidLists(
11531162
`Sized field "${sizedFieldName}" is not a field on type "${parent.type.coordinate}"`,
11541163
{ nodes: sourceASTs(application, parent) }
11551164
));
1156-
} else if (!sizedField.type || !isListType(sizedField.type)) {
1165+
} else if (!sizedField.type || !(isListType(sizedField.type) || isNonNullListType(sizedField.type))) {
11571166
// Sized fields must be lists
11581167
errorCollector.push(ERRORS.LIST_SIZE_APPLIED_TO_NON_LIST.err(
11591168
`Sized field "${sizedField.coordinate}" is not a list`,

0 commit comments

Comments
 (0)