diff --git a/CHANGELOG.md b/CHANGELOG.md index befeb9d3ebe..b289068e815 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,10 @@ [@freiksenet](https://github.com/freiksenet) in [#1003](https://github.com/apollographql/graphql-tools/pull/1003) * Allow user-provided `buildSchema` options.
[@trevor-scheer](https://github.com/trevor-scheer) in [#1154](https://github.com/apollographql/graphql-tools/pull/1154) +* Fix `delegateToSchema` to allow delegation to subscriptions with different root field names, allows + the use of the `RenameRootFields` transform with subscriptions, + pull request [#1104](https://github.com/apollographql/graphql-tools/pull/1104), fixes + [#997](https://github.com/apollographql/graphql-tools/issues/997).
### 4.0.4 diff --git a/src/stitching/delegateToSchema.ts b/src/stitching/delegateToSchema.ts index ff6bab772e9..9f38315968b 100644 --- a/src/stitching/delegateToSchema.ts +++ b/src/stitching/delegateToSchema.ts @@ -125,12 +125,11 @@ async function delegateToSchemaImplementation( // "subscribe" to the subscription result and map the result through the transforms return mapAsyncIterator(executionResult, result => { const transformedResult = applyResultTransforms(result, transforms); - const subscriptionKey = Object.keys(result.data)[0]; - // for some reason the returned transformedResult needs to be nested inside the root subscription field - // does not work otherwise... + // wrap with fieldName to return for an additional round of resolutioon + // with payload as rootValue return { - [subscriptionKey]: transformedResult, + [info.fieldName]: transformedResult, }; }); } diff --git a/src/test/testAlternateMergeSchemas.ts b/src/test/testAlternateMergeSchemas.ts index e593d0028e0..a7f4b3a422a 100644 --- a/src/test/testAlternateMergeSchemas.ts +++ b/src/test/testAlternateMergeSchemas.ts @@ -1,7 +1,13 @@ /* tslint:disable:no-unused-expression */ import { expect } from 'chai'; -import { graphql, GraphQLSchema } from 'graphql'; +import { + graphql, + GraphQLSchema, + ExecutionResult, + subscribe, + parse, +} from 'graphql'; import mergeSchemas from '../stitching/mergeSchemas'; import { transformSchema, @@ -9,7 +15,14 @@ import { RenameTypes, RenameRootFields, } from '../transforms'; -import { propertySchema, bookingSchema } from './testingSchemas'; +import { + propertySchema, + bookingSchema, + subscriptionSchema, + subscriptionPubSub, + subscriptionPubSubTrigger, +} from './testingSchemas'; +import { forAwaitEach } from 'iterall'; let linkSchema = ` """ @@ -78,11 +91,23 @@ describe('merge schemas through transforms', () => { (operation: string, name: string) => `Bookings_${name}`, ), ]); + const transformedSubscriptionSchema = transformSchema(subscriptionSchema, [ + new FilterRootFields( + (operation: string, rootField: string) => + // must include a Query type otherwise graphql will error + 'Query.notifications' === `${operation}.${rootField}` || + 'Subscription.notifications' === `${operation}.${rootField}`, + ), + new RenameTypes((name: string) => `Subscriptions_${name}`), + new RenameRootFields( + (operation: string, name: string) => `Subscriptions_${name}`), + ]); mergedSchema = mergeSchemas({ schemas: [ transformedPropertySchema, transformedBookingSchema, + transformedSubscriptionSchema, linkSchema, ], resolvers: { @@ -234,6 +259,41 @@ describe('merge schemas through transforms', () => { }, }); }); + + it('local subscriptions should work even if root fields are renamed', done => { + const originalNotification = { + notifications: { + text: 'Hello world', + }, + }; + + const transformedNotification = { + Subscriptions_notifications: originalNotification.notifications + }; + + const subscription = parse(` + subscription Subscription { + Subscriptions_notifications { + text + } + } + `); + + let notificationCnt = 0; + subscribe(mergedSchema, subscription) + .then(results => { + forAwaitEach( + results as AsyncIterable, + (result: ExecutionResult) => { + expect(result).to.have.property('data'); + expect(result.data).to.deep.equal(transformedNotification); + !notificationCnt++ ? done() : null; + }, + ).catch(done); + }).then(() => { + subscriptionPubSub.publish(subscriptionPubSubTrigger, originalNotification); + }).catch(done); + }); }); describe('interface resolver inheritance', () => {