@isograph/react 0.0.0-main-0e6e4170 → 0.0.0-main-7faadacd
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 +1 -1
- package/dist/core/read.d.ts +12 -6
- package/dist/core/read.d.ts.map +1 -1
- package/dist/core/read.js +203 -177
- package/package.json +4 -4
- package/src/core/read.ts +296 -241
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
|
|
2
|
-
> @isograph/react@0.0.0-main-
|
|
2
|
+
> @isograph/react@0.0.0-main-7faadacd compile-typescript /Users/runner/work/isograph/isograph/libs/isograph-react
|
|
3
3
|
> rm -rf dist/* && tsc -p tsconfig.pkg.json
|
|
4
4
|
|
package/dist/core/read.d.ts
CHANGED
|
@@ -1,24 +1,30 @@
|
|
|
1
1
|
import { type EncounteredIds } from './cache';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { RefetchQueryNormalizationArtifactWrapper } from './entrypoint';
|
|
3
|
+
import { ExtractData, FragmentReference, Variables, type UnknownTReadFromStore } from './FragmentReference';
|
|
4
|
+
import { IsographEnvironment, type DataTypeValue, type Link, type StoreRecord } from './IsographEnvironment';
|
|
5
|
+
import { PromiseWrapper } from './PromiseWrapper';
|
|
6
|
+
import { ReaderAst, type ReaderImperativelyLoadedField, type ReaderLinkedField, type ReaderScalarField } from './reader';
|
|
4
7
|
export type WithEncounteredRecords<T> = {
|
|
5
8
|
readonly encounteredRecords: EncounteredIds;
|
|
6
9
|
readonly item: ExtractData<T>;
|
|
7
10
|
};
|
|
8
11
|
export declare function readButDoNotEvaluate<TReadFromStore extends UnknownTReadFromStore>(environment: IsographEnvironment, fragmentReference: FragmentReference<TReadFromStore, unknown>, networkRequestOptions: NetworkRequestReaderOptions): WithEncounteredRecords<TReadFromStore>;
|
|
9
|
-
export type
|
|
12
|
+
export type ReadDataResultSuccess<Data> = {
|
|
10
13
|
readonly kind: 'Success';
|
|
11
|
-
readonly data:
|
|
12
|
-
|
|
13
|
-
|
|
14
|
+
readonly data: Data;
|
|
15
|
+
};
|
|
16
|
+
export type ReadDataResult<Data> = ReadDataResultSuccess<Data> | {
|
|
14
17
|
readonly kind: 'MissingData';
|
|
15
18
|
readonly reason: string;
|
|
16
19
|
readonly nestedReason?: ReadDataResult<unknown>;
|
|
17
20
|
readonly recordLink: Link;
|
|
18
21
|
};
|
|
22
|
+
export declare function readScalarFieldData(field: ReaderScalarField, storeRecord: StoreRecord, root: Link, variables: Variables): ReadDataResult<string | number | boolean | Link | DataTypeValue[] | null>;
|
|
23
|
+
export declare function readLinkedFieldData(environment: IsographEnvironment, field: ReaderLinkedField, storeRecord: StoreRecord, root: Link, variables: Variables, networkRequest: PromiseWrapper<void, any>, readData: <TReadFromStore>(ast: ReaderAst<TReadFromStore>, root: Link) => ReadDataResult<object>): ReadDataResult<unknown>;
|
|
19
24
|
export type NetworkRequestReaderOptions = {
|
|
20
25
|
suspendIfInFlight: boolean;
|
|
21
26
|
throwOnNetworkError: boolean;
|
|
22
27
|
};
|
|
23
28
|
export declare function getNetworkRequestOptionsWithDefaults(networkRequestOptions?: Partial<NetworkRequestReaderOptions> | void): NetworkRequestReaderOptions;
|
|
29
|
+
export declare function readImperativelyLoadedField(environment: IsographEnvironment, field: ReaderImperativelyLoadedField, root: Link, variables: Variables, nestedRefetchQueries: RefetchQueryNormalizationArtifactWrapper[], networkRequest: PromiseWrapper<void, any>, networkRequestOptions: NetworkRequestReaderOptions, mutableEncounteredRecords: EncounteredIds): ReadDataResult<unknown>;
|
|
24
30
|
//# sourceMappingURL=read.d.ts.map
|
package/dist/core/read.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"read.d.ts","sourceRoot":"","sources":["../../src/core/read.ts"],"names":[],"mappings":"AACA,OAAO,EAIL,KAAK,cAAc,EACpB,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"read.d.ts","sourceRoot":"","sources":["../../src/core/read.ts"],"names":[],"mappings":"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"}
|
package/dist/core/read.js
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.readButDoNotEvaluate = readButDoNotEvaluate;
|
|
4
|
+
exports.readScalarFieldData = readScalarFieldData;
|
|
5
|
+
exports.readLinkedFieldData = readLinkedFieldData;
|
|
4
6
|
exports.getNetworkRequestOptionsWithDefaults = getNetworkRequestOptionsWithDefaults;
|
|
7
|
+
exports.readImperativelyLoadedField = readImperativelyLoadedField;
|
|
5
8
|
const cache_1 = require("./cache");
|
|
6
9
|
const componentCache_1 = require("./componentCache");
|
|
7
10
|
const IsographEnvironment_1 = require("./IsographEnvironment");
|
|
@@ -56,7 +59,7 @@ function readButDoNotEvaluate(environment, fragmentReference, networkRequestOpti
|
|
|
56
59
|
}
|
|
57
60
|
}
|
|
58
61
|
function readData(environment, ast, root, variables, nestedRefetchQueries, networkRequest, networkRequestOptions, mutableEncounteredRecords) {
|
|
59
|
-
var _a, _b, _c
|
|
62
|
+
var _a, _b, _c;
|
|
60
63
|
const encounteredIds = (0, cache_1.insertIfNotExists)(mutableEncounteredRecords, root.__typename);
|
|
61
64
|
encounteredIds.add(root.__link);
|
|
62
65
|
let storeRecord = (_a = environment.store[root.__typename]) === null || _a === void 0 ? void 0 : _a[root.__link];
|
|
@@ -71,25 +74,17 @@ function readData(environment, ast, root, variables, nestedRefetchQueries, netwo
|
|
|
71
74
|
return {
|
|
72
75
|
kind: 'Success',
|
|
73
76
|
data: null,
|
|
74
|
-
encounteredRecords: mutableEncounteredRecords,
|
|
75
77
|
};
|
|
76
78
|
}
|
|
77
79
|
let target = {};
|
|
78
80
|
for (const field of ast) {
|
|
79
81
|
switch (field.kind) {
|
|
80
82
|
case 'Scalar': {
|
|
81
|
-
const
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
// to happen for when we handle errors.
|
|
85
|
-
if (value === undefined) {
|
|
86
|
-
return {
|
|
87
|
-
kind: 'MissingData',
|
|
88
|
-
reason: 'No value for ' + storeRecordName + ' on root ' + root.__link,
|
|
89
|
-
recordLink: root,
|
|
90
|
-
};
|
|
83
|
+
const data = readScalarFieldData(field, storeRecord, root, variables);
|
|
84
|
+
if (data.kind === 'MissingData') {
|
|
85
|
+
return data;
|
|
91
86
|
}
|
|
92
|
-
target[(_b = field.alias) !== null && _b !== void 0 ? _b : field.fieldName] =
|
|
87
|
+
target[(_b = field.alias) !== null && _b !== void 0 ? _b : field.fieldName] = data.data;
|
|
93
88
|
break;
|
|
94
89
|
}
|
|
95
90
|
case 'Link': {
|
|
@@ -97,176 +92,19 @@ function readData(environment, ast, root, variables, nestedRefetchQueries, netwo
|
|
|
97
92
|
break;
|
|
98
93
|
}
|
|
99
94
|
case 'Linked': {
|
|
100
|
-
const
|
|
101
|
-
const value = storeRecord[storeRecordName];
|
|
102
|
-
if (Array.isArray(value)) {
|
|
103
|
-
const results = [];
|
|
104
|
-
for (const item of value) {
|
|
105
|
-
const link = (0, IsographEnvironment_1.assertLink)(item);
|
|
106
|
-
if (link === undefined) {
|
|
107
|
-
return {
|
|
108
|
-
kind: 'MissingData',
|
|
109
|
-
reason: 'No link for ' +
|
|
110
|
-
storeRecordName +
|
|
111
|
-
' on root ' +
|
|
112
|
-
root.__link +
|
|
113
|
-
'. Link is ' +
|
|
114
|
-
JSON.stringify(item),
|
|
115
|
-
recordLink: root,
|
|
116
|
-
};
|
|
117
|
-
}
|
|
118
|
-
else if (link === null) {
|
|
119
|
-
results.push(null);
|
|
120
|
-
continue;
|
|
121
|
-
}
|
|
122
|
-
const result = readData(environment, field.selections, link, variables, nestedRefetchQueries, networkRequest, networkRequestOptions, mutableEncounteredRecords);
|
|
123
|
-
if (result.kind === 'MissingData') {
|
|
124
|
-
return {
|
|
125
|
-
kind: 'MissingData',
|
|
126
|
-
reason: 'Missing data for ' +
|
|
127
|
-
storeRecordName +
|
|
128
|
-
' on root ' +
|
|
129
|
-
root.__link +
|
|
130
|
-
'. Link is ' +
|
|
131
|
-
JSON.stringify(item),
|
|
132
|
-
nestedReason: result,
|
|
133
|
-
recordLink: result.recordLink,
|
|
134
|
-
};
|
|
135
|
-
}
|
|
136
|
-
results.push(result.data);
|
|
137
|
-
}
|
|
138
|
-
target[(_c = field.alias) !== null && _c !== void 0 ? _c : field.fieldName] = results;
|
|
139
|
-
break;
|
|
140
|
-
}
|
|
141
|
-
let link = (0, IsographEnvironment_1.assertLink)(value);
|
|
142
|
-
if (field.condition) {
|
|
143
|
-
const data = readData(environment, field.condition.readerAst, root, variables, nestedRefetchQueries, networkRequest, networkRequestOptions, mutableEncounteredRecords);
|
|
144
|
-
if (data.kind === 'MissingData') {
|
|
145
|
-
return {
|
|
146
|
-
kind: 'MissingData',
|
|
147
|
-
reason: 'Missing data for ' +
|
|
148
|
-
storeRecordName +
|
|
149
|
-
' on root ' +
|
|
150
|
-
root.__link,
|
|
151
|
-
nestedReason: data,
|
|
152
|
-
recordLink: data.recordLink,
|
|
153
|
-
};
|
|
154
|
-
}
|
|
155
|
-
const readerWithRefetchQueries = {
|
|
156
|
-
kind: 'ReaderWithRefetchQueries',
|
|
157
|
-
readerArtifact: field.condition,
|
|
158
|
-
// TODO this is wrong
|
|
159
|
-
// should map field.condition.usedRefetchQueries
|
|
160
|
-
// but it doesn't exist
|
|
161
|
-
nestedRefetchQueries: [],
|
|
162
|
-
};
|
|
163
|
-
const fragment = {
|
|
164
|
-
kind: 'FragmentReference',
|
|
165
|
-
readerWithRefetchQueries: (0, PromiseWrapper_1.wrapResolvedValue)(readerWithRefetchQueries),
|
|
166
|
-
root,
|
|
167
|
-
variables: generateChildVariableMap(variables,
|
|
168
|
-
// TODO this is wrong
|
|
169
|
-
// should use field.condition.variables
|
|
170
|
-
// but it doesn't exist
|
|
171
|
-
[]),
|
|
172
|
-
networkRequest,
|
|
173
|
-
};
|
|
174
|
-
const condition = field.condition.resolver(Object.assign({ data: data.data, parameters: {} }, (field.condition.hasUpdatable
|
|
175
|
-
? {
|
|
176
|
-
startUpdate: (0, startUpdate_1.getOrCreateCachedStartUpdate)(environment, fragment, readerWithRefetchQueries.readerArtifact.fieldName),
|
|
177
|
-
}
|
|
178
|
-
: undefined)));
|
|
179
|
-
if (condition === true) {
|
|
180
|
-
link = root;
|
|
181
|
-
}
|
|
182
|
-
else if (condition === false) {
|
|
183
|
-
link = null;
|
|
184
|
-
}
|
|
185
|
-
else {
|
|
186
|
-
link = condition;
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
if (link === undefined) {
|
|
190
|
-
// TODO make this configurable, and also generated and derived from the schema
|
|
191
|
-
const missingFieldHandler = environment.missingFieldHandler;
|
|
192
|
-
const altLink = missingFieldHandler === null || missingFieldHandler === void 0 ? void 0 : missingFieldHandler(storeRecord, root, field.fieldName, field.arguments, variables);
|
|
193
|
-
(0, logging_1.logMessage)(environment, {
|
|
194
|
-
kind: 'MissingFieldHandlerCalled',
|
|
195
|
-
root,
|
|
196
|
-
storeRecord,
|
|
197
|
-
fieldName: field.fieldName,
|
|
198
|
-
arguments: field.arguments,
|
|
199
|
-
variables,
|
|
200
|
-
});
|
|
201
|
-
if (altLink === undefined) {
|
|
202
|
-
return {
|
|
203
|
-
kind: 'MissingData',
|
|
204
|
-
reason: 'No link for ' +
|
|
205
|
-
storeRecordName +
|
|
206
|
-
' on root ' +
|
|
207
|
-
root.__link +
|
|
208
|
-
'. Link is ' +
|
|
209
|
-
JSON.stringify(value),
|
|
210
|
-
recordLink: root,
|
|
211
|
-
};
|
|
212
|
-
}
|
|
213
|
-
else {
|
|
214
|
-
link = altLink;
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
else if (link === null) {
|
|
218
|
-
target[(_d = field.alias) !== null && _d !== void 0 ? _d : field.fieldName] = null;
|
|
219
|
-
break;
|
|
220
|
-
}
|
|
221
|
-
const targetId = link;
|
|
222
|
-
const data = readData(environment, field.selections, targetId, variables, nestedRefetchQueries, networkRequest, networkRequestOptions, mutableEncounteredRecords);
|
|
95
|
+
const data = readLinkedFieldData(environment, field, storeRecord, root, variables, networkRequest, (ast, root) => readData(environment, ast, root, variables, nestedRefetchQueries, networkRequest, networkRequestOptions, mutableEncounteredRecords));
|
|
223
96
|
if (data.kind === 'MissingData') {
|
|
224
|
-
return
|
|
225
|
-
kind: 'MissingData',
|
|
226
|
-
reason: 'Missing data for ' + storeRecordName + ' on root ' + root.__link,
|
|
227
|
-
nestedReason: data,
|
|
228
|
-
recordLink: data.recordLink,
|
|
229
|
-
};
|
|
97
|
+
return data;
|
|
230
98
|
}
|
|
231
|
-
target[(
|
|
99
|
+
target[(_c = field.alias) !== null && _c !== void 0 ? _c : field.fieldName] = data.data;
|
|
232
100
|
break;
|
|
233
101
|
}
|
|
234
102
|
case 'ImperativelyLoadedField': {
|
|
235
|
-
|
|
236
|
-
// id field).
|
|
237
|
-
const data = readData(environment, field.refetchReaderArtifact.readerAst, root, variables,
|
|
238
|
-
// Refetch fields just read the id, and don't need refetch query artifacts
|
|
239
|
-
[],
|
|
240
|
-
// This is probably indicative of the fact that we are doing redundant checks
|
|
241
|
-
// on the status of this network request...
|
|
242
|
-
networkRequest, networkRequestOptions, mutableEncounteredRecords);
|
|
103
|
+
const data = readImperativelyLoadedField(environment, field, root, variables, nestedRefetchQueries, networkRequest, networkRequestOptions, mutableEncounteredRecords);
|
|
243
104
|
if (data.kind === 'MissingData') {
|
|
244
|
-
return
|
|
245
|
-
kind: 'MissingData',
|
|
246
|
-
reason: 'Missing data for ' + field.alias + ' on root ' + root.__link,
|
|
247
|
-
nestedReason: data,
|
|
248
|
-
recordLink: data.recordLink,
|
|
249
|
-
};
|
|
250
|
-
}
|
|
251
|
-
else {
|
|
252
|
-
const refetchQueryIndex = field.refetchQuery;
|
|
253
|
-
const refetchQuery = nestedRefetchQueries[refetchQueryIndex];
|
|
254
|
-
if (refetchQuery == null) {
|
|
255
|
-
throw new Error('refetchQuery is null in RefetchField. This is indicative of a bug in Isograph.');
|
|
256
|
-
}
|
|
257
|
-
const refetchQueryArtifact = refetchQuery.artifact;
|
|
258
|
-
const allowedVariables = refetchQuery.allowedVariables;
|
|
259
|
-
// Second, we allow the user to call the resolver, which will ultimately
|
|
260
|
-
// use the resolver reader AST to get the resolver parameters.
|
|
261
|
-
target[field.alias] = (args) => [
|
|
262
|
-
// Stable id
|
|
263
|
-
root.__link + '__' + field.name,
|
|
264
|
-
// Fetcher
|
|
265
|
-
field.refetchReaderArtifact.resolver(environment, refetchQueryArtifact, data.data, filterVariables(Object.assign(Object.assign({}, args), variables), allowedVariables), root,
|
|
266
|
-
// TODO these params should be removed
|
|
267
|
-
null, []),
|
|
268
|
-
];
|
|
105
|
+
return data;
|
|
269
106
|
}
|
|
107
|
+
target[field.alias] = data.data;
|
|
270
108
|
break;
|
|
271
109
|
}
|
|
272
110
|
case 'Resolver': {
|
|
@@ -436,7 +274,6 @@ function readData(environment, ast, root, variables, nestedRefetchQueries, netwo
|
|
|
436
274
|
return {
|
|
437
275
|
kind: 'Success',
|
|
438
276
|
data: target,
|
|
439
|
-
encounteredRecords: mutableEncounteredRecords,
|
|
440
277
|
};
|
|
441
278
|
}
|
|
442
279
|
function filterVariables(variables, allowedVariables) {
|
|
@@ -504,6 +341,155 @@ function writeQueryArgsToVariables(targetVariables, queryArgs, variables) {
|
|
|
504
341
|
}
|
|
505
342
|
}
|
|
506
343
|
}
|
|
344
|
+
function readScalarFieldData(field, storeRecord, root, variables) {
|
|
345
|
+
const storeRecordName = (0, cache_1.getParentRecordKey)(field, variables);
|
|
346
|
+
const value = storeRecord[storeRecordName];
|
|
347
|
+
// TODO consider making scalars into discriminated unions. This probably has
|
|
348
|
+
// to happen for when we handle errors.
|
|
349
|
+
if (value === undefined) {
|
|
350
|
+
return {
|
|
351
|
+
kind: 'MissingData',
|
|
352
|
+
reason: 'No value for ' + storeRecordName + ' on root ' + root.__link,
|
|
353
|
+
recordLink: root,
|
|
354
|
+
};
|
|
355
|
+
}
|
|
356
|
+
return { kind: 'Success', data: value };
|
|
357
|
+
}
|
|
358
|
+
function readLinkedFieldData(environment, field, storeRecord, root, variables, networkRequest, readData) {
|
|
359
|
+
const storeRecordName = (0, cache_1.getParentRecordKey)(field, variables);
|
|
360
|
+
const value = storeRecord[storeRecordName];
|
|
361
|
+
if (Array.isArray(value)) {
|
|
362
|
+
const results = [];
|
|
363
|
+
for (const item of value) {
|
|
364
|
+
const link = (0, IsographEnvironment_1.assertLink)(item);
|
|
365
|
+
if (link === undefined) {
|
|
366
|
+
return {
|
|
367
|
+
kind: 'MissingData',
|
|
368
|
+
reason: 'No link for ' +
|
|
369
|
+
storeRecordName +
|
|
370
|
+
' on root ' +
|
|
371
|
+
root.__link +
|
|
372
|
+
'. Link is ' +
|
|
373
|
+
JSON.stringify(item),
|
|
374
|
+
recordLink: root,
|
|
375
|
+
};
|
|
376
|
+
}
|
|
377
|
+
else if (link === null) {
|
|
378
|
+
results.push(null);
|
|
379
|
+
continue;
|
|
380
|
+
}
|
|
381
|
+
const result = readData(field.selections, link);
|
|
382
|
+
if (result.kind === 'MissingData') {
|
|
383
|
+
return {
|
|
384
|
+
kind: 'MissingData',
|
|
385
|
+
reason: 'Missing data for ' +
|
|
386
|
+
storeRecordName +
|
|
387
|
+
' on root ' +
|
|
388
|
+
root.__link +
|
|
389
|
+
'. Link is ' +
|
|
390
|
+
JSON.stringify(item),
|
|
391
|
+
nestedReason: result,
|
|
392
|
+
recordLink: result.recordLink,
|
|
393
|
+
};
|
|
394
|
+
}
|
|
395
|
+
results.push(result.data);
|
|
396
|
+
}
|
|
397
|
+
return {
|
|
398
|
+
kind: 'Success',
|
|
399
|
+
data: results,
|
|
400
|
+
};
|
|
401
|
+
}
|
|
402
|
+
let link = (0, IsographEnvironment_1.assertLink)(value);
|
|
403
|
+
if (field.condition) {
|
|
404
|
+
const data = readData(field.condition.readerAst, root);
|
|
405
|
+
if (data.kind === 'MissingData') {
|
|
406
|
+
return {
|
|
407
|
+
kind: 'MissingData',
|
|
408
|
+
reason: 'Missing data for ' + storeRecordName + ' on root ' + root.__link,
|
|
409
|
+
nestedReason: data,
|
|
410
|
+
recordLink: data.recordLink,
|
|
411
|
+
};
|
|
412
|
+
}
|
|
413
|
+
const readerWithRefetchQueries = {
|
|
414
|
+
kind: 'ReaderWithRefetchQueries',
|
|
415
|
+
readerArtifact: field.condition,
|
|
416
|
+
// TODO this is wrong
|
|
417
|
+
// should map field.condition.usedRefetchQueries
|
|
418
|
+
// but it doesn't exist
|
|
419
|
+
nestedRefetchQueries: [],
|
|
420
|
+
};
|
|
421
|
+
const fragment = {
|
|
422
|
+
kind: 'FragmentReference',
|
|
423
|
+
readerWithRefetchQueries: (0, PromiseWrapper_1.wrapResolvedValue)(readerWithRefetchQueries),
|
|
424
|
+
root,
|
|
425
|
+
variables: generateChildVariableMap(variables,
|
|
426
|
+
// TODO this is wrong
|
|
427
|
+
// should use field.condition.variables
|
|
428
|
+
// but it doesn't exist
|
|
429
|
+
[]),
|
|
430
|
+
networkRequest,
|
|
431
|
+
};
|
|
432
|
+
const condition = field.condition.resolver(Object.assign({ data: data.data, parameters: {} }, (field.condition.hasUpdatable
|
|
433
|
+
? {
|
|
434
|
+
startUpdate: (0, startUpdate_1.getOrCreateCachedStartUpdate)(environment, fragment, readerWithRefetchQueries.readerArtifact.fieldName),
|
|
435
|
+
}
|
|
436
|
+
: undefined)));
|
|
437
|
+
if (condition === true) {
|
|
438
|
+
link = root;
|
|
439
|
+
}
|
|
440
|
+
else if (condition === false) {
|
|
441
|
+
link = null;
|
|
442
|
+
}
|
|
443
|
+
else {
|
|
444
|
+
link = condition;
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
if (link === undefined) {
|
|
448
|
+
// TODO make this configurable, and also generated and derived from the schema
|
|
449
|
+
const missingFieldHandler = environment.missingFieldHandler;
|
|
450
|
+
const altLink = missingFieldHandler === null || missingFieldHandler === void 0 ? void 0 : missingFieldHandler(storeRecord, root, field.fieldName, field.arguments, variables);
|
|
451
|
+
(0, logging_1.logMessage)(environment, {
|
|
452
|
+
kind: 'MissingFieldHandlerCalled',
|
|
453
|
+
root,
|
|
454
|
+
storeRecord,
|
|
455
|
+
fieldName: field.fieldName,
|
|
456
|
+
arguments: field.arguments,
|
|
457
|
+
variables,
|
|
458
|
+
});
|
|
459
|
+
if (altLink === undefined) {
|
|
460
|
+
return {
|
|
461
|
+
kind: 'MissingData',
|
|
462
|
+
reason: 'No link for ' +
|
|
463
|
+
storeRecordName +
|
|
464
|
+
' on root ' +
|
|
465
|
+
root.__link +
|
|
466
|
+
'. Link is ' +
|
|
467
|
+
JSON.stringify(value),
|
|
468
|
+
recordLink: root,
|
|
469
|
+
};
|
|
470
|
+
}
|
|
471
|
+
else {
|
|
472
|
+
link = altLink;
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
else if (link === null) {
|
|
476
|
+
return {
|
|
477
|
+
kind: 'Success',
|
|
478
|
+
data: null,
|
|
479
|
+
};
|
|
480
|
+
}
|
|
481
|
+
const targetId = link;
|
|
482
|
+
const data = readData(field.selections, targetId);
|
|
483
|
+
if (data.kind === 'MissingData') {
|
|
484
|
+
return {
|
|
485
|
+
kind: 'MissingData',
|
|
486
|
+
reason: 'Missing data for ' + storeRecordName + ' on root ' + root.__link,
|
|
487
|
+
nestedReason: data,
|
|
488
|
+
recordLink: data.recordLink,
|
|
489
|
+
};
|
|
490
|
+
}
|
|
491
|
+
return data;
|
|
492
|
+
}
|
|
507
493
|
function getNetworkRequestOptionsWithDefaults(networkRequestOptions) {
|
|
508
494
|
var _a, _b;
|
|
509
495
|
return {
|
|
@@ -525,3 +511,43 @@ function stableStringifyArgs(args) {
|
|
|
525
511
|
}
|
|
526
512
|
return s;
|
|
527
513
|
}
|
|
514
|
+
function readImperativelyLoadedField(environment, field, root, variables, nestedRefetchQueries, networkRequest, networkRequestOptions, mutableEncounteredRecords) {
|
|
515
|
+
// First, we read the data using the refetch reader AST (i.e. read out the
|
|
516
|
+
// id field).
|
|
517
|
+
const data = readData(environment, field.refetchReaderArtifact.readerAst, root, variables,
|
|
518
|
+
// Refetch fields just read the id, and don't need refetch query artifacts
|
|
519
|
+
[],
|
|
520
|
+
// This is probably indicative of the fact that we are doing redundant checks
|
|
521
|
+
// on the status of this network request...
|
|
522
|
+
networkRequest, networkRequestOptions, mutableEncounteredRecords);
|
|
523
|
+
if (data.kind === 'MissingData') {
|
|
524
|
+
return {
|
|
525
|
+
kind: 'MissingData',
|
|
526
|
+
reason: 'Missing data for ' + field.alias + ' on root ' + root.__link,
|
|
527
|
+
nestedReason: data,
|
|
528
|
+
recordLink: data.recordLink,
|
|
529
|
+
};
|
|
530
|
+
}
|
|
531
|
+
else {
|
|
532
|
+
const refetchQueryIndex = field.refetchQuery;
|
|
533
|
+
const refetchQuery = nestedRefetchQueries[refetchQueryIndex];
|
|
534
|
+
if (refetchQuery == null) {
|
|
535
|
+
throw new Error('refetchQuery is null in RefetchField. This is indicative of a bug in Isograph.');
|
|
536
|
+
}
|
|
537
|
+
const refetchQueryArtifact = refetchQuery.artifact;
|
|
538
|
+
const allowedVariables = refetchQuery.allowedVariables;
|
|
539
|
+
// Second, we allow the user to call the resolver, which will ultimately
|
|
540
|
+
// use the resolver reader AST to get the resolver parameters.
|
|
541
|
+
return {
|
|
542
|
+
kind: 'Success',
|
|
543
|
+
data: (args) => [
|
|
544
|
+
// Stable id
|
|
545
|
+
root.__link + '__' + field.name,
|
|
546
|
+
// Fetcher
|
|
547
|
+
field.refetchReaderArtifact.resolver(environment, refetchQueryArtifact, data.data, filterVariables(Object.assign(Object.assign({}, args), variables), allowedVariables), root,
|
|
548
|
+
// TODO these params should be removed
|
|
549
|
+
null, []),
|
|
550
|
+
],
|
|
551
|
+
};
|
|
552
|
+
}
|
|
553
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@isograph/react",
|
|
3
|
-
"version": "0.0.0-main-
|
|
3
|
+
"version": "0.0.0-main-7faadacd",
|
|
4
4
|
"description": "Use Isograph with React",
|
|
5
5
|
"homepage": "https://isograph.dev",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -20,9 +20,9 @@
|
|
|
20
20
|
"iso-watch": "cross-env ../../target/debug/isograph_cli --config ./isograph.config.json --watch"
|
|
21
21
|
},
|
|
22
22
|
"dependencies": {
|
|
23
|
-
"@isograph/disposable-types": "0.0.0-main-
|
|
24
|
-
"@isograph/react-disposable-state": "0.0.0-main-
|
|
25
|
-
"@isograph/reference-counted-pointer": "0.0.0-main-
|
|
23
|
+
"@isograph/disposable-types": "0.0.0-main-7faadacd",
|
|
24
|
+
"@isograph/react-disposable-state": "0.0.0-main-7faadacd",
|
|
25
|
+
"@isograph/reference-counted-pointer": "0.0.0-main-7faadacd"
|
|
26
26
|
},
|
|
27
27
|
"peerDependencies": {
|
|
28
28
|
"react": "^18.0.0 || ^19.0.0"
|
package/src/core/read.ts
CHANGED
|
@@ -14,7 +14,6 @@ import {
|
|
|
14
14
|
} from './entrypoint';
|
|
15
15
|
import {
|
|
16
16
|
ExtractData,
|
|
17
|
-
ExtractParameters,
|
|
18
17
|
FragmentReference,
|
|
19
18
|
Variables,
|
|
20
19
|
type UnknownTReadFromStore,
|
|
@@ -23,7 +22,9 @@ import {
|
|
|
23
22
|
assertLink,
|
|
24
23
|
getOrLoadIsographArtifact,
|
|
25
24
|
IsographEnvironment,
|
|
25
|
+
type DataTypeValue,
|
|
26
26
|
type Link,
|
|
27
|
+
type StoreRecord,
|
|
27
28
|
} from './IsographEnvironment';
|
|
28
29
|
import { logMessage } from './logging';
|
|
29
30
|
import { maybeMakeNetworkRequest } from './makeNetworkRequest';
|
|
@@ -35,7 +36,12 @@ import {
|
|
|
35
36
|
wrapPromise,
|
|
36
37
|
wrapResolvedValue,
|
|
37
38
|
} from './PromiseWrapper';
|
|
38
|
-
import {
|
|
39
|
+
import {
|
|
40
|
+
ReaderAst,
|
|
41
|
+
type ReaderImperativelyLoadedField,
|
|
42
|
+
type ReaderLinkedField,
|
|
43
|
+
type ReaderScalarField,
|
|
44
|
+
} from './reader';
|
|
39
45
|
import { getOrCreateCachedStartUpdate } from './startUpdate';
|
|
40
46
|
import { Arguments } from './util';
|
|
41
47
|
|
|
@@ -117,12 +123,13 @@ export function readButDoNotEvaluate<
|
|
|
117
123
|
}
|
|
118
124
|
}
|
|
119
125
|
|
|
120
|
-
export type
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
+
export type ReadDataResultSuccess<Data> = {
|
|
127
|
+
readonly kind: 'Success';
|
|
128
|
+
readonly data: Data;
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
export type ReadDataResult<Data> =
|
|
132
|
+
| ReadDataResultSuccess<Data>
|
|
126
133
|
| {
|
|
127
134
|
readonly kind: 'MissingData';
|
|
128
135
|
readonly reason: string;
|
|
@@ -134,12 +141,12 @@ function readData<TReadFromStore>(
|
|
|
134
141
|
environment: IsographEnvironment,
|
|
135
142
|
ast: ReaderAst<TReadFromStore>,
|
|
136
143
|
root: Link,
|
|
137
|
-
variables:
|
|
144
|
+
variables: Variables,
|
|
138
145
|
nestedRefetchQueries: RefetchQueryNormalizationArtifactWrapper[],
|
|
139
146
|
networkRequest: PromiseWrapper<void, any>,
|
|
140
147
|
networkRequestOptions: NetworkRequestReaderOptions,
|
|
141
148
|
mutableEncounteredRecords: EncounteredIds,
|
|
142
|
-
): ReadDataResult<TReadFromStore
|
|
149
|
+
): ReadDataResult<ExtractData<TReadFromStore>> {
|
|
143
150
|
const encounteredIds = insertIfNotExists(
|
|
144
151
|
mutableEncounteredRecords,
|
|
145
152
|
root.__typename,
|
|
@@ -158,7 +165,6 @@ function readData<TReadFromStore>(
|
|
|
158
165
|
return {
|
|
159
166
|
kind: 'Success',
|
|
160
167
|
data: null as any,
|
|
161
|
-
encounteredRecords: mutableEncounteredRecords,
|
|
162
168
|
};
|
|
163
169
|
}
|
|
164
170
|
|
|
@@ -167,19 +173,12 @@ function readData<TReadFromStore>(
|
|
|
167
173
|
for (const field of ast) {
|
|
168
174
|
switch (field.kind) {
|
|
169
175
|
case 'Scalar': {
|
|
170
|
-
const
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
if (value === undefined) {
|
|
175
|
-
return {
|
|
176
|
-
kind: 'MissingData',
|
|
177
|
-
reason:
|
|
178
|
-
'No value for ' + storeRecordName + ' on root ' + root.__link,
|
|
179
|
-
recordLink: root,
|
|
180
|
-
};
|
|
176
|
+
const data = readScalarFieldData(field, storeRecord, root, variables);
|
|
177
|
+
|
|
178
|
+
if (data.kind === 'MissingData') {
|
|
179
|
+
return data;
|
|
181
180
|
}
|
|
182
|
-
target[field.alias ?? field.fieldName] =
|
|
181
|
+
target[field.alias ?? field.fieldName] = data.data;
|
|
183
182
|
break;
|
|
184
183
|
}
|
|
185
184
|
case 'Link': {
|
|
@@ -187,246 +186,46 @@ function readData<TReadFromStore>(
|
|
|
187
186
|
break;
|
|
188
187
|
}
|
|
189
188
|
case 'Linked': {
|
|
190
|
-
const
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
reason:
|
|
200
|
-
'No link for ' +
|
|
201
|
-
storeRecordName +
|
|
202
|
-
' on root ' +
|
|
203
|
-
root.__link +
|
|
204
|
-
'. Link is ' +
|
|
205
|
-
JSON.stringify(item),
|
|
206
|
-
recordLink: root,
|
|
207
|
-
};
|
|
208
|
-
} else if (link === null) {
|
|
209
|
-
results.push(null);
|
|
210
|
-
continue;
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
const result = readData(
|
|
189
|
+
const data = readLinkedFieldData(
|
|
190
|
+
environment,
|
|
191
|
+
field,
|
|
192
|
+
storeRecord,
|
|
193
|
+
root,
|
|
194
|
+
variables,
|
|
195
|
+
networkRequest,
|
|
196
|
+
(ast, root) =>
|
|
197
|
+
readData(
|
|
214
198
|
environment,
|
|
215
|
-
|
|
216
|
-
|
|
199
|
+
ast,
|
|
200
|
+
root,
|
|
217
201
|
variables,
|
|
218
202
|
nestedRefetchQueries,
|
|
219
203
|
networkRequest,
|
|
220
204
|
networkRequestOptions,
|
|
221
205
|
mutableEncounteredRecords,
|
|
222
|
-
);
|
|
223
|
-
if (result.kind === 'MissingData') {
|
|
224
|
-
return {
|
|
225
|
-
kind: 'MissingData',
|
|
226
|
-
reason:
|
|
227
|
-
'Missing data for ' +
|
|
228
|
-
storeRecordName +
|
|
229
|
-
' on root ' +
|
|
230
|
-
root.__link +
|
|
231
|
-
'. Link is ' +
|
|
232
|
-
JSON.stringify(item),
|
|
233
|
-
nestedReason: result,
|
|
234
|
-
recordLink: result.recordLink,
|
|
235
|
-
};
|
|
236
|
-
}
|
|
237
|
-
results.push(result.data);
|
|
238
|
-
}
|
|
239
|
-
target[field.alias ?? field.fieldName] = results;
|
|
240
|
-
break;
|
|
241
|
-
}
|
|
242
|
-
let link = assertLink(value);
|
|
243
|
-
|
|
244
|
-
if (field.condition) {
|
|
245
|
-
const data = readData(
|
|
246
|
-
environment,
|
|
247
|
-
field.condition.readerAst,
|
|
248
|
-
root,
|
|
249
|
-
variables,
|
|
250
|
-
nestedRefetchQueries,
|
|
251
|
-
networkRequest,
|
|
252
|
-
networkRequestOptions,
|
|
253
|
-
mutableEncounteredRecords,
|
|
254
|
-
);
|
|
255
|
-
if (data.kind === 'MissingData') {
|
|
256
|
-
return {
|
|
257
|
-
kind: 'MissingData',
|
|
258
|
-
reason:
|
|
259
|
-
'Missing data for ' +
|
|
260
|
-
storeRecordName +
|
|
261
|
-
' on root ' +
|
|
262
|
-
root.__link,
|
|
263
|
-
nestedReason: data,
|
|
264
|
-
recordLink: data.recordLink,
|
|
265
|
-
};
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
const readerWithRefetchQueries = {
|
|
269
|
-
kind: 'ReaderWithRefetchQueries',
|
|
270
|
-
readerArtifact: field.condition,
|
|
271
|
-
// TODO this is wrong
|
|
272
|
-
// should map field.condition.usedRefetchQueries
|
|
273
|
-
// but it doesn't exist
|
|
274
|
-
nestedRefetchQueries: [],
|
|
275
|
-
} satisfies ReaderWithRefetchQueries<any, any>;
|
|
276
|
-
|
|
277
|
-
const fragment = {
|
|
278
|
-
kind: 'FragmentReference',
|
|
279
|
-
readerWithRefetchQueries: wrapResolvedValue(
|
|
280
|
-
readerWithRefetchQueries,
|
|
281
206
|
),
|
|
282
|
-
root,
|
|
283
|
-
variables: generateChildVariableMap(
|
|
284
|
-
variables,
|
|
285
|
-
// TODO this is wrong
|
|
286
|
-
// should use field.condition.variables
|
|
287
|
-
// but it doesn't exist
|
|
288
|
-
[],
|
|
289
|
-
),
|
|
290
|
-
networkRequest,
|
|
291
|
-
} satisfies FragmentReference<any, any>;
|
|
292
|
-
|
|
293
|
-
const condition = field.condition.resolver({
|
|
294
|
-
data: data.data,
|
|
295
|
-
parameters: {},
|
|
296
|
-
...(field.condition.hasUpdatable
|
|
297
|
-
? {
|
|
298
|
-
startUpdate: getOrCreateCachedStartUpdate(
|
|
299
|
-
environment,
|
|
300
|
-
fragment,
|
|
301
|
-
readerWithRefetchQueries.readerArtifact.fieldName,
|
|
302
|
-
),
|
|
303
|
-
}
|
|
304
|
-
: undefined),
|
|
305
|
-
});
|
|
306
|
-
if (condition === true) {
|
|
307
|
-
link = root;
|
|
308
|
-
} else if (condition === false) {
|
|
309
|
-
link = null;
|
|
310
|
-
} else {
|
|
311
|
-
link = condition;
|
|
312
|
-
}
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
if (link === undefined) {
|
|
316
|
-
// TODO make this configurable, and also generated and derived from the schema
|
|
317
|
-
const missingFieldHandler = environment.missingFieldHandler;
|
|
318
|
-
|
|
319
|
-
const altLink = missingFieldHandler?.(
|
|
320
|
-
storeRecord,
|
|
321
|
-
root,
|
|
322
|
-
field.fieldName,
|
|
323
|
-
field.arguments,
|
|
324
|
-
variables,
|
|
325
|
-
);
|
|
326
|
-
logMessage(environment, {
|
|
327
|
-
kind: 'MissingFieldHandlerCalled',
|
|
328
|
-
root,
|
|
329
|
-
storeRecord,
|
|
330
|
-
fieldName: field.fieldName,
|
|
331
|
-
arguments: field.arguments,
|
|
332
|
-
variables,
|
|
333
|
-
});
|
|
334
|
-
|
|
335
|
-
if (altLink === undefined) {
|
|
336
|
-
return {
|
|
337
|
-
kind: 'MissingData',
|
|
338
|
-
reason:
|
|
339
|
-
'No link for ' +
|
|
340
|
-
storeRecordName +
|
|
341
|
-
' on root ' +
|
|
342
|
-
root.__link +
|
|
343
|
-
'. Link is ' +
|
|
344
|
-
JSON.stringify(value),
|
|
345
|
-
recordLink: root,
|
|
346
|
-
};
|
|
347
|
-
} else {
|
|
348
|
-
link = altLink;
|
|
349
|
-
}
|
|
350
|
-
} else if (link === null) {
|
|
351
|
-
target[field.alias ?? field.fieldName] = null;
|
|
352
|
-
break;
|
|
353
|
-
}
|
|
354
|
-
const targetId = link;
|
|
355
|
-
const data = readData(
|
|
356
|
-
environment,
|
|
357
|
-
field.selections,
|
|
358
|
-
targetId,
|
|
359
|
-
variables,
|
|
360
|
-
nestedRefetchQueries,
|
|
361
|
-
networkRequest,
|
|
362
|
-
networkRequestOptions,
|
|
363
|
-
mutableEncounteredRecords,
|
|
364
207
|
);
|
|
365
208
|
if (data.kind === 'MissingData') {
|
|
366
|
-
return
|
|
367
|
-
kind: 'MissingData',
|
|
368
|
-
reason:
|
|
369
|
-
'Missing data for ' + storeRecordName + ' on root ' + root.__link,
|
|
370
|
-
nestedReason: data,
|
|
371
|
-
recordLink: data.recordLink,
|
|
372
|
-
};
|
|
209
|
+
return data;
|
|
373
210
|
}
|
|
374
211
|
target[field.alias ?? field.fieldName] = data.data;
|
|
375
212
|
break;
|
|
376
213
|
}
|
|
377
214
|
case 'ImperativelyLoadedField': {
|
|
378
|
-
|
|
379
|
-
// id field).
|
|
380
|
-
const data = readData(
|
|
215
|
+
const data = readImperativelyLoadedField(
|
|
381
216
|
environment,
|
|
382
|
-
field
|
|
217
|
+
field,
|
|
383
218
|
root,
|
|
384
219
|
variables,
|
|
385
|
-
|
|
386
|
-
[],
|
|
387
|
-
// This is probably indicative of the fact that we are doing redundant checks
|
|
388
|
-
// on the status of this network request...
|
|
220
|
+
nestedRefetchQueries,
|
|
389
221
|
networkRequest,
|
|
390
222
|
networkRequestOptions,
|
|
391
223
|
mutableEncounteredRecords,
|
|
392
224
|
);
|
|
393
225
|
if (data.kind === 'MissingData') {
|
|
394
|
-
return
|
|
395
|
-
kind: 'MissingData',
|
|
396
|
-
reason:
|
|
397
|
-
'Missing data for ' + field.alias + ' on root ' + root.__link,
|
|
398
|
-
nestedReason: data,
|
|
399
|
-
recordLink: data.recordLink,
|
|
400
|
-
};
|
|
401
|
-
} else {
|
|
402
|
-
const refetchQueryIndex = field.refetchQuery;
|
|
403
|
-
const refetchQuery = nestedRefetchQueries[refetchQueryIndex];
|
|
404
|
-
if (refetchQuery == null) {
|
|
405
|
-
throw new Error(
|
|
406
|
-
'refetchQuery is null in RefetchField. This is indicative of a bug in Isograph.',
|
|
407
|
-
);
|
|
408
|
-
}
|
|
409
|
-
const refetchQueryArtifact = refetchQuery.artifact;
|
|
410
|
-
const allowedVariables = refetchQuery.allowedVariables;
|
|
411
|
-
|
|
412
|
-
// Second, we allow the user to call the resolver, which will ultimately
|
|
413
|
-
// use the resolver reader AST to get the resolver parameters.
|
|
414
|
-
target[field.alias] = (args: any) => [
|
|
415
|
-
// Stable id
|
|
416
|
-
root.__link + '__' + field.name,
|
|
417
|
-
// Fetcher
|
|
418
|
-
field.refetchReaderArtifact.resolver(
|
|
419
|
-
environment,
|
|
420
|
-
refetchQueryArtifact,
|
|
421
|
-
data.data,
|
|
422
|
-
filterVariables({ ...args, ...variables }, allowedVariables),
|
|
423
|
-
root,
|
|
424
|
-
// TODO these params should be removed
|
|
425
|
-
null,
|
|
426
|
-
[],
|
|
427
|
-
),
|
|
428
|
-
];
|
|
226
|
+
return data;
|
|
429
227
|
}
|
|
228
|
+
target[field.alias] = data.data;
|
|
430
229
|
break;
|
|
431
230
|
}
|
|
432
231
|
case 'Resolver': {
|
|
@@ -690,7 +489,6 @@ function readData<TReadFromStore>(
|
|
|
690
489
|
return {
|
|
691
490
|
kind: 'Success',
|
|
692
491
|
data: target as any,
|
|
693
|
-
encounteredRecords: mutableEncounteredRecords,
|
|
694
492
|
};
|
|
695
493
|
}
|
|
696
494
|
|
|
@@ -776,6 +574,197 @@ function writeQueryArgsToVariables(
|
|
|
776
574
|
}
|
|
777
575
|
}
|
|
778
576
|
|
|
577
|
+
export function readScalarFieldData(
|
|
578
|
+
field: ReaderScalarField,
|
|
579
|
+
storeRecord: StoreRecord,
|
|
580
|
+
root: Link,
|
|
581
|
+
variables: Variables,
|
|
582
|
+
): ReadDataResult<string | number | boolean | Link | DataTypeValue[] | null> {
|
|
583
|
+
const storeRecordName = getParentRecordKey(field, variables);
|
|
584
|
+
const value = storeRecord[storeRecordName];
|
|
585
|
+
// TODO consider making scalars into discriminated unions. This probably has
|
|
586
|
+
// to happen for when we handle errors.
|
|
587
|
+
if (value === undefined) {
|
|
588
|
+
return {
|
|
589
|
+
kind: 'MissingData',
|
|
590
|
+
reason: 'No value for ' + storeRecordName + ' on root ' + root.__link,
|
|
591
|
+
recordLink: root,
|
|
592
|
+
};
|
|
593
|
+
}
|
|
594
|
+
return { kind: 'Success', data: value };
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
export function readLinkedFieldData(
|
|
598
|
+
environment: IsographEnvironment,
|
|
599
|
+
field: ReaderLinkedField,
|
|
600
|
+
storeRecord: StoreRecord,
|
|
601
|
+
root: Link,
|
|
602
|
+
variables: Variables,
|
|
603
|
+
networkRequest: PromiseWrapper<void, any>,
|
|
604
|
+
|
|
605
|
+
readData: <TReadFromStore>(
|
|
606
|
+
ast: ReaderAst<TReadFromStore>,
|
|
607
|
+
root: Link,
|
|
608
|
+
) => ReadDataResult<object>,
|
|
609
|
+
): ReadDataResult<unknown> {
|
|
610
|
+
const storeRecordName = getParentRecordKey(field, variables);
|
|
611
|
+
const value = storeRecord[storeRecordName];
|
|
612
|
+
if (Array.isArray(value)) {
|
|
613
|
+
const results = [];
|
|
614
|
+
for (const item of value) {
|
|
615
|
+
const link = assertLink(item);
|
|
616
|
+
if (link === undefined) {
|
|
617
|
+
return {
|
|
618
|
+
kind: 'MissingData',
|
|
619
|
+
reason:
|
|
620
|
+
'No link for ' +
|
|
621
|
+
storeRecordName +
|
|
622
|
+
' on root ' +
|
|
623
|
+
root.__link +
|
|
624
|
+
'. Link is ' +
|
|
625
|
+
JSON.stringify(item),
|
|
626
|
+
recordLink: root,
|
|
627
|
+
};
|
|
628
|
+
} else if (link === null) {
|
|
629
|
+
results.push(null);
|
|
630
|
+
continue;
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
const result = readData(field.selections, link);
|
|
634
|
+
if (result.kind === 'MissingData') {
|
|
635
|
+
return {
|
|
636
|
+
kind: 'MissingData',
|
|
637
|
+
reason:
|
|
638
|
+
'Missing data for ' +
|
|
639
|
+
storeRecordName +
|
|
640
|
+
' on root ' +
|
|
641
|
+
root.__link +
|
|
642
|
+
'. Link is ' +
|
|
643
|
+
JSON.stringify(item),
|
|
644
|
+
nestedReason: result,
|
|
645
|
+
recordLink: result.recordLink,
|
|
646
|
+
};
|
|
647
|
+
}
|
|
648
|
+
results.push(result.data);
|
|
649
|
+
}
|
|
650
|
+
return {
|
|
651
|
+
kind: 'Success',
|
|
652
|
+
data: results,
|
|
653
|
+
};
|
|
654
|
+
}
|
|
655
|
+
let link = assertLink(value);
|
|
656
|
+
|
|
657
|
+
if (field.condition) {
|
|
658
|
+
const data = readData(field.condition.readerAst, root);
|
|
659
|
+
if (data.kind === 'MissingData') {
|
|
660
|
+
return {
|
|
661
|
+
kind: 'MissingData',
|
|
662
|
+
reason:
|
|
663
|
+
'Missing data for ' + storeRecordName + ' on root ' + root.__link,
|
|
664
|
+
nestedReason: data,
|
|
665
|
+
recordLink: data.recordLink,
|
|
666
|
+
};
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
const readerWithRefetchQueries = {
|
|
670
|
+
kind: 'ReaderWithRefetchQueries',
|
|
671
|
+
readerArtifact: field.condition,
|
|
672
|
+
// TODO this is wrong
|
|
673
|
+
// should map field.condition.usedRefetchQueries
|
|
674
|
+
// but it doesn't exist
|
|
675
|
+
nestedRefetchQueries: [],
|
|
676
|
+
} satisfies ReaderWithRefetchQueries<any, any>;
|
|
677
|
+
|
|
678
|
+
const fragment = {
|
|
679
|
+
kind: 'FragmentReference',
|
|
680
|
+
readerWithRefetchQueries: wrapResolvedValue(readerWithRefetchQueries),
|
|
681
|
+
root,
|
|
682
|
+
variables: generateChildVariableMap(
|
|
683
|
+
variables,
|
|
684
|
+
// TODO this is wrong
|
|
685
|
+
// should use field.condition.variables
|
|
686
|
+
// but it doesn't exist
|
|
687
|
+
[],
|
|
688
|
+
),
|
|
689
|
+
networkRequest,
|
|
690
|
+
} satisfies FragmentReference<any, any>;
|
|
691
|
+
|
|
692
|
+
const condition = field.condition.resolver({
|
|
693
|
+
data: data.data,
|
|
694
|
+
parameters: {},
|
|
695
|
+
...(field.condition.hasUpdatable
|
|
696
|
+
? {
|
|
697
|
+
startUpdate: getOrCreateCachedStartUpdate(
|
|
698
|
+
environment,
|
|
699
|
+
fragment,
|
|
700
|
+
readerWithRefetchQueries.readerArtifact.fieldName,
|
|
701
|
+
),
|
|
702
|
+
}
|
|
703
|
+
: undefined),
|
|
704
|
+
});
|
|
705
|
+
if (condition === true) {
|
|
706
|
+
link = root;
|
|
707
|
+
} else if (condition === false) {
|
|
708
|
+
link = null;
|
|
709
|
+
} else {
|
|
710
|
+
link = condition;
|
|
711
|
+
}
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
if (link === undefined) {
|
|
715
|
+
// TODO make this configurable, and also generated and derived from the schema
|
|
716
|
+
const missingFieldHandler = environment.missingFieldHandler;
|
|
717
|
+
|
|
718
|
+
const altLink = missingFieldHandler?.(
|
|
719
|
+
storeRecord,
|
|
720
|
+
root,
|
|
721
|
+
field.fieldName,
|
|
722
|
+
field.arguments,
|
|
723
|
+
variables,
|
|
724
|
+
);
|
|
725
|
+
logMessage(environment, {
|
|
726
|
+
kind: 'MissingFieldHandlerCalled',
|
|
727
|
+
root,
|
|
728
|
+
storeRecord,
|
|
729
|
+
fieldName: field.fieldName,
|
|
730
|
+
arguments: field.arguments,
|
|
731
|
+
variables,
|
|
732
|
+
});
|
|
733
|
+
|
|
734
|
+
if (altLink === undefined) {
|
|
735
|
+
return {
|
|
736
|
+
kind: 'MissingData',
|
|
737
|
+
reason:
|
|
738
|
+
'No link for ' +
|
|
739
|
+
storeRecordName +
|
|
740
|
+
' on root ' +
|
|
741
|
+
root.__link +
|
|
742
|
+
'. Link is ' +
|
|
743
|
+
JSON.stringify(value),
|
|
744
|
+
recordLink: root,
|
|
745
|
+
};
|
|
746
|
+
} else {
|
|
747
|
+
link = altLink;
|
|
748
|
+
}
|
|
749
|
+
} else if (link === null) {
|
|
750
|
+
return {
|
|
751
|
+
kind: 'Success',
|
|
752
|
+
data: null,
|
|
753
|
+
};
|
|
754
|
+
}
|
|
755
|
+
const targetId = link;
|
|
756
|
+
const data = readData(field.selections, targetId);
|
|
757
|
+
if (data.kind === 'MissingData') {
|
|
758
|
+
return {
|
|
759
|
+
kind: 'MissingData',
|
|
760
|
+
reason: 'Missing data for ' + storeRecordName + ' on root ' + root.__link,
|
|
761
|
+
nestedReason: data,
|
|
762
|
+
recordLink: data.recordLink,
|
|
763
|
+
};
|
|
764
|
+
}
|
|
765
|
+
return data;
|
|
766
|
+
}
|
|
767
|
+
|
|
779
768
|
export type NetworkRequestReaderOptions = {
|
|
780
769
|
suspendIfInFlight: boolean;
|
|
781
770
|
throwOnNetworkError: boolean;
|
|
@@ -804,3 +793,69 @@ function stableStringifyArgs(args: object) {
|
|
|
804
793
|
}
|
|
805
794
|
return s;
|
|
806
795
|
}
|
|
796
|
+
|
|
797
|
+
export function readImperativelyLoadedField(
|
|
798
|
+
environment: IsographEnvironment,
|
|
799
|
+
field: ReaderImperativelyLoadedField,
|
|
800
|
+
root: Link,
|
|
801
|
+
variables: Variables,
|
|
802
|
+
nestedRefetchQueries: RefetchQueryNormalizationArtifactWrapper[],
|
|
803
|
+
networkRequest: PromiseWrapper<void, any>,
|
|
804
|
+
networkRequestOptions: NetworkRequestReaderOptions,
|
|
805
|
+
mutableEncounteredRecords: EncounteredIds,
|
|
806
|
+
): ReadDataResult<unknown> {
|
|
807
|
+
// First, we read the data using the refetch reader AST (i.e. read out the
|
|
808
|
+
// id field).
|
|
809
|
+
const data = readData(
|
|
810
|
+
environment,
|
|
811
|
+
field.refetchReaderArtifact.readerAst,
|
|
812
|
+
root,
|
|
813
|
+
variables,
|
|
814
|
+
// Refetch fields just read the id, and don't need refetch query artifacts
|
|
815
|
+
[],
|
|
816
|
+
// This is probably indicative of the fact that we are doing redundant checks
|
|
817
|
+
// on the status of this network request...
|
|
818
|
+
networkRequest,
|
|
819
|
+
networkRequestOptions,
|
|
820
|
+
mutableEncounteredRecords,
|
|
821
|
+
);
|
|
822
|
+
if (data.kind === 'MissingData') {
|
|
823
|
+
return {
|
|
824
|
+
kind: 'MissingData',
|
|
825
|
+
reason: 'Missing data for ' + field.alias + ' on root ' + root.__link,
|
|
826
|
+
nestedReason: data,
|
|
827
|
+
recordLink: data.recordLink,
|
|
828
|
+
};
|
|
829
|
+
} else {
|
|
830
|
+
const refetchQueryIndex = field.refetchQuery;
|
|
831
|
+
const refetchQuery = nestedRefetchQueries[refetchQueryIndex];
|
|
832
|
+
if (refetchQuery == null) {
|
|
833
|
+
throw new Error(
|
|
834
|
+
'refetchQuery is null in RefetchField. This is indicative of a bug in Isograph.',
|
|
835
|
+
);
|
|
836
|
+
}
|
|
837
|
+
const refetchQueryArtifact = refetchQuery.artifact;
|
|
838
|
+
const allowedVariables = refetchQuery.allowedVariables;
|
|
839
|
+
|
|
840
|
+
// Second, we allow the user to call the resolver, which will ultimately
|
|
841
|
+
// use the resolver reader AST to get the resolver parameters.
|
|
842
|
+
return {
|
|
843
|
+
kind: 'Success',
|
|
844
|
+
data: (args: any) => [
|
|
845
|
+
// Stable id
|
|
846
|
+
root.__link + '__' + field.name,
|
|
847
|
+
// Fetcher
|
|
848
|
+
field.refetchReaderArtifact.resolver(
|
|
849
|
+
environment,
|
|
850
|
+
refetchQueryArtifact,
|
|
851
|
+
data.data,
|
|
852
|
+
filterVariables({ ...args, ...variables }, allowedVariables),
|
|
853
|
+
root,
|
|
854
|
+
// TODO these params should be removed
|
|
855
|
+
null,
|
|
856
|
+
[],
|
|
857
|
+
),
|
|
858
|
+
],
|
|
859
|
+
};
|
|
860
|
+
}
|
|
861
|
+
}
|