Created
August 23, 2020 01:07
-
-
Save josemarluedke/2e60b6d7303d4eb4fdfbba157e11dc34 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
import ApolloService from 'ember-apollo-client/services/apollo'; | |
import { tracked } from '@glimmer/tracking'; | |
import { resource } from 'ember-usable'; | |
import { inject as service } from '@ember/service'; | |
import { getOwner } from '@ember/application'; | |
import { | |
ApolloQueryResult, | |
NetworkStatus, | |
OperationVariables, | |
DocumentNode, | |
WatchQueryOptions, | |
ObservableQuery, | |
ApolloError | |
} from '@apollo/client/core'; | |
import Fastboot from 'ember-cli-fastboot/services/fastboot'; | |
interface BaseQueryOptions<TVariables = OperationVariables> | |
extends Omit<WatchQueryOptions<TVariables>, 'query'> { | |
ssr?: boolean; | |
} | |
type WatchQueryResourceArgs<TVariables = OperationVariables> = [ | |
DocumentNode, | |
BaseQueryOptions<TVariables>? | |
]; | |
class WatchQueryResource<TData = {}> { | |
@service apollo!: ApolloService; | |
@tracked isLoading = true; | |
@tracked observable?: ObservableQuery<TData>; | |
@tracked error?: ApolloError; | |
subscription?: ZenObservable.Subscription; | |
@tracked result: ApolloQueryResult<TData> = { | |
loading: this.isLoading, | |
networkStatus: NetworkStatus.loading | |
}; | |
manager = null; | |
get state(): ApolloQueryResult<TData> { | |
const loading = this.isLoading ? this.isLoading : this.result.loading; | |
return { | |
...this.result, | |
error: this.result.error || this.error, | |
loading | |
}; | |
} | |
async setup( | |
query: WatchQueryResourceArgs[0], | |
options: WatchQueryResourceArgs[1] | |
): Promise<void> { | |
console.log('SETUP'); | |
this.isLoading = true; | |
const fastboot = this.getFastboot(); | |
if (fastboot && fastboot.isFastBoot && options && options.ssr === false) { | |
return; | |
} | |
const [promise, resolve] = this.createPromise(options); | |
const observable = this.apollo.client.watchQuery({ | |
query, | |
...(options || {}) | |
}); | |
this.observable = observable; | |
this.subscription = observable.subscribe({ | |
next: (result) => { | |
this.updateResult(result); | |
if (typeof resolve === 'function') { | |
resolve(this.state); | |
} | |
}, | |
error: (e) => { | |
this.isLoading = false; | |
this.error = e; | |
} | |
}); | |
if (promise && fastboot) { | |
fastboot.deferRendering(promise); | |
} | |
} | |
updateResult(result: ApolloQueryResult<TData>): void { | |
console.log('UPDATE RESULT', result); | |
this.error = undefined; | |
this.result = result; | |
this.isLoading = false; | |
} | |
update(...args: WatchQueryResourceArgs): void { | |
console.log('UPDATE RESOURCE', ...args); | |
this.teardown(); | |
this.setup(...args); | |
} | |
teardown(): void { | |
if (this.subscription) { | |
this.subscription.unsubscribe(); | |
} | |
} | |
private createPromise( | |
options: { ssr?: boolean } | undefined | |
): [Promise<unknown> | undefined, (val?: unknown) => void | undefined] { | |
let promise: Promise<unknown> | undefined; | |
let resolvePromise: (val?: unknown) => void | undefined; | |
const fastboot = this.getFastboot(); | |
if (fastboot && fastboot.isFastBoot && options && options.ssr !== false) { | |
promise = new Promise((resolve) => { | |
resolvePromise = resolve; | |
}); | |
} | |
return [promise, resolvePromise!]; //eslint-disable-line | |
} | |
private getFastboot(): Fastboot | undefined { | |
return getOwner(this)?.lookup('service:fastboot') as Fastboot; | |
} | |
} | |
export function watchQuery<TData = {}, TVariables = OperationVariables>( | |
...args: WatchQueryResourceArgs<TVariables> | |
): WatchQueryResource<TData>['state'] { | |
return resource< | |
WatchQueryResource<TData>, | |
WatchQueryResource<TData>['state'], | |
WatchQueryResourceArgs<TVariables> | |
>(WatchQueryResource)(...args); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment