@isograph/react 0.3.0 → 0.4.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.
- package/.turbo/turbo-compile-libs.log +5 -0
- package/dist/core/FragmentReference.d.ts +17 -8
- package/dist/core/FragmentReference.d.ts.map +1 -1
- package/dist/core/FragmentReference.js +3 -12
- package/dist/core/IsographEnvironment.d.ts +30 -35
- package/dist/core/IsographEnvironment.d.ts.map +1 -1
- package/dist/core/IsographEnvironment.js +4 -0
- package/dist/core/PromiseWrapper.d.ts +6 -7
- package/dist/core/PromiseWrapper.d.ts.map +1 -1
- package/dist/core/PromiseWrapper.js +6 -12
- package/dist/core/areEqualWithDeepComparison.d.ts +1 -3
- package/dist/core/areEqualWithDeepComparison.d.ts.map +1 -1
- package/dist/core/areEqualWithDeepComparison.js +16 -2
- package/dist/core/brand.d.ts +2 -0
- package/dist/core/brand.d.ts.map +1 -0
- package/dist/core/brand.js +2 -0
- package/dist/core/cache.d.ts +16 -24
- package/dist/core/cache.d.ts.map +1 -1
- package/dist/core/cache.js +105 -72
- package/dist/core/check.d.ts +11 -7
- package/dist/core/check.d.ts.map +1 -1
- package/dist/core/check.js +2 -2
- package/dist/core/componentCache.d.ts +1 -1
- package/dist/core/componentCache.d.ts.map +1 -1
- package/dist/core/componentCache.js +27 -31
- package/dist/core/entrypoint.d.ts +43 -28
- package/dist/core/entrypoint.d.ts.map +1 -1
- package/dist/core/garbageCollection.d.ts +5 -6
- package/dist/core/garbageCollection.d.ts.map +1 -1
- package/dist/core/garbageCollection.js +1 -1
- package/dist/core/logging.d.ts +23 -15
- package/dist/core/logging.d.ts.map +1 -1
- package/dist/core/logging.js +8 -5
- package/dist/core/makeNetworkRequest.d.ts +5 -5
- package/dist/core/makeNetworkRequest.d.ts.map +1 -1
- package/dist/core/makeNetworkRequest.js +113 -28
- package/dist/core/read.d.ts +16 -11
- package/dist/core/read.d.ts.map +1 -1
- package/dist/core/read.js +468 -305
- package/dist/core/reader.d.ts +33 -37
- package/dist/core/reader.d.ts.map +1 -1
- package/dist/core/startUpdate.d.ts +8 -0
- package/dist/core/startUpdate.d.ts.map +1 -0
- package/dist/core/startUpdate.js +163 -0
- package/dist/core/util.d.ts +3 -0
- package/dist/core/util.d.ts.map +1 -1
- package/dist/index.d.ts +18 -15
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -1
- package/dist/loadable-hooks/useClientSideDefer.d.ts +4 -10
- package/dist/loadable-hooks/useClientSideDefer.d.ts.map +1 -1
- package/dist/loadable-hooks/useClientSideDefer.js +2 -2
- package/dist/loadable-hooks/useConnectionSpecPagination.d.ts +8 -15
- package/dist/loadable-hooks/useConnectionSpecPagination.d.ts.map +1 -1
- package/dist/loadable-hooks/useConnectionSpecPagination.js +6 -4
- package/dist/loadable-hooks/useImperativeExposedMutationField.d.ts +1 -2
- package/dist/loadable-hooks/useImperativeExposedMutationField.d.ts.map +1 -1
- package/dist/loadable-hooks/useImperativeLoadableField.d.ts +4 -6
- package/dist/loadable-hooks/useImperativeLoadableField.d.ts.map +1 -1
- package/dist/loadable-hooks/useImperativeLoadableField.js +1 -1
- package/dist/loadable-hooks/useSkipLimitPagination.d.ts +6 -13
- package/dist/loadable-hooks/useSkipLimitPagination.d.ts.map +1 -1
- package/dist/loadable-hooks/useSkipLimitPagination.js +11 -9
- package/dist/react/FragmentReader.d.ts +7 -14
- package/dist/react/FragmentReader.d.ts.map +1 -1
- package/dist/react/FragmentReader.js +3 -30
- package/dist/react/FragmentRenderer.d.ts +15 -0
- package/dist/react/FragmentRenderer.d.ts.map +1 -0
- package/dist/react/FragmentRenderer.js +35 -0
- package/dist/react/IsographEnvironmentProvider.d.ts.map +1 -1
- package/dist/react/LoadableFieldReader.d.ts +12 -0
- package/dist/react/LoadableFieldReader.d.ts.map +1 -0
- package/dist/react/LoadableFieldReader.js +10 -0
- package/dist/react/LoadableFieldRenderer.d.ts +13 -0
- package/dist/react/LoadableFieldRenderer.d.ts.map +1 -0
- package/dist/react/LoadableFieldRenderer.js +37 -0
- package/dist/react/useImperativeReference.d.ts +7 -10
- package/dist/react/useImperativeReference.d.ts.map +1 -1
- package/dist/react/useImperativeReference.js +8 -9
- package/dist/react/useLazyReference.d.ts +4 -7
- package/dist/react/useLazyReference.d.ts.map +1 -1
- package/dist/react/useLazyReference.js +26 -5
- package/dist/react/useReadAndSubscribe.d.ts +3 -9
- package/dist/react/useReadAndSubscribe.d.ts.map +1 -1
- package/dist/react/useReadAndSubscribe.js +7 -3
- package/dist/react/useRerenderOnChange.d.ts +1 -1
- package/dist/react/useRerenderOnChange.d.ts.map +1 -1
- package/dist/react/useResult.d.ts +3 -6
- package/dist/react/useResult.d.ts.map +1 -1
- package/dist/react/useResult.js +10 -8
- package/isograph.config.json +1 -0
- package/package.json +6 -6
- package/src/core/FragmentReference.ts +40 -16
- package/src/core/IsographEnvironment.ts +57 -39
- package/src/core/PromiseWrapper.ts +15 -18
- package/src/core/areEqualWithDeepComparison.ts +22 -2
- package/src/core/brand.ts +18 -0
- package/src/core/cache.ts +153 -113
- package/src/core/check.ts +17 -12
- package/src/core/componentCache.ts +47 -50
- package/src/core/entrypoint.ts +66 -21
- package/src/core/garbageCollection.ts +9 -9
- package/src/core/logging.ts +39 -25
- package/src/core/makeNetworkRequest.ts +212 -34
- package/src/core/read.ts +728 -440
- package/src/core/reader.ts +46 -29
- package/src/core/startUpdate.ts +334 -0
- package/src/core/util.ts +4 -0
- package/src/index.ts +89 -8
- package/src/loadable-hooks/useClientSideDefer.ts +11 -10
- package/src/loadable-hooks/useConnectionSpecPagination.ts +27 -13
- package/src/loadable-hooks/useImperativeExposedMutationField.ts +1 -1
- package/src/loadable-hooks/useImperativeLoadableField.ts +10 -12
- package/src/loadable-hooks/useSkipLimitPagination.ts +38 -19
- package/src/react/FragmentReader.tsx +23 -39
- package/src/react/FragmentRenderer.tsx +46 -0
- package/src/react/IsographEnvironmentProvider.tsx +1 -1
- package/src/react/LoadableFieldReader.tsx +40 -0
- package/src/react/LoadableFieldRenderer.tsx +41 -0
- package/src/react/useImperativeReference.ts +49 -27
- package/src/react/useLazyReference.ts +62 -14
- package/src/react/useReadAndSubscribe.ts +17 -9
- package/src/react/useRerenderOnChange.ts +2 -2
- package/src/react/useResult.ts +22 -8
- package/src/tests/__isograph/Economist/link/output_type.ts +2 -0
- package/src/tests/__isograph/Node/asEconomist/resolver_reader.ts +28 -0
- package/src/tests/__isograph/Node/link/output_type.ts +3 -0
- package/src/tests/__isograph/Query/linkedUpdate/entrypoint.ts +31 -0
- package/src/tests/__isograph/Query/linkedUpdate/normalization_ast.ts +95 -0
- package/src/tests/__isograph/Query/linkedUpdate/output_type.ts +3 -0
- package/src/tests/__isograph/Query/linkedUpdate/param_type.ts +51 -0
- package/src/tests/__isograph/Query/linkedUpdate/query_text.ts +20 -0
- package/src/tests/__isograph/Query/linkedUpdate/resolver_reader.ts +93 -0
- package/src/tests/__isograph/Query/meName/entrypoint.ts +8 -29
- package/src/tests/__isograph/Query/meName/normalization_ast.ts +25 -0
- package/src/tests/__isograph/Query/meName/query_text.ts +6 -0
- package/src/tests/__isograph/Query/meName/resolver_reader.ts +5 -0
- package/src/tests/__isograph/Query/meNameSuccessor/entrypoint.ts +8 -67
- package/src/tests/__isograph/Query/meNameSuccessor/normalization_ast.ts +56 -0
- package/src/tests/__isograph/Query/meNameSuccessor/query_text.ts +13 -0
- package/src/tests/__isograph/Query/meNameSuccessor/resolver_reader.ts +10 -0
- package/src/tests/__isograph/Query/nodeField/entrypoint.ts +8 -34
- package/src/tests/__isograph/Query/nodeField/normalization_ast.ts +30 -0
- package/src/tests/__isograph/Query/nodeField/query_text.ts +6 -0
- package/src/tests/__isograph/Query/nodeField/resolver_reader.ts +5 -0
- package/src/tests/__isograph/Query/startUpdate/entrypoint.ts +31 -0
- package/src/tests/__isograph/Query/startUpdate/normalization_ast.ts +51 -0
- package/src/tests/__isograph/Query/startUpdate/output_type.ts +3 -0
- package/src/tests/__isograph/Query/startUpdate/param_type.ts +26 -0
- package/src/tests/__isograph/Query/startUpdate/parameters_type.ts +3 -0
- package/src/tests/__isograph/Query/startUpdate/query_text.ts +11 -0
- package/src/tests/__isograph/Query/startUpdate/resolver_reader.ts +55 -0
- package/src/tests/__isograph/Query/subquery/entrypoint.ts +8 -44
- package/src/tests/__isograph/Query/subquery/normalization_ast.ts +38 -0
- package/src/tests/__isograph/Query/subquery/query_text.ts +8 -0
- package/src/tests/__isograph/Query/subquery/resolver_reader.ts +7 -0
- package/src/tests/__isograph/iso.ts +24 -3
- package/src/tests/__isograph/tsconfig.json +8 -0
- package/src/tests/garbageCollection.test.ts +10 -8
- package/src/tests/meNameSuccessor.ts +1 -1
- package/src/tests/nodeQuery.ts +2 -1
- package/src/tests/normalizeData.test.ts +1 -2
- package/src/tests/startUpdate.test.ts +205 -0
- package/tsconfig.pkg.json +1 -2
package/src/core/read.ts
CHANGED
|
@@ -1,39 +1,51 @@
|
|
|
1
|
+
import { CleanupFn, type ItemCleanupPair } from '@isograph/disposable-types';
|
|
1
2
|
import {
|
|
2
3
|
getParentRecordKey,
|
|
3
|
-
|
|
4
|
+
insertEmptySetIfMissing,
|
|
4
5
|
onNextChangeToRecord,
|
|
5
6
|
type EncounteredIds,
|
|
6
7
|
} from './cache';
|
|
8
|
+
import { FetchOptions } from './check';
|
|
7
9
|
import { getOrCreateCachedComponent } from './componentCache';
|
|
8
10
|
import {
|
|
9
11
|
IsographEntrypoint,
|
|
10
12
|
RefetchQueryNormalizationArtifactWrapper,
|
|
13
|
+
type ReaderWithRefetchQueries,
|
|
11
14
|
} from './entrypoint';
|
|
12
15
|
import {
|
|
16
|
+
ExtractData,
|
|
13
17
|
FragmentReference,
|
|
14
18
|
Variables,
|
|
15
|
-
|
|
16
|
-
ExtractParameters,
|
|
19
|
+
type UnknownTReadFromStore,
|
|
17
20
|
} from './FragmentReference';
|
|
18
21
|
import {
|
|
19
22
|
assertLink,
|
|
20
23
|
getOrLoadIsographArtifact,
|
|
21
24
|
IsographEnvironment,
|
|
22
|
-
type
|
|
25
|
+
type DataTypeValue,
|
|
26
|
+
type StoreLink,
|
|
27
|
+
type StoreRecord,
|
|
23
28
|
} from './IsographEnvironment';
|
|
29
|
+
import { logMessage } from './logging';
|
|
24
30
|
import { maybeMakeNetworkRequest } from './makeNetworkRequest';
|
|
25
31
|
import {
|
|
26
32
|
getPromiseState,
|
|
33
|
+
NOT_SET,
|
|
27
34
|
PromiseWrapper,
|
|
28
35
|
readPromise,
|
|
29
36
|
wrapPromise,
|
|
30
37
|
wrapResolvedValue,
|
|
31
38
|
} from './PromiseWrapper';
|
|
32
|
-
import {
|
|
39
|
+
import {
|
|
40
|
+
ReaderAst,
|
|
41
|
+
type LoadablySelectedField,
|
|
42
|
+
type ReaderImperativelyLoadedField,
|
|
43
|
+
type ReaderLinkedField,
|
|
44
|
+
type ReaderNonLoadableResolverField,
|
|
45
|
+
type ReaderScalarField,
|
|
46
|
+
} from './reader';
|
|
47
|
+
import { getOrCreateCachedStartUpdate } from './startUpdate';
|
|
33
48
|
import { Arguments } from './util';
|
|
34
|
-
import { logMessage } from './logging';
|
|
35
|
-
import { CleanupFn } from '@isograph/disposable-types';
|
|
36
|
-
import { FetchOptions } from './check';
|
|
37
49
|
|
|
38
50
|
export type WithEncounteredRecords<T> = {
|
|
39
51
|
readonly encounteredRecords: EncounteredIds;
|
|
@@ -41,7 +53,7 @@ export type WithEncounteredRecords<T> = {
|
|
|
41
53
|
};
|
|
42
54
|
|
|
43
55
|
export function readButDoNotEvaluate<
|
|
44
|
-
TReadFromStore extends
|
|
56
|
+
TReadFromStore extends UnknownTReadFromStore,
|
|
45
57
|
>(
|
|
46
58
|
environment: IsographEnvironment,
|
|
47
59
|
fragmentReference: FragmentReference<TReadFromStore, unknown>,
|
|
@@ -49,6 +61,7 @@ export function readButDoNotEvaluate<
|
|
|
49
61
|
): WithEncounteredRecords<TReadFromStore> {
|
|
50
62
|
const mutableEncounteredRecords: EncounteredIds = new Map();
|
|
51
63
|
|
|
64
|
+
// TODO consider moving this to the outside
|
|
52
65
|
const readerWithRefetchQueries = readPromise(
|
|
53
66
|
fragmentReference.readerWithRefetchQueries,
|
|
54
67
|
);
|
|
@@ -64,14 +77,16 @@ export function readButDoNotEvaluate<
|
|
|
64
77
|
mutableEncounteredRecords,
|
|
65
78
|
);
|
|
66
79
|
|
|
67
|
-
logMessage(environment, {
|
|
80
|
+
logMessage(environment, () => ({
|
|
68
81
|
kind: 'DoneReading',
|
|
69
82
|
response,
|
|
70
|
-
|
|
83
|
+
fieldName: readerWithRefetchQueries.readerArtifact.fieldName,
|
|
84
|
+
root: fragmentReference.root,
|
|
85
|
+
}));
|
|
71
86
|
|
|
72
87
|
if (response.kind === 'MissingData') {
|
|
73
88
|
// There are two cases here that we care about:
|
|
74
|
-
// 1. the network request is in flight, we haven't
|
|
89
|
+
// 1. the network request is in flight, we haven't suspended on it, and we want
|
|
75
90
|
// to throw if it errors out. So, networkRequestOptions.suspendIfInFlight === false
|
|
76
91
|
// and networkRequestOptions.throwOnNetworkError === true.
|
|
77
92
|
// 2. everything else
|
|
@@ -83,7 +98,17 @@ export function readButDoNotEvaluate<
|
|
|
83
98
|
!networkRequestOptions.suspendIfInFlight &&
|
|
84
99
|
networkRequestOptions.throwOnNetworkError
|
|
85
100
|
) {
|
|
86
|
-
//
|
|
101
|
+
// What are we doing here? If the network response has errored out, we can do
|
|
102
|
+
// two things: throw a rejected promise, or throw an error. Both work identically
|
|
103
|
+
// in the browser. However, during initial SSR on NextJS, throwing a rejected
|
|
104
|
+
// promise results in an infinite loop (including re-issuing the query until the
|
|
105
|
+
// process OOM's or something.) Hence, we throw an error.
|
|
106
|
+
|
|
107
|
+
const result = fragmentReference.networkRequest.result;
|
|
108
|
+
if (result !== NOT_SET && result.kind === 'Err') {
|
|
109
|
+
throw new Error('NetworkError', { cause: result.error });
|
|
110
|
+
}
|
|
111
|
+
|
|
87
112
|
throw new Promise((resolve, reject) => {
|
|
88
113
|
onNextChangeToRecord(environment, response.recordLink).then(resolve);
|
|
89
114
|
fragmentReference.networkRequest.promise.catch(reject);
|
|
@@ -98,30 +123,31 @@ export function readButDoNotEvaluate<
|
|
|
98
123
|
}
|
|
99
124
|
}
|
|
100
125
|
|
|
101
|
-
export type
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
126
|
+
export type ReadDataResultSuccess<Data> = {
|
|
127
|
+
readonly kind: 'Success';
|
|
128
|
+
readonly data: Data;
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
export type ReadDataResult<Data> =
|
|
132
|
+
| ReadDataResultSuccess<Data>
|
|
107
133
|
| {
|
|
108
134
|
readonly kind: 'MissingData';
|
|
109
135
|
readonly reason: string;
|
|
110
136
|
readonly nestedReason?: ReadDataResult<unknown>;
|
|
111
|
-
readonly recordLink:
|
|
137
|
+
readonly recordLink: StoreLink;
|
|
112
138
|
};
|
|
113
139
|
|
|
114
140
|
function readData<TReadFromStore>(
|
|
115
141
|
environment: IsographEnvironment,
|
|
116
142
|
ast: ReaderAst<TReadFromStore>,
|
|
117
|
-
root:
|
|
118
|
-
variables:
|
|
143
|
+
root: StoreLink,
|
|
144
|
+
variables: Variables,
|
|
119
145
|
nestedRefetchQueries: RefetchQueryNormalizationArtifactWrapper[],
|
|
120
146
|
networkRequest: PromiseWrapper<void, any>,
|
|
121
147
|
networkRequestOptions: NetworkRequestReaderOptions,
|
|
122
148
|
mutableEncounteredRecords: EncounteredIds,
|
|
123
|
-
): ReadDataResult<TReadFromStore
|
|
124
|
-
const encounteredIds =
|
|
149
|
+
): ReadDataResult<ExtractData<TReadFromStore>> {
|
|
150
|
+
const encounteredIds = insertEmptySetIfMissing(
|
|
125
151
|
mutableEncounteredRecords,
|
|
126
152
|
root.__typename,
|
|
127
153
|
);
|
|
@@ -139,7 +165,6 @@ function readData<TReadFromStore>(
|
|
|
139
165
|
return {
|
|
140
166
|
kind: 'Success',
|
|
141
167
|
data: null as any,
|
|
142
|
-
encounteredRecords: mutableEncounteredRecords,
|
|
143
168
|
};
|
|
144
169
|
}
|
|
145
170
|
|
|
@@ -148,156 +173,51 @@ function readData<TReadFromStore>(
|
|
|
148
173
|
for (const field of ast) {
|
|
149
174
|
switch (field.kind) {
|
|
150
175
|
case 'Scalar': {
|
|
151
|
-
const
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
if (value === undefined) {
|
|
156
|
-
return {
|
|
157
|
-
kind: 'MissingData',
|
|
158
|
-
reason:
|
|
159
|
-
'No value for ' + storeRecordName + ' on root ' + root.__link,
|
|
160
|
-
recordLink: root,
|
|
161
|
-
};
|
|
176
|
+
const data = readScalarFieldData(field, storeRecord, root, variables);
|
|
177
|
+
|
|
178
|
+
if (data.kind === 'MissingData') {
|
|
179
|
+
return data;
|
|
162
180
|
}
|
|
163
|
-
target[field.alias ?? field.fieldName] =
|
|
181
|
+
target[field.alias ?? field.fieldName] = data.data;
|
|
182
|
+
break;
|
|
183
|
+
}
|
|
184
|
+
case 'Link': {
|
|
185
|
+
target[field.alias] = root;
|
|
164
186
|
break;
|
|
165
187
|
}
|
|
166
188
|
case 'Linked': {
|
|
167
|
-
const
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
storeRecordName +
|
|
179
|
-
' on root ' +
|
|
180
|
-
root.__link +
|
|
181
|
-
'. Link is ' +
|
|
182
|
-
JSON.stringify(item),
|
|
183
|
-
recordLink: root,
|
|
184
|
-
};
|
|
185
|
-
} else if (link === null) {
|
|
186
|
-
results.push(null);
|
|
187
|
-
continue;
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
const result = readData(
|
|
189
|
+
const data = readLinkedFieldData(
|
|
190
|
+
environment,
|
|
191
|
+
field,
|
|
192
|
+
storeRecord,
|
|
193
|
+
root,
|
|
194
|
+
variables,
|
|
195
|
+
nestedRefetchQueries,
|
|
196
|
+
networkRequest,
|
|
197
|
+
networkRequestOptions,
|
|
198
|
+
(ast, root) =>
|
|
199
|
+
readData(
|
|
191
200
|
environment,
|
|
192
|
-
|
|
193
|
-
|
|
201
|
+
ast,
|
|
202
|
+
root,
|
|
194
203
|
variables,
|
|
195
204
|
nestedRefetchQueries,
|
|
196
205
|
networkRequest,
|
|
197
206
|
networkRequestOptions,
|
|
198
207
|
mutableEncounteredRecords,
|
|
199
|
-
)
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
reason:
|
|
204
|
-
'Missing data for ' +
|
|
205
|
-
storeRecordName +
|
|
206
|
-
' on root ' +
|
|
207
|
-
root.__link +
|
|
208
|
-
'. Link is ' +
|
|
209
|
-
JSON.stringify(item),
|
|
210
|
-
nestedReason: result,
|
|
211
|
-
recordLink: result.recordLink,
|
|
212
|
-
};
|
|
213
|
-
}
|
|
214
|
-
results.push(result.data);
|
|
215
|
-
}
|
|
216
|
-
target[field.alias ?? field.fieldName] = results;
|
|
217
|
-
break;
|
|
218
|
-
}
|
|
219
|
-
let link = assertLink(value);
|
|
220
|
-
|
|
221
|
-
if (field.condition) {
|
|
222
|
-
const data = readData(
|
|
223
|
-
environment,
|
|
224
|
-
field.condition.readerAst,
|
|
225
|
-
root,
|
|
226
|
-
variables,
|
|
227
|
-
nestedRefetchQueries,
|
|
228
|
-
networkRequest,
|
|
229
|
-
networkRequestOptions,
|
|
230
|
-
mutableEncounteredRecords,
|
|
231
|
-
);
|
|
232
|
-
if (data.kind === 'MissingData') {
|
|
233
|
-
return {
|
|
234
|
-
kind: 'MissingData',
|
|
235
|
-
reason:
|
|
236
|
-
'Missing data for ' +
|
|
237
|
-
storeRecordName +
|
|
238
|
-
' on root ' +
|
|
239
|
-
root.__link,
|
|
240
|
-
nestedReason: data,
|
|
241
|
-
recordLink: data.recordLink,
|
|
242
|
-
};
|
|
243
|
-
}
|
|
244
|
-
const condition = field.condition.resolver({
|
|
245
|
-
data: data.data,
|
|
246
|
-
parameters: {},
|
|
247
|
-
});
|
|
248
|
-
if (condition === true) {
|
|
249
|
-
link = root;
|
|
250
|
-
} else if (condition === false) {
|
|
251
|
-
link = null;
|
|
252
|
-
} else {
|
|
253
|
-
link = condition;
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
if (link === undefined) {
|
|
258
|
-
// TODO make this configurable, and also generated and derived from the schema
|
|
259
|
-
const missingFieldHandler = environment.missingFieldHandler;
|
|
260
|
-
|
|
261
|
-
const altLink = missingFieldHandler?.(
|
|
262
|
-
storeRecord,
|
|
263
|
-
root,
|
|
264
|
-
field.fieldName,
|
|
265
|
-
field.arguments,
|
|
266
|
-
variables,
|
|
267
|
-
);
|
|
268
|
-
logMessage(environment, {
|
|
269
|
-
kind: 'MissingFieldHandlerCalled',
|
|
270
|
-
root,
|
|
271
|
-
storeRecord,
|
|
272
|
-
fieldName: field.fieldName,
|
|
273
|
-
arguments: field.arguments,
|
|
274
|
-
variables,
|
|
275
|
-
});
|
|
276
|
-
|
|
277
|
-
if (altLink === undefined) {
|
|
278
|
-
return {
|
|
279
|
-
kind: 'MissingData',
|
|
280
|
-
reason:
|
|
281
|
-
'No link for ' +
|
|
282
|
-
storeRecordName +
|
|
283
|
-
' on root ' +
|
|
284
|
-
root.__link +
|
|
285
|
-
'. Link is ' +
|
|
286
|
-
JSON.stringify(value),
|
|
287
|
-
recordLink: root,
|
|
288
|
-
};
|
|
289
|
-
} else {
|
|
290
|
-
link = altLink;
|
|
291
|
-
}
|
|
292
|
-
} else if (link === null) {
|
|
293
|
-
target[field.alias ?? field.fieldName] = null;
|
|
294
|
-
break;
|
|
208
|
+
),
|
|
209
|
+
);
|
|
210
|
+
if (data.kind === 'MissingData') {
|
|
211
|
+
return data;
|
|
295
212
|
}
|
|
296
|
-
|
|
297
|
-
|
|
213
|
+
target[field.alias ?? field.fieldName] = data.data;
|
|
214
|
+
break;
|
|
215
|
+
}
|
|
216
|
+
case 'ImperativelyLoadedField': {
|
|
217
|
+
const data = readImperativelyLoadedField(
|
|
298
218
|
environment,
|
|
299
|
-
field
|
|
300
|
-
|
|
219
|
+
field,
|
|
220
|
+
root,
|
|
301
221
|
variables,
|
|
302
222
|
nestedRefetchQueries,
|
|
303
223
|
networkRequest,
|
|
@@ -305,306 +225,45 @@ function readData<TReadFromStore>(
|
|
|
305
225
|
mutableEncounteredRecords,
|
|
306
226
|
);
|
|
307
227
|
if (data.kind === 'MissingData') {
|
|
308
|
-
return
|
|
309
|
-
kind: 'MissingData',
|
|
310
|
-
reason:
|
|
311
|
-
'Missing data for ' + storeRecordName + ' on root ' + root.__link,
|
|
312
|
-
nestedReason: data,
|
|
313
|
-
recordLink: data.recordLink,
|
|
314
|
-
};
|
|
228
|
+
return data;
|
|
315
229
|
}
|
|
316
|
-
target[field.alias
|
|
230
|
+
target[field.alias] = data.data;
|
|
317
231
|
break;
|
|
318
232
|
}
|
|
319
|
-
case '
|
|
320
|
-
|
|
321
|
-
// id field).
|
|
322
|
-
const data = readData(
|
|
233
|
+
case 'Resolver': {
|
|
234
|
+
const data = readResolverFieldData(
|
|
323
235
|
environment,
|
|
324
|
-
field
|
|
236
|
+
field,
|
|
325
237
|
root,
|
|
326
238
|
variables,
|
|
327
|
-
|
|
328
|
-
[],
|
|
329
|
-
// This is probably indicative of the fact that we are doing redundant checks
|
|
330
|
-
// on the status of this network request...
|
|
239
|
+
nestedRefetchQueries,
|
|
331
240
|
networkRequest,
|
|
332
241
|
networkRequestOptions,
|
|
333
242
|
mutableEncounteredRecords,
|
|
334
243
|
);
|
|
335
244
|
if (data.kind === 'MissingData') {
|
|
336
|
-
return
|
|
337
|
-
kind: 'MissingData',
|
|
338
|
-
reason:
|
|
339
|
-
'Missing data for ' + field.alias + ' on root ' + root.__link,
|
|
340
|
-
nestedReason: data,
|
|
341
|
-
recordLink: data.recordLink,
|
|
342
|
-
};
|
|
343
|
-
} else {
|
|
344
|
-
const refetchQueryIndex = field.refetchQuery;
|
|
345
|
-
const refetchQuery = nestedRefetchQueries[refetchQueryIndex];
|
|
346
|
-
if (refetchQuery == null) {
|
|
347
|
-
throw new Error(
|
|
348
|
-
'refetchQuery is null in RefetchField. This is indicative of a bug in Isograph.',
|
|
349
|
-
);
|
|
350
|
-
}
|
|
351
|
-
const refetchQueryArtifact = refetchQuery.artifact;
|
|
352
|
-
const allowedVariables = refetchQuery.allowedVariables;
|
|
353
|
-
|
|
354
|
-
// Second, we allow the user to call the resolver, which will ultimately
|
|
355
|
-
// use the resolver reader AST to get the resolver parameters.
|
|
356
|
-
target[field.alias] = (args: any) => [
|
|
357
|
-
// Stable id
|
|
358
|
-
root.__link + '__' + field.name,
|
|
359
|
-
// Fetcher
|
|
360
|
-
field.refetchReaderArtifact.resolver(
|
|
361
|
-
environment,
|
|
362
|
-
refetchQueryArtifact,
|
|
363
|
-
data.data,
|
|
364
|
-
filterVariables({ ...args, ...variables }, allowedVariables),
|
|
365
|
-
root,
|
|
366
|
-
// TODO these params should be removed
|
|
367
|
-
null,
|
|
368
|
-
[],
|
|
369
|
-
),
|
|
370
|
-
];
|
|
371
|
-
}
|
|
372
|
-
break;
|
|
373
|
-
}
|
|
374
|
-
case 'Resolver': {
|
|
375
|
-
const usedRefetchQueries = field.usedRefetchQueries;
|
|
376
|
-
const resolverRefetchQueries = usedRefetchQueries.map((index) => {
|
|
377
|
-
const resolverRefetchQuery = nestedRefetchQueries[index];
|
|
378
|
-
if (resolverRefetchQuery == null) {
|
|
379
|
-
throw new Error(
|
|
380
|
-
'resolverRefetchQuery is null in Resolver. This is indicative of a bug in Isograph.',
|
|
381
|
-
);
|
|
382
|
-
}
|
|
383
|
-
return resolverRefetchQuery;
|
|
384
|
-
});
|
|
385
|
-
|
|
386
|
-
switch (field.readerArtifact.kind) {
|
|
387
|
-
case 'EagerReaderArtifact': {
|
|
388
|
-
const data = readData(
|
|
389
|
-
environment,
|
|
390
|
-
field.readerArtifact.readerAst,
|
|
391
|
-
root,
|
|
392
|
-
generateChildVariableMap(variables, field.arguments),
|
|
393
|
-
resolverRefetchQueries,
|
|
394
|
-
networkRequest,
|
|
395
|
-
networkRequestOptions,
|
|
396
|
-
mutableEncounteredRecords,
|
|
397
|
-
);
|
|
398
|
-
if (data.kind === 'MissingData') {
|
|
399
|
-
return {
|
|
400
|
-
kind: 'MissingData',
|
|
401
|
-
reason:
|
|
402
|
-
'Missing data for ' + field.alias + ' on root ' + root.__link,
|
|
403
|
-
nestedReason: data,
|
|
404
|
-
recordLink: data.recordLink,
|
|
405
|
-
};
|
|
406
|
-
} else {
|
|
407
|
-
const firstParameter = {
|
|
408
|
-
data: data.data,
|
|
409
|
-
parameters: variables,
|
|
410
|
-
};
|
|
411
|
-
target[field.alias] =
|
|
412
|
-
field.readerArtifact.resolver(firstParameter);
|
|
413
|
-
}
|
|
414
|
-
break;
|
|
415
|
-
}
|
|
416
|
-
case 'ComponentReaderArtifact': {
|
|
417
|
-
target[field.alias] = getOrCreateCachedComponent(
|
|
418
|
-
environment,
|
|
419
|
-
field.readerArtifact.componentName,
|
|
420
|
-
{
|
|
421
|
-
kind: 'FragmentReference',
|
|
422
|
-
readerWithRefetchQueries: wrapResolvedValue({
|
|
423
|
-
kind: 'ReaderWithRefetchQueries',
|
|
424
|
-
readerArtifact: field.readerArtifact,
|
|
425
|
-
nestedRefetchQueries: resolverRefetchQueries,
|
|
426
|
-
}),
|
|
427
|
-
root,
|
|
428
|
-
variables: generateChildVariableMap(variables, field.arguments),
|
|
429
|
-
networkRequest,
|
|
430
|
-
} as const,
|
|
431
|
-
networkRequestOptions,
|
|
432
|
-
);
|
|
433
|
-
break;
|
|
434
|
-
}
|
|
435
|
-
default: {
|
|
436
|
-
let _: never = field.readerArtifact;
|
|
437
|
-
_;
|
|
438
|
-
throw new Error('Unexpected kind');
|
|
439
|
-
}
|
|
245
|
+
return data;
|
|
440
246
|
}
|
|
247
|
+
target[field.alias] = data.data;
|
|
441
248
|
break;
|
|
442
249
|
}
|
|
443
250
|
case 'LoadablySelectedField': {
|
|
444
|
-
const
|
|
251
|
+
const data = readLoadablySelectedFieldData(
|
|
445
252
|
environment,
|
|
446
|
-
field
|
|
253
|
+
field,
|
|
447
254
|
root,
|
|
448
255
|
variables,
|
|
449
|
-
// Refetch fields just read the id, and don't need refetch query artifacts
|
|
450
|
-
[],
|
|
451
256
|
networkRequest,
|
|
452
257
|
networkRequestOptions,
|
|
453
258
|
mutableEncounteredRecords,
|
|
454
259
|
);
|
|
455
|
-
if (
|
|
456
|
-
return
|
|
457
|
-
kind: 'MissingData',
|
|
458
|
-
reason:
|
|
459
|
-
'Missing data for ' + field.alias + ' on root ' + root.__link,
|
|
460
|
-
nestedReason: refetchReaderParams,
|
|
461
|
-
recordLink: refetchReaderParams.recordLink,
|
|
462
|
-
};
|
|
463
|
-
} else {
|
|
464
|
-
target[field.alias] = (args: any, fetchOptions?: FetchOptions) => {
|
|
465
|
-
// TODO we should use the reader AST for this
|
|
466
|
-
const includeReadOutData = (variables: any, readOutData: any) => {
|
|
467
|
-
variables.id = readOutData.id;
|
|
468
|
-
return variables;
|
|
469
|
-
};
|
|
470
|
-
const localVariables = includeReadOutData(
|
|
471
|
-
args ?? {},
|
|
472
|
-
refetchReaderParams.data,
|
|
473
|
-
);
|
|
474
|
-
writeQueryArgsToVariables(
|
|
475
|
-
localVariables,
|
|
476
|
-
field.queryArguments,
|
|
477
|
-
variables,
|
|
478
|
-
);
|
|
479
|
-
|
|
480
|
-
return [
|
|
481
|
-
// Stable id
|
|
482
|
-
root.__typename +
|
|
483
|
-
':' +
|
|
484
|
-
root.__link +
|
|
485
|
-
'/' +
|
|
486
|
-
field.name +
|
|
487
|
-
'/' +
|
|
488
|
-
stableStringifyArgs(localVariables),
|
|
489
|
-
// Fetcher
|
|
490
|
-
() => {
|
|
491
|
-
const fragmentReferenceAndDisposeFromEntrypoint = (
|
|
492
|
-
entrypoint: IsographEntrypoint<any, any>,
|
|
493
|
-
): [FragmentReference<any, any>, CleanupFn] => {
|
|
494
|
-
const [networkRequest, disposeNetworkRequest] =
|
|
495
|
-
maybeMakeNetworkRequest(
|
|
496
|
-
environment,
|
|
497
|
-
entrypoint,
|
|
498
|
-
localVariables,
|
|
499
|
-
fetchOptions,
|
|
500
|
-
);
|
|
501
|
-
|
|
502
|
-
const fragmentReference: FragmentReference<any, any> = {
|
|
503
|
-
kind: 'FragmentReference',
|
|
504
|
-
readerWithRefetchQueries: wrapResolvedValue({
|
|
505
|
-
kind: 'ReaderWithRefetchQueries',
|
|
506
|
-
readerArtifact:
|
|
507
|
-
entrypoint.readerWithRefetchQueries.readerArtifact,
|
|
508
|
-
nestedRefetchQueries:
|
|
509
|
-
entrypoint.readerWithRefetchQueries
|
|
510
|
-
.nestedRefetchQueries,
|
|
511
|
-
} as const),
|
|
512
|
-
|
|
513
|
-
// TODO localVariables is not guaranteed to have an id field
|
|
514
|
-
root,
|
|
515
|
-
variables: localVariables,
|
|
516
|
-
networkRequest,
|
|
517
|
-
};
|
|
518
|
-
return [fragmentReference, disposeNetworkRequest];
|
|
519
|
-
};
|
|
520
|
-
|
|
521
|
-
if (field.entrypoint.kind === 'Entrypoint') {
|
|
522
|
-
return fragmentReferenceAndDisposeFromEntrypoint(
|
|
523
|
-
field.entrypoint,
|
|
524
|
-
);
|
|
525
|
-
} else {
|
|
526
|
-
const isographArtifactPromiseWrapper =
|
|
527
|
-
getOrLoadIsographArtifact(
|
|
528
|
-
environment,
|
|
529
|
-
field.entrypoint.typeAndField,
|
|
530
|
-
field.entrypoint.loader,
|
|
531
|
-
);
|
|
532
|
-
const state = getPromiseState(isographArtifactPromiseWrapper);
|
|
533
|
-
if (state.kind === 'Ok') {
|
|
534
|
-
return fragmentReferenceAndDisposeFromEntrypoint(
|
|
535
|
-
state.value,
|
|
536
|
-
);
|
|
537
|
-
} else {
|
|
538
|
-
// Promise is pending or thrown
|
|
539
|
-
|
|
540
|
-
let entrypointLoaderState:
|
|
541
|
-
| {
|
|
542
|
-
kind: 'EntrypointNotLoaded';
|
|
543
|
-
}
|
|
544
|
-
| {
|
|
545
|
-
kind: 'NetworkRequestStarted';
|
|
546
|
-
disposeNetworkRequest: CleanupFn;
|
|
547
|
-
}
|
|
548
|
-
| { kind: 'Disposed' } = { kind: 'EntrypointNotLoaded' };
|
|
549
|
-
|
|
550
|
-
const networkRequest = wrapPromise(
|
|
551
|
-
isographArtifactPromiseWrapper.promise.then(
|
|
552
|
-
(entrypoint) => {
|
|
553
|
-
if (
|
|
554
|
-
entrypointLoaderState.kind === 'EntrypointNotLoaded'
|
|
555
|
-
) {
|
|
556
|
-
const [networkRequest, disposeNetworkRequest] =
|
|
557
|
-
maybeMakeNetworkRequest(
|
|
558
|
-
environment,
|
|
559
|
-
entrypoint,
|
|
560
|
-
localVariables,
|
|
561
|
-
fetchOptions,
|
|
562
|
-
);
|
|
563
|
-
entrypointLoaderState = {
|
|
564
|
-
kind: 'NetworkRequestStarted',
|
|
565
|
-
disposeNetworkRequest,
|
|
566
|
-
};
|
|
567
|
-
return networkRequest.promise;
|
|
568
|
-
}
|
|
569
|
-
},
|
|
570
|
-
),
|
|
571
|
-
);
|
|
572
|
-
const readerWithRefetchPromise =
|
|
573
|
-
isographArtifactPromiseWrapper.promise.then(
|
|
574
|
-
(entrypoint) => entrypoint.readerWithRefetchQueries,
|
|
575
|
-
);
|
|
576
|
-
|
|
577
|
-
const fragmentReference: FragmentReference<any, any> = {
|
|
578
|
-
kind: 'FragmentReference',
|
|
579
|
-
readerWithRefetchQueries: wrapPromise(
|
|
580
|
-
readerWithRefetchPromise,
|
|
581
|
-
),
|
|
582
|
-
|
|
583
|
-
// TODO localVariables is not guaranteed to have an id field
|
|
584
|
-
root,
|
|
585
|
-
variables: localVariables,
|
|
586
|
-
networkRequest,
|
|
587
|
-
};
|
|
588
|
-
|
|
589
|
-
return [
|
|
590
|
-
fragmentReference,
|
|
591
|
-
() => {
|
|
592
|
-
if (
|
|
593
|
-
entrypointLoaderState.kind === 'NetworkRequestStarted'
|
|
594
|
-
) {
|
|
595
|
-
entrypointLoaderState.disposeNetworkRequest();
|
|
596
|
-
}
|
|
597
|
-
entrypointLoaderState = { kind: 'Disposed' };
|
|
598
|
-
},
|
|
599
|
-
];
|
|
600
|
-
}
|
|
601
|
-
}
|
|
602
|
-
},
|
|
603
|
-
];
|
|
604
|
-
};
|
|
260
|
+
if (data.kind === 'MissingData') {
|
|
261
|
+
return data;
|
|
605
262
|
}
|
|
263
|
+
target[field.alias] = data.data;
|
|
606
264
|
break;
|
|
607
265
|
}
|
|
266
|
+
|
|
608
267
|
default: {
|
|
609
268
|
// Ensure we have covered all variants
|
|
610
269
|
let _: never = field;
|
|
@@ -616,7 +275,177 @@ function readData<TReadFromStore>(
|
|
|
616
275
|
return {
|
|
617
276
|
kind: 'Success',
|
|
618
277
|
data: target as any,
|
|
619
|
-
|
|
278
|
+
};
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
export function readLoadablySelectedFieldData(
|
|
282
|
+
environment: IsographEnvironment,
|
|
283
|
+
field: LoadablySelectedField,
|
|
284
|
+
root: StoreLink,
|
|
285
|
+
variables: Variables,
|
|
286
|
+
networkRequest: PromiseWrapper<void, any>,
|
|
287
|
+
networkRequestOptions: NetworkRequestReaderOptions,
|
|
288
|
+
mutableEncounteredRecords: EncounteredIds,
|
|
289
|
+
): ReadDataResult<unknown> {
|
|
290
|
+
const refetchReaderParams = readData(
|
|
291
|
+
environment,
|
|
292
|
+
field.refetchReaderAst,
|
|
293
|
+
root,
|
|
294
|
+
variables,
|
|
295
|
+
// Refetch fields just read the id, and don't need refetch query artifacts
|
|
296
|
+
[],
|
|
297
|
+
networkRequest,
|
|
298
|
+
networkRequestOptions,
|
|
299
|
+
mutableEncounteredRecords,
|
|
300
|
+
);
|
|
301
|
+
|
|
302
|
+
if (refetchReaderParams.kind === 'MissingData') {
|
|
303
|
+
return {
|
|
304
|
+
kind: 'MissingData',
|
|
305
|
+
reason: 'Missing data for ' + field.alias + ' on root ' + root.__link,
|
|
306
|
+
nestedReason: refetchReaderParams,
|
|
307
|
+
recordLink: refetchReaderParams.recordLink,
|
|
308
|
+
};
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
return {
|
|
312
|
+
kind: 'Success',
|
|
313
|
+
data: (
|
|
314
|
+
args: any,
|
|
315
|
+
// TODO get the associated type for FetchOptions from the loadably selected field
|
|
316
|
+
fetchOptions?: FetchOptions<any>,
|
|
317
|
+
) => {
|
|
318
|
+
// TODO we should use the reader AST for this
|
|
319
|
+
const includeReadOutData = (variables: any, readOutData: any) => {
|
|
320
|
+
variables.id = readOutData.id;
|
|
321
|
+
return variables;
|
|
322
|
+
};
|
|
323
|
+
const localVariables = includeReadOutData(
|
|
324
|
+
args ?? {},
|
|
325
|
+
refetchReaderParams.data,
|
|
326
|
+
);
|
|
327
|
+
writeQueryArgsToVariables(
|
|
328
|
+
localVariables,
|
|
329
|
+
field.queryArguments,
|
|
330
|
+
variables,
|
|
331
|
+
);
|
|
332
|
+
|
|
333
|
+
return [
|
|
334
|
+
// Stable id
|
|
335
|
+
root.__typename +
|
|
336
|
+
':' +
|
|
337
|
+
root.__link +
|
|
338
|
+
'/' +
|
|
339
|
+
field.name +
|
|
340
|
+
'/' +
|
|
341
|
+
stableStringifyArgs(localVariables),
|
|
342
|
+
// Fetcher
|
|
343
|
+
() => {
|
|
344
|
+
const fragmentReferenceAndDisposeFromEntrypoint = (
|
|
345
|
+
entrypoint: IsographEntrypoint<any, any, any>,
|
|
346
|
+
): [FragmentReference<any, any>, CleanupFn] => {
|
|
347
|
+
const readerWithRefetchQueries =
|
|
348
|
+
entrypoint.readerWithRefetchQueries.kind ===
|
|
349
|
+
'ReaderWithRefetchQueriesLoader'
|
|
350
|
+
? wrapPromise(entrypoint.readerWithRefetchQueries.loader())
|
|
351
|
+
: wrapResolvedValue(entrypoint.readerWithRefetchQueries);
|
|
352
|
+
const [networkRequest, disposeNetworkRequest] =
|
|
353
|
+
maybeMakeNetworkRequest(
|
|
354
|
+
environment,
|
|
355
|
+
entrypoint,
|
|
356
|
+
localVariables,
|
|
357
|
+
readerWithRefetchQueries,
|
|
358
|
+
fetchOptions ?? null,
|
|
359
|
+
);
|
|
360
|
+
|
|
361
|
+
const fragmentReference: FragmentReference<any, any> = {
|
|
362
|
+
kind: 'FragmentReference',
|
|
363
|
+
readerWithRefetchQueries,
|
|
364
|
+
|
|
365
|
+
// TODO localVariables is not guaranteed to have an id field
|
|
366
|
+
root,
|
|
367
|
+
variables: localVariables,
|
|
368
|
+
networkRequest,
|
|
369
|
+
};
|
|
370
|
+
return [fragmentReference, disposeNetworkRequest];
|
|
371
|
+
};
|
|
372
|
+
|
|
373
|
+
if (field.entrypoint.kind === 'Entrypoint') {
|
|
374
|
+
return fragmentReferenceAndDisposeFromEntrypoint(field.entrypoint);
|
|
375
|
+
} else {
|
|
376
|
+
const isographArtifactPromiseWrapper = getOrLoadIsographArtifact(
|
|
377
|
+
environment,
|
|
378
|
+
field.entrypoint.typeAndField,
|
|
379
|
+
field.entrypoint.loader,
|
|
380
|
+
);
|
|
381
|
+
const state = getPromiseState(isographArtifactPromiseWrapper);
|
|
382
|
+
if (state.kind === 'Ok') {
|
|
383
|
+
return fragmentReferenceAndDisposeFromEntrypoint(state.value);
|
|
384
|
+
} else {
|
|
385
|
+
// Promise is pending or thrown
|
|
386
|
+
|
|
387
|
+
let entrypointLoaderState:
|
|
388
|
+
| {
|
|
389
|
+
kind: 'EntrypointNotLoaded';
|
|
390
|
+
}
|
|
391
|
+
| {
|
|
392
|
+
kind: 'NetworkRequestStarted';
|
|
393
|
+
disposeNetworkRequest: CleanupFn;
|
|
394
|
+
}
|
|
395
|
+
| { kind: 'Disposed' } = { kind: 'EntrypointNotLoaded' };
|
|
396
|
+
|
|
397
|
+
const readerWithRefetchQueries = wrapPromise(
|
|
398
|
+
isographArtifactPromiseWrapper.promise.then((entrypoint) =>
|
|
399
|
+
entrypoint.readerWithRefetchQueries.kind ===
|
|
400
|
+
'ReaderWithRefetchQueriesLoader'
|
|
401
|
+
? entrypoint.readerWithRefetchQueries.loader()
|
|
402
|
+
: entrypoint.readerWithRefetchQueries,
|
|
403
|
+
),
|
|
404
|
+
);
|
|
405
|
+
const networkRequest = wrapPromise(
|
|
406
|
+
isographArtifactPromiseWrapper.promise.then((entrypoint) => {
|
|
407
|
+
if (entrypointLoaderState.kind === 'EntrypointNotLoaded') {
|
|
408
|
+
const [networkRequest, disposeNetworkRequest] =
|
|
409
|
+
maybeMakeNetworkRequest(
|
|
410
|
+
environment,
|
|
411
|
+
entrypoint,
|
|
412
|
+
localVariables,
|
|
413
|
+
readerWithRefetchQueries,
|
|
414
|
+
fetchOptions ?? null,
|
|
415
|
+
);
|
|
416
|
+
entrypointLoaderState = {
|
|
417
|
+
kind: 'NetworkRequestStarted',
|
|
418
|
+
disposeNetworkRequest,
|
|
419
|
+
};
|
|
420
|
+
return networkRequest.promise;
|
|
421
|
+
}
|
|
422
|
+
}),
|
|
423
|
+
);
|
|
424
|
+
|
|
425
|
+
const fragmentReference: FragmentReference<any, any> = {
|
|
426
|
+
kind: 'FragmentReference',
|
|
427
|
+
readerWithRefetchQueries,
|
|
428
|
+
|
|
429
|
+
// TODO localVariables is not guaranteed to have an id field
|
|
430
|
+
root,
|
|
431
|
+
variables: localVariables,
|
|
432
|
+
networkRequest,
|
|
433
|
+
};
|
|
434
|
+
|
|
435
|
+
return [
|
|
436
|
+
fragmentReference,
|
|
437
|
+
() => {
|
|
438
|
+
if (entrypointLoaderState.kind === 'NetworkRequestStarted') {
|
|
439
|
+
entrypointLoaderState.disposeNetworkRequest();
|
|
440
|
+
}
|
|
441
|
+
entrypointLoaderState = { kind: 'Disposed' };
|
|
442
|
+
},
|
|
443
|
+
];
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
},
|
|
447
|
+
];
|
|
448
|
+
},
|
|
620
449
|
};
|
|
621
450
|
}
|
|
622
451
|
|
|
@@ -643,7 +472,9 @@ function generateChildVariableMap(
|
|
|
643
472
|
type Writable<T> = { -readonly [P in keyof T]: T[P] };
|
|
644
473
|
const childVars: Writable<Variables> = {};
|
|
645
474
|
for (const [name, value] of fieldArguments) {
|
|
646
|
-
if (value.kind === '
|
|
475
|
+
if (value.kind === 'Object') {
|
|
476
|
+
childVars[name] = generateChildVariableMap(variables, value.value);
|
|
477
|
+
} else if (value.kind === 'Variable') {
|
|
647
478
|
const variable = variables[value.name];
|
|
648
479
|
// Variable could be null if it was not provided but has a default case,
|
|
649
480
|
// so we allow the loop to continue rather than throwing an error.
|
|
@@ -667,6 +498,14 @@ function writeQueryArgsToVariables(
|
|
|
667
498
|
}
|
|
668
499
|
for (const [name, argType] of queryArgs) {
|
|
669
500
|
switch (argType.kind) {
|
|
501
|
+
case 'Object': {
|
|
502
|
+
writeQueryArgsToVariables(
|
|
503
|
+
(targetVariables[name] = {}),
|
|
504
|
+
argType.value,
|
|
505
|
+
variables,
|
|
506
|
+
);
|
|
507
|
+
break;
|
|
508
|
+
}
|
|
670
509
|
case 'Variable': {
|
|
671
510
|
targetVariables[name] = variables[argType.name];
|
|
672
511
|
break;
|
|
@@ -692,6 +531,389 @@ function writeQueryArgsToVariables(
|
|
|
692
531
|
}
|
|
693
532
|
}
|
|
694
533
|
|
|
534
|
+
export function readResolverFieldData(
|
|
535
|
+
environment: IsographEnvironment,
|
|
536
|
+
field: ReaderNonLoadableResolverField,
|
|
537
|
+
root: StoreLink,
|
|
538
|
+
variables: Variables,
|
|
539
|
+
nestedRefetchQueries: RefetchQueryNormalizationArtifactWrapper[],
|
|
540
|
+
networkRequest: PromiseWrapper<void, any>,
|
|
541
|
+
networkRequestOptions: NetworkRequestReaderOptions,
|
|
542
|
+
mutableEncounteredRecords: EncounteredIds,
|
|
543
|
+
): ReadDataResult<unknown> {
|
|
544
|
+
const usedRefetchQueries = field.usedRefetchQueries;
|
|
545
|
+
const resolverRefetchQueries = usedRefetchQueries.map((index) => {
|
|
546
|
+
const resolverRefetchQuery = nestedRefetchQueries[index];
|
|
547
|
+
if (resolverRefetchQuery == null) {
|
|
548
|
+
throw new Error(
|
|
549
|
+
'resolverRefetchQuery is null in Resolver. This is indicative of a bug in Isograph.',
|
|
550
|
+
);
|
|
551
|
+
}
|
|
552
|
+
return resolverRefetchQuery;
|
|
553
|
+
});
|
|
554
|
+
|
|
555
|
+
const readerWithRefetchQueries = {
|
|
556
|
+
kind: 'ReaderWithRefetchQueries',
|
|
557
|
+
readerArtifact: field.readerArtifact,
|
|
558
|
+
nestedRefetchQueries: resolverRefetchQueries,
|
|
559
|
+
} satisfies ReaderWithRefetchQueries<any, any>;
|
|
560
|
+
|
|
561
|
+
const fragment = {
|
|
562
|
+
kind: 'FragmentReference',
|
|
563
|
+
readerWithRefetchQueries: wrapResolvedValue(readerWithRefetchQueries),
|
|
564
|
+
root,
|
|
565
|
+
variables: generateChildVariableMap(variables, field.arguments),
|
|
566
|
+
networkRequest,
|
|
567
|
+
} satisfies FragmentReference<any, any>;
|
|
568
|
+
|
|
569
|
+
switch (field.readerArtifact.kind) {
|
|
570
|
+
case 'EagerReaderArtifact': {
|
|
571
|
+
const data = readData(
|
|
572
|
+
environment,
|
|
573
|
+
field.readerArtifact.readerAst,
|
|
574
|
+
root,
|
|
575
|
+
generateChildVariableMap(variables, field.arguments),
|
|
576
|
+
resolverRefetchQueries,
|
|
577
|
+
networkRequest,
|
|
578
|
+
networkRequestOptions,
|
|
579
|
+
mutableEncounteredRecords,
|
|
580
|
+
);
|
|
581
|
+
if (data.kind === 'MissingData') {
|
|
582
|
+
return {
|
|
583
|
+
kind: 'MissingData',
|
|
584
|
+
reason: 'Missing data for ' + field.alias + ' on root ' + root.__link,
|
|
585
|
+
nestedReason: data,
|
|
586
|
+
recordLink: data.recordLink,
|
|
587
|
+
};
|
|
588
|
+
}
|
|
589
|
+
const firstParameter = {
|
|
590
|
+
data: data.data,
|
|
591
|
+
parameters: variables,
|
|
592
|
+
startUpdate: field.readerArtifact.hasUpdatable
|
|
593
|
+
? getOrCreateCachedStartUpdate(
|
|
594
|
+
environment,
|
|
595
|
+
fragment,
|
|
596
|
+
readerWithRefetchQueries.readerArtifact.fieldName,
|
|
597
|
+
networkRequestOptions,
|
|
598
|
+
)
|
|
599
|
+
: undefined,
|
|
600
|
+
};
|
|
601
|
+
return {
|
|
602
|
+
kind: 'Success',
|
|
603
|
+
data: field.readerArtifact.resolver(firstParameter),
|
|
604
|
+
};
|
|
605
|
+
}
|
|
606
|
+
case 'ComponentReaderArtifact': {
|
|
607
|
+
return {
|
|
608
|
+
kind: 'Success',
|
|
609
|
+
data: getOrCreateCachedComponent(
|
|
610
|
+
environment,
|
|
611
|
+
field.readerArtifact.fieldName,
|
|
612
|
+
fragment,
|
|
613
|
+
networkRequestOptions,
|
|
614
|
+
),
|
|
615
|
+
};
|
|
616
|
+
}
|
|
617
|
+
default: {
|
|
618
|
+
let _: never = field.readerArtifact;
|
|
619
|
+
_;
|
|
620
|
+
throw new Error('Unexpected kind');
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
export function readScalarFieldData(
|
|
626
|
+
field: ReaderScalarField,
|
|
627
|
+
storeRecord: StoreRecord,
|
|
628
|
+
root: StoreLink,
|
|
629
|
+
variables: Variables,
|
|
630
|
+
): ReadDataResult<
|
|
631
|
+
string | number | boolean | StoreLink | DataTypeValue[] | null
|
|
632
|
+
> {
|
|
633
|
+
const storeRecordName = getParentRecordKey(field, variables);
|
|
634
|
+
const value = storeRecord[storeRecordName];
|
|
635
|
+
// TODO consider making scalars into discriminated unions. This probably has
|
|
636
|
+
// to happen for when we handle errors.
|
|
637
|
+
if (value === undefined) {
|
|
638
|
+
return {
|
|
639
|
+
kind: 'MissingData',
|
|
640
|
+
reason: 'No value for ' + storeRecordName + ' on root ' + root.__link,
|
|
641
|
+
recordLink: root,
|
|
642
|
+
};
|
|
643
|
+
}
|
|
644
|
+
return { kind: 'Success', data: value };
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
export function readLinkedFieldData(
|
|
648
|
+
environment: IsographEnvironment,
|
|
649
|
+
field: ReaderLinkedField,
|
|
650
|
+
storeRecord: StoreRecord,
|
|
651
|
+
root: StoreLink,
|
|
652
|
+
variables: Variables,
|
|
653
|
+
nestedRefetchQueries: RefetchQueryNormalizationArtifactWrapper[],
|
|
654
|
+
networkRequest: PromiseWrapper<void, any>,
|
|
655
|
+
networkRequestOptions: NetworkRequestReaderOptions,
|
|
656
|
+
readData: <TReadFromStore>(
|
|
657
|
+
ast: ReaderAst<TReadFromStore>,
|
|
658
|
+
root: StoreLink,
|
|
659
|
+
) => ReadDataResult<object>,
|
|
660
|
+
): ReadDataResult<unknown> {
|
|
661
|
+
const storeRecordName = getParentRecordKey(field, variables);
|
|
662
|
+
const value = storeRecord[storeRecordName];
|
|
663
|
+
if (Array.isArray(value)) {
|
|
664
|
+
const results = [];
|
|
665
|
+
for (const item of value) {
|
|
666
|
+
const link = assertLink(item);
|
|
667
|
+
if (link === undefined) {
|
|
668
|
+
return {
|
|
669
|
+
kind: 'MissingData',
|
|
670
|
+
reason:
|
|
671
|
+
'No link for ' +
|
|
672
|
+
storeRecordName +
|
|
673
|
+
' on root ' +
|
|
674
|
+
root.__link +
|
|
675
|
+
'. Link is ' +
|
|
676
|
+
JSON.stringify(item),
|
|
677
|
+
recordLink: root,
|
|
678
|
+
};
|
|
679
|
+
} else if (link === null) {
|
|
680
|
+
results.push(null);
|
|
681
|
+
continue;
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
const result = readData(field.selections, link);
|
|
685
|
+
if (result.kind === 'MissingData') {
|
|
686
|
+
return {
|
|
687
|
+
kind: 'MissingData',
|
|
688
|
+
reason:
|
|
689
|
+
'Missing data for ' +
|
|
690
|
+
storeRecordName +
|
|
691
|
+
' on root ' +
|
|
692
|
+
root.__link +
|
|
693
|
+
'. Link is ' +
|
|
694
|
+
JSON.stringify(item),
|
|
695
|
+
nestedReason: result,
|
|
696
|
+
recordLink: result.recordLink,
|
|
697
|
+
};
|
|
698
|
+
}
|
|
699
|
+
results.push(result.data);
|
|
700
|
+
}
|
|
701
|
+
return {
|
|
702
|
+
kind: 'Success',
|
|
703
|
+
data: results,
|
|
704
|
+
};
|
|
705
|
+
}
|
|
706
|
+
let link = assertLink(value);
|
|
707
|
+
|
|
708
|
+
if (field.condition) {
|
|
709
|
+
const data = readData(field.condition.readerAst, root);
|
|
710
|
+
if (data.kind === 'MissingData') {
|
|
711
|
+
return {
|
|
712
|
+
kind: 'MissingData',
|
|
713
|
+
reason:
|
|
714
|
+
'Missing data for ' + storeRecordName + ' on root ' + root.__link,
|
|
715
|
+
nestedReason: data,
|
|
716
|
+
recordLink: data.recordLink,
|
|
717
|
+
};
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
const readerWithRefetchQueries = {
|
|
721
|
+
kind: 'ReaderWithRefetchQueries',
|
|
722
|
+
readerArtifact: field.condition,
|
|
723
|
+
// TODO this is wrong
|
|
724
|
+
// should map field.condition.usedRefetchQueries
|
|
725
|
+
// but it doesn't exist
|
|
726
|
+
nestedRefetchQueries: [],
|
|
727
|
+
} satisfies ReaderWithRefetchQueries<any, any>;
|
|
728
|
+
|
|
729
|
+
const fragment = {
|
|
730
|
+
kind: 'FragmentReference',
|
|
731
|
+
readerWithRefetchQueries: wrapResolvedValue(readerWithRefetchQueries),
|
|
732
|
+
root,
|
|
733
|
+
variables: generateChildVariableMap(
|
|
734
|
+
variables,
|
|
735
|
+
// TODO this is wrong
|
|
736
|
+
// should use field.arguments
|
|
737
|
+
// but it doesn't exist
|
|
738
|
+
[],
|
|
739
|
+
),
|
|
740
|
+
networkRequest,
|
|
741
|
+
} satisfies FragmentReference<any, any>;
|
|
742
|
+
|
|
743
|
+
const condition = field.condition.resolver({
|
|
744
|
+
data: data.data,
|
|
745
|
+
parameters: {},
|
|
746
|
+
...(field.condition.hasUpdatable
|
|
747
|
+
? {
|
|
748
|
+
startUpdate: getOrCreateCachedStartUpdate(
|
|
749
|
+
environment,
|
|
750
|
+
fragment,
|
|
751
|
+
readerWithRefetchQueries.readerArtifact.fieldName,
|
|
752
|
+
networkRequestOptions,
|
|
753
|
+
),
|
|
754
|
+
}
|
|
755
|
+
: undefined),
|
|
756
|
+
});
|
|
757
|
+
link = condition;
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
if (link === undefined) {
|
|
761
|
+
// TODO make this configurable, and also generated and derived from the schema
|
|
762
|
+
const missingFieldHandler = environment.missingFieldHandler;
|
|
763
|
+
|
|
764
|
+
const altLink = missingFieldHandler?.(
|
|
765
|
+
storeRecord,
|
|
766
|
+
root,
|
|
767
|
+
field.fieldName,
|
|
768
|
+
field.arguments,
|
|
769
|
+
variables,
|
|
770
|
+
);
|
|
771
|
+
logMessage(environment, () => ({
|
|
772
|
+
kind: 'MissingFieldHandlerCalled',
|
|
773
|
+
root,
|
|
774
|
+
storeRecord,
|
|
775
|
+
fieldName: field.fieldName,
|
|
776
|
+
arguments: field.arguments,
|
|
777
|
+
variables,
|
|
778
|
+
}));
|
|
779
|
+
|
|
780
|
+
if (altLink === undefined) {
|
|
781
|
+
return {
|
|
782
|
+
kind: 'MissingData',
|
|
783
|
+
reason:
|
|
784
|
+
'No link for ' +
|
|
785
|
+
storeRecordName +
|
|
786
|
+
' on root ' +
|
|
787
|
+
root.__link +
|
|
788
|
+
'. Link is ' +
|
|
789
|
+
JSON.stringify(value),
|
|
790
|
+
recordLink: root,
|
|
791
|
+
};
|
|
792
|
+
} else {
|
|
793
|
+
link = altLink;
|
|
794
|
+
}
|
|
795
|
+
} else if (link === null) {
|
|
796
|
+
return {
|
|
797
|
+
kind: 'Success',
|
|
798
|
+
data: null,
|
|
799
|
+
};
|
|
800
|
+
}
|
|
801
|
+
const targetId = link;
|
|
802
|
+
const { refetchQueryIndex } = field;
|
|
803
|
+
if (refetchQueryIndex != null) {
|
|
804
|
+
// if field.refetchQueryIndex is not null, then the field is a client pointer, i.e.
|
|
805
|
+
// it is like a loadable field that returns the selections.
|
|
806
|
+
const refetchReaderParams = readData(
|
|
807
|
+
[
|
|
808
|
+
{
|
|
809
|
+
kind: 'Scalar',
|
|
810
|
+
fieldName: 'id',
|
|
811
|
+
alias: null,
|
|
812
|
+
arguments: null,
|
|
813
|
+
isUpdatable: false,
|
|
814
|
+
},
|
|
815
|
+
],
|
|
816
|
+
targetId,
|
|
817
|
+
);
|
|
818
|
+
|
|
819
|
+
if (refetchReaderParams.kind === 'MissingData') {
|
|
820
|
+
return {
|
|
821
|
+
kind: 'MissingData',
|
|
822
|
+
reason:
|
|
823
|
+
'Missing data for ' + field.alias + ' on root ' + targetId.__link,
|
|
824
|
+
nestedReason: refetchReaderParams,
|
|
825
|
+
recordLink: refetchReaderParams.recordLink,
|
|
826
|
+
};
|
|
827
|
+
}
|
|
828
|
+
|
|
829
|
+
const refetchQuery = nestedRefetchQueries[refetchQueryIndex];
|
|
830
|
+
if (refetchQuery == null) {
|
|
831
|
+
throw new Error(
|
|
832
|
+
'refetchQuery is null in RefetchField. This is indicative of a bug in Isograph.',
|
|
833
|
+
);
|
|
834
|
+
}
|
|
835
|
+
const refetchQueryArtifact = refetchQuery.artifact;
|
|
836
|
+
const allowedVariables = refetchQuery.allowedVariables;
|
|
837
|
+
|
|
838
|
+
return {
|
|
839
|
+
kind: 'Success',
|
|
840
|
+
data: (
|
|
841
|
+
args: any,
|
|
842
|
+
// TODO get the associated type for FetchOptions from the loadably selected field
|
|
843
|
+
fetchOptions?: FetchOptions<any>,
|
|
844
|
+
) => {
|
|
845
|
+
const includeReadOutData = (variables: any, readOutData: any) => {
|
|
846
|
+
variables.id = readOutData.id;
|
|
847
|
+
return variables;
|
|
848
|
+
};
|
|
849
|
+
const localVariables = includeReadOutData(
|
|
850
|
+
args ?? {},
|
|
851
|
+
refetchReaderParams.data,
|
|
852
|
+
);
|
|
853
|
+
writeQueryArgsToVariables(localVariables, field.arguments, variables);
|
|
854
|
+
|
|
855
|
+
return [
|
|
856
|
+
// Stable id
|
|
857
|
+
targetId.__typename +
|
|
858
|
+
':' +
|
|
859
|
+
targetId.__link +
|
|
860
|
+
'/' +
|
|
861
|
+
field.fieldName +
|
|
862
|
+
'/' +
|
|
863
|
+
stableStringifyArgs(localVariables),
|
|
864
|
+
// Fetcher
|
|
865
|
+
(): ItemCleanupPair<FragmentReference<any, any>> | undefined => {
|
|
866
|
+
const variables = includeReadOutData(
|
|
867
|
+
filterVariables({ ...args, ...localVariables }, allowedVariables),
|
|
868
|
+
refetchReaderParams.data,
|
|
869
|
+
);
|
|
870
|
+
|
|
871
|
+
const readerWithRefetchQueries = wrapResolvedValue({
|
|
872
|
+
kind: 'ReaderWithRefetchQueries',
|
|
873
|
+
readerArtifact: {
|
|
874
|
+
kind: 'EagerReaderArtifact',
|
|
875
|
+
fieldName: field.fieldName,
|
|
876
|
+
readerAst: field.selections,
|
|
877
|
+
resolver: ({ data }: { data: any }) => data,
|
|
878
|
+
hasUpdatable: false,
|
|
879
|
+
},
|
|
880
|
+
nestedRefetchQueries,
|
|
881
|
+
} as const);
|
|
882
|
+
|
|
883
|
+
const [networkRequest, disposeNetworkRequest] =
|
|
884
|
+
maybeMakeNetworkRequest(
|
|
885
|
+
environment,
|
|
886
|
+
refetchQueryArtifact,
|
|
887
|
+
variables,
|
|
888
|
+
readerWithRefetchQueries,
|
|
889
|
+
fetchOptions ?? null,
|
|
890
|
+
);
|
|
891
|
+
|
|
892
|
+
const fragmentReference: FragmentReference<any, any> = {
|
|
893
|
+
kind: 'FragmentReference',
|
|
894
|
+
readerWithRefetchQueries: readerWithRefetchQueries,
|
|
895
|
+
root: targetId,
|
|
896
|
+
variables,
|
|
897
|
+
networkRequest,
|
|
898
|
+
};
|
|
899
|
+
return [fragmentReference, disposeNetworkRequest];
|
|
900
|
+
},
|
|
901
|
+
];
|
|
902
|
+
},
|
|
903
|
+
};
|
|
904
|
+
}
|
|
905
|
+
const data = readData(field.selections, targetId);
|
|
906
|
+
if (data.kind === 'MissingData') {
|
|
907
|
+
return {
|
|
908
|
+
kind: 'MissingData',
|
|
909
|
+
reason: 'Missing data for ' + storeRecordName + ' on root ' + root.__link,
|
|
910
|
+
nestedReason: data,
|
|
911
|
+
recordLink: data.recordLink,
|
|
912
|
+
};
|
|
913
|
+
}
|
|
914
|
+
return data;
|
|
915
|
+
}
|
|
916
|
+
|
|
695
917
|
export type NetworkRequestReaderOptions = {
|
|
696
918
|
suspendIfInFlight: boolean;
|
|
697
919
|
throwOnNetworkError: boolean;
|
|
@@ -720,3 +942,69 @@ function stableStringifyArgs(args: object) {
|
|
|
720
942
|
}
|
|
721
943
|
return s;
|
|
722
944
|
}
|
|
945
|
+
|
|
946
|
+
export function readImperativelyLoadedField(
|
|
947
|
+
environment: IsographEnvironment,
|
|
948
|
+
field: ReaderImperativelyLoadedField,
|
|
949
|
+
root: StoreLink,
|
|
950
|
+
variables: Variables,
|
|
951
|
+
nestedRefetchQueries: RefetchQueryNormalizationArtifactWrapper[],
|
|
952
|
+
networkRequest: PromiseWrapper<void, any>,
|
|
953
|
+
networkRequestOptions: NetworkRequestReaderOptions,
|
|
954
|
+
mutableEncounteredRecords: EncounteredIds,
|
|
955
|
+
): ReadDataResult<unknown> {
|
|
956
|
+
// First, we read the data using the refetch reader AST (i.e. read out the
|
|
957
|
+
// id field).
|
|
958
|
+
const data = readData(
|
|
959
|
+
environment,
|
|
960
|
+
field.refetchReaderArtifact.readerAst,
|
|
961
|
+
root,
|
|
962
|
+
variables,
|
|
963
|
+
// Refetch fields just read the id, and don't need refetch query artifacts
|
|
964
|
+
[],
|
|
965
|
+
// This is probably indicative of the fact that we are doing redundant checks
|
|
966
|
+
// on the status of this network request...
|
|
967
|
+
networkRequest,
|
|
968
|
+
networkRequestOptions,
|
|
969
|
+
mutableEncounteredRecords,
|
|
970
|
+
);
|
|
971
|
+
if (data.kind === 'MissingData') {
|
|
972
|
+
return {
|
|
973
|
+
kind: 'MissingData',
|
|
974
|
+
reason: 'Missing data for ' + field.alias + ' on root ' + root.__link,
|
|
975
|
+
nestedReason: data,
|
|
976
|
+
recordLink: data.recordLink,
|
|
977
|
+
};
|
|
978
|
+
} else {
|
|
979
|
+
const { refetchQueryIndex } = field;
|
|
980
|
+
const refetchQuery = nestedRefetchQueries[refetchQueryIndex];
|
|
981
|
+
if (refetchQuery == null) {
|
|
982
|
+
throw new Error(
|
|
983
|
+
'Refetch query not found. This is indicative of a bug in Isograph.',
|
|
984
|
+
);
|
|
985
|
+
}
|
|
986
|
+
const refetchQueryArtifact = refetchQuery.artifact;
|
|
987
|
+
const allowedVariables = refetchQuery.allowedVariables;
|
|
988
|
+
|
|
989
|
+
// Second, we allow the user to call the resolver, which will ultimately
|
|
990
|
+
// use the resolver reader AST to get the resolver parameters.
|
|
991
|
+
return {
|
|
992
|
+
kind: 'Success',
|
|
993
|
+
data: (args: any) => [
|
|
994
|
+
// Stable id
|
|
995
|
+
root.__typename + ':' + root.__link + '__' + field.name,
|
|
996
|
+
// Fetcher
|
|
997
|
+
field.refetchReaderArtifact.resolver(
|
|
998
|
+
environment,
|
|
999
|
+
refetchQueryArtifact,
|
|
1000
|
+
data.data,
|
|
1001
|
+
filterVariables({ ...args, ...variables }, allowedVariables),
|
|
1002
|
+
root,
|
|
1003
|
+
// TODO these params should be removed
|
|
1004
|
+
null,
|
|
1005
|
+
[],
|
|
1006
|
+
),
|
|
1007
|
+
],
|
|
1008
|
+
};
|
|
1009
|
+
}
|
|
1010
|
+
}
|