diff --git a/src/engine/subscription/Subscription.spec.ts b/src/engine/subscription/Subscription.spec.ts index fd5485eb..caf9ded8 100644 --- a/src/engine/subscription/Subscription.spec.ts +++ b/src/engine/subscription/Subscription.spec.ts @@ -195,7 +195,7 @@ describe('Subscription', () => { description: 'mutate the world', attributes: ['anything'], preProcessor() { - return {}; + return null; }, postProcessor() { return {}; @@ -390,13 +390,10 @@ describe('Subscription', () => { const subscriptionByName = testEntity.getSubscriptionByName( 'SomeSubWithPreProcessor', ); - expect(subscriptionByName).toMatchSnapshot(); const setup = await generateTestSchema({ entities: [testEntity] }); - const graphqlSchema = generateGraphQLSchema(setup.configuration); - const subscriptionDoc = parse(` subscription someSubWithPreProcessorSomeTestsEntityName($input: SomeSubWithPreProcessorSomeTestsEntityNameInput!) { someSubWithPreProcessorSomeTestsEntityName(input: $input) { @@ -419,10 +416,6 @@ describe('Subscription', () => { contextValue: { pubsub }, })) as AsyncIterableIterator; - // if (subscription.errors) { - // console.log({ errors: subscription.errors }); - // } - let pending = subscription.next(); await pubsub.publish('SomeSubWithPreProcessorSomeTestsEntityName', { @@ -433,8 +426,10 @@ describe('Subscription', () => { }); let result = await pending; - expect(result).toMatchSnapshot(); - expect(await subscription.return()).toMatchSnapshot(); + expect(result).toMatchSnapshot('withoutPreProcessorResult'); + expect(await subscription.return()).toMatchSnapshot( + 'withoutPreProcessorEnd', + ); // subscription topic will be generated in preProcessor subscription = (await subscribe({ @@ -461,8 +456,120 @@ describe('Subscription', () => { ); result = await pending; - expect(result).toMatchSnapshot(); - expect(await subscription.return()).toMatchSnapshot(); + expect(result).toMatchSnapshot('withPreProcessorResult'); + expect(await subscription.return()).toMatchSnapshot( + 'withPreProcessorEnd', + ); + }); + }); + + describe('postProcessor', () => { + const testEntity = new Entity({ + name: 'SomeTestsEntityName', + description: 'Just some description', + attributes: { + someAttribute: { + type: DataTypeString, + description: 'Just some description', + required: false, + }, + anotherAttribute: { + type: DataTypeString, + description: 'Just some description', + }, + }, + subscriptions: [ + new Subscription({ + name: 'SomeSubWithPostProcessor', + type: SUBSCRIPTION_TYPE_CREATE, + description: 'build item', + attributes: ['someAttribute'], + delimiter: '/', + postProcessor: ( + _entity, + // _id, + _source, + input, + typeName, + entitySubscription, + context, + ) => { + if (context && context.changePayload) { + return { anotherAttribute: 'earth' }; + } + return null; + }, + }), + ], + }); + + const someAttribute = 'test'; + + it('should pass through postProcessor if it is declared', async () => { + const subscriptionByName = testEntity.getSubscriptionByName( + 'SomeSubWithPostProcessor', + ); + expect(subscriptionByName).toMatchSnapshot(); + + const setup = await generateTestSchema({ entities: [testEntity] }); + const graphqlSchema = generateGraphQLSchema(setup.configuration); + const subscriptionDoc = parse(` + subscription someSubWithPostProcessorSomeTestsEntityName($input: SomeSubWithPostProcessorSomeTestsEntityNameInput!) { + someSubWithPostProcessorSomeTestsEntityName(input: $input) { + someTestsEntityName { + # someAttribute + anotherAttribute + } + } + }`); + + let subscription = (await subscribe({ + schema: graphqlSchema, + document: subscriptionDoc, + variableValues: { + input: { + someTestsEntityName: {}, + }, + }, + contextValue: { pubsub }, + })) as AsyncIterableIterator; + + let pending = subscription.next(); + + await pubsub.publish('SomeSubWithPostProcessorSomeTestsEntityName', { + someAttribute, + anotherAttribute: 'world', + }); + + let result = await pending; + expect(result).toMatchSnapshot('withoutPostProcessorResult'); + expect(await subscription.return()).toMatchSnapshot( + 'withoutPostProcessorEnd', + ); + + subscription = (await subscribe({ + schema: graphqlSchema, + document: subscriptionDoc, + variableValues: { + input: { + someTestsEntityName: {}, + }, + }, + contextValue: { pubsub, changePayload: true }, + })) as AsyncIterableIterator; + + pending = subscription.next(); + + await pubsub.publish('SomeSubWithPostProcessorSomeTestsEntityName', { + someAttribute, + anotherAttribute: 'world', + }); + + result = await pending; + expect(result).toMatchSnapshot('withPostProcessorResult'); + expect(await subscription.return()).toMatchSnapshot( + 'withPostProcessorEnd', + ); }); }); }); diff --git a/src/engine/subscription/Subscription.ts b/src/engine/subscription/Subscription.ts index e8b84e60..36aba830 100644 --- a/src/engine/subscription/Subscription.ts +++ b/src/engine/subscription/Subscription.ts @@ -54,7 +54,7 @@ export type SubscriptionSetup = { input?: any, typeName?: string, entitySubscription?: Subscription, - context?: object, + context?: any, info?: any, ) => Promise | string | null; postProcessor?: ( @@ -64,7 +64,7 @@ export type SubscriptionSetup = { input?: any, typeName?: string, entitySubscription?: Subscription, - context?: object, + context?: any, info?: any, ) => Promise | object | null; }; diff --git a/src/engine/subscription/__snapshots__/Subscription.spec.ts.snap b/src/engine/subscription/__snapshots__/Subscription.spec.ts.snap index bbe4a364..9df0e641 100644 --- a/src/engine/subscription/__snapshots__/Subscription.spec.ts.snap +++ b/src/engine/subscription/__snapshots__/Subscription.spec.ts.snap @@ -2,7 +2,7 @@ exports[`Subscription isSubscription should recognize non-Subscription objects 1`] = `"Not a Subscription object"`; -exports[`Subscription preProcessor should pass through preProcessor if it is declared 1`] = ` +exports[`Subscription postProcessor should pass through postProcessor if it is declared 1`] = ` Subscription { "attributes": Array [ "someAttribute", @@ -10,18 +10,47 @@ Subscription { "delimiter": "/", "description": "build item", "isTypeCreate": true, - "name": "SomeSubWithPreProcessor", - "preProcessor": [Function], + "name": "SomeSubWithPostProcessor", + "postProcessor": [Function], "type": "onCreate", } `; -exports[`Subscription preProcessor should pass through preProcessor if it is declared 2`] = ` +exports[`Subscription postProcessor should pass through postProcessor if it is declared: withPostProcessorEnd 1`] = ` +Object { + "done": true, + "value": undefined, +} +`; + +exports[`Subscription postProcessor should pass through postProcessor if it is declared: withPostProcessorResult 1`] = ` Object { "done": false, "value": Object { "data": Object { - "someSubWithPreProcessorSomeTestsEntityName": Object { + "someSubWithPostProcessorSomeTestsEntityName": Object { + "someTestsEntityName": Object { + "anotherAttribute": "earth", + }, + }, + }, + }, +} +`; + +exports[`Subscription postProcessor should pass through postProcessor if it is declared: withoutPostProcessorEnd 1`] = ` +Object { + "done": true, + "value": undefined, +} +`; + +exports[`Subscription postProcessor should pass through postProcessor if it is declared: withoutPostProcessorResult 1`] = ` +Object { + "done": false, + "value": Object { + "data": Object { + "someSubWithPostProcessorSomeTestsEntityName": Object { "someTestsEntityName": Object { "anotherAttribute": "world", }, @@ -31,14 +60,28 @@ Object { } `; -exports[`Subscription preProcessor should pass through preProcessor if it is declared 3`] = ` +exports[`Subscription preProcessor should pass through preProcessor if it is declared 1`] = ` +Subscription { + "attributes": Array [ + "someAttribute", + ], + "delimiter": "/", + "description": "build item", + "isTypeCreate": true, + "name": "SomeSubWithPreProcessor", + "preProcessor": [Function], + "type": "onCreate", +} +`; + +exports[`Subscription preProcessor should pass through preProcessor if it is declared: withPreProcessorEnd 1`] = ` Object { "done": true, "value": undefined, } `; -exports[`Subscription preProcessor should pass through preProcessor if it is declared 4`] = ` +exports[`Subscription preProcessor should pass through preProcessor if it is declared: withPreProcessorResult 1`] = ` Object { "done": false, "value": Object { @@ -53,13 +96,28 @@ Object { } `; -exports[`Subscription preProcessor should pass through preProcessor if it is declared 5`] = ` +exports[`Subscription preProcessor should pass through preProcessor if it is declared: withoutPreProcessorEnd 1`] = ` Object { "done": true, "value": undefined, } `; +exports[`Subscription preProcessor should pass through preProcessor if it is declared: withoutPreProcessorResult 1`] = ` +Object { + "done": false, + "value": Object { + "data": Object { + "someSubWithPreProcessorSomeTestsEntityName": Object { + "someTestsEntityName": Object { + "anotherAttribute": "world", + }, + }, + }, + }, +} +`; + exports[`Subscription processEntitySubscriptions should throw if provided with an invalid list of subscriptions 1`] = `"Entity 'SomeEntityName' subscriptions definition needs to be an array of subscriptions"`; exports[`Subscription processEntitySubscriptions should throw if provided with an invalid subscription 1`] = `"Invalid subscription definition for entity 'SomeEntityName' at position '0'"`; diff --git a/src/graphqlProtocol/resolver.ts b/src/graphqlProtocol/resolver.ts index 6ade9134..ce323d4b 100644 --- a/src/graphqlProtocol/resolver.ts +++ b/src/graphqlProtocol/resolver.ts @@ -531,6 +531,7 @@ export const getSubscriptionResolver = ( // } let topic; + const delimiter = entitySubscription.delimiter; if (entitySubscription.pattern) { // const delimiter = entitySubscription.delimiter; // const filled = entitySubscription.attributes @@ -538,17 +539,17 @@ export const getSubscriptionResolver = ( // .reduce((acc, curr) => `${acc + delimiter + curr}`, ''); const params = entitySubscription.pattern - .split(entitySubscription.delimiter) + .split(delimiter) .reduce((acc, curr) => (acc[curr] = args.input[typeName][curr]), {}); console.log('getSubscriptionResolver', { params }); - const filled = Object.values(params).join(entitySubscription.delimiter); + const filled = Object.values(params).join(delimiter); console.log('getSubscriptionResolver', { filled }); topic = `${entitySubscription.name}${entity.name}/${filled}${ entitySubscription.wildCard - ? entitySubscription.delimiter + entitySubscription.wildCard + ? delimiter + entitySubscription.wildCard : '' }`; } else if (entitySubscription.preProcessor) { @@ -566,7 +567,7 @@ export const getSubscriptionResolver = ( if (!topic) { topic = `${entitySubscription.name}${entity.name}${ entitySubscription.wildCard - ? entitySubscription.delimiter + entitySubscription.wildCard + ? delimiter + entitySubscription.wildCard : '' }`; } @@ -603,7 +604,9 @@ export const getSubscriptionPayloadResolver = ( context, info, ); - } else { + } + + if (!result) { result = source; }