@isograph/react 0.3.1 → 0.4.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-libs.log +5 -0
- package/dist/core/FragmentReference.d.ts +5 -5
- package/dist/core/FragmentReference.d.ts.map +1 -1
- package/dist/core/IsographEnvironment.d.ts +15 -10
- package/dist/core/IsographEnvironment.d.ts.map +1 -1
- package/dist/core/PromiseWrapper.d.ts +4 -4
- package/dist/core/PromiseWrapper.d.ts.map +1 -1
- package/dist/core/PromiseWrapper.js +2 -9
- package/dist/core/areEqualWithDeepComparison.d.ts +1 -3
- package/dist/core/areEqualWithDeepComparison.d.ts.map +1 -1
- package/dist/core/areEqualWithDeepComparison.js +0 -2
- package/dist/core/brand.d.ts +2 -0
- package/dist/core/brand.d.ts.map +1 -0
- package/dist/core/brand.js +2 -0
- package/dist/core/cache.d.ts +7 -6
- package/dist/core/cache.d.ts.map +1 -1
- package/dist/core/cache.js +57 -36
- package/dist/core/check.d.ts +3 -3
- package/dist/core/check.d.ts.map +1 -1
- package/dist/core/componentCache.d.ts.map +1 -1
- package/dist/core/componentCache.js +3 -2
- package/dist/core/entrypoint.d.ts +20 -2
- package/dist/core/entrypoint.d.ts.map +1 -1
- package/dist/core/garbageCollection.d.ts +2 -2
- package/dist/core/garbageCollection.d.ts.map +1 -1
- package/dist/core/logging.d.ts +13 -4
- package/dist/core/logging.d.ts.map +1 -1
- package/dist/core/makeNetworkRequest.d.ts +3 -3
- package/dist/core/makeNetworkRequest.d.ts.map +1 -1
- package/dist/core/makeNetworkRequest.js +15 -15
- package/dist/core/read.d.ts +8 -8
- package/dist/core/read.d.ts.map +1 -1
- package/dist/core/read.js +98 -29
- package/dist/core/reader.d.ts +12 -8
- package/dist/core/reader.d.ts.map +1 -1
- package/dist/core/startUpdate.d.ts +7 -4
- package/dist/core/startUpdate.d.ts.map +1 -1
- package/dist/core/startUpdate.js +153 -5
- package/dist/core/util.d.ts +2 -1
- package/dist/core/util.d.ts.map +1 -1
- package/dist/index.d.ts +8 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -1
- package/dist/loadable-hooks/useConnectionSpecPagination.d.ts.map +1 -1
- package/dist/loadable-hooks/useConnectionSpecPagination.js +1 -1
- package/dist/loadable-hooks/useImperativeExposedMutationField.d.ts +1 -1
- package/dist/loadable-hooks/useImperativeExposedMutationField.d.ts.map +1 -1
- package/dist/loadable-hooks/useImperativeExposedMutationField.js +1 -1
- package/dist/loadable-hooks/useImperativeLoadableField.d.ts +1 -1
- package/dist/loadable-hooks/useImperativeLoadableField.d.ts.map +1 -1
- package/dist/loadable-hooks/useImperativeLoadableField.js +1 -1
- package/dist/loadable-hooks/useSkipLimitPagination.d.ts.map +1 -1
- package/dist/loadable-hooks/useSkipLimitPagination.js +1 -1
- package/dist/react/FragmentReader.d.ts +7 -13
- package/dist/react/FragmentReader.d.ts.map +1 -1
- package/dist/react/FragmentReader.js +3 -30
- package/dist/react/FragmentRenderer.d.ts +15 -0
- package/dist/react/FragmentRenderer.d.ts.map +1 -0
- package/dist/react/FragmentRenderer.js +35 -0
- package/dist/react/LoadableFieldReader.d.ts +12 -0
- package/dist/react/LoadableFieldReader.d.ts.map +1 -0
- package/dist/react/LoadableFieldReader.js +10 -0
- package/dist/react/LoadableFieldRenderer.d.ts +13 -0
- package/dist/react/LoadableFieldRenderer.d.ts.map +1 -0
- package/dist/react/LoadableFieldRenderer.js +37 -0
- package/dist/react/useImperativeReference.d.ts.map +1 -1
- package/dist/react/useImperativeReference.js +6 -6
- package/dist/react/useResult.d.ts.map +1 -1
- package/dist/react/useResult.js +1 -1
- package/package.json +4 -5
- package/src/core/FragmentReference.ts +16 -7
- package/src/core/IsographEnvironment.ts +20 -10
- package/src/core/PromiseWrapper.ts +13 -16
- package/src/core/areEqualWithDeepComparison.ts +5 -5
- package/src/core/brand.ts +18 -0
- package/src/core/cache.ts +74 -51
- package/src/core/check.ts +4 -4
- package/src/core/componentCache.ts +7 -2
- package/src/core/entrypoint.ts +32 -5
- package/src/core/garbageCollection.ts +3 -3
- package/src/core/logging.ts +16 -4
- package/src/core/makeNetworkRequest.ts +48 -23
- package/src/core/read.ts +153 -48
- package/src/core/reader.ts +11 -7
- package/src/core/startUpdate.ts +313 -7
- package/src/core/util.ts +4 -2
- package/src/index.ts +11 -3
- package/src/loadable-hooks/useConnectionSpecPagination.ts +1 -0
- package/src/loadable-hooks/useImperativeExposedMutationField.ts +2 -2
- package/src/loadable-hooks/useImperativeLoadableField.ts +2 -2
- package/src/loadable-hooks/useSkipLimitPagination.ts +1 -0
- package/src/react/FragmentReader.tsx +23 -39
- package/src/react/FragmentRenderer.tsx +46 -0
- package/src/react/LoadableFieldReader.tsx +40 -0
- package/src/react/LoadableFieldRenderer.tsx +41 -0
- package/src/react/useImperativeReference.ts +9 -8
- package/src/react/useResult.ts +1 -0
- package/src/tests/__isograph/Economist/link/output_type.ts +2 -0
- package/src/tests/__isograph/Node/asEconomist/resolver_reader.ts +28 -0
- package/src/tests/__isograph/Node/link/output_type.ts +3 -0
- package/src/tests/__isograph/Query/linkedUpdate/entrypoint.ts +31 -0
- package/src/tests/__isograph/Query/linkedUpdate/normalization_ast.ts +95 -0
- package/src/tests/__isograph/Query/linkedUpdate/output_type.ts +3 -0
- package/src/tests/__isograph/Query/linkedUpdate/param_type.ts +51 -0
- package/src/tests/__isograph/Query/linkedUpdate/query_text.ts +20 -0
- package/src/tests/__isograph/Query/linkedUpdate/resolver_reader.ts +93 -0
- package/src/tests/__isograph/Query/meName/entrypoint.ts +4 -1
- package/src/tests/__isograph/Query/meName/query_text.ts +1 -1
- package/src/tests/__isograph/Query/meName/resolver_reader.ts +1 -0
- package/src/tests/__isograph/Query/meNameSuccessor/entrypoint.ts +4 -1
- package/src/tests/__isograph/Query/meNameSuccessor/query_text.ts +1 -1
- package/src/tests/__isograph/Query/meNameSuccessor/resolver_reader.ts +3 -0
- package/src/tests/__isograph/Query/nodeField/entrypoint.ts +4 -1
- package/src/tests/__isograph/Query/nodeField/query_text.ts +1 -1
- package/src/tests/__isograph/Query/nodeField/resolver_reader.ts +1 -0
- package/src/tests/__isograph/Query/startUpdate/entrypoint.ts +31 -0
- package/src/tests/__isograph/Query/startUpdate/normalization_ast.ts +51 -0
- package/src/tests/__isograph/Query/startUpdate/output_type.ts +3 -0
- package/src/tests/__isograph/Query/startUpdate/param_type.ts +26 -0
- package/src/tests/__isograph/Query/startUpdate/parameters_type.ts +3 -0
- package/src/tests/__isograph/Query/startUpdate/query_text.ts +11 -0
- package/src/tests/__isograph/Query/startUpdate/resolver_reader.ts +55 -0
- package/src/tests/__isograph/Query/subquery/entrypoint.ts +4 -1
- package/src/tests/__isograph/Query/subquery/query_text.ts +1 -1
- package/src/tests/__isograph/Query/subquery/resolver_reader.ts +2 -0
- package/src/tests/__isograph/iso.ts +21 -1
- package/src/tests/__isograph/tsconfig.json +8 -0
- package/src/tests/normalizeData.test.ts +0 -1
- package/src/tests/startUpdate.test.ts +205 -0
- package/.turbo/turbo-compile-typescript.log +0 -4
package/src/core/startUpdate.ts
CHANGED
|
@@ -1,28 +1,334 @@
|
|
|
1
|
+
import {
|
|
2
|
+
callSubscriptions,
|
|
3
|
+
getParentRecordKey,
|
|
4
|
+
insertEmptySetIfMissing,
|
|
5
|
+
type EncounteredIds,
|
|
6
|
+
} from './cache';
|
|
7
|
+
import type { RefetchQueryNormalizationArtifactWrapper } from './entrypoint';
|
|
1
8
|
import {
|
|
2
9
|
stableIdForFragmentReference,
|
|
10
|
+
type ExtractParameters,
|
|
3
11
|
type ExtractStartUpdate,
|
|
12
|
+
type ExtractUpdatableData,
|
|
4
13
|
type FragmentReference,
|
|
5
14
|
type UnknownTReadFromStore,
|
|
6
15
|
} from './FragmentReference';
|
|
7
|
-
import
|
|
16
|
+
import {
|
|
17
|
+
assertLink,
|
|
18
|
+
type IsographEnvironment,
|
|
19
|
+
type StoreLink,
|
|
20
|
+
} from './IsographEnvironment';
|
|
21
|
+
import { logMessage } from './logging';
|
|
22
|
+
import { readPromise, type PromiseWrapper } from './PromiseWrapper';
|
|
23
|
+
import {
|
|
24
|
+
readImperativelyLoadedField,
|
|
25
|
+
readLinkedFieldData,
|
|
26
|
+
readLoadablySelectedFieldData,
|
|
27
|
+
readResolverFieldData,
|
|
28
|
+
readScalarFieldData,
|
|
29
|
+
type NetworkRequestReaderOptions,
|
|
30
|
+
type ReadDataResultSuccess,
|
|
31
|
+
} from './read';
|
|
32
|
+
import type { ReaderAst } from './reader';
|
|
8
33
|
|
|
9
34
|
export function getOrCreateCachedStartUpdate<
|
|
10
35
|
TReadFromStore extends UnknownTReadFromStore,
|
|
11
36
|
>(
|
|
12
37
|
environment: IsographEnvironment,
|
|
13
|
-
fragmentReference: FragmentReference<TReadFromStore,
|
|
38
|
+
fragmentReference: FragmentReference<TReadFromStore, unknown>,
|
|
14
39
|
eagerResolverName: string,
|
|
40
|
+
networkRequestOptions: NetworkRequestReaderOptions,
|
|
15
41
|
): ExtractStartUpdate<TReadFromStore> {
|
|
16
42
|
return (environment.eagerReaderCache[
|
|
17
43
|
stableIdForFragmentReference(fragmentReference, eagerResolverName)
|
|
18
|
-
] ??= createStartUpdate(
|
|
44
|
+
] ??= createStartUpdate(
|
|
45
|
+
environment,
|
|
46
|
+
fragmentReference,
|
|
47
|
+
networkRequestOptions,
|
|
48
|
+
));
|
|
19
49
|
}
|
|
20
50
|
|
|
21
51
|
export function createStartUpdate<TReadFromStore extends UnknownTReadFromStore>(
|
|
22
|
-
|
|
23
|
-
|
|
52
|
+
environment: IsographEnvironment,
|
|
53
|
+
fragmentReference: FragmentReference<TReadFromStore, unknown>,
|
|
54
|
+
networkRequestOptions: NetworkRequestReaderOptions,
|
|
24
55
|
): ExtractStartUpdate<TReadFromStore> {
|
|
25
|
-
return (
|
|
26
|
-
|
|
56
|
+
return (updater) => {
|
|
57
|
+
let mutableUpdatedIds: EncounteredIds = new Map();
|
|
58
|
+
|
|
59
|
+
let data = createUpdatableProxy(
|
|
60
|
+
environment,
|
|
61
|
+
fragmentReference,
|
|
62
|
+
networkRequestOptions,
|
|
63
|
+
mutableUpdatedIds,
|
|
64
|
+
);
|
|
65
|
+
|
|
66
|
+
try {
|
|
67
|
+
updater(data);
|
|
68
|
+
} catch (e) {
|
|
69
|
+
logMessage(environment, () => ({
|
|
70
|
+
kind: 'StartUpdateError',
|
|
71
|
+
error: e,
|
|
72
|
+
}));
|
|
73
|
+
throw e;
|
|
74
|
+
} finally {
|
|
75
|
+
logMessage(environment, () => ({
|
|
76
|
+
kind: 'StartUpdateComplete',
|
|
77
|
+
updatedIds: mutableUpdatedIds,
|
|
78
|
+
}));
|
|
79
|
+
callSubscriptions(environment, mutableUpdatedIds);
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export function createUpdatableProxy<
|
|
85
|
+
TReadFromStore extends UnknownTReadFromStore,
|
|
86
|
+
>(
|
|
87
|
+
environment: IsographEnvironment,
|
|
88
|
+
fragmentReference: FragmentReference<TReadFromStore, unknown>,
|
|
89
|
+
networkRequestOptions: NetworkRequestReaderOptions,
|
|
90
|
+
mutableUpdatedIds: EncounteredIds,
|
|
91
|
+
): ExtractUpdatableData<TReadFromStore> {
|
|
92
|
+
const readerWithRefetchQueries = readPromise(
|
|
93
|
+
fragmentReference.readerWithRefetchQueries,
|
|
94
|
+
);
|
|
95
|
+
|
|
96
|
+
return readUpdatableData(
|
|
97
|
+
environment,
|
|
98
|
+
readerWithRefetchQueries.readerArtifact.readerAst,
|
|
99
|
+
fragmentReference.root,
|
|
100
|
+
fragmentReference.variables ?? {},
|
|
101
|
+
readerWithRefetchQueries.nestedRefetchQueries,
|
|
102
|
+
fragmentReference.networkRequest,
|
|
103
|
+
networkRequestOptions,
|
|
104
|
+
{
|
|
105
|
+
lastInvalidated: 0,
|
|
106
|
+
},
|
|
107
|
+
mutableUpdatedIds,
|
|
108
|
+
).data;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
type MutableInvalidationState = {
|
|
112
|
+
lastInvalidated: number;
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
function defineCachedProperty<T>(
|
|
116
|
+
target: T,
|
|
117
|
+
property: PropertyKey,
|
|
118
|
+
mutableState: MutableInvalidationState,
|
|
119
|
+
get: () => any,
|
|
120
|
+
set?: (v: any) => void,
|
|
121
|
+
) {
|
|
122
|
+
let value:
|
|
123
|
+
| { kind: 'Set'; value: T; validatedAt: number }
|
|
124
|
+
| {
|
|
125
|
+
kind: 'NotSet';
|
|
126
|
+
} = {
|
|
127
|
+
kind: 'NotSet',
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
Object.defineProperty(target, property, {
|
|
131
|
+
configurable: false,
|
|
132
|
+
enumerable: true,
|
|
133
|
+
get: () => {
|
|
134
|
+
if (
|
|
135
|
+
value.kind === 'NotSet' ||
|
|
136
|
+
value.validatedAt < mutableState.lastInvalidated
|
|
137
|
+
) {
|
|
138
|
+
value = {
|
|
139
|
+
kind: 'Set',
|
|
140
|
+
value: get(),
|
|
141
|
+
validatedAt: mutableState.lastInvalidated,
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
return value.value;
|
|
145
|
+
},
|
|
146
|
+
...(set && {
|
|
147
|
+
set: (newValue) => {
|
|
148
|
+
set(newValue);
|
|
149
|
+
mutableState.lastInvalidated++;
|
|
150
|
+
},
|
|
151
|
+
}),
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
function readUpdatableData<TReadFromStore extends UnknownTReadFromStore>(
|
|
156
|
+
environment: IsographEnvironment,
|
|
157
|
+
ast: ReaderAst<TReadFromStore>,
|
|
158
|
+
root: StoreLink,
|
|
159
|
+
variables: ExtractParameters<TReadFromStore>,
|
|
160
|
+
nestedRefetchQueries: RefetchQueryNormalizationArtifactWrapper[],
|
|
161
|
+
networkRequest: PromiseWrapper<void, any>,
|
|
162
|
+
networkRequestOptions: NetworkRequestReaderOptions,
|
|
163
|
+
mutableState: MutableInvalidationState,
|
|
164
|
+
mutableUpdatedIds: EncounteredIds,
|
|
165
|
+
): ReadDataResultSuccess<ExtractUpdatableData<TReadFromStore>> {
|
|
166
|
+
let storeRecord = environment.store[root.__typename]?.[root.__link];
|
|
167
|
+
if (storeRecord == null) {
|
|
168
|
+
return {
|
|
169
|
+
kind: 'Success',
|
|
170
|
+
data: null as any,
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
let target: { [index: string]: any } = {};
|
|
175
|
+
|
|
176
|
+
for (const field of ast) {
|
|
177
|
+
switch (field.kind) {
|
|
178
|
+
case 'Scalar': {
|
|
179
|
+
const storeRecordName = getParentRecordKey(field, variables);
|
|
180
|
+
|
|
181
|
+
defineCachedProperty(
|
|
182
|
+
target,
|
|
183
|
+
field.alias ?? field.fieldName,
|
|
184
|
+
mutableState,
|
|
185
|
+
() => {
|
|
186
|
+
const data = readScalarFieldData(
|
|
187
|
+
field,
|
|
188
|
+
storeRecord,
|
|
189
|
+
root,
|
|
190
|
+
variables,
|
|
191
|
+
);
|
|
192
|
+
if (data.kind === 'MissingData') {
|
|
193
|
+
throw new Error(data.reason);
|
|
194
|
+
}
|
|
195
|
+
return data.data;
|
|
196
|
+
},
|
|
197
|
+
field.isUpdatable
|
|
198
|
+
? (newValue) => {
|
|
199
|
+
storeRecord[storeRecordName] = newValue;
|
|
200
|
+
const updatedIds = insertEmptySetIfMissing(
|
|
201
|
+
mutableUpdatedIds,
|
|
202
|
+
root.__typename,
|
|
203
|
+
);
|
|
204
|
+
updatedIds.add(root.__link);
|
|
205
|
+
}
|
|
206
|
+
: undefined,
|
|
207
|
+
);
|
|
208
|
+
break;
|
|
209
|
+
}
|
|
210
|
+
case 'Linked': {
|
|
211
|
+
const storeRecordName = getParentRecordKey(field, variables);
|
|
212
|
+
defineCachedProperty(
|
|
213
|
+
target,
|
|
214
|
+
field.alias ?? field.fieldName,
|
|
215
|
+
mutableState,
|
|
216
|
+
() => {
|
|
217
|
+
const data = readLinkedFieldData(
|
|
218
|
+
environment,
|
|
219
|
+
field,
|
|
220
|
+
storeRecord,
|
|
221
|
+
root,
|
|
222
|
+
variables,
|
|
223
|
+
nestedRefetchQueries,
|
|
224
|
+
networkRequest,
|
|
225
|
+
networkRequestOptions,
|
|
226
|
+
(ast, root) =>
|
|
227
|
+
readUpdatableData(
|
|
228
|
+
environment,
|
|
229
|
+
ast,
|
|
230
|
+
root,
|
|
231
|
+
variables,
|
|
232
|
+
nestedRefetchQueries,
|
|
233
|
+
networkRequest,
|
|
234
|
+
networkRequestOptions,
|
|
235
|
+
mutableState,
|
|
236
|
+
mutableUpdatedIds,
|
|
237
|
+
),
|
|
238
|
+
);
|
|
239
|
+
if (data.kind === 'MissingData') {
|
|
240
|
+
throw new Error(data.reason);
|
|
241
|
+
}
|
|
242
|
+
return data.data;
|
|
243
|
+
},
|
|
244
|
+
'isUpdatable' in field && field.isUpdatable
|
|
245
|
+
? (newValue) => {
|
|
246
|
+
if (Array.isArray(newValue)) {
|
|
247
|
+
storeRecord[storeRecordName] = newValue.map((node) =>
|
|
248
|
+
assertLink(node?.link),
|
|
249
|
+
);
|
|
250
|
+
} else {
|
|
251
|
+
storeRecord[storeRecordName] = assertLink(newValue?.link);
|
|
252
|
+
}
|
|
253
|
+
const updatedIds = insertEmptySetIfMissing(
|
|
254
|
+
mutableUpdatedIds,
|
|
255
|
+
root.__typename,
|
|
256
|
+
);
|
|
257
|
+
updatedIds.add(root.__link);
|
|
258
|
+
}
|
|
259
|
+
: undefined,
|
|
260
|
+
);
|
|
261
|
+
break;
|
|
262
|
+
}
|
|
263
|
+
case 'ImperativelyLoadedField': {
|
|
264
|
+
defineCachedProperty(target, field.alias, mutableState, () => {
|
|
265
|
+
const data = readImperativelyLoadedField(
|
|
266
|
+
environment,
|
|
267
|
+
field,
|
|
268
|
+
root,
|
|
269
|
+
variables,
|
|
270
|
+
nestedRefetchQueries,
|
|
271
|
+
networkRequest,
|
|
272
|
+
networkRequestOptions,
|
|
273
|
+
new Map(),
|
|
274
|
+
);
|
|
275
|
+
if (data.kind === 'MissingData') {
|
|
276
|
+
throw new Error(data.reason);
|
|
277
|
+
}
|
|
278
|
+
return data.data;
|
|
279
|
+
});
|
|
280
|
+
break;
|
|
281
|
+
}
|
|
282
|
+
case 'Resolver': {
|
|
283
|
+
defineCachedProperty(target, field.alias, mutableState, () => {
|
|
284
|
+
const data = readResolverFieldData(
|
|
285
|
+
environment,
|
|
286
|
+
field,
|
|
287
|
+
root,
|
|
288
|
+
variables,
|
|
289
|
+
nestedRefetchQueries,
|
|
290
|
+
networkRequest,
|
|
291
|
+
networkRequestOptions,
|
|
292
|
+
new Map(),
|
|
293
|
+
);
|
|
294
|
+
if (data.kind === 'MissingData') {
|
|
295
|
+
throw new Error(data.reason);
|
|
296
|
+
}
|
|
297
|
+
return data.data;
|
|
298
|
+
});
|
|
299
|
+
break;
|
|
300
|
+
}
|
|
301
|
+
case 'LoadablySelectedField': {
|
|
302
|
+
defineCachedProperty(target, field.alias, mutableState, () => {
|
|
303
|
+
const data = readLoadablySelectedFieldData(
|
|
304
|
+
environment,
|
|
305
|
+
field,
|
|
306
|
+
root,
|
|
307
|
+
variables,
|
|
308
|
+
networkRequest,
|
|
309
|
+
networkRequestOptions,
|
|
310
|
+
new Map(),
|
|
311
|
+
);
|
|
312
|
+
if (data.kind === 'MissingData') {
|
|
313
|
+
throw new Error(data.reason);
|
|
314
|
+
}
|
|
315
|
+
return data.data;
|
|
316
|
+
});
|
|
317
|
+
break;
|
|
318
|
+
}
|
|
319
|
+
case 'Link': {
|
|
320
|
+
target[field.alias] = root;
|
|
321
|
+
break;
|
|
322
|
+
}
|
|
323
|
+
default: {
|
|
324
|
+
field satisfies never;
|
|
325
|
+
throw new Error('Unexpected case.');
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
return {
|
|
331
|
+
kind: 'Success',
|
|
332
|
+
data: target as any,
|
|
27
333
|
};
|
|
28
334
|
}
|
package/src/core/util.ts
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
|
+
import type React from 'react';
|
|
2
|
+
|
|
1
3
|
export type ExtractSecondParam<T extends (arg1: any, arg2: any) => any> =
|
|
2
4
|
T extends (arg1: any, arg2: infer P) => any ? P : never;
|
|
3
5
|
export type CombineWithIntrinsicAttributes<T> =
|
|
4
6
|
T extends Record<PropertyKey, never>
|
|
5
|
-
? JSX.IntrinsicAttributes
|
|
6
|
-
: T & JSX.IntrinsicAttributes;
|
|
7
|
+
? React.JSX.IntrinsicAttributes
|
|
8
|
+
: T & React.JSX.IntrinsicAttributes;
|
|
7
9
|
|
|
8
10
|
export type Arguments = Argument[];
|
|
9
11
|
export type Argument = [ArgumentName, ArgumentValue];
|
package/src/index.ts
CHANGED
|
@@ -18,6 +18,7 @@ export {
|
|
|
18
18
|
NOT_SET,
|
|
19
19
|
} from './core/PromiseWrapper';
|
|
20
20
|
export {
|
|
21
|
+
callSubscriptions,
|
|
21
22
|
subscribe,
|
|
22
23
|
normalizeData,
|
|
23
24
|
type NetworkResponseObject,
|
|
@@ -34,6 +35,7 @@ export {
|
|
|
34
35
|
type IsographNetworkFunction,
|
|
35
36
|
type IsographStore,
|
|
36
37
|
type MissingFieldHandler,
|
|
38
|
+
type StoreLink,
|
|
37
39
|
type Link,
|
|
38
40
|
type StoreRecord,
|
|
39
41
|
type CacheMap,
|
|
@@ -63,7 +65,7 @@ export {
|
|
|
63
65
|
type StableId,
|
|
64
66
|
type ResolverFirstParameter,
|
|
65
67
|
type ReaderImperativelyLoadedField,
|
|
66
|
-
type ReaderLoadableField,
|
|
68
|
+
type LoadablySelectedField as ReaderLoadableField,
|
|
67
69
|
type ReaderLinkField,
|
|
68
70
|
type StartUpdate,
|
|
69
71
|
} from './core/reader';
|
|
@@ -75,6 +77,9 @@ export {
|
|
|
75
77
|
type NormalizationLinkedField,
|
|
76
78
|
type NormalizationScalarField,
|
|
77
79
|
type IsographEntrypoint,
|
|
80
|
+
type IsographOperation,
|
|
81
|
+
type IsographPersistedOperation,
|
|
82
|
+
type IsographPersistedOperationExtraInfo,
|
|
78
83
|
assertIsEntrypoint,
|
|
79
84
|
type RefetchQueryNormalizationArtifact,
|
|
80
85
|
type RefetchQueryNormalizationArtifactWrapper,
|
|
@@ -137,9 +142,12 @@ export {
|
|
|
137
142
|
type UseImperativeReferenceResult,
|
|
138
143
|
} from './react/useImperativeReference';
|
|
139
144
|
export {
|
|
140
|
-
|
|
145
|
+
FragmentRenderer,
|
|
141
146
|
type IsExactlyIntrinsicAttributes,
|
|
142
|
-
} from './react/
|
|
147
|
+
} from './react/FragmentRenderer';
|
|
148
|
+
export { FragmentReader } from './react/FragmentReader';
|
|
149
|
+
export { LoadableFieldReader } from './react/LoadableFieldReader';
|
|
150
|
+
export { LoadableFieldRenderer } from './react/LoadableFieldRenderer';
|
|
143
151
|
export { useResult } from './react/useResult';
|
|
144
152
|
export {
|
|
145
153
|
useReadAndSubscribe,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export type UseImperativeLoadableFieldReturn<TArgs> = {
|
|
2
|
-
|
|
2
|
+
loadFragmentReference: (args: TArgs) => void;
|
|
3
3
|
};
|
|
4
4
|
|
|
5
5
|
// Note: this function doesn't seem to work if there are additional arguments,
|
|
@@ -9,7 +9,7 @@ export function useImperativeExposedMutationField<TArgs>(
|
|
|
9
9
|
exposedField: (args: TArgs) => [string, () => void],
|
|
10
10
|
): UseImperativeLoadableFieldReturn<TArgs> {
|
|
11
11
|
return {
|
|
12
|
-
|
|
12
|
+
loadFragmentReference: (args: TArgs) => {
|
|
13
13
|
const [_id, loader] = exposedField(args);
|
|
14
14
|
loader();
|
|
15
15
|
},
|
|
@@ -15,7 +15,7 @@ export type UseImperativeLoadableFieldReturn<
|
|
|
15
15
|
TProvidedArgs extends object,
|
|
16
16
|
> = {
|
|
17
17
|
fragmentReference: FragmentReference<TReadFromStore, TResult> | null;
|
|
18
|
-
|
|
18
|
+
loadFragmentReference: (
|
|
19
19
|
// TODO this should be void iff all args are provided by the query, like in
|
|
20
20
|
// useClientSideDefer.
|
|
21
21
|
args: Omit<ExtractParameters<TReadFromStore>, keyof TProvidedArgs> | void,
|
|
@@ -38,7 +38,7 @@ export function useImperativeLoadableField<
|
|
|
38
38
|
useUpdatableDisposableState<FragmentReference<TReadFromStore, TResult>>();
|
|
39
39
|
|
|
40
40
|
return {
|
|
41
|
-
|
|
41
|
+
loadFragmentReference: (
|
|
42
42
|
args: Omit<ExtractParameters<TReadFromStore>, keyof TProvidedArgs> | void,
|
|
43
43
|
fetchOptions?: FetchOptions<TResult>,
|
|
44
44
|
) => {
|
|
@@ -1,43 +1,27 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
import {
|
|
2
|
+
type ExtractReadFromStore,
|
|
3
|
+
type IsographEntrypoint,
|
|
4
|
+
} from '../core/entrypoint';
|
|
5
|
+
import { type FragmentReference } from '../core/FragmentReference';
|
|
6
|
+
import { type NetworkRequestReaderOptions } from '../core/read';
|
|
5
7
|
import { useResult } from './useResult';
|
|
6
8
|
|
|
7
|
-
export type IsExactlyIntrinsicAttributes<T> = T extends JSX.IntrinsicAttributes
|
|
8
|
-
? JSX.IntrinsicAttributes extends T
|
|
9
|
-
? true
|
|
10
|
-
: false
|
|
11
|
-
: false;
|
|
12
|
-
|
|
13
9
|
export function FragmentReader<
|
|
14
|
-
|
|
15
|
-
TEntrypoint extends IsographEntrypoint<any,
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
additionalProps: Omit<TProps, keyof JSX.IntrinsicAttributes>;
|
|
32
|
-
networkRequestOptions?: Partial<NetworkRequestReaderOptions>;
|
|
33
|
-
},
|
|
34
|
-
): React.ReactNode {
|
|
35
|
-
const Component = useResult(
|
|
36
|
-
props.fragmentReference,
|
|
37
|
-
props.networkRequestOptions,
|
|
38
|
-
);
|
|
39
|
-
// TypeScript is not understanding that if additionalProps is Record<PropertyKey, never>,
|
|
40
|
-
// it means that TProps === JSX.IntrinsicAttributes.
|
|
41
|
-
// @ts-expect-error
|
|
42
|
-
return <Component {...props.additionalProps} />;
|
|
10
|
+
TResult,
|
|
11
|
+
TEntrypoint extends IsographEntrypoint<any, TResult, any>,
|
|
12
|
+
TChildrenResult,
|
|
13
|
+
>({
|
|
14
|
+
fragmentReference,
|
|
15
|
+
networkRequestOptions,
|
|
16
|
+
children,
|
|
17
|
+
}: {
|
|
18
|
+
fragmentReference: FragmentReference<
|
|
19
|
+
ExtractReadFromStore<TEntrypoint>,
|
|
20
|
+
TResult
|
|
21
|
+
>;
|
|
22
|
+
networkRequestOptions?: Partial<NetworkRequestReaderOptions>;
|
|
23
|
+
children: (data: TResult) => TChildrenResult;
|
|
24
|
+
}): TChildrenResult {
|
|
25
|
+
const result = useResult(fragmentReference, networkRequestOptions);
|
|
26
|
+
return children(result);
|
|
43
27
|
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import {
|
|
3
|
+
type ExtractReadFromStore,
|
|
4
|
+
type IsographEntrypoint,
|
|
5
|
+
} from '../core/entrypoint';
|
|
6
|
+
import { type FragmentReference } from '../core/FragmentReference';
|
|
7
|
+
import { type NetworkRequestReaderOptions } from '../core/read';
|
|
8
|
+
import { useResult } from './useResult';
|
|
9
|
+
|
|
10
|
+
export type IsExactlyIntrinsicAttributes<T> = T extends JSX.IntrinsicAttributes
|
|
11
|
+
? JSX.IntrinsicAttributes extends T
|
|
12
|
+
? true
|
|
13
|
+
: false
|
|
14
|
+
: false;
|
|
15
|
+
|
|
16
|
+
export function FragmentRenderer<
|
|
17
|
+
TProps extends Record<any, any>,
|
|
18
|
+
TEntrypoint extends IsographEntrypoint<any, React.FC<TProps>, any>,
|
|
19
|
+
>(
|
|
20
|
+
props: IsExactlyIntrinsicAttributes<TProps> extends true
|
|
21
|
+
? {
|
|
22
|
+
fragmentReference: FragmentReference<
|
|
23
|
+
ExtractReadFromStore<TEntrypoint>,
|
|
24
|
+
React.FC<TProps>
|
|
25
|
+
>;
|
|
26
|
+
additionalProps?: Record<PropertyKey, never>;
|
|
27
|
+
networkRequestOptions?: Partial<NetworkRequestReaderOptions>;
|
|
28
|
+
}
|
|
29
|
+
: {
|
|
30
|
+
fragmentReference: FragmentReference<
|
|
31
|
+
ExtractReadFromStore<TEntrypoint>,
|
|
32
|
+
React.FC<TProps>
|
|
33
|
+
>;
|
|
34
|
+
additionalProps: Omit<TProps, keyof JSX.IntrinsicAttributes>;
|
|
35
|
+
networkRequestOptions?: Partial<NetworkRequestReaderOptions>;
|
|
36
|
+
},
|
|
37
|
+
): React.ReactNode {
|
|
38
|
+
const Component = useResult(
|
|
39
|
+
props.fragmentReference,
|
|
40
|
+
props.networkRequestOptions,
|
|
41
|
+
);
|
|
42
|
+
// TypeScript is not understanding that if additionalProps is Record<PropertyKey, never>,
|
|
43
|
+
// it means that TProps === JSX.IntrinsicAttributes.
|
|
44
|
+
// @ts-expect-error
|
|
45
|
+
return <Component {...props.additionalProps} />;
|
|
46
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { type FetchOptions } from '../core/check';
|
|
2
|
+
import {
|
|
3
|
+
ExtractParameters,
|
|
4
|
+
type UnknownTReadFromStore,
|
|
5
|
+
} from '../core/FragmentReference';
|
|
6
|
+
import { type NetworkRequestReaderOptions } from '../core/read';
|
|
7
|
+
import { type LoadableField } from '../core/reader';
|
|
8
|
+
import { useClientSideDefer } from '../loadable-hooks/useClientSideDefer';
|
|
9
|
+
import { useResult } from './useResult';
|
|
10
|
+
|
|
11
|
+
export function LoadableFieldReader<
|
|
12
|
+
TReadFromStore extends UnknownTReadFromStore,
|
|
13
|
+
TResult,
|
|
14
|
+
TProvidedArgs extends object,
|
|
15
|
+
TChildrenResult,
|
|
16
|
+
>(props: {
|
|
17
|
+
loadableField: LoadableField<
|
|
18
|
+
TReadFromStore,
|
|
19
|
+
TResult,
|
|
20
|
+
Omit<ExtractParameters<TReadFromStore>, keyof TProvidedArgs>
|
|
21
|
+
>;
|
|
22
|
+
// TODO we can improve this to not require args if its an empty object
|
|
23
|
+
args: Omit<ExtractParameters<TReadFromStore>, keyof TProvidedArgs>;
|
|
24
|
+
fetchOptions?: FetchOptions<TResult>;
|
|
25
|
+
networkRequestOptions?: Partial<NetworkRequestReaderOptions>;
|
|
26
|
+
children: (arg: TResult) => TChildrenResult;
|
|
27
|
+
}): TChildrenResult {
|
|
28
|
+
const { fragmentReference } = useClientSideDefer(
|
|
29
|
+
props.loadableField,
|
|
30
|
+
props.args,
|
|
31
|
+
props.fetchOptions,
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
const readOutFragmentData = useResult(
|
|
35
|
+
fragmentReference,
|
|
36
|
+
props.networkRequestOptions,
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
return props.children(readOutFragmentData);
|
|
40
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { type FetchOptions } from '../core/check';
|
|
3
|
+
import {
|
|
4
|
+
ExtractParameters,
|
|
5
|
+
type UnknownTReadFromStore,
|
|
6
|
+
} from '../core/FragmentReference';
|
|
7
|
+
import { type NetworkRequestReaderOptions } from '../core/read';
|
|
8
|
+
import { type LoadableField } from '../core/reader';
|
|
9
|
+
import { useClientSideDefer } from '../loadable-hooks/useClientSideDefer';
|
|
10
|
+
import { useResult } from './useResult';
|
|
11
|
+
|
|
12
|
+
export function LoadableFieldRenderer<
|
|
13
|
+
TReadFromStore extends UnknownTReadFromStore,
|
|
14
|
+
TProvidedArgs extends object,
|
|
15
|
+
TChildrenResult,
|
|
16
|
+
TProps,
|
|
17
|
+
>(props: {
|
|
18
|
+
loadableField: LoadableField<
|
|
19
|
+
TReadFromStore,
|
|
20
|
+
React.FC<TProps>,
|
|
21
|
+
Omit<ExtractParameters<TReadFromStore>, keyof TProvidedArgs>
|
|
22
|
+
>;
|
|
23
|
+
// TODO we can improve this to not require args if its an empty object
|
|
24
|
+
args: Omit<ExtractParameters<TReadFromStore>, keyof TProvidedArgs>;
|
|
25
|
+
fetchOptions?: FetchOptions<React.FC<TProps>>;
|
|
26
|
+
networkRequestOptions?: Partial<NetworkRequestReaderOptions>;
|
|
27
|
+
additionalProps: Omit<TProps, keyof JSX.IntrinsicAttributes>;
|
|
28
|
+
}): TChildrenResult {
|
|
29
|
+
const { fragmentReference } = useClientSideDefer(
|
|
30
|
+
props.loadableField,
|
|
31
|
+
props.args,
|
|
32
|
+
props.fetchOptions,
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
const Component = useResult(fragmentReference, props.networkRequestOptions);
|
|
36
|
+
|
|
37
|
+
// TODO we probably can figure out a way to convince TypeScript of
|
|
38
|
+
// the validity of this.
|
|
39
|
+
// @ts-expect-error
|
|
40
|
+
return <Component {...props.additionalProps} />;
|
|
41
|
+
}
|
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
} from '../core/FragmentReference';
|
|
16
16
|
import { ROOT_ID } from '../core/IsographEnvironment';
|
|
17
17
|
import { maybeMakeNetworkRequest } from '../core/makeNetworkRequest';
|
|
18
|
-
import { wrapResolvedValue } from '../core/PromiseWrapper';
|
|
18
|
+
import { wrapPromise, wrapResolvedValue } from '../core/PromiseWrapper';
|
|
19
19
|
import { useIsographEnvironment } from './IsographEnvironmentProvider';
|
|
20
20
|
|
|
21
21
|
export type UseImperativeReferenceResult<
|
|
@@ -61,21 +61,22 @@ export function useImperativeReference<
|
|
|
61
61
|
variables: ExtractParameters<TReadFromStore>,
|
|
62
62
|
fetchOptions?: FetchOptions<TClientFieldValue>,
|
|
63
63
|
) => {
|
|
64
|
+
const readerWithRefetchQueries =
|
|
65
|
+
entrypoint.readerWithRefetchQueries.kind ===
|
|
66
|
+
'ReaderWithRefetchQueriesLoader'
|
|
67
|
+
? wrapPromise(entrypoint.readerWithRefetchQueries.loader())
|
|
68
|
+
: wrapResolvedValue(entrypoint.readerWithRefetchQueries);
|
|
64
69
|
const [networkRequest, disposeNetworkRequest] = maybeMakeNetworkRequest(
|
|
65
70
|
environment,
|
|
66
71
|
entrypoint,
|
|
67
72
|
variables,
|
|
68
|
-
|
|
73
|
+
readerWithRefetchQueries,
|
|
74
|
+
fetchOptions ?? null,
|
|
69
75
|
);
|
|
70
76
|
setState([
|
|
71
77
|
{
|
|
72
78
|
kind: 'FragmentReference',
|
|
73
|
-
readerWithRefetchQueries
|
|
74
|
-
kind: 'ReaderWithRefetchQueries',
|
|
75
|
-
readerArtifact: entrypoint.readerWithRefetchQueries.readerArtifact,
|
|
76
|
-
nestedRefetchQueries:
|
|
77
|
-
entrypoint.readerWithRefetchQueries.nestedRefetchQueries,
|
|
78
|
-
}),
|
|
79
|
+
readerWithRefetchQueries,
|
|
79
80
|
root: { __link: ROOT_ID, __typename: entrypoint.concreteType },
|
|
80
81
|
variables,
|
|
81
82
|
networkRequest,
|