@isograph/react 0.0.0-main-5141cf39 → 0.0.0-main-7f95f0cd
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 +1 -1
- package/dist/core/cache.d.ts +1 -1
- package/dist/core/cache.d.ts.map +1 -1
- package/dist/core/check.d.ts +8 -4
- package/dist/core/check.d.ts.map +1 -1
- package/dist/core/makeNetworkRequest.d.ts +2 -2
- package/dist/core/makeNetworkRequest.d.ts.map +1 -1
- package/dist/core/makeNetworkRequest.js +72 -23
- package/dist/core/optimisticProxy.d.ts +13 -5
- package/dist/core/optimisticProxy.d.ts.map +1 -1
- package/dist/core/optimisticProxy.js +35 -8
- package/dist/core/reader.d.ts +1 -1
- package/dist/core/reader.d.ts.map +1 -1
- package/dist/loadable-hooks/useClientSideDefer.d.ts +2 -2
- package/dist/loadable-hooks/useClientSideDefer.d.ts.map +1 -1
- package/dist/loadable-hooks/useConnectionSpecPagination.d.ts +1 -1
- package/dist/loadable-hooks/useConnectionSpecPagination.d.ts.map +1 -1
- package/dist/loadable-hooks/useImperativeLoadableField.d.ts +1 -1
- package/dist/loadable-hooks/useImperativeLoadableField.d.ts.map +1 -1
- package/dist/loadable-hooks/useSkipLimitPagination.d.ts +1 -1
- package/dist/loadable-hooks/useSkipLimitPagination.d.ts.map +1 -1
- package/dist/react/LoadableFieldReader.d.ts +1 -1
- package/dist/react/LoadableFieldReader.d.ts.map +1 -1
- package/dist/react/LoadableFieldRenderer.d.ts +1 -1
- package/dist/react/LoadableFieldRenderer.d.ts.map +1 -1
- package/dist/react/useImperativeReference.d.ts +3 -3
- package/dist/react/useImperativeReference.d.ts.map +1 -1
- package/dist/react/useLazyReference.d.ts +1 -1
- package/dist/react/useLazyReference.d.ts.map +1 -1
- package/package.json +4 -4
- package/src/core/cache.ts +1 -1
- package/src/core/check.ts +10 -4
- package/src/core/makeNetworkRequest.ts +180 -43
- package/src/core/optimisticProxy.ts +67 -14
- package/src/core/read.ts +2 -2
- package/src/core/reader.ts +1 -1
- package/src/loadable-hooks/useClientSideDefer.ts +2 -2
- package/src/loadable-hooks/useConnectionSpecPagination.ts +5 -2
- package/src/loadable-hooks/useImperativeLoadableField.ts +2 -2
- package/src/loadable-hooks/useSkipLimitPagination.ts +2 -2
- package/src/react/LoadableFieldReader.tsx +1 -1
- package/src/react/LoadableFieldRenderer.tsx +1 -1
- package/src/react/useImperativeReference.ts +5 -3
- package/src/react/useLazyReference.ts +1 -1
- package/src/tests/optimisticProxy.test.ts +19 -19
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useLazyReference.d.ts","sourceRoot":"","sources":["../../src/react/useLazyReference.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,KAAK,qBAAqB,EAC3B,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,YAAY,EAAE,KAAK,oBAAoB,EAAE,MAAM,eAAe,CAAC;AACxE,OAAO,EACL,kBAAkB,EAClB,KAAK,gBAAgB,EACrB,KAAK,sBAAsB,EAC5B,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,iBAAiB,EACjB,iBAAiB,EACjB,KAAK,qBAAqB,EAC3B,MAAM,2BAA2B,CAAC;AAInC,wBAAgB,gBAAgB,CAC9B,cAAc,SAAS,qBAAqB,EAC5C,iBAAiB,EACjB,iBAAiB,SAAS,gBAAgB,GAAG,sBAAsB,EACnE,gBAAgB,SAAS,qBAAqB,EAE9C,UAAU,EAAE,kBAAkB,CAC5B,cAAc,EACd,iBAAiB,EACjB,iBAAiB,EACjB,gBAAgB,CACjB,EACD,SAAS,EAAE,iBAAiB,CAAC,cAAc,CAAC,EAC5C,GAAG,CAAC,YAAY,CAAC,EAAE,iBAAiB,SAAS,sBAAsB,GAC/D,CAAC,YAAY,EAAE,oBAAoB,CAAC,iBAAiB,CAAC,CAAC,GACvD,CAAC,YAAY,CAAC,EAAE,YAAY,CAAC,iBAAiB,CAAC,CAAC,
|
|
1
|
+
{"version":3,"file":"useLazyReference.d.ts","sourceRoot":"","sources":["../../src/react/useLazyReference.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,KAAK,qBAAqB,EAC3B,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,YAAY,EAAE,KAAK,oBAAoB,EAAE,MAAM,eAAe,CAAC;AACxE,OAAO,EACL,kBAAkB,EAClB,KAAK,gBAAgB,EACrB,KAAK,sBAAsB,EAC5B,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,iBAAiB,EACjB,iBAAiB,EACjB,KAAK,qBAAqB,EAC3B,MAAM,2BAA2B,CAAC;AAInC,wBAAgB,gBAAgB,CAC9B,cAAc,SAAS,qBAAqB,EAC5C,iBAAiB,EACjB,iBAAiB,SAAS,gBAAgB,GAAG,sBAAsB,EACnE,gBAAgB,SAAS,qBAAqB,EAE9C,UAAU,EAAE,kBAAkB,CAC5B,cAAc,EACd,iBAAiB,EACjB,iBAAiB,EACjB,gBAAgB,CACjB,EACD,SAAS,EAAE,iBAAiB,CAAC,cAAc,CAAC,EAC5C,GAAG,CAAC,YAAY,CAAC,EAAE,iBAAiB,SAAS,sBAAsB,GAC/D,CAAC,YAAY,EAAE,oBAAoB,CAAC,iBAAiB,CAAC,CAAC,GACvD,CAAC,YAAY,CAAC,EAAE,YAAY,CAAC,iBAAiB,EAAE,gBAAgB,CAAC,CAAC,GACrE,gBAAgB,GAAG,sBAAsB,SAAS,iBAAiB,GAClE,OAAO,GACP;IACE,iBAAiB,EAAE,iBAAiB,CAAC,cAAc,EAAE,iBAAiB,CAAC,CAAC;CACzE,CAqBJ"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@isograph/react",
|
|
3
|
-
"version": "0.0.0-main-
|
|
3
|
+
"version": "0.0.0-main-7f95f0cd",
|
|
4
4
|
"description": "Use Isograph with React",
|
|
5
5
|
"homepage": "https://isograph.dev",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -8,9 +8,9 @@
|
|
|
8
8
|
"author": "Isograph Labs",
|
|
9
9
|
"license": "MIT",
|
|
10
10
|
"dependencies": {
|
|
11
|
-
"@isograph/disposable-types": "0.0.0-main-
|
|
12
|
-
"@isograph/reference-counted-pointer": "0.0.0-main-
|
|
13
|
-
"@isograph/react-disposable-state": "0.0.0-main-
|
|
11
|
+
"@isograph/disposable-types": "0.0.0-main-7f95f0cd",
|
|
12
|
+
"@isograph/reference-counted-pointer": "0.0.0-main-7f95f0cd",
|
|
13
|
+
"@isograph/react-disposable-state": "0.0.0-main-7f95f0cd"
|
|
14
14
|
},
|
|
15
15
|
"peerDependencies": {
|
|
16
16
|
"react": "^18.0.0 || ^19.0.0"
|
package/src/core/cache.ts
CHANGED
|
@@ -100,7 +100,7 @@ export function getOrCreateCacheForArtifact<
|
|
|
100
100
|
TRawResponseType
|
|
101
101
|
>,
|
|
102
102
|
variables: ExtractParameters<TReadFromStore>,
|
|
103
|
-
fetchOptions?: FetchOptions<TClientFieldValue>,
|
|
103
|
+
fetchOptions?: FetchOptions<TClientFieldValue, TRawResponseType>,
|
|
104
104
|
): ParentCache<FragmentReference<TReadFromStore, TClientFieldValue>> {
|
|
105
105
|
let cacheKey = '';
|
|
106
106
|
switch (entrypoint.networkRequestInfo.operation.kind) {
|
package/src/core/check.ts
CHANGED
|
@@ -15,15 +15,21 @@ export type RequiredShouldFetch = 'Yes' | 'No';
|
|
|
15
15
|
|
|
16
16
|
export const DEFAULT_SHOULD_FETCH_VALUE: ShouldFetch = 'IfNecessary';
|
|
17
17
|
|
|
18
|
-
|
|
19
|
-
shouldFetch?: ShouldFetch;
|
|
18
|
+
type FetchOptionsShared<TReadOutData> = {
|
|
20
19
|
onComplete?: (data: TReadOutData) => void;
|
|
21
20
|
onError?: () => void;
|
|
22
21
|
};
|
|
23
22
|
|
|
24
|
-
export
|
|
23
|
+
export interface FetchOptions<TReadOutData, TRawResponseType>
|
|
24
|
+
extends FetchOptionsShared<TReadOutData> {
|
|
25
|
+
shouldFetch?: ShouldFetch;
|
|
26
|
+
optimisticNetworkResponse?: TRawResponseType;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export interface RequiredFetchOptions<TReadOutData>
|
|
30
|
+
extends FetchOptionsShared<TReadOutData> {
|
|
25
31
|
shouldFetch: RequiredShouldFetch;
|
|
26
|
-
}
|
|
32
|
+
}
|
|
27
33
|
|
|
28
34
|
export type CheckResult =
|
|
29
35
|
| {
|
|
@@ -27,7 +27,13 @@ import {
|
|
|
27
27
|
} from './garbageCollection';
|
|
28
28
|
import { IsographEnvironment, ROOT_ID, StoreLink } from './IsographEnvironment';
|
|
29
29
|
import { logMessage } from './logging';
|
|
30
|
-
import {
|
|
30
|
+
import {
|
|
31
|
+
addNetworkResponseStoreLayer,
|
|
32
|
+
addOptimisticNetworkResponseStoreLayer,
|
|
33
|
+
revertOptimisticStoreLayerAndMaybeReplace,
|
|
34
|
+
type OptimisticStoreLayer,
|
|
35
|
+
type StoreLayerWithData,
|
|
36
|
+
} from './optimisticProxy';
|
|
31
37
|
import {
|
|
32
38
|
AnyError,
|
|
33
39
|
PromiseWrapper,
|
|
@@ -58,7 +64,7 @@ export function maybeMakeNetworkRequest<
|
|
|
58
64
|
readerWithRefetchQueries: PromiseWrapper<
|
|
59
65
|
ReaderWithRefetchQueries<TReadFromStore, TClientFieldValue>
|
|
60
66
|
> | null,
|
|
61
|
-
fetchOptions: FetchOptions<TClientFieldValue> | null,
|
|
67
|
+
fetchOptions: FetchOptions<TClientFieldValue, TRawResponseType> | null,
|
|
62
68
|
): ItemCleanupPair<PromiseWrapper<void, AnyError>> {
|
|
63
69
|
switch (fetchOptions?.shouldFetch ?? DEFAULT_SHOULD_FETCH_VALUE) {
|
|
64
70
|
case 'Yes': {
|
|
@@ -83,7 +89,8 @@ export function maybeMakeNetworkRequest<
|
|
|
83
89
|
'NormalizationAstLoader'
|
|
84
90
|
) {
|
|
85
91
|
throw new Error(
|
|
86
|
-
'Using lazy loaded normalizationAst with shouldFetch: "IfNecessary" is
|
|
92
|
+
'Using lazy loaded normalizationAst with shouldFetch: "IfNecessary" is ' +
|
|
93
|
+
'not supported as it will lead to a network waterfall.',
|
|
87
94
|
);
|
|
88
95
|
}
|
|
89
96
|
const result = check(
|
|
@@ -131,8 +138,10 @@ export function retainQueryWithoutMakingNetworkRequest<
|
|
|
131
138
|
>,
|
|
132
139
|
variables: ExtractParameters<TReadFromStore>,
|
|
133
140
|
): ItemCleanupPair<PromiseWrapper<void, AnyError>> {
|
|
134
|
-
let status:
|
|
135
|
-
|
|
141
|
+
let status:
|
|
142
|
+
| NetworkRequestStatusUndisposedComplete
|
|
143
|
+
| NetworkRequestStatusDisposed = {
|
|
144
|
+
kind: 'UndisposedComplete',
|
|
136
145
|
retainedQuery: fetchNormalizationAstAndRetainArtifact(
|
|
137
146
|
environment,
|
|
138
147
|
artifact,
|
|
@@ -142,12 +151,9 @@ export function retainQueryWithoutMakingNetworkRequest<
|
|
|
142
151
|
return [
|
|
143
152
|
wrapResolvedValue(undefined),
|
|
144
153
|
() => {
|
|
145
|
-
if (status.kind
|
|
146
|
-
unretainAndGarbageCollect(environment, status);
|
|
154
|
+
if (status.kind !== 'Disposed') {
|
|
155
|
+
status = unretainAndGarbageCollect(environment, status);
|
|
147
156
|
}
|
|
148
|
-
status = {
|
|
149
|
-
kind: 'Disposed',
|
|
150
|
-
};
|
|
151
157
|
},
|
|
152
158
|
];
|
|
153
159
|
}
|
|
@@ -171,18 +177,27 @@ export function makeNetworkRequest<
|
|
|
171
177
|
readerWithRefetchQueries: PromiseWrapper<
|
|
172
178
|
ReaderWithRefetchQueries<TReadFromStore, TClientFieldValue>
|
|
173
179
|
> | null,
|
|
174
|
-
fetchOptions: FetchOptions<TClientFieldValue> | null,
|
|
180
|
+
fetchOptions: FetchOptions<TClientFieldValue, TRawResponseType> | null,
|
|
175
181
|
): ItemCleanupPair<PromiseWrapper<void, AnyError>> {
|
|
176
182
|
// TODO this should be a DataId and stored in the store
|
|
177
183
|
const myNetworkRequestId = networkRequestId + '';
|
|
178
184
|
networkRequestId++;
|
|
179
185
|
let status: NetworkRequestStatus = {
|
|
180
|
-
kind: '
|
|
186
|
+
kind: 'UndisposedIncomplete',
|
|
181
187
|
retainedQuery: fetchNormalizationAstAndRetainArtifact(
|
|
182
188
|
environment,
|
|
183
189
|
artifact,
|
|
184
190
|
variables,
|
|
185
191
|
),
|
|
192
|
+
optimistic:
|
|
193
|
+
fetchOptions?.optimisticNetworkResponse != null
|
|
194
|
+
? makeOptimisticUpdate(
|
|
195
|
+
environment,
|
|
196
|
+
artifact,
|
|
197
|
+
variables,
|
|
198
|
+
fetchOptions?.optimisticNetworkResponse,
|
|
199
|
+
)
|
|
200
|
+
: null,
|
|
186
201
|
};
|
|
187
202
|
|
|
188
203
|
logMessage(environment, () => ({
|
|
@@ -218,26 +233,50 @@ export function makeNetworkRequest<
|
|
|
218
233
|
}
|
|
219
234
|
|
|
220
235
|
const root = { __link: ROOT_ID, __typename: artifact.concreteType };
|
|
221
|
-
if (status.kind === 'Undisposed') {
|
|
222
|
-
const encounteredIds: EncounteredIds = new Map();
|
|
223
|
-
environment.store = addNetworkResponseStoreLayer(environment.store);
|
|
224
|
-
normalizeData(
|
|
225
|
-
environment,
|
|
226
|
-
environment.store,
|
|
227
|
-
normalizationAst.selections,
|
|
228
|
-
networkResponse.data ?? {},
|
|
229
|
-
variables,
|
|
230
|
-
root,
|
|
231
|
-
encounteredIds,
|
|
232
|
-
);
|
|
233
236
|
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
237
|
+
if (status.kind === 'UndisposedIncomplete') {
|
|
238
|
+
if (status.optimistic != null) {
|
|
239
|
+
status =
|
|
240
|
+
revertOptimisticStoreLayerAndMaybeReplaceIfUndisposedIncomplete(
|
|
241
|
+
environment,
|
|
242
|
+
status,
|
|
243
|
+
(storeLayer) =>
|
|
244
|
+
normalizeData(
|
|
245
|
+
environment,
|
|
246
|
+
storeLayer,
|
|
247
|
+
normalizationAst.selections,
|
|
248
|
+
networkResponse.data ?? {},
|
|
249
|
+
variables,
|
|
250
|
+
root,
|
|
251
|
+
new Map(),
|
|
252
|
+
),
|
|
253
|
+
);
|
|
254
|
+
} else {
|
|
255
|
+
const encounteredIds: EncounteredIds = new Map();
|
|
256
|
+
environment.store = addNetworkResponseStoreLayer(environment.store);
|
|
257
|
+
normalizeData(
|
|
258
|
+
environment,
|
|
259
|
+
environment.store,
|
|
260
|
+
normalizationAst.selections,
|
|
261
|
+
networkResponse.data ?? {},
|
|
262
|
+
variables,
|
|
263
|
+
root,
|
|
264
|
+
encounteredIds,
|
|
265
|
+
);
|
|
266
|
+
|
|
267
|
+
logMessage(environment, () => ({
|
|
268
|
+
kind: 'AfterNormalization',
|
|
269
|
+
store: environment.store,
|
|
270
|
+
encounteredIds: encounteredIds,
|
|
271
|
+
}));
|
|
239
272
|
|
|
240
|
-
|
|
273
|
+
callSubscriptions(environment, encounteredIds);
|
|
274
|
+
|
|
275
|
+
status = {
|
|
276
|
+
kind: 'UndisposedComplete',
|
|
277
|
+
retainedQuery: status.retainedQuery,
|
|
278
|
+
};
|
|
279
|
+
}
|
|
241
280
|
}
|
|
242
281
|
|
|
243
282
|
const onComplete = fetchOptions?.onComplete;
|
|
@@ -268,6 +307,16 @@ export function makeNetworkRequest<
|
|
|
268
307
|
try {
|
|
269
308
|
fetchOptions?.onError?.();
|
|
270
309
|
} catch {}
|
|
310
|
+
|
|
311
|
+
if (status.kind === 'UndisposedIncomplete') {
|
|
312
|
+
status =
|
|
313
|
+
revertOptimisticStoreLayerAndMaybeReplaceIfUndisposedIncomplete(
|
|
314
|
+
environment,
|
|
315
|
+
status,
|
|
316
|
+
null,
|
|
317
|
+
);
|
|
318
|
+
}
|
|
319
|
+
|
|
271
320
|
throw e;
|
|
272
321
|
});
|
|
273
322
|
|
|
@@ -276,27 +325,41 @@ export function makeNetworkRequest<
|
|
|
276
325
|
const response: ItemCleanupPair<PromiseWrapper<void, AnyError>> = [
|
|
277
326
|
wrapper,
|
|
278
327
|
() => {
|
|
279
|
-
if (status.kind === '
|
|
280
|
-
|
|
328
|
+
if (status.kind === 'UndisposedIncomplete') {
|
|
329
|
+
status =
|
|
330
|
+
revertOptimisticStoreLayerAndMaybeReplaceIfUndisposedIncomplete(
|
|
331
|
+
environment,
|
|
332
|
+
status,
|
|
333
|
+
null,
|
|
334
|
+
);
|
|
335
|
+
}
|
|
336
|
+
if (status.kind !== 'Disposed') {
|
|
337
|
+
status = unretainAndGarbageCollect(environment, status);
|
|
281
338
|
}
|
|
282
|
-
status = {
|
|
283
|
-
kind: 'Disposed',
|
|
284
|
-
};
|
|
285
339
|
},
|
|
286
340
|
];
|
|
287
341
|
return response;
|
|
288
342
|
}
|
|
289
343
|
|
|
290
|
-
type
|
|
291
|
-
readonly kind: '
|
|
344
|
+
type NetworkRequestStatusUndisposedIncomplete = {
|
|
345
|
+
readonly kind: 'UndisposedIncomplete';
|
|
292
346
|
readonly retainedQuery: RetainedQuery;
|
|
347
|
+
readonly optimistic: OptimisticStoreLayer | null;
|
|
348
|
+
};
|
|
349
|
+
|
|
350
|
+
type NetworkRequestStatusUndisposedComplete = {
|
|
351
|
+
readonly kind: 'UndisposedComplete';
|
|
352
|
+
readonly retainedQuery: RetainedQuery;
|
|
353
|
+
};
|
|
354
|
+
|
|
355
|
+
type NetworkRequestStatusDisposed = {
|
|
356
|
+
readonly kind: 'Disposed';
|
|
293
357
|
};
|
|
294
358
|
|
|
295
359
|
type NetworkRequestStatus =
|
|
296
|
-
|
|
|
297
|
-
|
|
|
298
|
-
|
|
299
|
-
};
|
|
360
|
+
| NetworkRequestStatusUndisposedIncomplete
|
|
361
|
+
| NetworkRequestStatusUndisposedComplete
|
|
362
|
+
| NetworkRequestStatusDisposed;
|
|
300
363
|
|
|
301
364
|
function readDataForOnComplete<
|
|
302
365
|
TReadFromStore extends UnknownTReadFromStore,
|
|
@@ -438,12 +501,86 @@ function fetchNormalizationAstAndRetainArtifact<
|
|
|
438
501
|
return retainedQuery;
|
|
439
502
|
}
|
|
440
503
|
|
|
504
|
+
function makeOptimisticUpdate<
|
|
505
|
+
TReadFromStore extends UnknownTReadFromStore,
|
|
506
|
+
TClientFieldValue,
|
|
507
|
+
TNormalizationAst extends NormalizationAst | NormalizationAstLoader,
|
|
508
|
+
TRawResponseType extends NetworkResponseObject,
|
|
509
|
+
>(
|
|
510
|
+
environment: IsographEnvironment,
|
|
511
|
+
artifact:
|
|
512
|
+
| RefetchQueryNormalizationArtifact
|
|
513
|
+
| IsographEntrypoint<
|
|
514
|
+
TReadFromStore,
|
|
515
|
+
TClientFieldValue,
|
|
516
|
+
TNormalizationAst,
|
|
517
|
+
TRawResponseType
|
|
518
|
+
>,
|
|
519
|
+
variables: ExtractParameters<TReadFromStore>,
|
|
520
|
+
optimisticNetworkResponse: TRawResponseType,
|
|
521
|
+
): OptimisticStoreLayer {
|
|
522
|
+
const root = { __link: ROOT_ID, __typename: artifact.concreteType };
|
|
523
|
+
|
|
524
|
+
if (
|
|
525
|
+
artifact.networkRequestInfo.normalizationAst.kind ===
|
|
526
|
+
'NormalizationAstLoader'
|
|
527
|
+
) {
|
|
528
|
+
throw new Error(
|
|
529
|
+
'Using lazy loaded normalizationAst with optimisticNetworkResponse is not supported.',
|
|
530
|
+
);
|
|
531
|
+
}
|
|
532
|
+
const encounteredIds: EncounteredIds = new Map();
|
|
533
|
+
const optimistic = (environment.store =
|
|
534
|
+
addOptimisticNetworkResponseStoreLayer(environment.store));
|
|
535
|
+
normalizeData(
|
|
536
|
+
environment,
|
|
537
|
+
environment.store,
|
|
538
|
+
artifact.networkRequestInfo.normalizationAst.selections,
|
|
539
|
+
optimisticNetworkResponse,
|
|
540
|
+
variables,
|
|
541
|
+
root,
|
|
542
|
+
encounteredIds,
|
|
543
|
+
);
|
|
544
|
+
|
|
545
|
+
logMessage(environment, () => ({
|
|
546
|
+
kind: 'AfterNormalization',
|
|
547
|
+
store: environment.store,
|
|
548
|
+
encounteredIds: encounteredIds,
|
|
549
|
+
}));
|
|
550
|
+
|
|
551
|
+
callSubscriptions(environment, encounteredIds);
|
|
552
|
+
return optimistic;
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
function revertOptimisticStoreLayerAndMaybeReplaceIfUndisposedIncomplete(
|
|
556
|
+
environment: IsographEnvironment,
|
|
557
|
+
status: NetworkRequestStatusUndisposedIncomplete,
|
|
558
|
+
normalizeData: null | ((storeLayer: StoreLayerWithData) => void),
|
|
559
|
+
): NetworkRequestStatusUndisposedComplete {
|
|
560
|
+
if (status.optimistic) {
|
|
561
|
+
revertOptimisticStoreLayerAndMaybeReplace(
|
|
562
|
+
environment,
|
|
563
|
+
status.optimistic,
|
|
564
|
+
normalizeData,
|
|
565
|
+
);
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
return {
|
|
569
|
+
kind: 'UndisposedComplete',
|
|
570
|
+
retainedQuery: status.retainedQuery,
|
|
571
|
+
};
|
|
572
|
+
}
|
|
573
|
+
|
|
441
574
|
function unretainAndGarbageCollect(
|
|
442
575
|
environment: IsographEnvironment,
|
|
443
|
-
status:
|
|
444
|
-
) {
|
|
576
|
+
status: NetworkRequestStatusUndisposedComplete,
|
|
577
|
+
): NetworkRequestStatusDisposed {
|
|
445
578
|
const didUnretainSomeQuery = unretainQuery(environment, status.retainedQuery);
|
|
446
579
|
if (didUnretainSomeQuery) {
|
|
447
580
|
garbageCollectEnvironment(environment);
|
|
448
581
|
}
|
|
582
|
+
|
|
583
|
+
return {
|
|
584
|
+
kind: 'Disposed',
|
|
585
|
+
};
|
|
449
586
|
}
|
|
@@ -122,8 +122,28 @@ export type StartUpdateStoreLayer = {
|
|
|
122
122
|
startUpdate: DataUpdate<StartUpdateStoreLayer | BaseStoreLayer>;
|
|
123
123
|
};
|
|
124
124
|
|
|
125
|
-
export type OptimisticStoreLayer =
|
|
126
|
-
|
|
125
|
+
export type OptimisticStoreLayer =
|
|
126
|
+
| OptimisticUpdaterStoreLayer
|
|
127
|
+
| OptimisticNetworkResponseStoreLayer;
|
|
128
|
+
|
|
129
|
+
export type OptimisticUpdaterStoreLayer = {
|
|
130
|
+
readonly kind: 'OptimisticUpdaterStoreLayer';
|
|
131
|
+
childStoreLayer:
|
|
132
|
+
| OptimisticStoreLayer
|
|
133
|
+
| StartUpdateStoreLayer
|
|
134
|
+
| NetworkResponseStoreLayer
|
|
135
|
+
| null;
|
|
136
|
+
parentStoreLayer:
|
|
137
|
+
| OptimisticStoreLayer
|
|
138
|
+
| StartUpdateStoreLayer
|
|
139
|
+
| NetworkResponseStoreLayer
|
|
140
|
+
| BaseStoreLayer;
|
|
141
|
+
data: StoreLayerData;
|
|
142
|
+
readonly startUpdate: DataUpdate<OptimisticUpdaterStoreLayer>;
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
export type OptimisticNetworkResponseStoreLayer = {
|
|
146
|
+
readonly kind: 'OptimisticNetworkResponseStoreLayer';
|
|
127
147
|
childStoreLayer:
|
|
128
148
|
| OptimisticStoreLayer
|
|
129
149
|
| StartUpdateStoreLayer
|
|
@@ -135,7 +155,6 @@ export type OptimisticStoreLayer = {
|
|
|
135
155
|
| NetworkResponseStoreLayer
|
|
136
156
|
| BaseStoreLayer;
|
|
137
157
|
data: StoreLayerData;
|
|
138
|
-
readonly startUpdate: DataUpdate<OptimisticStoreLayer>;
|
|
139
158
|
};
|
|
140
159
|
|
|
141
160
|
export function addNetworkResponseStoreLayer(
|
|
@@ -147,7 +166,8 @@ export function addNetworkResponseStoreLayer(
|
|
|
147
166
|
return parent;
|
|
148
167
|
}
|
|
149
168
|
case 'StartUpdateStoreLayer':
|
|
150
|
-
case '
|
|
169
|
+
case 'OptimisticNetworkResponseStoreLayer':
|
|
170
|
+
case 'OptimisticUpdaterStoreLayer': {
|
|
151
171
|
const node: NetworkResponseStoreLayer = {
|
|
152
172
|
kind: 'NetworkResponseStoreLayer',
|
|
153
173
|
parentStoreLayer: parent,
|
|
@@ -205,7 +225,8 @@ export function addStartUpdateStoreLayer(
|
|
|
205
225
|
return node;
|
|
206
226
|
}
|
|
207
227
|
case 'NetworkResponseStoreLayer':
|
|
208
|
-
case '
|
|
228
|
+
case 'OptimisticNetworkResponseStoreLayer':
|
|
229
|
+
case 'OptimisticUpdaterStoreLayer': {
|
|
209
230
|
const node: StartUpdateStoreLayer = {
|
|
210
231
|
kind: 'StartUpdateStoreLayer',
|
|
211
232
|
parentStoreLayer: parent,
|
|
@@ -225,17 +246,18 @@ export function addStartUpdateStoreLayer(
|
|
|
225
246
|
}
|
|
226
247
|
}
|
|
227
248
|
|
|
228
|
-
export function
|
|
249
|
+
export function addOptimisticUpdaterStoreLayer(
|
|
229
250
|
parent: StoreLayer,
|
|
230
|
-
startUpdate:
|
|
231
|
-
):
|
|
251
|
+
startUpdate: OptimisticUpdaterStoreLayer['startUpdate'],
|
|
252
|
+
): OptimisticUpdaterStoreLayer {
|
|
232
253
|
switch (parent.kind) {
|
|
233
254
|
case 'BaseStoreLayer':
|
|
234
255
|
case 'StartUpdateStoreLayer':
|
|
235
256
|
case 'NetworkResponseStoreLayer':
|
|
236
|
-
case '
|
|
237
|
-
|
|
238
|
-
|
|
257
|
+
case 'OptimisticNetworkResponseStoreLayer':
|
|
258
|
+
case 'OptimisticUpdaterStoreLayer': {
|
|
259
|
+
const node: OptimisticUpdaterStoreLayer = {
|
|
260
|
+
kind: 'OptimisticUpdaterStoreLayer',
|
|
239
261
|
parentStoreLayer: parent,
|
|
240
262
|
childStoreLayer: null,
|
|
241
263
|
data: {},
|
|
@@ -254,6 +276,33 @@ export function addOptimisticStoreLayer(
|
|
|
254
276
|
}
|
|
255
277
|
}
|
|
256
278
|
|
|
279
|
+
export function addOptimisticNetworkResponseStoreLayer(
|
|
280
|
+
parent: StoreLayer,
|
|
281
|
+
): OptimisticNetworkResponseStoreLayer {
|
|
282
|
+
switch (parent.kind) {
|
|
283
|
+
case 'BaseStoreLayer':
|
|
284
|
+
case 'StartUpdateStoreLayer':
|
|
285
|
+
case 'NetworkResponseStoreLayer':
|
|
286
|
+
case 'OptimisticNetworkResponseStoreLayer':
|
|
287
|
+
case 'OptimisticUpdaterStoreLayer': {
|
|
288
|
+
const node: OptimisticNetworkResponseStoreLayer = {
|
|
289
|
+
kind: 'OptimisticNetworkResponseStoreLayer',
|
|
290
|
+
parentStoreLayer: parent,
|
|
291
|
+
childStoreLayer: null,
|
|
292
|
+
data: {},
|
|
293
|
+
};
|
|
294
|
+
|
|
295
|
+
parent.childStoreLayer = node;
|
|
296
|
+
|
|
297
|
+
return node;
|
|
298
|
+
}
|
|
299
|
+
default: {
|
|
300
|
+
parent satisfies never;
|
|
301
|
+
throw new Error('Unreachable. This is a bug in Isograph.');
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
|
|
257
306
|
/**
|
|
258
307
|
* Merge storeLayerToMerge, and its children, into baseStoreLayer.
|
|
259
308
|
* We can merge until we reach a revertible layer (i.e. an optimistic layer).
|
|
@@ -273,7 +322,7 @@ function mergeLayersWithDataIntoBaseLayer(
|
|
|
273
322
|
) {
|
|
274
323
|
while (
|
|
275
324
|
storeLayerToMerge &&
|
|
276
|
-
storeLayerToMerge.kind !== '
|
|
325
|
+
storeLayerToMerge.kind !== 'OptimisticUpdaterStoreLayer'
|
|
277
326
|
) {
|
|
278
327
|
mergeDataLayer(baseStoreLayer.data, storeLayerToMerge.data);
|
|
279
328
|
storeLayerToMerge = storeLayerToMerge.childStoreLayer;
|
|
@@ -309,6 +358,7 @@ function reexecuteUpdatesAndMergeData(
|
|
|
309
358
|
while (storeLayer !== null) {
|
|
310
359
|
mergeDataLayer(oldMergedData, storeLayer.data);
|
|
311
360
|
switch (storeLayer.kind) {
|
|
361
|
+
case 'OptimisticNetworkResponseStoreLayer':
|
|
312
362
|
case 'NetworkResponseStoreLayer':
|
|
313
363
|
break;
|
|
314
364
|
case 'StartUpdateStoreLayer': {
|
|
@@ -316,7 +366,7 @@ function reexecuteUpdatesAndMergeData(
|
|
|
316
366
|
storeLayer.startUpdate(storeLayer);
|
|
317
367
|
break;
|
|
318
368
|
}
|
|
319
|
-
case '
|
|
369
|
+
case 'OptimisticUpdaterStoreLayer': {
|
|
320
370
|
storeLayer.data = {};
|
|
321
371
|
storeLayer.startUpdate(storeLayer);
|
|
322
372
|
break;
|
|
@@ -467,7 +517,10 @@ export type StoreLayer =
|
|
|
467
517
|
| StartUpdateStoreLayer
|
|
468
518
|
| BaseStoreLayer;
|
|
469
519
|
|
|
470
|
-
export type StoreLayerWithData =
|
|
520
|
+
export type StoreLayerWithData =
|
|
521
|
+
| BaseStoreLayer
|
|
522
|
+
| NetworkResponseStoreLayer
|
|
523
|
+
| OptimisticNetworkResponseStoreLayer;
|
|
471
524
|
|
|
472
525
|
function compareData(
|
|
473
526
|
oldData: StoreLayerData,
|
package/src/core/read.ts
CHANGED
|
@@ -316,7 +316,7 @@ export function readLoadablySelectedFieldData(
|
|
|
316
316
|
data: (
|
|
317
317
|
args: any,
|
|
318
318
|
// TODO get the associated type for FetchOptions from the loadably selected field
|
|
319
|
-
fetchOptions?: FetchOptions<any>,
|
|
319
|
+
fetchOptions?: FetchOptions<any, never>,
|
|
320
320
|
) => {
|
|
321
321
|
// TODO we should use the reader AST for this
|
|
322
322
|
const includeReadOutData = (variables: any, readOutData: any) => {
|
|
@@ -919,7 +919,7 @@ export function readClientPointerData(
|
|
|
919
919
|
data: (
|
|
920
920
|
args: any,
|
|
921
921
|
// TODO get the associated type for FetchOptions from the loadably selected field
|
|
922
|
-
fetchOptions?: FetchOptions<any>,
|
|
922
|
+
fetchOptions?: FetchOptions<any, never>,
|
|
923
923
|
) => {
|
|
924
924
|
const includeReadOutData = (variables: any, readOutData: any) => {
|
|
925
925
|
variables.id = readOutData.id;
|
package/src/core/reader.ts
CHANGED
|
@@ -177,5 +177,5 @@ export type LoadableField<
|
|
|
177
177
|
// user-facing API. Users should only interact with LoadableFields via APIs
|
|
178
178
|
// like useClientSideDefer. These APIs should have a nullable fetchOptions
|
|
179
179
|
// parameter, and provide a default value ({}) to the LoadableField.
|
|
180
|
-
fetchOptions: FetchOptions<TResult>,
|
|
180
|
+
fetchOptions: FetchOptions<TResult, never>,
|
|
181
181
|
) => [StableId, Factory<FragmentReference<TReadFromStore, TResult>>];
|
|
@@ -30,11 +30,11 @@ export function useClientSideDefer<
|
|
|
30
30
|
>
|
|
31
31
|
? [
|
|
32
32
|
args?: ArgsWithoutProvidedArgs<TReadFromStore, TProvidedArgs>,
|
|
33
|
-
fetchOptions?: FetchOptions<TResult>,
|
|
33
|
+
fetchOptions?: FetchOptions<TResult, never>,
|
|
34
34
|
]
|
|
35
35
|
: [
|
|
36
36
|
args: ArgsWithoutProvidedArgs<TReadFromStore, TProvidedArgs>,
|
|
37
|
-
fetchOptions?: FetchOptions<TResult>,
|
|
37
|
+
fetchOptions?: FetchOptions<TResult, never>,
|
|
38
38
|
]
|
|
39
39
|
): { fragmentReference: FragmentReference<TReadFromStore, TResult> } {
|
|
40
40
|
const [args, fetchOptions] = maybeRequiredArgs;
|
|
@@ -38,7 +38,7 @@ export type UsePaginationReturnValue<
|
|
|
38
38
|
kind: 'HasMoreRecords';
|
|
39
39
|
fetchMore: (
|
|
40
40
|
count: number,
|
|
41
|
-
fetchOptions?: FetchOptions<Connection<TItem
|
|
41
|
+
fetchOptions?: FetchOptions<Connection<TItem>, never>,
|
|
42
42
|
) => void;
|
|
43
43
|
results: ReadonlyArray<TItem>;
|
|
44
44
|
}
|
|
@@ -210,7 +210,10 @@ export function useConnectionSpecPagination<
|
|
|
210
210
|
|
|
211
211
|
const getFetchMore =
|
|
212
212
|
(after: string | null) =>
|
|
213
|
-
(
|
|
213
|
+
(
|
|
214
|
+
count: number,
|
|
215
|
+
fetchOptions?: FetchOptions<Connection<TItem>, never>,
|
|
216
|
+
): void => {
|
|
214
217
|
const loadedField = loadableField(
|
|
215
218
|
{
|
|
216
219
|
after: after,
|
|
@@ -19,7 +19,7 @@ export type UseImperativeLoadableFieldReturn<
|
|
|
19
19
|
// TODO this should be void iff all args are provided by the query, like in
|
|
20
20
|
// useClientSideDefer.
|
|
21
21
|
args: Omit<ExtractParameters<TReadFromStore>, keyof TProvidedArgs> | void,
|
|
22
|
-
fetchOptions?: FetchOptions<TResult>,
|
|
22
|
+
fetchOptions?: FetchOptions<TResult, never>,
|
|
23
23
|
) => void;
|
|
24
24
|
};
|
|
25
25
|
|
|
@@ -40,7 +40,7 @@ export function useImperativeLoadableField<
|
|
|
40
40
|
return {
|
|
41
41
|
loadFragmentReference: (
|
|
42
42
|
args: Omit<ExtractParameters<TReadFromStore>, keyof TProvidedArgs> | void,
|
|
43
|
-
fetchOptions?: FetchOptions<TResult>,
|
|
43
|
+
fetchOptions?: FetchOptions<TResult, never>,
|
|
44
44
|
) => {
|
|
45
45
|
const [_id, loader] = loadableField(args, fetchOptions ?? {});
|
|
46
46
|
setState(loader());
|
|
@@ -33,7 +33,7 @@ export type UseSkipLimitReturnValue<
|
|
|
33
33
|
readonly kind: 'Complete';
|
|
34
34
|
readonly fetchMore: (
|
|
35
35
|
count: number,
|
|
36
|
-
fetchOptions?: FetchOptions<ReadonlyArray<TItem
|
|
36
|
+
fetchOptions?: FetchOptions<ReadonlyArray<TItem>, never>,
|
|
37
37
|
) => void;
|
|
38
38
|
readonly results: ReadonlyArray<TItem>;
|
|
39
39
|
}
|
|
@@ -196,7 +196,7 @@ export function useSkipLimitPagination<
|
|
|
196
196
|
(loadedSoFar: number) =>
|
|
197
197
|
(
|
|
198
198
|
count: number,
|
|
199
|
-
fetchOptions?: FetchOptions<ReadonlyArray<TItem
|
|
199
|
+
fetchOptions?: FetchOptions<ReadonlyArray<TItem>, never>,
|
|
200
200
|
): void => {
|
|
201
201
|
const loadedField = loadableField(
|
|
202
202
|
{
|
|
@@ -38,7 +38,7 @@ export function LoadableFieldReader<
|
|
|
38
38
|
TResult,
|
|
39
39
|
Omit<ExtractParameters<TReadFromStore>, keyof TProvidedArgs>
|
|
40
40
|
>;
|
|
41
|
-
fetchOptions?: FetchOptions<TResult>;
|
|
41
|
+
fetchOptions?: FetchOptions<TResult, never>;
|
|
42
42
|
networkRequestOptions?: Partial<NetworkRequestReaderOptions>;
|
|
43
43
|
children: (arg: TResult) => TChildrenResult;
|
|
44
44
|
} & MaybeRequiredArgs<TReadFromStore, TProvidedArgs>,
|
|
@@ -38,7 +38,7 @@ export function LoadableFieldRenderer<
|
|
|
38
38
|
React.FC<TProps>,
|
|
39
39
|
Omit<ExtractParameters<TReadFromStore>, keyof TProvidedArgs>
|
|
40
40
|
>;
|
|
41
|
-
fetchOptions?: FetchOptions<React.FC<TProps
|
|
41
|
+
fetchOptions?: FetchOptions<React.FC<TProps>, never>;
|
|
42
42
|
networkRequestOptions?: Partial<NetworkRequestReaderOptions>;
|
|
43
43
|
additionalProps: Omit<TProps, keyof JSX.IntrinsicAttributes>;
|
|
44
44
|
} & MaybeRequiredArgs<TReadFromStore, TProvidedArgs>,
|