From 1cc1cff31ac1a6edc731cb2eb5858e2b817baaff Mon Sep 17 00:00:00 2001 From: Cyril BESLAY Date: Fri, 1 Aug 2025 15:26:31 +0200 Subject: [PATCH] fix(federation): Fix a use case around @keys sync check --- src/helpers/federation.ts | 12 ++++++++ test/integration/5_diff.feature | 49 ++++++++++++++++++++++++++++++++- 2 files changed, 60 insertions(+), 1 deletion(-) diff --git a/src/helpers/federation.ts b/src/helpers/federation.ts index 942cf5f..c535f1b 100644 --- a/src/helpers/federation.ts +++ b/src/helpers/federation.ts @@ -101,6 +101,7 @@ export function checkKeySanity(servicesSchemaMap, service: Service): Change[] { type KeyDirective = { fields: string; serviceName: string; + isResolvable; }; type TypeKeyMap = Map; @@ -132,6 +133,15 @@ function extractKeysFromSDL( ? fieldsArg.value.value : ''; + const resolvableKeyPresent = key.arguments?.find( + (arg) => arg.name.value === 'resolvable' + ); + const isResolvable = resolvableKeyPresent + ? resolvableKeyPresent.value.kind === 'BooleanValue' + ? resolvableKeyPresent.value.value + : true + : true; + const normalizedFieldsValue = normalizeKeyFields(fieldsValue); if (!keyMap.has(node.name.value)) { @@ -141,6 +151,7 @@ function extractKeysFromSDL( keyMap.get(node.name.value)?.push({ fields: normalizedFieldsValue, serviceName, + isResolvable, }); } }, @@ -191,6 +202,7 @@ function checkServiceKeysWithinSupergraph( const supergraphTypeKeys = supergraphKeys.get(typeName); for (const key of keys) { if ( + !key.isResolvable && supergraphTypeKeys && !supergraphTypeKeys.some((k) => k.fields === key.fields) ) { diff --git a/test/integration/5_diff.feature b/test/integration/5_diff.feature index 4c9e0db..da22ec7 100644 --- a/test/integration/5_diff.feature +++ b/test/integration/5_diff.feature @@ -245,7 +245,7 @@ Feature: As a customer { "name": "Reviews", "version": "newest", - "type_defs": "type User @key(fields: \"email\") { email: String! reviews: [Review] } type Review { id: ID! body: String }" + "type_defs": "type User @key(fields: \"email\", resolvable: false) { email: String! reviews: [Review] } type Review { id: ID! body: String }" } """ Then the response status code should be 200 @@ -268,3 +268,50 @@ Feature: As a customer } """ + Scenario: Checking keys with different schemas (owner graph) + Given the database is imported from 'breakdown_schema_db' + And I send a "POST" request to "/schema/push" with body: + """ + { + "name": "User", + "version": "newest", + "type_defs": "type Query { getUser: User } type User @key(fields: \"id\") { id: ID! name: String }" + } + """ + And I send a "POST" request to "/schema/push" with body: + """ + { + "name": "Email", + "version": "newest", + "type_defs": "type Query { getEmails: User } type User @key(fields: \"id\", resolvable: false) { id: ID! name: String }" + } + """ + Then I send a "POST" request to "/schema/diff" with body: + """ + { + "name": "User", + "version": "newest", + "type_defs": "type Query { getUser: User } type User @key(fields: \"id\") @key(fields: \"email\") { id: ID! name: String, email: String! }" + } + """ + Then the response status code should be 200 + And the response should be in JSON and contain: + """ + { + "success": true, + "data": [{ + "criticality": { + "level": "NON_BREAKING" + }, + "message": "Field 'email' was added to object type 'User'", + "meta": { + "addedFieldName": "email", + "typeName": "User", + "typeType": "object type" + }, + "path": "User.email", + "type": "FIELD_ADDED" + }] + } + """ +