Skip to content

Commit a441116

Browse files
committed
fix deleteOthers showing on undeletable relations and make updateByNodeId work
1 parent 39426f8 commit a441116

File tree

7 files changed

+328
-6
lines changed

7 files changed

+328
-6
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# Changes
22

3+
## v1.0.0-alpha.19
4+
5+
* `deleteOthers` now is not in the schema where the foreign table
6+
has `@omit delete`.
7+
* Fixed error that prevented `updateByNodeId` from working.
8+
39
## v1.0.0-alpha.18
410

511
* Correctly handle `null` values to connect and update fields.

__tests__/integration/__snapshots__/update.test.js.snap

Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,90 @@
11
// Jest Snapshot v1, https://goo.gl/fbAQLP
22

3+
exports[`deleteOthers is not available if foreign table has @omit delete 1`] = `
4+
GraphQLSchema {
5+
"__allowedLegacyNames": Array [],
6+
"__validationErrors": undefined,
7+
"_directives": Array [
8+
"@include",
9+
"@skip",
10+
"@deprecated",
11+
],
12+
"_implementations": Object {
13+
"Node": Array [
14+
"Query",
15+
"Child",
16+
"Parent",
17+
],
18+
},
19+
"_mutationType": "Mutation",
20+
"_possibleTypeMap": undefined,
21+
"_queryType": "Query",
22+
"_subscriptionType": undefined,
23+
"_typeMap": Object {
24+
"Boolean": "Boolean",
25+
"Child": "Child",
26+
"ChildChildPkeyConnect": "ChildChildPkeyConnect",
27+
"ChildCondition": "ChildCondition",
28+
"ChildInput": "ChildInput",
29+
"ChildNodeIdConnect": "ChildNodeIdConnect",
30+
"ChildOnChildForChildParentFkeyNodeIdUpdate": "ChildOnChildForChildParentFkeyNodeIdUpdate",
31+
"ChildOnChildForChildParentFkeyUsingChildPkeyUpdate": "ChildOnChildForChildParentFkeyUsingChildPkeyUpdate",
32+
"ChildParentFkeyChildCreateInput": "ChildParentFkeyChildCreateInput",
33+
"ChildParentFkeyInput": "ChildParentFkeyInput",
34+
"ChildParentFkeyInverseInput": "ChildParentFkeyInverseInput",
35+
"ChildParentFkeyParentCreateInput": "ChildParentFkeyParentCreateInput",
36+
"ChildPatch": "ChildPatch",
37+
"ChildrenConnection": "ChildrenConnection",
38+
"ChildrenEdge": "ChildrenEdge",
39+
"ChildrenOrderBy": "ChildrenOrderBy",
40+
"CreateChildInput": "CreateChildInput",
41+
"CreateChildPayload": "CreateChildPayload",
42+
"CreateParentInput": "CreateParentInput",
43+
"CreateParentPayload": "CreateParentPayload",
44+
"Cursor": "Cursor",
45+
"DeleteParentByIdInput": "DeleteParentByIdInput",
46+
"DeleteParentInput": "DeleteParentInput",
47+
"DeleteParentPayload": "DeleteParentPayload",
48+
"ID": "ID",
49+
"Int": "Int",
50+
"Mutation": "Mutation",
51+
"Node": "Node",
52+
"PageInfo": "PageInfo",
53+
"Parent": "Parent",
54+
"ParentCondition": "ParentCondition",
55+
"ParentInput": "ParentInput",
56+
"ParentNodeIdConnect": "ParentNodeIdConnect",
57+
"ParentOnChildForChildParentFkeyNodeIdUpdate": "ParentOnChildForChildParentFkeyNodeIdUpdate",
58+
"ParentOnChildForChildParentFkeyUsingParentPkeyUpdate": "ParentOnChildForChildParentFkeyUsingParentPkeyUpdate",
59+
"ParentParentPkeyConnect": "ParentParentPkeyConnect",
60+
"ParentPatch": "ParentPatch",
61+
"ParentsConnection": "ParentsConnection",
62+
"ParentsEdge": "ParentsEdge",
63+
"ParentsOrderBy": "ParentsOrderBy",
64+
"Query": "Query",
65+
"String": "String",
66+
"UpdateChildByIdInput": "UpdateChildByIdInput",
67+
"UpdateChildInput": "UpdateChildInput",
68+
"UpdateChildPayload": "UpdateChildPayload",
69+
"UpdateParentByIdInput": "UpdateParentByIdInput",
70+
"UpdateParentInput": "UpdateParentInput",
71+
"UpdateParentPayload": "UpdateParentPayload",
72+
"__Directive": "__Directive",
73+
"__DirectiveLocation": "__DirectiveLocation",
74+
"__EnumValue": "__EnumValue",
75+
"__Field": "__Field",
76+
"__InputValue": "__InputValue",
77+
"__Schema": "__Schema",
78+
"__Type": "__Type",
79+
"__TypeKind": "__TypeKind",
80+
"updateChildOnChildForChildParentFkeyPatch": "updateChildOnChildForChildParentFkeyPatch",
81+
"updateParentOnChildForChildParentFkeyPatch": "updateParentOnChildForChildParentFkeyPatch",
82+
},
83+
"astNode": undefined,
84+
"extensionASTNodes": undefined,
85+
}
86+
`;
87+
388
exports[`deleteOthers is not available when no primary key on the foreign relation 1`] = `
489
GraphQLSchema {
590
"__allowedLegacyNames": Array [],
@@ -515,6 +600,94 @@ GraphQLSchema {
515600
}
516601
`;
517602

