From 52cd068b33ab5b4854aef6e2928d86a87bc7d8be Mon Sep 17 00:00:00 2001 From: Guillaume Chau Date: Tue, 1 Nov 2016 17:54:26 +0100 Subject: [PATCH] Basic subscription support --- package.json | 3 +- src/vue-plugin.js | 104 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 106 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index c3f7f8c..b776fcd 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "vue-apollo", - "version": "1.0.0-rc.2", + "version": "1.1.0-beta.0", "description": "Vue apollo integration", "main": "index.js", "scripts": { @@ -30,6 +30,7 @@ "apollo-client": "^0.5.0" }, "dependencies": { + "graphql-tag": "^0.1.15", "lodash.omit": "^4.5.0" }, "devDependencies": { diff --git a/src/vue-plugin.js b/src/vue-plugin.js index f97ad57..520b8a0 100644 --- a/src/vue-plugin.js +++ b/src/vue-plugin.js @@ -1,9 +1,25 @@ import omit from 'lodash.omit'; +import { print } from 'graphql-tag/printer'; let apolloClient = null; let defineReactive = function() {}; +// quick way to add the subscribe and unsubscribe functions to the network interface +function addGraphQLSubscriptions(networkInterface, wsClient) { + return Object.assign(networkInterface, { + subscribe(request, handler) { + return wsClient.subscribe({ + query: print(request.query), + variables: request.variables, + }, handler); + }, + unsubscribe(id) { + wsClient.unsubscribe(id); + }, + }); +} + class DollarApollo { constructor(vm) { this.vm = vm; @@ -34,6 +50,18 @@ class DollarApollo { return this.client.mutate; } + subscribe(options) { + const vm = this.vm; + const observable = this.client.subscribe(options); + const _subscribe = observable.subscribe.bind(observable); + observable.subscribe = (function(options) { + let sub = _subscribe(options); + vm._apolloSubscriptions.push(sub); + return sub; + }).bind(observable); + return observable; + } + option(key, options) { const vm = this.vm; const $apollo = this; @@ -162,6 +190,73 @@ class DollarApollo { } } } + + subscribeOption(key, options) { + const vm = this.vm; + const $apollo = this; + + let observer, sub; + + function generateApolloOptions(variables) { + const apolloOptions = omit(options, [ + 'variables', + 'result', + 'error', + ]); + apolloOptions.variables = variables; + return apolloOptions; + } + + function q(variables) { + console.log(variables); + + if (sub) { + sub.unsubscribe(); + } + + // Create observer + observer = $apollo.subscribe(generateApolloOptions(variables)); + + // Create subscription + sub = observer.subscribe({ + next: nextResult, + error: catchError + }); + } + + if (typeof options.variables === 'function') { + vm.$watch(options.variables.bind(vm), q, { + immediate: true + }); + } else { + q(options.variables); + } + + function nextResult(data) { + if (typeof options.result === 'function') { + options.result.call(vm, data); + } + } + + function catchError(error) { + loadingDone(); + + if (error.graphQLErrors && error.graphQLErrors.length !== 0) { + console.error(`GraphQL execution errors for subscription ${query}`); + for (let e of error.graphQLErrors) { + console.error(e); + } + } else if (error.networkError) { + console.error(`Error sending the subscription ${query}`, error.networkError); + } else { + console.error(error); + } + + if (typeof options.error === 'function') { + options.error(error); + } + } + } } const prepare = function prepare() { @@ -199,9 +294,18 @@ const launch = function launch() { this.$apollo.option(key, this._apolloQueries[key]); } } + + let apollo = this.$options.apollo; + if(apollo && apollo.subscribe) { + for (let key in apollo.subscribe) { + this.$apollo.subscribeOption(key, apollo.subscribe[key]); + } + } } module.exports = { + addGraphQLSubscriptions, + install(Vue, options) { defineReactive = Vue.util.defineReactive;