-
-
Save ispyinternet/05372d2963b301108c43a9447c578e43 to your computer and use it in GitHub Desktop.
query.ts
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 { pipe, fromValue, concat, map, subscribe } from 'wonka'; | |
import { DocumentNode } from 'graphql'; | |
import { request$, Request$ } from './request'; | |
import { context$, Context$ } from './context'; | |
import { source$ } from './source'; | |
import { derived, writable, Writable, Readable } from 'svelte/store'; | |
import { OperationContext, RequestPolicy } from '@urql/core'; | |
export interface QueryArgs { | |
query: string | DocumentNode; | |
variables?: object; | |
requestPolicy?: RequestPolicy; | |
pollInterval?: number; | |
context?: Partial<OperationContext>; | |
pause?: boolean; | |
} | |
const initialState: Partial<ResultStore<any>> = { | |
fetching: false, | |
stale: false, | |
error: undefined, | |
data: undefined, | |
extensions: undefined, | |
operation: undefined, | |
}; | |
export interface ResultStore<T> { | |
fetching: boolean; | |
stale: boolean; | |
error: any; | |
data: T; | |
extensions: any; | |
operation: any; | |
} | |
export type ExecuteQueryFunction = (args: Partial<QueryArgs>) => void; | |
export interface Query$<T> extends Readable<Partial<ResultStore<T>>> { | |
reexecute: ExecuteQueryFunction; | |
} | |
/** | |
* query store - readable is result of query source | |
* bind method allows to bind query, variables and context to template vars | |
* reexecuteQuery method programatically triggers a new query | |
*/ | |
export function query<T>(args: QueryArgs): Query$<T> { | |
// create our context store | |
const context = { | |
...args.context, | |
...{ pollInterval: args.pollInterval, requestPolicy: args.requestPolicy }, | |
}; | |
const context$$: Context$ = context$(context); | |
// create our request store | |
const variables = { ...args.variables }; | |
const request$$: Request$ = request$(args.query, variables); | |
// create our source store - derived by request and context | |
const source$$ = source$<T>(request$$, context$$); | |
// pause store. | |
const pause$: Writable<boolean> = writable(!!args.pause); | |
// results store. | |
const { subscribe, update } = writable(initialState, () => { | |
// subscribe to the changes store - which will trigger updates on this store | |
// return the unsubscribe function which should hopefully clean up! | |
return changes.subscribe(() => {}); // need to satify typescript. | |
}); | |
// if source or pause changes then change query / state | |
const changes = derived( | |
[source$$, pause$], | |
([source, pause], set) => { | |
// for some reason typescript wants this store value to be typeof ResultState | |
set(initialState); | |
if (pause) { | |
update(state => ({ ...state, ...{ fetching: false, stale: false } })); | |
} else { | |
// re-run the source query and update the results store, | |
// return the wonka unsubscribe function - this ensures any previous wonka | |
// streams are unsubscribed from | |
return run(source, update); | |
} | |
}, | |
initialState | |
); | |
/** | |
* // in the template the user can reexeute the query, for example: | |
* let query, nextToken, pollInterval, requestPolicy, context; | |
* export let numResults; | |
* | |
* // if any of the variables change, either from external or within reexecute | |
* $: query.reexecute({ query, variables: { nextToken, numResults }, requestPolicy, pollInterval, context }) | |
*/ | |
const reexecute = args => { | |
if (args.query) request$$.setQuery(args.query); | |
if (args.variables) request$$.setVars(args.variables); | |
if ('pause' in args) pause$.set(!!args.pause); | |
const context = { | |
...args.context, | |
...{ | |
pollInterval: args.pollInterval, | |
requestPolicy: args.requestPolicy, | |
}, | |
}; | |
context$$.set(context); | |
}; | |
return { | |
subscribe, | |
reexecute, | |
}; | |
} | |
function run(source, update) { | |
return pipe( | |
concat([ | |
fromValue({ fetching: true, stale: false }), | |
pipe( | |
source, | |
map((result: object) => ({ fetching: false, ...result })) | |
), | |
fromValue({ fetching: false, stale: false }), | |
]), | |
subscribe(result => update(state => ({ ...state, ...result }))) | |
)[0]; // return unsubscribe function | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment