Skip to content

Commit 2425572

Browse files
hsimahfacebook-github-bot
authored andcommittedJan 11, 2021
support multiple edges in @appendEdge and @prependEdge
Reviewed By: tyao1 Differential Revision: D25849295 fbshipit-source-id: 5052798e7983c44aca2564764069f195520447c4
1 parent 39cb99e commit 2425572

File tree

3 files changed

+269
-21
lines changed

3 files changed

+269
-21
lines changed
 

‎packages/relay-compiler/transforms/DeclarativeConnectionMutationTransform.js

+4-1
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,10 @@ function visitLinkedField(field: LinkedField): LinkedField {
164164
}
165165
const schema = this.getContext().getSchema();
166166
if (edgeDirective) {
167-
const fields = schema.getFields(transformedField.type);
167+
const fieldType = schema.isList(transformedField.type)
168+
? transformedField.type.ofType
169+
: transformedField.type;
170+
const fields = schema.getFields(fieldType);
168171
let cursorFieldID;
169172
let nodeFieldID;
170173
for (const fieldID of fields) {

‎packages/relay-runtime/handlers/connection/MutationHandlers.js

+34-20
Original file line numberDiff line numberDiff line change
@@ -104,33 +104,47 @@ function edgeUpdater(
104104
connections != null,
105105
'MutationHandlers: Expected connection IDs to be specified.',
106106
);
107-
const serverEdge = record.getLinkedRecord(payload.fieldKey, payload.args);
108-
if (serverEdge == null) {
107+
let singleServerEdge, serverEdges;
108+
try {
109+
singleServerEdge = record.getLinkedRecord(payload.fieldKey, payload.args);
110+
} catch {}
111+
if (!singleServerEdge) {
112+
try {
113+
serverEdges = record.getLinkedRecords(payload.fieldKey, payload.args);
114+
} catch {}
115+
}
116+
if (singleServerEdge == null && serverEdges == null) {
109117
warning(
110118
false,
111-
'MutationHandlers: Expected the server edge to be non-null',
119+
'MutationHandlers: Expected the server edge to be non-null.',
112120
);
113121
return;
114122
}
115-
for (const connectionID of connections) {
116-
const connection = store.get(connectionID);
117-
if (connection == null) {
118-
warning(
119-
false,
120-
`[Relay][Mutation] The connection with id '${connectionID}' doesn't exist.`,
121-
);
123+
const serverEdgeList = serverEdges ?? [singleServerEdge];
124+
for (const serverEdge of serverEdgeList) {
125+
if (serverEdge == null) {
122126
continue;
123127
}
124-
const clientEdge = ConnectionHandler.buildConnectionEdge(
125-
store,
126-
connection,
127-
serverEdge,
128-
);
129-
invariant(
130-
clientEdge != null,
131-
'MutationHandlers: Failed to build the edge.',
132-
);
133-
insertFn(connection, clientEdge);
128+
for (const connectionID of connections) {
129+
const connection = store.get(connectionID);
130+
if (connection == null) {
131+
warning(
132+
false,
133+
`[Relay][Mutation] The connection with id '${connectionID}' doesn't exist.`,
134+
);
135+
continue;
136+
}
137+
const clientEdge = ConnectionHandler.buildConnectionEdge(
138+
store,
139+
connection,
140+
serverEdge,
141+
);
142+
invariant(
143+
clientEdge != null,
144+
'MutationHandlers: Failed to build the edge.',
145+
);
146+
insertFn(connection, clientEdge);
147+
}
134148
}
135149
};
136150
}

‎packages/relay-runtime/store/__tests__/RelayModernEnvironment-ExecuteMutationWithDeclarativeMutation-test.js

+231
Original file line numberDiff line numberDiff line change
@@ -576,11 +576,15 @@ describe('connection edge mutations', () => {
576576
let source;
577577
let store;
578578
let AppendCommentMutation;
579+
let AppendCommentsMutation;
579580
let PrependCommentMutation;
581+
let PrependCommentsMutation;
580582
let DeleteCommentMutation;
581583
let DeleteCommentsMutation;
582584
let appendOperation;
585+
let appendMultipleOperation;
583586
let prependOperation;
587+
let prependMultipleOperation;
584588
let deleteOperation;
585589
let deletePluralOperation;
586590
const clientID =
@@ -594,7 +598,9 @@ describe('connection edge mutations', () => {
594598
({
595599
FeedbackQuery: query,
596600
AppendCommentMutation,
601+
AppendCommentsMutation,
597602
PrependCommentMutation,
603+
PrependCommentsMutation,
598604
DeleteCommentMutation,
599605
DeleteCommentsMutation,
600606
} = generateAndCompile(`
@@ -606,7 +612,9 @@ describe('connection edge mutations', () => {
606612
) {
607613
__id
608614
edges {
615+
__typename
609616
node {
617+
__typename
610618
id
611619
}
612620
}
@@ -628,6 +636,20 @@ describe('connection edge mutations', () => {
628636
}
629637
}
630638
639+
mutation AppendCommentsMutation(
640+
$connections: [ID!]!
641+
$input: CommentsCreateInput
642+
) {
643+
commentsCreate(input: $input) {
644+
feedbackCommentEdges @appendEdge(connections: $connections) {
645+
cursor
646+
node {
647+
id
648+
}
649+
}
650+
}
651+
}
652+
631653
mutation PrependCommentMutation(
632654
$connections: [ID!]!
633655
$input: CommentCreateInput
@@ -642,6 +664,20 @@ describe('connection edge mutations', () => {
642664
}
643665
}
644666
667+
mutation PrependCommentsMutation(
668+
$connections: [ID!]!
669+
$input: CommentsCreateInput
670+
) {
671+
commentsCreate(input: $input) {
672+
feedbackCommentEdges @prependEdge(connections: $connections) {
673+
cursor
674+
node {
675+
id
676+
}
677+
}
678+
}
679+
}
680+
645681
mutation DeleteCommentMutation(
646682
$connections: [ID!]!
647683
$input: CommentDeleteInput
@@ -668,10 +704,24 @@ describe('connection edge mutations', () => {
668704
connections: [clientID],
669705
input: {},
670706
});
707+
appendMultipleOperation = createOperationDescriptor(
708+
AppendCommentsMutation,
709+
{
710+
connections: [clientID],
711+
input: {},
712+
},
713+
);
671714
prependOperation = createOperationDescriptor(PrependCommentMutation, {
672715
connections: [clientID],
673716
input: {},
674717
});
718+
prependMultipleOperation = createOperationDescriptor(
719+
PrependCommentsMutation,
720+
{
721+
connections: [clientID],
722+
input: {},
723+
},
724+
);
675725
deleteOperation = createOperationDescriptor(DeleteCommentMutation, {
676726
connections: [clientID],
677727
input: {},
@@ -705,13 +755,15 @@ describe('connection edge mutations', () => {
705755
comments: {
706756
edges: [
707757
{
758+
__typename: 'CommentsEdge',
708759
cursor: 'cursor-1',
709760
node: {
710761
__typename: 'Comment',
711762
id: 'node-1',
712763
},
713764
},
714765
{
766+
__typename: 'CommentsEdge',
715767
cursor: 'cursor-2',
716768
node: {
717769
__typename: 'Comment',
@@ -735,13 +787,15 @@ describe('connection edge mutations', () => {
735787
__id: clientID,
736788
edges: [
737789
{
790+
__typename: 'CommentsEdge',
738791
cursor: 'cursor-1',
739792
node: {
740793
__typename: 'Comment',
741794
id: 'node-1',
742795
},
743796
},
744797
{
798+
__typename: 'CommentsEdge',
745799
cursor: 'cursor-2',
746800
node: {
747801
__typename: 'Comment',
@@ -795,20 +849,23 @@ describe('connection edge mutations', () => {
795849
// $FlowExpectedError[incompatible-use]
796850
expect(callback.mock.calls[0][0].data.node.comments.edges).toEqual([
797851
{
852+
__typename: 'CommentsEdge',
798853
cursor: 'cursor-1',
799854
node: {
800855
__typename: 'Comment',
801856
id: 'node-1',
802857
},
803858
},
804859
{
860+
__typename: 'CommentsEdge',
805861
cursor: 'cursor-2',
806862
node: {
807863
__typename: 'Comment',
808864
id: 'node-2',
809865
},
810866
},
811867
{
868+
__typename: 'CommentsEdge',
812869
cursor: 'cursor-append',
813870
node: {
814871
__typename: 'Comment',
@@ -842,27 +899,31 @@ describe('connection edge mutations', () => {
842899
// $FlowExpectedError[incompatible-use]
843900
expect(callback.mock.calls[0][0].data.node.comments.edges).toEqual([
844901
{
902+
__typename: 'CommentsEdge',
845903
cursor: 'cursor-prepend',
846904
node: {
847905
__typename: 'Comment',
848906
id: 'node-prepend',
849907
},
850908
},
851909
{
910+
__typename: 'CommentsEdge',
852911
cursor: 'cursor-1',
853912
node: {
854913
__typename: 'Comment',
855914
id: 'node-1',
856915
},
857916
},
858917
{
918+
__typename: 'CommentsEdge',
859919
cursor: 'cursor-2',
860920
node: {
861921
__typename: 'Comment',
862922
id: 'node-2',
863923
},
864924
},
865925
{
926+
__typename: 'CommentsEdge',
866927
cursor: 'cursor-append',
867928
node: {
868929
__typename: 'Comment',
@@ -872,6 +933,169 @@ describe('connection edge mutations', () => {
872933
]);
873934
});
874935

936+
it('commits the mutation and inserts multiple comment edges into the connection', () => {
937+
const snapshot = environment.lookup(operation.fragment);
938+
const callback = jest.fn();
939+
environment.subscribe(snapshot, callback);
940+
941+
environment
942+
.executeMutation({
943+
operation: appendMultipleOperation,
944+
})
945+
.subscribe(callbacks);
946+
947+
callback.mockClear();
948+
subject.next({
949+
data: {
950+
commentsCreate: {
951+
feedbackCommentEdges: [
952+
{
953+
__typename: 'CommentsEdge',
954+
cursor: 'node-append-1',
955+
node: {
956+
__typename: 'Comment',
957+
id: 'node-append-1',
958+
},
959+
},
960+
{
961+
__typename: 'CommentsEdge',
962+
cursor: 'node-append-2',
963+
node: {
964+
__typename: 'Comment',
965+
id: 'node-append-2',
966+
},
967+
},
968+
],
969+
},
970+
},
971+
});
972+
subject.complete();
973+
974+
expect(complete).toBeCalled();
975+
expect(error).not.toBeCalled();
976+
expect(callback.mock.calls.length).toBe(1);
977+
// $FlowExpectedError[incompatible-use]
978+
expect(callback.mock.calls[0][0].data.node.comments.edges).toEqual([
979+
{
980+
__typename: 'CommentsEdge',
981+
cursor: 'cursor-1',
982+
node: {
983+
__typename: 'Comment',
984+
id: 'node-1',
985+
},
986+
},
987+
{
988+
__typename: 'CommentsEdge',
989+
cursor: 'cursor-2',
990+
node: {
991+
__typename: 'Comment',
992+
id: 'node-2',
993+
},
994+
},
995+
{
996+
__typename: 'CommentsEdge',
997+
cursor: 'node-append-1',
998+
node: {
999+
__typename: 'Comment',
1000+
id: 'node-append-1',
1001+
},
1002+
},
1003+
{
1004+
__typename: 'CommentsEdge',
1005+
cursor: 'node-append-2',
1006+
node: {
1007+
__typename: 'Comment',
1008+
id: 'node-append-2',
1009+
},
1010+
},
1011+
]);
1012+
1013+
environment
1014+
.executeMutation({
1015+
operation: prependMultipleOperation,
1016+
})
1017+
.subscribe(callbacks);
1018+
1019+
callback.mockClear();
1020+
subject.next({
1021+
data: {
1022+
commentsCreate: {
1023+
feedbackCommentEdges: [
1024+
{
1025+
__typename: 'CommentsEdge',
1026+
cursor: 'node-prepend-1',
1027+
node: {
1028+
__typename: 'Comment',
1029+
id: 'node-prepend-1',
1030+
},
1031+
},
1032+
{
1033+
__typename: 'CommentsEdge',
1034+
cursor: 'node-prepend-2',
1035+
node: {
1036+
__typename: 'Comment',
1037+
id: 'node-prepend-2',
1038+
},
1039+
},
1040+
],
1041+
},
1042+
},
1043+
});
1044+
subject.complete();
1045+
expect(callback.mock.calls.length).toBe(1);
1046+
// $FlowExpectedError[incompatible-use]
1047+
expect(callback.mock.calls[0][0].data.node.comments.edges).toEqual([
1048+
{
1049+
__typename: 'CommentsEdge',
1050+
cursor: 'node-prepend-2',
1051+
node: {
1052+
__typename: 'Comment',
1053+
id: 'node-prepend-2',
1054+
},
1055+
},
1056+
{
1057+
__typename: 'CommentsEdge',
1058+
cursor: 'node-prepend-1',
1059+
node: {
1060+
__typename: 'Comment',
1061+
id: 'node-prepend-1',
1062+
},
1063+
},
1064+
{
1065+
__typename: 'CommentsEdge',
1066+
cursor: 'cursor-1',
1067+
node: {
1068+
__typename: 'Comment',
1069+
id: 'node-1',
1070+
},
1071+
},
1072+
{
1073+
__typename: 'CommentsEdge',
1074+
cursor: 'cursor-2',
1075+
node: {
1076+
__typename: 'Comment',
1077+
id: 'node-2',
1078+
},
1079+
},
1080+
{
1081+
__typename: 'CommentsEdge',
1082+
cursor: 'node-append-1',
1083+
node: {
1084+
__typename: 'Comment',
1085+
id: 'node-append-1',
1086+
},
1087+
},
1088+
{
1089+
__typename: 'CommentsEdge',
1090+
cursor: 'node-append-2',
1091+
node: {
1092+
__typename: 'Comment',
1093+
id: 'node-append-2',
1094+
},
1095+
},
1096+
]);
1097+
});
1098+
8751099
it('inserts an comment edge during optmistic update, and reverts and inserts new edge when server payload resolves', () => {
8761100
const snapshot = environment.lookup(operation.fragment);
8771101
const callback = jest.fn();
@@ -898,20 +1122,23 @@ describe('connection edge mutations', () => {
8981122
// $FlowExpectedError[incompatible-use]
8991123
expect(callback.mock.calls[0][0].data.node.comments.edges).toEqual([
9001124
{
1125+
__typename: 'CommentsEdge',
9011126
cursor: 'cursor-1',
9021127
node: {
9031128
__typename: 'Comment',
9041129
id: 'node-1',
9051130
},
9061131
},
9071132
{
1133+
__typename: 'CommentsEdge',
9081134
cursor: 'cursor-2',
9091135
node: {
9101136
__typename: 'Comment',
9111137
id: 'node-2',
9121138
},
9131139
},
9141140
{
1141+
__typename: 'CommentsEdge',
9151142
cursor: 'cursor-optimistic-append',
9161143
node: {
9171144
__typename: 'Comment',
@@ -942,20 +1169,23 @@ describe('connection edge mutations', () => {
9421169
// $FlowExpectedError[incompatible-use]
9431170
expect(callback.mock.calls[0][0].data.node.comments.edges).toEqual([
9441171
{
1172+
__typename: 'CommentsEdge',
9451173
cursor: 'cursor-1',
9461174
node: {
9471175
__typename: 'Comment',
9481176
id: 'node-1',
9491177
},
9501178
},
9511179
{
1180+
__typename: 'CommentsEdge',
9521181
cursor: 'cursor-2',
9531182
node: {
9541183
__typename: 'Comment',
9551184
id: 'node-2',
9561185
},
9571186
},
9581187
{
1188+
__typename: 'CommentsEdge',
9591189
cursor: 'cursor-append',
9601190
node: {
9611191
__typename: 'Comment',
@@ -994,6 +1224,7 @@ describe('connection edge mutations', () => {
9941224
// $FlowExpectedError[incompatible-use]
9951225
expect(callback.mock.calls[0][0].data.node.comments.edges).toEqual([
9961226
{
1227+
__typename: 'CommentsEdge',
9971228
cursor: 'cursor-2',
9981229
node: {
9991230
__typename: 'Comment',

0 commit comments

Comments
 (0)
Please sign in to comment.