@isograph/react 0.2.0 → 0.3.1
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-typescript.log +4 -0
- package/dist/core/FragmentReference.d.ts +25 -6
- package/dist/core/FragmentReference.d.ts.map +1 -0
- package/dist/core/FragmentReference.js +3 -13
- package/dist/core/IsographEnvironment.d.ts +34 -26
- package/dist/core/IsographEnvironment.d.ts.map +1 -0
- package/dist/core/IsographEnvironment.js +19 -22
- package/dist/core/PromiseWrapper.d.ts +4 -4
- package/dist/core/PromiseWrapper.d.ts.map +1 -0
- package/dist/core/PromiseWrapper.js +9 -9
- package/dist/core/areEqualWithDeepComparison.d.ts +5 -3
- package/dist/core/areEqualWithDeepComparison.d.ts.map +1 -0
- package/dist/core/areEqualWithDeepComparison.js +89 -39
- package/dist/core/cache.d.ts +20 -13
- package/dist/core/cache.d.ts.map +1 -0
- package/dist/core/cache.js +205 -128
- package/dist/core/check.d.ts +22 -0
- package/dist/core/check.d.ts.map +1 -0
- package/dist/core/check.js +127 -0
- package/dist/core/componentCache.d.ts +2 -2
- package/dist/core/componentCache.d.ts.map +1 -0
- package/dist/core/componentCache.js +28 -32
- package/dist/core/entrypoint.d.ts +31 -15
- package/dist/core/entrypoint.d.ts.map +1 -0
- package/dist/core/entrypoint.js +1 -2
- package/dist/core/garbageCollection.d.ts +6 -5
- package/dist/core/garbageCollection.d.ts.map +1 -0
- package/dist/core/garbageCollection.js +49 -16
- package/dist/core/logging.d.ts +68 -0
- package/dist/core/logging.d.ts.map +1 -0
- package/dist/core/logging.js +22 -0
- package/dist/core/makeNetworkRequest.d.ts +6 -3
- package/dist/core/makeNetworkRequest.d.ts.map +1 -0
- package/dist/core/makeNetworkRequest.js +160 -19
- package/dist/core/read.d.ts +25 -5
- package/dist/core/read.d.ts.map +1 -0
- package/dist/core/read.js +416 -259
- package/dist/core/reader.d.ts +31 -15
- package/dist/core/reader.d.ts.map +1 -0
- package/dist/core/startUpdate.d.ts +5 -0
- package/dist/core/startUpdate.d.ts.map +1 -0
- package/dist/core/startUpdate.js +15 -0
- package/dist/core/util.d.ts +5 -0
- package/dist/core/util.d.ts.map +1 -0
- package/dist/index.d.ts +19 -14
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +11 -2
- package/dist/loadable-hooks/useClientSideDefer.d.ts +9 -3
- package/dist/loadable-hooks/useClientSideDefer.d.ts.map +1 -0
- package/dist/loadable-hooks/useClientSideDefer.js +6 -8
- package/dist/loadable-hooks/useConnectionSpecPagination.d.ts +27 -0
- package/dist/loadable-hooks/useConnectionSpecPagination.d.ts.map +1 -0
- package/dist/loadable-hooks/useConnectionSpecPagination.js +162 -0
- package/dist/loadable-hooks/useImperativeExposedMutationField.d.ts +2 -2
- package/dist/loadable-hooks/useImperativeExposedMutationField.d.ts.map +1 -0
- package/dist/loadable-hooks/useImperativeExposedMutationField.js +1 -2
- package/dist/loadable-hooks/useImperativeLoadableField.d.ts +13 -7
- package/dist/loadable-hooks/useImperativeLoadableField.d.ts.map +1 -0
- package/dist/loadable-hooks/useImperativeLoadableField.js +4 -5
- package/dist/loadable-hooks/useSkipLimitPagination.d.ts +13 -26
- package/dist/loadable-hooks/useSkipLimitPagination.d.ts.map +1 -0
- package/dist/loadable-hooks/useSkipLimitPagination.js +93 -47
- package/dist/react/FragmentReader.d.ts +6 -4
- package/dist/react/FragmentReader.d.ts.map +1 -0
- package/dist/react/FragmentReader.js +4 -2
- package/dist/react/IsographEnvironmentProvider.d.ts +1 -0
- package/dist/react/IsographEnvironmentProvider.d.ts.map +1 -0
- package/dist/react/IsographEnvironmentProvider.js +3 -3
- package/dist/react/RenderAfterCommit__DO_NOT_USE.d.ts +10 -0
- package/dist/react/RenderAfterCommit__DO_NOT_USE.d.ts.map +1 -0
- package/dist/react/RenderAfterCommit__DO_NOT_USE.js +15 -0
- package/dist/react/useImperativeReference.d.ts +8 -6
- package/dist/react/useImperativeReference.d.ts.map +1 -0
- package/dist/react/useImperativeReference.js +6 -8
- package/dist/react/useLazyReference.d.ts +5 -3
- package/dist/react/useLazyReference.d.ts.map +1 -0
- package/dist/react/useLazyReference.js +34 -6
- package/dist/react/useReadAndSubscribe.d.ts +6 -3
- package/dist/react/useReadAndSubscribe.d.ts.map +1 -0
- package/dist/react/useReadAndSubscribe.js +13 -10
- package/dist/react/useRerenderOnChange.d.ts +7 -2
- package/dist/react/useRerenderOnChange.d.ts.map +1 -0
- package/dist/react/useRerenderOnChange.js +3 -4
- package/dist/react/useResult.d.ts +4 -3
- package/dist/react/useResult.d.ts.map +1 -0
- package/dist/react/useResult.js +14 -9
- package/isograph.config.json +8 -0
- package/package.json +14 -9
- package/{src/tests/schema.graphql → schema.graphql} +1 -0
- package/src/core/FragmentReference.ts +44 -17
- package/src/core/IsographEnvironment.ts +67 -50
- package/src/core/PromiseWrapper.ts +3 -3
- package/src/core/areEqualWithDeepComparison.ts +95 -41
- package/src/core/cache.ts +316 -169
- package/src/core/check.ts +212 -0
- package/src/core/componentCache.ts +40 -46
- package/src/core/entrypoint.ts +41 -16
- package/src/core/garbageCollection.ts +77 -26
- package/src/core/logging.ts +118 -0
- package/src/core/makeNetworkRequest.ts +249 -20
- package/src/core/read.ts +658 -368
- package/src/core/reader.ts +61 -21
- package/src/core/startUpdate.ts +28 -0
- package/src/core/util.ts +8 -0
- package/src/index.ts +94 -8
- package/src/loadable-hooks/useClientSideDefer.ts +48 -17
- package/src/loadable-hooks/useConnectionSpecPagination.ts +344 -0
- package/src/loadable-hooks/useImperativeExposedMutationField.ts +1 -1
- package/src/loadable-hooks/useImperativeLoadableField.ts +36 -12
- package/src/loadable-hooks/useSkipLimitPagination.ts +253 -94
- package/src/react/FragmentReader.tsx +15 -6
- package/src/react/IsographEnvironmentProvider.tsx +1 -1
- package/src/react/RenderAfterCommit__DO_NOT_USE.tsx +17 -0
- package/src/react/useImperativeReference.ts +50 -18
- package/src/react/useLazyReference.ts +79 -11
- package/src/react/useReadAndSubscribe.ts +33 -10
- package/src/react/useRerenderOnChange.ts +7 -2
- package/src/react/useResult.ts +30 -9
- package/src/tests/__isograph/Query/meName/entrypoint.ts +10 -29
- package/src/tests/__isograph/Query/meName/normalization_ast.ts +25 -0
- package/src/tests/__isograph/Query/meName/param_type.ts +5 -2
- 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 +10 -65
- package/src/tests/__isograph/Query/meNameSuccessor/normalization_ast.ts +56 -0
- package/src/tests/__isograph/Query/meNameSuccessor/param_type.ts +9 -6
- 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 +10 -28
- package/src/tests/__isograph/Query/nodeField/normalization_ast.ts +30 -0
- package/src/tests/__isograph/Query/nodeField/param_type.ts +7 -3
- package/src/tests/__isograph/Query/nodeField/parameters_type.ts +3 -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/subquery/entrypoint.ts +28 -0
- package/src/tests/__isograph/Query/subquery/normalization_ast.ts +38 -0
- package/src/tests/__isograph/Query/subquery/output_type.ts +3 -0
- package/src/tests/__isograph/Query/subquery/param_type.ts +12 -0
- package/src/tests/__isograph/Query/subquery/parameters_type.ts +3 -0
- package/src/tests/__isograph/Query/subquery/query_text.ts +8 -0
- package/src/tests/__isograph/Query/subquery/resolver_reader.ts +52 -0
- package/src/tests/__isograph/iso.ts +24 -12
- package/src/tests/garbageCollection.test.ts +53 -45
- package/src/tests/meNameSuccessor.ts +8 -3
- package/src/tests/nodeQuery.ts +7 -4
- package/src/tests/normalizeData.test.ts +120 -0
- package/src/tests/tsconfig.json +3 -3
- package/tsconfig.json +2 -2
- package/tsconfig.pkg.json +7 -3
- package/vitest.config.ts +20 -0
- package/src/tests/isograph.config.json +0 -7
package/dist/core/cache.js
CHANGED
@@ -1,28 +1,30 @@
|
|
1
1
|
"use strict";
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
-
exports.
|
3
|
+
exports.THIRD_SPLIT_KEY = exports.SECOND_SPLIT_KEY = exports.FIRST_SPLIT_KEY = exports.TYPENAME_FIELD_NAME = void 0;
|
4
|
+
exports.getOrCreateItemInSuspenseCache = getOrCreateItemInSuspenseCache;
|
5
|
+
exports.stableCopy = stableCopy;
|
6
|
+
exports.getOrCreateCacheForArtifact = getOrCreateCacheForArtifact;
|
7
|
+
exports.normalizeData = normalizeData;
|
8
|
+
exports.subscribeToAnyChange = subscribeToAnyChange;
|
9
|
+
exports.subscribeToAnyChangesToRecord = subscribeToAnyChangesToRecord;
|
10
|
+
exports.subscribe = subscribe;
|
11
|
+
exports.onNextChangeToRecord = onNextChangeToRecord;
|
12
|
+
exports.insertIfNotExists = insertIfNotExists;
|
13
|
+
exports.getParentRecordKey = getParentRecordKey;
|
4
14
|
const react_disposable_state_1 = require("@isograph/react-disposable-state");
|
5
|
-
const IsographEnvironment_1 = require("./IsographEnvironment");
|
6
|
-
const read_1 = require("./read");
|
7
15
|
const areEqualWithDeepComparison_1 = require("./areEqualWithDeepComparison");
|
16
|
+
const IsographEnvironment_1 = require("./IsographEnvironment");
|
17
|
+
const logging_1 = require("./logging");
|
8
18
|
const makeNetworkRequest_1 = require("./makeNetworkRequest");
|
9
19
|
const PromiseWrapper_1 = require("./PromiseWrapper");
|
10
|
-
const
|
20
|
+
const read_1 = require("./read");
|
21
|
+
exports.TYPENAME_FIELD_NAME = '__typename';
|
11
22
|
function getOrCreateItemInSuspenseCache(environment, index, factory) {
|
12
|
-
// @ts-expect-error
|
13
|
-
if (typeof window !== 'undefined' && window.__LOG) {
|
14
|
-
console.log('getting cache for', {
|
15
|
-
index,
|
16
|
-
cache: Object.keys(environment.fragmentCache),
|
17
|
-
found: !!environment.fragmentCache[index],
|
18
|
-
});
|
19
|
-
}
|
20
23
|
if (environment.fragmentCache[index] == null) {
|
21
24
|
environment.fragmentCache[index] = new react_disposable_state_1.ParentCache(factory);
|
22
25
|
}
|
23
26
|
return environment.fragmentCache[index];
|
24
27
|
}
|
25
|
-
exports.getOrCreateItemInSuspenseCache = getOrCreateItemInSuspenseCache;
|
26
28
|
/**
|
27
29
|
* Creates a copy of the provided value, ensuring any nested objects have their
|
28
30
|
* keys sorted such that equivalent values would have identical JSON.stringify
|
@@ -44,11 +46,11 @@ function stableCopy(value) {
|
|
44
46
|
}
|
45
47
|
return stable;
|
46
48
|
}
|
47
|
-
|
48
|
-
|
49
|
-
|
49
|
+
function getOrCreateCacheForArtifact(environment, entrypoint, variables, fetchOptions) {
|
50
|
+
const cacheKey = entrypoint.networkRequestInfo.queryText +
|
51
|
+
JSON.stringify(stableCopy(variables));
|
50
52
|
const factory = () => {
|
51
|
-
const [networkRequest, disposeNetworkRequest] = (0, makeNetworkRequest_1.
|
53
|
+
const [networkRequest, disposeNetworkRequest] = (0, makeNetworkRequest_1.maybeMakeNetworkRequest)(environment, entrypoint, variables, fetchOptions);
|
52
54
|
const itemCleanupPair = [
|
53
55
|
{
|
54
56
|
kind: 'FragmentReference',
|
@@ -57,7 +59,7 @@ function getOrCreateCacheForArtifact(environment, entrypoint, variables) {
|
|
57
59
|
readerArtifact: entrypoint.readerWithRefetchQueries.readerArtifact,
|
58
60
|
nestedRefetchQueries: entrypoint.readerWithRefetchQueries.nestedRefetchQueries,
|
59
61
|
}),
|
60
|
-
root: IsographEnvironment_1.ROOT_ID,
|
62
|
+
root: { __link: IsographEnvironment_1.ROOT_ID, __typename: entrypoint.concreteType },
|
61
63
|
variables,
|
62
64
|
networkRequest: networkRequest,
|
63
65
|
},
|
@@ -67,26 +69,27 @@ function getOrCreateCacheForArtifact(environment, entrypoint, variables) {
|
|
67
69
|
};
|
68
70
|
return getOrCreateItemInSuspenseCache(environment, cacheKey, factory);
|
69
71
|
}
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
72
|
+
function normalizeData(environment, normalizationAst, networkResponse, variables, nestedRefetchQueries, root) {
|
73
|
+
var _a, _b;
|
74
|
+
var _c, _d, _e;
|
75
|
+
const encounteredIds = new Map();
|
76
|
+
(0, logging_1.logMessage)(environment, () => ({
|
77
|
+
kind: 'AboutToNormalize',
|
78
|
+
normalizationAst,
|
79
|
+
networkResponse,
|
80
|
+
variables,
|
81
|
+
}));
|
82
|
+
const recordsById = ((_a = (_c = environment.store)[_d = root.__typename]) !== null && _a !== void 0 ? _a : (_c[_d] = {}));
|
83
|
+
const newStoreRecord = ((_b = recordsById[_e = root.__link]) !== null && _b !== void 0 ? _b : (recordsById[_e] = {}));
|
84
|
+
normalizeDataIntoRecord(environment, normalizationAst, networkResponse, newStoreRecord, root, variables, nestedRefetchQueries, encounteredIds);
|
85
|
+
(0, logging_1.logMessage)(environment, () => ({
|
86
|
+
kind: 'AfterNormalization',
|
87
|
+
store: environment.store,
|
88
|
+
encounteredIds,
|
89
|
+
}));
|
86
90
|
callSubscriptions(environment, encounteredIds);
|
87
91
|
return encounteredIds;
|
88
92
|
}
|
89
|
-
exports.normalizeData = normalizeData;
|
90
93
|
function subscribeToAnyChange(environment, callback) {
|
91
94
|
const subscription = {
|
92
95
|
kind: 'AnyRecords',
|
@@ -95,30 +98,35 @@ function subscribeToAnyChange(environment, callback) {
|
|
95
98
|
environment.subscriptions.add(subscription);
|
96
99
|
return () => environment.subscriptions.delete(subscription);
|
97
100
|
}
|
98
|
-
|
101
|
+
function subscribeToAnyChangesToRecord(environment, recordLink, callback) {
|
102
|
+
const subscription = {
|
103
|
+
kind: 'AnyChangesToRecord',
|
104
|
+
recordLink,
|
105
|
+
callback,
|
106
|
+
};
|
107
|
+
environment.subscriptions.add(subscription);
|
108
|
+
return () => environment.subscriptions.delete(subscription);
|
109
|
+
}
|
99
110
|
// TODO we should re-read and call callback if the value has changed
|
100
|
-
function subscribe(environment, encounteredDataAndRecords, fragmentReference, callback) {
|
111
|
+
function subscribe(environment, encounteredDataAndRecords, fragmentReference, callback, readerAst) {
|
101
112
|
const fragmentSubscription = {
|
102
113
|
kind: 'FragmentSubscription',
|
103
114
|
callback,
|
104
115
|
encounteredDataAndRecords,
|
105
116
|
fragmentReference,
|
117
|
+
readerAst,
|
106
118
|
};
|
107
|
-
// @ts-expect-error
|
108
119
|
environment.subscriptions.add(fragmentSubscription);
|
109
|
-
// @ts-expect-error
|
110
120
|
return () => environment.subscriptions.delete(fragmentSubscription);
|
111
121
|
}
|
112
|
-
|
113
|
-
function onNextChange(environment) {
|
122
|
+
function onNextChangeToRecord(environment, recordLink) {
|
114
123
|
return new Promise((resolve) => {
|
115
|
-
const unsubscribe =
|
124
|
+
const unsubscribe = subscribeToAnyChangesToRecord(environment, recordLink, () => {
|
116
125
|
unsubscribe();
|
117
126
|
resolve();
|
118
127
|
});
|
119
128
|
});
|
120
129
|
}
|
121
|
-
exports.onNextChange = onNextChange;
|
122
130
|
// Calls to readButDoNotEvaluate can suspend (i.e. throw a promise).
|
123
131
|
// Maybe in the future, they will be able to throw errors.
|
124
132
|
//
|
@@ -134,6 +142,7 @@ function withErrorHandling(f) {
|
|
134
142
|
}
|
135
143
|
function callSubscriptions(environment, recordsEncounteredWhenNormalizing) {
|
136
144
|
environment.subscriptions.forEach(withErrorHandling((subscription) => {
|
145
|
+
var _a;
|
137
146
|
switch (subscription.kind) {
|
138
147
|
case 'FragmentSubscription': {
|
139
148
|
// TODO if there are multiple components subscribed to the same
|
@@ -157,32 +166,30 @@ function callSubscriptions(environment, recordsEncounteredWhenNormalizing) {
|
|
157
166
|
suspendIfInFlight: false,
|
158
167
|
throwOnNetworkError: false,
|
159
168
|
});
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
// TODO deep compare values
|
169
|
+
const mergedItem = (0, areEqualWithDeepComparison_1.mergeObjectsUsingReaderAst)(subscription.readerAst, subscription.encounteredDataAndRecords.item, newEncounteredDataAndRecords.item);
|
170
|
+
(0, logging_1.logMessage)(environment, () => ({
|
171
|
+
kind: 'DeepEqualityCheck',
|
172
|
+
fragmentReference: subscription.fragmentReference,
|
173
|
+
old: subscription.encounteredDataAndRecords.item,
|
174
|
+
new: newEncounteredDataAndRecords.item,
|
175
|
+
deeplyEqual: mergedItem === subscription.encounteredDataAndRecords.item,
|
176
|
+
}));
|
177
|
+
if (mergedItem !== subscription.encounteredDataAndRecords.item) {
|
170
178
|
subscription.callback(newEncounteredDataAndRecords);
|
171
179
|
}
|
172
|
-
else {
|
173
|
-
// @ts-expect-error
|
174
|
-
if (typeof window !== 'undefined' && window.__LOG) {
|
175
|
-
console.log('Deep equality - Yes', {
|
176
|
-
fragmentReference: subscription.fragmentReference,
|
177
|
-
old: subscription.encounteredDataAndRecords.item,
|
178
|
-
});
|
179
|
-
}
|
180
|
-
}
|
181
180
|
}
|
182
181
|
return;
|
183
182
|
}
|
184
183
|
case 'AnyRecords': {
|
185
|
-
|
184
|
+
subscription.callback();
|
185
|
+
return;
|
186
|
+
}
|
187
|
+
case 'AnyChangesToRecord': {
|
188
|
+
if ((_a = recordsEncounteredWhenNormalizing
|
189
|
+
.get(subscription.recordLink.__typename)) === null || _a === void 0 ? void 0 : _a.has(subscription.recordLink.__link)) {
|
190
|
+
subscription.callback();
|
191
|
+
}
|
192
|
+
return;
|
186
193
|
}
|
187
194
|
default: {
|
188
195
|
// Ensure we have covered all variants
|
@@ -193,7 +200,20 @@ function callSubscriptions(environment, recordsEncounteredWhenNormalizing) {
|
|
193
200
|
}
|
194
201
|
}));
|
195
202
|
}
|
196
|
-
function hasOverlappingIds(
|
203
|
+
function hasOverlappingIds(ids1, ids2) {
|
204
|
+
for (const [typeName, set1] of ids1.entries()) {
|
205
|
+
const set2 = ids2.get(typeName);
|
206
|
+
if (set2 === undefined) {
|
207
|
+
continue;
|
208
|
+
}
|
209
|
+
if (isNotDisjointFrom(set1, set2)) {
|
210
|
+
return true;
|
211
|
+
}
|
212
|
+
}
|
213
|
+
return false;
|
214
|
+
}
|
215
|
+
// TODO use a polyfill library
|
216
|
+
function isNotDisjointFrom(set1, set2) {
|
197
217
|
for (const id of set1) {
|
198
218
|
if (set2.has(id)) {
|
199
219
|
return true;
|
@@ -204,7 +224,7 @@ function hasOverlappingIds(set1, set2) {
|
|
204
224
|
/**
|
205
225
|
* Mutate targetParentRecord according to the normalizationAst and networkResponseParentRecord.
|
206
226
|
*/
|
207
|
-
function normalizeDataIntoRecord(environment, normalizationAst, networkResponseParentRecord, targetParentRecord,
|
227
|
+
function normalizeDataIntoRecord(environment, normalizationAst, networkResponseParentRecord, targetParentRecord, targetParentRecordLink, variables, nestedRefetchQueries, mutableEncounteredIds) {
|
208
228
|
let recordHasBeenUpdated = false;
|
209
229
|
for (const normalizationNode of normalizationAst) {
|
210
230
|
switch (normalizationNode.kind) {
|
@@ -215,13 +235,13 @@ function normalizeDataIntoRecord(environment, normalizationAst, networkResponseP
|
|
215
235
|
break;
|
216
236
|
}
|
217
237
|
case 'Linked': {
|
218
|
-
const linkedFieldResultedInChange = normalizeLinkedField(environment, normalizationNode, networkResponseParentRecord, targetParentRecord,
|
238
|
+
const linkedFieldResultedInChange = normalizeLinkedField(environment, normalizationNode, networkResponseParentRecord, targetParentRecord, targetParentRecordLink, variables, nestedRefetchQueries, mutableEncounteredIds);
|
219
239
|
recordHasBeenUpdated =
|
220
240
|
recordHasBeenUpdated || linkedFieldResultedInChange;
|
221
241
|
break;
|
222
242
|
}
|
223
243
|
case 'InlineFragment': {
|
224
|
-
const inlineFragmentResultedInChange = normalizeInlineFragment(environment, normalizationNode, networkResponseParentRecord, targetParentRecord,
|
244
|
+
const inlineFragmentResultedInChange = normalizeInlineFragment(environment, normalizationNode, networkResponseParentRecord, targetParentRecord, targetParentRecordLink, variables, nestedRefetchQueries, mutableEncounteredIds);
|
225
245
|
recordHasBeenUpdated =
|
226
246
|
recordHasBeenUpdated || inlineFragmentResultedInChange;
|
227
247
|
break;
|
@@ -235,10 +255,19 @@ function normalizeDataIntoRecord(environment, normalizationAst, networkResponseP
|
|
235
255
|
}
|
236
256
|
}
|
237
257
|
if (recordHasBeenUpdated) {
|
238
|
-
mutableEncounteredIds.
|
258
|
+
let encounteredRecordsIds = insertIfNotExists(mutableEncounteredIds, targetParentRecordLink.__typename);
|
259
|
+
encounteredRecordsIds.add(targetParentRecordLink.__link);
|
239
260
|
}
|
240
261
|
return recordHasBeenUpdated;
|
241
262
|
}
|
263
|
+
function insertIfNotExists(map, key) {
|
264
|
+
let result = map.get(key);
|
265
|
+
if (result === undefined) {
|
266
|
+
result = new Set();
|
267
|
+
map.set(key, result);
|
268
|
+
}
|
269
|
+
return result;
|
270
|
+
}
|
242
271
|
function normalizeScalarField(astNode, networkResponseParentRecord, targetStoreRecord, variables) {
|
243
272
|
const networkResponseKey = getNetworkResponseKey(astNode);
|
244
273
|
const networkResponseData = networkResponseParentRecord[networkResponseKey];
|
@@ -256,7 +285,8 @@ function normalizeScalarField(astNode, networkResponseParentRecord, targetStoreR
|
|
256
285
|
/**
|
257
286
|
* Mutate targetParentRecord with a given linked field ast node.
|
258
287
|
*/
|
259
|
-
function normalizeLinkedField(environment, astNode, networkResponseParentRecord, targetParentRecord,
|
288
|
+
function normalizeLinkedField(environment, astNode, networkResponseParentRecord, targetParentRecord, targetParentRecordLink, variables, nestedRefetchQueries, mutableEncounteredIds) {
|
289
|
+
var _a, _b;
|
260
290
|
const networkResponseKey = getNetworkResponseKey(astNode);
|
261
291
|
const networkResponseData = networkResponseParentRecord[networkResponseKey];
|
262
292
|
const parentRecordKey = getParentRecordKey(astNode, variables);
|
@@ -265,7 +295,8 @@ function normalizeLinkedField(environment, astNode, networkResponseParentRecord,
|
|
265
295
|
targetParentRecord[parentRecordKey] = null;
|
266
296
|
return existingValue !== null;
|
267
297
|
}
|
268
|
-
if (
|
298
|
+
if (isScalarOrEmptyArray(networkResponseData) &&
|
299
|
+
!isNullOrEmptyArray(networkResponseData)) {
|
269
300
|
throw new Error('Unexpected scalar network response when normalizing a linked field');
|
270
301
|
}
|
271
302
|
if (Array.isArray(networkResponseData)) {
|
@@ -273,43 +304,61 @@ function normalizeLinkedField(environment, astNode, networkResponseParentRecord,
|
|
273
304
|
const dataIds = [];
|
274
305
|
for (let i = 0; i < networkResponseData.length; i++) {
|
275
306
|
const networkResponseObject = networkResponseData[i];
|
276
|
-
|
277
|
-
|
307
|
+
if (networkResponseObject == null) {
|
308
|
+
dataIds.push(null);
|
309
|
+
continue;
|
310
|
+
}
|
311
|
+
const newStoreRecordId = normalizeNetworkResponseObject(environment, astNode, networkResponseObject, targetParentRecordLink, variables, i, nestedRefetchQueries, mutableEncounteredIds);
|
312
|
+
const __typename = (_a = astNode.concreteType) !== null && _a !== void 0 ? _a : networkResponseObject[exports.TYPENAME_FIELD_NAME];
|
313
|
+
if (__typename == null) {
|
314
|
+
throw new Error('Unexpected missing __typename in network response when normalizing a linked field. ' +
|
315
|
+
'This is indicative of a bug in Isograph.');
|
316
|
+
}
|
317
|
+
dataIds.push({
|
318
|
+
__link: newStoreRecordId,
|
319
|
+
__typename,
|
320
|
+
});
|
278
321
|
}
|
279
322
|
targetParentRecord[parentRecordKey] = dataIds;
|
280
323
|
return !dataIdsAreTheSame(existingValue, dataIds);
|
281
324
|
}
|
282
325
|
else {
|
283
|
-
const newStoreRecordId = normalizeNetworkResponseObject(environment, astNode, networkResponseData,
|
326
|
+
const newStoreRecordId = normalizeNetworkResponseObject(environment, astNode, networkResponseData, targetParentRecordLink, variables, null, nestedRefetchQueries, mutableEncounteredIds);
|
327
|
+
let __typename = (_b = astNode.concreteType) !== null && _b !== void 0 ? _b : networkResponseData[exports.TYPENAME_FIELD_NAME];
|
328
|
+
if (__typename == null) {
|
329
|
+
throw new Error('Unexpected missing __typename in network response when normalizing a linked field. ' +
|
330
|
+
'This is indicative of a bug in Isograph.');
|
331
|
+
}
|
284
332
|
targetParentRecord[parentRecordKey] = {
|
285
333
|
__link: newStoreRecordId,
|
334
|
+
__typename,
|
286
335
|
};
|
287
336
|
const link = (0, IsographEnvironment_1.getLink)(existingValue);
|
288
|
-
return (link === null || link === void 0 ? void 0 : link.__link) !== newStoreRecordId;
|
337
|
+
return (link === null || link === void 0 ? void 0 : link.__link) !== newStoreRecordId || link.__typename !== __typename;
|
289
338
|
}
|
290
339
|
}
|
291
340
|
/**
|
292
341
|
* Mutate targetParentRecord with a given linked field ast node.
|
293
342
|
*/
|
294
|
-
function normalizeInlineFragment(environment, astNode, networkResponseParentRecord, targetParentRecord,
|
343
|
+
function normalizeInlineFragment(environment, astNode, networkResponseParentRecord, targetParentRecord, targetParentRecordLink, variables, nestedRefetchQueries, mutableEncounteredIds) {
|
295
344
|
const typeToRefineTo = astNode.type;
|
296
|
-
if (networkResponseParentRecord[TYPENAME_FIELD_NAME] === typeToRefineTo) {
|
297
|
-
const hasBeenModified = normalizeDataIntoRecord(environment, astNode.selections, networkResponseParentRecord, targetParentRecord,
|
345
|
+
if (networkResponseParentRecord[exports.TYPENAME_FIELD_NAME] === typeToRefineTo) {
|
346
|
+
const hasBeenModified = normalizeDataIntoRecord(environment, astNode.selections, networkResponseParentRecord, targetParentRecord, targetParentRecordLink, variables, nestedRefetchQueries, mutableEncounteredIds);
|
298
347
|
return hasBeenModified;
|
299
348
|
}
|
300
349
|
return false;
|
301
350
|
}
|
302
351
|
function dataIdsAreTheSame(existingValue, newDataIds) {
|
352
|
+
var _a, _b;
|
303
353
|
if (Array.isArray(existingValue)) {
|
304
354
|
if (newDataIds.length !== existingValue.length) {
|
305
355
|
return false;
|
306
356
|
}
|
307
357
|
for (let i = 0; i < newDataIds.length; i++) {
|
308
358
|
const maybeLink = (0, IsographEnvironment_1.getLink)(existingValue[i]);
|
309
|
-
if (
|
310
|
-
|
311
|
-
|
312
|
-
}
|
359
|
+
if (((_a = newDataIds[i]) === null || _a === void 0 ? void 0 : _a.__link) !== (maybeLink === null || maybeLink === void 0 ? void 0 : maybeLink.__link) ||
|
360
|
+
((_b = newDataIds[i]) === null || _b === void 0 ? void 0 : _b.__typename) !== (maybeLink === null || maybeLink === void 0 ? void 0 : maybeLink.__typename)) {
|
361
|
+
return false;
|
313
362
|
}
|
314
363
|
}
|
315
364
|
return true;
|
@@ -318,12 +367,18 @@ function dataIdsAreTheSame(existingValue, newDataIds) {
|
|
318
367
|
return false;
|
319
368
|
}
|
320
369
|
}
|
321
|
-
function normalizeNetworkResponseObject(environment, astNode, networkResponseData,
|
322
|
-
var _a;
|
323
|
-
|
324
|
-
const
|
325
|
-
|
326
|
-
|
370
|
+
function normalizeNetworkResponseObject(environment, astNode, networkResponseData, targetParentRecordLink, variables, index, nestedRefetchQueries, mutableEncounteredIds) {
|
371
|
+
var _a, _b, _c;
|
372
|
+
var _d;
|
373
|
+
const newStoreRecordId = getDataIdOfNetworkResponse(targetParentRecordLink, networkResponseData, astNode, variables, index);
|
374
|
+
const __typename = (_a = astNode.concreteType) !== null && _a !== void 0 ? _a : networkResponseData[exports.TYPENAME_FIELD_NAME];
|
375
|
+
if (__typename == null) {
|
376
|
+
throw new Error('Unexpected missing __typename in network response object. ' +
|
377
|
+
'This is indicative of a bug in Isograph.');
|
378
|
+
}
|
379
|
+
const recordsById = ((_b = (_d = environment.store)[__typename]) !== null && _b !== void 0 ? _b : (_d[__typename] = {}));
|
380
|
+
const newStoreRecord = ((_c = recordsById[newStoreRecordId]) !== null && _c !== void 0 ? _c : (recordsById[newStoreRecordId] = {}));
|
381
|
+
normalizeDataIntoRecord(environment, astNode.selections, networkResponseData, newStoreRecord, { __link: newStoreRecordId, __typename: __typename }, variables, nestedRefetchQueries, mutableEncounteredIds);
|
327
382
|
return newStoreRecordId;
|
328
383
|
}
|
329
384
|
function isScalarOrEmptyArray(data) {
|
@@ -332,24 +387,20 @@ function isScalarOrEmptyArray(data) {
|
|
332
387
|
// This is maybe fixed in a new version of Typescript??
|
333
388
|
return data.every((x) => isScalarOrEmptyArray(x));
|
334
389
|
}
|
335
|
-
const isScalarValue =
|
390
|
+
const isScalarValue = data === null ||
|
391
|
+
typeof data === 'string' ||
|
336
392
|
typeof data === 'number' ||
|
337
393
|
typeof data === 'boolean';
|
338
394
|
return isScalarValue;
|
339
395
|
}
|
340
|
-
function
|
341
|
-
// N.B. empty arrays count as empty arrays of linked fields.
|
396
|
+
function isNullOrEmptyArray(data) {
|
342
397
|
if (Array.isArray(data)) {
|
343
398
|
if (data.length === 0) {
|
344
|
-
return
|
399
|
+
return true;
|
345
400
|
}
|
346
|
-
|
347
|
-
return data.every((x) => isScalarOrEmptyArray(x));
|
401
|
+
return data.every((x) => isNullOrEmptyArray(x));
|
348
402
|
}
|
349
|
-
|
350
|
-
typeof data === 'number' ||
|
351
|
-
typeof data === 'boolean';
|
352
|
-
return isScalarValue;
|
403
|
+
return data === null;
|
353
404
|
}
|
354
405
|
function getParentRecordKey(astNode, variables) {
|
355
406
|
let parentRecordKey = astNode.fieldName;
|
@@ -361,10 +412,18 @@ function getParentRecordKey(astNode, variables) {
|
|
361
412
|
}
|
362
413
|
return parentRecordKey;
|
363
414
|
}
|
364
|
-
exports.getParentRecordKey = getParentRecordKey;
|
365
415
|
function getStoreKeyChunkForArgumentValue(argumentValue, variables) {
|
366
416
|
var _a;
|
367
417
|
switch (argumentValue.kind) {
|
418
|
+
case 'Object': {
|
419
|
+
return Object.fromEntries(argumentValue.value.map(([argumentName, argumentValue]) => {
|
420
|
+
return [
|
421
|
+
argumentName,
|
422
|
+
// substitute variables
|
423
|
+
getStoreKeyChunkForArgumentValue(argumentValue, variables),
|
424
|
+
];
|
425
|
+
}));
|
426
|
+
}
|
368
427
|
case 'Literal': {
|
369
428
|
return argumentValue.value;
|
370
429
|
}
|
@@ -387,57 +446,75 @@ function getStoreKeyChunkForArgumentValue(argumentValue, variables) {
|
|
387
446
|
}
|
388
447
|
}
|
389
448
|
function getStoreKeyChunkForArgument(argument, variables) {
|
390
|
-
|
449
|
+
let chunk = getStoreKeyChunkForArgumentValue(argument[1], variables);
|
450
|
+
if (typeof chunk === 'object') {
|
451
|
+
chunk = JSON.stringify(stableCopy(chunk));
|
452
|
+
}
|
391
453
|
return `${exports.FIRST_SPLIT_KEY}${argument[0]}${exports.SECOND_SPLIT_KEY}${chunk}`;
|
392
454
|
}
|
393
455
|
function getNetworkResponseKey(astNode) {
|
394
456
|
let networkResponseKey = astNode.fieldName;
|
395
457
|
const fieldParameters = astNode.arguments;
|
396
458
|
if (fieldParameters != null) {
|
397
|
-
for (const
|
398
|
-
|
399
|
-
let argumentValueChunk;
|
400
|
-
switch (argumentValue.kind) {
|
401
|
-
case 'Literal': {
|
402
|
-
argumentValueChunk = 'l_' + argumentValue.value;
|
403
|
-
break;
|
404
|
-
}
|
405
|
-
case 'Variable': {
|
406
|
-
argumentValueChunk = 'v_' + argumentValue.name;
|
407
|
-
break;
|
408
|
-
}
|
409
|
-
case 'String': {
|
410
|
-
argumentValueChunk = 's_' + argumentValue.value;
|
411
|
-
break;
|
412
|
-
}
|
413
|
-
case 'Enum': {
|
414
|
-
argumentValueChunk = 'e_' + argumentValue.value;
|
415
|
-
break;
|
416
|
-
}
|
417
|
-
default: {
|
418
|
-
// Ensure we have covered all variants
|
419
|
-
let _ = argumentValue;
|
420
|
-
_;
|
421
|
-
throw new Error('Unexpected case');
|
422
|
-
}
|
423
|
-
}
|
459
|
+
for (const [argumentName, argumentValue] of fieldParameters) {
|
460
|
+
let argumentValueChunk = getArgumentValueChunk(argumentValue);
|
424
461
|
networkResponseKey += `${exports.FIRST_SPLIT_KEY}${argumentName}${exports.SECOND_SPLIT_KEY}${argumentValueChunk}`;
|
425
462
|
}
|
426
463
|
}
|
427
464
|
return networkResponseKey;
|
428
465
|
}
|
466
|
+
function getArgumentValueChunk(argumentValue) {
|
467
|
+
switch (argumentValue.kind) {
|
468
|
+
case 'Object': {
|
469
|
+
return ('o_' +
|
470
|
+
argumentValue.value
|
471
|
+
.map(([argumentName, argumentValue]) => {
|
472
|
+
return (argumentName +
|
473
|
+
exports.THIRD_SPLIT_KEY +
|
474
|
+
getArgumentValueChunk(argumentValue));
|
475
|
+
})
|
476
|
+
.join('_') +
|
477
|
+
'_c');
|
478
|
+
}
|
479
|
+
case 'Literal': {
|
480
|
+
return 'l_' + argumentValue.value;
|
481
|
+
}
|
482
|
+
case 'Variable': {
|
483
|
+
return 'v_' + argumentValue.name;
|
484
|
+
}
|
485
|
+
case 'String': {
|
486
|
+
// replace all non-word characters (alphanumeric & underscore) with underscores
|
487
|
+
return 's_' + argumentValue.value.replaceAll(/\W/g, '_');
|
488
|
+
}
|
489
|
+
case 'Enum': {
|
490
|
+
return 'e_' + argumentValue.value;
|
491
|
+
}
|
492
|
+
default: {
|
493
|
+
// Ensure we have covered all variants
|
494
|
+
let _ = argumentValue;
|
495
|
+
_;
|
496
|
+
throw new Error('Unexpected case');
|
497
|
+
}
|
498
|
+
}
|
499
|
+
}
|
429
500
|
// an alias might be pullRequests____first___first____after___cursor
|
430
501
|
exports.FIRST_SPLIT_KEY = '____';
|
431
502
|
exports.SECOND_SPLIT_KEY = '___';
|
503
|
+
exports.THIRD_SPLIT_KEY = '__';
|
432
504
|
// Returns a key to look up an item in the store
|
433
|
-
function getDataIdOfNetworkResponse(
|
505
|
+
function getDataIdOfNetworkResponse(parentRecordLink, dataToNormalize, astNode, variables, index) {
|
506
|
+
// If we are dealing with nested Query, use __ROOT as id
|
507
|
+
// TODO do not hard code this value here
|
508
|
+
if (astNode.concreteType === 'Query') {
|
509
|
+
return IsographEnvironment_1.ROOT_ID;
|
510
|
+
}
|
434
511
|
// Check whether the dataToNormalize has an id field. If so, that is the key.
|
435
512
|
// If not, we construct an id from the parentRecordId and the field parameters.
|
436
513
|
const dataId = dataToNormalize.id;
|
437
514
|
if (dataId != null) {
|
438
515
|
return dataId;
|
439
516
|
}
|
440
|
-
let storeKey = `${
|
517
|
+
let storeKey = `${parentRecordLink.__typename}:${parentRecordLink.__link}.${astNode.fieldName}`;
|
441
518
|
if (index != null) {
|
442
519
|
storeKey += `.${index}`;
|
443
520
|
}
|
@@ -0,0 +1,22 @@
|
|
1
|
+
import { NormalizationAstNodes } from './entrypoint';
|
2
|
+
import { Variables } from './FragmentReference';
|
3
|
+
import { IsographEnvironment, Link } from './IsographEnvironment';
|
4
|
+
export type ShouldFetch = RequiredShouldFetch | 'IfNecessary';
|
5
|
+
export type RequiredShouldFetch = 'Yes' | 'No';
|
6
|
+
export declare const DEFAULT_SHOULD_FETCH_VALUE: ShouldFetch;
|
7
|
+
export type FetchOptions<TReadOutData> = {
|
8
|
+
shouldFetch?: ShouldFetch;
|
9
|
+
onComplete?: (data: TReadOutData) => void;
|
10
|
+
onError?: () => void;
|
11
|
+
};
|
12
|
+
export type RequiredFetchOptions<TReadOutData> = {
|
13
|
+
shouldFetch: RequiredShouldFetch;
|
14
|
+
} & FetchOptions<TReadOutData>;
|
15
|
+
export type CheckResult = {
|
16
|
+
kind: 'EnoughData';
|
17
|
+
} | {
|
18
|
+
kind: 'MissingData';
|
19
|
+
record: Link;
|
20
|
+
};
|
21
|
+
export declare function check(environment: IsographEnvironment, normalizationAst: NormalizationAstNodes, variables: Variables, root: Link): CheckResult;
|
22
|
+
//# sourceMappingURL=check.d.ts.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"check.d.ts","sourceRoot":"","sources":["../../src/core/check.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC;AACrD,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAChD,OAAO,EAEL,mBAAmB,EACnB,IAAI,EAEL,MAAM,uBAAuB,CAAC;AAG/B,MAAM,MAAM,WAAW,GAAG,mBAAmB,GAAG,aAAa,CAAC;AAC9D,MAAM,MAAM,mBAAmB,GAAG,KAAK,GAAG,IAAI,CAAC;AAE/C,eAAO,MAAM,0BAA0B,EAAE,WAA2B,CAAC;AAErE,MAAM,MAAM,YAAY,CAAC,YAAY,IAAI;IACvC,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,YAAY,KAAK,IAAI,CAAC;IAC1C,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB,CAAC;AAEF,MAAM,MAAM,oBAAoB,CAAC,YAAY,IAAI;IAC/C,WAAW,EAAE,mBAAmB,CAAC;CAClC,GAAG,YAAY,CAAC,YAAY,CAAC,CAAC;AAE/B,MAAM,MAAM,WAAW,GACnB;IACE,IAAI,EAAE,YAAY,CAAC;CACpB,GACD;IACE,IAAI,EAAE,aAAa,CAAC;IACpB,MAAM,EAAE,IAAI,CAAC;CACd,CAAC;AAEN,wBAAgB,KAAK,CACnB,WAAW,EAAE,mBAAmB,EAChC,gBAAgB,EAAE,qBAAqB,EACvC,SAAS,EAAE,SAAS,EACpB,IAAI,EAAE,IAAI,GACT,WAAW,CAgBb"}
|