diff --git a/docs-old/APIReference-GraphQL.md b/docs-old/APIReference-GraphQL.md index 3aea9e87ba..470de306f6 100644 --- a/docs-old/APIReference-GraphQL.md +++ b/docs-old/APIReference-GraphQL.md @@ -66,6 +66,12 @@ _Type Definitions_ A union type within GraphQL that defines a list of implementations. +
class GraphQLIntersectionType+ An intersection type within GraphQL that defines a list of constraining types. + +
class GraphQLEnumTypediff --git a/docs-old/APIReference-TypeSystem.md b/docs-old/APIReference-TypeSystem.md index 5b5047c349..f6e81b360c 100644 --- a/docs-old/APIReference-TypeSystem.md +++ b/docs-old/APIReference-TypeSystem.md @@ -54,6 +54,12 @@ _Definitions_ A union type within GraphQL that defines a list of implementations.
class GraphQLIntersectionType+ An intersection type within GraphQL that defines a list of constraining types. + +
class GraphQLEnumTypediff --git a/src/__testUtils__/kitchenSinkSDL.ts b/src/__testUtils__/kitchenSinkSDL.ts index cdf2f9afce..14552f2806 100644 --- a/src/__testUtils__/kitchenSinkSDL.ts +++ b/src/__testUtils__/kitchenSinkSDL.ts @@ -79,6 +79,18 @@ extend union Feed = Photo | Video extend union Feed @onUnion +intersection Resource = Feed & Node + +intersection AnnotatedIntersection @onIntersection = Feed & Node + +intersection AnnotatedIntersectionTwo @onIntersection = Feed & Node + +intersection UndefinedIntersection + +extend intersection Resource = Media & Accessible + +extend intersection Resource @onIntersection + scalar CustomScalar scalar AnnotatedScalar @onScalar diff --git a/src/execution/__tests__/abstract-test.ts b/src/execution/__tests__/abstract-test.ts index 5253d0d9e0..2439edef3d 100644 --- a/src/execution/__tests__/abstract-test.ts +++ b/src/execution/__tests__/abstract-test.ts @@ -8,6 +8,7 @@ import { parse } from '../../language/parser'; import { assertInterfaceType, GraphQLInterfaceType, + GraphQLIntersectionType, GraphQLList, GraphQLObjectType, GraphQLUnionType, @@ -352,6 +353,94 @@ describe('Execute: Handles execution of abstract types', () => { }); }); + it('isTypeOf used to resolve runtime type for Intersection', async () => { + const DogType = new GraphQLObjectType({ + name: 'Dog', + isTypeOf(obj, context) { + const isDog = obj instanceof Dog; + return context.async ? Promise.resolve(isDog) : isDog; + }, + interfaces: () => [PetType], + fields: { + name: { type: GraphQLString }, + woofs: { type: GraphQLBoolean }, + }, + }); + + const CatType = new GraphQLObjectType({ + name: 'Cat', + isTypeOf(obj, context) { + const isCat = obj instanceof Cat; + return context.async ? Promise.resolve(isCat) : isCat; + }, + interfaces: () => [PetType], + fields: { + name: { type: GraphQLString }, + meows: { type: GraphQLBoolean }, + }, + }); + + const PetType = new GraphQLInterfaceType({ + name: 'Pet', + fields: { + name: { type: GraphQLString }, + }, + }); + + const CatOrDogType = new GraphQLUnionType({ + name: 'CatOrDog', + types: [DogType, CatType], + }); + + const CatOrDogPetType = new GraphQLIntersectionType({ + name: 'CatOrDogPet', + types: [CatOrDogType, PetType], + }); + + const schema = new GraphQLSchema({ + query: new GraphQLObjectType({ + name: 'Query', + fields: { + catOrDogPets: { + type: new GraphQLList(CatOrDogPetType), + resolve() { + return [new Dog('Odie', true), new Cat('Garfield', false)]; + }, + }, + }, + }), + }); + + const query = `{ + catOrDogPets { + ... on Pet { + name + } + ... on Dog { + woofs + } + ... on Cat { + meows + } + } + }`; + + expect(await executeQuery({ schema, query })).to.deep.equal({ + data: { + catOrDogPets: [ + { + name: 'Odie', + woofs: true, + }, + { + name: 'Garfield', + meows: false, + }, + ], + }, + }); + }); + it('resolveType can throw', async () => { const PetType = new GraphQLInterfaceType({ name: 'Pet', @@ -497,6 +586,78 @@ describe('Execute: Handles execution of abstract types', () => { }); }); + it('resolve Intersection type using __typename on source object', async () => { + const schema = buildSchema(` + type Query { + catOrDogPets: [CatOrDogPet] + } + + union CatOrDog = Cat | Dog + + interface Pet { + name: String + } + + intersection CatOrDogPet = CatOrDog & Pet + + type Cat implements Pet { + name: String + meows: Boolean + } + + type Dog implements Pet { + name: String + woofs: Boolean + } + `); + + const query = ` + { + catOrDogPets { + ... on Pet { + name + } + ... on Dog { + woofs + } + ... on Cat { + meows + } + } + } + `; + + const rootValue = { + catOrDogPets: [ + { + __typename: 'Dog', + name: 'Odie', + woofs: true, + }, + { + __typename: 'Cat', + name: 'Garfield', + meows: false, + }, + ], + }; + + expect(await executeQuery({ schema, query, rootValue })).to.deep.equal({ + data: { + catOrDogPets: [ + { + name: 'Odie', + woofs: true, + }, + { + name: 'Garfield', + meows: false, + }, + ], + }, + }); + }); + it('resolve Interface type using __typename on source object', async () => { const schema = buildSchema(` type Query { diff --git a/src/execution/__tests__/union-interface-test.ts b/src/execution/__tests__/union-interface-test.ts index 7ce9f8b3bc..dd90947819 100644 --- a/src/execution/__tests__/union-interface-test.ts +++ b/src/execution/__tests__/union-interface-test.ts @@ -5,6 +5,7 @@ import { parse } from '../../language/parser'; import { GraphQLInterfaceType, + GraphQLIntersectionType, GraphQLList, GraphQLObjectType, GraphQLUnionType, @@ -45,15 +46,18 @@ class Cat { class Person { name: string; pets?: ReadonlyArray