@isograph/react 0.0.0-main-1cd3db6d → 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 +30 -35
- package/dist/componentCache.d.ts +2 -2
- package/dist/componentCache.js +1 -1
- package/dist/index.d.ts +23 -20
- package/dist/index.js +62 -58
- package/package.json +3 -3
- package/src/PromiseWrapper.ts +1 -1
- package/src/cache.ts +65 -92
- package/src/componentCache.ts +4 -8
- package/src/index.tsx +142 -204
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
|
};
|
@@ -143,51 +129,33 @@ export type Argument = [ArgumentName, ArgumentValue];
|
|
143
129
|
export type ArgumentName = string;
|
144
130
|
export type ArgumentValue =
|
145
131
|
| {
|
146
|
-
kind:
|
132
|
+
kind: 'Variable';
|
147
133
|
name: string;
|
148
134
|
}
|
149
135
|
| {
|
150
|
-
kind:
|
136
|
+
kind: 'Literal';
|
151
137
|
value: any;
|
152
138
|
};
|
153
139
|
|
154
|
-
export type FragmentReference<
|
155
|
-
|
156
|
-
TResolverProps,
|
157
|
-
TResolverResult
|
158
|
-
> = {
|
159
|
-
kind: "FragmentReference";
|
160
|
-
readerArtifact: ReaderArtifact<
|
161
|
-
TReadFromStore,
|
162
|
-
TResolverProps,
|
163
|
-
TResolverResult
|
164
|
-
>;
|
140
|
+
export type FragmentReference<TReadFromStore extends Object, TResolverProps, TResolverResult> = {
|
141
|
+
kind: 'FragmentReference';
|
142
|
+
readerArtifact: ReaderArtifact<TReadFromStore, TResolverProps, TResolverResult>;
|
165
143
|
root: DataId;
|
166
144
|
variables: { [index: string]: string } | null;
|
167
145
|
// TODO: We should instead have ReaderAst<TResolverProps>
|
168
146
|
nestedRefetchQueries: RefetchQueryArtifactWrapper[];
|
169
147
|
};
|
170
148
|
|
171
|
-
function assertIsEntrypoint<
|
172
|
-
TReadFromStore
|
173
|
-
|
174
|
-
|
175
|
-
>(
|
176
|
-
value:
|
177
|
-
| IsographEntrypoint<TReadFromStore, TResolverProps, TResolverResult>
|
178
|
-
| typeof iso
|
179
|
-
): asserts value is IsographEntrypoint<
|
180
|
-
TReadFromStore,
|
181
|
-
TResolverProps,
|
182
|
-
TResolverResult
|
183
|
-
> {
|
184
|
-
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');
|
185
153
|
}
|
186
154
|
|
187
|
-
export function iso<TResolverParameter
|
188
|
-
_queryText: TemplateStringsArray
|
189
|
-
): (
|
190
|
-
x: (param: TResolverParameter) => TResolverReturn
|
155
|
+
export function iso<TResolverParameter>(
|
156
|
+
_queryText: TemplateStringsArray,
|
157
|
+
): <TResolverReturn>(
|
158
|
+
x: (param: TResolverParameter) => TResolverReturn,
|
191
159
|
) => (param: TResolverParameter) => TResolverReturn {
|
192
160
|
// The name `identity` here is a bit of a double entendre.
|
193
161
|
// First, it is the identity function, constrained to operate
|
@@ -197,44 +165,49 @@ export function iso<TResolverParameter, TResolverReturn = TResolverParameter>(
|
|
197
165
|
// is the identity function. At that point, the types
|
198
166
|
// TResolverParameter and TResolverReturn must be identical.
|
199
167
|
|
200
|
-
return function identity(
|
201
|
-
x: (param: TResolverParameter) => TResolverReturn
|
168
|
+
return function identity<TResolverReturn>(
|
169
|
+
x: (param: TResolverParameter) => TResolverReturn,
|
202
170
|
): (param: TResolverParameter) => TResolverReturn {
|
203
171
|
return x;
|
204
172
|
};
|
205
173
|
}
|
206
174
|
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
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>(
|
212
183
|
entrypoint:
|
213
|
-
|
|
214
|
-
|
215
|
-
|
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,
|
216
190
|
): {
|
217
191
|
queryReference: FragmentReference<
|
218
|
-
|
219
|
-
|
220
|
-
|
192
|
+
ExtractTReadFromStore<TEntrypoint>,
|
193
|
+
ExtractResolverProps<TEntrypoint>,
|
194
|
+
ExtractResolverResult<TEntrypoint>
|
221
195
|
>;
|
222
196
|
} {
|
223
197
|
assertIsEntrypoint(entrypoint);
|
224
198
|
// Typechecking fails here... TODO investigate
|
225
|
-
const cache = getOrCreateCacheForArtifact<
|
199
|
+
const cache = getOrCreateCacheForArtifact<ExtractResolverResult<TEntrypoint>>(
|
226
200
|
entrypoint,
|
227
|
-
variables
|
201
|
+
variables,
|
228
202
|
);
|
229
203
|
|
230
204
|
// TODO add comment explaining why we never use this value
|
231
205
|
// @ts-ignore
|
232
|
-
const data =
|
233
|
-
useLazyDisposableState<PromiseWrapper<TResolverResult>>(cache).state;
|
206
|
+
const data = useLazyDisposableState<PromiseWrapper<TResolverResult>>(cache).state;
|
234
207
|
|
235
208
|
return {
|
236
209
|
queryReference: {
|
237
|
-
kind:
|
210
|
+
kind: 'FragmentReference',
|
238
211
|
readerArtifact: entrypoint.readerArtifact,
|
239
212
|
root: ROOT_ID,
|
240
213
|
variables,
|
@@ -243,57 +216,49 @@ export function useLazyReference<
|
|
243
216
|
};
|
244
217
|
}
|
245
218
|
|
246
|
-
export function read<
|
247
|
-
TReadFromStore
|
248
|
-
TResolverProps,
|
249
|
-
TResolverResult
|
250
|
-
>(
|
251
|
-
fragmentReference: FragmentReference<
|
252
|
-
TReadFromStore,
|
253
|
-
TResolverProps,
|
254
|
-
TResolverResult
|
255
|
-
>
|
219
|
+
export function read<TReadFromStore extends Object, TResolverProps, TResolverResult>(
|
220
|
+
fragmentReference: FragmentReference<TReadFromStore, TResolverProps, TResolverResult>,
|
256
221
|
): TResolverResult {
|
257
222
|
const variant = fragmentReference.readerArtifact.variant;
|
258
|
-
if (variant.kind ===
|
223
|
+
if (variant.kind === 'Eager') {
|
259
224
|
const data = readData(
|
260
225
|
fragmentReference.readerArtifact.readerAst,
|
261
226
|
fragmentReference.root,
|
262
227
|
fragmentReference.variables ?? {},
|
263
|
-
fragmentReference.nestedRefetchQueries
|
228
|
+
fragmentReference.nestedRefetchQueries,
|
264
229
|
);
|
265
|
-
if (data.kind ===
|
230
|
+
if (data.kind === 'MissingData') {
|
266
231
|
throw onNextChange();
|
267
232
|
} else {
|
268
233
|
return fragmentReference.readerArtifact.resolver(data.data);
|
269
234
|
}
|
270
|
-
} else if (variant.kind ===
|
235
|
+
} else if (variant.kind === 'Component') {
|
271
236
|
// @ts-ignore
|
272
237
|
return getOrCreateCachedComponent(
|
273
238
|
fragmentReference.root,
|
274
239
|
variant.componentName,
|
275
240
|
fragmentReference.readerArtifact,
|
276
241
|
fragmentReference.variables ?? {},
|
277
|
-
fragmentReference.nestedRefetchQueries
|
242
|
+
fragmentReference.nestedRefetchQueries,
|
278
243
|
);
|
279
244
|
}
|
280
245
|
// Why can't Typescript realize that this is unreachable??
|
281
|
-
throw new Error(
|
246
|
+
throw new Error('This is unreachable');
|
282
247
|
}
|
283
248
|
|
284
249
|
export function readButDoNotEvaluate<TReadFromStore extends Object>(
|
285
|
-
reference: FragmentReference<TReadFromStore, unknown, unknown
|
250
|
+
reference: FragmentReference<TReadFromStore, unknown, unknown>,
|
286
251
|
): TReadFromStore {
|
287
252
|
const response = readData(
|
288
253
|
reference.readerArtifact.readerAst,
|
289
254
|
reference.root,
|
290
255
|
reference.variables ?? {},
|
291
|
-
reference.nestedRefetchQueries
|
256
|
+
reference.nestedRefetchQueries,
|
292
257
|
);
|
293
|
-
if (typeof window !==
|
294
|
-
console.log(
|
258
|
+
if (typeof window !== 'undefined' && window.__LOG) {
|
259
|
+
console.log('done reading', { response });
|
295
260
|
}
|
296
|
-
if (response.kind ===
|
261
|
+
if (response.kind === 'MissingData') {
|
297
262
|
throw onNextChange();
|
298
263
|
} else {
|
299
264
|
return response.data;
|
@@ -302,11 +267,11 @@ export function readButDoNotEvaluate<TReadFromStore extends Object>(
|
|
302
267
|
|
303
268
|
type ReadDataResult<TReadFromStore> =
|
304
269
|
| {
|
305
|
-
kind:
|
270
|
+
kind: 'Success';
|
306
271
|
data: TReadFromStore;
|
307
272
|
}
|
308
273
|
| {
|
309
|
-
kind:
|
274
|
+
kind: 'MissingData';
|
310
275
|
reason: string;
|
311
276
|
nestedReason?: ReadDataResult<unknown>;
|
312
277
|
};
|
@@ -315,36 +280,36 @@ function readData<TReadFromStore>(
|
|
315
280
|
ast: ReaderAst<TReadFromStore>,
|
316
281
|
root: DataId,
|
317
282
|
variables: { [index: string]: string },
|
318
|
-
nestedRefetchQueries: RefetchQueryArtifactWrapper[]
|
283
|
+
nestedRefetchQueries: RefetchQueryArtifactWrapper[],
|
319
284
|
): ReadDataResult<TReadFromStore> {
|
320
285
|
let storeRecord = getStore()[root];
|
321
286
|
if (storeRecord === undefined) {
|
322
|
-
return { kind:
|
287
|
+
return { kind: 'MissingData', reason: 'No record for root ' + root };
|
323
288
|
}
|
324
289
|
|
325
290
|
if (storeRecord === null) {
|
326
|
-
return { kind:
|
291
|
+
return { kind: 'Success', data: null as any };
|
327
292
|
}
|
328
293
|
|
329
294
|
let target: { [index: string]: any } = {};
|
330
295
|
|
331
296
|
for (const field of ast) {
|
332
297
|
switch (field.kind) {
|
333
|
-
case
|
298
|
+
case 'Scalar': {
|
334
299
|
const storeRecordName = getParentRecordKey(field, variables);
|
335
300
|
const value = storeRecord[storeRecordName];
|
336
301
|
// TODO consider making scalars into discriminated unions. This probably has
|
337
302
|
// to happen for when we handle errors.
|
338
303
|
if (value === undefined) {
|
339
304
|
return {
|
340
|
-
kind:
|
341
|
-
reason:
|
305
|
+
kind: 'MissingData',
|
306
|
+
reason: 'No value for ' + storeRecordName + ' on root ' + root,
|
342
307
|
};
|
343
308
|
}
|
344
309
|
target[field.alias ?? field.fieldName] = value;
|
345
310
|
break;
|
346
311
|
}
|
347
|
-
case
|
312
|
+
case 'Linked': {
|
348
313
|
const storeRecordName = getParentRecordKey(field, variables);
|
349
314
|
const value = storeRecord[storeRecordName];
|
350
315
|
if (Array.isArray(value)) {
|
@@ -353,34 +318,29 @@ function readData<TReadFromStore>(
|
|
353
318
|
const link = assertLink(item);
|
354
319
|
if (link === undefined) {
|
355
320
|
return {
|
356
|
-
kind:
|
321
|
+
kind: 'MissingData',
|
357
322
|
reason:
|
358
|
-
|
323
|
+
'No link for ' +
|
359
324
|
storeRecordName +
|
360
|
-
|
325
|
+
' on root ' +
|
361
326
|
root +
|
362
|
-
|
327
|
+
'. Link is ' +
|
363
328
|
JSON.stringify(item),
|
364
329
|
};
|
365
330
|
} else if (link === null) {
|
366
331
|
results.push(null);
|
367
332
|
continue;
|
368
333
|
}
|
369
|
-
const result = readData(
|
370
|
-
|
371
|
-
link.__link,
|
372
|
-
variables,
|
373
|
-
nestedRefetchQueries
|
374
|
-
);
|
375
|
-
if (result.kind === "MissingData") {
|
334
|
+
const result = readData(field.selections, link.__link, variables, nestedRefetchQueries);
|
335
|
+
if (result.kind === 'MissingData') {
|
376
336
|
return {
|
377
|
-
kind:
|
337
|
+
kind: 'MissingData',
|
378
338
|
reason:
|
379
|
-
|
339
|
+
'Missing data for ' +
|
380
340
|
storeRecordName +
|
381
|
-
|
341
|
+
' on root ' +
|
382
342
|
root +
|
383
|
-
|
343
|
+
'. Link is ' +
|
384
344
|
JSON.stringify(item),
|
385
345
|
nestedReason: result,
|
386
346
|
};
|
@@ -398,17 +358,17 @@ function readData<TReadFromStore>(
|
|
398
358
|
root,
|
399
359
|
field.fieldName,
|
400
360
|
field.arguments,
|
401
|
-
variables
|
361
|
+
variables,
|
402
362
|
);
|
403
363
|
if (altLink === undefined) {
|
404
364
|
return {
|
405
|
-
kind:
|
365
|
+
kind: 'MissingData',
|
406
366
|
reason:
|
407
|
-
|
367
|
+
'No link for ' +
|
408
368
|
storeRecordName +
|
409
|
-
|
369
|
+
' on root ' +
|
410
370
|
root +
|
411
|
-
|
371
|
+
'. Link is ' +
|
412
372
|
JSON.stringify(value),
|
413
373
|
};
|
414
374
|
} else {
|
@@ -419,81 +379,73 @@ function readData<TReadFromStore>(
|
|
419
379
|
break;
|
420
380
|
}
|
421
381
|
const targetId = link.__link;
|
422
|
-
const data = readData(
|
423
|
-
|
424
|
-
targetId,
|
425
|
-
variables,
|
426
|
-
nestedRefetchQueries
|
427
|
-
);
|
428
|
-
if (data.kind === "MissingData") {
|
382
|
+
const data = readData(field.selections, targetId, variables, nestedRefetchQueries);
|
383
|
+
if (data.kind === 'MissingData') {
|
429
384
|
return {
|
430
|
-
kind:
|
431
|
-
reason:
|
385
|
+
kind: 'MissingData',
|
386
|
+
reason: 'Missing data for ' + storeRecordName + ' on root ' + root,
|
432
387
|
nestedReason: data,
|
433
388
|
};
|
434
389
|
}
|
435
390
|
target[field.alias ?? field.fieldName] = data.data;
|
436
391
|
break;
|
437
392
|
}
|
438
|
-
case
|
393
|
+
case 'RefetchField': {
|
439
394
|
const data = readData(
|
440
395
|
field.readerArtifact.readerAst,
|
441
396
|
root,
|
442
397
|
variables,
|
443
398
|
// Refetch fields just read the id, and don't need refetch query artifacts
|
444
|
-
[]
|
399
|
+
[],
|
445
400
|
);
|
446
|
-
if (typeof window !==
|
447
|
-
console.log(
|
401
|
+
if (typeof window !== 'undefined' && window.__LOG) {
|
402
|
+
console.log('refetch field data', data, field);
|
448
403
|
}
|
449
|
-
if (data.kind ===
|
404
|
+
if (data.kind === 'MissingData') {
|
450
405
|
return {
|
451
|
-
kind:
|
452
|
-
reason:
|
406
|
+
kind: 'MissingData',
|
407
|
+
reason: 'Missing data for ' + field.alias + ' on root ' + root,
|
453
408
|
nestedReason: data,
|
454
409
|
};
|
455
410
|
} else {
|
456
411
|
const refetchQueryIndex = field.refetchQuery;
|
457
412
|
if (refetchQueryIndex == null) {
|
458
|
-
throw new Error(
|
413
|
+
throw new Error('refetchQuery is null in RefetchField');
|
459
414
|
}
|
460
415
|
const refetchQuery = nestedRefetchQueries[refetchQueryIndex];
|
461
416
|
const refetchQueryArtifact = refetchQuery.artifact;
|
462
417
|
const allowedVariables = refetchQuery.allowedVariables;
|
463
418
|
|
464
|
-
target[field.alias] = field.readerArtifact.resolver(
|
465
|
-
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
...filterVariables(variables, allowedVariables),
|
471
|
-
}
|
472
|
-
);
|
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
|
+
});
|
473
425
|
}
|
474
426
|
break;
|
475
427
|
}
|
476
|
-
case
|
428
|
+
case 'MutationField': {
|
477
429
|
const data = readData(
|
478
430
|
field.readerArtifact.readerAst,
|
479
431
|
root,
|
480
432
|
variables,
|
481
433
|
// Refetch fields just read the id, and don't need refetch query artifacts
|
482
|
-
[]
|
434
|
+
[],
|
483
435
|
);
|
484
|
-
if (typeof window !==
|
485
|
-
console.log(
|
436
|
+
if (typeof window !== 'undefined' && window.__LOG) {
|
437
|
+
console.log('refetch field data', data, field);
|
486
438
|
}
|
487
|
-
if (data.kind ===
|
439
|
+
if (data.kind === 'MissingData') {
|
488
440
|
return {
|
489
|
-
kind:
|
490
|
-
reason:
|
441
|
+
kind: 'MissingData',
|
442
|
+
reason: 'Missing data for ' + field.alias + ' on root ' + root,
|
491
443
|
nestedReason: data,
|
492
444
|
};
|
493
445
|
} else {
|
494
446
|
const refetchQueryIndex = field.refetchQuery;
|
495
447
|
if (refetchQueryIndex == null) {
|
496
|
-
throw new Error(
|
448
|
+
throw new Error('refetchQuery is null in MutationField');
|
497
449
|
}
|
498
450
|
const refetchQuery = nestedRefetchQueries[refetchQueryIndex];
|
499
451
|
const refetchQueryArtifact = refetchQuery.artifact;
|
@@ -502,48 +454,48 @@ function readData<TReadFromStore>(
|
|
502
454
|
target[field.alias] = field.readerArtifact.resolver(
|
503
455
|
refetchQueryArtifact,
|
504
456
|
data.data,
|
505
|
-
filterVariables(variables, allowedVariables)
|
457
|
+
filterVariables(variables, allowedVariables),
|
506
458
|
);
|
507
459
|
}
|
508
460
|
break;
|
509
461
|
}
|
510
|
-
case
|
462
|
+
case 'Resolver': {
|
511
463
|
const usedRefetchQueries = field.usedRefetchQueries;
|
512
464
|
const resolverRefetchQueries = usedRefetchQueries.map(
|
513
|
-
(index) => nestedRefetchQueries[index]
|
465
|
+
(index) => nestedRefetchQueries[index],
|
514
466
|
);
|
515
467
|
|
516
468
|
const variant = field.readerArtifact.variant;
|
517
|
-
if (variant.kind ===
|
469
|
+
if (variant.kind === 'Eager') {
|
518
470
|
const data = readData(
|
519
471
|
field.readerArtifact.readerAst,
|
520
472
|
root,
|
521
473
|
variables,
|
522
|
-
resolverRefetchQueries
|
474
|
+
resolverRefetchQueries,
|
523
475
|
);
|
524
|
-
if (data.kind ===
|
476
|
+
if (data.kind === 'MissingData') {
|
525
477
|
return {
|
526
|
-
kind:
|
527
|
-
reason:
|
478
|
+
kind: 'MissingData',
|
479
|
+
reason: 'Missing data for ' + field.alias + ' on root ' + root,
|
528
480
|
nestedReason: data,
|
529
481
|
};
|
530
482
|
} else {
|
531
483
|
target[field.alias] = field.readerArtifact.resolver(data.data);
|
532
484
|
}
|
533
|
-
} else if (variant.kind ===
|
485
|
+
} else if (variant.kind === 'Component') {
|
534
486
|
target[field.alias] = getOrCreateCachedComponent(
|
535
487
|
root,
|
536
488
|
variant.componentName,
|
537
489
|
field.readerArtifact,
|
538
490
|
variables,
|
539
|
-
resolverRefetchQueries
|
491
|
+
resolverRefetchQueries,
|
540
492
|
);
|
541
493
|
}
|
542
494
|
break;
|
543
495
|
}
|
544
496
|
}
|
545
497
|
}
|
546
|
-
return { kind:
|
498
|
+
return { kind: 'Success', data: target as any };
|
547
499
|
}
|
548
500
|
|
549
501
|
let customMissingFieldHandler: typeof defaultMissingFieldHandler | null = null;
|
@@ -553,24 +505,12 @@ function missingFieldHandler(
|
|
553
505
|
root: DataId,
|
554
506
|
fieldName: string,
|
555
507
|
arguments_: { [index: string]: any } | null,
|
556
|
-
variables: { [index: string]: any } | null
|
508
|
+
variables: { [index: string]: any } | null,
|
557
509
|
): Link | undefined {
|
558
510
|
if (customMissingFieldHandler != null) {
|
559
|
-
return customMissingFieldHandler(
|
560
|
-
storeRecord,
|
561
|
-
root,
|
562
|
-
fieldName,
|
563
|
-
arguments_,
|
564
|
-
variables
|
565
|
-
);
|
511
|
+
return customMissingFieldHandler(storeRecord, root, fieldName, arguments_, variables);
|
566
512
|
} else {
|
567
|
-
return defaultMissingFieldHandler(
|
568
|
-
storeRecord,
|
569
|
-
root,
|
570
|
-
fieldName,
|
571
|
-
arguments_,
|
572
|
-
variables
|
573
|
-
);
|
513
|
+
return defaultMissingFieldHandler(storeRecord, root, fieldName, arguments_, variables);
|
574
514
|
}
|
575
515
|
}
|
576
516
|
|
@@ -579,10 +519,10 @@ export function defaultMissingFieldHandler(
|
|
579
519
|
root: DataId,
|
580
520
|
fieldName: string,
|
581
521
|
arguments_: { [index: string]: any } | null,
|
582
|
-
variables: { [index: string]: any } | null
|
522
|
+
variables: { [index: string]: any } | null,
|
583
523
|
): Link | undefined {
|
584
|
-
if (fieldName ===
|
585
|
-
const variable = arguments_?.[
|
524
|
+
if (fieldName === 'node' || fieldName === 'user') {
|
525
|
+
const variable = arguments_?.['id'];
|
586
526
|
const value = variables?.[variable];
|
587
527
|
|
588
528
|
// TODO can we handle explicit nulls here too? Probably, after wrapping in objects
|
@@ -592,23 +532,21 @@ export function defaultMissingFieldHandler(
|
|
592
532
|
}
|
593
533
|
}
|
594
534
|
|
595
|
-
export function setMissingFieldHandler(
|
596
|
-
handler: typeof defaultMissingFieldHandler
|
597
|
-
) {
|
535
|
+
export function setMissingFieldHandler(handler: typeof defaultMissingFieldHandler) {
|
598
536
|
customMissingFieldHandler = handler;
|
599
537
|
}
|
600
538
|
|
601
539
|
function assertLink(link: DataTypeValue): Link | undefined | null {
|
602
540
|
if (Array.isArray(link)) {
|
603
|
-
throw new Error(
|
541
|
+
throw new Error('Unexpected array');
|
604
542
|
}
|
605
|
-
if (typeof link ===
|
543
|
+
if (typeof link === 'object') {
|
606
544
|
return link;
|
607
545
|
}
|
608
546
|
if (link === undefined) {
|
609
547
|
return undefined;
|
610
548
|
}
|
611
|
-
throw new Error(
|
549
|
+
throw new Error('Invalid link');
|
612
550
|
}
|
613
551
|
|
614
552
|
export type IsographComponentProps<TDataType, TOtherProps = Object> = {
|
@@ -617,7 +555,7 @@ export type IsographComponentProps<TDataType, TOtherProps = Object> = {
|
|
617
555
|
|
618
556
|
function filterVariables(
|
619
557
|
variables: { [index: string]: string },
|
620
|
-
allowedVariables: string[]
|
558
|
+
allowedVariables: string[],
|
621
559
|
): { [index: string]: string } {
|
622
560
|
const result: { [index: string]: string } = {};
|
623
561
|
for (const key of allowedVariables) {
|