Skip to content

Commit 074bbad

Browse files
authored
Merge pull request #32 from wayfair-incubator/mk228f_revert-fix-no-partial-shareable-types
2 parents 5d5d3da + 46839ae commit 074bbad

File tree

7 files changed

+6
-250
lines changed

7 files changed

+6
-250
lines changed

CHANGELOG.md

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,6 @@ 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.3] - 2025-09-29
10-
11-
### Fix
12-
13-
- The `FroidSchema` class does not include all shareable value type fields found
14-
across subgraphs.
15-
169
## [v3.2.2] - 2024-08-20
1710

1811
### 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.3",
3+
"version": "3.2.4",
44
"description": "Federated GQL Relay Object Identification implementation",
55
"main": "dist/index.js",
66
"types": "dist/index.d.ts",

src/schema/FroidSchema.ts

Lines changed: 2 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ import {ObjectTypeNode} from './types';
2020
import {
2121
CONTRACT_DIRECTIVE_NAME,
2222
DEFAULT_FEDERATION_LINK_IMPORTS,
23-
Directive,
2423
DirectiveName,
2524
FED2_OPT_IN_URL,
2625
FED2_VERSION_PREFIX,
@@ -185,15 +184,10 @@ export class FroidSchema {
185184
this.generateFroidDependencies();
186185

187186
// build schema
188-
const imports = [...DEFAULT_FEDERATION_LINK_IMPORTS];
189-
if (this.hasShareableTypes()) {
190-
imports.push(Directive.Shareable);
191-
}
192-
193187
this.froidAst = sortDocumentAst({
194188
kind: Kind.DOCUMENT,
195189
definitions: [
196-
this.createLinkSchemaExtension(imports),
190+
this.createLinkSchemaExtension(),
197191
this.createQueryDefinition(),
198192
this.createNodeInterface(),
199193
...this.createCustomReturnTypes(),
@@ -248,14 +242,7 @@ export class FroidSchema {
248242
)
249243
);
250244

251-
const isShareableValueType = node.directives?.some(
252-
(directive) => directive.name.value === DirectiveName.Shareable
253-
);
254-
255-
if (
256-
isException ||
257-
(!FroidSchema.isEntity(node) && !isShareableValueType)
258-
) {
245+
if (isException || !FroidSchema.isEntity(node)) {
259246
return;
260247
}
261248

@@ -875,15 +862,4 @@ export class FroidSchema {
875862
private static parseSchema(schema: string): DocumentNode {
876863
return parse(schema, {noLocation: true});
877864
}
878-
879-
/**
880-
* Checks if there are any shareable types in the FROID object types.
881-
*
882-
* @returns {boolean} True if there are shareable types, false otherwise.
883-
*/
884-
private hasShareableTypes(): boolean {
885-
return Object.values(this.froidObjectTypes).some(
886-
(objectType) => objectType.isShareable
887-
);
888-
}
889865
}

src/schema/ObjectType.ts

Lines changed: 2 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import {DirectiveName, EXTERNAL_DIRECTIVE_AST} from './constants';
1010
import {ObjectTypeNode} from './types';
1111
import {FroidSchema, KeySorter, NodeQualifier} from './FroidSchema';
1212
import {KeyField} from './KeyField';
13-
import {implementsNodeInterface, shareableDirective} from './astDefinitions';
13+
import {implementsNodeInterface} from './astDefinitions';
1414

1515
const FINAL_KEY_MAX_DEPTH = 100;
1616

@@ -360,20 +360,6 @@ export class ObjectType {
360360
return this.getFinalKey();
361361
}
362362

363-
/**
364-
* Checks if the type is shareable by looking for @shareable directive
365-
* on any of its occurrences across subgraphs.
366-
*
367-
* @returns {boolean} True if any occurrence has the @shareable directive
368-
*/
369-
public get isShareable(): boolean {
370-
return this.occurrences.some((occurrence) =>
371-
occurrence.directives?.some(
372-
(directive) => directive.name.value === DirectiveName.Shareable
373-
)
374-
);
375-
}
376-
377363
/**
378364
* Generates the final key for the node based on all descendant types and their keys (if they have keys).
379365
*
@@ -526,22 +512,10 @@ export class ObjectType {
526512
* @returns {FieldDefinitionNode[]} The final fields
527513
*/
528514
private getFinalFields(finalKey: Key | undefined): FieldDefinitionNode[] {
529-
// If the type is shareable, include all fields from the supergraph
530-
if (this.isShareable) {
531-
return this.allFields.map((field) => ({
532-
...field,
533-
description: undefined,
534-
directives: [],
535-
}));
536-
}
537-
538-
const shareableFields = this.getShareableFields();
539-
// Original behavior for non-shareable types, plus shareable fields
540515
const fieldsList = [
541516
...new Set([
542517
...(finalKey?.fieldsList || []),
543518
...this._externallySelectedFields,
544-
...shareableFields.map((field) => field.name.value),
545519
]),
546520
];
547521
const fields = fieldsList
@@ -564,32 +538,6 @@ export class ObjectType {
564538
return fields;
565539
}
566540

567-
/**
568-
* Gets all fields that have @shareable directive across all occurrences.
569-
*
570-
* @returns {FieldDefinitionNode[]} Fields with @shareable directive
571-
*/
572-
private getShareableFields(): FieldDefinitionNode[] {
573-
const shareableFields: FieldDefinitionNode[] = [];
574-
575-
this.occurrences.forEach((occurrence) => {
576-
occurrence?.fields?.forEach((field) => {
577-
const hasShareableDirective = field.directives?.some(
578-
(directive) => directive.name.value === DirectiveName.Shareable
579-
);
580-
581-
if (hasShareableDirective) {
582-
// Only add if we haven't already added this field
583-
if (!shareableFields.some((f) => f.name.value === field.name.value)) {
584-
shareableFields.push(field);
585-
}
586-
}
587-
});
588-
});
589-
590-
return shareableFields;
591-
}
592-
593541
/**
594542
* Get contract @tag directives for an ID field. Returns all occurrences of unique @tag
595543
* directives used across all fields included in the node's @key directive
@@ -670,16 +618,11 @@ export class ObjectType {
670618
}
671619

672620
const fields = [...froidFields, ...this.getFinalFields(finalKey)];
673-
const directives = [
674-
...(finalKeyDirective ? [finalKeyDirective] : []),
675-
...(this.isShareable ? [shareableDirective] : []),
676-
];
677-
678621
return {
679622
...this.node,
680623
description: undefined,
681624
interfaces: froidInterfaces,
682-
directives,
625+
directives: [...(finalKeyDirective ? [finalKeyDirective] : [])],
683626
fields,
684627
};
685628
}

src/schema/__tests__/FroidSchema.test.ts

Lines changed: 0 additions & 137 deletions
Original file line numberDiff line numberDiff line change
@@ -1347,143 +1347,6 @@ describe('FroidSchema class', () => {
13471347
);
13481348
});
13491349

1350-
it('applies the @shareable directive to types marked with @shareable and includes all fields from supergraph', () => {
1351-
const bookSchema = gql`
1352-
type Book @key(fields: "isbn") {
1353-
isbn: String!
1354-
title: String!
1355-
author: Author!
1356-
}
1357-
1358-
type Author @shareable {
1359-
authorId: Int!
1360-
}
1361-
`;
1362-
1363-
const authorSchema = gql`
1364-
type Author @shareable {
1365-
authorId: Int!
1366-
name: String!
1367-
email: String!
1368-
age: Int
1369-
}
1370-
`;
1371-
1372-
const subgraphs = new Map();
1373-
subgraphs.set('book-subgraph', bookSchema);
1374-
subgraphs.set('author-subgraph', authorSchema);
1375-
1376-
const actual = generateSchema({
1377-
subgraphs,
1378-
froidSubgraphName: 'relay-subgraph',
1379-
contractTags: ['storefront', 'internal'],
1380-
federationVersion: FED2_DEFAULT_VERSION,
1381-
});
1382-
1383-
expect(actual).toEqual(
1384-
// prettier-ignore
1385-
gql`
1386-
extend schema @link(url: "https://specs.apollo.dev/federation/v2.0", import: ["@key", "@tag", "@external", "@shareable"])
1387-
1388-
type Author @shareable {
1389-
age: Int
1390-
authorId: Int!
1391-
email: String!
1392-
name: String!
1393-
}
1394-
1395-
type Book implements Node @key(fields: "isbn") {
1396-
"The globally unique identifier."
1397-
id: ID!
1398-
isbn: String!
1399-
}
1400-
1401-
"The global identification interface implemented by all entities."
1402-
interface Node @tag(name: "internal") @tag(name: "storefront") {
1403-
"The globally unique identifier."
1404-
id: ID!
1405-
}
1406-
1407-
type Query {
1408-
"Fetches an entity by its globally unique identifier."
1409-
node(
1410-
"A globally unique entity identifier."
1411-
id: ID!
1412-
): Node @tag(name: "internal") @tag(name: "storefront")
1413-
}
1414-
`
1415-
);
1416-
});
1417-
1418-
it('applies the @external directive to fields marked with @shareable and includes them in froid schema', () => {
1419-
const bookSchema = gql`
1420-
type Book @key(fields: "isbn") {
1421-
isbn: String!
1422-
title: String!
1423-
edition: Edition
1424-
}
1425-
1426-
type Edition @key(fields: "isbn") {
1427-
isbn: String!
1428-
publicationYear: Int @shareable
1429-
}
1430-
`;
1431-
1432-
const editionsSchema = gql`
1433-
type Edition @key(fields: "isbn") {
1434-
isbn: String!
1435-
format: String!
1436-
pageCount: Int!
1437-
publicationYear: Int @shareable
1438-
}
1439-
`;
1440-
1441-
const subgraphs = new Map();
1442-
subgraphs.set('book-subgraph', bookSchema);
1443-
subgraphs.set('editions-subgraph', editionsSchema);
1444-
1445-
const actual = generateSchema({
1446-
subgraphs,
1447-
froidSubgraphName: 'relay-subgraph',
1448-
contractTags: ['storefront', 'internal'],
1449-
federationVersion: FED2_DEFAULT_VERSION,
1450-
});
1451-
1452-
expect(actual).toEqual(
1453-
// prettier-ignore
1454-
gql`
1455-
extend schema @link(url: "https://specs.apollo.dev/federation/v2.0", import: ["@key", "@tag", "@external"])
1456-
1457-
type Book implements Node @key(fields: "isbn") {
1458-
"The globally unique identifier."
1459-
id: ID!
1460-
isbn: String!
1461-
}
1462-
1463-
type Edition implements Node @key(fields: "isbn") {
1464-
"The globally unique identifier."
1465-
id: ID!
1466-
isbn: String!
1467-
publicationYear: Int @external
1468-
}
1469-
1470-
"The global identification interface implemented by all entities."
1471-
interface Node @tag(name: "internal") @tag(name: "storefront") {
1472-
"The globally unique identifier."
1473-
id: ID!
1474-
}
1475-
1476-
type Query {
1477-
"Fetches an entity by its globally unique identifier."
1478-
node(
1479-
"A globally unique entity identifier."
1480-
id: ID!
1481-
): Node @tag(name: "internal") @tag(name: "storefront")
1482-
}
1483-
`
1484-
);
1485-
});
1486-
14871350
it('uses a custom qualifier to prefer fields', () => {
14881351
const bookSchema = gql`
14891352
type Book @key(fields: "isbn") {

src/schema/astDefinitions.ts

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import {ConstDirectiveNode, Kind, NamedTypeNode} from 'graphql';
2-
import {EXTERNAL_DIRECTIVE, SHAREABLE_DIRECTIVE} from './constants';
2+
import {EXTERNAL_DIRECTIVE} from './constants';
33

44
/**
55
* Represents AST for `implements Node`
@@ -22,14 +22,3 @@ export const externalDirective: ConstDirectiveNode = {
2222
value: EXTERNAL_DIRECTIVE,
2323
},
2424
};
25-
26-
/**
27-
* Represents AST for `@shareable` directive
28-
*/
29-
export const shareableDirective: ConstDirectiveNode = {
30-
kind: Kind.DIRECTIVE,
31-
name: {
32-
kind: Kind.NAME,
33-
value: SHAREABLE_DIRECTIVE,
34-
},
35-
};

src/schema/constants.ts

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ export enum Directive {
1313
External = '@external',
1414
InterfaceObject = '@interfaceObject',
1515
Key = '@key',
16-
Shareable = '@shareable',
1716
Tag = '@tag',
1817
}
1918

@@ -22,7 +21,6 @@ export enum DirectiveName {
2221
External = 'external',
2322
InterfaceObject = 'interfaceObject',
2423
Key = 'key',
25-
Shareable = 'shareable',
2624
Tag = 'tag',
2725
}
2826

@@ -36,18 +34,12 @@ export const EXTENDS_DIRECTIVE = DirectiveName.Extends;
3634
export const TAG_DIRECTIVE = DirectiveName.Tag;
3735
export const KEY_DIRECTIVE = DirectiveName.Key;
3836
export const INTERFACE_OBJECT_DIRECTIVE = DirectiveName.InterfaceObject;
39-
export const SHAREABLE_DIRECTIVE = DirectiveName.Shareable;
4037

4138
export const EXTERNAL_DIRECTIVE_AST = {
4239
kind: Kind.DIRECTIVE,
4340
name: {kind: Kind.NAME, value: DirectiveName.External},
4441
} as ConstDirectiveNode;
4542

46-
export const SHAREABLE_DIRECTIVE_AST = {
47-
kind: Kind.DIRECTIVE,
48-
name: {kind: Kind.NAME, value: DirectiveName.Shareable},
49-
} as ConstDirectiveNode;
50-
5143
export const DEFAULT_FEDERATION_LINK_IMPORTS = [
5244
Directive.Key,
5345
Directive.Tag,

0 commit comments

Comments
 (0)