@isograph/react 0.0.0-main-4adb5045 → 0.0.0-main-82400fb8
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 +1 -1
- package/dist/core/FragmentReference.d.ts +1 -1
- package/dist/core/FragmentReference.d.ts.map +1 -1
- package/dist/core/FragmentReference.js +2 -2
- package/dist/core/IsographEnvironment.d.ts +7 -5
- package/dist/core/IsographEnvironment.d.ts.map +1 -1
- package/dist/core/IsographEnvironment.js +5 -4
- package/dist/core/cache.d.ts +5 -18
- package/dist/core/cache.d.ts.map +1 -1
- package/dist/core/cache.js +6 -218
- package/dist/core/componentCache.d.ts +2 -2
- package/dist/core/componentCache.d.ts.map +1 -1
- package/dist/core/componentCache.js +1 -26
- package/dist/core/entrypoint.d.ts +2 -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/getOrCreateCacheForArtifact.d.ts +8 -0
- package/dist/core/getOrCreateCacheForArtifact.d.ts.map +1 -0
- package/dist/core/getOrCreateCacheForArtifact.js +40 -0
- package/dist/core/logging.d.ts +8 -8
- 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 +3 -2
- package/dist/core/optimisticProxy.d.ts.map +1 -1
- package/dist/core/optimisticProxy.js +2 -1
- package/dist/core/read.d.ts +3 -3
- package/dist/core/read.d.ts.map +1 -1
- package/dist/core/startUpdate.d.ts.map +1 -1
- package/dist/core/startUpdate.js +2 -1
- package/dist/core/subscribe.d.ts +8 -0
- package/dist/core/subscribe.d.ts.map +1 -0
- package/dist/core/subscribe.js +127 -0
- package/dist/core/util.d.ts +7 -0
- package/dist/core/util.d.ts.map +1 -1
- package/dist/core/util.js +26 -0
- package/dist/core/writeData.d.ts +7 -0
- package/dist/core/writeData.d.ts.map +1 -0
- package/dist/core/writeData.js +36 -0
- package/dist/index.d.ts +5 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -5
- package/dist/loadable-hooks/useConnectionSpecPagination.d.ts +3 -3
- package/dist/loadable-hooks/useConnectionSpecPagination.d.ts.map +1 -1
- package/dist/loadable-hooks/useConnectionSpecPagination.js +2 -2
- package/dist/loadable-hooks/useSkipLimitPagination.d.ts +3 -3
- package/dist/loadable-hooks/useSkipLimitPagination.d.ts.map +1 -1
- package/dist/loadable-hooks/useSkipLimitPagination.js +2 -2
- package/dist/react/createIsographEnvironment.d.ts +4 -0
- package/dist/react/createIsographEnvironment.d.ts.map +1 -0
- package/dist/react/createIsographEnvironment.js +8 -0
- package/dist/react/maybeUnwrapNetworkRequest.d.ts +4 -0
- package/dist/react/maybeUnwrapNetworkRequest.d.ts.map +1 -0
- package/dist/react/maybeUnwrapNetworkRequest.js +14 -0
- package/dist/react/useLazyReference.d.ts.map +1 -1
- package/dist/react/useLazyReference.js +2 -2
- package/dist/react/useReadAndSubscribe.d.ts +4 -2
- package/dist/react/useReadAndSubscribe.d.ts.map +1 -1
- package/dist/react/useReadAndSubscribe.js +31 -2
- package/dist/react/useRerenderOnChange.d.ts +2 -2
- package/dist/react/useRerenderOnChange.d.ts.map +1 -1
- package/dist/react/useRerenderOnChange.js +2 -2
- package/dist/react/useResult.d.ts +2 -4
- package/dist/react/useResult.d.ts.map +1 -1
- package/dist/react/useResult.js +3 -13
- package/package.json +4 -4
- package/src/core/FragmentReference.ts +2 -2
- package/src/core/IsographEnvironment.ts +26 -10
- package/src/core/cache.ts +14 -360
- package/src/core/componentCache.ts +8 -43
- package/src/core/entrypoint.ts +2 -2
- package/src/core/garbageCollection.ts +5 -5
- package/src/core/getOrCreateCacheForArtifact.ts +86 -0
- package/src/core/logging.ts +10 -10
- package/src/core/makeNetworkRequest.ts +8 -8
- package/src/core/optimisticProxy.ts +2 -5
- package/src/core/read.ts +13 -13
- package/src/core/startUpdate.ts +1 -1
- package/src/core/subscribe.ts +195 -0
- package/src/core/util.ts +26 -0
- package/src/core/writeData.ts +79 -0
- package/src/index.ts +3 -4
- package/src/loadable-hooks/useConnectionSpecPagination.ts +5 -5
- package/src/loadable-hooks/useSkipLimitPagination.ts +5 -5
- package/src/react/createIsographEnvironment.ts +23 -0
- package/src/react/maybeUnwrapNetworkRequest.ts +17 -0
- package/src/react/useLazyReference.ts +2 -4
- package/src/react/useReadAndSubscribe.ts +53 -5
- package/src/react/useRerenderOnChange.ts +3 -3
- package/src/react/useResult.ts +6 -24
- package/src/tests/garbageCollection.test.ts +3 -6
- package/src/tests/meNameSuccessor.ts +1 -1
- package/src/tests/nodeQuery.ts +1 -1
- package/src/tests/normalizeData.test.ts +5 -3
- package/src/tests/optimisticProxy.test.ts +5 -3
- package/src/tests/startUpdate.test.ts +5 -7
- package/vitest.config.ts +5 -0
package/src/core/read.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { CleanupFn,
|
|
1
|
+
import type { CleanupFn, ItemCleanupPair } from '@isograph/disposable-types';
|
|
2
2
|
import {
|
|
3
3
|
getParentRecordKey,
|
|
4
4
|
insertEmptySetIfMissing,
|
|
@@ -7,16 +7,16 @@ import {
|
|
|
7
7
|
} from './cache';
|
|
8
8
|
import { FetchOptions } from './check';
|
|
9
9
|
import { getOrCreateCachedComponent } from './componentCache';
|
|
10
|
-
import {
|
|
10
|
+
import type {
|
|
11
11
|
IsographEntrypoint,
|
|
12
|
+
ReaderWithRefetchQueries,
|
|
12
13
|
RefetchQueryNormalizationArtifactWrapper,
|
|
13
|
-
type ReaderWithRefetchQueries,
|
|
14
14
|
} from './entrypoint';
|
|
15
|
-
import {
|
|
15
|
+
import type {
|
|
16
16
|
ExtractData,
|
|
17
17
|
FragmentReference,
|
|
18
|
+
UnknownTReadFromStore,
|
|
18
19
|
Variables,
|
|
19
|
-
type UnknownTReadFromStore,
|
|
20
20
|
} from './FragmentReference';
|
|
21
21
|
import {
|
|
22
22
|
assertLink,
|
|
@@ -38,17 +38,17 @@ import {
|
|
|
38
38
|
wrapPromise,
|
|
39
39
|
wrapResolvedValue,
|
|
40
40
|
} from './PromiseWrapper';
|
|
41
|
-
import {
|
|
41
|
+
import type {
|
|
42
|
+
LoadablySelectedField,
|
|
42
43
|
ReaderAst,
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
type ReaderScalarField,
|
|
44
|
+
ReaderClientPointer,
|
|
45
|
+
ReaderImperativelyLoadedField,
|
|
46
|
+
ReaderLinkedField,
|
|
47
|
+
ReaderNonLoadableResolverField,
|
|
48
|
+
ReaderScalarField,
|
|
49
49
|
} from './reader';
|
|
50
50
|
import { getOrCreateCachedStartUpdate } from './startUpdate';
|
|
51
|
-
import { Arguments } from './util';
|
|
51
|
+
import type { Arguments } from './util';
|
|
52
52
|
|
|
53
53
|
export type WithEncounteredRecords<T> = {
|
|
54
54
|
readonly encounteredRecords: EncounteredIds;
|
package/src/core/startUpdate.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import {
|
|
2
|
-
callSubscriptions,
|
|
3
2
|
getParentRecordKey,
|
|
4
3
|
insertEmptySetIfMissing,
|
|
5
4
|
type EncounteredIds,
|
|
@@ -37,6 +36,7 @@ import {
|
|
|
37
36
|
type ReadDataResultSuccess,
|
|
38
37
|
} from './read';
|
|
39
38
|
import type { ReaderAst } from './reader';
|
|
39
|
+
import { callSubscriptions } from './subscribe';
|
|
40
40
|
|
|
41
41
|
export function getOrCreateCachedStartUpdate<
|
|
42
42
|
TReadFromStore extends UnknownTReadFromStore,
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
import { mergeObjectsUsingReaderAst } from './areEqualWithDeepComparison';
|
|
2
|
+
import type { EncounteredIds } from './cache';
|
|
3
|
+
import type {
|
|
4
|
+
FragmentReference,
|
|
5
|
+
UnknownTReadFromStore,
|
|
6
|
+
} from './FragmentReference';
|
|
7
|
+
import type {
|
|
8
|
+
FragmentSubscription,
|
|
9
|
+
IsographEnvironment,
|
|
10
|
+
} from './IsographEnvironment';
|
|
11
|
+
import { logMessage } from './logging';
|
|
12
|
+
import { type WithEncounteredRecords, readButDoNotEvaluate } from './read';
|
|
13
|
+
import type { ReaderAst } from './reader';
|
|
14
|
+
|
|
15
|
+
export function subscribe<TReadFromStore extends UnknownTReadFromStore>(
|
|
16
|
+
environment: IsographEnvironment,
|
|
17
|
+
encounteredDataAndRecords: WithEncounteredRecords<TReadFromStore>,
|
|
18
|
+
fragmentReference: FragmentReference<TReadFromStore, any>,
|
|
19
|
+
callback: (
|
|
20
|
+
newEncounteredDataAndRecords: WithEncounteredRecords<TReadFromStore>,
|
|
21
|
+
) => void,
|
|
22
|
+
readerAst: ReaderAst<TReadFromStore>,
|
|
23
|
+
): () => void {
|
|
24
|
+
const fragmentSubscription: FragmentSubscription<TReadFromStore> = {
|
|
25
|
+
kind: 'FragmentSubscription',
|
|
26
|
+
callback,
|
|
27
|
+
encounteredDataAndRecords,
|
|
28
|
+
fragmentReference,
|
|
29
|
+
readerAst,
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
// subscribe is called in an effect. (We should actually subscribe during the
|
|
33
|
+
// initial render.) Because it's called in an effect, we might have missed some
|
|
34
|
+
// changes since the initial render! So, at this point, we re-read and call the
|
|
35
|
+
// subscription (i.e. re-render) if the fragment data has changed.
|
|
36
|
+
callSubscriptionIfDataChanged(environment, fragmentSubscription);
|
|
37
|
+
|
|
38
|
+
environment.subscriptions.add(fragmentSubscription);
|
|
39
|
+
return () => environment.subscriptions.delete(fragmentSubscription);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Calls to readButDoNotEvaluate can suspend (i.e. throw a promise).
|
|
43
|
+
// Maybe in the future, they will be able to throw errors.
|
|
44
|
+
//
|
|
45
|
+
// That's probably okay to ignore. We don't, however, want to prevent
|
|
46
|
+
// updating other subscriptions if one subscription had missing data.
|
|
47
|
+
function logAnyError(
|
|
48
|
+
environment: IsographEnvironment,
|
|
49
|
+
context: any,
|
|
50
|
+
f: () => void,
|
|
51
|
+
) {
|
|
52
|
+
try {
|
|
53
|
+
f();
|
|
54
|
+
} catch (e) {
|
|
55
|
+
logMessage(environment, () => ({
|
|
56
|
+
kind: 'ErrorEncounteredInWithErrorHandling',
|
|
57
|
+
error: e,
|
|
58
|
+
context,
|
|
59
|
+
}));
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export function callSubscriptions(
|
|
64
|
+
environment: IsographEnvironment,
|
|
65
|
+
recordsEncounteredWhenNormalizing: EncounteredIds,
|
|
66
|
+
) {
|
|
67
|
+
environment.subscriptions.forEach((subscription) =>
|
|
68
|
+
logAnyError(environment, { situation: 'calling subscriptions' }, () => {
|
|
69
|
+
switch (subscription.kind) {
|
|
70
|
+
case 'FragmentSubscription': {
|
|
71
|
+
// TODO if there are multiple components subscribed to the same
|
|
72
|
+
// fragment, we will call readButNotEvaluate multiple times. We
|
|
73
|
+
// should fix that.
|
|
74
|
+
if (
|
|
75
|
+
hasOverlappingIds(
|
|
76
|
+
recordsEncounteredWhenNormalizing,
|
|
77
|
+
subscription.encounteredDataAndRecords.encounteredRecords,
|
|
78
|
+
)
|
|
79
|
+
) {
|
|
80
|
+
callSubscriptionIfDataChanged(environment, subscription);
|
|
81
|
+
}
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
case 'AnyRecords': {
|
|
85
|
+
logAnyError(
|
|
86
|
+
environment,
|
|
87
|
+
{ situation: 'calling AnyRecords callback' },
|
|
88
|
+
() => subscription.callback(),
|
|
89
|
+
);
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
case 'AnyChangesToRecord': {
|
|
93
|
+
if (
|
|
94
|
+
recordsEncounteredWhenNormalizing
|
|
95
|
+
.get(subscription.recordLink.__typename)
|
|
96
|
+
?.has(subscription.recordLink.__link) != null
|
|
97
|
+
) {
|
|
98
|
+
logAnyError(
|
|
99
|
+
environment,
|
|
100
|
+
{ situation: 'calling AnyChangesToRecord callback' },
|
|
101
|
+
() => subscription.callback(),
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
default: {
|
|
107
|
+
// Ensure we have covered all variants
|
|
108
|
+
const _: never = subscription;
|
|
109
|
+
_;
|
|
110
|
+
throw new Error('Unexpected case');
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}),
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function callSubscriptionIfDataChanged<
|
|
118
|
+
TReadFromStore extends UnknownTReadFromStore,
|
|
119
|
+
>(
|
|
120
|
+
environment: IsographEnvironment,
|
|
121
|
+
subscription: FragmentSubscription<TReadFromStore>,
|
|
122
|
+
) {
|
|
123
|
+
const newEncounteredDataAndRecords = readButDoNotEvaluate(
|
|
124
|
+
environment,
|
|
125
|
+
subscription.fragmentReference,
|
|
126
|
+
// Is this wrong?
|
|
127
|
+
// Reasons to think no:
|
|
128
|
+
// - we are only updating the read-out value, and the network
|
|
129
|
+
// options only affect whether we throw.
|
|
130
|
+
// - the component will re-render, and re-throw on its own, anyway.
|
|
131
|
+
//
|
|
132
|
+
// Reasons to think not:
|
|
133
|
+
// - it seems more efficient to suspend here and not update state,
|
|
134
|
+
// if we expect that the component will just throw anyway
|
|
135
|
+
// - consistency
|
|
136
|
+
// - it's also weird, this is called from makeNetworkRequest, where
|
|
137
|
+
// we don't currently pass network request options
|
|
138
|
+
{
|
|
139
|
+
suspendIfInFlight: false,
|
|
140
|
+
throwOnNetworkError: false,
|
|
141
|
+
},
|
|
142
|
+
);
|
|
143
|
+
|
|
144
|
+
const mergedItem = mergeObjectsUsingReaderAst(
|
|
145
|
+
subscription.readerAst,
|
|
146
|
+
subscription.encounteredDataAndRecords.item,
|
|
147
|
+
newEncounteredDataAndRecords.item,
|
|
148
|
+
);
|
|
149
|
+
|
|
150
|
+
logMessage(environment, () => ({
|
|
151
|
+
kind: 'DeepEqualityCheck',
|
|
152
|
+
fragmentReference: subscription.fragmentReference,
|
|
153
|
+
old: subscription.encounteredDataAndRecords.item,
|
|
154
|
+
new: newEncounteredDataAndRecords.item,
|
|
155
|
+
deeplyEqual: mergedItem === subscription.encounteredDataAndRecords.item,
|
|
156
|
+
}));
|
|
157
|
+
|
|
158
|
+
if (mergedItem !== subscription.encounteredDataAndRecords.item) {
|
|
159
|
+
logAnyError(
|
|
160
|
+
environment,
|
|
161
|
+
{ situation: 'calling FragmentSubscription callback' },
|
|
162
|
+
() => {
|
|
163
|
+
subscription.callback(newEncounteredDataAndRecords);
|
|
164
|
+
},
|
|
165
|
+
);
|
|
166
|
+
subscription.encounteredDataAndRecords = newEncounteredDataAndRecords;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
function hasOverlappingIds(
|
|
171
|
+
ids1: EncounteredIds,
|
|
172
|
+
ids2: EncounteredIds,
|
|
173
|
+
): boolean {
|
|
174
|
+
for (const [typeName, set1] of ids1.entries()) {
|
|
175
|
+
const set2 = ids2.get(typeName);
|
|
176
|
+
if (set2 === undefined) {
|
|
177
|
+
continue;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
if (isNotDisjointFrom(set1, set2)) {
|
|
181
|
+
return true;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
return false;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// TODO use a polyfill library
|
|
188
|
+
function isNotDisjointFrom<T>(set1: Set<T>, set2: Set<T>): boolean {
|
|
189
|
+
for (const id of set1) {
|
|
190
|
+
if (set2.has(id)) {
|
|
191
|
+
return true;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
return false;
|
|
195
|
+
}
|
package/src/core/util.ts
CHANGED
|
@@ -31,3 +31,29 @@ export type ArgumentValue =
|
|
|
31
31
|
readonly kind: 'Object';
|
|
32
32
|
readonly value: Arguments;
|
|
33
33
|
};
|
|
34
|
+
|
|
35
|
+
export function isArray(value: unknown): value is readonly unknown[] {
|
|
36
|
+
return Array.isArray(value);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Creates a copy of the provided value, ensuring any nested objects have their
|
|
41
|
+
* keys sorted such that equivalent values would have identical JSON.stringify
|
|
42
|
+
* results.
|
|
43
|
+
*/
|
|
44
|
+
export function stableCopy<T>(value: T): T {
|
|
45
|
+
if (value == null || typeof value !== 'object') {
|
|
46
|
+
return value;
|
|
47
|
+
}
|
|
48
|
+
if (isArray(value)) {
|
|
49
|
+
// @ts-ignore
|
|
50
|
+
return value.map(stableCopy);
|
|
51
|
+
}
|
|
52
|
+
const keys = Object.keys(value).sort();
|
|
53
|
+
const stable: { [index: string]: any } = {};
|
|
54
|
+
for (let i = 0; i < keys.length; i++) {
|
|
55
|
+
// @ts-ignore
|
|
56
|
+
stable[keys[i]] = stableCopy(value[keys[i]]);
|
|
57
|
+
}
|
|
58
|
+
return stable as any;
|
|
59
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import type { ItemCleanupPair } from '@isograph/isograph-disposable-types/dist';
|
|
2
|
+
import { callSubscriptions } from './subscribe';
|
|
3
|
+
import {
|
|
4
|
+
type NetworkResponseObject,
|
|
5
|
+
type EncounteredIds,
|
|
6
|
+
normalizeData,
|
|
7
|
+
} from './cache';
|
|
8
|
+
import type { IsographEntrypoint, NormalizationAst } from './entrypoint';
|
|
9
|
+
import type {
|
|
10
|
+
UnknownTReadFromStore,
|
|
11
|
+
ExtractParameters,
|
|
12
|
+
FragmentReference,
|
|
13
|
+
} from './FragmentReference';
|
|
14
|
+
import {
|
|
15
|
+
type IsographEnvironment,
|
|
16
|
+
ROOT_ID,
|
|
17
|
+
getOrLoadReaderWithRefetchQueries,
|
|
18
|
+
} from './IsographEnvironment';
|
|
19
|
+
import { logMessage } from './logging';
|
|
20
|
+
import { retainQueryWithoutMakingNetworkRequest } from './makeNetworkRequest';
|
|
21
|
+
import { addNetworkResponseStoreLayer } from './optimisticProxy';
|
|
22
|
+
|
|
23
|
+
export function writeData<
|
|
24
|
+
TReadFromStore extends UnknownTReadFromStore,
|
|
25
|
+
TRawResponseType extends NetworkResponseObject,
|
|
26
|
+
TClientFieldValue,
|
|
27
|
+
>(
|
|
28
|
+
environment: IsographEnvironment,
|
|
29
|
+
entrypoint: IsographEntrypoint<
|
|
30
|
+
TReadFromStore,
|
|
31
|
+
TClientFieldValue,
|
|
32
|
+
NormalizationAst,
|
|
33
|
+
TRawResponseType
|
|
34
|
+
>,
|
|
35
|
+
data: TRawResponseType,
|
|
36
|
+
variables: ExtractParameters<TReadFromStore>,
|
|
37
|
+
): ItemCleanupPair<FragmentReference<TReadFromStore, TClientFieldValue>> {
|
|
38
|
+
const encounteredIds: EncounteredIds = new Map();
|
|
39
|
+
environment.store = addNetworkResponseStoreLayer(environment.store);
|
|
40
|
+
normalizeData(
|
|
41
|
+
environment,
|
|
42
|
+
environment.store,
|
|
43
|
+
entrypoint.networkRequestInfo.normalizationAst.selections,
|
|
44
|
+
data,
|
|
45
|
+
variables,
|
|
46
|
+
{ __link: ROOT_ID, __typename: entrypoint.concreteType },
|
|
47
|
+
encounteredIds,
|
|
48
|
+
);
|
|
49
|
+
logMessage(environment, () => ({
|
|
50
|
+
kind: 'AfterNormalization',
|
|
51
|
+
store: environment.store,
|
|
52
|
+
encounteredIds,
|
|
53
|
+
}));
|
|
54
|
+
|
|
55
|
+
callSubscriptions(environment, encounteredIds);
|
|
56
|
+
|
|
57
|
+
const { fieldName, readerArtifactKind, readerWithRefetchQueries } =
|
|
58
|
+
getOrLoadReaderWithRefetchQueries(
|
|
59
|
+
environment,
|
|
60
|
+
entrypoint.readerWithRefetchQueries,
|
|
61
|
+
);
|
|
62
|
+
const [networkRequest, disposeNetworkRequest] =
|
|
63
|
+
retainQueryWithoutMakingNetworkRequest(environment, entrypoint, variables);
|
|
64
|
+
|
|
65
|
+
return [
|
|
66
|
+
{
|
|
67
|
+
kind: 'FragmentReference',
|
|
68
|
+
readerWithRefetchQueries,
|
|
69
|
+
fieldName,
|
|
70
|
+
readerArtifactKind,
|
|
71
|
+
root: { __link: ROOT_ID, __typename: entrypoint.concreteType },
|
|
72
|
+
variables,
|
|
73
|
+
networkRequest,
|
|
74
|
+
},
|
|
75
|
+
() => {
|
|
76
|
+
disposeNetworkRequest();
|
|
77
|
+
},
|
|
78
|
+
];
|
|
79
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -18,15 +18,14 @@ export {
|
|
|
18
18
|
NOT_SET,
|
|
19
19
|
} from './core/PromiseWrapper';
|
|
20
20
|
export {
|
|
21
|
-
callSubscriptions,
|
|
22
|
-
subscribe,
|
|
23
21
|
normalizeData,
|
|
24
|
-
writeData,
|
|
25
22
|
type NetworkResponseObject,
|
|
26
23
|
type NetworkResponseValue,
|
|
27
24
|
type NetworkResponseScalarValue,
|
|
28
25
|
type EncounteredIds,
|
|
29
26
|
} from './core/cache';
|
|
27
|
+
export { callSubscriptions, subscribe } from './core/subscribe';
|
|
28
|
+
export { writeData } from './core/writeData';
|
|
30
29
|
export { makeNetworkRequest } from './core/makeNetworkRequest';
|
|
31
30
|
export {
|
|
32
31
|
ROOT_ID,
|
|
@@ -40,7 +39,6 @@ export {
|
|
|
40
39
|
type Link,
|
|
41
40
|
type StoreRecord,
|
|
42
41
|
type CacheMap,
|
|
43
|
-
createIsographEnvironment,
|
|
44
42
|
createIsographStore,
|
|
45
43
|
type FieldCache,
|
|
46
44
|
type Subscriptions,
|
|
@@ -159,6 +157,7 @@ export {
|
|
|
159
157
|
export { useLazyReference } from './react/useLazyReference';
|
|
160
158
|
export { useRerenderOnChange } from './react/useRerenderOnChange';
|
|
161
159
|
export { RenderAfterCommit__DO_NOT_USE } from './react/RenderAfterCommit__DO_NOT_USE';
|
|
160
|
+
export { createIsographEnvironment } from './react/createIsographEnvironment';
|
|
162
161
|
|
|
163
162
|
export { useClientSideDefer } from './loadable-hooks/useClientSideDefer';
|
|
164
163
|
export {
|
|
@@ -9,21 +9,21 @@ import {
|
|
|
9
9
|
} from '@isograph/reference-counted-pointer';
|
|
10
10
|
import { useState } from 'react';
|
|
11
11
|
import { subscribeToAnyChange } from '../core/cache';
|
|
12
|
-
import { FetchOptions } from '../core/check';
|
|
13
|
-
import {
|
|
12
|
+
import type { FetchOptions } from '../core/check';
|
|
13
|
+
import type {
|
|
14
14
|
FragmentReference,
|
|
15
|
-
|
|
15
|
+
UnknownTReadFromStore,
|
|
16
16
|
} from '../core/FragmentReference';
|
|
17
17
|
import { getPromiseState, readPromise } from '../core/PromiseWrapper';
|
|
18
18
|
import {
|
|
19
19
|
readButDoNotEvaluate,
|
|
20
20
|
type WithEncounteredRecords,
|
|
21
21
|
} from '../core/read';
|
|
22
|
-
import { LoadableField,
|
|
22
|
+
import type { LoadableField, ReaderAst } from '../core/reader';
|
|
23
23
|
import { getOrCreateCachedStartUpdate } from '../core/startUpdate';
|
|
24
24
|
import { useIsographEnvironment } from '../react/IsographEnvironmentProvider';
|
|
25
|
+
import { maybeUnwrapNetworkRequest } from '../react/maybeUnwrapNetworkRequest';
|
|
25
26
|
import { useSubscribeToMultiple } from '../react/useReadAndSubscribe';
|
|
26
|
-
import { maybeUnwrapNetworkRequest } from '../react/useResult';
|
|
27
27
|
|
|
28
28
|
export type UsePaginationReturnValue<
|
|
29
29
|
TReadFromStore extends UnknownTReadFromStore,
|
|
@@ -9,21 +9,21 @@ import {
|
|
|
9
9
|
} from '@isograph/reference-counted-pointer';
|
|
10
10
|
import { useState } from 'react';
|
|
11
11
|
import { subscribeToAnyChange } from '../core/cache';
|
|
12
|
-
import { FetchOptions } from '../core/check';
|
|
13
|
-
import {
|
|
12
|
+
import type { FetchOptions } from '../core/check';
|
|
13
|
+
import type {
|
|
14
14
|
FragmentReference,
|
|
15
|
-
|
|
15
|
+
UnknownTReadFromStore,
|
|
16
16
|
} from '../core/FragmentReference';
|
|
17
17
|
import { getPromiseState, readPromise } from '../core/PromiseWrapper';
|
|
18
18
|
import {
|
|
19
19
|
readButDoNotEvaluate,
|
|
20
20
|
type WithEncounteredRecords,
|
|
21
21
|
} from '../core/read';
|
|
22
|
-
import { LoadableField,
|
|
22
|
+
import type { LoadableField, ReaderAst } from '../core/reader';
|
|
23
23
|
import { getOrCreateCachedStartUpdate } from '../core/startUpdate';
|
|
24
24
|
import { useIsographEnvironment } from '../react/IsographEnvironmentProvider';
|
|
25
|
+
import { maybeUnwrapNetworkRequest } from '../react/maybeUnwrapNetworkRequest';
|
|
25
26
|
import { useSubscribeToMultiple } from '../react/useReadAndSubscribe';
|
|
26
|
-
import { maybeUnwrapNetworkRequest } from '../react/useResult';
|
|
27
27
|
|
|
28
28
|
export type UseSkipLimitReturnValue<
|
|
29
29
|
TReadFromStore extends UnknownTReadFromStore,
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createIsographEnvironmentCore,
|
|
3
|
+
type BaseStoreLayerData,
|
|
4
|
+
type IsographNetworkFunction,
|
|
5
|
+
type MissingFieldHandler,
|
|
6
|
+
} from '../core/IsographEnvironment';
|
|
7
|
+
import type { LogFunction } from '../core/logging';
|
|
8
|
+
import { componentFunction } from './useReadAndSubscribe';
|
|
9
|
+
|
|
10
|
+
export function createIsographEnvironment(
|
|
11
|
+
baseStoreLayerData: BaseStoreLayerData,
|
|
12
|
+
networkFunction: IsographNetworkFunction,
|
|
13
|
+
missingFieldHandler?: MissingFieldHandler | null,
|
|
14
|
+
logFunction?: LogFunction | null,
|
|
15
|
+
) {
|
|
16
|
+
return createIsographEnvironmentCore(
|
|
17
|
+
baseStoreLayerData,
|
|
18
|
+
networkFunction,
|
|
19
|
+
componentFunction,
|
|
20
|
+
missingFieldHandler,
|
|
21
|
+
logFunction,
|
|
22
|
+
);
|
|
23
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { type PromiseWrapper, getPromiseState } from '../core/PromiseWrapper';
|
|
2
|
+
import type { NetworkRequestReaderOptions } from '../core/read';
|
|
3
|
+
|
|
4
|
+
export function maybeUnwrapNetworkRequest(
|
|
5
|
+
networkRequest: PromiseWrapper<void, any>,
|
|
6
|
+
networkRequestOptions: NetworkRequestReaderOptions,
|
|
7
|
+
) {
|
|
8
|
+
const state = getPromiseState(networkRequest);
|
|
9
|
+
if (state.kind === 'Err' && networkRequestOptions.throwOnNetworkError) {
|
|
10
|
+
throw state.error;
|
|
11
|
+
} else if (
|
|
12
|
+
state.kind === 'Pending' &&
|
|
13
|
+
networkRequestOptions.suspendIfInFlight
|
|
14
|
+
) {
|
|
15
|
+
throw state.promise;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -1,8 +1,5 @@
|
|
|
1
1
|
import { useLazyDisposableState } from '@isograph/react-disposable-state';
|
|
2
|
-
import {
|
|
3
|
-
getOrCreateCacheForArtifact,
|
|
4
|
-
type NetworkResponseObject,
|
|
5
|
-
} from '../core/cache';
|
|
2
|
+
import { type NetworkResponseObject } from '../core/cache';
|
|
6
3
|
import { FetchOptions, type RequiredFetchOptions } from '../core/check';
|
|
7
4
|
import {
|
|
8
5
|
IsographEntrypoint,
|
|
@@ -16,6 +13,7 @@ import {
|
|
|
16
13
|
} from '../core/FragmentReference';
|
|
17
14
|
import { logMessage } from '../core/logging';
|
|
18
15
|
import { useIsographEnvironment } from './IsographEnvironmentProvider';
|
|
16
|
+
import { getOrCreateCacheForArtifact } from '../core/getOrCreateCacheForArtifact';
|
|
19
17
|
|
|
20
18
|
export function useLazyReference<
|
|
21
19
|
TReadFromStore extends UnknownTReadFromStore,
|
|
@@ -1,18 +1,22 @@
|
|
|
1
1
|
import { useEffect, useState } from 'react';
|
|
2
|
-
import { subscribe } from '../core/cache';
|
|
3
2
|
import {
|
|
4
|
-
ExtractData,
|
|
5
|
-
FragmentReference,
|
|
3
|
+
type ExtractData,
|
|
4
|
+
type FragmentReference,
|
|
6
5
|
stableIdForFragmentReference,
|
|
7
6
|
type UnknownTReadFromStore,
|
|
8
7
|
} from '../core/FragmentReference';
|
|
8
|
+
import type { IsographComponentFunction } from '../core/IsographEnvironment';
|
|
9
|
+
import { logMessage } from '../core/logging';
|
|
10
|
+
import { readPromise } from '../core/PromiseWrapper';
|
|
9
11
|
import {
|
|
10
|
-
NetworkRequestReaderOptions,
|
|
12
|
+
type NetworkRequestReaderOptions,
|
|
11
13
|
readButDoNotEvaluate,
|
|
12
|
-
WithEncounteredRecords,
|
|
14
|
+
type WithEncounteredRecords,
|
|
13
15
|
} from '../core/read';
|
|
14
16
|
import type { ReaderAst } from '../core/reader';
|
|
17
|
+
import { subscribe } from '../core/subscribe';
|
|
15
18
|
import { useIsographEnvironment } from './IsographEnvironmentProvider';
|
|
19
|
+
import { maybeUnwrapNetworkRequest } from './maybeUnwrapNetworkRequest';
|
|
16
20
|
import { useRerenderOnChange } from './useRerenderOnChange';
|
|
17
21
|
|
|
18
22
|
/**
|
|
@@ -80,3 +84,47 @@ export function useSubscribeToMultiple<
|
|
|
80
84
|
],
|
|
81
85
|
);
|
|
82
86
|
}
|
|
87
|
+
|
|
88
|
+
export const componentFunction: IsographComponentFunction = (
|
|
89
|
+
environment,
|
|
90
|
+
fragmentReference,
|
|
91
|
+
networkRequestOptions,
|
|
92
|
+
startUpdate,
|
|
93
|
+
) => {
|
|
94
|
+
function Component(additionalRuntimeProps: { [key: string]: any }) {
|
|
95
|
+
maybeUnwrapNetworkRequest(
|
|
96
|
+
fragmentReference.networkRequest,
|
|
97
|
+
networkRequestOptions,
|
|
98
|
+
);
|
|
99
|
+
const readerWithRefetchQueries = readPromise(
|
|
100
|
+
fragmentReference.readerWithRefetchQueries,
|
|
101
|
+
);
|
|
102
|
+
|
|
103
|
+
const data = useReadAndSubscribe(
|
|
104
|
+
fragmentReference,
|
|
105
|
+
networkRequestOptions,
|
|
106
|
+
readerWithRefetchQueries.readerArtifact.readerAst,
|
|
107
|
+
);
|
|
108
|
+
|
|
109
|
+
logMessage(environment, () => ({
|
|
110
|
+
kind: 'ComponentRerendered',
|
|
111
|
+
componentName: fragmentReference.fieldName,
|
|
112
|
+
rootLink: fragmentReference.root,
|
|
113
|
+
}));
|
|
114
|
+
|
|
115
|
+
return readerWithRefetchQueries.readerArtifact.resolver(
|
|
116
|
+
// @ts-expect-error
|
|
117
|
+
{
|
|
118
|
+
data,
|
|
119
|
+
parameters: fragmentReference.variables,
|
|
120
|
+
startUpdate: readerWithRefetchQueries.readerArtifact.hasUpdatable
|
|
121
|
+
? startUpdate
|
|
122
|
+
: undefined,
|
|
123
|
+
},
|
|
124
|
+
additionalRuntimeProps,
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
const idString = `(type: ${fragmentReference.root.__typename}, id: ${fragmentReference.root.__link})`;
|
|
128
|
+
Component.displayName = `${fragmentReference.fieldName} ${idString} @component`;
|
|
129
|
+
return Component;
|
|
130
|
+
};
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { useEffect } from 'react';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { WithEncounteredRecords } from '../core/read';
|
|
2
|
+
import type { FragmentReference } from '../core/FragmentReference';
|
|
3
|
+
import type { WithEncounteredRecords } from '../core/read';
|
|
5
4
|
import type { ReaderAst } from '../core/reader';
|
|
5
|
+
import { subscribe } from '../core/subscribe';
|
|
6
6
|
import { useIsographEnvironment } from './IsographEnvironmentProvider';
|
|
7
7
|
|
|
8
8
|
// TODO add unit tests for this. Add integration tests that test
|
package/src/react/useResult.ts
CHANGED
|
@@ -1,19 +1,16 @@
|
|
|
1
1
|
import { getOrCreateCachedComponent } from '../core/componentCache';
|
|
2
|
-
import {
|
|
2
|
+
import type {
|
|
3
3
|
FragmentReference,
|
|
4
|
-
|
|
4
|
+
UnknownTReadFromStore,
|
|
5
5
|
} from '../core/FragmentReference';
|
|
6
|
+
import { readPromise } from '../core/PromiseWrapper';
|
|
6
7
|
import {
|
|
7
|
-
|
|
8
|
-
PromiseWrapper,
|
|
9
|
-
readPromise,
|
|
10
|
-
} from '../core/PromiseWrapper';
|
|
11
|
-
import {
|
|
8
|
+
type NetworkRequestReaderOptions,
|
|
12
9
|
getNetworkRequestOptionsWithDefaults,
|
|
13
|
-
NetworkRequestReaderOptions,
|
|
14
10
|
} from '../core/read';
|
|
15
11
|
import { getOrCreateCachedStartUpdate } from '../core/startUpdate';
|
|
16
|
-
import { useIsographEnvironment } from '
|
|
12
|
+
import { useIsographEnvironment } from './IsographEnvironmentProvider';
|
|
13
|
+
import { maybeUnwrapNetworkRequest } from './maybeUnwrapNetworkRequest';
|
|
17
14
|
import { useReadAndSubscribe } from './useReadAndSubscribe';
|
|
18
15
|
|
|
19
16
|
export function useResult<
|
|
@@ -68,18 +65,3 @@ export function useResult<
|
|
|
68
65
|
}
|
|
69
66
|
}
|
|
70
67
|
}
|
|
71
|
-
|
|
72
|
-
export function maybeUnwrapNetworkRequest(
|
|
73
|
-
networkRequest: PromiseWrapper<void, any>,
|
|
74
|
-
networkRequestOptions: NetworkRequestReaderOptions,
|
|
75
|
-
) {
|
|
76
|
-
const state = getPromiseState(networkRequest);
|
|
77
|
-
if (state.kind === 'Err' && networkRequestOptions.throwOnNetworkError) {
|
|
78
|
-
throw state.error;
|
|
79
|
-
} else if (
|
|
80
|
-
state.kind === 'Pending' &&
|
|
81
|
-
networkRequestOptions.suspendIfInFlight
|
|
82
|
-
) {
|
|
83
|
-
throw state.promise;
|
|
84
|
-
}
|
|
85
|
-
}
|
|
@@ -1,18 +1,15 @@
|
|
|
1
|
+
import { iso } from '@iso';
|
|
1
2
|
import { describe, expect, test } from 'vitest';
|
|
2
3
|
import {
|
|
3
4
|
garbageCollectEnvironment,
|
|
4
5
|
retainQuery,
|
|
5
6
|
type RetainedQuery,
|
|
6
7
|
} from '../core/garbageCollection';
|
|
7
|
-
import {
|
|
8
|
-
createIsographEnvironment,
|
|
9
|
-
ROOT_ID,
|
|
10
|
-
type BaseStoreLayerData,
|
|
11
|
-
} from '../core/IsographEnvironment';
|
|
8
|
+
import { ROOT_ID, type BaseStoreLayerData } from '../core/IsographEnvironment';
|
|
12
9
|
import { wrapResolvedValue } from '../core/PromiseWrapper';
|
|
13
|
-
import { iso } from './__isograph/iso';
|
|
14
10
|
import { meNameSuccessorRetainedQuery } from './meNameSuccessor';
|
|
15
11
|
import { nodeFieldRetainedQuery } from './nodeQuery';
|
|
12
|
+
import { createIsographEnvironment } from '../react/createIsographEnvironment';
|
|
16
13
|
|
|
17
14
|
const getDefaultStore = (): BaseStoreLayerData => ({
|
|
18
15
|
Query: {
|