@isograph/react 0.0.0-main-adb0955b → 0.0.0-main-1ed9144e
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/core/cache.d.ts +2 -1
- package/dist/core/cache.js +5 -2
- package/dist/core/check.d.ts +15 -0
- package/dist/core/check.js +133 -0
- package/dist/core/logging.d.ts +4 -0
- package/dist/core/makeNetworkRequest.d.ts +2 -0
- package/dist/core/makeNetworkRequest.js +21 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +3 -1
- package/dist/react/useImperativeReference.d.ts +2 -1
- package/dist/react/useImperativeReference.js +5 -2
- package/dist/react/useLazyReference.d.ts +2 -1
- package/dist/react/useLazyReference.js +2 -2
- package/package.json +4 -4
- package/src/core/cache.ts +7 -2
- package/src/core/check.ts +208 -0
- package/src/core/logging.ts +5 -0
- package/src/core/makeNetworkRequest.ts +31 -1
- package/src/core/read.ts +1 -1
- package/src/index.ts +1 -0
- package/src/react/useImperativeReference.ts +13 -4
- package/src/react/useLazyReference.ts +8 -1
package/dist/core/cache.d.ts
CHANGED
|
@@ -4,6 +4,7 @@ import { IsographEntrypoint, NormalizationAst, NormalizationLinkedField, Normali
|
|
|
4
4
|
import { ReaderLinkedField, ReaderScalarField, type ReaderAst } from './reader';
|
|
5
5
|
import { WithEncounteredRecords } from './read';
|
|
6
6
|
import { FragmentReference, Variables, ExtractParameters } from './FragmentReference';
|
|
7
|
+
import { FetchOptions } from './check';
|
|
7
8
|
export declare function getOrCreateItemInSuspenseCache<TReadFromStore extends {
|
|
8
9
|
parameters: object;
|
|
9
10
|
data: object;
|
|
@@ -17,7 +18,7 @@ export declare function stableCopy<T>(value: T): T;
|
|
|
17
18
|
export declare function getOrCreateCacheForArtifact<TReadFromStore extends {
|
|
18
19
|
parameters: object;
|
|
19
20
|
data: object;
|
|
20
|
-
}, TClientFieldValue>(environment: IsographEnvironment, entrypoint: IsographEntrypoint<TReadFromStore, TClientFieldValue>, variables: ExtractParameters<TReadFromStore
|
|
21
|
+
}, TClientFieldValue>(environment: IsographEnvironment, entrypoint: IsographEntrypoint<TReadFromStore, TClientFieldValue>, variables: ExtractParameters<TReadFromStore>, options?: FetchOptions): ParentCache<FragmentReference<TReadFromStore, TClientFieldValue>>;
|
|
21
22
|
type NetworkResponseScalarValue = string | number | boolean;
|
|
22
23
|
type NetworkResponseValue = NetworkResponseScalarValue | null | NetworkResponseObject | NetworkResponseObject[] | NetworkResponseScalarValue[];
|
|
23
24
|
export type NetworkResponseObject = {
|
package/dist/core/cache.js
CHANGED
|
@@ -17,6 +17,7 @@ const areEqualWithDeepComparison_1 = require("./areEqualWithDeepComparison");
|
|
|
17
17
|
const makeNetworkRequest_1 = require("./makeNetworkRequest");
|
|
18
18
|
const PromiseWrapper_1 = require("./PromiseWrapper");
|
|
19
19
|
const logging_1 = require("./logging");
|
|
20
|
+
const check_1 = require("./check");
|
|
20
21
|
const TYPENAME_FIELD_NAME = '__typename';
|
|
21
22
|
function getOrCreateItemInSuspenseCache(environment, index, factory) {
|
|
22
23
|
// TODO this is probably a useless message, we should remove it
|
|
@@ -52,10 +53,12 @@ function stableCopy(value) {
|
|
|
52
53
|
}
|
|
53
54
|
return stable;
|
|
54
55
|
}
|
|
55
|
-
function getOrCreateCacheForArtifact(environment, entrypoint, variables) {
|
|
56
|
+
function getOrCreateCacheForArtifact(environment, entrypoint, variables, options) {
|
|
56
57
|
const cacheKey = entrypoint.queryText + JSON.stringify(stableCopy(variables));
|
|
57
58
|
const factory = () => {
|
|
58
|
-
|
|
59
|
+
var _a;
|
|
60
|
+
const fetchPolicy = (_a = options === null || options === void 0 ? void 0 : options.fetchPolicy) !== null && _a !== void 0 ? _a : check_1.DEFAULT_FETCH_POLICY;
|
|
61
|
+
const [networkRequest, disposeNetworkRequest] = (0, makeNetworkRequest_1.maybeMakeNetworkRequest)(environment, entrypoint, variables, fetchPolicy);
|
|
59
62
|
const itemCleanupPair = [
|
|
60
63
|
{
|
|
61
64
|
kind: 'FragmentReference',
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { NormalizationAst } from './entrypoint';
|
|
2
|
+
import { Variables } from './FragmentReference';
|
|
3
|
+
import { IsographEnvironment, Link } from './IsographEnvironment';
|
|
4
|
+
export type FetchPolicy = 'Yes' | 'No' | 'IfNecessary';
|
|
5
|
+
export declare const DEFAULT_FETCH_POLICY: FetchPolicy;
|
|
6
|
+
export type FetchOptions = {
|
|
7
|
+
fetchPolicy?: FetchPolicy;
|
|
8
|
+
};
|
|
9
|
+
export type CheckResult = {
|
|
10
|
+
kind: 'EnoughData';
|
|
11
|
+
} | {
|
|
12
|
+
kind: 'MissingData';
|
|
13
|
+
record: Link;
|
|
14
|
+
};
|
|
15
|
+
export declare function check(environment: IsographEnvironment, normalizationAst: NormalizationAst, variables: Variables): CheckResult;
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DEFAULT_FETCH_POLICY = void 0;
|
|
4
|
+
exports.check = check;
|
|
5
|
+
const cache_1 = require("./cache");
|
|
6
|
+
const IsographEnvironment_1 = require("./IsographEnvironment");
|
|
7
|
+
const logging_1 = require("./logging");
|
|
8
|
+
exports.DEFAULT_FETCH_POLICY = 'IfNecessary';
|
|
9
|
+
function check(environment, normalizationAst, variables) {
|
|
10
|
+
const checkResult = checkFromRecord(environment, normalizationAst, variables, environment.store[IsographEnvironment_1.ROOT_ID], IsographEnvironment_1.ROOT_ID);
|
|
11
|
+
(0, logging_1.logMessage)(environment, {
|
|
12
|
+
kind: 'EnvironmentCheck',
|
|
13
|
+
result: checkResult,
|
|
14
|
+
});
|
|
15
|
+
return checkResult;
|
|
16
|
+
}
|
|
17
|
+
function checkFromRecord(environment, normalizationAst, variables, record, backupId) {
|
|
18
|
+
var _a, _b, _c;
|
|
19
|
+
normalizationAstLoop: for (const normalizationAstNode of normalizationAst) {
|
|
20
|
+
switch (normalizationAstNode.kind) {
|
|
21
|
+
case 'Scalar': {
|
|
22
|
+
const parentRecordKey = (0, cache_1.getParentRecordKey)(normalizationAstNode, variables);
|
|
23
|
+
const scalarValue = record[parentRecordKey];
|
|
24
|
+
// null means the value is known to be missing, so it must
|
|
25
|
+
// be exactly undefined
|
|
26
|
+
if (scalarValue === undefined) {
|
|
27
|
+
return {
|
|
28
|
+
kind: 'MissingData',
|
|
29
|
+
record: {
|
|
30
|
+
__link: (_a = record.id) !== null && _a !== void 0 ? _a : backupId,
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
continue normalizationAstLoop;
|
|
35
|
+
}
|
|
36
|
+
case 'Linked': {
|
|
37
|
+
const parentRecordKey = (0, cache_1.getParentRecordKey)(normalizationAstNode, variables);
|
|
38
|
+
const linkedValue = record[parentRecordKey];
|
|
39
|
+
if (linkedValue === undefined) {
|
|
40
|
+
return {
|
|
41
|
+
kind: 'MissingData',
|
|
42
|
+
record: {
|
|
43
|
+
__link: (_b = record.id) !== null && _b !== void 0 ? _b : backupId,
|
|
44
|
+
},
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
else if (linkedValue === null) {
|
|
48
|
+
continue;
|
|
49
|
+
}
|
|
50
|
+
else if (Array.isArray(linkedValue)) {
|
|
51
|
+
arrayItemsLoop: for (const item of linkedValue) {
|
|
52
|
+
const link = (0, IsographEnvironment_1.getLink)(item);
|
|
53
|
+
if (link === null) {
|
|
54
|
+
throw new Error('Unexpected non-link in the Isograph store. ' +
|
|
55
|
+
'This is indicative of a bug in Isograph.');
|
|
56
|
+
}
|
|
57
|
+
const linkedRecord = environment.store[link.__link];
|
|
58
|
+
if (linkedRecord === undefined) {
|
|
59
|
+
return {
|
|
60
|
+
kind: 'MissingData',
|
|
61
|
+
record: link,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
else if (linkedRecord === null) {
|
|
65
|
+
continue arrayItemsLoop;
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
// TODO in __DEV__ assert linkedRecord is an object
|
|
69
|
+
const result = checkFromRecord(environment, normalizationAstNode.selections, variables, linkedRecord,
|
|
70
|
+
// TODO this seems likely to be wrong
|
|
71
|
+
backupId + '.' + parentRecordKey);
|
|
72
|
+
if (result.kind === 'MissingData') {
|
|
73
|
+
return result;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
const link = (0, IsographEnvironment_1.getLink)(linkedValue);
|
|
80
|
+
if (link === null) {
|
|
81
|
+
throw new Error('Unexpected non-link in the Isograph store. ' +
|
|
82
|
+
'This is indicative of a bug in Isograph.');
|
|
83
|
+
}
|
|
84
|
+
const linkedRecord = environment.store[link.__link];
|
|
85
|
+
if (linkedRecord === undefined) {
|
|
86
|
+
return {
|
|
87
|
+
kind: 'MissingData',
|
|
88
|
+
record: link,
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
else if (linkedRecord === null) {
|
|
92
|
+
continue normalizationAstLoop;
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
// TODO in __DEV__ assert linkedRecord is an object
|
|
96
|
+
const result = checkFromRecord(environment, normalizationAstNode.selections, variables, linkedRecord,
|
|
97
|
+
// TODO this seems likely to be wrong
|
|
98
|
+
backupId + '.' + parentRecordKey);
|
|
99
|
+
if (result.kind === 'MissingData') {
|
|
100
|
+
return result;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
continue normalizationAstLoop;
|
|
105
|
+
}
|
|
106
|
+
case 'InlineFragment': {
|
|
107
|
+
const existingRecordTypename = record['__typename'];
|
|
108
|
+
if (existingRecordTypename == null ||
|
|
109
|
+
existingRecordTypename !== normalizationAstNode.type) {
|
|
110
|
+
return {
|
|
111
|
+
kind: 'MissingData',
|
|
112
|
+
record: {
|
|
113
|
+
__link: (_c = record.id) !== null && _c !== void 0 ? _c : backupId,
|
|
114
|
+
},
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
const result = checkFromRecord(environment, normalizationAstNode.selections, variables, record, backupId);
|
|
118
|
+
if (result.kind === 'MissingData') {
|
|
119
|
+
return result;
|
|
120
|
+
}
|
|
121
|
+
continue normalizationAstLoop;
|
|
122
|
+
}
|
|
123
|
+
default: {
|
|
124
|
+
let _ = normalizationAstNode;
|
|
125
|
+
_;
|
|
126
|
+
throw new Error('Unexpected case. This is indicative of a bug in Isograph.');
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
return {
|
|
131
|
+
kind: 'EnoughData',
|
|
132
|
+
};
|
|
133
|
+
}
|
package/dist/core/logging.d.ts
CHANGED
|
@@ -5,6 +5,7 @@ import { FragmentReference, Variables } from './FragmentReference';
|
|
|
5
5
|
import { NetworkResponseObject } from './cache';
|
|
6
6
|
import { Arguments } from './util';
|
|
7
7
|
import { ReadDataResult } from './read';
|
|
8
|
+
import { CheckResult } from './check';
|
|
8
9
|
export type LogMessage = {
|
|
9
10
|
kind: 'GettingSuspenseCacheItem';
|
|
10
11
|
index: string;
|
|
@@ -51,6 +52,9 @@ export type LogMessage = {
|
|
|
51
52
|
} | {
|
|
52
53
|
kind: 'NonEntrypointReceived';
|
|
53
54
|
entrypoint: any;
|
|
55
|
+
} | {
|
|
56
|
+
kind: 'EnvironmentCheck';
|
|
57
|
+
result: CheckResult;
|
|
54
58
|
};
|
|
55
59
|
export type LogFunction = (logMessage: LogMessage) => void;
|
|
56
60
|
export type WrappedLogFunction = {
|
|
@@ -3,4 +3,6 @@ import { IsographEntrypoint, RefetchQueryNormalizationArtifact } from './entrypo
|
|
|
3
3
|
import { Variables } from './FragmentReference';
|
|
4
4
|
import { IsographEnvironment } from './IsographEnvironment';
|
|
5
5
|
import { AnyError, PromiseWrapper } from './PromiseWrapper';
|
|
6
|
+
import { FetchPolicy } from './check';
|
|
7
|
+
export declare function maybeMakeNetworkRequest(environment: IsographEnvironment, artifact: RefetchQueryNormalizationArtifact | IsographEntrypoint<any, any>, variables: Variables, fetchPolicy: FetchPolicy): ItemCleanupPair<PromiseWrapper<void, AnyError>>;
|
|
6
8
|
export declare function makeNetworkRequest(environment: IsographEnvironment, artifact: RefetchQueryNormalizationArtifact | IsographEntrypoint<any, any>, variables: Variables): ItemCleanupPair<PromiseWrapper<void, AnyError>>;
|
|
@@ -1,11 +1,32 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.maybeMakeNetworkRequest = maybeMakeNetworkRequest;
|
|
3
4
|
exports.makeNetworkRequest = makeNetworkRequest;
|
|
4
5
|
const garbageCollection_1 = require("./garbageCollection");
|
|
5
6
|
const PromiseWrapper_1 = require("./PromiseWrapper");
|
|
6
7
|
const cache_1 = require("./cache");
|
|
7
8
|
const logging_1 = require("./logging");
|
|
9
|
+
const check_1 = require("./check");
|
|
8
10
|
let networkRequestId = 0;
|
|
11
|
+
function maybeMakeNetworkRequest(environment, artifact, variables, fetchPolicy) {
|
|
12
|
+
switch (fetchPolicy) {
|
|
13
|
+
case 'Yes': {
|
|
14
|
+
return makeNetworkRequest(environment, artifact, variables);
|
|
15
|
+
}
|
|
16
|
+
case 'No': {
|
|
17
|
+
return [(0, PromiseWrapper_1.wrapResolvedValue)(undefined), () => { }];
|
|
18
|
+
}
|
|
19
|
+
case 'IfNecessary': {
|
|
20
|
+
const result = (0, check_1.check)(environment, artifact.normalizationAst, variables);
|
|
21
|
+
if (result.kind === 'EnoughData') {
|
|
22
|
+
return [(0, PromiseWrapper_1.wrapResolvedValue)(undefined), () => { }];
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
return makeNetworkRequest(environment, artifact, variables);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
9
30
|
function makeNetworkRequest(environment, artifact, variables) {
|
|
10
31
|
// TODO this should be a DataId and stored in the store
|
|
11
32
|
const myNetworkRequestId = networkRequestId + '';
|
package/dist/index.d.ts
CHANGED
|
@@ -9,6 +9,7 @@ export { readButDoNotEvaluate } from './core/read';
|
|
|
9
9
|
export { type ExtractSecondParam, type CombineWithIntrinsicAttributes, type Argument, type ArgumentName, type ArgumentValue, type Arguments, } from './core/util';
|
|
10
10
|
export { type FragmentReference, type Variables, type ExtractParameters, type ExtractData, stableIdForFragmentReference, } from './core/FragmentReference';
|
|
11
11
|
export { type LogMessage, type LogFunction, logMessage, registerLogger, } from './core/logging';
|
|
12
|
+
export { check, CheckResult, FetchOptions, FetchPolicy } from './core/check';
|
|
12
13
|
export { IsographEnvironmentProvider, useIsographEnvironment, type IsographEnvironmentProviderProps, } from './react/IsographEnvironmentProvider';
|
|
13
14
|
export { useImperativeReference } from './react/useImperativeReference';
|
|
14
15
|
export { FragmentReader } from './react/FragmentReader';
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.useImperativeLoadableField = exports.useConnectionSpecPagination = exports.useSkipLimitPagination = exports.useImperativeExposedMutationField = exports.useClientSideDefer = exports.RenderAfterCommit__DO_NOT_USE = exports.useRerenderOnChange = exports.useLazyReference = exports.useSubscribeToMultiple = exports.useReadAndSubscribe = exports.useResult = exports.FragmentReader = exports.useImperativeReference = exports.useIsographEnvironment = exports.IsographEnvironmentProvider = exports.registerLogger = exports.logMessage = exports.stableIdForFragmentReference = exports.readButDoNotEvaluate = exports.assertIsEntrypoint = exports.defaultMissingFieldHandler = exports.createIsographStore = exports.createIsographEnvironment = exports.ROOT_ID = exports.makeNetworkRequest = exports.normalizeData = exports.subscribe = exports.wrapPromise = exports.wrapResolvedValue = exports.getPromiseState = exports.readPromise = exports.garbageCollectEnvironment = exports.unretainQuery = exports.retainQuery = void 0;
|
|
3
|
+
exports.useImperativeLoadableField = exports.useConnectionSpecPagination = exports.useSkipLimitPagination = exports.useImperativeExposedMutationField = exports.useClientSideDefer = exports.RenderAfterCommit__DO_NOT_USE = exports.useRerenderOnChange = exports.useLazyReference = exports.useSubscribeToMultiple = exports.useReadAndSubscribe = exports.useResult = exports.FragmentReader = exports.useImperativeReference = exports.useIsographEnvironment = exports.IsographEnvironmentProvider = exports.check = exports.registerLogger = exports.logMessage = exports.stableIdForFragmentReference = exports.readButDoNotEvaluate = exports.assertIsEntrypoint = exports.defaultMissingFieldHandler = exports.createIsographStore = exports.createIsographEnvironment = exports.ROOT_ID = exports.makeNetworkRequest = exports.normalizeData = exports.subscribe = exports.wrapPromise = exports.wrapResolvedValue = exports.getPromiseState = exports.readPromise = exports.garbageCollectEnvironment = exports.unretainQuery = exports.retainQuery = void 0;
|
|
4
4
|
var garbageCollection_1 = require("./core/garbageCollection");
|
|
5
5
|
Object.defineProperty(exports, "retainQuery", { enumerable: true, get: function () { return garbageCollection_1.retainQuery; } });
|
|
6
6
|
Object.defineProperty(exports, "unretainQuery", { enumerable: true, get: function () { return garbageCollection_1.unretainQuery; } });
|
|
@@ -29,6 +29,8 @@ Object.defineProperty(exports, "stableIdForFragmentReference", { enumerable: tru
|
|
|
29
29
|
var logging_1 = require("./core/logging");
|
|
30
30
|
Object.defineProperty(exports, "logMessage", { enumerable: true, get: function () { return logging_1.logMessage; } });
|
|
31
31
|
Object.defineProperty(exports, "registerLogger", { enumerable: true, get: function () { return logging_1.registerLogger; } });
|
|
32
|
+
var check_1 = require("./core/check");
|
|
33
|
+
Object.defineProperty(exports, "check", { enumerable: true, get: function () { return check_1.check; } });
|
|
32
34
|
var IsographEnvironmentProvider_1 = require("./react/IsographEnvironmentProvider");
|
|
33
35
|
Object.defineProperty(exports, "IsographEnvironmentProvider", { enumerable: true, get: function () { return IsographEnvironmentProvider_1.IsographEnvironmentProvider; } });
|
|
34
36
|
Object.defineProperty(exports, "useIsographEnvironment", { enumerable: true, get: function () { return IsographEnvironmentProvider_1.useIsographEnvironment; } });
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { UnassignedState } from '@isograph/react-disposable-state';
|
|
2
2
|
import { IsographEntrypoint } from '../core/entrypoint';
|
|
3
3
|
import { FragmentReference, ExtractParameters } from '../core/FragmentReference';
|
|
4
|
+
import { FetchOptions } from '../core/check';
|
|
4
5
|
export declare function useImperativeReference<TReadFromStore extends {
|
|
5
6
|
parameters: object;
|
|
6
7
|
data: object;
|
|
7
8
|
}, TClientFieldValue>(entrypoint: IsographEntrypoint<TReadFromStore, TClientFieldValue>): {
|
|
8
9
|
fragmentReference: FragmentReference<TReadFromStore, TClientFieldValue> | UnassignedState;
|
|
9
|
-
loadFragmentReference: (variables: ExtractParameters<TReadFromStore
|
|
10
|
+
loadFragmentReference: (variables: ExtractParameters<TReadFromStore>, options?: FetchOptions) => void;
|
|
10
11
|
};
|
|
@@ -6,14 +6,17 @@ const IsographEnvironmentProvider_1 = require("./IsographEnvironmentProvider");
|
|
|
6
6
|
const IsographEnvironment_1 = require("../core/IsographEnvironment");
|
|
7
7
|
const makeNetworkRequest_1 = require("../core/makeNetworkRequest");
|
|
8
8
|
const PromiseWrapper_1 = require("../core/PromiseWrapper");
|
|
9
|
+
const check_1 = require("../core/check");
|
|
9
10
|
// TODO rename this to useImperativelyLoadedEntrypoint
|
|
10
11
|
function useImperativeReference(entrypoint) {
|
|
11
12
|
const { state, setState } = (0, react_disposable_state_1.useUpdatableDisposableState)();
|
|
12
13
|
const environment = (0, IsographEnvironmentProvider_1.useIsographEnvironment)();
|
|
13
14
|
return {
|
|
14
15
|
fragmentReference: state,
|
|
15
|
-
loadFragmentReference: (variables) => {
|
|
16
|
-
|
|
16
|
+
loadFragmentReference: (variables, options) => {
|
|
17
|
+
var _a;
|
|
18
|
+
const fetchPolicy = (_a = options === null || options === void 0 ? void 0 : options.fetchPolicy) !== null && _a !== void 0 ? _a : check_1.DEFAULT_FETCH_POLICY;
|
|
19
|
+
const [networkRequest, disposeNetworkRequest] = (0, makeNetworkRequest_1.maybeMakeNetworkRequest)(environment, entrypoint, variables, fetchPolicy);
|
|
17
20
|
setState([
|
|
18
21
|
{
|
|
19
22
|
kind: 'FragmentReference',
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { FragmentReference, ExtractParameters } from '../core/FragmentReference';
|
|
2
2
|
import { IsographEntrypoint } from '../core/entrypoint';
|
|
3
|
+
import { FetchOptions } from '../core/check';
|
|
3
4
|
export declare function useLazyReference<TReadFromStore extends {
|
|
4
5
|
parameters: object;
|
|
5
6
|
data: object;
|
|
6
|
-
}, TClientFieldValue>(entrypoint: IsographEntrypoint<TReadFromStore, TClientFieldValue>, variables: ExtractParameters<TReadFromStore
|
|
7
|
+
}, TClientFieldValue>(entrypoint: IsographEntrypoint<TReadFromStore, TClientFieldValue>, variables: ExtractParameters<TReadFromStore>, options?: FetchOptions): {
|
|
7
8
|
fragmentReference: FragmentReference<TReadFromStore, TClientFieldValue>;
|
|
8
9
|
};
|
|
@@ -5,7 +5,7 @@ const IsographEnvironmentProvider_1 = require("./IsographEnvironmentProvider");
|
|
|
5
5
|
const cache_1 = require("../core/cache");
|
|
6
6
|
const react_disposable_state_1 = require("@isograph/react-disposable-state");
|
|
7
7
|
const logging_1 = require("../core/logging");
|
|
8
|
-
function useLazyReference(entrypoint, variables) {
|
|
8
|
+
function useLazyReference(entrypoint, variables, options) {
|
|
9
9
|
const environment = (0, IsographEnvironmentProvider_1.useIsographEnvironment)();
|
|
10
10
|
if ((entrypoint === null || entrypoint === void 0 ? void 0 : entrypoint.kind) !== 'Entrypoint') {
|
|
11
11
|
// TODO have a separate error logger
|
|
@@ -14,7 +14,7 @@ function useLazyReference(entrypoint, variables) {
|
|
|
14
14
|
entrypoint,
|
|
15
15
|
});
|
|
16
16
|
}
|
|
17
|
-
const cache = (0, cache_1.getOrCreateCacheForArtifact)(environment, entrypoint, variables);
|
|
17
|
+
const cache = (0, cache_1.getOrCreateCacheForArtifact)(environment, entrypoint, variables, options);
|
|
18
18
|
return {
|
|
19
19
|
fragmentReference: (0, react_disposable_state_1.useLazyDisposableState)(cache).state,
|
|
20
20
|
};
|
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-1ed9144e",
|
|
4
4
|
"description": "Use Isograph with React",
|
|
5
5
|
"homepage": "https://isograph.dev",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -17,9 +17,9 @@
|
|
|
17
17
|
"tsc": "tsc"
|
|
18
18
|
},
|
|
19
19
|
"dependencies": {
|
|
20
|
-
"@isograph/disposable-types": "0.0.0-main-
|
|
21
|
-
"@isograph/react-disposable-state": "0.0.0-main-
|
|
22
|
-
"@isograph/reference-counted-pointer": "0.0.0-main-
|
|
20
|
+
"@isograph/disposable-types": "0.0.0-main-1ed9144e",
|
|
21
|
+
"@isograph/react-disposable-state": "0.0.0-main-1ed9144e",
|
|
22
|
+
"@isograph/reference-counted-pointer": "0.0.0-main-1ed9144e"
|
|
23
23
|
},
|
|
24
24
|
"peerDependencies": {
|
|
25
25
|
"react": "18.3.1"
|
package/src/core/cache.ts
CHANGED
|
@@ -30,9 +30,10 @@ import {
|
|
|
30
30
|
ExtractParameters,
|
|
31
31
|
} from './FragmentReference';
|
|
32
32
|
import { mergeObjectsUsingReaderAst } from './areEqualWithDeepComparison';
|
|
33
|
-
import {
|
|
33
|
+
import { maybeMakeNetworkRequest } from './makeNetworkRequest';
|
|
34
34
|
import { wrapResolvedValue } from './PromiseWrapper';
|
|
35
35
|
import { logMessage } from './logging';
|
|
36
|
+
import { DEFAULT_FETCH_POLICY, FetchOptions } from './check';
|
|
36
37
|
|
|
37
38
|
const TYPENAME_FIELD_NAME = '__typename';
|
|
38
39
|
|
|
@@ -87,14 +88,18 @@ export function getOrCreateCacheForArtifact<
|
|
|
87
88
|
environment: IsographEnvironment,
|
|
88
89
|
entrypoint: IsographEntrypoint<TReadFromStore, TClientFieldValue>,
|
|
89
90
|
variables: ExtractParameters<TReadFromStore>,
|
|
91
|
+
options?: FetchOptions,
|
|
90
92
|
): ParentCache<FragmentReference<TReadFromStore, TClientFieldValue>> {
|
|
91
93
|
const cacheKey = entrypoint.queryText + JSON.stringify(stableCopy(variables));
|
|
92
94
|
const factory = () => {
|
|
93
|
-
const
|
|
95
|
+
const fetchPolicy = options?.fetchPolicy ?? DEFAULT_FETCH_POLICY;
|
|
96
|
+
const [networkRequest, disposeNetworkRequest] = maybeMakeNetworkRequest(
|
|
94
97
|
environment,
|
|
95
98
|
entrypoint,
|
|
96
99
|
variables,
|
|
100
|
+
fetchPolicy,
|
|
97
101
|
);
|
|
102
|
+
|
|
98
103
|
const itemCleanupPair: ItemCleanupPair<
|
|
99
104
|
FragmentReference<TReadFromStore, TClientFieldValue>
|
|
100
105
|
> = [
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
import { getParentRecordKey } from './cache';
|
|
2
|
+
import { NormalizationAst } from './entrypoint';
|
|
3
|
+
import { Variables } from './FragmentReference';
|
|
4
|
+
import {
|
|
5
|
+
getLink,
|
|
6
|
+
IsographEnvironment,
|
|
7
|
+
Link,
|
|
8
|
+
ROOT_ID,
|
|
9
|
+
StoreRecord,
|
|
10
|
+
} from './IsographEnvironment';
|
|
11
|
+
import { logMessage } from './logging';
|
|
12
|
+
|
|
13
|
+
export type FetchPolicy = 'Yes' | 'No' | 'IfNecessary';
|
|
14
|
+
|
|
15
|
+
export const DEFAULT_FETCH_POLICY: FetchPolicy = 'IfNecessary';
|
|
16
|
+
|
|
17
|
+
export type FetchOptions = {
|
|
18
|
+
fetchPolicy?: FetchPolicy;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export type CheckResult =
|
|
22
|
+
| {
|
|
23
|
+
kind: 'EnoughData';
|
|
24
|
+
}
|
|
25
|
+
| {
|
|
26
|
+
kind: 'MissingData';
|
|
27
|
+
record: Link;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export function check(
|
|
31
|
+
environment: IsographEnvironment,
|
|
32
|
+
normalizationAst: NormalizationAst,
|
|
33
|
+
variables: Variables,
|
|
34
|
+
): CheckResult {
|
|
35
|
+
const checkResult = checkFromRecord(
|
|
36
|
+
environment,
|
|
37
|
+
normalizationAst,
|
|
38
|
+
variables,
|
|
39
|
+
environment.store[ROOT_ID],
|
|
40
|
+
ROOT_ID,
|
|
41
|
+
);
|
|
42
|
+
logMessage(environment, {
|
|
43
|
+
kind: 'EnvironmentCheck',
|
|
44
|
+
result: checkResult,
|
|
45
|
+
});
|
|
46
|
+
return checkResult;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function checkFromRecord(
|
|
50
|
+
environment: IsographEnvironment,
|
|
51
|
+
normalizationAst: NormalizationAst,
|
|
52
|
+
variables: Variables,
|
|
53
|
+
record: StoreRecord,
|
|
54
|
+
backupId: string,
|
|
55
|
+
): CheckResult {
|
|
56
|
+
normalizationAstLoop: for (const normalizationAstNode of normalizationAst) {
|
|
57
|
+
switch (normalizationAstNode.kind) {
|
|
58
|
+
case 'Scalar': {
|
|
59
|
+
const parentRecordKey = getParentRecordKey(
|
|
60
|
+
normalizationAstNode,
|
|
61
|
+
variables,
|
|
62
|
+
);
|
|
63
|
+
const scalarValue = record[parentRecordKey];
|
|
64
|
+
|
|
65
|
+
// null means the value is known to be missing, so it must
|
|
66
|
+
// be exactly undefined
|
|
67
|
+
if (scalarValue === undefined) {
|
|
68
|
+
return {
|
|
69
|
+
kind: 'MissingData',
|
|
70
|
+
record: {
|
|
71
|
+
__link: record.id ?? backupId,
|
|
72
|
+
},
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
continue normalizationAstLoop;
|
|
76
|
+
}
|
|
77
|
+
case 'Linked': {
|
|
78
|
+
const parentRecordKey = getParentRecordKey(
|
|
79
|
+
normalizationAstNode,
|
|
80
|
+
variables,
|
|
81
|
+
);
|
|
82
|
+
|
|
83
|
+
const linkedValue = record[parentRecordKey];
|
|
84
|
+
|
|
85
|
+
if (linkedValue === undefined) {
|
|
86
|
+
return {
|
|
87
|
+
kind: 'MissingData',
|
|
88
|
+
record: {
|
|
89
|
+
__link: record.id ?? backupId,
|
|
90
|
+
},
|
|
91
|
+
};
|
|
92
|
+
} else if (linkedValue === null) {
|
|
93
|
+
continue;
|
|
94
|
+
} else if (Array.isArray(linkedValue)) {
|
|
95
|
+
arrayItemsLoop: for (const item of linkedValue) {
|
|
96
|
+
const link = getLink(item);
|
|
97
|
+
if (link === null) {
|
|
98
|
+
throw new Error(
|
|
99
|
+
'Unexpected non-link in the Isograph store. ' +
|
|
100
|
+
'This is indicative of a bug in Isograph.',
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const linkedRecord = environment.store[link.__link];
|
|
105
|
+
|
|
106
|
+
if (linkedRecord === undefined) {
|
|
107
|
+
return {
|
|
108
|
+
kind: 'MissingData',
|
|
109
|
+
record: link,
|
|
110
|
+
};
|
|
111
|
+
} else if (linkedRecord === null) {
|
|
112
|
+
continue arrayItemsLoop;
|
|
113
|
+
} else {
|
|
114
|
+
// TODO in __DEV__ assert linkedRecord is an object
|
|
115
|
+
const result = checkFromRecord(
|
|
116
|
+
environment,
|
|
117
|
+
normalizationAstNode.selections,
|
|
118
|
+
variables,
|
|
119
|
+
linkedRecord,
|
|
120
|
+
// TODO this seems likely to be wrong
|
|
121
|
+
backupId + '.' + parentRecordKey,
|
|
122
|
+
);
|
|
123
|
+
|
|
124
|
+
if (result.kind === 'MissingData') {
|
|
125
|
+
return result;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
} else {
|
|
130
|
+
const link = getLink(linkedValue);
|
|
131
|
+
if (link === null) {
|
|
132
|
+
throw new Error(
|
|
133
|
+
'Unexpected non-link in the Isograph store. ' +
|
|
134
|
+
'This is indicative of a bug in Isograph.',
|
|
135
|
+
);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const linkedRecord = environment.store[link.__link];
|
|
139
|
+
|
|
140
|
+
if (linkedRecord === undefined) {
|
|
141
|
+
return {
|
|
142
|
+
kind: 'MissingData',
|
|
143
|
+
record: link,
|
|
144
|
+
};
|
|
145
|
+
} else if (linkedRecord === null) {
|
|
146
|
+
continue normalizationAstLoop;
|
|
147
|
+
} else {
|
|
148
|
+
// TODO in __DEV__ assert linkedRecord is an object
|
|
149
|
+
const result = checkFromRecord(
|
|
150
|
+
environment,
|
|
151
|
+
normalizationAstNode.selections,
|
|
152
|
+
variables,
|
|
153
|
+
linkedRecord,
|
|
154
|
+
// TODO this seems likely to be wrong
|
|
155
|
+
backupId + '.' + parentRecordKey,
|
|
156
|
+
);
|
|
157
|
+
|
|
158
|
+
if (result.kind === 'MissingData') {
|
|
159
|
+
return result;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
continue normalizationAstLoop;
|
|
165
|
+
}
|
|
166
|
+
case 'InlineFragment': {
|
|
167
|
+
const existingRecordTypename = record['__typename'];
|
|
168
|
+
|
|
169
|
+
if (
|
|
170
|
+
existingRecordTypename == null ||
|
|
171
|
+
existingRecordTypename !== normalizationAstNode.type
|
|
172
|
+
) {
|
|
173
|
+
return {
|
|
174
|
+
kind: 'MissingData',
|
|
175
|
+
record: {
|
|
176
|
+
__link: record.id ?? backupId,
|
|
177
|
+
},
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
const result = checkFromRecord(
|
|
182
|
+
environment,
|
|
183
|
+
normalizationAstNode.selections,
|
|
184
|
+
variables,
|
|
185
|
+
record,
|
|
186
|
+
backupId,
|
|
187
|
+
);
|
|
188
|
+
|
|
189
|
+
if (result.kind === 'MissingData') {
|
|
190
|
+
return result;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
continue normalizationAstLoop;
|
|
194
|
+
}
|
|
195
|
+
default: {
|
|
196
|
+
let _: never = normalizationAstNode;
|
|
197
|
+
_;
|
|
198
|
+
throw new Error(
|
|
199
|
+
'Unexpected case. This is indicative of a bug in Isograph.',
|
|
200
|
+
);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
return {
|
|
206
|
+
kind: 'EnoughData',
|
|
207
|
+
};
|
|
208
|
+
}
|
package/src/core/logging.ts
CHANGED
|
@@ -14,6 +14,7 @@ import { FragmentReference, Variables } from './FragmentReference';
|
|
|
14
14
|
import { NetworkResponseObject } from './cache';
|
|
15
15
|
import { Arguments } from './util';
|
|
16
16
|
import { ReadDataResult } from './read';
|
|
17
|
+
import { CheckResult } from './check';
|
|
17
18
|
|
|
18
19
|
export type LogMessage =
|
|
19
20
|
| {
|
|
@@ -74,6 +75,10 @@ export type LogMessage =
|
|
|
74
75
|
| {
|
|
75
76
|
kind: 'NonEntrypointReceived';
|
|
76
77
|
entrypoint: any;
|
|
78
|
+
}
|
|
79
|
+
| {
|
|
80
|
+
kind: 'EnvironmentCheck';
|
|
81
|
+
result: CheckResult;
|
|
77
82
|
};
|
|
78
83
|
|
|
79
84
|
export type LogFunction = (logMessage: LogMessage) => void;
|
|
@@ -11,12 +11,42 @@ import {
|
|
|
11
11
|
unretainQuery,
|
|
12
12
|
} from './garbageCollection';
|
|
13
13
|
import { IsographEnvironment } from './IsographEnvironment';
|
|
14
|
-
import {
|
|
14
|
+
import {
|
|
15
|
+
AnyError,
|
|
16
|
+
PromiseWrapper,
|
|
17
|
+
wrapPromise,
|
|
18
|
+
wrapResolvedValue,
|
|
19
|
+
} from './PromiseWrapper';
|
|
15
20
|
import { normalizeData } from './cache';
|
|
16
21
|
import { logMessage } from './logging';
|
|
22
|
+
import { check, FetchPolicy } from './check';
|
|
17
23
|
|
|
18
24
|
let networkRequestId = 0;
|
|
19
25
|
|
|
26
|
+
export function maybeMakeNetworkRequest(
|
|
27
|
+
environment: IsographEnvironment,
|
|
28
|
+
artifact: RefetchQueryNormalizationArtifact | IsographEntrypoint<any, any>,
|
|
29
|
+
variables: Variables,
|
|
30
|
+
fetchPolicy: FetchPolicy,
|
|
31
|
+
): ItemCleanupPair<PromiseWrapper<void, AnyError>> {
|
|
32
|
+
switch (fetchPolicy) {
|
|
33
|
+
case 'Yes': {
|
|
34
|
+
return makeNetworkRequest(environment, artifact, variables);
|
|
35
|
+
}
|
|
36
|
+
case 'No': {
|
|
37
|
+
return [wrapResolvedValue(undefined), () => {}];
|
|
38
|
+
}
|
|
39
|
+
case 'IfNecessary': {
|
|
40
|
+
const result = check(environment, artifact.normalizationAst, variables);
|
|
41
|
+
if (result.kind === 'EnoughData') {
|
|
42
|
+
return [wrapResolvedValue(undefined), () => {}];
|
|
43
|
+
} else {
|
|
44
|
+
return makeNetworkRequest(environment, artifact, variables);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
20
50
|
export function makeNetworkRequest(
|
|
21
51
|
environment: IsographEnvironment,
|
|
22
52
|
artifact: RefetchQueryNormalizationArtifact | IsographEntrypoint<any, any>,
|
package/src/core/read.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { CleanupFn } from '@isograph/isograph-disposable-types/dist';
|
|
2
1
|
import { getParentRecordKey, onNextChangeToRecord } from './cache';
|
|
3
2
|
import { getOrCreateCachedComponent } from './componentCache';
|
|
4
3
|
import {
|
|
@@ -30,6 +29,7 @@ import {
|
|
|
30
29
|
import { ReaderAst } from './reader';
|
|
31
30
|
import { Arguments } from './util';
|
|
32
31
|
import { logMessage } from './logging';
|
|
32
|
+
import { CleanupFn } from '@isograph/disposable-types';
|
|
33
33
|
|
|
34
34
|
export type WithEncounteredRecords<T> = {
|
|
35
35
|
readonly encounteredRecords: Set<DataId>;
|
package/src/index.ts
CHANGED
|
@@ -9,8 +9,9 @@ import {
|
|
|
9
9
|
} from '../core/FragmentReference';
|
|
10
10
|
import { useIsographEnvironment } from './IsographEnvironmentProvider';
|
|
11
11
|
import { ROOT_ID } from '../core/IsographEnvironment';
|
|
12
|
-
import {
|
|
12
|
+
import { maybeMakeNetworkRequest } from '../core/makeNetworkRequest';
|
|
13
13
|
import { wrapResolvedValue } from '../core/PromiseWrapper';
|
|
14
|
+
import { DEFAULT_FETCH_POLICY, FetchOptions } from '../core/check';
|
|
14
15
|
|
|
15
16
|
// TODO rename this to useImperativelyLoadedEntrypoint
|
|
16
17
|
|
|
@@ -23,7 +24,10 @@ export function useImperativeReference<
|
|
|
23
24
|
fragmentReference:
|
|
24
25
|
| FragmentReference<TReadFromStore, TClientFieldValue>
|
|
25
26
|
| UnassignedState;
|
|
26
|
-
loadFragmentReference: (
|
|
27
|
+
loadFragmentReference: (
|
|
28
|
+
variables: ExtractParameters<TReadFromStore>,
|
|
29
|
+
options?: FetchOptions,
|
|
30
|
+
) => void;
|
|
27
31
|
} {
|
|
28
32
|
const { state, setState } =
|
|
29
33
|
useUpdatableDisposableState<
|
|
@@ -32,11 +36,16 @@ export function useImperativeReference<
|
|
|
32
36
|
const environment = useIsographEnvironment();
|
|
33
37
|
return {
|
|
34
38
|
fragmentReference: state,
|
|
35
|
-
loadFragmentReference: (
|
|
36
|
-
|
|
39
|
+
loadFragmentReference: (
|
|
40
|
+
variables: ExtractParameters<TReadFromStore>,
|
|
41
|
+
options?: FetchOptions,
|
|
42
|
+
) => {
|
|
43
|
+
const fetchPolicy = options?.fetchPolicy ?? DEFAULT_FETCH_POLICY;
|
|
44
|
+
const [networkRequest, disposeNetworkRequest] = maybeMakeNetworkRequest(
|
|
37
45
|
environment,
|
|
38
46
|
entrypoint,
|
|
39
47
|
variables,
|
|
48
|
+
fetchPolicy,
|
|
40
49
|
);
|
|
41
50
|
setState([
|
|
42
51
|
{
|
|
@@ -7,6 +7,7 @@ import { IsographEntrypoint } from '../core/entrypoint';
|
|
|
7
7
|
import { getOrCreateCacheForArtifact } from '../core/cache';
|
|
8
8
|
import { useLazyDisposableState } from '@isograph/react-disposable-state';
|
|
9
9
|
import { logMessage } from '../core/logging';
|
|
10
|
+
import { FetchOptions } from '../core/check';
|
|
10
11
|
|
|
11
12
|
export function useLazyReference<
|
|
12
13
|
TReadFromStore extends { parameters: object; data: object },
|
|
@@ -14,6 +15,7 @@ export function useLazyReference<
|
|
|
14
15
|
>(
|
|
15
16
|
entrypoint: IsographEntrypoint<TReadFromStore, TClientFieldValue>,
|
|
16
17
|
variables: ExtractParameters<TReadFromStore>,
|
|
18
|
+
options?: FetchOptions,
|
|
17
19
|
): {
|
|
18
20
|
fragmentReference: FragmentReference<TReadFromStore, TClientFieldValue>;
|
|
19
21
|
} {
|
|
@@ -27,7 +29,12 @@ export function useLazyReference<
|
|
|
27
29
|
});
|
|
28
30
|
}
|
|
29
31
|
|
|
30
|
-
const cache = getOrCreateCacheForArtifact(
|
|
32
|
+
const cache = getOrCreateCacheForArtifact(
|
|
33
|
+
environment,
|
|
34
|
+
entrypoint,
|
|
35
|
+
variables,
|
|
36
|
+
options,
|
|
37
|
+
);
|
|
31
38
|
|
|
32
39
|
return {
|
|
33
40
|
fragmentReference: useLazyDisposableState(cache).state,
|