/* eslint no-shadow: ["error", { "allow": ["options"] }] */ import { ApolloClient } from 'apollo-client' import { InMemoryCache, IntrospectionFragmentMatcher } from 'apollo-cache-inmemory' import { createHttpLink } from 'apollo-link-http' import { setContext } from 'apollo-link-context' import { computed, reactive, toRefs } from '@vue/composition-api' import useAuth from './auth' import introspectionQueryResultData from '../fragmentTypes.json' const fragmentMatcher = new IntrospectionFragmentMatcher({ introspectionQueryResultData }) let instance = null const apiUrl = process.env.graphqlApi || '/query' const cache = new InMemoryCache({ fragmentMatcher }) const httpLink = createHttpLink({ uri: apiUrl }) const getToken = async options => { const { getTokenSilently } = useAuth() return getTokenSilently.value(options) } const authLink = setContext(async (_, { headers }) => { return getToken().then(token => ({ headers: { ...headers, authorization: token ? `Bearer ${token}` : '' } })) }) console.log('Setting up Apollo') instance = new ApolloClient({ link: authLink.concat(httpLink), cache, defaultOptions: { watchQuery: { fetchPolicy: 'cache-and-network' } } }) const merge = (target, ...source) => { const sources = source instanceof Array ? source : [source] return sources.reduce((acc, src) => { Object.keys(src).forEach(key => { if (src[key] instanceof Object) Object.assign(src[key], merge(acc[key], src[key])) }) return Object.assign(acc, src) }, target || {}) } export const useMutation = (mutation, options) => { const opts = options const out = reactive({ data: {}, error: null, loading: false }) const doMutate = options => new Promise((resolve, reject) => { out.loading = true instance .mutate({ mutation, ...opts, ...options }) .then(result => { out.loading = false out.data = result.data resolve(result) }) .catch(e => { out.loading = false out.error = e reject(e) }) }) return [doMutate, toRefs(out)] } export const useLazyQuery = (query, options) => { const opts = options let watchedQuery = null const out = reactive({ data: {}, error: null, loading: false }) const doQuery = options => new Promise((resolve, reject) => { out.loading = true const effectiveOptions = merge({ query }, opts || {}, options || {}) watchedQuery = instance.watchQuery(effectiveOptions) watchedQuery.subscribe( ({ loading, data }) => { out.loading = loading out.data = data || {} out.error = null resolve(data) }, error => { out.loading = false out.error = error reject(error) } ) }) const refetch = variables => { doQuery({ variables: { ...(variables || {}) } }) } const startPolling = interval => doQuery({ pollInterval: interval }) const stopPolling = () => { if (watchedQuery) { watchedQuery.stopPolling() } } return [ doQuery, { ...toRefs(out), refetch, startPolling, stopPolling } ] } export const useQuery = (query, options) => { const [doQuery, out] = useLazyQuery(query, options) doQuery() return out } export const useResult = (result, defaultValue, pick) => { return computed(() => { const { value } = result if (value) { if (pick) { try { return pick(value) } catch (e) { // Silent error return defaultValue } } else { const keys = Object.keys(value) if (keys.length === 1) { // Automatically take the only key in result data return value[keys[0]] } // Return entire result data return value } } else { return defaultValue } }) }