Skip to content

Commit

Permalink
fix(buildOperationNodeForField): mutation response return a field of …
Browse files Browse the repository at this point in the history
…type Query (#3383)

* test: Test for buildOperationNodeForField #3380

* fix(buildOperationNodeForField): mutation response return a field of type Query

* enhance(buildOperationNodeForField): mutation response return a field of type Query

Co-authored-by: Arda TANRIKULU <ardatanrikulu@gmail.com>
  • Loading branch information
yurtaev and ardatan committed Aug 16, 2021
1 parent 9dfad28 commit 2c807dd
Show file tree
Hide file tree
Showing 3 changed files with 104 additions and 4 deletions.
5 changes: 5 additions & 0 deletions .changeset/shaggy-monkeys-smoke.md
@@ -0,0 +1,5 @@
---
'@graphql-tools/utils': patch
---

enhance(buildOperationNodeForField): mutation response return a field of type Query
22 changes: 18 additions & 4 deletions packages/utils/src/build-operation-for-field.ts
Expand Up @@ -28,7 +28,7 @@ import {
Kind,
} from 'graphql';

import { getDefinedRootType } from './rootTypes';
import { getDefinedRootType, getRootTypeNames } from './rootTypes';

let operationVariables: VariableDefinitionNode[] = [];
let fieldTypeMap = new Map();
Expand Down Expand Up @@ -60,7 +60,7 @@ export function buildOperationNodeForField({
kind,
field,
models,
ignore,
ignore = [],
depthLimit,
circularReferenceDepth,
argNames,
Expand All @@ -79,16 +79,19 @@ export function buildOperationNodeForField({
resetOperationVariables();
resetFieldMap();

const rootTypeNames = getRootTypeNames(schema);

const operationNode = buildOperationAndCollectVariables({
schema,
fieldName: field,
kind,
models: models || [],
ignore: ignore || [],
ignore,
depthLimit: depthLimit || Infinity,
circularReferenceDepth: circularReferenceDepth || 1,
argNames,
selectedFields,
rootTypeNames,
});

// attach variables
Expand All @@ -110,6 +113,7 @@ function buildOperationAndCollectVariables({
circularReferenceDepth,
argNames,
selectedFields,
rootTypeNames,
}: {
schema: GraphQLSchema;
fieldName: string;
Expand All @@ -120,6 +124,7 @@ function buildOperationAndCollectVariables({
circularReferenceDepth: number;
argNames?: string[];
selectedFields: SelectedFields;
rootTypeNames: Set<string>;
}): OperationDefinitionNode {
const type = getDefinedRootType(schema, kind);
const field = type.getFields()[fieldName];
Expand Down Expand Up @@ -159,6 +164,7 @@ function buildOperationAndCollectVariables({
depth: 0,
argNames,
selectedFields,
rootTypeNames,
}),
],
},
Expand All @@ -179,6 +185,7 @@ function resolveSelectionSet({
depth,
argNames,
selectedFields,
rootTypeNames,
}: {
parent: GraphQLNamedType;
type: GraphQLNamedType;
Expand All @@ -193,6 +200,7 @@ function resolveSelectionSet({
depth: number;
selectedFields: SelectedFields;
argNames?: string[];
rootTypeNames: Set<string>;
}): SelectionSetNode | void {
if (typeof selectedFields === 'boolean' && depth > depthLimit) {
return;
Expand Down Expand Up @@ -232,6 +240,7 @@ function resolveSelectionSet({
depth,
argNames,
selectedFields,
rootTypeNames,
}) as SelectionSetNode,
};
})
Expand Down Expand Up @@ -276,14 +285,15 @@ function resolveSelectionSet({
depth,
argNames,
selectedFields,
rootTypeNames,
}) as SelectionSetNode,
};
})
.filter(fragmentNode => fragmentNode?.selectionSet?.selections?.length > 0),
};
}

if (isObjectType(type)) {
if (isObjectType(type) && !rootTypeNames.has(type.name)) {
const isIgnored = ignore.includes(type.name) || ignore.includes(`${parent.name}.${path[path.length - 1]}`);
const isModel = models.includes(type.name);

Expand Down Expand Up @@ -328,6 +338,7 @@ function resolveSelectionSet({
depth,
argNames,
selectedFields: selectedSubFields,
rootTypeNames,
});
}
return null;
Expand Down Expand Up @@ -403,6 +414,7 @@ function resolveField({
depth,
argNames,
selectedFields,
rootTypeNames,
}: {
type: GraphQLObjectType;
field: GraphQLField<any, any>;
Expand All @@ -417,6 +429,7 @@ function resolveField({
depth: number;
selectedFields: SelectedFields;
argNames?: string[];
rootTypeNames: Set<string>;
}): SelectionNode {
const namedType = getNamedType(field.type);
let args: ArgumentNode[] = [];
Expand Down Expand Up @@ -489,6 +502,7 @@ function resolveField({
depth: depth + 1,
argNames,
selectedFields,
rootTypeNames,
}) || undefined,
arguments: args,
};
Expand Down
81 changes: 81 additions & 0 deletions packages/utils/tests/build-operation-node-for-field.spec.ts
Expand Up @@ -260,6 +260,87 @@ test('should work with mutation', async () => {
);
});

test('should work with mutation + return a field of type Query', async () => {
const schema = buildSchema(/* GraphQL */ `
type Pizza {
dough: String!
toppings: [String!]
query: Query
}
type Query {
pizza: Pizza
pizzaById(id: String!): Pizza
}
type Mutation {
addPizza(name: String!): Pizza
}
`)
const document = buildOperationNodeForField({
schema,
kind: 'mutation',
field: 'addPizza',
models,
ignore: [],
})!;

expect(clean(document)).toEqual(
clean(/* GraphQL */ `
mutation addPizza_mutation($name: String!) {
addPizza(name: $name) {
dough
toppings
}
}
`)
);
});

test('should work with mutation + Union + return a field of type Query', async () => {
const schema = buildSchema(/* GraphQL */ `
type Pizza {
dough: String!
toppings: [String!]
query: Query
}
type Salad {
ingredients: [String!]!
query: Query
}
union Food = Pizza | Salad
type Query {
pizza: Pizza
getPizzaById(id: String!): Pizza
}
type Mutation {
addRandomFood(name: String!): Food
}
`)
const document = buildOperationNodeForField({
schema,
kind: 'mutation',
field: 'addRandomFood',
models,
ignore: [],
})!;

expect(clean(document)).toEqual(
clean(/* GraphQL */ `
mutation addRandomFood_mutation($name: String!) {
addRandomFood(name: $name) {
... on Pizza {
dough
toppings
}
... on Salad {
ingredients
}
}
}
`)
);
});

test('should work with mutation and unions', async () => {
const document = buildOperationNodeForField({
schema,
Expand Down

1 comment on commit 2c807dd

@vercel
Copy link

@vercel vercel bot commented on 2c807dd Aug 16, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.