graphql-subscriptions
Advanced tools
Comparing version 0.1.5 to 0.2.0
import { GraphQLSchema, GraphQLError } from 'graphql'; | ||
export interface PubSubEngine { | ||
publish(triggerName: string, payload: any): boolean; | ||
subscribe(triggerName: string, onMessage: Function): Promise<number>; | ||
subscribe(triggerName: string, onMessage: Function, options: Object): Promise<number>; | ||
unsubscribe(subId: number): any; | ||
@@ -32,2 +32,17 @@ } | ||
} | ||
export interface TriggerConfig { | ||
channelOptions?: Object; | ||
filter?: Function; | ||
} | ||
export interface TriggerMap { | ||
[triggerName: string]: TriggerConfig; | ||
} | ||
export interface SetupFunction { | ||
(options: SubscriptionOptions, args: { | ||
[key: string]: any; | ||
}, subscriptionName: string): TriggerMap; | ||
} | ||
export interface SetupFunctions { | ||
[subscriptionName: string]: SetupFunction; | ||
} | ||
export declare class SubscriptionManager { | ||
@@ -41,5 +56,3 @@ private pubsub; | ||
schema: GraphQLSchema; | ||
setupFunctions: { | ||
[subscriptionName: string]: Function; | ||
}; | ||
setupFunctions: SetupFunctions; | ||
pubsub: PubSubEngine; | ||
@@ -46,0 +59,0 @@ }); |
@@ -77,6 +77,9 @@ "use strict"; | ||
}); | ||
var triggerMap = (_a = {}, _a[subscriptionName] = function () { return true; }, _a); | ||
var triggerMap; | ||
if (this.setupFunctions[subscriptionName]) { | ||
triggerMap = this.setupFunctions[subscriptionName](options, args, subscriptionName); | ||
} | ||
else { | ||
triggerMap = (_a = {}, _a[subscriptionName] = {}, _a); | ||
} | ||
var externalSubscriptionId = this.maxSubscriptionId++; | ||
@@ -86,13 +89,23 @@ this.subscriptions[externalSubscriptionId] = []; | ||
Object.keys(triggerMap).forEach(function (triggerName) { | ||
var _a = triggerMap[triggerName], _b = _a.channelOptions, channelOptions = _b === void 0 ? {} : _b, _c = _a.filter, filter = _c === void 0 ? function () { return true; } : _c; | ||
var onMessage = function (rootValue) { | ||
try { | ||
graphql_1.execute(_this.schema, parsedQuery, rootValue, options.context, options.variables, options.operationName).then(function (data) { return options.callback(null, data); }); | ||
var contextPromise; | ||
if (typeof options.context === 'function') { | ||
contextPromise = new Promise(function (resolve) { | ||
resolve(options.context()); | ||
}); | ||
} | ||
catch (e) { | ||
options.callback(e); | ||
else { | ||
contextPromise = Promise.resolve(options.context); | ||
} | ||
contextPromise.then(function (context) { | ||
if (!filter(rootValue, context)) { | ||
return; | ||
} | ||
graphql_1.execute(_this.schema, parsedQuery, rootValue, context, options.variables, options.operationName).then(function (data) { return options.callback(null, data); }); | ||
}).catch(function (error) { | ||
options.callback(error); | ||
}); | ||
}; | ||
var shouldTrigger = triggerMap[triggerName]; | ||
var handler = function (data) { return shouldTrigger(data) && onMessage(data); }; | ||
var subsPromise = _this.pubsub.subscribe(triggerName, handler); | ||
var subsPromise = _this.pubsub.subscribe(triggerName, onMessage, channelOptions); | ||
subsPromise.then(function (id) { return _this.subscriptions[externalSubscriptionId].push(id); }); | ||
@@ -99,0 +112,0 @@ subscriptionPromises.push(subsPromise); |
"use strict"; | ||
var sinon = require('sinon'); | ||
var chai = require('chai'); | ||
var chaiAsPromised = require('chai-as-promised'); | ||
var sinonChai = require('sinon-chai'); | ||
var graphql_1 = require('graphql'); | ||
@@ -8,2 +10,3 @@ var pubsub_1 = require('../pubsub'); | ||
chai.use(chaiAsPromised); | ||
chai.use(sinonChai); | ||
var expect = chai.expect; | ||
@@ -55,2 +58,8 @@ var assert = chai.assert; | ||
}, | ||
testContext: { | ||
type: graphql_1.GraphQLString, | ||
resolve: function (rootValue, args, context) { | ||
return context; | ||
}, | ||
}, | ||
testFilter: { | ||
@@ -78,2 +87,8 @@ type: graphql_1.GraphQLString, | ||
}, | ||
testChannelOptions: { | ||
type: graphql_1.GraphQLString, | ||
resolve: function (root) { | ||
return root; | ||
}, | ||
}, | ||
}, | ||
@@ -83,2 +98,3 @@ }), | ||
describe('SubscriptionManager', function () { | ||
var pubsub = new pubsub_1.PubSub(); | ||
var subManager = new pubsub_1.SubscriptionManager({ | ||
@@ -90,3 +106,5 @@ schema: schema, | ||
return { | ||
'Filter1': function (root) { return root.filterBoolean === filterBoolean; }, | ||
'Filter1': { | ||
filter: function (root) { return root.filterBoolean === filterBoolean; }, | ||
}, | ||
}; | ||
@@ -96,9 +114,35 @@ }, | ||
return { | ||
'Trigger1': function () { return true; }, | ||
'Trigger2': function () { return true; }, | ||
'Trigger1': { | ||
filter: function () { return true; }, | ||
}, | ||
'Trigger2': { | ||
filter: function () { return true; }, | ||
}, | ||
}; | ||
}, | ||
'testChannelOptions': function () { | ||
return { | ||
'Trigger1': { | ||
channelOptions: { | ||
foo: 'bar', | ||
}, | ||
}, | ||
}; | ||
}, | ||
testContext: function (options) { | ||
return { | ||
contextTrigger: function (rootValue, context) { | ||
return context === 'trigger'; | ||
}, | ||
}; | ||
}, | ||
}, | ||
pubsub: new pubsub_1.PubSub(), | ||
pubsub: pubsub, | ||
}); | ||
beforeEach(function () { | ||
sinon.spy(pubsub, 'subscribe'); | ||
}); | ||
afterEach(function () { | ||
sinon.restore(pubsub.subscribe); | ||
}); | ||
it('throws an error if query is not valid', function () { | ||
@@ -192,2 +236,19 @@ var query = 'query a{ testInt }'; | ||
}); | ||
it('can subscribe to a trigger and pass options to PubSub using "channelOptions"', function (done) { | ||
var query = 'subscription X{ testChannelOptions }'; | ||
subManager.subscribe({ | ||
query: query, | ||
operationName: 'X', | ||
callback: function () { return null; }, | ||
}).then(function () { | ||
expect(pubsub.subscribe).to.have.been.calledOnce; | ||
var expectedChannelOptions = { | ||
foo: 'bar', | ||
}; | ||
expect(pubsub.subscribe).to.have.been.calledWith(sinon.match.string, sinon.match.func, expectedChannelOptions); | ||
done(); | ||
}).catch(function (err) { | ||
done(err); | ||
}); | ||
}); | ||
it('can unsubscribe', function (done) { | ||
@@ -233,2 +294,23 @@ var query = 'subscription X{ testSubscription }'; | ||
}); | ||
it('calls context if it is a function', function (done) { | ||
var query = "subscription TestContext { testContext }"; | ||
var callback = function (error, payload) { | ||
expect(error).to.be.null; | ||
expect(payload.data.testContext).to.eq('trigger'); | ||
done(); | ||
}; | ||
var context = function () { | ||
return 'trigger'; | ||
}; | ||
subManager.subscribe({ | ||
query: query, | ||
context: context, | ||
operationName: 'TestContext', | ||
variables: {}, | ||
callback: callback, | ||
}).then(function (subId) { | ||
subManager.publish('contextTrigger', 'ignored'); | ||
subManager.unsubscribe(subId); | ||
}); | ||
}); | ||
}); | ||
@@ -235,0 +317,0 @@ var validationSchema = new graphql_1.GraphQLSchema({ |
{ | ||
"name": "graphql-subscriptions", | ||
"version": "0.1.5", | ||
"version": "0.2.0", | ||
"description": "GraphQL subscriptions for node.js", | ||
"main": "dist/index.js", | ||
"repository": { | ||
"type": "git", | ||
"url": "https://github.com/apollostack/graphql-subscriptions.git" | ||
}, | ||
"dependencies": { | ||
@@ -28,2 +32,4 @@ "es6-promise": "^3.2.1", | ||
"remap-istanbul": "^0.6.4", | ||
"sinon": "^1.17.6", | ||
"sinon-chai": "^2.8.0", | ||
"tslint": "^3.13.0", | ||
@@ -30,0 +36,0 @@ "typescript": "^2.0.0", |
# graphql-subscriptions | ||
GraphQL subscriptions is a simple npm package that lets you wire up GraphQL with a pubsub system (like Redis) to implement subscriptions in GraphQL. | ||
GraphQL subscriptions is a simple npm package that lets you wire up GraphQL with a pubsub system (like Redis) to implement subscriptions in GraphQL. | ||
### Installation | ||
`npm install graphql-subscriptions` | ||
`npm install graphql-subscriptions` | ||
@@ -22,3 +22,3 @@ | ||
pubsub, | ||
// setupFunctions maps from subscription name to a map of channel names and their filter functions | ||
@@ -29,3 +29,5 @@ // in this case it will subscribe to the commentAddedChannel and re-run the subscription query | ||
commentAdded: (options, args) => ({ | ||
newCommentsChannel: comment => comment.repository_name === args.repoFullName, | ||
newCommentsChannel: { | ||
filter: comment => comment.repository_name === args.repoFullName, | ||
}, | ||
}), | ||
@@ -32,0 +34,0 @@ }, |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
No repository
Supply chain riskPackage does not have a linked source code repository. Without this field, a package will have no reference to the location of the source code use to generate the package.
Found 1 instance in 1 package
80
0
44394
10
16
580
1