603+
exports[`forward nested mutation with nested updateByNodeId 1`] = `
604+
GraphQLSchema {
605+
"__allowedLegacyNames": Array [],
606+
"__validationErrors": Array [],
607+
"_directives": Array [
608+
"@include",
609+
"@skip",
610+
"@deprecated",
611+
],
612+
"_implementations": Object {
613+
"Node": Array [
614+
"Query",
615+
"Child",
616+
"Parent",
617+
],
618+
},
619+
"_mutationType": "Mutation",
620+
"_possibleTypeMap": undefined,
621+
"_queryType": "Query",
622+
"_subscriptionType": undefined,
623+
"_typeMap": Object {
624+
"Boolean": "Boolean",
625+
"Child": "Child",
626+
"ChildChildPkeyConnect": "ChildChildPkeyConnect",
627+
"ChildCondition": "ChildCondition",
628+
"ChildInput": "ChildInput",
629+
"ChildNodeIdConnect": "ChildNodeIdConnect",
630+
"ChildOnChildForChildParentFkeyNodeIdUpdate": "ChildOnChildForChildParentFkeyNodeIdUpdate",
631+
"ChildOnChildForChildParentFkeyUsingChildPkeyUpdate": "ChildOnChildForChildParentFkeyUsingChildPkeyUpdate",
632+
"ChildParentFkeyChildCreateInput": "ChildParentFkeyChildCreateInput",
633+
"ChildParentFkeyInput": "ChildParentFkeyInput",
634+
"ChildParentFkeyInverseInput": "ChildParentFkeyInverseInput",
635+
"ChildParentFkeyParentCreateInput": "ChildParentFkeyParentCreateInput",
636+
"ChildPatch": "ChildPatch",
637+
"ChildrenConnection": "ChildrenConnection",
638+
"ChildrenEdge": "ChildrenEdge",
639+
"ChildrenOrderBy": "ChildrenOrderBy",
640+
"CreateChildInput": "CreateChildInput",
641+
"CreateChildPayload": "CreateChildPayload",
642+
"CreateParentInput": "CreateParentInput",
643+
"CreateParentPayload": "CreateParentPayload",
644+
"Cursor": "Cursor",
645+
"DeleteChildByIdInput": "DeleteChildByIdInput",
646+
"DeleteChildInput": "DeleteChildInput",
647+
"DeleteChildPayload": "DeleteChildPayload",
648+
"DeleteParentByIdInput": "DeleteParentByIdInput",
649+
"DeleteParentInput": "DeleteParentInput",
650+
"DeleteParentPayload": "DeleteParentPayload",
651+
"ID": "ID",
652+
"Int": "Int",
653+
"Mutation": "Mutation",
654+
"Node": "Node",
655+
"PageInfo": "PageInfo",
656+
"Parent": "Parent",
657+
"ParentCondition": "ParentCondition",
658+
"ParentInput": "ParentInput",
659+
"ParentNodeIdConnect": "ParentNodeIdConnect",
660+
"ParentOnChildForChildParentFkeyNodeIdUpdate": "ParentOnChildForChildParentFkeyNodeIdUpdate",
661+
"ParentOnChildForChildParentFkeyUsingParentPkeyUpdate": "ParentOnChildForChildParentFkeyUsingParentPkeyUpdate",
662+
"ParentParentPkeyConnect": "ParentParentPkeyConnect",
663+
"ParentPatch": "ParentPatch",
664+
"ParentsConnection": "ParentsConnection",
665+
"ParentsEdge": "ParentsEdge",
666+
"ParentsOrderBy": "ParentsOrderBy",
667+
"Query": "Query",
668+
"String": "String",
669+
"UpdateChildByIdInput": "UpdateChildByIdInput",
670+
"UpdateChildInput": "UpdateChildInput",
671+
"UpdateChildPayload": "UpdateChildPayload",
672+
"UpdateParentByIdInput": "UpdateParentByIdInput",
673+
"UpdateParentInput": "UpdateParentInput",
674+
"UpdateParentPayload": "UpdateParentPayload",
675+
"__Directive": "__Directive",
676+
"__DirectiveLocation": "__DirectiveLocation",
677+
"__EnumValue": "__EnumValue",
678+
"__Field": "__Field",
679+
"__InputValue": "__InputValue",
680+
"__Schema": "__Schema",
681+
"__Type": "__Type",
682+
"__TypeKind": "__TypeKind",
683+
"updateChildOnChildForChildParentFkeyPatch": "updateChildOnChildForChildParentFkeyPatch",
684+
"updateParentOnChildForChildParentFkeyPatch": "updateParentOnChildForChildParentFkeyPatch",
685+
},
686+
"astNode": undefined,
687+
"extensionASTNodes": undefined,
688+
}
689+
`;
690+
518691
exports[`reverse nested mutation with nested update 1`] = `
519692
GraphQLSchema {
520693
"__allowedLegacyNames": Array [],

__tests__/integration/update.test.js

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,71 @@ test(
245245
}),
246246
);
247247

248+
test(
249+
'deleteOthers is not available if foreign table has @omit delete',
250+
withSchema({
251+
setup: `
252+
create table p.parent (
253+
id serial primary key,
254+
name text not null
255+
);
256+
257+
create table p.child (
258+
id integer primary key,
259+
parent_id integer,
260+
name text not null,
261+
constraint child_parent_fkey foreign key (parent_id)
262+
references p.parent (id)
263+
);
264+
265+
comment on table p.child is E'@omit delete';
266+
267+
insert into p.parent values(1, 'test');
268+
insert into p.child values(99, 1, 'test child');
269+
`,
270+
test: async ({ schema, pgClient }) => {
271+
const query = `
272+
mutation {
273+
updateParentById(
274+
input: {
275+
id: 1
276+
parentPatch: {
277+
childrenUsingId: {
278+
deleteOthers: true
279+
create: [{
280+
id: 1
281+
name: "test child 2"
282+
}, {
283+
id: 2
284+
name: "test child 3"
285+
}]
286+
}
287+
}
288+
}
289+
) {
290+
parent {
291+
id
292+
name
293+
childrenByParentId {
294+
nodes {
295+
id
296+
parentId
297+
name
298+
}
299+
}
300+
}
301+
}
302+
}
303+
`;
304+
expect(schema).toMatchSnapshot();
305+
306+
const result = await graphql(schema, query, null, { pgClient });
307+
expect(result).toHaveProperty('errors');
308+
expect(result.errors[0].message).toMatch(/"deleteOthers" is not defined/);
309+
},
310+
}),
311+
);
312+
248313
test(
249314
'forward nested mutation with nested update',
250315
withSchema({
@@ -310,6 +375,82 @@ test(
310375
}),
311376
);
312377

378+
test(
379+
'forward nested mutation with nested updateByNodeId',
380+
withSchema({
381+
setup: `
382+
create table p.parent (
383+
id serial primary key,
384+
name text not null
385+
);
386+
387+
create table p.child (
388+
id serial primary key,
389+
parent_id integer,
390+
name text not null,
391+
constraint child_parent_fkey foreign key (parent_id)
392+
references p.parent (id)
393+
);
394+
395+
insert into p.parent values(1, 'test parent');
396+
insert into p.child values(1, 1, 'test child');
397+
`,
398+
test: async ({ schema, pgClient }) => {
399+
const lookupQuery = `
400+
query {
401+
childById(id: 1) {
402+
nodeId
403+
}
404+
}
405+
`;
406+
const lookupResult = await graphql(schema, lookupQuery, null, { pgClient });
407+
const { nodeId } = lookupResult.data.childById;
408+
expect(nodeId).not.toBeUndefined();
409+
410+
const query = `
411+
mutation {
412+
updateParentById(
413+
input: {
414+
id: 1
415+
parentPatch: {
416+
childrenUsingId: {
417+
updateByNodeId: {
418+
nodeId: "${nodeId}"
419+
childPatch: {
420+
name: "renamed child"
421+
}
422+
}
423+
}
424+
}
425+
}
426+
) {
427+
parent {
428+
id
429+
name
430+
childrenByParentId {
431+
nodes {
432+
id
433+
parentId
434+
name
435+
}
436+
}
437+
}
438+
}
439+
}
440+
`;
441+
expect(schema).toMatchSnapshot();
442+
443+
const result = await graphql(schema, query, null, { pgClient });
444+
expect(result).not.toHaveProperty('errors');
445+
446+
const data = result.data.updateParentById.parent;
447+
expect(data.childrenByParentId.nodes).toHaveLength(1);
448+
data.childrenByParentId.nodes.map(n => expect(n.parentId).toBe(data.id));
449+
expect(data.childrenByParentId.nodes[0].name).toEqual('renamed child');
450+
},
451+
}),
452+
);
453+
313454
test(
314455
'reverse nested mutation with nested update',
315456
withSchema({

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "postgraphile-plugin-nested-mutations",
3-
"version": "1.0.0-alpha.18",
3+
"version": "1.0.0-alpha.19",
44
"description": "Nested mutations plugin for PostGraphile",
55
"main": "index.js",
66
"repository": {

src/PostgraphileNestedConnectorsPlugin.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,6 @@ module.exports = function PostGraphileNestedConnectorsPlugin(
4444
pgSql: sql,
4545
gql2pg,
4646
nodeIdFieldName,
47-
getTypeAndIdentifiersFromNodeId,
4847
pgGetGqlTypeByTypeIdAndModifier,
4948
} = build;
5049

@@ -73,7 +72,7 @@ module.exports = function PostGraphileNestedConnectorsPlugin(
7372
if (isNodeIdConnector) {
7473
const nodeId = input[nodeIdFieldName];
7574
const primaryKeys = foreignTable.primaryKeyConstraint.keyAttributes;
76-
const { Type, identifiers } = getTypeAndIdentifiersFromNodeId.bind(build)(nodeId);
75+
const { Type, identifiers } = build.getTypeAndIdentifiersFromNodeId(nodeId);
7776
if (Type !== ForeignTableType) {
7877
throw new Error('Mismatched type');
7978
}

src/PostgraphileNestedTypesPlugin.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,10 @@ module.exports = function PostGraphileNestedTypesPlugin(
185185
&& !constraint.keyAttributes.some(key => omit(key, 'create'));
186186
const updateable = !omit(foreignTable, 'update')
187187
&& !omit(constraint, 'update');
188+
const deleteable = nestedMutationsDeleteOthers
189+
&& foreignTable.primaryKeyConstraint
190+
&& !omit(foreignTable, 'delete')
191+
&& !omit(constraint, 'delete');
188192

189193
if (
190194
(!connectable && !creatable && !updateable)
@@ -232,7 +236,7 @@ module.exports = function PostGraphileNestedTypesPlugin(
232236
const gqlForeignTableType = getGqlInputTypeByTypeIdAndModifier(foreignTable.type.id, null);
233237
const operations = {};
234238

235-
if (!isForward && nestedMutationsDeleteOthers && foreignTable.primaryKeyConstraint) {
239+
if (!isForward && deleteable) {
236240
operations.deleteOthers = {
237241
description: `Flag indicating whether all other \`${foreignTableName}\` records that match this relationship should be removed.`,
238242
type: GraphQLBoolean,

0 commit comments

Comments
 (0)