Skip to content

Commit 8e6e41f

Browse files
authored
Merge pull request #30 from wayfair-incubator/gwardwell_improve_empty_froid_key_errors
Improves error messages when an empty key is generated
2 parents fa1a6dc + 7c10892 commit 8e6e41f

File tree

5 files changed

+66
-9
lines changed

5 files changed

+66
-9
lines changed

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,13 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to
77
[Semantic Versioning](https://semver.org/spec/v2.0.0.html).
88

9+
## [v3.2.2] - 2024-08-20
10+
11+
### Fixed
12+
13+
- Improves the error message surfaced in cases where FROID generates an empty
14+
key.
15+
916
## [v3.2.1] - 2024-04-29
1017

1118
### Fixed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@wayfair/node-froid",
3-
"version": "3.2.1",
3+
"version": "3.2.2",
44
"description": "Federated GQL Relay Object Identification implementation",
55
"main": "dist/index.js",
66
"types": "dist/index.d.ts",

src/schema/Key.ts

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ export class Key {
7171
parseableField = Key.getKeyDirectiveFields(parseableField);
7272
}
7373
(
74-
Key.parseKeyFields(parseableField)
74+
Key.parseKeyFields(this.typename, parseableField)
7575
.definitions[0] as OperationDefinitionNode
7676
)?.selectionSet?.selections?.forEach((selection) =>
7777
this.addSelection(selection)
@@ -174,6 +174,7 @@ export class Key {
174174
*/
175175
public toString(): string {
176176
return Key.getSortedSelectionSetFields(
177+
this.typename,
177178
this._fields.map((field) => field.toString()).join(' ')
178179
);
179180
}
@@ -210,10 +211,22 @@ export class Key {
210211
* Parses a key fields string into AST.
211212
*
212213
* @param {string} keyFields - The key fields string
214+
* @param {string} typename - The typename of the node the directive belongs to
213215
* @returns {DocumentNode} The key fields represented in AST
214216
*/
215-
private static parseKeyFields(keyFields: string): DocumentNode {
216-
return parse(`{${keyFields}}`, {noLocation: true});
217+
private static parseKeyFields(
218+
typename: string,
219+
keyFields: string
220+
): DocumentNode {
221+
try {
222+
return parse(`{${keyFields}}`, {noLocation: true});
223+
} catch (error) {
224+
throw new Error(
225+
`Failed to parse key fields "${keyFields}" for type "${typename}" due to error: ${
226+
(error as Error).message
227+
}`
228+
);
229+
}
217230
}
218231

219232
/**
@@ -234,12 +247,18 @@ export class Key {
234247
* Sorts the selection set fields.
235248
*
236249
* @param {string} fields - The selection set fields.
250+
* @param {string} typename - The typename of the node the directive belongs to
237251
* @returns {string} The sorted selection set fields.
238252
*/
239-
public static getSortedSelectionSetFields(fields: string): string {
253+
public static getSortedSelectionSetFields(
254+
typename: string,
255+
fields: string
256+
): string {
240257
const selections = Key.sortSelectionSetByNameAscending(
241-
(Key.parseKeyFields(fields).definitions[0] as OperationDefinitionNode)
242-
.selectionSet
258+
(
259+
Key.parseKeyFields(typename, fields)
260+
.definitions[0] as OperationDefinitionNode
261+
).selectionSet
243262
);
244263
return Key.formatSelectionSetFields(print(selections));
245264
}

src/schema/__tests__/FroidSchema.test.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3009,6 +3009,31 @@ describe('FroidSchema class', () => {
30093009
);
30103010
});
30113011

3012+
it('provides a helpful message when failing to stringify the FROID schema', () => {
3013+
const productSchema = gql`
3014+
type Product @key(fields: "__typename") {
3015+
name: String
3016+
}
3017+
`;
3018+
const subgraphs = new Map();
3019+
subgraphs.set('product-subgraph', productSchema);
3020+
3021+
let errorMessage;
3022+
try {
3023+
generateSchema({
3024+
subgraphs,
3025+
froidSubgraphName: 'relay-subgraph',
3026+
federationVersion: FED2_DEFAULT_VERSION,
3027+
});
3028+
} catch (error) {
3029+
errorMessage = error.message;
3030+
}
3031+
3032+
expect(errorMessage).toMatch(
3033+
'Failed to parse key fields "" for type "Product"'
3034+
);
3035+
});
3036+
30123037
it('generates schema document AST', () => {
30133038
const productSchema = gql`
30143039
type Product @key(fields: "upc") {

src/schema/sortDocumentAst.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,11 @@ function sortChildren(node: NamedNode): NamedNode {
193193
}
194194

195195
const directives = node?.directives
196-
? {directives: sortDirectives(sortKeyDirectiveFields(node.directives))}
196+
? {
197+
directives: sortDirectives(
198+
sortKeyDirectiveFields(node.name.value, node.directives)
199+
),
200+
}
197201
: {};
198202

199203
if (
@@ -254,10 +258,12 @@ function sortChildren(node: NamedNode): NamedNode {
254258
/**
255259
* Sorts the `fields` argument of any @key directives in a list of directives.
256260
*
261+
* @param {string} typename - The typename of the node the directive belongs to
257262
* @param {ConstDirectiveNode[]} directives - A list of directives that may include the @key directive
258263
* @returns {ConstDirectiveNode[]} The list of directives after any key fields have been sorted
259264
*/
260265
function sortKeyDirectiveFields(
266+
typename: string,
261267
directives: readonly ConstDirectiveNode[]
262268
): readonly ConstDirectiveNode[] {
263269
return directives.map((directive) => {
@@ -285,7 +291,7 @@ function sortKeyDirectiveFields(
285291
...fieldsArgument,
286292
value: {
287293
...fieldsArgument.value,
288-
value: Key.getSortedSelectionSetFields(fields),
294+
value: Key.getSortedSelectionSetFields(typename, fields),
289295
},
290296
},
291297
],

0 commit comments

Comments
 (0)