Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ensure transient key dependencies are applied #29

Merged
merged 2 commits into from
Apr 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,13 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to
[Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [v3.2.1] - 2024-04-29

### Fixed

- Fixes a case where sub-entity keys failed to roll up properly to referencing
entity keys when a value type was in-between.

## [v3.2.0] - 2024-03-22

### Added
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@wayfair/node-froid",
"version": "3.2.0",
"version": "3.2.1",
"description": "Federated GQL Relay Object Identification implementation",
"main": "dist/index.js",
"types": "dist/index.d.ts",
Expand Down
39 changes: 1 addition & 38 deletions src/schema/FroidSchema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import {
ObjectTypeDefinitionNode,
ScalarTypeDefinitionNode,
SchemaExtensionNode,
StringValueNode,
parse,
print,
specifiedScalarTypes,
Expand Down Expand Up @@ -346,6 +345,7 @@ export class FroidSchema {
}

existingNode.addExternallySelectedFields(keyField.selections);
existingNode.addExternalKeySelections(keyField.selections);

this.generateFroidDependency(keyField.selections, existingNode.allFields);
});
Expand All @@ -365,43 +365,6 @@ export class FroidSchema {
) as ObjectTypeNode[];
}

/**
* Get contract @tag directives for an ID field. Returns all occurrences of unique @tag
* directives used across all fields included in the node's @key directive
*
* @param {ObjectTypeDefinitionNode} node - The node to process `@key` directives for
* @returns {ConstDirectiveNode[]} A list of `@tag` directives to use for the given `id` field
*/
private getTagDirectivesForIdField(
node: ObjectTypeDefinitionNode
): ConstDirectiveNode[] {
const tagDirectiveNames = this.extensionAndDefinitionNodes
.filter((obj) => obj.name.value === node.name.value)
.flatMap((obj) => {
const taggableNodes = obj.fields?.flatMap((field) => [
field,
...(field?.arguments || []),
]);
return taggableNodes?.flatMap((field) =>
field.directives
?.filter((directive) => directive.name.value === DirectiveName.Tag)
.map(
(directive) =>
(directive?.arguments?.[0].value as StringValueNode).value
)
);
})
.filter(Boolean)
.sort() as string[];

const uniqueTagDirectivesNames: string[] = [
...new Set(tagDirectiveNames || []),
];
return uniqueTagDirectivesNames.map<ConstDirectiveNode>((tagName) =>
FroidSchema.createTagDirective(tagName)
);
}

/**
* Creates the Apollo Federation @link directive.
*
Expand Down
71 changes: 68 additions & 3 deletions src/schema/ObjectType.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,11 @@ export class ObjectType {
* use in the keys of other object types.
*/
private _externallySelectedFields: string[] = [];
/**
* Key selections belonging to this object type that were selected
* for use in the keys of other object types.
*/
private _externalKeySelections: KeyField[] = [];
/**
* The key selected for use in the FROID schema.
*/
Expand Down Expand Up @@ -307,6 +312,15 @@ export class ObjectType {
return this._externallySelectedFields;
}

/**
* The key selections that are referenced in another entity's key.
*
* @returns {KeyField[]} The list of key field selections
*/
public get externalKeySelections(): KeyField[] {
return this._externalKeySelections;
}

/**
* The list of all fields referenced in the node key and by other entities.
*
Expand Down Expand Up @@ -354,6 +368,10 @@ export class ObjectType {
* @returns {Key|undefined} The final key or undefined if the node has no key.
*/
private getFinalKey(depth = 0, ancestors: string[] = []): Key | undefined {
if (!this._selectedKey) {
this.setSelectedKeyFromExternalSelections();
}

if (!this._selectedKey) {
return;
}
Expand Down Expand Up @@ -425,13 +443,46 @@ export class ObjectType {
this.directlySelectedFields = this.getDirectlySelectedFields();
}

/**
* Assigns a new selected key based on key selections from
* another entity's key.
*
* This is used to generate a selected key for _value types_.
*/
private setSelectedKeyFromExternalSelections(): void {
if (this.isEntity) {
// This method is only meant to be used when the
// object is a value type. It the object is an entity,
// don't proceed
return;
}
let selectedKey: Key | undefined;
this._externalKeySelections.forEach((selections) => {
if (selectedKey) {
selectedKey.merge(new Key(this.typename, selections.toString()));
} else {
selectedKey = new Key(this.typename, selections.toString());
}
});

if (!selectedKey) {
return;
}

this.setSelectedKey(selectedKey);
}

/**
* Gets the keys used either by default or in other entity keys.
*
* @returns {Key[]} The used keys
*/
private getUsedKeys(): Key[] {
if (!this.isEntity || !this._selectedKey) {
if (!this.isEntity) {
this.setSelectedKeyFromExternalSelections();
}

if (!this._selectedKey) {
return [];
}

Expand Down Expand Up @@ -536,6 +587,17 @@ export class ObjectType {
];
}

/**
* Add key selections found in another entity's key.
*
* @param {KeyField[]} selections - The selections found in another entity's key
*/
public addExternalKeySelections(selections: KeyField[]): void {
this._externalKeySelections = [
...new Set([...this._externalKeySelections, ...selections]),
];
}

/**
* Creates the object's AST.
*
Expand All @@ -544,14 +606,17 @@ export class ObjectType {
public toAst(): ObjectTypeDefinitionNode {
let froidFields: FieldDefinitionNode[] = [];
let froidInterfaces: NamedTypeNode[] = [];
let finalKeyDirective: ConstDirectiveNode | undefined;
const finalKey = this.finalKey;

if (this.isEntity) {
froidFields = [
FroidSchema.createIdField(this.getTagDirectivesForIdField()),
];
froidInterfaces = [implementsNodeInterface];
finalKeyDirective = finalKey?.toDirective();
}
const finalKey = this.finalKey;
const finalKeyDirective = finalKey?.toDirective();

const fields = [...froidFields, ...this.getFinalFields(finalKey)];
return {
...this.node,
Expand Down
Loading
Loading