Skip to content

Commit b801db0

Browse files
tyao1facebook-github-bot
authored andcommitted
Fix nested @defer when server doesn't support streaming
Reviewed By: captbaritone Differential Revision: D75566414 Privacy Context Container: L1125407 fbshipit-source-id: 5725c02dacb4d34c964c7807b2c8cd8cc4d25360
1 parent 8fbc0b9 commit b801db0

6 files changed

+489
-2
lines changed

packages/relay-runtime/store/OperationExecutor.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -918,7 +918,8 @@ class Executor<TMutation: MutationParameters> {
918918
placeholder.label,
919919
placeholder.path,
920920
placeholder,
921-
{data: placeholder.data},
921+
// `is_final` flag needs to be set for processing nested defer payloads
922+
{data: placeholder.data, extensions: {is_final: true}},
922923
),
923924
);
924925
}

packages/relay-runtime/store/__tests__/RelayModernEnvironment-ExecuteWithDefer-test.js

Lines changed: 108 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,11 @@ const {
3737
const {createReaderSelector} = require('../RelayModernSelector');
3838
const RelayModernStore = require('../RelayModernStore');
3939
const RelayRecordSource = require('../RelayRecordSource');
40-
const {disallowWarnings, expectToWarn} = require('relay-test-utils-internal');
40+
const {
41+
disallowWarnings,
42+
expectToWarn,
43+
expectToWarnMany,
44+
} = require('relay-test-utils-internal');
4145

4246
disallowWarnings();
4347

@@ -737,6 +741,109 @@ describe.each(['RelayModernEnvironment', 'MultiActorEnvironment'])(
737741
name: 'ALICE',
738742
});
739743
});
744+
745+
it('warns if nested defer is executed in non-streaming mode and processes deferred selections', () => {
746+
const query = graphql`
747+
query RelayModernEnvironmentExecuteWithDeferTestNestedUserQuery(
748+
$id: ID!
749+
) {
750+
node(id: $id) {
751+
...RelayModernEnvironmentExecuteWithDeferTestNestedUserFragment
752+
@dangerously_unaliased_fixme
753+
@defer(label: "UserFragment")
754+
}
755+
}
756+
`;
757+
const fragment = graphql`
758+
fragment RelayModernEnvironmentExecuteWithDeferTestNestedUserFragment on User {
759+
id
760+
...RelayModernEnvironmentExecuteWithDeferTestNestedInnerUserFragment
761+
@defer
762+
}
763+
`;
764+
const fragmentInner = graphql`
765+
fragment RelayModernEnvironmentExecuteWithDeferTestNestedInnerUserFragment on User {
766+
name
767+
...RelayModernEnvironmentExecuteWithDeferTestNestedInnerInner2UserFragment
768+
@defer
769+
}
770+
`;
771+
const fragmentInnerInner2 = graphql`
772+
fragment RelayModernEnvironmentExecuteWithDeferTestNestedInnerInner2UserFragment on User {
773+
lastName
774+
}
775+
`;
776+
variables = {id: '1'};
777+
operation = createOperationDescriptor(query, variables);
778+
selector = createReaderSelector(fragment, '1', {}, operation.request);
779+
780+
const initialSnapshot = environment.lookup(selector);
781+
const callback = jest.fn<[Snapshot], void>();
782+
environment.subscribe(initialSnapshot, callback);
783+
784+
environment.execute({operation}).subscribe(callbacks);
785+
const payload = {
786+
data: {
787+
node: {
788+
id: '1',
789+
__typename: 'User',
790+
name: 'Alice',
791+
lastName: 'Bob',
792+
},
793+
},
794+
extensions: {
795+
is_final: true,
796+
},
797+
};
798+
799+
expectToWarnMany(
800+
[
801+
'RelayModernEnvironment: Operation `RelayModernEnvironmentExecuteWithDeferTestNestedUserQuery` contains @defer/@stream ' +
802+
'directives but was executed in non-streaming mode. See ' +
803+
'https://fburl.com/relay-incremental-delivery-non-streaming-warning.',
804+
'RelayModernEnvironment: Operation `RelayModernEnvironmentExecuteWithDeferTestNestedUserQuery` contains @defer/@stream ' +
805+
'directives but was executed in non-streaming mode. See ' +
806+
'https://fburl.com/relay-incremental-delivery-non-streaming-warning.',
807+
'RelayModernEnvironment: Operation `RelayModernEnvironmentExecuteWithDeferTestNestedUserQuery` contains @defer/@stream ' +
808+
'directives but was executed in non-streaming mode. See ' +
809+
'https://fburl.com/relay-incremental-delivery-non-streaming-warning.',
810+
],
811+
() => {
812+
dataSource.next(payload);
813+
},
814+
);
815+
816+
expect(complete).not.toBeCalled();
817+
expect(error).not.toBeCalled();
818+
expect(next.mock.calls.length).toBe(1);
819+
820+
expect(callback.mock.calls.length).toBe(1);
821+
const snapshot = callback.mock.calls[0][0];
822+
expect(snapshot.isMissingData).toBe(false);
823+
expect(snapshot.data?.id).toBe('1');
824+
825+
const innerSelector = createReaderSelector(
826+
fragmentInner,
827+
'1',
828+
{},
829+
operation.request,
830+
);
831+
const innerSnapshot = environment.lookup(innerSelector);
832+
expect(innerSnapshot.isMissingData).toBe(false);
833+
expect(innerSnapshot.data?.name).toEqual('Alice');
834+
835+
const innerInner2Selector = createReaderSelector(
836+
fragmentInnerInner2,
837+
'1',
838+
{},
839+
operation.request,
840+
);
841+
const innerInner2Snapshot = environment.lookup(innerInner2Selector);
842+
expect(innerInner2Snapshot.isMissingData).toBe(false);
843+
expect(innerInner2Snapshot.data).toEqual({
844+
lastName: 'Bob',
845+
});
846+
});
740847
});
741848
},
742849
);

packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentExecuteWithDeferTestNestedInnerInner2UserFragment.graphql.js

Lines changed: 59 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentExecuteWithDeferTestNestedInnerUserFragment.graphql.js

Lines changed: 71 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/relay-runtime/store/__tests__/__generated__/RelayModernEnvironmentExecuteWithDeferTestNestedUserFragment.graphql.js

Lines changed: 71 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)