@isograph/react 0.3.1 → 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 +5 -5
- package/dist/core/FragmentReference.d.ts.map +1 -1
- package/dist/core/IsographEnvironment.d.ts +14 -9
- package/dist/core/IsographEnvironment.d.ts.map +1 -1
- package/dist/core/PromiseWrapper.d.ts +4 -4
- package/dist/core/PromiseWrapper.d.ts.map +1 -1
- package/dist/core/PromiseWrapper.js +2 -9
- package/dist/core/areEqualWithDeepComparison.d.ts +1 -3
- package/dist/core/areEqualWithDeepComparison.d.ts.map +1 -1
- package/dist/core/areEqualWithDeepComparison.js +0 -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 +7 -6
- package/dist/core/cache.d.ts.map +1 -1
- package/dist/core/cache.js +46 -28
- package/dist/core/check.d.ts +3 -3
- package/dist/core/check.d.ts.map +1 -1
- package/dist/core/componentCache.d.ts.map +1 -1
- package/dist/core/componentCache.js +1 -1
- package/dist/core/entrypoint.d.ts +20 -2
- package/dist/core/entrypoint.d.ts.map +1 -1
- package/dist/core/garbageCollection.d.ts +2 -2
- package/dist/core/garbageCollection.d.ts.map +1 -1
- package/dist/core/logging.d.ts +13 -4
- package/dist/core/logging.d.ts.map +1 -1
- package/dist/core/makeNetworkRequest.d.ts +3 -3
- package/dist/core/makeNetworkRequest.d.ts.map +1 -1
- package/dist/core/makeNetworkRequest.js +15 -15
- package/dist/core/read.d.ts +8 -8
- package/dist/core/read.d.ts.map +1 -1
- package/dist/core/read.js +98 -29
- package/dist/core/reader.d.ts +12 -8
- package/dist/core/reader.d.ts.map +1 -1
- package/dist/core/startUpdate.d.ts +7 -4
- package/dist/core/startUpdate.d.ts.map +1 -1
- package/dist/core/startUpdate.js +153 -5
- package/dist/index.d.ts +8 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -1
- package/dist/loadable-hooks/useConnectionSpecPagination.d.ts.map +1 -1
- package/dist/loadable-hooks/useConnectionSpecPagination.js +1 -1
- package/dist/loadable-hooks/useSkipLimitPagination.d.ts.map +1 -1
- package/dist/loadable-hooks/useSkipLimitPagination.js +1 -1
- package/dist/react/FragmentReader.d.ts +7 -13
- 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/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.map +1 -1
- package/dist/react/useImperativeReference.js +6 -6
- package/dist/react/useResult.d.ts.map +1 -1
- package/dist/react/useResult.js +1 -1
- package/package.json +4 -5
- package/src/core/FragmentReference.ts +16 -7
- package/src/core/IsographEnvironment.ts +19 -9
- package/src/core/PromiseWrapper.ts +13 -16
- package/src/core/areEqualWithDeepComparison.ts +5 -5
- package/src/core/brand.ts +18 -0
- package/src/core/cache.ts +50 -43
- package/src/core/check.ts +4 -4
- package/src/core/componentCache.ts +5 -1
- package/src/core/entrypoint.ts +32 -5
- package/src/core/garbageCollection.ts +3 -3
- package/src/core/logging.ts +16 -4
- package/src/core/makeNetworkRequest.ts +48 -23
- package/src/core/read.ts +153 -48
- package/src/core/reader.ts +11 -7
- package/src/core/startUpdate.ts +313 -7
- package/src/index.ts +11 -3
- package/src/loadable-hooks/useConnectionSpecPagination.ts +1 -0
- package/src/loadable-hooks/useSkipLimitPagination.ts +1 -0
- package/src/react/FragmentReader.tsx +23 -39
- package/src/react/FragmentRenderer.tsx +46 -0
- package/src/react/LoadableFieldReader.tsx +40 -0
- package/src/react/LoadableFieldRenderer.tsx +41 -0
- package/src/react/useImperativeReference.ts +9 -8
- package/src/react/useResult.ts +1 -0
- 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 +4 -1
- package/src/tests/__isograph/Query/meName/query_text.ts +1 -1
- package/src/tests/__isograph/Query/meName/resolver_reader.ts +1 -0
- package/src/tests/__isograph/Query/meNameSuccessor/entrypoint.ts +4 -1
- package/src/tests/__isograph/Query/meNameSuccessor/query_text.ts +1 -1
- package/src/tests/__isograph/Query/meNameSuccessor/resolver_reader.ts +3 -0
- package/src/tests/__isograph/Query/nodeField/entrypoint.ts +4 -1
- package/src/tests/__isograph/Query/nodeField/query_text.ts +1 -1
- package/src/tests/__isograph/Query/nodeField/resolver_reader.ts +1 -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 +4 -1
- package/src/tests/__isograph/Query/subquery/query_text.ts +1 -1
- package/src/tests/__isograph/Query/subquery/resolver_reader.ts +2 -0
- package/src/tests/__isograph/iso.ts +21 -1
- package/src/tests/__isograph/tsconfig.json +8 -0
- package/src/tests/normalizeData.test.ts +0 -1
- package/src/tests/startUpdate.test.ts +205 -0
- package/.turbo/turbo-compile-typescript.log +0 -4
package/src/core/logging.ts
CHANGED
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
IsographEnvironment,
|
|
12
12
|
IsographStore,
|
|
13
13
|
StoreRecord,
|
|
14
|
-
type
|
|
14
|
+
type StoreLink,
|
|
15
15
|
} from './IsographEnvironment';
|
|
16
16
|
import { ReadDataResult } from './read';
|
|
17
17
|
import { Arguments } from './util';
|
|
@@ -38,7 +38,7 @@ export type LogMessage =
|
|
|
38
38
|
| {
|
|
39
39
|
kind: 'ComponentRerendered';
|
|
40
40
|
componentName: string;
|
|
41
|
-
rootLink:
|
|
41
|
+
rootLink: StoreLink;
|
|
42
42
|
}
|
|
43
43
|
| {
|
|
44
44
|
kind: 'MakeNetworkRequest';
|
|
@@ -61,7 +61,7 @@ export type LogMessage =
|
|
|
61
61
|
}
|
|
62
62
|
| {
|
|
63
63
|
kind: 'MissingFieldHandlerCalled';
|
|
64
|
-
root:
|
|
64
|
+
root: StoreLink;
|
|
65
65
|
storeRecord: StoreRecord;
|
|
66
66
|
fieldName: string;
|
|
67
67
|
arguments: Arguments | null;
|
|
@@ -71,7 +71,7 @@ export type LogMessage =
|
|
|
71
71
|
kind: 'DoneReading';
|
|
72
72
|
response: ReadDataResult<any>;
|
|
73
73
|
fieldName: string;
|
|
74
|
-
root:
|
|
74
|
+
root: StoreLink;
|
|
75
75
|
}
|
|
76
76
|
| {
|
|
77
77
|
kind: 'NonEntrypointReceived';
|
|
@@ -83,6 +83,18 @@ export type LogMessage =
|
|
|
83
83
|
}
|
|
84
84
|
| {
|
|
85
85
|
kind: 'EnvironmentCreated';
|
|
86
|
+
}
|
|
87
|
+
| {
|
|
88
|
+
kind: 'StartUpdateError';
|
|
89
|
+
error: any;
|
|
90
|
+
}
|
|
91
|
+
| {
|
|
92
|
+
kind: 'StartUpdateComplete';
|
|
93
|
+
updatedIds: EncounteredIds;
|
|
94
|
+
}
|
|
95
|
+
| {
|
|
96
|
+
kind: 'ErrorEncounteredInWithErrorHandling';
|
|
97
|
+
error: any;
|
|
86
98
|
};
|
|
87
99
|
|
|
88
100
|
export type LogFunction = (logMessage: LogMessage) => void;
|
|
@@ -4,6 +4,7 @@ import { check, DEFAULT_SHOULD_FETCH_VALUE, FetchOptions } from './check';
|
|
|
4
4
|
import { getOrCreateCachedComponent } from './componentCache';
|
|
5
5
|
import {
|
|
6
6
|
IsographEntrypoint,
|
|
7
|
+
ReaderWithRefetchQueries,
|
|
7
8
|
RefetchQueryNormalizationArtifact,
|
|
8
9
|
type NormalizationAst,
|
|
9
10
|
type NormalizationAstLoader,
|
|
@@ -19,7 +20,7 @@ import {
|
|
|
19
20
|
retainQuery,
|
|
20
21
|
unretainQuery,
|
|
21
22
|
} from './garbageCollection';
|
|
22
|
-
import { IsographEnvironment,
|
|
23
|
+
import { IsographEnvironment, ROOT_ID, StoreLink } from './IsographEnvironment';
|
|
23
24
|
import { logMessage } from './logging';
|
|
24
25
|
import {
|
|
25
26
|
AnyError,
|
|
@@ -35,18 +36,28 @@ let networkRequestId = 0;
|
|
|
35
36
|
export function maybeMakeNetworkRequest<
|
|
36
37
|
TReadFromStore extends UnknownTReadFromStore,
|
|
37
38
|
TClientFieldValue,
|
|
39
|
+
TArtifact extends
|
|
40
|
+
| RefetchQueryNormalizationArtifact
|
|
41
|
+
| IsographEntrypoint<TReadFromStore, TClientFieldValue, TNormalizationAst>,
|
|
38
42
|
TNormalizationAst extends NormalizationAst | NormalizationAstLoader,
|
|
39
43
|
>(
|
|
40
44
|
environment: IsographEnvironment,
|
|
41
|
-
artifact:
|
|
42
|
-
| RefetchQueryNormalizationArtifact
|
|
43
|
-
| IsographEntrypoint<TReadFromStore, TClientFieldValue, TNormalizationAst>,
|
|
45
|
+
artifact: TArtifact,
|
|
44
46
|
variables: ExtractParameters<TReadFromStore>,
|
|
45
|
-
|
|
47
|
+
readerWithRefetchQueries: PromiseWrapper<
|
|
48
|
+
ReaderWithRefetchQueries<TReadFromStore, TClientFieldValue>
|
|
49
|
+
> | null,
|
|
50
|
+
fetchOptions: FetchOptions<TClientFieldValue> | null,
|
|
46
51
|
): ItemCleanupPair<PromiseWrapper<void, AnyError>> {
|
|
47
52
|
switch (fetchOptions?.shouldFetch ?? DEFAULT_SHOULD_FETCH_VALUE) {
|
|
48
53
|
case 'Yes': {
|
|
49
|
-
return makeNetworkRequest(
|
|
54
|
+
return makeNetworkRequest(
|
|
55
|
+
environment,
|
|
56
|
+
artifact,
|
|
57
|
+
variables,
|
|
58
|
+
readerWithRefetchQueries,
|
|
59
|
+
fetchOptions,
|
|
60
|
+
);
|
|
50
61
|
}
|
|
51
62
|
case 'No': {
|
|
52
63
|
return [wrapResolvedValue(undefined), () => {}];
|
|
@@ -77,6 +88,7 @@ export function maybeMakeNetworkRequest<
|
|
|
77
88
|
environment,
|
|
78
89
|
artifact,
|
|
79
90
|
variables,
|
|
91
|
+
readerWithRefetchQueries,
|
|
80
92
|
fetchOptions,
|
|
81
93
|
);
|
|
82
94
|
}
|
|
@@ -100,14 +112,18 @@ function loadNormalizationAst(
|
|
|
100
112
|
export function makeNetworkRequest<
|
|
101
113
|
TReadFromStore extends UnknownTReadFromStore,
|
|
102
114
|
TClientFieldValue,
|
|
115
|
+
TArtifact extends
|
|
116
|
+
| RefetchQueryNormalizationArtifact
|
|
117
|
+
| IsographEntrypoint<TReadFromStore, TClientFieldValue, TNormalizationAst>,
|
|
103
118
|
TNormalizationAst extends NormalizationAst | NormalizationAstLoader,
|
|
104
119
|
>(
|
|
105
120
|
environment: IsographEnvironment,
|
|
106
|
-
artifact:
|
|
107
|
-
| RefetchQueryNormalizationArtifact
|
|
108
|
-
| IsographEntrypoint<TReadFromStore, TClientFieldValue, TNormalizationAst>,
|
|
121
|
+
artifact: TArtifact,
|
|
109
122
|
variables: ExtractParameters<TReadFromStore>,
|
|
110
|
-
|
|
123
|
+
readerWithRefetchQueries: PromiseWrapper<
|
|
124
|
+
ReaderWithRefetchQueries<TReadFromStore, TClientFieldValue>
|
|
125
|
+
> | null,
|
|
126
|
+
fetchOptions: FetchOptions<TClientFieldValue> | null,
|
|
111
127
|
): ItemCleanupPair<PromiseWrapper<void, AnyError>> {
|
|
112
128
|
// TODO this should be a DataId and stored in the store
|
|
113
129
|
const myNetworkRequestId = networkRequestId + '';
|
|
@@ -126,12 +142,13 @@ export function makeNetworkRequest<
|
|
|
126
142
|
// This should be an observable, not a promise
|
|
127
143
|
const promise = Promise.all([
|
|
128
144
|
environment.networkFunction(
|
|
129
|
-
artifact.networkRequestInfo.
|
|
145
|
+
artifact.networkRequestInfo.operation,
|
|
130
146
|
variables,
|
|
131
147
|
),
|
|
132
148
|
loadNormalizationAst(artifact.networkRequestInfo.normalizationAst),
|
|
149
|
+
readerWithRefetchQueries?.promise,
|
|
133
150
|
])
|
|
134
|
-
.then(([networkResponse, normalizationAst]) => {
|
|
151
|
+
.then(([networkResponse, normalizationAst, readerWithRefetchQueries]) => {
|
|
135
152
|
logMessage(environment, () => ({
|
|
136
153
|
kind: 'ReceivedNetworkResponse',
|
|
137
154
|
networkResponse,
|
|
@@ -154,9 +171,6 @@ export function makeNetworkRequest<
|
|
|
154
171
|
normalizationAst.selections,
|
|
155
172
|
networkResponse.data ?? {},
|
|
156
173
|
variables,
|
|
157
|
-
artifact.kind === 'Entrypoint'
|
|
158
|
-
? artifact.readerWithRefetchQueries.nestedRefetchQueries
|
|
159
|
-
: [],
|
|
160
174
|
root,
|
|
161
175
|
);
|
|
162
176
|
const retainedQuery = {
|
|
@@ -178,6 +192,7 @@ export function makeNetworkRequest<
|
|
|
178
192
|
environment,
|
|
179
193
|
root,
|
|
180
194
|
variables,
|
|
195
|
+
readerWithRefetchQueries,
|
|
181
196
|
);
|
|
182
197
|
|
|
183
198
|
try {
|
|
@@ -238,14 +253,18 @@ type NetworkRequestStatus =
|
|
|
238
253
|
function readDataForOnComplete<
|
|
239
254
|
TReadFromStore extends UnknownTReadFromStore,
|
|
240
255
|
TClientFieldValue,
|
|
241
|
-
|
|
242
|
-
>(
|
|
243
|
-
artifact:
|
|
256
|
+
TArtifact extends
|
|
244
257
|
| RefetchQueryNormalizationArtifact
|
|
245
258
|
| IsographEntrypoint<TReadFromStore, TClientFieldValue, TNormalizationAst>,
|
|
259
|
+
TNormalizationAst extends NormalizationAst | NormalizationAstLoader,
|
|
260
|
+
>(
|
|
261
|
+
artifact: TArtifact,
|
|
246
262
|
environment: IsographEnvironment,
|
|
247
|
-
root:
|
|
263
|
+
root: StoreLink,
|
|
248
264
|
variables: ExtractParameters<TReadFromStore>,
|
|
265
|
+
readerWithRefetchQueries:
|
|
266
|
+
| ReaderWithRefetchQueries<TReadFromStore, TClientFieldValue>
|
|
267
|
+
| undefined,
|
|
249
268
|
): TClientFieldValue | null {
|
|
250
269
|
// An entrypoint, but not a RefetchQueryNormalizationArtifact, has a reader ASTs.
|
|
251
270
|
// So, we can only pass data to onComplete if makeNetworkRequest was passed an entrypoint.
|
|
@@ -262,12 +281,17 @@ function readDataForOnComplete<
|
|
|
262
281
|
suspendIfInFlight: false,
|
|
263
282
|
throwOnNetworkError: false,
|
|
264
283
|
};
|
|
284
|
+
const resolvedReaderWithRefetchQueries =
|
|
285
|
+
readerWithRefetchQueries as ReaderWithRefetchQueries<
|
|
286
|
+
TReadFromStore,
|
|
287
|
+
TClientFieldValue
|
|
288
|
+
>;
|
|
265
289
|
|
|
266
290
|
const fragment: FragmentReference<TReadFromStore, TClientFieldValue> = {
|
|
267
291
|
kind: 'FragmentReference',
|
|
268
292
|
// TODO this smells.
|
|
269
293
|
readerWithRefetchQueries: wrapResolvedValue(
|
|
270
|
-
|
|
294
|
+
resolvedReaderWithRefetchQueries,
|
|
271
295
|
),
|
|
272
296
|
root,
|
|
273
297
|
variables,
|
|
@@ -278,7 +302,7 @@ function readDataForOnComplete<
|
|
|
278
302
|
fragment,
|
|
279
303
|
fakeNetworkRequestOptions,
|
|
280
304
|
).item;
|
|
281
|
-
const readerArtifact =
|
|
305
|
+
const readerArtifact = resolvedReaderWithRefetchQueries.readerArtifact;
|
|
282
306
|
switch (readerArtifact.kind) {
|
|
283
307
|
case 'ComponentReaderArtifact': {
|
|
284
308
|
// @ts-expect-error We should find a way to encode this in the type system:
|
|
@@ -293,7 +317,7 @@ function readDataForOnComplete<
|
|
|
293
317
|
kind: 'ReaderWithRefetchQueries',
|
|
294
318
|
readerArtifact: readerArtifact,
|
|
295
319
|
nestedRefetchQueries:
|
|
296
|
-
|
|
320
|
+
resolvedReaderWithRefetchQueries.nestedRefetchQueries,
|
|
297
321
|
}),
|
|
298
322
|
root,
|
|
299
323
|
variables,
|
|
@@ -311,7 +335,8 @@ function readDataForOnComplete<
|
|
|
311
335
|
startUpdate: getOrCreateCachedStartUpdate(
|
|
312
336
|
environment,
|
|
313
337
|
fragment,
|
|
314
|
-
|
|
338
|
+
resolvedReaderWithRefetchQueries.readerArtifact.fieldName,
|
|
339
|
+
fakeNetworkRequestOptions,
|
|
315
340
|
),
|
|
316
341
|
}
|
|
317
342
|
: undefined),
|
package/src/core/read.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { CleanupFn } from '@isograph/disposable-types';
|
|
1
|
+
import { CleanupFn, type ItemCleanupPair } from '@isograph/disposable-types';
|
|
2
2
|
import {
|
|
3
3
|
getParentRecordKey,
|
|
4
|
-
|
|
4
|
+
insertEmptySetIfMissing,
|
|
5
5
|
onNextChangeToRecord,
|
|
6
6
|
type EncounteredIds,
|
|
7
7
|
} from './cache';
|
|
@@ -23,24 +23,24 @@ import {
|
|
|
23
23
|
getOrLoadIsographArtifact,
|
|
24
24
|
IsographEnvironment,
|
|
25
25
|
type DataTypeValue,
|
|
26
|
-
type
|
|
26
|
+
type StoreLink,
|
|
27
27
|
type StoreRecord,
|
|
28
28
|
} from './IsographEnvironment';
|
|
29
29
|
import { logMessage } from './logging';
|
|
30
30
|
import { maybeMakeNetworkRequest } from './makeNetworkRequest';
|
|
31
31
|
import {
|
|
32
32
|
getPromiseState,
|
|
33
|
+
NOT_SET,
|
|
33
34
|
PromiseWrapper,
|
|
34
35
|
readPromise,
|
|
35
|
-
Result,
|
|
36
36
|
wrapPromise,
|
|
37
37
|
wrapResolvedValue,
|
|
38
38
|
} from './PromiseWrapper';
|
|
39
39
|
import {
|
|
40
40
|
ReaderAst,
|
|
41
|
+
type LoadablySelectedField,
|
|
41
42
|
type ReaderImperativelyLoadedField,
|
|
42
43
|
type ReaderLinkedField,
|
|
43
|
-
type ReaderLoadableField,
|
|
44
44
|
type ReaderNonLoadableResolverField,
|
|
45
45
|
type ReaderScalarField,
|
|
46
46
|
} from './reader';
|
|
@@ -104,12 +104,8 @@ export function readButDoNotEvaluate<
|
|
|
104
104
|
// promise results in an infinite loop (including re-issuing the query until the
|
|
105
105
|
// process OOM's or something.) Hence, we throw an error.
|
|
106
106
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
any,
|
|
110
|
-
any
|
|
111
|
-
>;
|
|
112
|
-
if (result.kind === 'Err') {
|
|
107
|
+
const result = fragmentReference.networkRequest.result;
|
|
108
|
+
if (result !== NOT_SET && result.kind === 'Err') {
|
|
113
109
|
throw new Error('NetworkError', { cause: result.error });
|
|
114
110
|
}
|
|
115
111
|
|
|
@@ -138,20 +134,20 @@ export type ReadDataResult<Data> =
|
|
|
138
134
|
readonly kind: 'MissingData';
|
|
139
135
|
readonly reason: string;
|
|
140
136
|
readonly nestedReason?: ReadDataResult<unknown>;
|
|
141
|
-
readonly recordLink:
|
|
137
|
+
readonly recordLink: StoreLink;
|
|
142
138
|
};
|
|
143
139
|
|
|
144
140
|
function readData<TReadFromStore>(
|
|
145
141
|
environment: IsographEnvironment,
|
|
146
142
|
ast: ReaderAst<TReadFromStore>,
|
|
147
|
-
root:
|
|
143
|
+
root: StoreLink,
|
|
148
144
|
variables: Variables,
|
|
149
145
|
nestedRefetchQueries: RefetchQueryNormalizationArtifactWrapper[],
|
|
150
146
|
networkRequest: PromiseWrapper<void, any>,
|
|
151
147
|
networkRequestOptions: NetworkRequestReaderOptions,
|
|
152
148
|
mutableEncounteredRecords: EncounteredIds,
|
|
153
149
|
): ReadDataResult<ExtractData<TReadFromStore>> {
|
|
154
|
-
const encounteredIds =
|
|
150
|
+
const encounteredIds = insertEmptySetIfMissing(
|
|
155
151
|
mutableEncounteredRecords,
|
|
156
152
|
root.__typename,
|
|
157
153
|
);
|
|
@@ -196,7 +192,9 @@ function readData<TReadFromStore>(
|
|
|
196
192
|
storeRecord,
|
|
197
193
|
root,
|
|
198
194
|
variables,
|
|
195
|
+
nestedRefetchQueries,
|
|
199
196
|
networkRequest,
|
|
197
|
+
networkRequestOptions,
|
|
200
198
|
(ast, root) =>
|
|
201
199
|
readData(
|
|
202
200
|
environment,
|
|
@@ -282,8 +280,8 @@ function readData<TReadFromStore>(
|
|
|
282
280
|
|
|
283
281
|
export function readLoadablySelectedFieldData(
|
|
284
282
|
environment: IsographEnvironment,
|
|
285
|
-
field:
|
|
286
|
-
root:
|
|
283
|
+
field: LoadablySelectedField,
|
|
284
|
+
root: StoreLink,
|
|
287
285
|
variables: Variables,
|
|
288
286
|
networkRequest: PromiseWrapper<void, any>,
|
|
289
287
|
networkRequestOptions: NetworkRequestReaderOptions,
|
|
@@ -346,23 +344,23 @@ export function readLoadablySelectedFieldData(
|
|
|
346
344
|
const fragmentReferenceAndDisposeFromEntrypoint = (
|
|
347
345
|
entrypoint: IsographEntrypoint<any, any, any>,
|
|
348
346
|
): [FragmentReference<any, any>, CleanupFn] => {
|
|
347
|
+
const readerWithRefetchQueries =
|
|
348
|
+
entrypoint.readerWithRefetchQueries.kind ===
|
|
349
|
+
'ReaderWithRefetchQueriesLoader'
|
|
350
|
+
? wrapPromise(entrypoint.readerWithRefetchQueries.loader())
|
|
351
|
+
: wrapResolvedValue(entrypoint.readerWithRefetchQueries);
|
|
349
352
|
const [networkRequest, disposeNetworkRequest] =
|
|
350
353
|
maybeMakeNetworkRequest(
|
|
351
354
|
environment,
|
|
352
355
|
entrypoint,
|
|
353
356
|
localVariables,
|
|
354
|
-
|
|
357
|
+
readerWithRefetchQueries,
|
|
358
|
+
fetchOptions ?? null,
|
|
355
359
|
);
|
|
356
360
|
|
|
357
361
|
const fragmentReference: FragmentReference<any, any> = {
|
|
358
362
|
kind: 'FragmentReference',
|
|
359
|
-
readerWithRefetchQueries
|
|
360
|
-
kind: 'ReaderWithRefetchQueries',
|
|
361
|
-
readerArtifact:
|
|
362
|
-
entrypoint.readerWithRefetchQueries.readerArtifact,
|
|
363
|
-
nestedRefetchQueries:
|
|
364
|
-
entrypoint.readerWithRefetchQueries.nestedRefetchQueries,
|
|
365
|
-
} as const),
|
|
363
|
+
readerWithRefetchQueries,
|
|
366
364
|
|
|
367
365
|
// TODO localVariables is not guaranteed to have an id field
|
|
368
366
|
root,
|
|
@@ -396,6 +394,14 @@ export function readLoadablySelectedFieldData(
|
|
|
396
394
|
}
|
|
397
395
|
| { kind: 'Disposed' } = { kind: 'EntrypointNotLoaded' };
|
|
398
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
|
+
);
|
|
399
405
|
const networkRequest = wrapPromise(
|
|
400
406
|
isographArtifactPromiseWrapper.promise.then((entrypoint) => {
|
|
401
407
|
if (entrypointLoaderState.kind === 'EntrypointNotLoaded') {
|
|
@@ -404,7 +410,8 @@ export function readLoadablySelectedFieldData(
|
|
|
404
410
|
environment,
|
|
405
411
|
entrypoint,
|
|
406
412
|
localVariables,
|
|
407
|
-
|
|
413
|
+
readerWithRefetchQueries,
|
|
414
|
+
fetchOptions ?? null,
|
|
408
415
|
);
|
|
409
416
|
entrypointLoaderState = {
|
|
410
417
|
kind: 'NetworkRequestStarted',
|
|
@@ -414,14 +421,10 @@ export function readLoadablySelectedFieldData(
|
|
|
414
421
|
}
|
|
415
422
|
}),
|
|
416
423
|
);
|
|
417
|
-
const readerWithRefetchPromise =
|
|
418
|
-
isographArtifactPromiseWrapper.promise.then(
|
|
419
|
-
(entrypoint) => entrypoint.readerWithRefetchQueries,
|
|
420
|
-
);
|
|
421
424
|
|
|
422
425
|
const fragmentReference: FragmentReference<any, any> = {
|
|
423
426
|
kind: 'FragmentReference',
|
|
424
|
-
readerWithRefetchQueries
|
|
427
|
+
readerWithRefetchQueries,
|
|
425
428
|
|
|
426
429
|
// TODO localVariables is not guaranteed to have an id field
|
|
427
430
|
root,
|
|
@@ -531,7 +534,7 @@ function writeQueryArgsToVariables(
|
|
|
531
534
|
export function readResolverFieldData(
|
|
532
535
|
environment: IsographEnvironment,
|
|
533
536
|
field: ReaderNonLoadableResolverField,
|
|
534
|
-
root:
|
|
537
|
+
root: StoreLink,
|
|
535
538
|
variables: Variables,
|
|
536
539
|
nestedRefetchQueries: RefetchQueryNormalizationArtifactWrapper[],
|
|
537
540
|
networkRequest: PromiseWrapper<void, any>,
|
|
@@ -591,6 +594,7 @@ export function readResolverFieldData(
|
|
|
591
594
|
environment,
|
|
592
595
|
fragment,
|
|
593
596
|
readerWithRefetchQueries.readerArtifact.fieldName,
|
|
597
|
+
networkRequestOptions,
|
|
594
598
|
)
|
|
595
599
|
: undefined,
|
|
596
600
|
};
|
|
@@ -621,9 +625,11 @@ export function readResolverFieldData(
|
|
|
621
625
|
export function readScalarFieldData(
|
|
622
626
|
field: ReaderScalarField,
|
|
623
627
|
storeRecord: StoreRecord,
|
|
624
|
-
root:
|
|
628
|
+
root: StoreLink,
|
|
625
629
|
variables: Variables,
|
|
626
|
-
): ReadDataResult<
|
|
630
|
+
): ReadDataResult<
|
|
631
|
+
string | number | boolean | StoreLink | DataTypeValue[] | null
|
|
632
|
+
> {
|
|
627
633
|
const storeRecordName = getParentRecordKey(field, variables);
|
|
628
634
|
const value = storeRecord[storeRecordName];
|
|
629
635
|
// TODO consider making scalars into discriminated unions. This probably has
|
|
@@ -642,13 +648,14 @@ export function readLinkedFieldData(
|
|
|
642
648
|
environment: IsographEnvironment,
|
|
643
649
|
field: ReaderLinkedField,
|
|
644
650
|
storeRecord: StoreRecord,
|
|
645
|
-
root:
|
|
651
|
+
root: StoreLink,
|
|
646
652
|
variables: Variables,
|
|
653
|
+
nestedRefetchQueries: RefetchQueryNormalizationArtifactWrapper[],
|
|
647
654
|
networkRequest: PromiseWrapper<void, any>,
|
|
648
|
-
|
|
655
|
+
networkRequestOptions: NetworkRequestReaderOptions,
|
|
649
656
|
readData: <TReadFromStore>(
|
|
650
657
|
ast: ReaderAst<TReadFromStore>,
|
|
651
|
-
root:
|
|
658
|
+
root: StoreLink,
|
|
652
659
|
) => ReadDataResult<object>,
|
|
653
660
|
): ReadDataResult<unknown> {
|
|
654
661
|
const storeRecordName = getParentRecordKey(field, variables);
|
|
@@ -726,7 +733,7 @@ export function readLinkedFieldData(
|
|
|
726
733
|
variables: generateChildVariableMap(
|
|
727
734
|
variables,
|
|
728
735
|
// TODO this is wrong
|
|
729
|
-
// should use field.
|
|
736
|
+
// should use field.arguments
|
|
730
737
|
// but it doesn't exist
|
|
731
738
|
[],
|
|
732
739
|
),
|
|
@@ -742,17 +749,12 @@ export function readLinkedFieldData(
|
|
|
742
749
|
environment,
|
|
743
750
|
fragment,
|
|
744
751
|
readerWithRefetchQueries.readerArtifact.fieldName,
|
|
752
|
+
networkRequestOptions,
|
|
745
753
|
),
|
|
746
754
|
}
|
|
747
755
|
: undefined),
|
|
748
756
|
});
|
|
749
|
-
|
|
750
|
-
link = root;
|
|
751
|
-
} else if (condition === false) {
|
|
752
|
-
link = null;
|
|
753
|
-
} else {
|
|
754
|
-
link = condition;
|
|
755
|
-
}
|
|
757
|
+
link = condition;
|
|
756
758
|
}
|
|
757
759
|
|
|
758
760
|
if (link === undefined) {
|
|
@@ -797,6 +799,109 @@ export function readLinkedFieldData(
|
|
|
797
799
|
};
|
|
798
800
|
}
|
|
799
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
|
+
}
|
|
800
905
|
const data = readData(field.selections, targetId);
|
|
801
906
|
if (data.kind === 'MissingData') {
|
|
802
907
|
return {
|
|
@@ -841,7 +946,7 @@ function stableStringifyArgs(args: object) {
|
|
|
841
946
|
export function readImperativelyLoadedField(
|
|
842
947
|
environment: IsographEnvironment,
|
|
843
948
|
field: ReaderImperativelyLoadedField,
|
|
844
|
-
root:
|
|
949
|
+
root: StoreLink,
|
|
845
950
|
variables: Variables,
|
|
846
951
|
nestedRefetchQueries: RefetchQueryNormalizationArtifactWrapper[],
|
|
847
952
|
networkRequest: PromiseWrapper<void, any>,
|
|
@@ -871,11 +976,11 @@ export function readImperativelyLoadedField(
|
|
|
871
976
|
recordLink: data.recordLink,
|
|
872
977
|
};
|
|
873
978
|
} else {
|
|
874
|
-
const refetchQueryIndex = field
|
|
979
|
+
const { refetchQueryIndex } = field;
|
|
875
980
|
const refetchQuery = nestedRefetchQueries[refetchQueryIndex];
|
|
876
981
|
if (refetchQuery == null) {
|
|
877
982
|
throw new Error(
|
|
878
|
-
'
|
|
983
|
+
'Refetch query not found. This is indicative of a bug in Isograph.',
|
|
879
984
|
);
|
|
880
985
|
}
|
|
881
986
|
const refetchQueryArtifact = refetchQuery.artifact;
|
|
@@ -887,7 +992,7 @@ export function readImperativelyLoadedField(
|
|
|
887
992
|
kind: 'Success',
|
|
888
993
|
data: (args: any) => [
|
|
889
994
|
// Stable id
|
|
890
|
-
root.__link + '__' + field.name,
|
|
995
|
+
root.__typename + ':' + root.__link + '__' + field.name,
|
|
891
996
|
// Fetcher
|
|
892
997
|
field.refetchReaderArtifact.resolver(
|
|
893
998
|
environment,
|
package/src/core/reader.ts
CHANGED
|
@@ -14,7 +14,7 @@ import {
|
|
|
14
14
|
import {
|
|
15
15
|
ComponentOrFieldName,
|
|
16
16
|
IsographEnvironment,
|
|
17
|
-
type
|
|
17
|
+
type StoreLink,
|
|
18
18
|
} from './IsographEnvironment';
|
|
19
19
|
import { Arguments } from './util';
|
|
20
20
|
|
|
@@ -71,7 +71,7 @@ export type RefetchReaderArtifact = {
|
|
|
71
71
|
variables: any,
|
|
72
72
|
// TODO type this better
|
|
73
73
|
filteredVariables: any,
|
|
74
|
-
rootLink:
|
|
74
|
+
rootLink: StoreLink,
|
|
75
75
|
readerArtifact: TopLevelReaderArtifact<any, any, any> | null,
|
|
76
76
|
// TODO type this better
|
|
77
77
|
nestedRefetchQueries: RefetchQueryNormalizationArtifactWrapper[],
|
|
@@ -83,7 +83,7 @@ export type ReaderAstNode =
|
|
|
83
83
|
| ReaderLinkedField
|
|
84
84
|
| ReaderNonLoadableResolverField
|
|
85
85
|
| ReaderImperativelyLoadedField
|
|
86
|
-
|
|
|
86
|
+
| LoadablySelectedField
|
|
87
87
|
| ReaderLinkField;
|
|
88
88
|
|
|
89
89
|
// @ts-ignore
|
|
@@ -109,10 +109,14 @@ export type ReaderLinkedField = {
|
|
|
109
109
|
readonly selections: ReaderAst<unknown>;
|
|
110
110
|
readonly arguments: Arguments | null;
|
|
111
111
|
readonly condition: EagerReaderArtifact<
|
|
112
|
-
{ data:
|
|
113
|
-
|
|
112
|
+
{ data: any; parameters: any; startUpdate?: StartUpdate<any> },
|
|
113
|
+
StoreLink | null
|
|
114
114
|
> | null;
|
|
115
115
|
readonly isUpdatable: boolean;
|
|
116
|
+
/**
|
|
117
|
+
* If refetchQueryIndex != null, then the linked field is a client pointer.
|
|
118
|
+
*/
|
|
119
|
+
readonly refetchQueryIndex: number | null;
|
|
116
120
|
};
|
|
117
121
|
|
|
118
122
|
export type ReaderNonLoadableResolverField = {
|
|
@@ -128,11 +132,11 @@ export type ReaderImperativelyLoadedField = {
|
|
|
128
132
|
readonly kind: 'ImperativelyLoadedField';
|
|
129
133
|
readonly alias: string;
|
|
130
134
|
readonly refetchReaderArtifact: RefetchReaderArtifact;
|
|
131
|
-
readonly
|
|
135
|
+
readonly refetchQueryIndex: number;
|
|
132
136
|
readonly name: string;
|
|
133
137
|
};
|
|
134
138
|
|
|
135
|
-
export type
|
|
139
|
+
export type LoadablySelectedField = {
|
|
136
140
|
readonly kind: 'LoadablySelectedField';
|
|
137
141
|
readonly alias: string;
|
|
138
142
|
|