@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/cache.ts
CHANGED
|
@@ -3,56 +3,52 @@ import {
|
|
|
3
3
|
ItemCleanupPair,
|
|
4
4
|
ParentCache,
|
|
5
5
|
} from '@isograph/react-disposable-state';
|
|
6
|
-
import {
|
|
7
|
-
DataId,
|
|
8
|
-
Link,
|
|
9
|
-
ROOT_ID,
|
|
10
|
-
StoreRecord,
|
|
11
|
-
type IsographEnvironment,
|
|
12
|
-
DataTypeValue,
|
|
13
|
-
getLink,
|
|
14
|
-
FragmentSubscription,
|
|
15
|
-
type TypeName,
|
|
16
|
-
} from './IsographEnvironment';
|
|
17
6
|
import {
|
|
18
7
|
IsographEntrypoint,
|
|
19
|
-
NormalizationAst,
|
|
20
8
|
NormalizationInlineFragment,
|
|
21
9
|
NormalizationLinkedField,
|
|
22
10
|
NormalizationScalarField,
|
|
23
|
-
|
|
11
|
+
type NormalizationAst,
|
|
12
|
+
type NormalizationAstLoader,
|
|
13
|
+
type NormalizationAstNodes,
|
|
24
14
|
} from '../core/entrypoint';
|
|
25
|
-
import {
|
|
26
|
-
import {
|
|
27
|
-
import { WithEncounteredRecords, readButDoNotEvaluate } from './read';
|
|
15
|
+
import { mergeObjectsUsingReaderAst } from './areEqualWithDeepComparison';
|
|
16
|
+
import { FetchOptions } from './check';
|
|
28
17
|
import {
|
|
18
|
+
ExtractParameters,
|
|
29
19
|
FragmentReference,
|
|
30
20
|
Variables,
|
|
31
|
-
|
|
21
|
+
type UnknownTReadFromStore,
|
|
22
|
+
type VariableValue,
|
|
32
23
|
} from './FragmentReference';
|
|
33
|
-
import {
|
|
34
|
-
|
|
35
|
-
|
|
24
|
+
import {
|
|
25
|
+
DataId,
|
|
26
|
+
DataTypeValue,
|
|
27
|
+
FragmentSubscription,
|
|
28
|
+
getLink,
|
|
29
|
+
ROOT_ID,
|
|
30
|
+
StoreLink,
|
|
31
|
+
StoreRecord,
|
|
32
|
+
type IsographEnvironment,
|
|
33
|
+
type TypeName,
|
|
34
|
+
} from './IsographEnvironment';
|
|
36
35
|
import { logMessage } from './logging';
|
|
37
|
-
import {
|
|
36
|
+
import { maybeMakeNetworkRequest } from './makeNetworkRequest';
|
|
37
|
+
import { wrapPromise, wrapResolvedValue } from './PromiseWrapper';
|
|
38
|
+
import { readButDoNotEvaluate, WithEncounteredRecords } from './read';
|
|
39
|
+
import { ReaderLinkedField, ReaderScalarField, type ReaderAst } from './reader';
|
|
40
|
+
import { Argument, ArgumentValue } from './util';
|
|
38
41
|
|
|
39
42
|
export const TYPENAME_FIELD_NAME = '__typename';
|
|
40
43
|
|
|
41
44
|
export function getOrCreateItemInSuspenseCache<
|
|
42
|
-
TReadFromStore extends
|
|
45
|
+
TReadFromStore extends UnknownTReadFromStore,
|
|
43
46
|
TClientFieldValue,
|
|
44
47
|
>(
|
|
45
48
|
environment: IsographEnvironment,
|
|
46
49
|
index: string,
|
|
47
50
|
factory: Factory<FragmentReference<TReadFromStore, TClientFieldValue>>,
|
|
48
51
|
): ParentCache<FragmentReference<TReadFromStore, TClientFieldValue>> {
|
|
49
|
-
// TODO this is probably a useless message, we should remove it
|
|
50
|
-
logMessage(environment, {
|
|
51
|
-
kind: 'GettingSuspenseCacheItem',
|
|
52
|
-
index,
|
|
53
|
-
availableCacheItems: Object.keys(environment.fragmentCache),
|
|
54
|
-
found: !!environment.fragmentCache[index],
|
|
55
|
-
});
|
|
56
52
|
if (environment.fragmentCache[index] == null) {
|
|
57
53
|
environment.fragmentCache[index] = new ParentCache(factory);
|
|
58
54
|
}
|
|
@@ -83,23 +79,44 @@ export function stableCopy<T>(value: T): T {
|
|
|
83
79
|
}
|
|
84
80
|
|
|
85
81
|
export function getOrCreateCacheForArtifact<
|
|
86
|
-
TReadFromStore extends
|
|
82
|
+
TReadFromStore extends UnknownTReadFromStore,
|
|
87
83
|
TClientFieldValue,
|
|
84
|
+
TNormalizationAst extends NormalizationAst | NormalizationAstLoader,
|
|
88
85
|
>(
|
|
89
86
|
environment: IsographEnvironment,
|
|
90
|
-
entrypoint: IsographEntrypoint<
|
|
87
|
+
entrypoint: IsographEntrypoint<
|
|
88
|
+
TReadFromStore,
|
|
89
|
+
TClientFieldValue,
|
|
90
|
+
TNormalizationAst
|
|
91
|
+
>,
|
|
91
92
|
variables: ExtractParameters<TReadFromStore>,
|
|
92
|
-
fetchOptions?: FetchOptions
|
|
93
|
+
fetchOptions?: FetchOptions<TClientFieldValue>,
|
|
93
94
|
): ParentCache<FragmentReference<TReadFromStore, TClientFieldValue>> {
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
95
|
+
let cacheKey = '';
|
|
96
|
+
switch (entrypoint.networkRequestInfo.operation.kind) {
|
|
97
|
+
case 'Operation':
|
|
98
|
+
cacheKey =
|
|
99
|
+
entrypoint.networkRequestInfo.operation.text +
|
|
100
|
+
JSON.stringify(stableCopy(variables));
|
|
101
|
+
break;
|
|
102
|
+
case 'PersistedOperation':
|
|
103
|
+
cacheKey =
|
|
104
|
+
entrypoint.networkRequestInfo.operation.operationId +
|
|
105
|
+
JSON.stringify(stableCopy(variables));
|
|
106
|
+
break;
|
|
107
|
+
}
|
|
97
108
|
const factory = () => {
|
|
109
|
+
const readerWithRefetchQueries =
|
|
110
|
+
entrypoint.readerWithRefetchQueries.kind ===
|
|
111
|
+
'ReaderWithRefetchQueriesLoader'
|
|
112
|
+
? wrapPromise(entrypoint.readerWithRefetchQueries.loader())
|
|
113
|
+
: wrapResolvedValue(entrypoint.readerWithRefetchQueries);
|
|
98
114
|
const [networkRequest, disposeNetworkRequest] = maybeMakeNetworkRequest(
|
|
99
115
|
environment,
|
|
100
116
|
entrypoint,
|
|
101
117
|
variables,
|
|
102
|
-
|
|
118
|
+
readerWithRefetchQueries,
|
|
119
|
+
fetchOptions ?? null,
|
|
103
120
|
);
|
|
104
121
|
|
|
105
122
|
const itemCleanupPair: ItemCleanupPair<
|
|
@@ -107,12 +124,7 @@ export function getOrCreateCacheForArtifact<
|
|
|
107
124
|
> = [
|
|
108
125
|
{
|
|
109
126
|
kind: 'FragmentReference',
|
|
110
|
-
readerWithRefetchQueries
|
|
111
|
-
kind: 'ReaderWithRefetchQueries',
|
|
112
|
-
readerArtifact: entrypoint.readerWithRefetchQueries.readerArtifact,
|
|
113
|
-
nestedRefetchQueries:
|
|
114
|
-
entrypoint.readerWithRefetchQueries.nestedRefetchQueries,
|
|
115
|
-
}),
|
|
127
|
+
readerWithRefetchQueries,
|
|
116
128
|
root: { __link: ROOT_ID, __typename: entrypoint.concreteType },
|
|
117
129
|
variables,
|
|
118
130
|
networkRequest: networkRequest,
|
|
@@ -124,8 +136,8 @@ export function getOrCreateCacheForArtifact<
|
|
|
124
136
|
return getOrCreateItemInSuspenseCache(environment, cacheKey, factory);
|
|
125
137
|
}
|
|
126
138
|
|
|
127
|
-
type NetworkResponseScalarValue = string | number | boolean;
|
|
128
|
-
type NetworkResponseValue =
|
|
139
|
+
export type NetworkResponseScalarValue = string | number | boolean;
|
|
140
|
+
export type NetworkResponseValue =
|
|
129
141
|
| NetworkResponseScalarValue
|
|
130
142
|
| null
|
|
131
143
|
| NetworkResponseObject
|
|
@@ -142,20 +154,19 @@ export type NetworkResponseObject = {
|
|
|
142
154
|
|
|
143
155
|
export function normalizeData(
|
|
144
156
|
environment: IsographEnvironment,
|
|
145
|
-
normalizationAst:
|
|
157
|
+
normalizationAst: NormalizationAstNodes,
|
|
146
158
|
networkResponse: NetworkResponseObject,
|
|
147
159
|
variables: Variables,
|
|
148
|
-
|
|
149
|
-
root: Link,
|
|
160
|
+
root: StoreLink,
|
|
150
161
|
): EncounteredIds {
|
|
151
162
|
const encounteredIds: EncounteredIds = new Map();
|
|
152
163
|
|
|
153
|
-
logMessage(environment, {
|
|
164
|
+
logMessage(environment, () => ({
|
|
154
165
|
kind: 'AboutToNormalize',
|
|
155
166
|
normalizationAst,
|
|
156
167
|
networkResponse,
|
|
157
168
|
variables,
|
|
158
|
-
});
|
|
169
|
+
}));
|
|
159
170
|
|
|
160
171
|
const recordsById = (environment.store[root.__typename] ??= {});
|
|
161
172
|
const newStoreRecord = (recordsById[root.__link] ??= {});
|
|
@@ -167,15 +178,14 @@ export function normalizeData(
|
|
|
167
178
|
newStoreRecord,
|
|
168
179
|
root,
|
|
169
180
|
variables,
|
|
170
|
-
nestedRefetchQueries,
|
|
171
181
|
encounteredIds,
|
|
172
182
|
);
|
|
173
183
|
|
|
174
|
-
logMessage(environment, {
|
|
184
|
+
logMessage(environment, () => ({
|
|
175
185
|
kind: 'AfterNormalization',
|
|
176
186
|
store: environment.store,
|
|
177
187
|
encounteredIds,
|
|
178
|
-
});
|
|
188
|
+
}));
|
|
179
189
|
|
|
180
190
|
callSubscriptions(environment, encounteredIds);
|
|
181
191
|
return encounteredIds;
|
|
@@ -195,7 +205,7 @@ export function subscribeToAnyChange(
|
|
|
195
205
|
|
|
196
206
|
export function subscribeToAnyChangesToRecord(
|
|
197
207
|
environment: IsographEnvironment,
|
|
198
|
-
recordLink:
|
|
208
|
+
recordLink: StoreLink,
|
|
199
209
|
callback: () => void,
|
|
200
210
|
): () => void {
|
|
201
211
|
const subscription = {
|
|
@@ -208,9 +218,7 @@ export function subscribeToAnyChangesToRecord(
|
|
|
208
218
|
}
|
|
209
219
|
|
|
210
220
|
// TODO we should re-read and call callback if the value has changed
|
|
211
|
-
export function subscribe<
|
|
212
|
-
TReadFromStore extends { parameters: object; data: object },
|
|
213
|
-
>(
|
|
221
|
+
export function subscribe<TReadFromStore extends UnknownTReadFromStore>(
|
|
214
222
|
environment: IsographEnvironment,
|
|
215
223
|
encounteredDataAndRecords: WithEncounteredRecords<TReadFromStore>,
|
|
216
224
|
fragmentReference: FragmentReference<TReadFromStore, any>,
|
|
@@ -232,7 +240,7 @@ export function subscribe<
|
|
|
232
240
|
|
|
233
241
|
export function onNextChangeToRecord(
|
|
234
242
|
environment: IsographEnvironment,
|
|
235
|
-
recordLink:
|
|
243
|
+
recordLink: StoreLink,
|
|
236
244
|
): Promise<void> {
|
|
237
245
|
return new Promise((resolve) => {
|
|
238
246
|
const unsubscribe = subscribeToAnyChangesToRecord(
|
|
@@ -251,20 +259,28 @@ export function onNextChangeToRecord(
|
|
|
251
259
|
//
|
|
252
260
|
// That's probably okay to ignore. We don't, however, want to prevent
|
|
253
261
|
// updating other subscriptions if one subscription had missing data.
|
|
254
|
-
function withErrorHandling<T>(
|
|
262
|
+
function withErrorHandling<T>(
|
|
263
|
+
environment: IsographEnvironment,
|
|
264
|
+
f: (t: T) => void,
|
|
265
|
+
): (t: T) => void {
|
|
255
266
|
return (t) => {
|
|
256
267
|
try {
|
|
257
268
|
return f(t);
|
|
258
|
-
} catch {
|
|
269
|
+
} catch (e) {
|
|
270
|
+
logMessage(environment, () => ({
|
|
271
|
+
kind: 'ErrorEncounteredInWithErrorHandling',
|
|
272
|
+
error: e,
|
|
273
|
+
}));
|
|
274
|
+
}
|
|
259
275
|
};
|
|
260
276
|
}
|
|
261
277
|
|
|
262
|
-
function callSubscriptions(
|
|
278
|
+
export function callSubscriptions(
|
|
263
279
|
environment: IsographEnvironment,
|
|
264
280
|
recordsEncounteredWhenNormalizing: EncounteredIds,
|
|
265
281
|
) {
|
|
266
282
|
environment.subscriptions.forEach(
|
|
267
|
-
withErrorHandling((subscription) => {
|
|
283
|
+
withErrorHandling(environment, (subscription) => {
|
|
268
284
|
switch (subscription.kind) {
|
|
269
285
|
case 'FragmentSubscription': {
|
|
270
286
|
// TODO if there are multiple components subscribed to the same
|
|
@@ -303,14 +319,14 @@ function callSubscriptions(
|
|
|
303
319
|
newEncounteredDataAndRecords.item,
|
|
304
320
|
);
|
|
305
321
|
|
|
306
|
-
logMessage(environment, {
|
|
322
|
+
logMessage(environment, () => ({
|
|
307
323
|
kind: 'DeepEqualityCheck',
|
|
308
324
|
fragmentReference: subscription.fragmentReference,
|
|
309
325
|
old: subscription.encounteredDataAndRecords.item,
|
|
310
326
|
new: newEncounteredDataAndRecords.item,
|
|
311
327
|
deeplyEqual:
|
|
312
328
|
mergedItem === subscription.encounteredDataAndRecords.item,
|
|
313
|
-
});
|
|
329
|
+
}));
|
|
314
330
|
|
|
315
331
|
if (mergedItem !== subscription.encounteredDataAndRecords.item) {
|
|
316
332
|
subscription.callback(newEncounteredDataAndRecords);
|
|
@@ -376,12 +392,11 @@ export type EncounteredIds = Map<TypeName, Set<DataId>>;
|
|
|
376
392
|
*/
|
|
377
393
|
function normalizeDataIntoRecord(
|
|
378
394
|
environment: IsographEnvironment,
|
|
379
|
-
normalizationAst:
|
|
395
|
+
normalizationAst: NormalizationAstNodes,
|
|
380
396
|
networkResponseParentRecord: NetworkResponseObject,
|
|
381
397
|
targetParentRecord: StoreRecord,
|
|
382
|
-
targetParentRecordLink:
|
|
398
|
+
targetParentRecordLink: StoreLink,
|
|
383
399
|
variables: Variables,
|
|
384
|
-
nestedRefetchQueries: RefetchQueryNormalizationArtifactWrapper[],
|
|
385
400
|
mutableEncounteredIds: EncounteredIds,
|
|
386
401
|
): RecordHasBeenUpdated {
|
|
387
402
|
let recordHasBeenUpdated = false;
|
|
@@ -406,7 +421,6 @@ function normalizeDataIntoRecord(
|
|
|
406
421
|
targetParentRecord,
|
|
407
422
|
targetParentRecordLink,
|
|
408
423
|
variables,
|
|
409
|
-
nestedRefetchQueries,
|
|
410
424
|
mutableEncounteredIds,
|
|
411
425
|
);
|
|
412
426
|
recordHasBeenUpdated =
|
|
@@ -421,7 +435,6 @@ function normalizeDataIntoRecord(
|
|
|
421
435
|
targetParentRecord,
|
|
422
436
|
targetParentRecordLink,
|
|
423
437
|
variables,
|
|
424
|
-
nestedRefetchQueries,
|
|
425
438
|
mutableEncounteredIds,
|
|
426
439
|
);
|
|
427
440
|
recordHasBeenUpdated =
|
|
@@ -437,7 +450,7 @@ function normalizeDataIntoRecord(
|
|
|
437
450
|
}
|
|
438
451
|
}
|
|
439
452
|
if (recordHasBeenUpdated) {
|
|
440
|
-
let encounteredRecordsIds =
|
|
453
|
+
let encounteredRecordsIds = insertEmptySetIfMissing(
|
|
441
454
|
mutableEncounteredIds,
|
|
442
455
|
targetParentRecordLink.__typename,
|
|
443
456
|
);
|
|
@@ -447,7 +460,7 @@ function normalizeDataIntoRecord(
|
|
|
447
460
|
return recordHasBeenUpdated;
|
|
448
461
|
}
|
|
449
462
|
|
|
450
|
-
export function
|
|
463
|
+
export function insertEmptySetIfMissing<K, V>(map: Map<K, Set<V>>, key: K) {
|
|
451
464
|
let result = map.get(key);
|
|
452
465
|
if (result === undefined) {
|
|
453
466
|
result = new Set();
|
|
@@ -487,9 +500,8 @@ function normalizeLinkedField(
|
|
|
487
500
|
astNode: NormalizationLinkedField,
|
|
488
501
|
networkResponseParentRecord: NetworkResponseObject,
|
|
489
502
|
targetParentRecord: StoreRecord,
|
|
490
|
-
targetParentRecordLink:
|
|
503
|
+
targetParentRecordLink: StoreLink,
|
|
491
504
|
variables: Variables,
|
|
492
|
-
nestedRefetchQueries: RefetchQueryNormalizationArtifactWrapper[],
|
|
493
505
|
mutableEncounteredIds: EncounteredIds,
|
|
494
506
|
): RecordHasBeenUpdated {
|
|
495
507
|
const networkResponseKey = getNetworkResponseKey(astNode);
|
|
@@ -513,7 +525,7 @@ function normalizeLinkedField(
|
|
|
513
525
|
|
|
514
526
|
if (Array.isArray(networkResponseData)) {
|
|
515
527
|
// TODO check astNode.plural or the like
|
|
516
|
-
const dataIds: (
|
|
528
|
+
const dataIds: (StoreLink | null)[] = [];
|
|
517
529
|
for (let i = 0; i < networkResponseData.length; i++) {
|
|
518
530
|
const networkResponseObject = networkResponseData[i];
|
|
519
531
|
if (networkResponseObject == null) {
|
|
@@ -527,7 +539,6 @@ function normalizeLinkedField(
|
|
|
527
539
|
targetParentRecordLink,
|
|
528
540
|
variables,
|
|
529
541
|
i,
|
|
530
|
-
nestedRefetchQueries,
|
|
531
542
|
mutableEncounteredIds,
|
|
532
543
|
);
|
|
533
544
|
|
|
@@ -554,7 +565,6 @@ function normalizeLinkedField(
|
|
|
554
565
|
targetParentRecordLink,
|
|
555
566
|
variables,
|
|
556
567
|
null,
|
|
557
|
-
nestedRefetchQueries,
|
|
558
568
|
mutableEncounteredIds,
|
|
559
569
|
);
|
|
560
570
|
|
|
@@ -586,9 +596,8 @@ function normalizeInlineFragment(
|
|
|
586
596
|
astNode: NormalizationInlineFragment,
|
|
587
597
|
networkResponseParentRecord: NetworkResponseObject,
|
|
588
598
|
targetParentRecord: StoreRecord,
|
|
589
|
-
targetParentRecordLink:
|
|
599
|
+
targetParentRecordLink: StoreLink,
|
|
590
600
|
variables: Variables,
|
|
591
|
-
nestedRefetchQueries: RefetchQueryNormalizationArtifactWrapper[],
|
|
592
601
|
mutableEncounteredIds: EncounteredIds,
|
|
593
602
|
): RecordHasBeenUpdated {
|
|
594
603
|
const typeToRefineTo = astNode.type;
|
|
@@ -600,7 +609,6 @@ function normalizeInlineFragment(
|
|
|
600
609
|
targetParentRecord,
|
|
601
610
|
targetParentRecordLink,
|
|
602
611
|
variables,
|
|
603
|
-
nestedRefetchQueries,
|
|
604
612
|
mutableEncounteredIds,
|
|
605
613
|
);
|
|
606
614
|
return hasBeenModified;
|
|
@@ -610,7 +618,7 @@ function normalizeInlineFragment(
|
|
|
610
618
|
|
|
611
619
|
function dataIdsAreTheSame(
|
|
612
620
|
existingValue: DataTypeValue,
|
|
613
|
-
newDataIds: (
|
|
621
|
+
newDataIds: (StoreLink | null)[],
|
|
614
622
|
): boolean {
|
|
615
623
|
if (Array.isArray(existingValue)) {
|
|
616
624
|
if (newDataIds.length !== existingValue.length) {
|
|
@@ -635,10 +643,9 @@ function normalizeNetworkResponseObject(
|
|
|
635
643
|
environment: IsographEnvironment,
|
|
636
644
|
astNode: NormalizationLinkedField,
|
|
637
645
|
networkResponseData: NetworkResponseObject,
|
|
638
|
-
targetParentRecordLink:
|
|
646
|
+
targetParentRecordLink: StoreLink,
|
|
639
647
|
variables: Variables,
|
|
640
648
|
index: number | null,
|
|
641
|
-
nestedRefetchQueries: RefetchQueryNormalizationArtifactWrapper[],
|
|
642
649
|
mutableEncounteredIds: EncounteredIds,
|
|
643
650
|
): DataId /* The id of the modified or newly created item */ {
|
|
644
651
|
const newStoreRecordId = getDataIdOfNetworkResponse(
|
|
@@ -668,7 +675,6 @@ function normalizeNetworkResponseObject(
|
|
|
668
675
|
newStoreRecord,
|
|
669
676
|
{ __link: newStoreRecordId, __typename: __typename },
|
|
670
677
|
variables,
|
|
671
|
-
nestedRefetchQueries,
|
|
672
678
|
mutableEncounteredIds,
|
|
673
679
|
);
|
|
674
680
|
|
|
@@ -724,8 +730,19 @@ export function getParentRecordKey(
|
|
|
724
730
|
function getStoreKeyChunkForArgumentValue(
|
|
725
731
|
argumentValue: ArgumentValue,
|
|
726
732
|
variables: Variables,
|
|
727
|
-
) {
|
|
733
|
+
): VariableValue {
|
|
728
734
|
switch (argumentValue.kind) {
|
|
735
|
+
case 'Object': {
|
|
736
|
+
return Object.fromEntries(
|
|
737
|
+
argumentValue.value.map(([argumentName, argumentValue]) => {
|
|
738
|
+
return [
|
|
739
|
+
argumentName,
|
|
740
|
+
// substitute variables
|
|
741
|
+
getStoreKeyChunkForArgumentValue(argumentValue, variables),
|
|
742
|
+
];
|
|
743
|
+
}),
|
|
744
|
+
);
|
|
745
|
+
}
|
|
729
746
|
case 'Literal': {
|
|
730
747
|
return argumentValue.value;
|
|
731
748
|
}
|
|
@@ -749,8 +766,14 @@ function getStoreKeyChunkForArgumentValue(
|
|
|
749
766
|
}
|
|
750
767
|
|
|
751
768
|
function getStoreKeyChunkForArgument(argument: Argument, variables: Variables) {
|
|
752
|
-
const
|
|
753
|
-
|
|
769
|
+
const [argumentName, argumentValue] = argument;
|
|
770
|
+
let chunk = getStoreKeyChunkForArgumentValue(argumentValue, variables);
|
|
771
|
+
|
|
772
|
+
if (typeof chunk === 'object') {
|
|
773
|
+
chunk = JSON.stringify(stableCopy(chunk));
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
return `${FIRST_SPLIT_KEY}${argumentName}${SECOND_SPLIT_KEY}${chunk}`;
|
|
754
777
|
}
|
|
755
778
|
|
|
756
779
|
function getNetworkResponseKey(
|
|
@@ -758,47 +781,64 @@ function getNetworkResponseKey(
|
|
|
758
781
|
): string {
|
|
759
782
|
let networkResponseKey = astNode.fieldName;
|
|
760
783
|
const fieldParameters = astNode.arguments;
|
|
784
|
+
|
|
761
785
|
if (fieldParameters != null) {
|
|
762
|
-
for (const
|
|
763
|
-
|
|
764
|
-
let argumentValueChunk;
|
|
765
|
-
switch (argumentValue.kind) {
|
|
766
|
-
case 'Literal': {
|
|
767
|
-
argumentValueChunk = 'l_' + argumentValue.value;
|
|
768
|
-
break;
|
|
769
|
-
}
|
|
770
|
-
case 'Variable': {
|
|
771
|
-
argumentValueChunk = 'v_' + argumentValue.name;
|
|
772
|
-
break;
|
|
773
|
-
}
|
|
774
|
-
case 'String': {
|
|
775
|
-
argumentValueChunk = 's_' + argumentValue.value;
|
|
776
|
-
break;
|
|
777
|
-
}
|
|
778
|
-
case 'Enum': {
|
|
779
|
-
argumentValueChunk = 'e_' + argumentValue.value;
|
|
780
|
-
break;
|
|
781
|
-
}
|
|
782
|
-
default: {
|
|
783
|
-
// Ensure we have covered all variants
|
|
784
|
-
let _: never = argumentValue;
|
|
785
|
-
_;
|
|
786
|
-
throw new Error('Unexpected case');
|
|
787
|
-
}
|
|
788
|
-
}
|
|
786
|
+
for (const [argumentName, argumentValue] of fieldParameters) {
|
|
787
|
+
let argumentValueChunk = getArgumentValueChunk(argumentValue);
|
|
789
788
|
networkResponseKey += `${FIRST_SPLIT_KEY}${argumentName}${SECOND_SPLIT_KEY}${argumentValueChunk}`;
|
|
790
789
|
}
|
|
791
790
|
}
|
|
791
|
+
|
|
792
792
|
return networkResponseKey;
|
|
793
793
|
}
|
|
794
794
|
|
|
795
|
+
function getArgumentValueChunk(argumentValue: ArgumentValue): string {
|
|
796
|
+
switch (argumentValue.kind) {
|
|
797
|
+
case 'Object': {
|
|
798
|
+
return (
|
|
799
|
+
'o_' +
|
|
800
|
+
argumentValue.value
|
|
801
|
+
.map(([argumentName, argumentValue]) => {
|
|
802
|
+
return (
|
|
803
|
+
argumentName +
|
|
804
|
+
THIRD_SPLIT_KEY +
|
|
805
|
+
getArgumentValueChunk(argumentValue)
|
|
806
|
+
);
|
|
807
|
+
})
|
|
808
|
+
.join('_') +
|
|
809
|
+
'_c'
|
|
810
|
+
);
|
|
811
|
+
}
|
|
812
|
+
case 'Literal': {
|
|
813
|
+
return 'l_' + argumentValue.value;
|
|
814
|
+
}
|
|
815
|
+
case 'Variable': {
|
|
816
|
+
return 'v_' + argumentValue.name;
|
|
817
|
+
}
|
|
818
|
+
case 'String': {
|
|
819
|
+
// replace all non-word characters (alphanumeric & underscore) with underscores
|
|
820
|
+
return 's_' + argumentValue.value.replaceAll(/\W/g, '_');
|
|
821
|
+
}
|
|
822
|
+
case 'Enum': {
|
|
823
|
+
return 'e_' + argumentValue.value;
|
|
824
|
+
}
|
|
825
|
+
default: {
|
|
826
|
+
// Ensure we have covered all variants
|
|
827
|
+
let _: never = argumentValue;
|
|
828
|
+
_;
|
|
829
|
+
throw new Error('Unexpected case');
|
|
830
|
+
}
|
|
831
|
+
}
|
|
832
|
+
}
|
|
833
|
+
|
|
795
834
|
// an alias might be pullRequests____first___first____after___cursor
|
|
796
835
|
export const FIRST_SPLIT_KEY = '____';
|
|
797
836
|
export const SECOND_SPLIT_KEY = '___';
|
|
837
|
+
export const THIRD_SPLIT_KEY = '__';
|
|
798
838
|
|
|
799
839
|
// Returns a key to look up an item in the store
|
|
800
840
|
function getDataIdOfNetworkResponse(
|
|
801
|
-
parentRecordLink:
|
|
841
|
+
parentRecordLink: StoreLink,
|
|
802
842
|
dataToNormalize: NetworkResponseObject,
|
|
803
843
|
astNode: NormalizationLinkedField,
|
|
804
844
|
variables: Variables,
|
package/src/core/check.ts
CHANGED
|
@@ -1,38 +1,43 @@
|
|
|
1
1
|
import { getParentRecordKey } from './cache';
|
|
2
|
-
import {
|
|
2
|
+
import { NormalizationAstNodes } from './entrypoint';
|
|
3
3
|
import { Variables } from './FragmentReference';
|
|
4
4
|
import {
|
|
5
5
|
getLink,
|
|
6
6
|
IsographEnvironment,
|
|
7
|
-
|
|
7
|
+
StoreLink,
|
|
8
8
|
StoreRecord,
|
|
9
9
|
} from './IsographEnvironment';
|
|
10
10
|
import { logMessage } from './logging';
|
|
11
11
|
|
|
12
|
-
export type ShouldFetch =
|
|
12
|
+
export type ShouldFetch = RequiredShouldFetch | 'IfNecessary';
|
|
13
|
+
export type RequiredShouldFetch = 'Yes' | 'No';
|
|
13
14
|
|
|
14
15
|
export const DEFAULT_SHOULD_FETCH_VALUE: ShouldFetch = 'IfNecessary';
|
|
15
16
|
|
|
16
|
-
export type FetchOptions = {
|
|
17
|
+
export type FetchOptions<TReadOutData> = {
|
|
17
18
|
shouldFetch?: ShouldFetch;
|
|
18
|
-
onComplete?: () => void;
|
|
19
|
+
onComplete?: (data: TReadOutData) => void;
|
|
19
20
|
onError?: () => void;
|
|
20
21
|
};
|
|
21
22
|
|
|
23
|
+
export type RequiredFetchOptions<TReadOutData> = {
|
|
24
|
+
shouldFetch: RequiredShouldFetch;
|
|
25
|
+
} & FetchOptions<TReadOutData>;
|
|
26
|
+
|
|
22
27
|
export type CheckResult =
|
|
23
28
|
| {
|
|
24
29
|
kind: 'EnoughData';
|
|
25
30
|
}
|
|
26
31
|
| {
|
|
27
32
|
kind: 'MissingData';
|
|
28
|
-
record:
|
|
33
|
+
record: StoreLink;
|
|
29
34
|
};
|
|
30
35
|
|
|
31
36
|
export function check(
|
|
32
37
|
environment: IsographEnvironment,
|
|
33
|
-
normalizationAst:
|
|
38
|
+
normalizationAst: NormalizationAstNodes,
|
|
34
39
|
variables: Variables,
|
|
35
|
-
root:
|
|
40
|
+
root: StoreLink,
|
|
36
41
|
): CheckResult {
|
|
37
42
|
const recordsById = (environment.store[root.__typename] ??= {});
|
|
38
43
|
const newStoreRecord = (recordsById[root.__link] ??= {});
|
|
@@ -44,19 +49,19 @@ export function check(
|
|
|
44
49
|
newStoreRecord,
|
|
45
50
|
root,
|
|
46
51
|
);
|
|
47
|
-
logMessage(environment, {
|
|
52
|
+
logMessage(environment, () => ({
|
|
48
53
|
kind: 'EnvironmentCheck',
|
|
49
54
|
result: checkResult,
|
|
50
|
-
});
|
|
55
|
+
}));
|
|
51
56
|
return checkResult;
|
|
52
57
|
}
|
|
53
58
|
|
|
54
59
|
function checkFromRecord(
|
|
55
60
|
environment: IsographEnvironment,
|
|
56
|
-
normalizationAst:
|
|
61
|
+
normalizationAst: NormalizationAstNodes,
|
|
57
62
|
variables: Variables,
|
|
58
63
|
record: StoreRecord,
|
|
59
|
-
recordLink:
|
|
64
|
+
recordLink: StoreLink,
|
|
60
65
|
): CheckResult {
|
|
61
66
|
normalizationAstLoop: for (const normalizationAstNode of normalizationAst) {
|
|
62
67
|
switch (normalizationAstNode.kind) {
|