Skip to content

Commit

Permalink
fix(executor): handle resolveType correctly for v15 (#6280)
Browse files Browse the repository at this point in the history
* fix(executor): handle resolveType correctly for v15

* Better impl
  • Loading branch information
ardatan committed Jun 21, 2024
1 parent b10b725 commit 7dcd0af
Show file tree
Hide file tree
Showing 4 changed files with 220 additions and 9 deletions.
83 changes: 83 additions & 0 deletions .changeset/chilled-kids-flow.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
---
'@graphql-tools/executor': patch
---

Since the executor is version agnostic, it should respect the schemas created with older versions.

So if a type resolver returns a type instead of type name which is required since `graphql@16`, the executor should handle it correctly.

See the following example:
```ts
// Assume that the following code is executed with `graphql@15`
import { execute } from '@graphql-tools/executor';

const BarType = new GraphQLObjectType({
name: 'Bar',
fields: {
bar: {
type: GraphQLString,
resolve: () => 'bar'
}
}
});
const BazType = new GraphQLObjectType({
name: 'Baz',
fields: {
baz: {
type: GraphQLString,
resolve: () => 'baz'
}
}
});
const BarBazType = new GraphQLUnionType({
name: 'BarBaz',
types: [BarType, BazType],
// This is the resolver that returns the type instead of type name
resolveType(obj) {
if ('bar' in obj) {
return BarType;
}
if ('baz' in obj) {
return BazType;
}
}
});
const QueryType = new GraphQLObjectType({
name: 'Query',
fields: {
barBaz: {
type: BarBazType,
resolve: () => ({ bar: 'bar' })
}
}
});
const schema = new GraphQLSchema({
query: QueryType
});

const result = await execute({
schema,
document: parse(
/* GraphQL */ `
query {
barBaz {
... on Bar {
bar
}
... on Baz {
baz
}
}
}
`
)
});

expect(result).toEqual({
data: {
barBaz: {
bar: 'bar'
}
}
});
```
15 changes: 9 additions & 6 deletions packages/executor/src/execution/__tests__/abstract-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
GraphQLString,
GraphQLUnionType,
parse,
versionInfo,
} from 'graphql';
import { expectJSON } from '../../__testUtils__/expectJSON.js';
import { execute, executeSync } from '../execute.js';
Expand Down Expand Up @@ -622,11 +623,13 @@ describe('Execute: Handles execution of abstract types', () => {
'Abstract type "Pet" must resolve to an Object type at runtime for field "Query.pet" with value { __typename: undefined }, received "[]".',
);

// FIXME: workaround since we can't inject resolveType into SDL
// @ts-expect-error
assertInterfaceType(schema.getType('Pet')).resolveType = () => schema.getType('Cat');
expectError({ forTypeName: undefined }).toEqual(
'Support for returning GraphQLObjectType from resolveType was removed in [email protected] please return type name instead.',
);
if (versionInfo.major >= 16) {
// FIXME: workaround since we can't inject resolveType into SDL
// @ts-expect-error
assertInterfaceType(schema.getType('Pet')).resolveType = () => schema.getType('Cat');
expectError({ forTypeName: undefined }).toEqual(
'Support for returning GraphQLObjectType from resolveType was removed in [email protected] please return type name instead.',
);
}
});
});
121 changes: 121 additions & 0 deletions packages/executor/src/execution/__tests__/resolveType.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
import { GraphQLResolveInfo, parse, versionInfo } from 'graphql';
import { makeExecutableSchema } from '@graphql-tools/schema';
import { normalizedExecutor } from '../normalizedExecutor';

describe('resolveType', () => {
it('should resolve types correctly with type names', async () => {
const schema = makeExecutableSchema({
typeDefs: /* GraphQL */ `
type Query {
foo: Foo
}
union Foo = Bar | Baz
type Bar {
bar: String
}
type Baz {
baz: String
}
`,
resolvers: {
Query: {
foo: () => ({ bar: 'bar' }),
},
Foo: {
__resolveType: (obj: { bar: string } | { baz: string }) => {
if ('bar' in obj) {
return 'Bar';
}
if ('baz' in obj) {
return 'Baz';
}
return null;
},
},
},
});
const result = await normalizedExecutor({
schema,
document: parse(/* GraphQL */ `
query {
foo {
... on Bar {
bar
}
... on Baz {
baz
}
}
}
`),
});
expect(result).toEqual({
data: {
foo: {
bar: 'bar',
},
},
});
});
if (versionInfo.major < 16) {
it('should resolve types correctly with types', async () => {
const schema = makeExecutableSchema({
typeDefs: /* GraphQL */ `
type Query {
foo: Foo
}
union Foo = Bar | Baz
type Bar {
bar: String
}
type Baz {
baz: String
}
`,
resolvers: {
Query: {
foo: () => ({ bar: 'bar' }),
},
Foo: {
// @ts-ignore - tests for older versions
__resolveType: (
obj: { bar: string } | { baz: string },
_ctx: never,
info: GraphQLResolveInfo,
) => {
if ('bar' in obj) {
return info.schema.getType('Bar');
}
if ('baz' in obj) {
return info.schema.getType('Baz');
}
return null;
},
},
},
});
const result = await normalizedExecutor({
schema,
document: parse(/* GraphQL */ `
query {
foo {
... on Bar {
bar
}
... on Baz {
baz
}
}
}
`),
});
expect(result).toEqual({
data: {
foo: {
bar: 'bar',
},
},
});
});
}
});
10 changes: 7 additions & 3 deletions packages/executor/src/execution/execute.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import {
SchemaMetaFieldDef,
TypeMetaFieldDef,
TypeNameMetaFieldDef,
versionInfo,
} from 'graphql';
import { ValueOrPromise } from 'value-or-promise';
import {
Expand Down Expand Up @@ -1236,9 +1237,12 @@ function ensureValidRuntimeType(
// releases before 16.0.0 supported returning `GraphQLObjectType` from `resolveType`
// TODO: remove in 17.0.0 release
if (isObjectType(runtimeTypeName)) {
throw createGraphQLError(
'Support for returning GraphQLObjectType from resolveType was removed in [email protected] please return type name instead.',
);
if (versionInfo.major >= 16) {
throw createGraphQLError(
'Support for returning GraphQLObjectType from resolveType was removed in [email protected] please return type name instead.',
);
}
runtimeTypeName = runtimeTypeName.name;
}

if (typeof runtimeTypeName !== 'string') {
Expand Down

0 comments on commit 7dcd0af

Please sign in to comment.