Files
apollo/lib/vue-plugin.js
T
Guillaume Chau c8a2baacbb Initial version
2016-09-20 00:06:29 +02:00

231 lines
4.9 KiB
JavaScript

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;
}
}
});
}
};