Skip to content

Commit

Permalink
More strict selectors equal check
Browse files Browse the repository at this point in the history
Reviewed By: voideanvalue

Differential Revision: D52184539

fbshipit-source-id: 2116cb5ba866c763b5a026145910914a17ddf66d
  • Loading branch information
tyao1 authored and facebook-github-bot committed Dec 16, 2023
1 parent 82573ac commit 4c25549
Show file tree
Hide file tree
Showing 3 changed files with 126 additions and 1 deletion.
43 changes: 42 additions & 1 deletion packages/relay-runtime/store/RelayModernSelector.js
Expand Up @@ -23,6 +23,7 @@ import type {
SingularReaderSelector,
} from './RelayStoreTypes';

const RelayFeatureFlags = require('../util/RelayFeatureFlags');
const {getFragmentVariables} = require('./RelayConcreteVariables');
const {
CLIENT_EDGE_TRAVERSAL_PATH,
Expand Down Expand Up @@ -412,7 +413,14 @@ function areEqualSingularSelectors(
thisSelector.dataID === thatSelector.dataID &&
thisSelector.node === thatSelector.node &&
areEqual(thisSelector.variables, thatSelector.variables) &&
areEqualOwners(thisSelector.owner, thatSelector.owner)
areEqualOwners(thisSelector.owner, thatSelector.owner) &&
(!RelayFeatureFlags.ENABLE_STRICT_EQUAL_SELECTORS ||
(thisSelector.isWithinUnmatchedTypeRefinement ===
thatSelector.isWithinUnmatchedTypeRefinement &&
areEqualClientEdgeTraversalPaths(
thisSelector.clientEdgeTraversalPath,
thatSelector.clientEdgeTraversalPath,
)))
);
}

Expand All @@ -434,6 +442,39 @@ function areEqualOwners(
}
}

function areEqualClientEdgeTraversalPaths(
thisPath: ClientEdgeTraversalPath | null,
thatPath: ClientEdgeTraversalPath | null,
): boolean {
if (thisPath === thatPath) {
return true;
}
if (
thisPath == null ||
thatPath == null ||
thisPath.length !== thatPath.length
) {
return false;
}
let idx = thisPath.length;
while (idx--) {
const a = thisPath[idx];
const b = thatPath[idx];
if (a === b) {
continue;
}
if (
a == null ||
b == null ||
a.clientEdgeDestinationID !== b.clientEdgeDestinationID ||
a.readerClientEdge !== b.readerClientEdge
) {
return false;
}
}
return true;
}

/**
* @public
*
Expand Down
81 changes: 81 additions & 0 deletions packages/relay-runtime/store/__tests__/RelayModernSelector-test.js
Expand Up @@ -15,6 +15,7 @@ import type {OperationDescriptor} from '../RelayStoreTypes';
import type {Variables} from 'relay-runtime/util/RelayRuntimeTypes';

const {graphql} = require('../../query/GraphQLTag');
const RelayFeatureFlags = require('../../util/RelayFeatureFlags');
const {
createOperationDescriptor,
createRequestDescriptor,
Expand Down Expand Up @@ -120,6 +121,7 @@ describe('RelayModernSelector', () => {
size: null,
cond: false,
};
RelayFeatureFlags.ENABLE_STRICT_EQUAL_SELECTORS = true;
});

describe('getSingularSelector()', () => {
Expand Down Expand Up @@ -700,6 +702,85 @@ describe('RelayModernSelector', () => {
expect(areEqualSelectors(selector, differentOwner)).toBe(false);
});

it('returns false for equivalent selectors but with different isWithinUnmatchedTypeRefinement', () => {
const queryNode = UserQuery;
owner = createOperationDescriptor(queryNode, operationVariables);
const selector = createReaderSelector(
UserFragment,
'4',
variables,
owner.request,
);
const differentOwner = {
...selector,
isWithinUnmatchedTypeRefinement: true,
};
expect(areEqualSelectors(selector, differentOwner)).toBe(false);
});

it('returns false for equivalent selectors but with different clientEdgeTraversalPath', () => {
const queryNode = UserQuery;
owner = createOperationDescriptor(queryNode, operationVariables);
/*$FlowFixMe[unclear-type]*/
const fakeAstNode: Object = {};
const clientEdgeTraversalInfoA = {
readerClientEdge: fakeAstNode,
clientEdgeDestinationID: 'a',
};
const clientEdgeTraversalInfoB = {
readerClientEdge: fakeAstNode,
clientEdgeDestinationID: 'b',
};
const clientEdgeTraversalInfoANewNode = {
/*$FlowFixMe[unclear-type]*/
readerClientEdge: ({}: Object),
clientEdgeDestinationID: 'a',
};
const baseSelector = createReaderSelector(
UserFragment,
'4',
variables,
owner.request,
false,
null,
);
const selectors = [
baseSelector,
{
...baseSelector,
clientEdgeTraversalPath: [clientEdgeTraversalInfoA],
},
{
...baseSelector,
clientEdgeTraversalPath: [clientEdgeTraversalInfoB],
},
{
...baseSelector,
clientEdgeTraversalPath: [
clientEdgeTraversalInfoANewNode,
clientEdgeTraversalInfoANewNode,
],
},
{
...baseSelector,
clientEdgeTraversalPath: [clientEdgeTraversalInfoANewNode],
},
{
...baseSelector,
clientEdgeTraversalPath: [null],
},
{
...baseSelector,
clientEdgeTraversalPath: [null, clientEdgeTraversalInfoA],
},
];
for (let i = 0; i < selectors.length - 1; i++) {
for (let j = i + 1; j < selectors.length; j++) {
expect(areEqualSelectors(selectors[i], selectors[j])).toBe(false);
}
}
});

it('returns true for equivalent selectors and equivalent owners', () => {
const queryNode = UserQuery;
owner = createOperationDescriptor(queryNode, operationVariables);
Expand Down
3 changes: 3 additions & 0 deletions packages/relay-runtime/util/RelayFeatureFlags.js
Expand Up @@ -44,6 +44,8 @@ export type FeatureFlags = {
// in a partial response.
// @see https://spec.graphql.org/October2021/#sec-Handling-Field-Errors
ENABLE_FIELD_ERROR_HANDLING: boolean,

ENABLE_STRICT_EQUAL_SELECTORS: boolean,
};

const RelayFeatureFlags: FeatureFlags = {
Expand All @@ -65,6 +67,7 @@ const RelayFeatureFlags: FeatureFlags = {
ENABLE_RELAY_OPERATION_TRACKER_SUSPENSE: false,
ENABLE_FIELD_ERROR_HANDLING: false,
ENABLE_SHALLOW_FREEZE_RESOLVER_VALUES: true,
ENABLE_STRICT_EQUAL_SELECTORS: false,
};

module.exports = RelayFeatureFlags;

0 comments on commit 4c25549

Please sign in to comment.