From a88c0133f136eb10699a7c1f56c3d24bc17490fe Mon Sep 17 00:00:00 2001 From: Jordan Eldredge Date: Mon, 11 Nov 2024 15:45:09 -0800 Subject: [PATCH] Derive @required fieldPath at runtime Reviewed By: lynnshaoyu Differential Revision: D65459456 fbshipit-source-id: a6e4788a7fa979a8b3ce5c19781b9390d9d9fd59 --- packages/relay-runtime/store/RelayReader.js | 35 ++++++++++++------- .../relay-runtime/store/RelayStoreTypes.js | 4 +-- packages/relay-runtime/util/ReaderNode.js | 3 +- 3 files changed, 27 insertions(+), 15 deletions(-) diff --git a/packages/relay-runtime/store/RelayReader.js b/packages/relay-runtime/store/RelayReader.js index 0ab688bcb8f2e..e5ff4191f049d 100644 --- a/packages/relay-runtime/store/RelayReader.js +++ b/packages/relay-runtime/store/RelayReader.js @@ -295,18 +295,29 @@ class RelayReader { return this._variables[name]; } - _maybeReportUnexpectedNull(fieldPath: string, action: 'LOG' | 'THROW') { + _maybeReportUnexpectedNull(selection: ReaderRequiredField) { + if (selection.action === 'NONE') { + return; + } const owner = this._fragmentName; if (this._errorResponseFields == null) { this._errorResponseFields = []; } - switch (action) { + let fieldName: string; + if (selection.field.linkedField != null) { + fieldName = + selection.field.linkedField.alias ?? selection.field.linkedField.name; + } else { + fieldName = selection.field.alias ?? selection.field.name; + } + + switch (selection.action) { case 'THROW': this._errorResponseFields.push({ kind: 'missing_required_field.throw', - fieldPath, + fieldPath: fieldName, owner, handled: false, }); @@ -314,12 +325,12 @@ class RelayReader { case 'LOG': this._errorResponseFields.push({ kind: 'missing_required_field.log', - fieldPath, + fieldPath: fieldName, owner, }); return; default: - (action: empty); + (selection.action: empty); } } @@ -328,10 +339,7 @@ class RelayReader { value: mixed, ): boolean /*should continue to siblings*/ { if (value == null) { - const {action} = selection; - if (action !== 'NONE') { - this._maybeReportUnexpectedNull(selection.path, action); - } + this._maybeReportUnexpectedNull(selection); // We are going to throw, or our parent is going to get nulled out. // Either way, sibling values are going to be ignored, so we can // bail early here as an optimization. @@ -1137,8 +1145,9 @@ class RelayReader { * Similarly, when creating field errors, we simply initialize the `fieldPath` * as the direct field name. * - * Today we only use this apporach for `missing_expected_data` errors, but we - * intend to broaden it to handle all field error paths. + * Today we only use this apporach for `missing_expected_data` and + * `missing_required_field` errors, but we intend to broaden it to handle all + * field error paths. */ _prependPreviousErrors( prevErrors: ?Array, @@ -1150,7 +1159,9 @@ class RelayReader { if ( event.owner === this._fragmentName && (event.kind === 'missing_expected_data.throw' || - event.kind === 'missing_expected_data.log') + event.kind === 'missing_expected_data.log' || + event.kind === 'missing_required_field.throw' || + event.kind === 'missing_required_field.log') ) { event.fieldPath = `${fieldNameOrIndex}.${event.fieldPath}`; } diff --git a/packages/relay-runtime/store/RelayStoreTypes.js b/packages/relay-runtime/store/RelayStoreTypes.js index 6b1f03b443460..b838e1e1acc99 100644 --- a/packages/relay-runtime/store/RelayStoreTypes.js +++ b/packages/relay-runtime/store/RelayStoreTypes.js @@ -1311,7 +1311,7 @@ export type MissingExpectedDataThrowEvent = { export type MissingRequiredFieldLogEvent = { +kind: 'missing_required_field.log', +owner: string, - +fieldPath: string, + fieldPath: string, // Purposefully mutable to allow lazy construction in RelayReader }; /** @@ -1328,7 +1328,7 @@ export type MissingRequiredFieldLogEvent = { export type MissingRequiredFieldThrowEvent = { +kind: 'missing_required_field.throw', +owner: string, - +fieldPath: string, + fieldPath: string, // Purposefully mutable to allow lazy construction in RelayReader +handled: boolean, }; diff --git a/packages/relay-runtime/util/ReaderNode.js b/packages/relay-runtime/util/ReaderNode.js index 3024313b6fa9a..4ec3574d395d6 100644 --- a/packages/relay-runtime/util/ReaderNode.js +++ b/packages/relay-runtime/util/ReaderNode.js @@ -235,7 +235,8 @@ export type ReaderRequiredField = { +kind: 'RequiredField', +field: ReaderField | ReaderClientEdge, +action: RequiredFieldAction, - +path: string, + // TODO: This field is not used any more, we should be able to remove it. + +path?: mixed, }; export type CatchFieldTo = 'RESULT' | 'NULL';