-
-
Notifications
You must be signed in to change notification settings - Fork 805
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix(executor): handle resolveType correctly for v15 (#6280)
* fix(executor): handle resolveType correctly for v15 * Better impl
- Loading branch information
Showing
4 changed files
with
220 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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' | ||
} | ||
} | ||
}); | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,6 +9,7 @@ import { | |
GraphQLString, | ||
GraphQLUnionType, | ||
parse, | ||
versionInfo, | ||
} from 'graphql'; | ||
import { expectJSON } from '../../__testUtils__/expectJSON.js'; | ||
import { execute, executeSync } from '../execute.js'; | ||
|
@@ -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
121
packages/executor/src/execution/__tests__/resolveType.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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', | ||
}, | ||
}, | ||
}); | ||
}); | ||
} | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -27,6 +27,7 @@ import { | |
SchemaMetaFieldDef, | ||
TypeMetaFieldDef, | ||
TypeNameMetaFieldDef, | ||
versionInfo, | ||
} from 'graphql'; | ||
import { ValueOrPromise } from 'value-or-promise'; | ||
import { | ||
|
@@ -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') { | ||
|