From 34f725ac61f7963361a5e11ca816218bcf2c9f0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Decan?= Date: Tue, 29 Jun 2021 15:32:33 +0200 Subject: [PATCH 1/3] add nested updates support --- src/PostgraphileNestedMutationsPlugin.js | 71 ++++++++++++++++++++++-- src/PostgraphileNestedTypesPlugin.js | 3 +- 2 files changed, 68 insertions(+), 6 deletions(-) diff --git a/src/PostgraphileNestedMutationsPlugin.js b/src/PostgraphileNestedMutationsPlugin.js index c4aa384..3c55d84 100644 --- a/src/PostgraphileNestedMutationsPlugin.js +++ b/src/PostgraphileNestedMutationsPlugin.js @@ -66,7 +66,8 @@ module.exports = function PostGraphileNestedMutationPlugin(builder) { pgQueryFromResolveData: queryFromResolveData, pgNestedPluginForwardInputTypes, pgNestedPluginReverseInputTypes, - pgNestedResolvers, + pgNestedCreateResolvers, + pgNestedUpdateResolvers, pgNestedTableConnectorFields, pgNestedTableConnect, pgNestedTableDeleterFields, @@ -97,7 +98,7 @@ module.exports = function PostGraphileNestedMutationPlugin(builder) { !pgNestedPluginForwardInputTypes[table.id] && !pgNestedPluginReverseInputTypes[table.id] ) { - pgNestedResolvers[table.id] = field.resolve; + pgNestedCreateResolvers[table.id] = field.resolve; return field; } @@ -207,7 +208,7 @@ module.exports = function PostGraphileNestedMutationPlugin(builder) { if (fieldValue.create) { const createData = fieldValue.create; - const resolver = pgNestedResolvers[foreignTable.id]; + const resolver = pgNestedCreateResolvers[foreignTable.id]; const tableVar = inflection.tableFieldName(foreignTable); const insertData = Object.assign( @@ -232,6 +233,35 @@ module.exports = function PostGraphileNestedMutationPlugin(builder) { resolveResult.data[`__pk__${k.name}`]; }); } + + await Promise.all(Object.keys(fieldValue).map(async k => { + if (k.includes('updateBy')) { + const rowData = fieldValue[k] + const resolver = pgNestedUpdateResolvers[foreignTable.id]; + + const updateData = Object.assign( + {}, + rowData, + await recurseForwardNestedMutations( + data, + { input: rowData }, + { pgClient }, + resolveInfo, + ), + ); + + const resolveResult = await resolver( + data, + { input: updateData }, + { pgClient }, + resolveInfo, + ); + foreignKeys.forEach((k, idx) => { + output[inflection.column(keys[idx])] = + resolveResult.data[`__pk__${k.name}`]; + }); + } + })) }), ); @@ -580,7 +610,7 @@ module.exports = function PostGraphileNestedMutationPlugin(builder) { if (fieldValue.create) { await Promise.all( fieldValue.create.map(async (rowData) => { - const resolver = pgNestedResolvers[foreignTable.id]; + const resolver = pgNestedCreateResolvers[foreignTable.id]; const tableVar = inflection.tableFieldName(foreignTable); const keyData = {}; @@ -610,6 +640,33 @@ module.exports = function PostGraphileNestedMutationPlugin(builder) { }), ); } + + await Promise.all(Object.keys(fieldValue).map(async k => { + if (k.includes('updateBy')) { + await Promise.all( + fieldValue[k].map(async (rowData) => { + const resolver = pgNestedUpdateResolvers[foreignTable.id]; + + const { data: reverseRow } = await resolver( + data, + { + input: Object.assign({}, rowData), + }, + { pgClient }, + resolveInfo, + ); + + const rowKeyValues = {}; + if (primaryKeys) { + primaryKeys.forEach((k) => { + rowKeyValues[k.name] = reverseRow[`__pk__${k.name}`]; + }); + } + modifiedRows.push(rowKeyValues); + }), + ); + } + })) }), ); @@ -655,7 +712,11 @@ module.exports = function PostGraphileNestedMutationPlugin(builder) { }; if (isPgCreateMutationField) { - pgNestedResolvers[table.id] = newResolver; + pgNestedCreateResolvers[table.id] = newResolver; + } + + if (isPgUpdateMutationField) { + pgNestedUpdateResolvers[table.id] = newResolver; } return Object.assign({}, field, { resolve: newResolver }); diff --git a/src/PostgraphileNestedTypesPlugin.js b/src/PostgraphileNestedTypesPlugin.js index 16ecacc..9569128 100644 --- a/src/PostgraphileNestedTypesPlugin.js +++ b/src/PostgraphileNestedTypesPlugin.js @@ -41,7 +41,8 @@ module.exports = function PostGraphileNestedTypesPlugin( return extend(build, { pgNestedPluginForwardInputTypes: {}, pgNestedPluginReverseInputTypes: {}, - pgNestedResolvers: {}, + pgNestedCreateResolvers: {}, + pgNestedUpdateResolvers: {}, pgNestedFieldName(options) { const { constraint: { From 23731de47d035e833e0818b825e1127a52f11c1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Decan?= Date: Tue, 29 Jun 2021 16:11:26 +0200 Subject: [PATCH 2/3] support arrays and objects --- src/PostgraphileNestedMutationsPlugin.js | 72 ++++++++++++------------ 1 file changed, 36 insertions(+), 36 deletions(-) diff --git a/src/PostgraphileNestedMutationsPlugin.js b/src/PostgraphileNestedMutationsPlugin.js index 3c55d84..8695d72 100644 --- a/src/PostgraphileNestedMutationsPlugin.js +++ b/src/PostgraphileNestedMutationsPlugin.js @@ -236,29 +236,30 @@ module.exports = function PostGraphileNestedMutationPlugin(builder) { await Promise.all(Object.keys(fieldValue).map(async k => { if (k.includes('updateBy')) { - const rowData = fieldValue[k] - const resolver = pgNestedUpdateResolvers[foreignTable.id]; + (Array.isArray(fieldValue[k]) ? fieldValue[k] : [fieldValue[k]]).map(async (rowData) => { + const resolver = pgNestedUpdateResolvers[foreignTable.id]; - const updateData = Object.assign( - {}, - rowData, - await recurseForwardNestedMutations( + const updateData = Object.assign( + {}, + rowData, + await recurseForwardNestedMutations( + data, + { input: rowData }, + { pgClient }, + resolveInfo, + ), + ); + + const resolveResult = await resolver( data, - { input: rowData }, + { input: updateData }, { pgClient }, resolveInfo, - ), - ); - - const resolveResult = await resolver( - data, - { input: updateData }, - { pgClient }, - resolveInfo, - ); - foreignKeys.forEach((k, idx) => { - output[inflection.column(keys[idx])] = - resolveResult.data[`__pk__${k.name}`]; + ); + foreignKeys.forEach((k, idx) => { + output[inflection.column(keys[idx])] = + resolveResult.data[`__pk__${k.name}`]; + }); }); } })) @@ -327,13 +328,12 @@ module.exports = function PostGraphileNestedMutationPlugin(builder) { /* eslint indent: 0 */ mutationQuery = sql.query` insert into ${sql.identifier(table.namespace.name, table.name)} - ${ - sqlColumns.length - ? sql.fragment`( + ${sqlColumns.length + ? sql.fragment`( ${sql.join(sqlColumns, ', ')} ) values(${sql.join(sqlValues, ', ')})` - : sql.fragment`default values` - } returning *`; + : sql.fragment`default values` + } returning *`; } else if (isPgUpdateMutationField) { const sqlColumns = []; const sqlValues = []; @@ -396,9 +396,9 @@ module.exports = function PostGraphileNestedMutationPlugin(builder) { if (sqlColumns.length) { mutationQuery = sql.query` update ${sql.identifier( - table.namespace.name, - table.name, - )} set ${sql.join( + table.namespace.name, + table.name, + )} set ${sql.join( sqlColumns.map( (col, i) => sql.fragment`${col} = ${sqlValues[i]}`, ), @@ -522,14 +522,14 @@ module.exports = function PostGraphileNestedMutationPlugin(builder) { updaterField.map(async (node) => { const where = sql.fragment` (${sql.join( - keys.map( - (k, i) => - sql.fragment`${sql.identifier(k.name)} = ${sql.value( - row[foreignKeys[i].name], - )}`, - ), - ') and (', - )}) + keys.map( + (k, i) => + sql.fragment`${sql.identifier(k.name)} = ${sql.value( + row[foreignKeys[i].name], + )}`, + ), + ') and (', + )}) `; const updatedRow = await pgNestedTableUpdate({ nestedField, @@ -644,7 +644,7 @@ module.exports = function PostGraphileNestedMutationPlugin(builder) { await Promise.all(Object.keys(fieldValue).map(async k => { if (k.includes('updateBy')) { await Promise.all( - fieldValue[k].map(async (rowData) => { + (Array.isArray(fieldValue[k]) ? fieldValue[k] : [fieldValue[k]]).map(async (rowData) => { const resolver = pgNestedUpdateResolvers[foreignTable.id]; const { data: reverseRow } = await resolver( From 6e44ce9d8e466ca6db230552ca967c08b53ed984 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Isaksson=20Kraft?= Date: Fri, 30 Jul 2021 13:20:29 +0200 Subject: [PATCH 3/3] Added test cases and fixed regressions for nested mutations. --- .../__snapshots__/update.test.js.snap | 889 ++++++++++++++++++ __tests__/integration/update.test.js | 777 ++++++++++++++- src/PostgraphileNestedMutationsPlugin.js | 169 ++-- 3 files changed, 1754 insertions(+), 81 deletions(-) diff --git a/__tests__/integration/__snapshots__/update.test.js.snap b/__tests__/integration/__snapshots__/update.test.js.snap index e19c736..ea982ff 100644 --- a/__tests__/integration/__snapshots__/update.test.js.snap +++ b/__tests__/integration/__snapshots__/update.test.js.snap @@ -746,6 +746,641 @@ GraphQLSchema { } `; +exports[`forward deeply nested mutation with nested updateByNodeId 1`] = ` +GraphQLSchema { + "__validationErrors": Array [], + "_directives": Array [ + "@include", + "@skip", + "@deprecated", + "@specifiedBy", + ], + "_implementationsMap": Object { + "Node": Object { + "interfaces": Array [], + "objects": Array [ + "Query", + "Child", + "Parent", + "Grandchild", + ], + }, + }, + "_mutationType": "Mutation", + "_queryType": "Query", + "_subTypeMap": Object {}, + "_subscriptionType": undefined, + "_typeMap": Object { + "Boolean": "Boolean", + "Child": "Child", + "ChildChildPkeyConnect": "ChildChildPkeyConnect", + "ChildChildPkeyDelete": "ChildChildPkeyDelete", + "ChildCondition": "ChildCondition", + "ChildInput": "ChildInput", + "ChildNodeIdConnect": "ChildNodeIdConnect", + "ChildNodeIdDelete": "ChildNodeIdDelete", + "ChildOnChildForChildParentFkeyNodeIdUpdate": "ChildOnChildForChildParentFkeyNodeIdUpdate", + "ChildOnChildForChildParentFkeyUsingChildPkeyUpdate": "ChildOnChildForChildParentFkeyUsingChildPkeyUpdate", + "ChildOnGrandchildForGrandchildChildFkeyNodeIdUpdate": "ChildOnGrandchildForGrandchildChildFkeyNodeIdUpdate", + "ChildOnGrandchildForGrandchildChildFkeyUsingChildPkeyUpdate": "ChildOnGrandchildForGrandchildChildFkeyUsingChildPkeyUpdate", + "ChildParentFkeyChildCreateInput": "ChildParentFkeyChildCreateInput", + "ChildParentFkeyInput": "ChildParentFkeyInput", + "ChildParentFkeyInverseInput": "ChildParentFkeyInverseInput", + "ChildParentFkeyParentCreateInput": "ChildParentFkeyParentCreateInput", + "ChildPatch": "ChildPatch", + "ChildrenConnection": "ChildrenConnection", + "ChildrenEdge": "ChildrenEdge", + "ChildrenOrderBy": "ChildrenOrderBy", + "CreateChildInput": "CreateChildInput", + "CreateChildPayload": "CreateChildPayload", + "CreateGrandchildInput": "CreateGrandchildInput", + "CreateGrandchildPayload": "CreateGrandchildPayload", + "CreateParentInput": "CreateParentInput", + "CreateParentPayload": "CreateParentPayload", + "Cursor": "Cursor", + "DeleteChildByIdInput": "DeleteChildByIdInput", + "DeleteChildInput": "DeleteChildInput", + "DeleteChildPayload": "DeleteChildPayload", + "DeleteGrandchildByIdInput": "DeleteGrandchildByIdInput", + "DeleteGrandchildInput": "DeleteGrandchildInput", + "DeleteGrandchildPayload": "DeleteGrandchildPayload", + "DeleteParentByIdInput": "DeleteParentByIdInput", + "DeleteParentInput": "DeleteParentInput", + "DeleteParentPayload": "DeleteParentPayload", + "Grandchild": "Grandchild", + "GrandchildChildFkeyChildCreateInput": "GrandchildChildFkeyChildCreateInput", + "GrandchildChildFkeyGrandchildCreateInput": "GrandchildChildFkeyGrandchildCreateInput", + "GrandchildChildFkeyInput": "GrandchildChildFkeyInput", + "GrandchildChildFkeyInverseInput": "GrandchildChildFkeyInverseInput", + "GrandchildCondition": "GrandchildCondition", + "GrandchildGrandchildPkeyConnect": "GrandchildGrandchildPkeyConnect", + "GrandchildGrandchildPkeyDelete": "GrandchildGrandchildPkeyDelete", + "GrandchildInput": "GrandchildInput", + "GrandchildNodeIdConnect": "GrandchildNodeIdConnect", + "GrandchildNodeIdDelete": "GrandchildNodeIdDelete", + "GrandchildOnGrandchildForGrandchildChildFkeyNodeIdUpdate": "GrandchildOnGrandchildForGrandchildChildFkeyNodeIdUpdate", + "GrandchildOnGrandchildForGrandchildChildFkeyUsingGrandchildPkeyUpdate": "GrandchildOnGrandchildForGrandchildChildFkeyUsingGrandchildPkeyUpdate", + "GrandchildPatch": "GrandchildPatch", + "GrandchildrenConnection": "GrandchildrenConnection", + "GrandchildrenEdge": "GrandchildrenEdge", + "GrandchildrenOrderBy": "GrandchildrenOrderBy", + "ID": "ID", + "Int": "Int", + "Mutation": "Mutation", + "Node": "Node", + "PageInfo": "PageInfo", + "Parent": "Parent", + "ParentCondition": "ParentCondition", + "ParentInput": "ParentInput", + "ParentNodeIdConnect": "ParentNodeIdConnect", + "ParentNodeIdDelete": "ParentNodeIdDelete", + "ParentOnChildForChildParentFkeyNodeIdUpdate": "ParentOnChildForChildParentFkeyNodeIdUpdate", + "ParentOnChildForChildParentFkeyUsingParentPkeyUpdate": "ParentOnChildForChildParentFkeyUsingParentPkeyUpdate", + "ParentParentPkeyConnect": "ParentParentPkeyConnect", + "ParentParentPkeyDelete": "ParentParentPkeyDelete", + "ParentPatch": "ParentPatch", + "ParentsConnection": "ParentsConnection", + "ParentsEdge": "ParentsEdge", + "ParentsOrderBy": "ParentsOrderBy", + "Query": "Query", + "String": "String", + "UpdateChildByIdInput": "UpdateChildByIdInput", + "UpdateChildInput": "UpdateChildInput", + "UpdateChildPayload": "UpdateChildPayload", + "UpdateGrandchildByIdInput": "UpdateGrandchildByIdInput", + "UpdateGrandchildInput": "UpdateGrandchildInput", + "UpdateGrandchildPayload": "UpdateGrandchildPayload", + "UpdateParentByIdInput": "UpdateParentByIdInput", + "UpdateParentInput": "UpdateParentInput", + "UpdateParentPayload": "UpdateParentPayload", + "__Directive": "__Directive", + "__DirectiveLocation": "__DirectiveLocation", + "__EnumValue": "__EnumValue", + "__Field": "__Field", + "__InputValue": "__InputValue", + "__Schema": "__Schema", + "__Type": "__Type", + "__TypeKind": "__TypeKind", + "updateChildOnChildForChildParentFkeyPatch": "updateChildOnChildForChildParentFkeyPatch", + "updateChildOnGrandchildForGrandchildChildFkeyPatch": "updateChildOnGrandchildForGrandchildChildFkeyPatch", + "updateGrandchildOnGrandchildForGrandchildChildFkeyPatch": "updateGrandchildOnGrandchildForGrandchildChildFkeyPatch", + "updateParentOnChildForChildParentFkeyPatch": "updateParentOnChildForChildParentFkeyPatch", + }, + "astNode": undefined, + "description": undefined, + "extensionASTNodes": undefined, + "extensions": undefined, +} +`; + +exports[`forward deeply nested update mutation with nested updateById 1`] = ` +GraphQLSchema { + "__validationErrors": Array [], + "_directives": Array [ + "@include", + "@skip", + "@deprecated", + "@specifiedBy", + ], + "_implementationsMap": Object { + "Node": Object { + "interfaces": Array [], + "objects": Array [ + "Query", + "Child", + "Parent", + "Grandchild", + ], + }, + }, + "_mutationType": "Mutation", + "_queryType": "Query", + "_subTypeMap": Object {}, + "_subscriptionType": undefined, + "_typeMap": Object { + "Boolean": "Boolean", + "Child": "Child", + "ChildChildPkeyConnect": "ChildChildPkeyConnect", + "ChildChildPkeyDelete": "ChildChildPkeyDelete", + "ChildCondition": "ChildCondition", + "ChildInput": "ChildInput", + "ChildNodeIdConnect": "ChildNodeIdConnect", + "ChildNodeIdDelete": "ChildNodeIdDelete", + "ChildOnChildForChildParentFkeyNodeIdUpdate": "ChildOnChildForChildParentFkeyNodeIdUpdate", + "ChildOnChildForChildParentFkeyUsingChildPkeyUpdate": "ChildOnChildForChildParentFkeyUsingChildPkeyUpdate", + "ChildOnGrandchildForGrandchildChildFkeyNodeIdUpdate": "ChildOnGrandchildForGrandchildChildFkeyNodeIdUpdate", + "ChildOnGrandchildForGrandchildChildFkeyUsingChildPkeyUpdate": "ChildOnGrandchildForGrandchildChildFkeyUsingChildPkeyUpdate", + "ChildParentFkeyChildCreateInput": "ChildParentFkeyChildCreateInput", + "ChildParentFkeyInput": "ChildParentFkeyInput", + "ChildParentFkeyInverseInput": "ChildParentFkeyInverseInput", + "ChildParentFkeyParentCreateInput": "ChildParentFkeyParentCreateInput", + "ChildPatch": "ChildPatch", + "ChildrenConnection": "ChildrenConnection", + "ChildrenEdge": "ChildrenEdge", + "ChildrenOrderBy": "ChildrenOrderBy", + "CreateChildInput": "CreateChildInput", + "CreateChildPayload": "CreateChildPayload", + "CreateGrandchildInput": "CreateGrandchildInput", + "CreateGrandchildPayload": "CreateGrandchildPayload", + "CreateParentInput": "CreateParentInput", + "CreateParentPayload": "CreateParentPayload", + "Cursor": "Cursor", + "DeleteChildByIdInput": "DeleteChildByIdInput", + "DeleteChildInput": "DeleteChildInput", + "DeleteChildPayload": "DeleteChildPayload", + "DeleteGrandchildByIdInput": "DeleteGrandchildByIdInput", + "DeleteGrandchildInput": "DeleteGrandchildInput", + "DeleteGrandchildPayload": "DeleteGrandchildPayload", + "DeleteParentByIdInput": "DeleteParentByIdInput", + "DeleteParentInput": "DeleteParentInput", + "DeleteParentPayload": "DeleteParentPayload", + "Grandchild": "Grandchild", + "GrandchildChildFkeyChildCreateInput": "GrandchildChildFkeyChildCreateInput", + "GrandchildChildFkeyGrandchildCreateInput": "GrandchildChildFkeyGrandchildCreateInput", + "GrandchildChildFkeyInput": "GrandchildChildFkeyInput", + "GrandchildChildFkeyInverseInput": "GrandchildChildFkeyInverseInput", + "GrandchildCondition": "GrandchildCondition", + "GrandchildGrandchildPkeyConnect": "GrandchildGrandchildPkeyConnect", + "GrandchildGrandchildPkeyDelete": "GrandchildGrandchildPkeyDelete", + "GrandchildInput": "GrandchildInput", + "GrandchildNodeIdConnect": "GrandchildNodeIdConnect", + "GrandchildNodeIdDelete": "GrandchildNodeIdDelete", + "GrandchildOnGrandchildForGrandchildChildFkeyNodeIdUpdate": "GrandchildOnGrandchildForGrandchildChildFkeyNodeIdUpdate", + "GrandchildOnGrandchildForGrandchildChildFkeyUsingGrandchildPkeyUpdate": "GrandchildOnGrandchildForGrandchildChildFkeyUsingGrandchildPkeyUpdate", + "GrandchildPatch": "GrandchildPatch", + "GrandchildrenConnection": "GrandchildrenConnection", + "GrandchildrenEdge": "GrandchildrenEdge", + "GrandchildrenOrderBy": "GrandchildrenOrderBy", + "ID": "ID", + "Int": "Int", + "Mutation": "Mutation", + "Node": "Node", + "PageInfo": "PageInfo", + "Parent": "Parent", + "ParentCondition": "ParentCondition", + "ParentInput": "ParentInput", + "ParentNodeIdConnect": "ParentNodeIdConnect", + "ParentNodeIdDelete": "ParentNodeIdDelete", + "ParentOnChildForChildParentFkeyNodeIdUpdate": "ParentOnChildForChildParentFkeyNodeIdUpdate", + "ParentOnChildForChildParentFkeyUsingParentPkeyUpdate": "ParentOnChildForChildParentFkeyUsingParentPkeyUpdate", + "ParentParentPkeyConnect": "ParentParentPkeyConnect", + "ParentParentPkeyDelete": "ParentParentPkeyDelete", + "ParentPatch": "ParentPatch", + "ParentsConnection": "ParentsConnection", + "ParentsEdge": "ParentsEdge", + "ParentsOrderBy": "ParentsOrderBy", + "Query": "Query", + "String": "String", + "UpdateChildByIdInput": "UpdateChildByIdInput", + "UpdateChildInput": "UpdateChildInput", + "UpdateChildPayload": "UpdateChildPayload", + "UpdateGrandchildByIdInput": "UpdateGrandchildByIdInput", + "UpdateGrandchildInput": "UpdateGrandchildInput", + "UpdateGrandchildPayload": "UpdateGrandchildPayload", + "UpdateParentByIdInput": "UpdateParentByIdInput", + "UpdateParentInput": "UpdateParentInput", + "UpdateParentPayload": "UpdateParentPayload", + "__Directive": "__Directive", + "__DirectiveLocation": "__DirectiveLocation", + "__EnumValue": "__EnumValue", + "__Field": "__Field", + "__InputValue": "__InputValue", + "__Schema": "__Schema", + "__Type": "__Type", + "__TypeKind": "__TypeKind", + "updateChildOnChildForChildParentFkeyPatch": "updateChildOnChildForChildParentFkeyPatch", + "updateChildOnGrandchildForGrandchildChildFkeyPatch": "updateChildOnGrandchildForGrandchildChildFkeyPatch", + "updateGrandchildOnGrandchildForGrandchildChildFkeyPatch": "updateGrandchildOnGrandchildForGrandchildChildFkeyPatch", + "updateParentOnChildForChildParentFkeyPatch": "updateParentOnChildForChildParentFkeyPatch", + }, + "astNode": undefined, + "description": undefined, + "extensionASTNodes": undefined, + "extensions": undefined, +} +`; + +exports[`forward deeply nested update mutation with nested updateById and connectById 1`] = ` +GraphQLSchema { + "__validationErrors": Array [], + "_directives": Array [ + "@include", + "@skip", + "@deprecated", + "@specifiedBy", + ], + "_implementationsMap": Object { + "Node": Object { + "interfaces": Array [], + "objects": Array [ + "Query", + "Child", + "Parent", + "Grandchild", + ], + }, + }, + "_mutationType": "Mutation", + "_queryType": "Query", + "_subTypeMap": Object {}, + "_subscriptionType": undefined, + "_typeMap": Object { + "Boolean": "Boolean", + "Child": "Child", + "ChildChildPkeyConnect": "ChildChildPkeyConnect", + "ChildChildPkeyDelete": "ChildChildPkeyDelete", + "ChildCondition": "ChildCondition", + "ChildInput": "ChildInput", + "ChildNodeIdConnect": "ChildNodeIdConnect", + "ChildNodeIdDelete": "ChildNodeIdDelete", + "ChildOnChildForChildParentFkeyNodeIdUpdate": "ChildOnChildForChildParentFkeyNodeIdUpdate", + "ChildOnChildForChildParentFkeyUsingChildPkeyUpdate": "ChildOnChildForChildParentFkeyUsingChildPkeyUpdate", + "ChildOnGrandchildForGrandchildChildFkeyNodeIdUpdate": "ChildOnGrandchildForGrandchildChildFkeyNodeIdUpdate", + "ChildOnGrandchildForGrandchildChildFkeyUsingChildPkeyUpdate": "ChildOnGrandchildForGrandchildChildFkeyUsingChildPkeyUpdate", + "ChildParentFkeyChildCreateInput": "ChildParentFkeyChildCreateInput", + "ChildParentFkeyInput": "ChildParentFkeyInput", + "ChildParentFkeyInverseInput": "ChildParentFkeyInverseInput", + "ChildParentFkeyParentCreateInput": "ChildParentFkeyParentCreateInput", + "ChildPatch": "ChildPatch", + "ChildrenConnection": "ChildrenConnection", + "ChildrenEdge": "ChildrenEdge", + "ChildrenOrderBy": "ChildrenOrderBy", + "CreateChildInput": "CreateChildInput", + "CreateChildPayload": "CreateChildPayload", + "CreateGrandchildInput": "CreateGrandchildInput", + "CreateGrandchildPayload": "CreateGrandchildPayload", + "CreateParentInput": "CreateParentInput", + "CreateParentPayload": "CreateParentPayload", + "Cursor": "Cursor", + "DeleteChildByIdInput": "DeleteChildByIdInput", + "DeleteChildInput": "DeleteChildInput", + "DeleteChildPayload": "DeleteChildPayload", + "DeleteGrandchildByIdInput": "DeleteGrandchildByIdInput", + "DeleteGrandchildInput": "DeleteGrandchildInput", + "DeleteGrandchildPayload": "DeleteGrandchildPayload", + "DeleteParentByIdInput": "DeleteParentByIdInput", + "DeleteParentInput": "DeleteParentInput", + "DeleteParentPayload": "DeleteParentPayload", + "Grandchild": "Grandchild", + "GrandchildChildFkeyChildCreateInput": "GrandchildChildFkeyChildCreateInput", + "GrandchildChildFkeyGrandchildCreateInput": "GrandchildChildFkeyGrandchildCreateInput", + "GrandchildChildFkeyInput": "GrandchildChildFkeyInput", + "GrandchildChildFkeyInverseInput": "GrandchildChildFkeyInverseInput", + "GrandchildCondition": "GrandchildCondition", + "GrandchildGrandchildPkeyConnect": "GrandchildGrandchildPkeyConnect", + "GrandchildGrandchildPkeyDelete": "GrandchildGrandchildPkeyDelete", + "GrandchildInput": "GrandchildInput", + "GrandchildNodeIdConnect": "GrandchildNodeIdConnect", + "GrandchildNodeIdDelete": "GrandchildNodeIdDelete", + "GrandchildOnGrandchildForGrandchildChildFkeyNodeIdUpdate": "GrandchildOnGrandchildForGrandchildChildFkeyNodeIdUpdate", + "GrandchildOnGrandchildForGrandchildChildFkeyUsingGrandchildPkeyUpdate": "GrandchildOnGrandchildForGrandchildChildFkeyUsingGrandchildPkeyUpdate", + "GrandchildPatch": "GrandchildPatch", + "GrandchildrenConnection": "GrandchildrenConnection", + "GrandchildrenEdge": "GrandchildrenEdge", + "GrandchildrenOrderBy": "GrandchildrenOrderBy", + "ID": "ID", + "Int": "Int", + "Mutation": "Mutation", + "Node": "Node", + "PageInfo": "PageInfo", + "Parent": "Parent", + "ParentCondition": "ParentCondition", + "ParentInput": "ParentInput", + "ParentNodeIdConnect": "ParentNodeIdConnect", + "ParentNodeIdDelete": "ParentNodeIdDelete", + "ParentOnChildForChildParentFkeyNodeIdUpdate": "ParentOnChildForChildParentFkeyNodeIdUpdate", + "ParentOnChildForChildParentFkeyUsingParentPkeyUpdate": "ParentOnChildForChildParentFkeyUsingParentPkeyUpdate", + "ParentParentPkeyConnect": "ParentParentPkeyConnect", + "ParentParentPkeyDelete": "ParentParentPkeyDelete", + "ParentPatch": "ParentPatch", + "ParentsConnection": "ParentsConnection", + "ParentsEdge": "ParentsEdge", + "ParentsOrderBy": "ParentsOrderBy", + "Query": "Query", + "String": "String", + "UpdateChildByIdInput": "UpdateChildByIdInput", + "UpdateChildInput": "UpdateChildInput", + "UpdateChildPayload": "UpdateChildPayload", + "UpdateGrandchildByIdInput": "UpdateGrandchildByIdInput", + "UpdateGrandchildInput": "UpdateGrandchildInput", + "UpdateGrandchildPayload": "UpdateGrandchildPayload", + "UpdateParentByIdInput": "UpdateParentByIdInput", + "UpdateParentInput": "UpdateParentInput", + "UpdateParentPayload": "UpdateParentPayload", + "__Directive": "__Directive", + "__DirectiveLocation": "__DirectiveLocation", + "__EnumValue": "__EnumValue", + "__Field": "__Field", + "__InputValue": "__InputValue", + "__Schema": "__Schema", + "__Type": "__Type", + "__TypeKind": "__TypeKind", + "updateChildOnChildForChildParentFkeyPatch": "updateChildOnChildForChildParentFkeyPatch", + "updateChildOnGrandchildForGrandchildChildFkeyPatch": "updateChildOnGrandchildForGrandchildChildFkeyPatch", + "updateGrandchildOnGrandchildForGrandchildChildFkeyPatch": "updateGrandchildOnGrandchildForGrandchildChildFkeyPatch", + "updateParentOnChildForChildParentFkeyPatch": "updateParentOnChildForChildParentFkeyPatch", + }, + "astNode": undefined, + "description": undefined, + "extensionASTNodes": undefined, + "extensions": undefined, +} +`; + +exports[`forward deeply nested update mutation with nested updateById and create 1`] = ` +GraphQLSchema { + "__validationErrors": Array [], + "_directives": Array [ + "@include", + "@skip", + "@deprecated", + "@specifiedBy", + ], + "_implementationsMap": Object { + "Node": Object { + "interfaces": Array [], + "objects": Array [ + "Query", + "Child", + "Parent", + "Grandchild", + ], + }, + }, + "_mutationType": "Mutation", + "_queryType": "Query", + "_subTypeMap": Object {}, + "_subscriptionType": undefined, + "_typeMap": Object { + "Boolean": "Boolean", + "Child": "Child", + "ChildChildPkeyConnect": "ChildChildPkeyConnect", + "ChildChildPkeyDelete": "ChildChildPkeyDelete", + "ChildCondition": "ChildCondition", + "ChildInput": "ChildInput", + "ChildNodeIdConnect": "ChildNodeIdConnect", + "ChildNodeIdDelete": "ChildNodeIdDelete", + "ChildOnChildForChildParentFkeyNodeIdUpdate": "ChildOnChildForChildParentFkeyNodeIdUpdate", + "ChildOnChildForChildParentFkeyUsingChildPkeyUpdate": "ChildOnChildForChildParentFkeyUsingChildPkeyUpdate", + "ChildOnGrandchildForGrandchildChildFkeyNodeIdUpdate": "ChildOnGrandchildForGrandchildChildFkeyNodeIdUpdate", + "ChildOnGrandchildForGrandchildChildFkeyUsingChildPkeyUpdate": "ChildOnGrandchildForGrandchildChildFkeyUsingChildPkeyUpdate", + "ChildParentFkeyChildCreateInput": "ChildParentFkeyChildCreateInput", + "ChildParentFkeyInput": "ChildParentFkeyInput", + "ChildParentFkeyInverseInput": "ChildParentFkeyInverseInput", + "ChildParentFkeyParentCreateInput": "ChildParentFkeyParentCreateInput", + "ChildPatch": "ChildPatch", + "ChildrenConnection": "ChildrenConnection", + "ChildrenEdge": "ChildrenEdge", + "ChildrenOrderBy": "ChildrenOrderBy", + "CreateChildInput": "CreateChildInput", + "CreateChildPayload": "CreateChildPayload", + "CreateGrandchildInput": "CreateGrandchildInput", + "CreateGrandchildPayload": "CreateGrandchildPayload", + "CreateParentInput": "CreateParentInput", + "CreateParentPayload": "CreateParentPayload", + "Cursor": "Cursor", + "DeleteChildByIdInput": "DeleteChildByIdInput", + "DeleteChildInput": "DeleteChildInput", + "DeleteChildPayload": "DeleteChildPayload", + "DeleteGrandchildByIdInput": "DeleteGrandchildByIdInput", + "DeleteGrandchildInput": "DeleteGrandchildInput", + "DeleteGrandchildPayload": "DeleteGrandchildPayload", + "DeleteParentByIdInput": "DeleteParentByIdInput", + "DeleteParentInput": "DeleteParentInput", + "DeleteParentPayload": "DeleteParentPayload", + "Grandchild": "Grandchild", + "GrandchildChildFkeyChildCreateInput": "GrandchildChildFkeyChildCreateInput", + "GrandchildChildFkeyGrandchildCreateInput": "GrandchildChildFkeyGrandchildCreateInput", + "GrandchildChildFkeyInput": "GrandchildChildFkeyInput", + "GrandchildChildFkeyInverseInput": "GrandchildChildFkeyInverseInput", + "GrandchildCondition": "GrandchildCondition", + "GrandchildGrandchildPkeyConnect": "GrandchildGrandchildPkeyConnect", + "GrandchildGrandchildPkeyDelete": "GrandchildGrandchildPkeyDelete", + "GrandchildInput": "GrandchildInput", + "GrandchildNodeIdConnect": "GrandchildNodeIdConnect", + "GrandchildNodeIdDelete": "GrandchildNodeIdDelete", + "GrandchildOnGrandchildForGrandchildChildFkeyNodeIdUpdate": "GrandchildOnGrandchildForGrandchildChildFkeyNodeIdUpdate", + "GrandchildOnGrandchildForGrandchildChildFkeyUsingGrandchildPkeyUpdate": "GrandchildOnGrandchildForGrandchildChildFkeyUsingGrandchildPkeyUpdate", + "GrandchildPatch": "GrandchildPatch", + "GrandchildrenConnection": "GrandchildrenConnection", + "GrandchildrenEdge": "GrandchildrenEdge", + "GrandchildrenOrderBy": "GrandchildrenOrderBy", + "ID": "ID", + "Int": "Int", + "Mutation": "Mutation", + "Node": "Node", + "PageInfo": "PageInfo", + "Parent": "Parent", + "ParentCondition": "ParentCondition", + "ParentInput": "ParentInput", + "ParentNodeIdConnect": "ParentNodeIdConnect", + "ParentNodeIdDelete": "ParentNodeIdDelete", + "ParentOnChildForChildParentFkeyNodeIdUpdate": "ParentOnChildForChildParentFkeyNodeIdUpdate", + "ParentOnChildForChildParentFkeyUsingParentPkeyUpdate": "ParentOnChildForChildParentFkeyUsingParentPkeyUpdate", + "ParentParentPkeyConnect": "ParentParentPkeyConnect", + "ParentParentPkeyDelete": "ParentParentPkeyDelete", + "ParentPatch": "ParentPatch", + "ParentsConnection": "ParentsConnection", + "ParentsEdge": "ParentsEdge", + "ParentsOrderBy": "ParentsOrderBy", + "Query": "Query", + "String": "String", + "UpdateChildByIdInput": "UpdateChildByIdInput", + "UpdateChildInput": "UpdateChildInput", + "UpdateChildPayload": "UpdateChildPayload", + "UpdateGrandchildByIdInput": "UpdateGrandchildByIdInput", + "UpdateGrandchildInput": "UpdateGrandchildInput", + "UpdateGrandchildPayload": "UpdateGrandchildPayload", + "UpdateParentByIdInput": "UpdateParentByIdInput", + "UpdateParentInput": "UpdateParentInput", + "UpdateParentPayload": "UpdateParentPayload", + "__Directive": "__Directive", + "__DirectiveLocation": "__DirectiveLocation", + "__EnumValue": "__EnumValue", + "__Field": "__Field", + "__InputValue": "__InputValue", + "__Schema": "__Schema", + "__Type": "__Type", + "__TypeKind": "__TypeKind", + "updateChildOnChildForChildParentFkeyPatch": "updateChildOnChildForChildParentFkeyPatch", + "updateChildOnGrandchildForGrandchildChildFkeyPatch": "updateChildOnGrandchildForGrandchildChildFkeyPatch", + "updateGrandchildOnGrandchildForGrandchildChildFkeyPatch": "updateGrandchildOnGrandchildForGrandchildChildFkeyPatch", + "updateParentOnChildForChildParentFkeyPatch": "updateParentOnChildForChildParentFkeyPatch", + }, + "astNode": undefined, + "description": undefined, + "extensionASTNodes": undefined, + "extensions": undefined, +} +`; + +exports[`forward deeply nested update mutation with nested updateById and deleteById 1`] = ` +GraphQLSchema { + "__validationErrors": Array [], + "_directives": Array [ + "@include", + "@skip", + "@deprecated", + "@specifiedBy", + ], + "_implementationsMap": Object { + "Node": Object { + "interfaces": Array [], + "objects": Array [ + "Query", + "Child", + "Parent", + "Grandchild", + ], + }, + }, + "_mutationType": "Mutation", + "_queryType": "Query", + "_subTypeMap": Object {}, + "_subscriptionType": undefined, + "_typeMap": Object { + "Boolean": "Boolean", + "Child": "Child", + "ChildChildPkeyConnect": "ChildChildPkeyConnect", + "ChildChildPkeyDelete": "ChildChildPkeyDelete", + "ChildCondition": "ChildCondition", + "ChildInput": "ChildInput", + "ChildNodeIdConnect": "ChildNodeIdConnect", + "ChildNodeIdDelete": "ChildNodeIdDelete", + "ChildOnChildForChildParentFkeyNodeIdUpdate": "ChildOnChildForChildParentFkeyNodeIdUpdate", + "ChildOnChildForChildParentFkeyUsingChildPkeyUpdate": "ChildOnChildForChildParentFkeyUsingChildPkeyUpdate", + "ChildOnGrandchildForGrandchildChildFkeyNodeIdUpdate": "ChildOnGrandchildForGrandchildChildFkeyNodeIdUpdate", + "ChildOnGrandchildForGrandchildChildFkeyUsingChildPkeyUpdate": "ChildOnGrandchildForGrandchildChildFkeyUsingChildPkeyUpdate", + "ChildParentFkeyChildCreateInput": "ChildParentFkeyChildCreateInput", + "ChildParentFkeyInput": "ChildParentFkeyInput", + "ChildParentFkeyInverseInput": "ChildParentFkeyInverseInput", + "ChildParentFkeyParentCreateInput": "ChildParentFkeyParentCreateInput", + "ChildPatch": "ChildPatch", + "ChildrenConnection": "ChildrenConnection", + "ChildrenEdge": "ChildrenEdge", + "ChildrenOrderBy": "ChildrenOrderBy", + "CreateChildInput": "CreateChildInput", + "CreateChildPayload": "CreateChildPayload", + "CreateGrandchildInput": "CreateGrandchildInput", + "CreateGrandchildPayload": "CreateGrandchildPayload", + "CreateParentInput": "CreateParentInput", + "CreateParentPayload": "CreateParentPayload", + "Cursor": "Cursor", + "DeleteChildByIdInput": "DeleteChildByIdInput", + "DeleteChildInput": "DeleteChildInput", + "DeleteChildPayload": "DeleteChildPayload", + "DeleteGrandchildByIdInput": "DeleteGrandchildByIdInput", + "DeleteGrandchildInput": "DeleteGrandchildInput", + "DeleteGrandchildPayload": "DeleteGrandchildPayload", + "DeleteParentByIdInput": "DeleteParentByIdInput", + "DeleteParentInput": "DeleteParentInput", + "DeleteParentPayload": "DeleteParentPayload", + "Grandchild": "Grandchild", + "GrandchildChildFkeyChildCreateInput": "GrandchildChildFkeyChildCreateInput", + "GrandchildChildFkeyGrandchildCreateInput": "GrandchildChildFkeyGrandchildCreateInput", + "GrandchildChildFkeyInput": "GrandchildChildFkeyInput", + "GrandchildChildFkeyInverseInput": "GrandchildChildFkeyInverseInput", + "GrandchildCondition": "GrandchildCondition", + "GrandchildGrandchildPkeyConnect": "GrandchildGrandchildPkeyConnect", + "GrandchildGrandchildPkeyDelete": "GrandchildGrandchildPkeyDelete", + "GrandchildInput": "GrandchildInput", + "GrandchildNodeIdConnect": "GrandchildNodeIdConnect", + "GrandchildNodeIdDelete": "GrandchildNodeIdDelete", + "GrandchildOnGrandchildForGrandchildChildFkeyNodeIdUpdate": "GrandchildOnGrandchildForGrandchildChildFkeyNodeIdUpdate", + "GrandchildOnGrandchildForGrandchildChildFkeyUsingGrandchildPkeyUpdate": "GrandchildOnGrandchildForGrandchildChildFkeyUsingGrandchildPkeyUpdate", + "GrandchildPatch": "GrandchildPatch", + "GrandchildrenConnection": "GrandchildrenConnection", + "GrandchildrenEdge": "GrandchildrenEdge", + "GrandchildrenOrderBy": "GrandchildrenOrderBy", + "ID": "ID", + "Int": "Int", + "Mutation": "Mutation", + "Node": "Node", + "PageInfo": "PageInfo", + "Parent": "Parent", + "ParentCondition": "ParentCondition", + "ParentInput": "ParentInput", + "ParentNodeIdConnect": "ParentNodeIdConnect", + "ParentNodeIdDelete": "ParentNodeIdDelete", + "ParentOnChildForChildParentFkeyNodeIdUpdate": "ParentOnChildForChildParentFkeyNodeIdUpdate", + "ParentOnChildForChildParentFkeyUsingParentPkeyUpdate": "ParentOnChildForChildParentFkeyUsingParentPkeyUpdate", + "ParentParentPkeyConnect": "ParentParentPkeyConnect", + "ParentParentPkeyDelete": "ParentParentPkeyDelete", + "ParentPatch": "ParentPatch", + "ParentsConnection": "ParentsConnection", + "ParentsEdge": "ParentsEdge", + "ParentsOrderBy": "ParentsOrderBy", + "Query": "Query", + "String": "String", + "UpdateChildByIdInput": "UpdateChildByIdInput", + "UpdateChildInput": "UpdateChildInput", + "UpdateChildPayload": "UpdateChildPayload", + "UpdateGrandchildByIdInput": "UpdateGrandchildByIdInput", + "UpdateGrandchildInput": "UpdateGrandchildInput", + "UpdateGrandchildPayload": "UpdateGrandchildPayload", + "UpdateParentByIdInput": "UpdateParentByIdInput", + "UpdateParentInput": "UpdateParentInput", + "UpdateParentPayload": "UpdateParentPayload", + "__Directive": "__Directive", + "__DirectiveLocation": "__DirectiveLocation", + "__EnumValue": "__EnumValue", + "__Field": "__Field", + "__InputValue": "__InputValue", + "__Schema": "__Schema", + "__Type": "__Type", + "__TypeKind": "__TypeKind", + "updateChildOnChildForChildParentFkeyPatch": "updateChildOnChildForChildParentFkeyPatch", + "updateChildOnGrandchildForGrandchildChildFkeyPatch": "updateChildOnGrandchildForGrandchildChildFkeyPatch", + "updateGrandchildOnGrandchildForGrandchildChildFkeyPatch": "updateGrandchildOnGrandchildForGrandchildChildFkeyPatch", + "updateParentOnChildForChildParentFkeyPatch": "updateParentOnChildForChildParentFkeyPatch", + }, + "astNode": undefined, + "description": undefined, + "extensionASTNodes": undefined, + "extensions": undefined, +} +`; + exports[`forward nested mutation during update 1`] = ` GraphQLSchema { "__validationErrors": Array [], @@ -1134,6 +1769,260 @@ GraphQLSchema { } `; +exports[`reverse deeply nested mutation with nested updateById 1`] = ` +GraphQLSchema { + "__validationErrors": Array [], + "_directives": Array [ + "@include", + "@skip", + "@deprecated", + "@specifiedBy", + ], + "_implementationsMap": Object { + "Node": Object { + "interfaces": Array [], + "objects": Array [ + "Query", + "Child", + "Parent", + "Grandchild", + ], + }, + }, + "_mutationType": "Mutation", + "_queryType": "Query", + "_subTypeMap": Object {}, + "_subscriptionType": undefined, + "_typeMap": Object { + "Boolean": "Boolean", + "Child": "Child", + "ChildChildPkeyConnect": "ChildChildPkeyConnect", + "ChildChildPkeyDelete": "ChildChildPkeyDelete", + "ChildCondition": "ChildCondition", + "ChildInput": "ChildInput", + "ChildNodeIdConnect": "ChildNodeIdConnect", + "ChildNodeIdDelete": "ChildNodeIdDelete", + "ChildOnChildForChildParentFkeyNodeIdUpdate": "ChildOnChildForChildParentFkeyNodeIdUpdate", + "ChildOnChildForChildParentFkeyUsingChildPkeyUpdate": "ChildOnChildForChildParentFkeyUsingChildPkeyUpdate", + "ChildOnGrandchildForGrandchildChildFkeyNodeIdUpdate": "ChildOnGrandchildForGrandchildChildFkeyNodeIdUpdate", + "ChildOnGrandchildForGrandchildChildFkeyUsingChildPkeyUpdate": "ChildOnGrandchildForGrandchildChildFkeyUsingChildPkeyUpdate", + "ChildParentFkeyChildCreateInput": "ChildParentFkeyChildCreateInput", + "ChildParentFkeyInput": "ChildParentFkeyInput", + "ChildParentFkeyInverseInput": "ChildParentFkeyInverseInput", + "ChildParentFkeyParentCreateInput": "ChildParentFkeyParentCreateInput", + "ChildPatch": "ChildPatch", + "ChildrenConnection": "ChildrenConnection", + "ChildrenEdge": "ChildrenEdge", + "ChildrenOrderBy": "ChildrenOrderBy", + "CreateChildInput": "CreateChildInput", + "CreateChildPayload": "CreateChildPayload", + "CreateGrandchildInput": "CreateGrandchildInput", + "CreateGrandchildPayload": "CreateGrandchildPayload", + "CreateParentInput": "CreateParentInput", + "CreateParentPayload": "CreateParentPayload", + "Cursor": "Cursor", + "DeleteChildByIdInput": "DeleteChildByIdInput", + "DeleteChildInput": "DeleteChildInput", + "DeleteChildPayload": "DeleteChildPayload", + "DeleteGrandchildByIdInput": "DeleteGrandchildByIdInput", + "DeleteGrandchildInput": "DeleteGrandchildInput", + "DeleteGrandchildPayload": "DeleteGrandchildPayload", + "DeleteParentByIdInput": "DeleteParentByIdInput", + "DeleteParentInput": "DeleteParentInput", + "DeleteParentPayload": "DeleteParentPayload", + "Grandchild": "Grandchild", + "GrandchildChildFkeyChildCreateInput": "GrandchildChildFkeyChildCreateInput", + "GrandchildChildFkeyGrandchildCreateInput": "GrandchildChildFkeyGrandchildCreateInput", + "GrandchildChildFkeyInput": "GrandchildChildFkeyInput", + "GrandchildChildFkeyInverseInput": "GrandchildChildFkeyInverseInput", + "GrandchildCondition": "GrandchildCondition", + "GrandchildGrandchildPkeyConnect": "GrandchildGrandchildPkeyConnect", + "GrandchildGrandchildPkeyDelete": "GrandchildGrandchildPkeyDelete", + "GrandchildInput": "GrandchildInput", + "GrandchildNodeIdConnect": "GrandchildNodeIdConnect", + "GrandchildNodeIdDelete": "GrandchildNodeIdDelete", + "GrandchildOnGrandchildForGrandchildChildFkeyNodeIdUpdate": "GrandchildOnGrandchildForGrandchildChildFkeyNodeIdUpdate", + "GrandchildOnGrandchildForGrandchildChildFkeyUsingGrandchildPkeyUpdate": "GrandchildOnGrandchildForGrandchildChildFkeyUsingGrandchildPkeyUpdate", + "GrandchildPatch": "GrandchildPatch", + "GrandchildrenConnection": "GrandchildrenConnection", + "GrandchildrenEdge": "GrandchildrenEdge", + "GrandchildrenOrderBy": "GrandchildrenOrderBy", + "ID": "ID", + "Int": "Int", + "Mutation": "Mutation", + "Node": "Node", + "PageInfo": "PageInfo", + "Parent": "Parent", + "ParentCondition": "ParentCondition", + "ParentInput": "ParentInput", + "ParentNodeIdConnect": "ParentNodeIdConnect", + "ParentNodeIdDelete": "ParentNodeIdDelete", + "ParentOnChildForChildParentFkeyNodeIdUpdate": "ParentOnChildForChildParentFkeyNodeIdUpdate", + "ParentOnChildForChildParentFkeyUsingParentPkeyUpdate": "ParentOnChildForChildParentFkeyUsingParentPkeyUpdate", + "ParentParentPkeyConnect": "ParentParentPkeyConnect", + "ParentParentPkeyDelete": "ParentParentPkeyDelete", + "ParentPatch": "ParentPatch", + "ParentsConnection": "ParentsConnection", + "ParentsEdge": "ParentsEdge", + "ParentsOrderBy": "ParentsOrderBy", + "Query": "Query", + "String": "String", + "UpdateChildByIdInput": "UpdateChildByIdInput", + "UpdateChildInput": "UpdateChildInput", + "UpdateChildPayload": "UpdateChildPayload", + "UpdateGrandchildByIdInput": "UpdateGrandchildByIdInput", + "UpdateGrandchildInput": "UpdateGrandchildInput", + "UpdateGrandchildPayload": "UpdateGrandchildPayload", + "UpdateParentByIdInput": "UpdateParentByIdInput", + "UpdateParentInput": "UpdateParentInput", + "UpdateParentPayload": "UpdateParentPayload", + "__Directive": "__Directive", + "__DirectiveLocation": "__DirectiveLocation", + "__EnumValue": "__EnumValue", + "__Field": "__Field", + "__InputValue": "__InputValue", + "__Schema": "__Schema", + "__Type": "__Type", + "__TypeKind": "__TypeKind", + "updateChildOnChildForChildParentFkeyPatch": "updateChildOnChildForChildParentFkeyPatch", + "updateChildOnGrandchildForGrandchildChildFkeyPatch": "updateChildOnGrandchildForGrandchildChildFkeyPatch", + "updateGrandchildOnGrandchildForGrandchildChildFkeyPatch": "updateGrandchildOnGrandchildForGrandchildChildFkeyPatch", + "updateParentOnChildForChildParentFkeyPatch": "updateParentOnChildForChildParentFkeyPatch", + }, + "astNode": undefined, + "description": undefined, + "extensionASTNodes": undefined, + "extensions": undefined, +} +`; + +exports[`reverse deeply nested mutation with nested updateByNodeId 1`] = ` +GraphQLSchema { + "__validationErrors": Array [], + "_directives": Array [ + "@include", + "@skip", + "@deprecated", + "@specifiedBy", + ], + "_implementationsMap": Object { + "Node": Object { + "interfaces": Array [], + "objects": Array [ + "Query", + "Child", + "Parent", + "Grandchild", + ], + }, + }, + "_mutationType": "Mutation", + "_queryType": "Query", + "_subTypeMap": Object {}, + "_subscriptionType": undefined, + "_typeMap": Object { + "Boolean": "Boolean", + "Child": "Child", + "ChildChildPkeyConnect": "ChildChildPkeyConnect", + "ChildChildPkeyDelete": "ChildChildPkeyDelete", + "ChildCondition": "ChildCondition", + "ChildInput": "ChildInput", + "ChildNodeIdConnect": "ChildNodeIdConnect", + "ChildNodeIdDelete": "ChildNodeIdDelete", + "ChildOnChildForChildParentFkeyNodeIdUpdate": "ChildOnChildForChildParentFkeyNodeIdUpdate", + "ChildOnChildForChildParentFkeyUsingChildPkeyUpdate": "ChildOnChildForChildParentFkeyUsingChildPkeyUpdate", + "ChildOnGrandchildForGrandchildChildFkeyNodeIdUpdate": "ChildOnGrandchildForGrandchildChildFkeyNodeIdUpdate", + "ChildOnGrandchildForGrandchildChildFkeyUsingChildPkeyUpdate": "ChildOnGrandchildForGrandchildChildFkeyUsingChildPkeyUpdate", + "ChildParentFkeyChildCreateInput": "ChildParentFkeyChildCreateInput", + "ChildParentFkeyInput": "ChildParentFkeyInput", + "ChildParentFkeyInverseInput": "ChildParentFkeyInverseInput", + "ChildParentFkeyParentCreateInput": "ChildParentFkeyParentCreateInput", + "ChildPatch": "ChildPatch", + "ChildrenConnection": "ChildrenConnection", + "ChildrenEdge": "ChildrenEdge", + "ChildrenOrderBy": "ChildrenOrderBy", + "CreateChildInput": "CreateChildInput", + "CreateChildPayload": "CreateChildPayload", + "CreateGrandchildInput": "CreateGrandchildInput", + "CreateGrandchildPayload": "CreateGrandchildPayload", + "CreateParentInput": "CreateParentInput", + "CreateParentPayload": "CreateParentPayload", + "Cursor": "Cursor", + "DeleteChildByIdInput": "DeleteChildByIdInput", + "DeleteChildInput": "DeleteChildInput", + "DeleteChildPayload": "DeleteChildPayload", + "DeleteGrandchildByIdInput": "DeleteGrandchildByIdInput", + "DeleteGrandchildInput": "DeleteGrandchildInput", + "DeleteGrandchildPayload": "DeleteGrandchildPayload", + "DeleteParentByIdInput": "DeleteParentByIdInput", + "DeleteParentInput": "DeleteParentInput", + "DeleteParentPayload": "DeleteParentPayload", + "Grandchild": "Grandchild", + "GrandchildChildFkeyChildCreateInput": "GrandchildChildFkeyChildCreateInput", + "GrandchildChildFkeyGrandchildCreateInput": "GrandchildChildFkeyGrandchildCreateInput", + "GrandchildChildFkeyInput": "GrandchildChildFkeyInput", + "GrandchildChildFkeyInverseInput": "GrandchildChildFkeyInverseInput", + "GrandchildCondition": "GrandchildCondition", + "GrandchildGrandchildPkeyConnect": "GrandchildGrandchildPkeyConnect", + "GrandchildGrandchildPkeyDelete": "GrandchildGrandchildPkeyDelete", + "GrandchildInput": "GrandchildInput", + "GrandchildNodeIdConnect": "GrandchildNodeIdConnect", + "GrandchildNodeIdDelete": "GrandchildNodeIdDelete", + "GrandchildOnGrandchildForGrandchildChildFkeyNodeIdUpdate": "GrandchildOnGrandchildForGrandchildChildFkeyNodeIdUpdate", + "GrandchildOnGrandchildForGrandchildChildFkeyUsingGrandchildPkeyUpdate": "GrandchildOnGrandchildForGrandchildChildFkeyUsingGrandchildPkeyUpdate", + "GrandchildPatch": "GrandchildPatch", + "GrandchildrenConnection": "GrandchildrenConnection", + "GrandchildrenEdge": "GrandchildrenEdge", + "GrandchildrenOrderBy": "GrandchildrenOrderBy", + "ID": "ID", + "Int": "Int", + "Mutation": "Mutation", + "Node": "Node", + "PageInfo": "PageInfo", + "Parent": "Parent", + "ParentCondition": "ParentCondition", + "ParentInput": "ParentInput", + "ParentNodeIdConnect": "ParentNodeIdConnect", + "ParentNodeIdDelete": "ParentNodeIdDelete", + "ParentOnChildForChildParentFkeyNodeIdUpdate": "ParentOnChildForChildParentFkeyNodeIdUpdate", + "ParentOnChildForChildParentFkeyUsingParentPkeyUpdate": "ParentOnChildForChildParentFkeyUsingParentPkeyUpdate", + "ParentParentPkeyConnect": "ParentParentPkeyConnect", + "ParentParentPkeyDelete": "ParentParentPkeyDelete", + "ParentPatch": "ParentPatch", + "ParentsConnection": "ParentsConnection", + "ParentsEdge": "ParentsEdge", + "ParentsOrderBy": "ParentsOrderBy", + "Query": "Query", + "String": "String", + "UpdateChildByIdInput": "UpdateChildByIdInput", + "UpdateChildInput": "UpdateChildInput", + "UpdateChildPayload": "UpdateChildPayload", + "UpdateGrandchildByIdInput": "UpdateGrandchildByIdInput", + "UpdateGrandchildInput": "UpdateGrandchildInput", + "UpdateGrandchildPayload": "UpdateGrandchildPayload", + "UpdateParentByIdInput": "UpdateParentByIdInput", + "UpdateParentInput": "UpdateParentInput", + "UpdateParentPayload": "UpdateParentPayload", + "__Directive": "__Directive", + "__DirectiveLocation": "__DirectiveLocation", + "__EnumValue": "__EnumValue", + "__Field": "__Field", + "__InputValue": "__InputValue", + "__Schema": "__Schema", + "__Type": "__Type", + "__TypeKind": "__TypeKind", + "updateChildOnChildForChildParentFkeyPatch": "updateChildOnChildForChildParentFkeyPatch", + "updateChildOnGrandchildForGrandchildChildFkeyPatch": "updateChildOnGrandchildForGrandchildChildFkeyPatch", + "updateGrandchildOnGrandchildForGrandchildChildFkeyPatch": "updateGrandchildOnGrandchildForGrandchildChildFkeyPatch", + "updateParentOnChildForChildParentFkeyPatch": "updateParentOnChildForChildParentFkeyPatch", + }, + "astNode": undefined, + "description": undefined, + "extensionASTNodes": undefined, + "extensions": undefined, +} +`; + exports[`reverse nested mutation with nested update 1`] = ` GraphQLSchema { "__validationErrors": Array [], diff --git a/__tests__/integration/update.test.js b/__tests__/integration/update.test.js index c8949ca..3c065fe 100644 --- a/__tests__/integration/update.test.js +++ b/__tests__/integration/update.test.js @@ -130,8 +130,11 @@ test( data.childrenByParentId.nodes.map((n) => expect(n.parentId).toBe(data.id), ); - expect(data.childrenByParentId.nodes.map(n => n.id)) - .toEqual([95, 98, 99]); + expect(data.childrenByParentId.nodes.map((n) => n.id)).toEqual([ + 95, + 98, + 99, + ]); }, }), ); @@ -279,8 +282,12 @@ test( data.childrenByParentId.nodes.map((n) => expect(n.parentId).toBe(data.id), ); - expect(data.childrenByParentId.nodes.map(n => n.id)) - .toEqual([95, 97, 98, 99]); + expect(data.childrenByParentId.nodes.map((n) => n.id)).toEqual([ + 95, + 97, + 98, + 99, + ]); }, }), ); @@ -358,8 +365,9 @@ test( const result = await graphql(schema, query, null, { pgClient }); expect(result).toHaveProperty('errors'); - expect(result.errors[0].message) - .toMatch(/"deleteByNodeId" is not defined/); + expect(result.errors[0].message).toMatch( + /"deleteByNodeId" is not defined/, + ); }, }), ); @@ -1082,3 +1090,760 @@ test( }, }), ); + +test( + 'forward deeply nested update mutation with nested updateById and create', + withSchema({ + setup: ` + create table p.parent ( + id serial primary key, + name text not null + ); + + create table p.child ( + id serial primary key, + parent_id integer, + name text not null, + constraint child_parent_fkey foreign key (parent_id) + references p.parent (id) + ); + + create table p.grandchild ( + id serial primary key, + child_id integer not null, + name text not null, + constraint grandchild_child_fkey foreign key (child_id) + references p.child (id) + ); + + insert into p.parent values(1, 'test parent'); + insert into p.child values(1, 1, 'test child 1'); + `, + test: async ({ schema, pgClient }) => { + const query = ` + mutation { + updateParentById( + input: { + id: 1 + parentPatch: { + name: "updated parent" + childrenUsingId: { + updateById: { + id: 1 + childPatch: { + name: "updated child 1" + grandchildrenUsingId: { + create: [{ name: "grandchild 1 of child 1" }] + } + } + } + } + } + } + ) { + parent { + id + name + childrenByParentId { + nodes { + id + parentId + name + grandchildrenByChildId { + nodes { + id + childId + name + } + } + } + } + } + } + } + `; + expect(schema).toMatchSnapshot(); + + const result = await graphql(schema, query, null, { pgClient }); + expect(result).not.toHaveProperty('errors'); + + const { data } = result; + + expect(data.updateParentById.parent.name).toEqual('updated parent'); + data.updateParentById.parent.childrenByParentId.nodes.map((n) => + expect(n.parentId).toBe(data.updateParentById.parent.id), + ); + + expect( + data.updateParentById.parent.childrenByParentId.nodes, + ).toHaveLength(1); + expect( + data.updateParentById.parent.childrenByParentId.nodes[0].name, + ).toEqual('updated child 1'); + + expect( + data.updateParentById.parent.childrenByParentId.nodes[0] + .grandchildrenByChildId.nodes, + ).toHaveLength(1); + expect( + data.updateParentById.parent.childrenByParentId.nodes[0] + .grandchildrenByChildId.nodes[0].name, + ).toEqual('grandchild 1 of child 1'); + }, + }), +); + +test( + 'forward deeply nested update mutation with nested updateById', + withSchema({ + setup: ` + create table p.parent ( + id serial primary key, + name text not null + ); + + create table p.child ( + id serial primary key, + parent_id integer, + name text not null, + constraint child_parent_fkey foreign key (parent_id) + references p.parent (id) + ); + + create table p.grandchild ( + id serial primary key, + child_id integer not null, + name text not null, + constraint grandchild_child_fkey foreign key (child_id) + references p.child (id) + ); + + insert into p.parent values(1, 'test parent'); + insert into p.child values(1, 1, 'test child 1'); + insert into p.grandchild values(1, 1, 'test grandchild 1'); + `, + test: async ({ schema, pgClient }) => { + const query = ` + mutation { + updateParentById( + input: { + id: 1 + parentPatch: { + name: "updated parent" + childrenUsingId: { + updateById: { + id: 1 + childPatch: { + name: "updated child 1" + grandchildrenUsingId: { + updateById: { + id: 1 + grandchildPatch: { + name: "updated grandchild 1 of child 1" + } + } + } + } + } + } + } + } + ) { + parent { + id + name + childrenByParentId { + nodes { + id + parentId + name + grandchildrenByChildId { + nodes { + id + childId + name + } + } + } + } + } + } + } + `; + expect(schema).toMatchSnapshot(); + + const result = await graphql(schema, query, null, { pgClient }); + expect(result).not.toHaveProperty('errors'); + + const { data } = result; + + expect(data.updateParentById.parent.name).toEqual(`updated parent`); + data.updateParentById.parent.childrenByParentId.nodes.map((n) => + expect(n.parentId).toBe(data.updateParentById.parent.id), + ); + + expect( + data.updateParentById.parent.childrenByParentId.nodes, + ).toHaveLength(1); + expect( + data.updateParentById.parent.childrenByParentId.nodes[0].name, + ).toEqual('updated child 1'); + + expect( + data.updateParentById.parent.childrenByParentId.nodes[0] + .grandchildrenByChildId.nodes, + ).toHaveLength(1); + expect( + data.updateParentById.parent.childrenByParentId.nodes[0] + .grandchildrenByChildId.nodes[0].name, + ).toEqual('updated grandchild 1 of child 1'); + }, + }), +); + +test( + 'forward deeply nested update mutation with nested updateById and connectById', + withSchema({ + setup: ` + create table p.parent ( + id serial primary key, + name text not null + ); + + create table p.child ( + id serial primary key, + parent_id integer, + name text not null, + constraint child_parent_fkey foreign key (parent_id) + references p.parent (id) + ); + + create table p.grandchild ( + id serial primary key, + child_id integer not null, + name text not null, + constraint grandchild_child_fkey foreign key (child_id) + references p.child (id) + ); + + insert into p.parent values(1, 'test parent'); + insert into p.child values(1, 1, 'test child 1'); + insert into p.child values(2, 1, 'test child 2'); + insert into p.grandchild values(1, 1, 'test grandchild 1'); + `, + test: async ({ schema, pgClient }) => { + const query = ` + mutation { + updateParentById( + input: { + id: 1 + parentPatch: { + name: "updated parent" + childrenUsingId: { + updateById: { + id: 1 + childPatch: { + name: "updated child 1" + grandchildrenUsingId: { + updateById: { + id: 1 + grandchildPatch: { + childToChildId: { + connectById: { id: 2 } + } + name: "changed parent of grandchild 1" + } + } + } + } + } + } + } + } + ) { + parent { + id + name + childrenByParentId { + nodes { + id + parentId + name + grandchildrenByChildId { + nodes { + id + childId + name + } + } + } + } + } + } + } + `; + expect(schema).toMatchSnapshot(); + + const result = await graphql(schema, query, null, { pgClient }); + expect(result).not.toHaveProperty('errors'); + + const { data } = result; + + expect(data.updateParentById.parent.name).toEqual(`updated parent`); + data.updateParentById.parent.childrenByParentId.nodes.map((n) => + expect(n.parentId).toBe(data.updateParentById.parent.id), + ); + + expect( + data.updateParentById.parent.childrenByParentId.nodes, + ).toHaveLength(2); + expect( + data.updateParentById.parent.childrenByParentId.nodes[0].name, + ).toEqual('updated child 1'); + expect( + data.updateParentById.parent.childrenByParentId.nodes[1].name, + ).toEqual('test child 2'); + + expect( + data.updateParentById.parent.childrenByParentId.nodes[1] + .grandchildrenByChildId.nodes, + ).toHaveLength(1); + expect( + data.updateParentById.parent.childrenByParentId.nodes[1] + .grandchildrenByChildId.nodes[0].childId, + ).toEqual(2); + expect( + data.updateParentById.parent.childrenByParentId.nodes[1] + .grandchildrenByChildId.nodes[0].name, + ).toEqual('changed parent of grandchild 1'); + }, + }), +); + +test( + 'forward deeply nested update mutation with nested updateById and deleteById', + withSchema({ + setup: ` + create table p.parent ( + id serial primary key, + name text not null + ); + + create table p.child ( + id serial primary key, + parent_id integer, + name text not null, + constraint child_parent_fkey foreign key (parent_id) + references p.parent (id) + ); + + create table p.grandchild ( + id serial primary key, + child_id integer not null, + name text not null, + constraint grandchild_child_fkey foreign key (child_id) + references p.child (id) + ); + + insert into p.parent values(1, 'test parent'); + insert into p.child values(1, 1, 'test child 1'); + insert into p.child values(2, 1, 'test child 2'); + insert into p.grandchild values(1, 1, 'test grandchild 1'); + `, + test: async ({ schema, pgClient }) => { + const query = ` + mutation { + updateParentById( + input: { + id: 1 + parentPatch: { + name: "updated parent" + childrenUsingId: { + updateById: { + id: 1 + childPatch: { + name: "updated child 1" + grandchildrenUsingId: { + deleteById: { + id: 1 + } + } + } + } + } + } + } + ) { + parent { + id + name + childrenByParentId { + nodes { + id + parentId + name + grandchildrenByChildId { + nodes { + id + childId + name + } + } + } + } + } + } + } + `; + expect(schema).toMatchSnapshot(); + + const result = await graphql(schema, query, null, { pgClient }); + expect(result).not.toHaveProperty('errors'); + + const { data } = result; + + expect(data.updateParentById.parent.name).toEqual(`updated parent`); + data.updateParentById.parent.childrenByParentId.nodes.map((n) => + expect(n.parentId).toBe(data.updateParentById.parent.id), + ); + + expect( + data.updateParentById.parent.childrenByParentId.nodes, + ).toHaveLength(2); + expect( + data.updateParentById.parent.childrenByParentId.nodes[0].name, + ).toEqual('updated child 1'); + expect( + data.updateParentById.parent.childrenByParentId.nodes[1].name, + ).toEqual('test child 2'); + + expect( + data.updateParentById.parent.childrenByParentId.nodes[1] + .grandchildrenByChildId.nodes, + ).toHaveLength(0); + }, + }), +); + +test( + 'forward deeply nested mutation with nested updateByNodeId', + withSchema({ + setup: ` + create table p.parent ( + id serial primary key, + name text not null + ); + + create table p.child ( + id serial primary key, + parent_id integer, + name text not null, + constraint child_parent_fkey foreign key (parent_id) + references p.parent (id) + ); + + create table p.grandchild ( + id serial primary key, + child_id integer not null, + name text not null, + constraint grandchild_child_fkey foreign key (child_id) + references p.child (id) + ); + + insert into p.parent values(1, 'test parent'); + insert into p.child values(1, 1, 'test child'); + insert into p.grandchild values(1, 1, 'test grandchild'); + `, + test: async ({ schema, pgClient }) => { + const lookupChildQuery = ` + query { + childById(id: 1) { + nodeId + } + } + `; + const lookupChildResult = await graphql(schema, lookupChildQuery, null, { + pgClient, + }); + const { nodeId: childNodeId } = lookupChildResult.data.childById; + expect(childNodeId).not.toBeUndefined(); + + const lookupGrandchildQuery = ` + query { + grandchildById(id: 1) { + nodeId + } + } + `; + const lookupGrandchildResult = await graphql( + schema, + lookupGrandchildQuery, + null, + { + pgClient, + }, + ); + const { + nodeId: grandchildNodeId, + } = lookupGrandchildResult.data.grandchildById; + expect(grandchildNodeId).not.toBeUndefined(); + + const query = ` + mutation { + updateParentById( + input: { + id: 1 + parentPatch: { + childrenUsingId: { + updateByNodeId: { + nodeId: "${childNodeId}" + childPatch: { + name: "renamed child" + grandchildrenUsingId: { + updateByNodeId: { + nodeId: "${grandchildNodeId}" + grandchildPatch: { + name: "renamed grandchild" + } + } + } + } + } + } + } + } + ) { + parent { + id + name + childrenByParentId { + nodes { + id + parentId + name + grandchildrenByChildId { + nodes { + id + childId + name + } + } + } + } + } + } + } + `; + expect(schema).toMatchSnapshot(); + + const result = await graphql(schema, query, null, { pgClient }); + expect(result).not.toHaveProperty('errors'); + + const childData = result.data.updateParentById.parent; + expect(childData.childrenByParentId.nodes).toHaveLength(1); + childData.childrenByParentId.nodes.map((n) => + expect(n.parentId).toBe(childData.id), + ); + expect(childData.childrenByParentId.nodes[0].name).toEqual( + 'renamed child', + ); + + const grandchildData = childData.childrenByParentId.nodes[0]; + expect(grandchildData.grandchildrenByChildId.nodes).toHaveLength(1); + grandchildData.grandchildrenByChildId.nodes.map((n) => + expect(n.childId).toBe(grandchildData.id), + ); + expect(grandchildData.grandchildrenByChildId.nodes[0].name).toEqual( + 'renamed grandchild', + ); + }, + }), +); + +test( + 'reverse deeply nested mutation with nested updateById', + withSchema({ + setup: ` + create table p.parent ( + id serial primary key, + name text not null + ); + + create table p.child ( + id serial primary key, + parent_id integer, + name text not null, + constraint child_parent_fkey foreign key (parent_id) + references p.parent (id) + ); + + create table p.grandchild ( + id serial primary key, + child_id integer not null, + name text not null, + constraint grandchild_child_fkey foreign key (child_id) + references p.child (id) + ); + + insert into p.parent values(1, 'test parent'); + insert into p.child values(1, 1, 'test child'); + insert into p.grandchild values(1, 1, 'test grandchild'); + `, + test: async ({ schema, pgClient }) => { + const query = ` + mutation { + updateGrandchildById( + input: { + id: 1 + grandchildPatch: { + childToChildId: { + updateById: { + id: 1 + childPatch: { + parentToParentId: { + updateById: { id: 1, parentPatch: { name: "renamed parent" } } + } + } + } + } + } + } + ) { + grandchild { + id + name + childByChildId { + id + name + parentByParentId { + id + name + } + } + } + } + } + `; + expect(schema).toMatchSnapshot(); + + const result = await graphql(schema, query, null, { pgClient }); + expect(result).not.toHaveProperty('errors'); + + const child = result.data.updateGrandchildById.grandchild.childByChildId; + expect(child.parentByParentId).not.toBeNull(); + expect(child.parentByParentId.name).toEqual('renamed parent'); + }, + }), +); + +test( + 'reverse deeply nested mutation with nested updateByNodeId', + withSchema({ + setup: ` + create table p.parent ( + id serial primary key, + name text not null + ); + + create table p.child ( + id serial primary key, + parent_id integer, + name text not null, + constraint child_parent_fkey foreign key (parent_id) + references p.parent (id) + ); + + create table p.grandchild ( + id serial primary key, + child_id integer not null, + name text not null, + constraint grandchild_child_fkey foreign key (child_id) + references p.child (id) + ); + + insert into p.parent values(1, 'test parent'); + insert into p.child values(1, 1, 'test child'); + insert into p.grandchild values(1, 1, 'test grandchild'); + `, + test: async ({ schema, pgClient }) => { + const lookupParentQuery = ` + query { + parentById(id: 1) { + nodeId + } + } + `; + const lookupParentResult = await graphql( + schema, + lookupParentQuery, + null, + { + pgClient, + }, + ); + const { nodeId: parentNodeId } = lookupParentResult.data.parentById; + expect(parentNodeId).not.toBeUndefined(); + + const lookupChildQuery = ` + query { + childById(id: 1) { + nodeId + } + } + `; + const lookupChildResult = await graphql(schema, lookupChildQuery, null, { + pgClient, + }); + const { nodeId: childNodeId } = lookupChildResult.data.childById; + expect(childNodeId).not.toBeUndefined(); + + const query = ` + mutation { + updateGrandchildById( + input: { + id: 1 + grandchildPatch: { + childToChildId: { + updateByNodeId: { + nodeId: "${childNodeId}" + childPatch: { + parentToParentId: { + updateByNodeId: { + nodeId: "${parentNodeId}" + parentPatch: { + name: "renamed parent" + } + } + } + } + } + } + } + } + ) { + grandchild { + id + name + childByChildId { + id + name + parentByParentId { + id + name + } + } + } + } + } + `; + expect(schema).toMatchSnapshot(); + + const result = await graphql(schema, query, null, { pgClient }); + expect(result).not.toHaveProperty('errors'); + + const child = result.data.updateGrandchildById.grandchild.childByChildId; + expect(child.parentByParentId).not.toBeNull(); + expect(child.parentByParentId.name).toEqual('renamed parent'); + }, + }), +); diff --git a/src/PostgraphileNestedMutationsPlugin.js b/src/PostgraphileNestedMutationsPlugin.js index 8695d72..11661f6 100644 --- a/src/PostgraphileNestedMutationsPlugin.js +++ b/src/PostgraphileNestedMutationsPlugin.js @@ -82,7 +82,6 @@ module.exports = function PostGraphileNestedMutationPlugin(builder) { scope: { isPgCreateMutationField, isPgUpdateMutationField, - isPgNodeMutation, pgFieldIntrospection: table, pgFieldConstraint, }, @@ -142,6 +141,41 @@ module.exports = function PostGraphileNestedMutationPlugin(builder) { } = nestedField; const fieldValue = input[fieldName]; + if (fieldValue.updateById || fieldValue.updateByNodeId) { + await Promise.all( + Object.keys(fieldValue).map(async (k) => { + (Array.isArray(fieldValue[k]) + ? fieldValue[k] + : [fieldValue[k]] + ).map(async (rowData) => { + const updateData = Object.assign( + {}, + rowData, + await recurseForwardNestedMutations( + data, + { input: rowData }, + { pgClient }, + resolveInfo, + ), + ); + + const resolver = pgNestedUpdateResolvers[foreignTable.id]; + const resolveResult = await resolver( + data, + { input: updateData }, + { pgClient }, + resolveInfo, + ); + + foreignKeys.forEach((pk, idx) => { + output[inflection.column(keys[idx])] = + resolveResult.data[`__pk__${pk.name}`]; + }); + }); + }), + ); + } + await Promise.all( pgNestedTableConnectorFields[foreignTable.id] .filter((f) => fieldValue[f.fieldName]) @@ -233,43 +267,18 @@ module.exports = function PostGraphileNestedMutationPlugin(builder) { resolveResult.data[`__pk__${k.name}`]; }); } - - await Promise.all(Object.keys(fieldValue).map(async k => { - if (k.includes('updateBy')) { - (Array.isArray(fieldValue[k]) ? fieldValue[k] : [fieldValue[k]]).map(async (rowData) => { - const resolver = pgNestedUpdateResolvers[foreignTable.id]; - - const updateData = Object.assign( - {}, - rowData, - await recurseForwardNestedMutations( - data, - { input: rowData }, - { pgClient }, - resolveInfo, - ), - ); - - const resolveResult = await resolver( - data, - { input: updateData }, - { pgClient }, - resolveInfo, - ); - foreignKeys.forEach((k, idx) => { - output[inflection.column(keys[idx])] = - resolveResult.data[`__pk__${k.name}`]; - }); - }); - } - })) }), ); return output; }; - const newResolver = async (data, { input }, { pgClient }, resolveInfo) => { + const mutationResolver = async ( + data, + { input }, + { pgClient }, + resolveInfo, + ) => { const PayloadType = getTypeByName( isPgUpdateMutationField ? inflection.updatePayloadType(table) @@ -328,19 +337,20 @@ module.exports = function PostGraphileNestedMutationPlugin(builder) { /* eslint indent: 0 */ mutationQuery = sql.query` insert into ${sql.identifier(table.namespace.name, table.name)} - ${sqlColumns.length - ? sql.fragment`( + ${ + sqlColumns.length + ? sql.fragment`( ${sql.join(sqlColumns, ', ')} ) values(${sql.join(sqlValues, ', ')})` - : sql.fragment`default values` - } returning *`; + : sql.fragment`default values` + } returning *`; } else if (isPgUpdateMutationField) { const sqlColumns = []; const sqlValues = []; let condition = null; + const nodeId = input[nodeIdFieldName]; - if (isPgNodeMutation) { - const nodeId = input[nodeIdFieldName]; + if (nodeId) { try { const { Type, identifiers } = getTypeAndIdentifiersFromNodeId( nodeId, @@ -396,9 +406,9 @@ module.exports = function PostGraphileNestedMutationPlugin(builder) { if (sqlColumns.length) { mutationQuery = sql.query` update ${sql.identifier( - table.namespace.name, - table.name, - )} set ${sql.join( + table.namespace.name, + table.name, + )} set ${sql.join( sqlColumns.map( (col, i) => sql.fragment`${col} = ${sqlValues[i]}`, ), @@ -522,14 +532,14 @@ module.exports = function PostGraphileNestedMutationPlugin(builder) { updaterField.map(async (node) => { const where = sql.fragment` (${sql.join( - keys.map( - (k, i) => - sql.fragment`${sql.identifier(k.name)} = ${sql.value( - row[foreignKeys[i].name], - )}`, - ), - ') and (', - )}) + keys.map( + (k, i) => + sql.fragment`${sql.identifier(k.name)} = ${sql.value( + row[foreignKeys[i].name], + )}`, + ), + ') and (', + )}) `; const updatedRow = await pgNestedTableUpdate({ nestedField, @@ -641,32 +651,41 @@ module.exports = function PostGraphileNestedMutationPlugin(builder) { ); } - await Promise.all(Object.keys(fieldValue).map(async k => { - if (k.includes('updateBy')) { - await Promise.all( - (Array.isArray(fieldValue[k]) ? fieldValue[k] : [fieldValue[k]]).map(async (rowData) => { - const resolver = pgNestedUpdateResolvers[foreignTable.id]; + if (fieldValue.updateById || fieldValue.updateByNodeId) { + await Promise.all( + Object.keys(fieldValue) + .filter((f) => fieldValue[f]) + .map(async (f) => { + await Promise.all( + (Array.isArray(fieldValue[f]) + ? fieldValue[f] + : [fieldValue[f]] + ).map(async (rowData) => { + const resolver = + pgNestedUpdateResolvers[foreignTable.id]; + + const { data: reverseRow } = await resolver( + data, + { + input: Object.assign({}, rowData), + }, + { pgClient }, + resolveInfo, + ); - const { data: reverseRow } = await resolver( - data, - { - input: Object.assign({}, rowData), - }, - { pgClient }, - resolveInfo, + const rowKeyValues = {}; + if (primaryKeys && reverseRow) { + primaryKeys.forEach((k) => { + rowKeyValues[k.name] = + reverseRow[`__pk__${k.name}`]; + }); + } + modifiedRows.push(rowKeyValues); + }), ); - - const rowKeyValues = {}; - if (primaryKeys) { - primaryKeys.forEach((k) => { - rowKeyValues[k.name] = reverseRow[`__pk__${k.name}`]; - }); - } - modifiedRows.push(rowKeyValues); }), - ); - } - })) + ); + } }), ); @@ -712,13 +731,13 @@ module.exports = function PostGraphileNestedMutationPlugin(builder) { }; if (isPgCreateMutationField) { - pgNestedCreateResolvers[table.id] = newResolver; + pgNestedCreateResolvers[table.id] = mutationResolver; } if (isPgUpdateMutationField) { - pgNestedUpdateResolvers[table.id] = newResolver; + pgNestedUpdateResolvers[table.id] = mutationResolver; } - return Object.assign({}, field, { resolve: newResolver }); + return Object.assign({}, field, { resolve: mutationResolver }); }); };