Skip to content

Commit

Permalink
Fix for @required on client edges
Browse files Browse the repository at this point in the history
Reviewed By: andreqi

Differential Revision: D44843260

fbshipit-source-id: cd882818033fe37e1778c1f35499b64e664f3bb9
  • Loading branch information
captbaritone authored and facebook-github-bot committed Apr 10, 2023
1 parent ed612b8 commit 5c0a740
Show file tree
Hide file tree
Showing 8 changed files with 1,153 additions and 7 deletions.
14 changes: 8 additions & 6 deletions packages/relay-runtime/store/RelayReader.js
Original file line number Diff line number Diff line change
Expand Up @@ -697,7 +697,7 @@ class RelayReader {
field: ReaderClientEdgeToServerObject | ReaderClientEdgeToClientObject,
record: Record,
data: SelectorData,
): void {
): ?mixed {
const backingField = field.backingField;
// Because ReaderClientExtension doesn't have `alias` or `name` and so I don't know
Expand All @@ -719,7 +719,7 @@ class RelayReader {
isSuspenseSentinel(clientEdgeResolverResponse)
) {
data[applicationName] = clientEdgeResolverResponse;
return;
return clientEdgeResolverResponse;
}
const validClientEdgeResolverResponse =
Expand All @@ -733,14 +733,15 @@ class RelayReader {
this._resolverCache,
);
this._clientEdgeTraversalPath.push(null);
data[applicationName] = this._readLinkedIds(
const edgeValues = this._readLinkedIds(
field.linkedField,
storeIDs,
record,
data,
);
this._clientEdgeTraversalPath.pop();
break;
data[applicationName] = edgeValues;
return edgeValues;
case 'SingularConcrete':
const [storeID, traversalPathSegment] =
Expand All @@ -760,14 +761,15 @@ class RelayReader {
RelayModernRecord.getDataID(record),
prevData,
);
data[applicationName] = this._traverse(
const edgeValue = this._traverse(
field.linkedField,
storeID,
// $FlowFixMe[incompatible-variance]
prevData,
);
this._clientEdgeTraversalPath.pop();
break;
data[applicationName] = edgeValue;
return edgeValue;
default:
(validClientEdgeResolverResponse.kind: empty);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,15 @@ const {
} = require('../RelayModernOperationDescriptor');
const {read} = require('../RelayReader');
const RelayRecordSource = require('../RelayRecordSource');
const {createReaderSelector, getPluralSelector} = require('relay-runtime');
const {
RelayFeatureFlags,
createReaderSelector,
getPluralSelector,
} = require('relay-runtime');
const {
LiveResolverCache,
} = require('relay-runtime/store/experimental-live-resolvers/LiveResolverCache');
const LiveResolverStore = require('relay-runtime/store/experimental-live-resolvers/LiveResolverStore');

describe('RelayReader @required', () => {
it('bubbles @required(action: LOG) scalars up to LinkedField', () => {
Expand Down Expand Up @@ -791,4 +799,154 @@ describe('RelayReader @required', () => {
const data = pluralSelector.selectors.map(s => read(source, s).data);
expect(data).toEqual([{username: 'Wendy'}, null]);
});

describe('client edge with @required', () => {
beforeEach(() => {
RelayFeatureFlags.ENABLE_RELAY_RESOLVERS = true;
});
afterEach(() => {
RelayFeatureFlags.ENABLE_RELAY_RESOLVERS = false;
});
test('throws when missing required field', () => {
const source = RelayRecordSource.create({
'client:root': {
__id: 'client:root',
__typename: '__Root',
me: {__ref: '1'},
},
'1': {
__id: '1',
id: '1',
__typename: 'User',
},
});
const FooQuery = graphql`
query RelayReaderRequiredFieldsTest25Query {
me {
# client_object resolver will return null for an id of "0"
client_object(id: "0") @required(action: THROW) {
description
}
}
}
`;
const store = new LiveResolverStore(source);
const operation = createOperationDescriptor(FooQuery, {});
const resolverCache = new LiveResolverCache(() => source, store);
const {missingRequiredFields} = read(
source,
operation.fragment,
resolverCache,
);
expect(missingRequiredFields).toEqual({
action: 'THROW',
field: {
owner: 'RelayReaderRequiredFieldsTest25Query',
path: 'me.client_object',
},
});
});

test('does not throw when required field is present', () => {
const source = RelayRecordSource.create({
'client:root': {
__id: 'client:root',
__typename: '__Root',
me: {__ref: '1'},
},
'1': {
__id: '1',
id: '1',
__typename: 'User',
birthdate: {__ref: 'client:2'},
},
'client:2': {
month: 3,
day: 11,
},
});
const FooQuery = graphql`
query RelayReaderRequiredFieldsTest26Query {
me {
astrological_sign @required(action: THROW) {
name
}
}
}
`;

const store = new LiveResolverStore(source);
const operation = createOperationDescriptor(FooQuery, {});
const resolverCache = new LiveResolverCache(() => source, store);
const {data, missingRequiredFields} = read(
source,
operation.fragment,
resolverCache,
);
expect(data).toEqual({me: {astrological_sign: {name: 'Pisces'}}});
expect(missingRequiredFields).toBe(null);
});

test('does not throw when required plural field is present', () => {
const source = RelayRecordSource.create({
'client:root': {
__id: 'client:root',
__typename: '__Root',
me: {__ref: '1'},
},
'1': {
__id: '1',
id: '1',
__typename: 'User',
},
});
const FooQuery = graphql`
query RelayReaderRequiredFieldsTest27Query {
all_astrological_signs @required(action: THROW) {
name
}
}
`;

const store = new LiveResolverStore(source);
const operation = createOperationDescriptor(FooQuery, {});
const resolverCache = new LiveResolverCache(() => source, store);
const {data, missingRequiredFields} = read(
source,
operation.fragment,
resolverCache,
);
expect(data.all_astrological_signs.length).toBe(12);
expect(missingRequiredFields).toBe(null);
});

test('does not throw when @live required field is suspended', () => {
const source = RelayRecordSource.create({
'client:root': {
__id: 'client:root',
__typename: '__Root',
},
});
const FooQuery = graphql`
query RelayReaderRequiredFieldsTest28Query {
live_user_resolver_always_suspend
@waterfall
@required(action: THROW) {
name
}
}
`;
const store = new LiveResolverStore(source);
const operation = createOperationDescriptor(FooQuery, {});
const resolverCache = new LiveResolverCache(() => source, store);
const snapshot = read(source, operation.fragment, resolverCache);
expect(snapshot.missingRequiredFields).toEqual(null);
expect(snapshot.missingLiveResolverFields).toEqual([
{
path: 'RelayReaderRequiredFieldsTest28Query.live_user_resolver_always_suspend',
liveStateID: 'client:root:live_user_resolver_always_suspend',
},
]);
});
});
});

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 5c0a740

Please sign in to comment.