@isograph/react 0.0.0-main-55364d41 → 0.0.0-main-2c275831
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/PromiseWrapper.js +1 -1
- package/dist/cache.d.ts +4 -4
- package/dist/cache.js +62 -35
- package/dist/componentCache.d.ts +2 -2
- package/dist/componentCache.js +1 -1
- package/dist/index.d.ts +29 -21
- package/dist/index.js +62 -58
- package/package.json +3 -3
- package/src/PromiseWrapper.ts +1 -1
- package/src/cache.ts +102 -87
- package/src/componentCache.ts +4 -8
- package/src/index.tsx +151 -206
package/src/index.tsx
CHANGED
@@ -8,10 +8,10 @@ import {
|
|
8
8
|
onNextChange,
|
9
9
|
getStore,
|
10
10
|
getParentRecordKey,
|
11
|
-
} from
|
12
|
-
import { useLazyDisposableState } from
|
13
|
-
import { type PromiseWrapper } from
|
14
|
-
import { getOrCreateCachedComponent } from
|
11
|
+
} from './cache';
|
12
|
+
import { useLazyDisposableState } from '@isograph/react-disposable-state';
|
13
|
+
import { type PromiseWrapper } from './PromiseWrapper';
|
14
|
+
import { getOrCreateCachedComponent } from './componentCache';
|
15
15
|
|
16
16
|
export {
|
17
17
|
setNetwork,
|
@@ -21,31 +21,19 @@ export {
|
|
21
21
|
Link,
|
22
22
|
StoreRecord,
|
23
23
|
clearStore,
|
24
|
-
} from
|
24
|
+
} from './cache';
|
25
25
|
|
26
26
|
// This type should be treated as an opaque type.
|
27
|
-
export type IsographEntrypoint<
|
28
|
-
|
29
|
-
TResolverProps,
|
30
|
-
TResolverResult
|
31
|
-
> = {
|
32
|
-
kind: "Entrypoint";
|
27
|
+
export type IsographEntrypoint<TReadFromStore extends Object, TResolverProps, TResolverResult> = {
|
28
|
+
kind: 'Entrypoint';
|
33
29
|
queryText: string;
|
34
30
|
normalizationAst: NormalizationAst;
|
35
|
-
readerArtifact: ReaderArtifact<
|
36
|
-
TReadFromStore,
|
37
|
-
TResolverProps,
|
38
|
-
TResolverResult
|
39
|
-
>;
|
31
|
+
readerArtifact: ReaderArtifact<TReadFromStore, TResolverProps, TResolverResult>;
|
40
32
|
nestedRefetchQueries: RefetchQueryArtifactWrapper[];
|
41
33
|
};
|
42
34
|
|
43
|
-
export type ReaderArtifact<
|
44
|
-
|
45
|
-
TResolverProps,
|
46
|
-
TResolverResult
|
47
|
-
> = {
|
48
|
-
kind: "ReaderArtifact";
|
35
|
+
export type ReaderArtifact<TReadFromStore extends Object, TResolverProps, TResolverResult> = {
|
36
|
+
kind: 'ReaderArtifact';
|
49
37
|
readerAst: ReaderAst<TReadFromStore>;
|
50
38
|
resolver: (data: TResolverProps) => TResolverResult;
|
51
39
|
variant: ReaderResolverVariant;
|
@@ -62,13 +50,13 @@ export type ReaderAstNode =
|
|
62
50
|
export type ReaderAst<TReadFromStore> = ReaderAstNode[];
|
63
51
|
|
64
52
|
export type ReaderScalarField = {
|
65
|
-
kind:
|
53
|
+
kind: 'Scalar';
|
66
54
|
fieldName: string;
|
67
55
|
alias: string | null;
|
68
56
|
arguments: Arguments | null;
|
69
57
|
};
|
70
58
|
export type ReaderLinkedField = {
|
71
|
-
kind:
|
59
|
+
kind: 'Linked';
|
72
60
|
fieldName: string;
|
73
61
|
alias: string | null;
|
74
62
|
selections: ReaderAst<unknown>;
|
@@ -76,13 +64,13 @@ export type ReaderLinkedField = {
|
|
76
64
|
};
|
77
65
|
|
78
66
|
export type ReaderResolverVariant =
|
79
|
-
| { kind:
|
67
|
+
| { kind: 'Eager' }
|
80
68
|
// componentName is the component's cacheKey for getRefReaderByName
|
81
69
|
// and is the type + field concatenated
|
82
|
-
| { kind:
|
70
|
+
| { kind: 'Component'; componentName: string };
|
83
71
|
|
84
72
|
export type ReaderResolverField = {
|
85
|
-
kind:
|
73
|
+
kind: 'Resolver';
|
86
74
|
alias: string;
|
87
75
|
readerArtifact: ReaderArtifact<any, any, any>;
|
88
76
|
arguments: Arguments | null;
|
@@ -90,7 +78,7 @@ export type ReaderResolverField = {
|
|
90
78
|
};
|
91
79
|
|
92
80
|
export type ReaderRefetchField = {
|
93
|
-
kind:
|
81
|
+
kind: 'RefetchField';
|
94
82
|
alias: string;
|
95
83
|
// TODO this bad modeling. A refetch field cannot have variant: "Component" (I think)
|
96
84
|
readerArtifact: ReaderArtifact<any, any, any>;
|
@@ -98,7 +86,7 @@ export type ReaderRefetchField = {
|
|
98
86
|
};
|
99
87
|
|
100
88
|
export type ReaderMutationField = {
|
101
|
-
kind:
|
89
|
+
kind: 'MutationField';
|
102
90
|
alias: string;
|
103
91
|
// TODO this bad modeling. A mutation field cannot have variant: "Component" (I think)
|
104
92
|
readerArtifact: ReaderArtifact<any, any, any>;
|
@@ -106,20 +94,18 @@ export type ReaderMutationField = {
|
|
106
94
|
allowedVariables: string[];
|
107
95
|
};
|
108
96
|
|
109
|
-
export type NormalizationAstNode =
|
110
|
-
| NormalizationScalarField
|
111
|
-
| NormalizationLinkedField;
|
97
|
+
export type NormalizationAstNode = NormalizationScalarField | NormalizationLinkedField;
|
112
98
|
// @ts-ignore
|
113
99
|
export type NormalizationAst = NormalizationAstNode[];
|
114
100
|
|
115
101
|
export type NormalizationScalarField = {
|
116
|
-
kind:
|
102
|
+
kind: 'Scalar';
|
117
103
|
fieldName: string;
|
118
104
|
arguments: Arguments | null;
|
119
105
|
};
|
120
106
|
|
121
107
|
export type NormalizationLinkedField = {
|
122
|
-
kind:
|
108
|
+
kind: 'Linked';
|
123
109
|
fieldName: string;
|
124
110
|
arguments: Arguments | null;
|
125
111
|
selections: NormalizationAst;
|
@@ -127,7 +113,7 @@ export type NormalizationLinkedField = {
|
|
127
113
|
|
128
114
|
// This is more like an entrypoint, but one specifically for a refetch query/mutation
|
129
115
|
export type RefetchQueryArtifact = {
|
130
|
-
kind:
|
116
|
+
kind: 'RefetchQuery';
|
131
117
|
queryText: string;
|
132
118
|
normalizationAst: NormalizationAst;
|
133
119
|
};
|
@@ -139,48 +125,37 @@ export type RefetchQueryArtifactWrapper = {
|
|
139
125
|
};
|
140
126
|
|
141
127
|
export type Arguments = Argument[];
|
142
|
-
export type Argument =
|
143
|
-
|
144
|
-
|
145
|
-
|
128
|
+
export type Argument = [ArgumentName, ArgumentValue];
|
129
|
+
export type ArgumentName = string;
|
130
|
+
export type ArgumentValue =
|
131
|
+
| {
|
132
|
+
kind: 'Variable';
|
133
|
+
name: string;
|
134
|
+
}
|
135
|
+
| {
|
136
|
+
kind: 'Literal';
|
137
|
+
value: any;
|
138
|
+
};
|
146
139
|
|
147
|
-
export type FragmentReference<
|
148
|
-
|
149
|
-
TResolverProps,
|
150
|
-
TResolverResult
|
151
|
-
> = {
|
152
|
-
kind: "FragmentReference";
|
153
|
-
readerArtifact: ReaderArtifact<
|
154
|
-
TReadFromStore,
|
155
|
-
TResolverProps,
|
156
|
-
TResolverResult
|
157
|
-
>;
|
140
|
+
export type FragmentReference<TReadFromStore extends Object, TResolverProps, TResolverResult> = {
|
141
|
+
kind: 'FragmentReference';
|
142
|
+
readerArtifact: ReaderArtifact<TReadFromStore, TResolverProps, TResolverResult>;
|
158
143
|
root: DataId;
|
159
144
|
variables: { [index: string]: string } | null;
|
160
145
|
// TODO: We should instead have ReaderAst<TResolverProps>
|
161
146
|
nestedRefetchQueries: RefetchQueryArtifactWrapper[];
|
162
147
|
};
|
163
148
|
|
164
|
-
function assertIsEntrypoint<
|
165
|
-
TReadFromStore
|
166
|
-
|
167
|
-
|
168
|
-
>(
|
169
|
-
value:
|
170
|
-
| IsographEntrypoint<TReadFromStore, TResolverProps, TResolverResult>
|
171
|
-
| typeof iso
|
172
|
-
): asserts value is IsographEntrypoint<
|
173
|
-
TReadFromStore,
|
174
|
-
TResolverProps,
|
175
|
-
TResolverResult
|
176
|
-
> {
|
177
|
-
if (typeof value === "function") throw new Error("Not a string");
|
149
|
+
function assertIsEntrypoint<TReadFromStore extends Object, TResolverProps, TResolverResult>(
|
150
|
+
value: IsographEntrypoint<TReadFromStore, TResolverProps, TResolverResult> | typeof iso,
|
151
|
+
): asserts value is IsographEntrypoint<TReadFromStore, TResolverProps, TResolverResult> {
|
152
|
+
if (typeof value === 'function') throw new Error('Not a string');
|
178
153
|
}
|
179
154
|
|
180
|
-
export function iso<TResolverParameter
|
181
|
-
_queryText: TemplateStringsArray
|
182
|
-
): (
|
183
|
-
x: (param: TResolverParameter) => TResolverReturn
|
155
|
+
export function iso<TResolverParameter>(
|
156
|
+
_queryText: TemplateStringsArray,
|
157
|
+
): <TResolverReturn>(
|
158
|
+
x: (param: TResolverParameter) => TResolverReturn,
|
184
159
|
) => (param: TResolverParameter) => TResolverReturn {
|
185
160
|
// The name `identity` here is a bit of a double entendre.
|
186
161
|
// First, it is the identity function, constrained to operate
|
@@ -190,44 +165,49 @@ export function iso<TResolverParameter, TResolverReturn = TResolverParameter>(
|
|
190
165
|
// is the identity function. At that point, the types
|
191
166
|
// TResolverParameter and TResolverReturn must be identical.
|
192
167
|
|
193
|
-
return function identity(
|
194
|
-
x: (param: TResolverParameter) => TResolverReturn
|
168
|
+
return function identity<TResolverReturn>(
|
169
|
+
x: (param: TResolverParameter) => TResolverReturn,
|
195
170
|
): (param: TResolverParameter) => TResolverReturn {
|
196
171
|
return x;
|
197
172
|
};
|
198
173
|
}
|
199
174
|
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
175
|
+
type ExtractTReadFromStore<Type> = Type extends IsographEntrypoint<infer X, any, any> ? X : never;
|
176
|
+
type ExtractResolverProps<Type> = Type extends IsographEntrypoint<any, infer X, any> ? X : never;
|
177
|
+
type ExtractResolverResult<Type> = Type extends IsographEntrypoint<any, any, infer X> ? X : never;
|
178
|
+
// Note: we cannot write TEntrypoint extends IsographEntrypoint<any, any, any>, or else
|
179
|
+
// if we do not explicitly pass a type, the read out type will be any.
|
180
|
+
// We cannot write TEntrypoint extends IsographEntrypoint<never, never, never>, or else
|
181
|
+
// any actual Entrypoint we pass will not be valid.
|
182
|
+
export function useLazyReference<TEntrypoint>(
|
205
183
|
entrypoint:
|
206
|
-
|
|
207
|
-
|
208
|
-
|
184
|
+
| TEntrypoint
|
185
|
+
// Temporarily, we need to allow useLazyReference to take the result of calling
|
186
|
+
// iso`...`. At runtime, we confirm that the passed-in `iso` literal is actually
|
187
|
+
// an entrypoint.
|
188
|
+
| ((_: any) => any),
|
189
|
+
variables: object,
|
209
190
|
): {
|
210
191
|
queryReference: FragmentReference<
|
211
|
-
|
212
|
-
|
213
|
-
|
192
|
+
ExtractTReadFromStore<TEntrypoint>,
|
193
|
+
ExtractResolverProps<TEntrypoint>,
|
194
|
+
ExtractResolverResult<TEntrypoint>
|
214
195
|
>;
|
215
196
|
} {
|
216
197
|
assertIsEntrypoint(entrypoint);
|
217
198
|
// Typechecking fails here... TODO investigate
|
218
|
-
const cache = getOrCreateCacheForArtifact<
|
199
|
+
const cache = getOrCreateCacheForArtifact<ExtractResolverResult<TEntrypoint>>(
|
219
200
|
entrypoint,
|
220
|
-
variables
|
201
|
+
variables,
|
221
202
|
);
|
222
203
|
|
223
204
|
// TODO add comment explaining why we never use this value
|
224
205
|
// @ts-ignore
|
225
|
-
const data =
|
226
|
-
useLazyDisposableState<PromiseWrapper<TResolverResult>>(cache).state;
|
206
|
+
const data = useLazyDisposableState<PromiseWrapper<TResolverResult>>(cache).state;
|
227
207
|
|
228
208
|
return {
|
229
209
|
queryReference: {
|
230
|
-
kind:
|
210
|
+
kind: 'FragmentReference',
|
231
211
|
readerArtifact: entrypoint.readerArtifact,
|
232
212
|
root: ROOT_ID,
|
233
213
|
variables,
|
@@ -236,57 +216,49 @@ export function useLazyReference<
|
|
236
216
|
};
|
237
217
|
}
|
238
218
|
|
239
|
-
export function read<
|
240
|
-
TReadFromStore
|
241
|
-
TResolverProps,
|
242
|
-
TResolverResult
|
243
|
-
>(
|
244
|
-
fragmentReference: FragmentReference<
|
245
|
-
TReadFromStore,
|
246
|
-
TResolverProps,
|
247
|
-
TResolverResult
|
248
|
-
>
|
219
|
+
export function read<TReadFromStore extends Object, TResolverProps, TResolverResult>(
|
220
|
+
fragmentReference: FragmentReference<TReadFromStore, TResolverProps, TResolverResult>,
|
249
221
|
): TResolverResult {
|
250
222
|
const variant = fragmentReference.readerArtifact.variant;
|
251
|
-
if (variant.kind ===
|
223
|
+
if (variant.kind === 'Eager') {
|
252
224
|
const data = readData(
|
253
225
|
fragmentReference.readerArtifact.readerAst,
|
254
226
|
fragmentReference.root,
|
255
227
|
fragmentReference.variables ?? {},
|
256
|
-
fragmentReference.nestedRefetchQueries
|
228
|
+
fragmentReference.nestedRefetchQueries,
|
257
229
|
);
|
258
|
-
if (data.kind ===
|
230
|
+
if (data.kind === 'MissingData') {
|
259
231
|
throw onNextChange();
|
260
232
|
} else {
|
261
233
|
return fragmentReference.readerArtifact.resolver(data.data);
|
262
234
|
}
|
263
|
-
} else if (variant.kind ===
|
235
|
+
} else if (variant.kind === 'Component') {
|
264
236
|
// @ts-ignore
|
265
237
|
return getOrCreateCachedComponent(
|
266
238
|
fragmentReference.root,
|
267
239
|
variant.componentName,
|
268
240
|
fragmentReference.readerArtifact,
|
269
241
|
fragmentReference.variables ?? {},
|
270
|
-
fragmentReference.nestedRefetchQueries
|
242
|
+
fragmentReference.nestedRefetchQueries,
|
271
243
|
);
|
272
244
|
}
|
273
245
|
// Why can't Typescript realize that this is unreachable??
|
274
|
-
throw new Error(
|
246
|
+
throw new Error('This is unreachable');
|
275
247
|
}
|
276
248
|
|
277
249
|
export function readButDoNotEvaluate<TReadFromStore extends Object>(
|
278
|
-
reference: FragmentReference<TReadFromStore, unknown, unknown
|
250
|
+
reference: FragmentReference<TReadFromStore, unknown, unknown>,
|
279
251
|
): TReadFromStore {
|
280
252
|
const response = readData(
|
281
253
|
reference.readerArtifact.readerAst,
|
282
254
|
reference.root,
|
283
255
|
reference.variables ?? {},
|
284
|
-
reference.nestedRefetchQueries
|
256
|
+
reference.nestedRefetchQueries,
|
285
257
|
);
|
286
|
-
if (typeof window !==
|
287
|
-
console.log(
|
258
|
+
if (typeof window !== 'undefined' && window.__LOG) {
|
259
|
+
console.log('done reading', { response });
|
288
260
|
}
|
289
|
-
if (response.kind ===
|
261
|
+
if (response.kind === 'MissingData') {
|
290
262
|
throw onNextChange();
|
291
263
|
} else {
|
292
264
|
return response.data;
|
@@ -295,11 +267,11 @@ export function readButDoNotEvaluate<TReadFromStore extends Object>(
|
|
295
267
|
|
296
268
|
type ReadDataResult<TReadFromStore> =
|
297
269
|
| {
|
298
|
-
kind:
|
270
|
+
kind: 'Success';
|
299
271
|
data: TReadFromStore;
|
300
272
|
}
|
301
273
|
| {
|
302
|
-
kind:
|
274
|
+
kind: 'MissingData';
|
303
275
|
reason: string;
|
304
276
|
nestedReason?: ReadDataResult<unknown>;
|
305
277
|
};
|
@@ -308,36 +280,36 @@ function readData<TReadFromStore>(
|
|
308
280
|
ast: ReaderAst<TReadFromStore>,
|
309
281
|
root: DataId,
|
310
282
|
variables: { [index: string]: string },
|
311
|
-
nestedRefetchQueries: RefetchQueryArtifactWrapper[]
|
283
|
+
nestedRefetchQueries: RefetchQueryArtifactWrapper[],
|
312
284
|
): ReadDataResult<TReadFromStore> {
|
313
285
|
let storeRecord = getStore()[root];
|
314
286
|
if (storeRecord === undefined) {
|
315
|
-
return { kind:
|
287
|
+
return { kind: 'MissingData', reason: 'No record for root ' + root };
|
316
288
|
}
|
317
289
|
|
318
290
|
if (storeRecord === null) {
|
319
|
-
return { kind:
|
291
|
+
return { kind: 'Success', data: null as any };
|
320
292
|
}
|
321
293
|
|
322
294
|
let target: { [index: string]: any } = {};
|
323
295
|
|
324
296
|
for (const field of ast) {
|
325
297
|
switch (field.kind) {
|
326
|
-
case
|
298
|
+
case 'Scalar': {
|
327
299
|
const storeRecordName = getParentRecordKey(field, variables);
|
328
300
|
const value = storeRecord[storeRecordName];
|
329
301
|
// TODO consider making scalars into discriminated unions. This probably has
|
330
302
|
// to happen for when we handle errors.
|
331
303
|
if (value === undefined) {
|
332
304
|
return {
|
333
|
-
kind:
|
334
|
-
reason:
|
305
|
+
kind: 'MissingData',
|
306
|
+
reason: 'No value for ' + storeRecordName + ' on root ' + root,
|
335
307
|
};
|
336
308
|
}
|
337
309
|
target[field.alias ?? field.fieldName] = value;
|
338
310
|
break;
|
339
311
|
}
|
340
|
-
case
|
312
|
+
case 'Linked': {
|
341
313
|
const storeRecordName = getParentRecordKey(field, variables);
|
342
314
|
const value = storeRecord[storeRecordName];
|
343
315
|
if (Array.isArray(value)) {
|
@@ -346,34 +318,29 @@ function readData<TReadFromStore>(
|
|
346
318
|
const link = assertLink(item);
|
347
319
|
if (link === undefined) {
|
348
320
|
return {
|
349
|
-
kind:
|
321
|
+
kind: 'MissingData',
|
350
322
|
reason:
|
351
|
-
|
323
|
+
'No link for ' +
|
352
324
|
storeRecordName +
|
353
|
-
|
325
|
+
' on root ' +
|
354
326
|
root +
|
355
|
-
|
327
|
+
'. Link is ' +
|
356
328
|
JSON.stringify(item),
|
357
329
|
};
|
358
330
|
} else if (link === null) {
|
359
331
|
results.push(null);
|
360
332
|
continue;
|
361
333
|
}
|
362
|
-
const result = readData(
|
363
|
-
|
364
|
-
link.__link,
|
365
|
-
variables,
|
366
|
-
nestedRefetchQueries
|
367
|
-
);
|
368
|
-
if (result.kind === "MissingData") {
|
334
|
+
const result = readData(field.selections, link.__link, variables, nestedRefetchQueries);
|
335
|
+
if (result.kind === 'MissingData') {
|
369
336
|
return {
|
370
|
-
kind:
|
337
|
+
kind: 'MissingData',
|
371
338
|
reason:
|
372
|
-
|
339
|
+
'Missing data for ' +
|
373
340
|
storeRecordName +
|
374
|
-
|
341
|
+
' on root ' +
|
375
342
|
root +
|
376
|
-
|
343
|
+
'. Link is ' +
|
377
344
|
JSON.stringify(item),
|
378
345
|
nestedReason: result,
|
379
346
|
};
|
@@ -391,17 +358,17 @@ function readData<TReadFromStore>(
|
|
391
358
|
root,
|
392
359
|
field.fieldName,
|
393
360
|
field.arguments,
|
394
|
-
variables
|
361
|
+
variables,
|
395
362
|
);
|
396
363
|
if (altLink === undefined) {
|
397
364
|
return {
|
398
|
-
kind:
|
365
|
+
kind: 'MissingData',
|
399
366
|
reason:
|
400
|
-
|
367
|
+
'No link for ' +
|
401
368
|
storeRecordName +
|
402
|
-
|
369
|
+
' on root ' +
|
403
370
|
root +
|
404
|
-
|
371
|
+
'. Link is ' +
|
405
372
|
JSON.stringify(value),
|
406
373
|
};
|
407
374
|
} else {
|
@@ -412,81 +379,73 @@ function readData<TReadFromStore>(
|
|
412
379
|
break;
|
413
380
|
}
|
414
381
|
const targetId = link.__link;
|
415
|
-
const data = readData(
|
416
|
-
|
417
|
-
targetId,
|
418
|
-
variables,
|
419
|
-
nestedRefetchQueries
|
420
|
-
);
|
421
|
-
if (data.kind === "MissingData") {
|
382
|
+
const data = readData(field.selections, targetId, variables, nestedRefetchQueries);
|
383
|
+
if (data.kind === 'MissingData') {
|
422
384
|
return {
|
423
|
-
kind:
|
424
|
-
reason:
|
385
|
+
kind: 'MissingData',
|
386
|
+
reason: 'Missing data for ' + storeRecordName + ' on root ' + root,
|
425
387
|
nestedReason: data,
|
426
388
|
};
|
427
389
|
}
|
428
390
|
target[field.alias ?? field.fieldName] = data.data;
|
429
391
|
break;
|
430
392
|
}
|
431
|
-
case
|
393
|
+
case 'RefetchField': {
|
432
394
|
const data = readData(
|
433
395
|
field.readerArtifact.readerAst,
|
434
396
|
root,
|
435
397
|
variables,
|
436
398
|
// Refetch fields just read the id, and don't need refetch query artifacts
|
437
|
-
[]
|
399
|
+
[],
|
438
400
|
);
|
439
|
-
if (typeof window !==
|
440
|
-
console.log(
|
401
|
+
if (typeof window !== 'undefined' && window.__LOG) {
|
402
|
+
console.log('refetch field data', data, field);
|
441
403
|
}
|
442
|
-
if (data.kind ===
|
404
|
+
if (data.kind === 'MissingData') {
|
443
405
|
return {
|
444
|
-
kind:
|
445
|
-
reason:
|
406
|
+
kind: 'MissingData',
|
407
|
+
reason: 'Missing data for ' + field.alias + ' on root ' + root,
|
446
408
|
nestedReason: data,
|
447
409
|
};
|
448
410
|
} else {
|
449
411
|
const refetchQueryIndex = field.refetchQuery;
|
450
412
|
if (refetchQueryIndex == null) {
|
451
|
-
throw new Error(
|
413
|
+
throw new Error('refetchQuery is null in RefetchField');
|
452
414
|
}
|
453
415
|
const refetchQuery = nestedRefetchQueries[refetchQueryIndex];
|
454
416
|
const refetchQueryArtifact = refetchQuery.artifact;
|
455
417
|
const allowedVariables = refetchQuery.allowedVariables;
|
456
418
|
|
457
|
-
target[field.alias] = field.readerArtifact.resolver(
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
...filterVariables(variables, allowedVariables),
|
464
|
-
}
|
465
|
-
);
|
419
|
+
target[field.alias] = field.readerArtifact.resolver(refetchQueryArtifact, {
|
420
|
+
...data.data,
|
421
|
+
// TODO continue from here
|
422
|
+
// variables need to be filtered for what we need just for the refetch query
|
423
|
+
...filterVariables(variables, allowedVariables),
|
424
|
+
});
|
466
425
|
}
|
467
426
|
break;
|
468
427
|
}
|
469
|
-
case
|
428
|
+
case 'MutationField': {
|
470
429
|
const data = readData(
|
471
430
|
field.readerArtifact.readerAst,
|
472
431
|
root,
|
473
432
|
variables,
|
474
433
|
// Refetch fields just read the id, and don't need refetch query artifacts
|
475
|
-
[]
|
434
|
+
[],
|
476
435
|
);
|
477
|
-
if (typeof window !==
|
478
|
-
console.log(
|
436
|
+
if (typeof window !== 'undefined' && window.__LOG) {
|
437
|
+
console.log('refetch field data', data, field);
|
479
438
|
}
|
480
|
-
if (data.kind ===
|
439
|
+
if (data.kind === 'MissingData') {
|
481
440
|
return {
|
482
|
-
kind:
|
483
|
-
reason:
|
441
|
+
kind: 'MissingData',
|
442
|
+
reason: 'Missing data for ' + field.alias + ' on root ' + root,
|
484
443
|
nestedReason: data,
|
485
444
|
};
|
486
445
|
} else {
|
487
446
|
const refetchQueryIndex = field.refetchQuery;
|
488
447
|
if (refetchQueryIndex == null) {
|
489
|
-
throw new Error(
|
448
|
+
throw new Error('refetchQuery is null in MutationField');
|
490
449
|
}
|
491
450
|
const refetchQuery = nestedRefetchQueries[refetchQueryIndex];
|
492
451
|
const refetchQueryArtifact = refetchQuery.artifact;
|
@@ -495,48 +454,48 @@ function readData<TReadFromStore>(
|
|
495
454
|
target[field.alias] = field.readerArtifact.resolver(
|
496
455
|
refetchQueryArtifact,
|
497
456
|
data.data,
|
498
|
-
filterVariables(variables, allowedVariables)
|
457
|
+
filterVariables(variables, allowedVariables),
|
499
458
|
);
|
500
459
|
}
|
501
460
|
break;
|
502
461
|
}
|
503
|
-
case
|
462
|
+
case 'Resolver': {
|
504
463
|
const usedRefetchQueries = field.usedRefetchQueries;
|
505
464
|
const resolverRefetchQueries = usedRefetchQueries.map(
|
506
|
-
(index) => nestedRefetchQueries[index]
|
465
|
+
(index) => nestedRefetchQueries[index],
|
507
466
|
);
|
508
467
|
|
509
468
|
const variant = field.readerArtifact.variant;
|
510
|
-
if (variant.kind ===
|
469
|
+
if (variant.kind === 'Eager') {
|
511
470
|
const data = readData(
|
512
471
|
field.readerArtifact.readerAst,
|
513
472
|
root,
|
514
473
|
variables,
|
515
|
-
resolverRefetchQueries
|
474
|
+
resolverRefetchQueries,
|
516
475
|
);
|
517
|
-
if (data.kind ===
|
476
|
+
if (data.kind === 'MissingData') {
|
518
477
|
return {
|
519
|
-
kind:
|
520
|
-
reason:
|
478
|
+
kind: 'MissingData',
|
479
|
+
reason: 'Missing data for ' + field.alias + ' on root ' + root,
|
521
480
|
nestedReason: data,
|
522
481
|
};
|
523
482
|
} else {
|
524
483
|
target[field.alias] = field.readerArtifact.resolver(data.data);
|
525
484
|
}
|
526
|
-
} else if (variant.kind ===
|
485
|
+
} else if (variant.kind === 'Component') {
|
527
486
|
target[field.alias] = getOrCreateCachedComponent(
|
528
487
|
root,
|
529
488
|
variant.componentName,
|
530
489
|
field.readerArtifact,
|
531
490
|
variables,
|
532
|
-
resolverRefetchQueries
|
491
|
+
resolverRefetchQueries,
|
533
492
|
);
|
534
493
|
}
|
535
494
|
break;
|
536
495
|
}
|
537
496
|
}
|
538
497
|
}
|
539
|
-
return { kind:
|
498
|
+
return { kind: 'Success', data: target as any };
|
540
499
|
}
|
541
500
|
|
542
501
|
let customMissingFieldHandler: typeof defaultMissingFieldHandler | null = null;
|
@@ -546,24 +505,12 @@ function missingFieldHandler(
|
|
546
505
|
root: DataId,
|
547
506
|
fieldName: string,
|
548
507
|
arguments_: { [index: string]: any } | null,
|
549
|
-
variables: { [index: string]: any } | null
|
508
|
+
variables: { [index: string]: any } | null,
|
550
509
|
): Link | undefined {
|
551
510
|
if (customMissingFieldHandler != null) {
|
552
|
-
return customMissingFieldHandler(
|
553
|
-
storeRecord,
|
554
|
-
root,
|
555
|
-
fieldName,
|
556
|
-
arguments_,
|
557
|
-
variables
|
558
|
-
);
|
511
|
+
return customMissingFieldHandler(storeRecord, root, fieldName, arguments_, variables);
|
559
512
|
} else {
|
560
|
-
return defaultMissingFieldHandler(
|
561
|
-
storeRecord,
|
562
|
-
root,
|
563
|
-
fieldName,
|
564
|
-
arguments_,
|
565
|
-
variables
|
566
|
-
);
|
513
|
+
return defaultMissingFieldHandler(storeRecord, root, fieldName, arguments_, variables);
|
567
514
|
}
|
568
515
|
}
|
569
516
|
|
@@ -572,10 +519,10 @@ export function defaultMissingFieldHandler(
|
|
572
519
|
root: DataId,
|
573
520
|
fieldName: string,
|
574
521
|
arguments_: { [index: string]: any } | null,
|
575
|
-
variables: { [index: string]: any } | null
|
522
|
+
variables: { [index: string]: any } | null,
|
576
523
|
): Link | undefined {
|
577
|
-
if (fieldName ===
|
578
|
-
const variable = arguments_?.[
|
524
|
+
if (fieldName === 'node' || fieldName === 'user') {
|
525
|
+
const variable = arguments_?.['id'];
|
579
526
|
const value = variables?.[variable];
|
580
527
|
|
581
528
|
// TODO can we handle explicit nulls here too? Probably, after wrapping in objects
|
@@ -585,23 +532,21 @@ export function defaultMissingFieldHandler(
|
|
585
532
|
}
|
586
533
|
}
|
587
534
|
|
588
|
-
export function setMissingFieldHandler(
|
589
|
-
handler: typeof defaultMissingFieldHandler
|
590
|
-
) {
|
535
|
+
export function setMissingFieldHandler(handler: typeof defaultMissingFieldHandler) {
|
591
536
|
customMissingFieldHandler = handler;
|
592
537
|
}
|
593
538
|
|
594
539
|
function assertLink(link: DataTypeValue): Link | undefined | null {
|
595
540
|
if (Array.isArray(link)) {
|
596
|
-
throw new Error(
|
541
|
+
throw new Error('Unexpected array');
|
597
542
|
}
|
598
|
-
if (typeof link ===
|
543
|
+
if (typeof link === 'object') {
|
599
544
|
return link;
|
600
545
|
}
|
601
546
|
if (link === undefined) {
|
602
547
|
return undefined;
|
603
548
|
}
|
604
|
-
throw new Error(
|
549
|
+
throw new Error('Invalid link');
|
605
550
|
}
|
606
551
|
|
607
552
|
export type IsographComponentProps<TDataType, TOtherProps = Object> = {
|
@@ -610,7 +555,7 @@ export type IsographComponentProps<TDataType, TOtherProps = Object> = {
|
|
610
555
|
|
611
556
|
function filterVariables(
|
612
557
|
variables: { [index: string]: string },
|
613
|
-
allowedVariables: string[]
|
558
|
+
allowedVariables: string[],
|
614
559
|
): { [index: string]: string } {
|
615
560
|
const result: { [index: string]: string } = {};
|
616
561
|
for (const key of allowedVariables) {
|