Created
May 4, 2018 19:11
-
-
Save charlesdemers/fc4ff60287f3a099e4cef9d89bbd5476 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Vendor | |
import EmberObject, {computed} from '@ember/object'; | |
import {assert} from '@ember/debug'; | |
import {task, timeout} from 'ember-concurrency'; | |
const WatchQuery = EmberObject.extend({ | |
_hostObject: null, | |
_query: null, | |
_variablesProperty: null, | |
_originalFetchPolicy: null, | |
_shouldFetchResultsProperty: null, | |
_subscriptions: computed(() => []), | |
_internalSubscription: null, | |
init() { | |
this._setupInternalSubscription(); | |
this._addObservers(); | |
this._setupObjectAutoDestruction(); | |
}, | |
setVariables(variables, refetch = true) { | |
this.get('_query').setVariables(variables, refetch); | |
}, | |
startPolling(pollingInterval) { | |
this.get('_query').startPolling(pollingInterval); | |
}, | |
stopPolling() { | |
this.get('_query').stopPolling(); | |
}, | |
refetch(variables) { | |
this.get('_query').refetch(variables); | |
}, | |
fetchMore(options) { | |
this.get('_query').fetchMore(options); | |
}, | |
subscribe(callback) { | |
const subscription = this.get('_query').subscribe({ | |
next: (response) => { | |
callback(response); | |
} | |
}); | |
this.get('_subscriptions').push(subscription); | |
return subscription; | |
}, | |
subscribeOnce(callback) { | |
const subscription = this.subscribe((response) => { | |
if (response.loading) return; | |
this.unsubscribe(subscription); | |
callback(response); | |
}); | |
}, | |
unsubscribe(subscription) { | |
const subscriptions = this.get('_subscriptions') | |
.filter((activeSubscription) => subscription !== activeSubscription); | |
this.set('_subscriptions', subscriptions); | |
subscription.unsubscribe(); | |
}, | |
_getOnHost(property) { | |
return this.get('_hostObject').get(this.get(property)); | |
}, | |
_shouldFetchResults() { | |
return !this.get('_shouldFetchResultsProperty') | |
|| (this.get('_shouldFetchResultsProperty') && this._getOnHost('_shouldFetchResultsProperty')); | |
}, | |
_addObservers() { | |
const variablesProperty = this.get('_variablesProperty'); | |
const shouldFetchResultsProperty = this.get('_shouldFetchResultsProperty'); | |
if (shouldFetchResultsProperty) { | |
this.get('_hostObject').addObserver(shouldFetchResultsProperty, this, () => this.get('_respondToObservers').perform()); | |
} | |
if (variablesProperty) { | |
this.get('_hostObject').addObserver(variablesProperty, this, () => this.get('_respondToObservers').perform()); | |
} | |
}, | |
_respondToObservers: task(function *() { | |
// Wait for the next run loop so that if the `variables` | |
// and the `shouldFetch` observers fire simutaneously, | |
// we run this only once | |
yield timeout(0); | |
const shouldFetchResults = this._shouldFetchResults(); | |
if (shouldFetchResults) { | |
const wasPolling = this.get('_query.isCurrentlyPolling'); | |
const pollInterval = this.get('_query.options.pollInterval'); | |
if (wasPolling) this.stopPolling(); | |
this.get('_query').setOptions({ | |
variables: this._getOnHost('_variablesProperty'), | |
fetchPolicy: this.get('_originalFetchPolicy'), | |
pollInterval | |
}); | |
} else { | |
this.get('_query').setOptions({fetchPolicy: 'standby'}); | |
} | |
}).restartable(), | |
_setupInternalSubscription() { | |
if (this._shouldFetchResults()) { | |
this.set('response', this.get('_query').currentResult()); | |
} else { | |
this.get('_query').setOptions({fetchPolicy: 'standby'}); | |
this.set('response', {loading: false, data: null}); | |
} | |
const subscription = this.subscribe((response) => { | |
this.set('response', response); | |
}); | |
this.set('_internalSubscription', subscription); | |
}, | |
_setupObjectAutoDestruction() { | |
const hostObject = this.get('_hostObject'); | |
const destroyMethod = hostObject.get('isComponent') | |
? 'willDestroyElement' | |
: 'willDestroy'; | |
const oldWillDestroy = hostObject[destroyMethod]; | |
hostObject[destroyMethod] = () => { | |
this.get('_subscriptions').forEach((subscription) => subscription.unsubscribe()); | |
this.destroy(); | |
oldWillDestroy.call(hostObject); | |
}; | |
} | |
}); | |
export default ({query, variables, fetchPolicy = 'network-only', shouldFetchResults, pollInterval}) => { | |
return computed(function() { | |
assert('[apollo-watch-query] Cannot find the `apollo` service, maybe you forgot to inject it?', this.get('apollo.client')); | |
const computedVariables = variables ? this.get(variables) : {}; | |
const watchQuery = this.get('apollo.client').watchQuery({ | |
query, | |
fetchPolicy, | |
fetchResults: false, | |
variables: computedVariables, | |
pollInterval | |
}); | |
return WatchQuery.create({ | |
_hostObject: this, | |
_query: watchQuery, | |
_variablesProperty: variables, | |
_originalFetchPolicy: fetchPolicy, | |
_shouldFetchResultsProperty: shouldFetchResults | |
}); | |
}); | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Vendor | |
import Component from '@ember/component'; | |
import {inject as service} from '@ember/service'; | |
import {computed} from '@ember/object'; | |
import {notEmpty} from '@ember/object/computed'; | |
// Computed macros | |
import apolloWatchQuery from 'my-app/computed-macros/apollo-watch-query'; | |
// GraphQL | |
import userQuery from 'my-app/graphql/queries/user'; | |
export default Component.extend({ | |
apollo: service('apollo'), | |
userPresenter: service('users/presenter'), | |
userQuery: apolloWatchQuery({ | |
query: userQuery, | |
variables: 'userQueryVariables', | |
pollInterval: 10000, | |
shouldFetchResults: 'userQueryShouldFetchResults' | |
}), | |
userQueryVariables: computed('userId', function() { | |
return {userId: this.get('userId')}; | |
}), | |
userQueryShouldFetchResults: notEmpty('userId'), | |
user: computed('userQuery.response.{loading,data}', function() { | |
if (this.get('userQuery.response.loading') return null; | |
return this.get('userPresenter').present(this.get('userQuery.response.data.user')); | |
}) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment