Skip to content
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -88,15 +88,6 @@ test('Can read a resolver with a rootFragment on an abstract type', async () =>
jest.runAllImmediates();
});

// Incorrect! We provided `__isNode`!
expect(logEvents).toEqual([
{
fieldPath: '<abstract-type-hint>',
kind: 'missing_expected_data.log',
owner: 'NodeResolversGreeting',
uiContext: undefined,
},
]);
// Incorrect! Should be the greeting.
expect(renderer?.toJSON()).toEqual(null);
expect(logEvents).toEqual([]);
expect(renderer?.toJSON()).toEqual('Hello Node with id 4!');
});
82 changes: 53 additions & 29 deletions packages/relay-runtime/store/RelayResponseNormalizer.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import type {PayloadData, PayloadError} from '../network/RelayNetworkTypes';
import type {
NormalizationActorChange,
NormalizationDefer,
NormalizationInlineFragment,
NormalizationLinkedField,
NormalizationLiveResolverField,
NormalizationModuleImport,
Expand Down Expand Up @@ -54,6 +55,7 @@ const RelayModernRecord = require('./RelayModernRecord');
const {createNormalizationSelector} = require('./RelayModernSelector');
const {
ROOT_ID,
ROOT_TYPE,
TYPENAME_KEY,
getArgumentValues,
getHandleStorageKey,
Expand Down Expand Up @@ -243,34 +245,7 @@ class RelayResponseNormalizer {
break;
}
case 'InlineFragment': {
const {abstractKey} = selection;
if (abstractKey == null) {
const typeName = RelayModernRecord.getType(record);
if (typeName === selection.type) {
this._traverseSelections(selection, record, data);
}
} else {
// $FlowFixMe[method-unbinding] - data could be prototype less
const implementsInterface = Object.prototype.hasOwnProperty.call(
data,
abstractKey,
);
const typeName = RelayModernRecord.getType(record);
const typeID = generateTypeID(typeName);
let typeRecord = this._recordSource.get(typeID);
if (typeRecord == null) {
typeRecord = RelayModernRecord.create(typeID, TYPE_SCHEMA_TYPE);
this._recordSource.set(typeID, typeRecord);
}
RelayModernRecord.setValue(
typeRecord,
abstractKey,
implementsInterface,
);
if (implementsInterface) {
this._traverseSelections(selection, record, data);
}
}
this._normalizeInlineFragment(selection, record, data);
break;
}
case 'TypeDiscriminator': {
Expand Down Expand Up @@ -358,13 +333,62 @@ class RelayResponseNormalizer {
}
}

_normalizeInlineFragment(
selection: NormalizationInlineFragment,
record: Record,
data: PayloadData,
) {
const {abstractKey} = selection;
if (abstractKey == null) {
const typeName = RelayModernRecord.getType(record);
if (
typeName === selection.type ||
// The root record type is a special `__Root` type and may not match the
// type on the ast, so ignore type mismatches at the root. We currently
// detect whether we're at the root by checking against ROOT_ID, but this
// does not work for mutations/subscriptions which generate unique root
// ids. This is acceptable in practice as we don't read data for
// mutations/subscriptions in a situation where we would use
// isMissingData to decide whether to suspend or not.
// TODO T96653810: Correctly detect reading from root of mutation/subscription
(typeName === ROOT_TYPE &&
!RelayFeatureFlags.DISABLE_RESOLVER_ROOT_FRAGMENT_NORMALIZATION_BUG_FIX)
) {
this._traverseSelections(selection, record, data);
}
} else {
// $FlowFixMe[method-unbinding] - data could be prototype less
const implementsInterface = Object.prototype.hasOwnProperty.call(
data,
abstractKey,
);
const typeName = RelayModernRecord.getType(record);
const typeID = generateTypeID(typeName);
let typeRecord = this._recordSource.get(typeID);
if (typeRecord == null) {
typeRecord = RelayModernRecord.create(typeID, TYPE_SCHEMA_TYPE);
this._recordSource.set(typeID, typeRecord);
}
RelayModernRecord.setValue(typeRecord, abstractKey, implementsInterface);
if (implementsInterface) {
this._traverseSelections(selection, record, data);
}
}
}

_normalizeResolver(
resolver: NormalizationResolverField | NormalizationLiveResolverField,
record: Record,
data: PayloadData,
) {
if (resolver.fragment != null) {
this._traverseSelections(resolver.fragment, record, data);
if (
RelayFeatureFlags.DISABLE_RESOLVER_ROOT_FRAGMENT_NORMALIZATION_BUG_FIX
) {
this._traverseSelections(resolver.fragment, record, data);
} else {
this._normalizeInlineFragment(resolver.fragment, record, data);
}
}
}

Expand Down
5 changes: 5 additions & 0 deletions packages/relay-runtime/util/RelayFeatureFlags.js
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,10 @@ export type FeatureFlags = {
//
// See https://github.com/facebook/relay/issues/4882
CHECK_ALL_FRAGMENTS_FOR_MISSING_CLIENT_EDGES: boolean,

// Killswitch in case the fix in https://github.com/facebook/relay/pull/5059
// causes issues.
DISABLE_RESOLVER_ROOT_FRAGMENT_NORMALIZATION_BUG_FIX: boolean,
};

const RelayFeatureFlags: FeatureFlags = {
Expand Down Expand Up @@ -109,6 +113,7 @@ const RelayFeatureFlags: FeatureFlags = {
ENABLE_TYPENAME_PREFIXED_DATA_ID: false,
ENABLE_UI_CONTEXT_ON_RELAY_LOGGER: false,
CHECK_ALL_FRAGMENTS_FOR_MISSING_CLIENT_EDGES: false,
DISABLE_RESOLVER_ROOT_FRAGMENT_NORMALIZATION_BUG_FIX: false,
};

module.exports = RelayFeatureFlags;
Loading