@isograph/react 0.2.0 → 0.3.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/dist/core/FragmentReference.d.ts +14 -4
- package/dist/core/FragmentReference.d.ts.map +1 -0
- package/dist/core/FragmentReference.js +2 -3
- package/dist/core/IsographEnvironment.d.ts +28 -10
- package/dist/core/IsographEnvironment.d.ts.map +1 -0
- package/dist/core/IsographEnvironment.js +15 -22
- package/dist/core/PromiseWrapper.d.ts +1 -0
- package/dist/core/PromiseWrapper.d.ts.map +1 -0
- package/dist/core/PromiseWrapper.js +4 -5
- package/dist/core/areEqualWithDeepComparison.d.ts +5 -3
- package/dist/core/areEqualWithDeepComparison.d.ts.map +1 -0
- package/dist/core/areEqualWithDeepComparison.js +73 -39
- package/dist/core/cache.d.ts +26 -10
- package/dist/core/cache.d.ts.map +1 -0
- package/dist/core/cache.js +160 -98
- package/dist/core/check.d.ts +18 -0
- package/dist/core/check.d.ts.map +1 -0
- package/dist/core/check.js +127 -0
- package/dist/core/componentCache.d.ts +1 -1
- package/dist/core/componentCache.d.ts.map +1 -0
- package/dist/core/componentCache.js +14 -14
- package/dist/core/entrypoint.d.ts +27 -8
- package/dist/core/entrypoint.d.ts.map +1 -0
- package/dist/core/entrypoint.js +1 -2
- package/dist/core/garbageCollection.d.ts +3 -1
- package/dist/core/garbageCollection.d.ts.map +1 -0
- package/dist/core/garbageCollection.js +48 -15
- package/dist/core/logging.d.ts +69 -0
- package/dist/core/logging.d.ts.map +1 -0
- package/dist/core/logging.js +19 -0
- package/dist/core/makeNetworkRequest.d.ts +4 -1
- package/dist/core/makeNetworkRequest.d.ts.map +1 -0
- package/dist/core/makeNetworkRequest.js +71 -15
- package/dist/core/read.d.ts +20 -5
- package/dist/core/read.d.ts.map +1 -0
- package/dist/core/read.js +104 -41
- package/dist/core/reader.d.ts +34 -10
- package/dist/core/reader.d.ts.map +1 -0
- package/dist/core/util.d.ts +2 -0
- package/dist/core/util.d.ts.map +1 -0
- package/dist/index.d.ts +10 -5
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +10 -2
- package/dist/loadable-hooks/useClientSideDefer.d.ts +15 -3
- package/dist/loadable-hooks/useClientSideDefer.d.ts.map +1 -0
- package/dist/loadable-hooks/useClientSideDefer.js +4 -6
- package/dist/loadable-hooks/useConnectionSpecPagination.d.ts +34 -0
- package/dist/loadable-hooks/useConnectionSpecPagination.d.ts.map +1 -0
- package/dist/loadable-hooks/useConnectionSpecPagination.js +160 -0
- package/dist/loadable-hooks/useImperativeExposedMutationField.d.ts +1 -0
- 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 -5
- package/dist/loadable-hooks/useImperativeLoadableField.d.ts.map +1 -0
- package/dist/loadable-hooks/useImperativeLoadableField.js +3 -4
- package/dist/loadable-hooks/useSkipLimitPagination.d.ts +18 -24
- package/dist/loadable-hooks/useSkipLimitPagination.d.ts.map +1 -0
- package/dist/loadable-hooks/useSkipLimitPagination.js +88 -44
- package/dist/react/FragmentReader.d.ts +7 -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 -3
- package/dist/react/useImperativeReference.d.ts.map +1 -0
- package/dist/react/useImperativeReference.js +4 -5
- package/dist/react/useLazyReference.d.ts +7 -2
- package/dist/react/useLazyReference.d.ts.map +1 -0
- package/dist/react/useLazyReference.js +11 -4
- package/dist/react/useReadAndSubscribe.d.ts +12 -3
- package/dist/react/useReadAndSubscribe.d.ts.map +1 -0
- package/dist/react/useReadAndSubscribe.js +6 -7
- package/dist/react/useRerenderOnChange.d.ts +6 -1
- package/dist/react/useRerenderOnChange.d.ts.map +1 -0
- package/dist/react/useRerenderOnChange.js +3 -4
- package/dist/react/useResult.d.ts +5 -1
- package/dist/react/useResult.d.ts.map +1 -0
- package/dist/react/useResult.js +8 -5
- package/{src/tests/isograph.config.json → isograph.config.json} +1 -1
- package/package.json +12 -8
- package/{src/tests/schema.graphql → schema.graphql} +1 -0
- package/src/core/FragmentReference.ts +17 -5
- package/src/core/IsographEnvironment.ts +38 -29
- package/src/core/areEqualWithDeepComparison.ts +76 -42
- package/src/core/cache.ts +237 -123
- package/src/core/check.ts +207 -0
- package/src/core/componentCache.ts +18 -17
- package/src/core/entrypoint.ts +15 -8
- package/src/core/garbageCollection.ts +71 -20
- package/src/core/logging.ts +116 -0
- package/src/core/makeNetworkRequest.ts +89 -13
- package/src/core/read.ts +162 -55
- package/src/core/reader.ts +40 -13
- package/src/core/util.ts +4 -0
- package/src/index.ts +14 -1
- package/src/loadable-hooks/useClientSideDefer.ts +45 -15
- package/src/loadable-hooks/useConnectionSpecPagination.ts +331 -0
- package/src/loadable-hooks/useImperativeLoadableField.ts +36 -10
- package/src/loadable-hooks/useSkipLimitPagination.ts +231 -90
- package/src/react/FragmentReader.tsx +13 -4
- package/src/react/RenderAfterCommit__DO_NOT_USE.tsx +17 -0
- package/src/react/useImperativeReference.ts +18 -7
- package/src/react/useLazyReference.ts +24 -4
- package/src/react/useReadAndSubscribe.ts +20 -5
- package/src/react/useRerenderOnChange.ts +6 -1
- package/src/react/useResult.ts +10 -2
- package/src/tests/__isograph/Query/meName/entrypoint.ts +7 -2
- package/src/tests/__isograph/Query/meName/param_type.ts +5 -2
- package/src/tests/__isograph/Query/meName/resolver_reader.ts +1 -0
- package/src/tests/__isograph/Query/meNameSuccessor/entrypoint.ts +9 -2
- package/src/tests/__isograph/Query/meNameSuccessor/param_type.ts +9 -6
- package/src/tests/__isograph/Query/meNameSuccessor/resolver_reader.ts +3 -0
- package/src/tests/__isograph/Query/nodeField/entrypoint.ts +13 -2
- 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/resolver_reader.ts +1 -0
- package/src/tests/__isograph/Query/subquery/entrypoint.ts +67 -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/resolver_reader.ts +47 -0
- package/src/tests/__isograph/iso.ts +22 -11
- package/src/tests/garbageCollection.test.ts +45 -39
- package/src/tests/meNameSuccessor.ts +8 -3
- package/src/tests/nodeQuery.ts +6 -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 +6 -1
- package/vitest.config.ts +20 -0
@@ -10,32 +10,90 @@ import {
|
|
10
10
|
retainQuery,
|
11
11
|
unretainQuery,
|
12
12
|
} from './garbageCollection';
|
13
|
-
import { IsographEnvironment } from './IsographEnvironment';
|
14
|
-
import {
|
13
|
+
import { IsographEnvironment, ROOT_ID } from './IsographEnvironment';
|
14
|
+
import {
|
15
|
+
AnyError,
|
16
|
+
PromiseWrapper,
|
17
|
+
wrapPromise,
|
18
|
+
wrapResolvedValue,
|
19
|
+
} from './PromiseWrapper';
|
15
20
|
import { normalizeData } from './cache';
|
21
|
+
import { logMessage } from './logging';
|
22
|
+
import { check, DEFAULT_SHOULD_FETCH_VALUE, FetchOptions } from './check';
|
16
23
|
|
17
|
-
|
24
|
+
let networkRequestId = 0;
|
25
|
+
|
26
|
+
export function maybeMakeNetworkRequest(
|
18
27
|
environment: IsographEnvironment,
|
19
28
|
artifact: RefetchQueryNormalizationArtifact | IsographEntrypoint<any, any>,
|
20
29
|
variables: Variables,
|
30
|
+
fetchOptions?: FetchOptions,
|
21
31
|
): ItemCleanupPair<PromiseWrapper<void, AnyError>> {
|
22
|
-
|
23
|
-
|
24
|
-
|
32
|
+
switch (fetchOptions?.shouldFetch ?? DEFAULT_SHOULD_FETCH_VALUE) {
|
33
|
+
case 'Yes': {
|
34
|
+
return makeNetworkRequest(environment, artifact, variables, fetchOptions);
|
35
|
+
}
|
36
|
+
case 'No': {
|
37
|
+
return [wrapResolvedValue(undefined), () => {}];
|
38
|
+
}
|
39
|
+
case 'IfNecessary': {
|
40
|
+
const result = check(
|
41
|
+
environment,
|
42
|
+
artifact.networkRequestInfo.normalizationAst,
|
43
|
+
variables,
|
44
|
+
{
|
45
|
+
__link: ROOT_ID,
|
46
|
+
__typename: artifact.concreteType,
|
47
|
+
},
|
48
|
+
);
|
49
|
+
if (result.kind === 'EnoughData') {
|
50
|
+
return [wrapResolvedValue(undefined), () => {}];
|
51
|
+
} else {
|
52
|
+
return makeNetworkRequest(
|
53
|
+
environment,
|
54
|
+
artifact,
|
55
|
+
variables,
|
56
|
+
fetchOptions,
|
57
|
+
);
|
58
|
+
}
|
59
|
+
}
|
25
60
|
}
|
61
|
+
}
|
62
|
+
|
63
|
+
export function makeNetworkRequest(
|
64
|
+
environment: IsographEnvironment,
|
65
|
+
artifact: RefetchQueryNormalizationArtifact | IsographEntrypoint<any, any>,
|
66
|
+
variables: Variables,
|
67
|
+
fetchOptions?: FetchOptions,
|
68
|
+
): ItemCleanupPair<PromiseWrapper<void, AnyError>> {
|
69
|
+
// TODO this should be a DataId and stored in the store
|
70
|
+
const myNetworkRequestId = networkRequestId + '';
|
71
|
+
networkRequestId++;
|
72
|
+
|
73
|
+
logMessage(environment, {
|
74
|
+
kind: 'MakeNetworkRequest',
|
75
|
+
artifact,
|
76
|
+
variables,
|
77
|
+
networkRequestId: myNetworkRequestId,
|
78
|
+
});
|
79
|
+
|
26
80
|
let status: NetworkRequestStatus = {
|
27
81
|
kind: 'UndisposedIncomplete',
|
28
82
|
};
|
29
83
|
// This should be an observable, not a promise
|
30
84
|
const promise = environment
|
31
|
-
.networkFunction(artifact.queryText, variables)
|
85
|
+
.networkFunction(artifact.networkRequestInfo.queryText, variables)
|
32
86
|
.then((networkResponse) => {
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
87
|
+
logMessage(environment, {
|
88
|
+
kind: 'ReceivedNetworkResponse',
|
89
|
+
networkResponse,
|
90
|
+
networkRequestId: myNetworkRequestId,
|
91
|
+
});
|
37
92
|
|
38
93
|
if (networkResponse.errors != null) {
|
94
|
+
try {
|
95
|
+
fetchOptions?.onError?.();
|
96
|
+
} catch {}
|
39
97
|
// @ts-expect-error Why are we getting the wrong constructor here?
|
40
98
|
throw new Error('GraphQL network response had errors', {
|
41
99
|
cause: networkResponse,
|
@@ -43,18 +101,21 @@ export function makeNetworkRequest(
|
|
43
101
|
}
|
44
102
|
|
45
103
|
if (status.kind === 'UndisposedIncomplete') {
|
104
|
+
const root = { __link: ROOT_ID, __typename: artifact.concreteType };
|
46
105
|
normalizeData(
|
47
106
|
environment,
|
48
|
-
artifact.normalizationAst,
|
107
|
+
artifact.networkRequestInfo.normalizationAst,
|
49
108
|
networkResponse.data ?? {},
|
50
109
|
variables,
|
51
110
|
artifact.kind === 'Entrypoint'
|
52
111
|
? artifact.readerWithRefetchQueries.nestedRefetchQueries
|
53
112
|
: [],
|
113
|
+
root,
|
54
114
|
);
|
55
115
|
const retainedQuery = {
|
56
|
-
normalizationAst: artifact.normalizationAst,
|
116
|
+
normalizationAst: artifact.networkRequestInfo.normalizationAst,
|
57
117
|
variables,
|
118
|
+
root,
|
58
119
|
};
|
59
120
|
status = {
|
60
121
|
kind: 'UndisposedComplete',
|
@@ -62,6 +123,21 @@ export function makeNetworkRequest(
|
|
62
123
|
};
|
63
124
|
retainQuery(environment, retainedQuery);
|
64
125
|
}
|
126
|
+
|
127
|
+
try {
|
128
|
+
fetchOptions?.onComplete?.();
|
129
|
+
} catch {}
|
130
|
+
})
|
131
|
+
.catch((e) => {
|
132
|
+
logMessage(environment, {
|
133
|
+
kind: 'ReceivedNetworkError',
|
134
|
+
networkRequestId: myNetworkRequestId,
|
135
|
+
error: e,
|
136
|
+
});
|
137
|
+
try {
|
138
|
+
fetchOptions?.onError?.();
|
139
|
+
} catch {}
|
140
|
+
throw e;
|
65
141
|
});
|
66
142
|
|
67
143
|
const wrapper = wrapPromise(promise);
|
package/src/core/read.ts
CHANGED
@@ -1,19 +1,27 @@
|
|
1
|
-
import {
|
2
|
-
|
1
|
+
import {
|
2
|
+
getParentRecordKey,
|
3
|
+
insertIfNotExists,
|
4
|
+
onNextChangeToRecord,
|
5
|
+
type EncounteredIds,
|
6
|
+
} from './cache';
|
3
7
|
import { getOrCreateCachedComponent } from './componentCache';
|
4
8
|
import {
|
5
9
|
IsographEntrypoint,
|
6
10
|
RefetchQueryNormalizationArtifactWrapper,
|
7
11
|
} from './entrypoint';
|
8
|
-
import {
|
12
|
+
import {
|
13
|
+
FragmentReference,
|
14
|
+
Variables,
|
15
|
+
ExtractData,
|
16
|
+
ExtractParameters,
|
17
|
+
} from './FragmentReference';
|
9
18
|
import {
|
10
19
|
assertLink,
|
11
|
-
DataId,
|
12
|
-
defaultMissingFieldHandler,
|
13
20
|
getOrLoadIsographArtifact,
|
14
21
|
IsographEnvironment,
|
22
|
+
type Link,
|
15
23
|
} from './IsographEnvironment';
|
16
|
-
import {
|
24
|
+
import { maybeMakeNetworkRequest } from './makeNetworkRequest';
|
17
25
|
import {
|
18
26
|
getPromiseState,
|
19
27
|
PromiseWrapper,
|
@@ -23,18 +31,23 @@ import {
|
|
23
31
|
} from './PromiseWrapper';
|
24
32
|
import { ReaderAst } from './reader';
|
25
33
|
import { Arguments } from './util';
|
34
|
+
import { logMessage } from './logging';
|
35
|
+
import { CleanupFn } from '@isograph/disposable-types';
|
36
|
+
import { FetchOptions } from './check';
|
26
37
|
|
27
38
|
export type WithEncounteredRecords<T> = {
|
28
|
-
readonly encounteredRecords:
|
29
|
-
readonly item: T
|
39
|
+
readonly encounteredRecords: EncounteredIds;
|
40
|
+
readonly item: ExtractData<T>;
|
30
41
|
};
|
31
42
|
|
32
|
-
export function readButDoNotEvaluate<
|
43
|
+
export function readButDoNotEvaluate<
|
44
|
+
TReadFromStore extends { parameters: object; data: object },
|
45
|
+
>(
|
33
46
|
environment: IsographEnvironment,
|
34
47
|
fragmentReference: FragmentReference<TReadFromStore, unknown>,
|
35
48
|
networkRequestOptions: NetworkRequestReaderOptions,
|
36
49
|
): WithEncounteredRecords<TReadFromStore> {
|
37
|
-
const mutableEncounteredRecords = new
|
50
|
+
const mutableEncounteredRecords: EncounteredIds = new Map();
|
38
51
|
|
39
52
|
const readerWithRefetchQueries = readPromise(
|
40
53
|
fragmentReference.readerWithRefetchQueries,
|
@@ -50,10 +63,12 @@ export function readButDoNotEvaluate<TReadFromStore extends Object>(
|
|
50
63
|
networkRequestOptions,
|
51
64
|
mutableEncounteredRecords,
|
52
65
|
);
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
66
|
+
|
67
|
+
logMessage(environment, {
|
68
|
+
kind: 'DoneReading',
|
69
|
+
response,
|
70
|
+
});
|
71
|
+
|
57
72
|
if (response.kind === 'MissingData') {
|
58
73
|
// There are two cases here that we care about:
|
59
74
|
// 1. the network request is in flight, we haven't suspend on it, and we want
|
@@ -70,11 +85,11 @@ export function readButDoNotEvaluate<TReadFromStore extends Object>(
|
|
70
85
|
) {
|
71
86
|
// TODO assert that the network request state is not Err
|
72
87
|
throw new Promise((resolve, reject) => {
|
73
|
-
|
88
|
+
onNextChangeToRecord(environment, response.recordLink).then(resolve);
|
74
89
|
fragmentReference.networkRequest.promise.catch(reject);
|
75
90
|
});
|
76
91
|
}
|
77
|
-
throw
|
92
|
+
throw onNextChangeToRecord(environment, response.recordLink);
|
78
93
|
} else {
|
79
94
|
return {
|
80
95
|
encounteredRecords: mutableEncounteredRecords,
|
@@ -83,34 +98,40 @@ export function readButDoNotEvaluate<TReadFromStore extends Object>(
|
|
83
98
|
}
|
84
99
|
}
|
85
100
|
|
86
|
-
type ReadDataResult<TReadFromStore> =
|
101
|
+
export type ReadDataResult<TReadFromStore> =
|
87
102
|
| {
|
88
103
|
readonly kind: 'Success';
|
89
|
-
readonly data: TReadFromStore
|
90
|
-
readonly encounteredRecords:
|
104
|
+
readonly data: ExtractData<TReadFromStore>;
|
105
|
+
readonly encounteredRecords: EncounteredIds;
|
91
106
|
}
|
92
107
|
| {
|
93
108
|
readonly kind: 'MissingData';
|
94
109
|
readonly reason: string;
|
95
110
|
readonly nestedReason?: ReadDataResult<unknown>;
|
111
|
+
readonly recordLink: Link;
|
96
112
|
};
|
97
113
|
|
98
114
|
function readData<TReadFromStore>(
|
99
115
|
environment: IsographEnvironment,
|
100
116
|
ast: ReaderAst<TReadFromStore>,
|
101
|
-
root:
|
102
|
-
variables:
|
117
|
+
root: Link,
|
118
|
+
variables: ExtractParameters<TReadFromStore>,
|
103
119
|
nestedRefetchQueries: RefetchQueryNormalizationArtifactWrapper[],
|
104
120
|
networkRequest: PromiseWrapper<void, any>,
|
105
121
|
networkRequestOptions: NetworkRequestReaderOptions,
|
106
|
-
mutableEncounteredRecords:
|
122
|
+
mutableEncounteredRecords: EncounteredIds,
|
107
123
|
): ReadDataResult<TReadFromStore> {
|
108
|
-
|
109
|
-
|
124
|
+
const encounteredIds = insertIfNotExists(
|
125
|
+
mutableEncounteredRecords,
|
126
|
+
root.__typename,
|
127
|
+
);
|
128
|
+
encounteredIds.add(root.__link);
|
129
|
+
let storeRecord = environment.store[root.__typename]?.[root.__link];
|
110
130
|
if (storeRecord === undefined) {
|
111
131
|
return {
|
112
132
|
kind: 'MissingData',
|
113
|
-
reason: 'No record for root ' + root,
|
133
|
+
reason: 'No record for root ' + root.__link,
|
134
|
+
recordLink: root,
|
114
135
|
};
|
115
136
|
}
|
116
137
|
|
@@ -134,7 +155,9 @@ function readData<TReadFromStore>(
|
|
134
155
|
if (value === undefined) {
|
135
156
|
return {
|
136
157
|
kind: 'MissingData',
|
137
|
-
reason:
|
158
|
+
reason:
|
159
|
+
'No value for ' + storeRecordName + ' on root ' + root.__link,
|
160
|
+
recordLink: root,
|
138
161
|
};
|
139
162
|
}
|
140
163
|
target[field.alias ?? field.fieldName] = value;
|
@@ -154,18 +177,20 @@ function readData<TReadFromStore>(
|
|
154
177
|
'No link for ' +
|
155
178
|
storeRecordName +
|
156
179
|
' on root ' +
|
157
|
-
root +
|
180
|
+
root.__link +
|
158
181
|
'. Link is ' +
|
159
182
|
JSON.stringify(item),
|
183
|
+
recordLink: root,
|
160
184
|
};
|
161
185
|
} else if (link === null) {
|
162
186
|
results.push(null);
|
163
187
|
continue;
|
164
188
|
}
|
189
|
+
|
165
190
|
const result = readData(
|
166
191
|
environment,
|
167
192
|
field.selections,
|
168
|
-
link
|
193
|
+
link,
|
169
194
|
variables,
|
170
195
|
nestedRefetchQueries,
|
171
196
|
networkRequest,
|
@@ -179,10 +204,11 @@ function readData<TReadFromStore>(
|
|
179
204
|
'Missing data for ' +
|
180
205
|
storeRecordName +
|
181
206
|
' on root ' +
|
182
|
-
root +
|
207
|
+
root.__link +
|
183
208
|
'. Link is ' +
|
184
209
|
JSON.stringify(item),
|
185
210
|
nestedReason: result,
|
211
|
+
recordLink: result.recordLink,
|
186
212
|
};
|
187
213
|
}
|
188
214
|
results.push(result.data);
|
@@ -191,17 +217,63 @@ function readData<TReadFromStore>(
|
|
191
217
|
break;
|
192
218
|
}
|
193
219
|
let link = assertLink(value);
|
220
|
+
|
221
|
+
if (field.condition) {
|
222
|
+
const data = readData(
|
223
|
+
environment,
|
224
|
+
field.condition.readerAst,
|
225
|
+
root,
|
226
|
+
variables,
|
227
|
+
nestedRefetchQueries,
|
228
|
+
networkRequest,
|
229
|
+
networkRequestOptions,
|
230
|
+
mutableEncounteredRecords,
|
231
|
+
);
|
232
|
+
if (data.kind === 'MissingData') {
|
233
|
+
return {
|
234
|
+
kind: 'MissingData',
|
235
|
+
reason:
|
236
|
+
'Missing data for ' +
|
237
|
+
storeRecordName +
|
238
|
+
' on root ' +
|
239
|
+
root.__link,
|
240
|
+
nestedReason: data,
|
241
|
+
recordLink: data.recordLink,
|
242
|
+
};
|
243
|
+
}
|
244
|
+
const condition = field.condition.resolver({
|
245
|
+
data: data.data,
|
246
|
+
parameters: {},
|
247
|
+
});
|
248
|
+
if (condition === true) {
|
249
|
+
link = root;
|
250
|
+
} else if (condition === false) {
|
251
|
+
link = null;
|
252
|
+
} else {
|
253
|
+
link = condition;
|
254
|
+
}
|
255
|
+
}
|
256
|
+
|
194
257
|
if (link === undefined) {
|
195
258
|
// TODO make this configurable, and also generated and derived from the schema
|
196
|
-
const missingFieldHandler =
|
197
|
-
|
198
|
-
const altLink = missingFieldHandler(
|
259
|
+
const missingFieldHandler = environment.missingFieldHandler;
|
260
|
+
|
261
|
+
const altLink = missingFieldHandler?.(
|
199
262
|
storeRecord,
|
200
263
|
root,
|
201
264
|
field.fieldName,
|
202
265
|
field.arguments,
|
203
266
|
variables,
|
204
267
|
);
|
268
|
+
logMessage(environment, {
|
269
|
+
kind: 'MissingFieldHandlerCalled',
|
270
|
+
root,
|
271
|
+
storeRecord,
|
272
|
+
fieldName: field.fieldName,
|
273
|
+
arguments: field.arguments,
|
274
|
+
variables,
|
275
|
+
});
|
276
|
+
|
205
277
|
if (altLink === undefined) {
|
206
278
|
return {
|
207
279
|
kind: 'MissingData',
|
@@ -209,9 +281,10 @@ function readData<TReadFromStore>(
|
|
209
281
|
'No link for ' +
|
210
282
|
storeRecordName +
|
211
283
|
' on root ' +
|
212
|
-
root +
|
284
|
+
root.__link +
|
213
285
|
'. Link is ' +
|
214
286
|
JSON.stringify(value),
|
287
|
+
recordLink: root,
|
215
288
|
};
|
216
289
|
} else {
|
217
290
|
link = altLink;
|
@@ -220,7 +293,7 @@ function readData<TReadFromStore>(
|
|
220
293
|
target[field.alias ?? field.fieldName] = null;
|
221
294
|
break;
|
222
295
|
}
|
223
|
-
const targetId = link
|
296
|
+
const targetId = link;
|
224
297
|
const data = readData(
|
225
298
|
environment,
|
226
299
|
field.selections,
|
@@ -234,8 +307,10 @@ function readData<TReadFromStore>(
|
|
234
307
|
if (data.kind === 'MissingData') {
|
235
308
|
return {
|
236
309
|
kind: 'MissingData',
|
237
|
-
reason:
|
310
|
+
reason:
|
311
|
+
'Missing data for ' + storeRecordName + ' on root ' + root.__link,
|
238
312
|
nestedReason: data,
|
313
|
+
recordLink: data.recordLink,
|
239
314
|
};
|
240
315
|
}
|
241
316
|
target[field.alias ?? field.fieldName] = data.data;
|
@@ -260,15 +335,19 @@ function readData<TReadFromStore>(
|
|
260
335
|
if (data.kind === 'MissingData') {
|
261
336
|
return {
|
262
337
|
kind: 'MissingData',
|
263
|
-
reason:
|
338
|
+
reason:
|
339
|
+
'Missing data for ' + field.alias + ' on root ' + root.__link,
|
264
340
|
nestedReason: data,
|
341
|
+
recordLink: data.recordLink,
|
265
342
|
};
|
266
343
|
} else {
|
267
344
|
const refetchQueryIndex = field.refetchQuery;
|
268
|
-
if (refetchQueryIndex == null) {
|
269
|
-
throw new Error('refetchQuery is null in RefetchField');
|
270
|
-
}
|
271
345
|
const refetchQuery = nestedRefetchQueries[refetchQueryIndex];
|
346
|
+
if (refetchQuery == null) {
|
347
|
+
throw new Error(
|
348
|
+
'refetchQuery is null in RefetchField. This is indicative of a bug in Isograph.',
|
349
|
+
);
|
350
|
+
}
|
272
351
|
const refetchQueryArtifact = refetchQuery.artifact;
|
273
352
|
const allowedVariables = refetchQuery.allowedVariables;
|
274
353
|
|
@@ -276,7 +355,7 @@ function readData<TReadFromStore>(
|
|
276
355
|
// use the resolver reader AST to get the resolver parameters.
|
277
356
|
target[field.alias] = (args: any) => [
|
278
357
|
// Stable id
|
279
|
-
root + '__' + field.name,
|
358
|
+
root.__link + '__' + field.name,
|
280
359
|
// Fetcher
|
281
360
|
field.refetchReaderArtifact.resolver(
|
282
361
|
environment,
|
@@ -294,9 +373,15 @@ function readData<TReadFromStore>(
|
|
294
373
|
}
|
295
374
|
case 'Resolver': {
|
296
375
|
const usedRefetchQueries = field.usedRefetchQueries;
|
297
|
-
const resolverRefetchQueries = usedRefetchQueries.map(
|
298
|
-
|
299
|
-
|
376
|
+
const resolverRefetchQueries = usedRefetchQueries.map((index) => {
|
377
|
+
const resolverRefetchQuery = nestedRefetchQueries[index];
|
378
|
+
if (resolverRefetchQuery == null) {
|
379
|
+
throw new Error(
|
380
|
+
'resolverRefetchQuery is null in Resolver. This is indicative of a bug in Isograph.',
|
381
|
+
);
|
382
|
+
}
|
383
|
+
return resolverRefetchQuery;
|
384
|
+
});
|
300
385
|
|
301
386
|
switch (field.readerArtifact.kind) {
|
302
387
|
case 'EagerReaderArtifact': {
|
@@ -304,7 +389,7 @@ function readData<TReadFromStore>(
|
|
304
389
|
environment,
|
305
390
|
field.readerArtifact.readerAst,
|
306
391
|
root,
|
307
|
-
variables,
|
392
|
+
generateChildVariableMap(variables, field.arguments),
|
308
393
|
resolverRefetchQueries,
|
309
394
|
networkRequest,
|
310
395
|
networkRequestOptions,
|
@@ -313,11 +398,18 @@ function readData<TReadFromStore>(
|
|
313
398
|
if (data.kind === 'MissingData') {
|
314
399
|
return {
|
315
400
|
kind: 'MissingData',
|
316
|
-
reason:
|
401
|
+
reason:
|
402
|
+
'Missing data for ' + field.alias + ' on root ' + root.__link,
|
317
403
|
nestedReason: data,
|
404
|
+
recordLink: data.recordLink,
|
318
405
|
};
|
319
406
|
} else {
|
320
|
-
|
407
|
+
const firstParameter = {
|
408
|
+
data: data.data,
|
409
|
+
parameters: variables,
|
410
|
+
};
|
411
|
+
target[field.alias] =
|
412
|
+
field.readerArtifact.resolver(firstParameter);
|
321
413
|
}
|
322
414
|
break;
|
323
415
|
}
|
@@ -363,11 +455,13 @@ function readData<TReadFromStore>(
|
|
363
455
|
if (refetchReaderParams.kind === 'MissingData') {
|
364
456
|
return {
|
365
457
|
kind: 'MissingData',
|
366
|
-
reason:
|
458
|
+
reason:
|
459
|
+
'Missing data for ' + field.alias + ' on root ' + root.__link,
|
367
460
|
nestedReason: refetchReaderParams,
|
461
|
+
recordLink: refetchReaderParams.recordLink,
|
368
462
|
};
|
369
463
|
} else {
|
370
|
-
target[field.alias] = (args: any) => {
|
464
|
+
target[field.alias] = (args: any, fetchOptions?: FetchOptions) => {
|
371
465
|
// TODO we should use the reader AST for this
|
372
466
|
const includeReadOutData = (variables: any, readOutData: any) => {
|
373
467
|
variables.id = readOutData.id;
|
@@ -385,7 +479,9 @@ function readData<TReadFromStore>(
|
|
385
479
|
|
386
480
|
return [
|
387
481
|
// Stable id
|
388
|
-
root +
|
482
|
+
root.__typename +
|
483
|
+
':' +
|
484
|
+
root.__link +
|
389
485
|
'/' +
|
390
486
|
field.name +
|
391
487
|
'/' +
|
@@ -396,7 +492,12 @@ function readData<TReadFromStore>(
|
|
396
492
|
entrypoint: IsographEntrypoint<any, any>,
|
397
493
|
): [FragmentReference<any, any>, CleanupFn] => {
|
398
494
|
const [networkRequest, disposeNetworkRequest] =
|
399
|
-
|
495
|
+
maybeMakeNetworkRequest(
|
496
|
+
environment,
|
497
|
+
entrypoint,
|
498
|
+
localVariables,
|
499
|
+
fetchOptions,
|
500
|
+
);
|
400
501
|
|
401
502
|
const fragmentReference: FragmentReference<any, any> = {
|
402
503
|
kind: 'FragmentReference',
|
@@ -410,7 +511,7 @@ function readData<TReadFromStore>(
|
|
410
511
|
} as const),
|
411
512
|
|
412
513
|
// TODO localVariables is not guaranteed to have an id field
|
413
|
-
root
|
514
|
+
root,
|
414
515
|
variables: localVariables,
|
415
516
|
networkRequest,
|
416
517
|
};
|
@@ -453,10 +554,11 @@ function readData<TReadFromStore>(
|
|
453
554
|
entrypointLoaderState.kind === 'EntrypointNotLoaded'
|
454
555
|
) {
|
455
556
|
const [networkRequest, disposeNetworkRequest] =
|
456
|
-
|
557
|
+
maybeMakeNetworkRequest(
|
457
558
|
environment,
|
458
559
|
entrypoint,
|
459
560
|
localVariables,
|
561
|
+
fetchOptions,
|
460
562
|
);
|
461
563
|
entrypointLoaderState = {
|
462
564
|
kind: 'NetworkRequestStarted',
|
@@ -479,7 +581,7 @@ function readData<TReadFromStore>(
|
|
479
581
|
),
|
480
582
|
|
481
583
|
// TODO localVariables is not guaranteed to have an id field
|
482
|
-
root
|
584
|
+
root,
|
483
585
|
variables: localVariables,
|
484
586
|
networkRequest,
|
485
587
|
};
|
@@ -542,7 +644,12 @@ function generateChildVariableMap(
|
|
542
644
|
const childVars: Writable<Variables> = {};
|
543
645
|
for (const [name, value] of fieldArguments) {
|
544
646
|
if (value.kind === 'Variable') {
|
545
|
-
|
647
|
+
const variable = variables[value.name];
|
648
|
+
// Variable could be null if it was not provided but has a default case,
|
649
|
+
// so we allow the loop to continue rather than throwing an error.
|
650
|
+
if (variable != null) {
|
651
|
+
childVars[name] = variable;
|
652
|
+
}
|
546
653
|
} else {
|
547
654
|
childVars[name] = value.value;
|
548
655
|
}
|
@@ -603,7 +710,7 @@ export function getNetworkRequestOptionsWithDefaults(
|
|
603
710
|
// TODO call stableStringifyArgs on the variable values, as well.
|
604
711
|
// This doesn't matter for now, since we are just using primitive values
|
605
712
|
// in the demo.
|
606
|
-
function stableStringifyArgs(args:
|
713
|
+
function stableStringifyArgs(args: object) {
|
607
714
|
const keys = Object.keys(args);
|
608
715
|
keys.sort();
|
609
716
|
let s = '';
|