import _ from 'lodash'; let apolloClient = null; class DollarApollo { constructor(vm) { this.vm = vm; this.querySubscriptions = {}; } get client() { return apolloClient; } get query() { return this.client.query; } watchQuery(options) { const vm = this.vm; const observable = this.client.watchQuery(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; } get mutate() { return this.client.mutate; } option(key, options, watch) { const vm = this.vm; const $apollo = this; let query, observer, sub; let simpleQuery = false; let firstLoadingDone = false; let loadingKey = options.loadingKey; let loadingChangeCb = options.watchLoading; if (options.pollInterval) { watch = true; } if (typeof loadingChangeCb === 'function') { loadingChangeCb = loadingChangeCb.bind(vm); } // Simple query if (!options.query) { query = options; simpleQuery = true; } function generateApolloOptions(variables) { const apolloOptions = _.omit(options, [ 'variables', 'watch', 'update', 'result', 'error', 'loadingKey', 'watchLoading', ]); apolloOptions.variables = variables; return apolloOptions; } function q(variables) { applyLoadingModifier(1); if (simpleQuery) { $apollo.query({ query }).then(nextResult).catch(catchError); } else if (watch) { if (options.forceFetch && observer) { // Refresh query observer.refetch(variables, { forceFetch: !!options.forceFetch }); } else { if (sub) { sub.unsubscribe(); } // Create observer observer = $apollo.watchQuery(generateApolloOptions(variables)); // Create subscription sub = observer.subscribe({ next: nextResult, error: catchError }); } } else { $apollo.query(generateApolloOptions(variables)).then(nextResult).catch(catchError); } } if (typeof options.variables === 'function') { vm.$watch(options.variables.bind(vm), q, { immediate: true }); } else { q(options.variables); } function nextResult({ data }) { applyData(data); } function applyData(data) { loadingDone(); console.log(data, key); if (typeof options.update === 'function') { vm[key] = options.update.call(vm, data); } else if (data[key] === undefined) { console.error(`Missing ${key} attribute on result`, data); } else { vm[key] = data[key]; } if (typeof options.result === 'function') { options.result.call(vm, data); } } function applyLoadingModifier(value) { if (loadingKey) { vm.$set(loadingKey, vm.$get(loadingKey) + value); } if (loadingChangeCb) { loadingChangeCb(value === 1, value); } } function loadingDone() { if (!firstLoadingDone) { applyLoadingModifier(-1); firstLoadingDone = true; } } function catchError(error) { loadingDone(); if (error.graphQLErrors && error.graphQLErrors.length !== 0) { console.error(`GraphQL execution errors for query ${query}`); for (let e of error.graphQLErrors) { console.error(e); } } else if (error.networkError) { console.error(`Error sending the query ${query}`, error.networkError); } else { console.error(error); } if (typeof options.error === 'function') { options.error(error); } } } } function prepare() { this._apolloSubscriptions = []; this.$apollo = new DollarApollo(this); let apollo = this.$options.apollo; if (apollo) { // One-time queries with $query(), called each time a Vue dependency is updated (using $watch) if (apollo.data) { for (let key in apollo.data) { this.$apollo.option(key, apollo.data[key], false); } } // Auto updating queries with $watchQuery(), re-called each time a Vue dependency is updated (using $watch) if (apollo.watch) { for (let key in apollo.watch) { this.$apollo.option(key, apollo.watch[key], true); } } } } export default { install(Vue, options) { apolloClient = options.apolloClient; Vue.mixin({ // Vue 1.x beforeCompile: prepare, // Vue 2.x beforeCreate: prepare, destroyed: function() { this._apolloSubscriptions.forEach((sub) => { sub.unsubscribe(); }); this._apolloSubscriptions = null; if (this.$apollo) { this.$apollo = null; } } }); } };