-
Notifications
You must be signed in to change notification settings - Fork 464
/
Copy pathqueryStore.ts
189 lines (179 loc) · 5.26 KB
/
queryStore.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
import {
Client,
GraphQLRequestParams,
AnyVariables,
OperationContext,
RequestPolicy,
createRequest,
} from '@urql/core';
import {
Source,
pipe,
map,
fromValue,
switchMap,
subscribe,
concat,
scan,
never,
} from 'wonka';
import { derived, writable } from 'svelte/store';
import {
OperationResultState,
OperationResultStore,
Pausable,
initialResult,
createPausable,
fromStore,
} from './common';
/** Input arguments for the {@link queryStore} function.
*
* @param query - The GraphQL query that the `queryStore` executes.
* @param variables - The variables for the GraphQL query that `queryStore` executes.
*/
export type QueryArgs<
Data = any,
Variables extends AnyVariables = AnyVariables
> = {
/** The {@link Client} using which the query will be executed.
*
* @remarks
* If you’ve previously provided a {@link Client} on Svelte’s context
* this can be set to {@link getContextClient}’s return value.
*/
client: Client;
/** Updates the {@link OperationContext} for the executed GraphQL query operation.
*
* @remarks
* `context` may be passed to {@link queryStore}, to update the {@link OperationContext}
* of a query operation. This may be used to update the `context` that exchanges
* will receive for a single hook.
*
* @example
* ```ts
* queryStore({
* query,
* context: {
* additionalTypenames: ['Item'],
* },
* });
* ```
*/
context?: Partial<OperationContext>;
/** Sets the {@link RequestPolicy} for the executed GraphQL query operation.
*
* @remarks
* `requestPolicy` modifies the {@link RequestPolicy} of the GraphQL query operation
* that the {@link queryStore} executes, and indicates a caching strategy for cache exchanges.
*
* For example, when set to `'cache-and-network'`, the `queryStore` will
* receive a cached result with `stale: true` and an API request will be
* sent in the background.
*
* @see {@link OperationContext.requestPolicy} for where this value is set.
*/
requestPolicy?: RequestPolicy;
/** Prevents the {@link queryStore} from automatically executing GraphQL query operations.
*
* @remarks
* `pause` may be set to `true` to stop the {@link queryStore} from executing
* automatically. The store will stop receiving updates from the {@link Client}
* and won’t execute the query operation, until either it’s set to `false`
* or {@link Pausable.resume} is called.
*
* @see {@link https://urql.dev/goto/docs/basics/svelte#pausing-queries} for
* documentation on the `pause` option.
*/
pause?: boolean;
} & GraphQLRequestParams<Data, Variables>;
/** Function to create a `queryStore` that runs a GraphQL query and updates with GraphQL results.
*
* @param args - a {@link QueryArgs} object, to pass a `query`, `variables`, and options.
* @returns a {@link OperationResultStore} of query results, which implements {@link Pausable}.
*
* @remarks
* `queryStore` allows GraphQL queries to be defined as Svelte stores.
* Given {@link QueryArgs.query}, it executes the GraphQL query on the
* {@link QueryArgs.client}.
*
* The returned store updates with {@link OperationResult} values when
* the `Client` has new results for the query.
*
* @see {@link https://urql.dev/goto/docs/basics/svelte#queries} for `queryStore` docs.
*
* @example
* ```ts
* import { queryStore, gql, getContextClient } from '@urql/svelte';
*
* const todos = queryStore({
* client: getContextClient(),
* query: gql`{ todos { id, title } }`,
* });
* ```
*/
export function queryStore<
Data = any,
Variables extends AnyVariables = AnyVariables
>(
args: QueryArgs<Data, Variables>
): OperationResultStore<Data, Variables> & Pausable {
const request = createRequest(args.query, args.variables as Variables);
const context: Partial<OperationContext> = {
requestPolicy: args.requestPolicy,
...args.context,
};
const operation = args.client.createRequestOperation(
'query',
request,
context
);
const initialState: OperationResultState<Data, Variables> = {
...initialResult,
operation,
};
const result$ = writable(initialState, () => {
return subscription.unsubscribe;
});
const isPaused$ = writable(!!args.pause);
const subscription = pipe(
fromStore(isPaused$),
switchMap(
(isPaused): Source<Partial<OperationResultState<Data, Variables>>> => {
if (isPaused) {
return never as any;
}
return concat<Partial<OperationResultState<Data, Variables>>>([
fromValue({ fetching: true, stale: false }),
pipe(
args.client.executeRequestOperation(operation),
map(({ stale, data, error, extensions, operation }) => ({
fetching: false,
stale: !!stale,
data,
error,
operation,
extensions,
}))
),
fromValue({ fetching: false }),
]);
}
),
scan(
(result: OperationResultState<Data, Variables>, partial) => ({
...result,
...partial,
}),
initialState
),
subscribe(result => {
result$.set(result);
})
);
return {
...derived(result$, (result, set) => {
set(result);
}),
...createPausable(isPaused$),
};
}