@isograph/react 0.1.0 → 0.2.0

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