relay-runtime 8.0.0 → 10.0.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/handlers/RelayDefaultHandlerProvider.js.flow +41 -0
- package/handlers/connection/ConnectionHandler.js.flow +549 -0
- package/handlers/connection/ConnectionInterface.js.flow +92 -0
- package/handlers/connection/MutationHandlers.js.flow +88 -0
- package/index.js +1 -1
- package/index.js.flow +320 -0
- package/lib/handlers/RelayDefaultHandlerProvider.js +13 -2
- package/lib/handlers/connection/{RelayConnectionHandler.js → ConnectionHandler.js} +33 -35
- package/lib/handlers/connection/{RelayConnectionInterface.js → ConnectionInterface.js} +2 -2
- package/lib/handlers/connection/MutationHandlers.js +86 -0
- package/lib/index.js +15 -19
- package/lib/mutations/RelayDeclarativeMutationConfig.js +29 -52
- package/lib/mutations/RelayRecordProxy.js +1 -3
- package/lib/mutations/RelayRecordSourceMutator.js +2 -9
- package/lib/mutations/RelayRecordSourceProxy.js +2 -4
- package/lib/mutations/RelayRecordSourceSelectorProxy.js +1 -13
- package/lib/mutations/commitMutation.js +13 -3
- package/lib/mutations/validateMutation.js +16 -9
- package/lib/network/RelayObservable.js +9 -9
- package/lib/network/RelayQueryResponseCache.js +8 -6
- package/lib/query/PreloadableQueryRegistry.js +70 -0
- package/lib/query/fetchQueryInternal.js +31 -23
- package/lib/store/DataChecker.js +122 -110
- package/lib/store/RelayConcreteVariables.js +6 -2
- package/lib/store/RelayModernEnvironment.js +121 -67
- package/lib/store/RelayModernFragmentSpecResolver.js +12 -16
- package/lib/store/RelayModernQueryExecutor.js +389 -314
- package/lib/store/RelayModernRecord.js +14 -9
- package/lib/store/RelayModernSelector.js +7 -3
- package/lib/store/RelayModernStore.js +289 -484
- package/lib/store/RelayOperationTracker.js +35 -78
- package/lib/store/RelayOptimisticRecordSource.js +7 -5
- package/lib/store/RelayPublishQueue.js +6 -33
- package/lib/store/RelayReader.js +113 -45
- package/lib/store/RelayRecordSource.js +2 -9
- package/lib/store/RelayRecordSourceMapImpl.js +13 -18
- package/lib/store/RelayReferenceMarker.js +40 -60
- package/lib/store/RelayResponseNormalizer.js +158 -193
- package/lib/store/RelayStoreUtils.js +1 -0
- package/lib/store/StoreInspector.js +8 -8
- package/lib/store/TypeID.js +28 -0
- package/lib/store/cloneRelayScalarHandleSourceField.js +44 -0
- package/lib/store/normalizeRelayPayload.js +6 -2
- package/lib/store/readInlineData.js +1 -1
- package/lib/subscription/requestSubscription.js +5 -3
- package/lib/util/RelayConcreteNode.js +9 -6
- package/lib/util/RelayError.js +39 -9
- package/lib/util/RelayFeatureFlags.js +2 -5
- package/lib/util/RelayReplaySubject.js +3 -3
- package/lib/util/createPayloadFor3DField.js +7 -2
- package/lib/util/getRequestIdentifier.js +2 -2
- package/lib/util/recycleNodesInto.js +2 -6
- package/mutations/RelayDeclarativeMutationConfig.js.flow +380 -0
- package/mutations/RelayRecordProxy.js.flow +165 -0
- package/mutations/RelayRecordSourceMutator.js.flow +238 -0
- package/mutations/RelayRecordSourceProxy.js.flow +164 -0
- package/mutations/RelayRecordSourceSelectorProxy.js.flow +119 -0
- package/mutations/applyOptimisticMutation.js.flow +76 -0
- package/mutations/commitLocalUpdate.js.flow +24 -0
- package/mutations/commitMutation.js.flow +182 -0
- package/mutations/validateMutation.js.flow +213 -0
- package/network/ConvertToExecuteFunction.js.flow +49 -0
- package/network/RelayNetwork.js.flow +84 -0
- package/network/RelayNetworkTypes.js.flow +123 -0
- package/network/RelayObservable.js.flow +634 -0
- package/network/RelayQueryResponseCache.js.flow +111 -0
- package/package.json +1 -1
- package/query/GraphQLTag.js.flow +166 -0
- package/query/PreloadableQueryRegistry.js.flow +65 -0
- package/query/fetchQuery.js.flow +47 -0
- package/query/fetchQueryInternal.js.flow +348 -0
- package/relay-runtime.js +2 -2
- package/relay-runtime.min.js +2 -2
- package/store/ClientID.js.flow +43 -0
- package/store/DataChecker.js.flow +502 -0
- package/store/RelayConcreteVariables.js.flow +96 -0
- package/store/RelayModernEnvironment.js.flow +551 -0
- package/store/RelayModernFragmentSpecResolver.js.flow +426 -0
- package/store/RelayModernOperationDescriptor.js.flow +88 -0
- package/store/RelayModernQueryExecutor.js.flow +1321 -0
- package/store/RelayModernRecord.js.flow +403 -0
- package/store/RelayModernSelector.js.flow +455 -0
- package/store/RelayModernStore.js.flow +842 -0
- package/store/RelayOperationTracker.js.flow +164 -0
- package/store/RelayOptimisticRecordSource.js.flow +119 -0
- package/store/RelayPublishQueue.js.flow +401 -0
- package/store/RelayReader.js.flow +473 -0
- package/store/RelayRecordSource.js.flow +29 -0
- package/store/RelayRecordSourceMapImpl.js.flow +87 -0
- package/store/RelayRecordState.js.flow +37 -0
- package/store/RelayReferenceMarker.js.flow +257 -0
- package/store/RelayResponseNormalizer.js.flow +680 -0
- package/store/RelayStoreTypes.js.flow +899 -0
- package/store/RelayStoreUtils.js.flow +219 -0
- package/store/StoreInspector.js.flow +171 -0
- package/store/TypeID.js.flow +28 -0
- package/store/ViewerPattern.js.flow +26 -0
- package/store/cloneRelayHandleSourceField.js.flow +66 -0
- package/store/cloneRelayScalarHandleSourceField.js.flow +62 -0
- package/store/createFragmentSpecResolver.js.flow +55 -0
- package/store/createRelayContext.js.flow +44 -0
- package/store/defaultGetDataID.js.flow +27 -0
- package/store/hasOverlappingIDs.js.flow +34 -0
- package/store/isRelayModernEnvironment.js.flow +27 -0
- package/store/normalizeRelayPayload.js.flow +51 -0
- package/store/readInlineData.js.flow +75 -0
- package/subscription/requestSubscription.js.flow +100 -0
- package/util/JSResourceTypes.flow.js.flow +20 -0
- package/util/NormalizationNode.js.flow +198 -0
- package/util/ReaderNode.js.flow +208 -0
- package/util/RelayConcreteNode.js.flow +93 -0
- package/util/RelayDefaultHandleKey.js.flow +17 -0
- package/util/RelayError.js.flow +62 -0
- package/util/RelayFeatureFlags.js.flow +30 -0
- package/util/RelayProfiler.js.flow +284 -0
- package/util/RelayReplaySubject.js.flow +135 -0
- package/util/RelayRuntimeTypes.js.flow +72 -0
- package/util/createPayloadFor3DField.js.flow +43 -0
- package/util/deepFreeze.js.flow +36 -0
- package/util/generateID.js.flow +21 -0
- package/util/getFragmentIdentifier.js.flow +52 -0
- package/util/getRelayHandleKey.js.flow +41 -0
- package/util/getRequestIdentifier.js.flow +42 -0
- package/util/isPromise.js.flow +21 -0
- package/util/isScalarAndEqual.js.flow +26 -0
- package/util/recycleNodesInto.js.flow +76 -0
- package/util/resolveImmediate.js.flow +30 -0
- package/util/stableCopy.js.flow +35 -0
- package/lib/handlers/RelayDefaultMissingFieldHandlers.js +0 -26
- package/lib/handlers/getRelayDefaultMissingFieldHandlers.js +0 -36
- package/lib/query/RelayModernGraphQLTag.js +0 -104
- package/lib/store/RelayConnection.js +0 -37
- package/lib/store/RelayConnectionResolver.js +0 -178
- package/lib/store/RelayRecordSourceObjectImpl.js +0 -79
- package/lib/util/getFragmentSpecIdentifier.js +0 -27
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
7
|
+
* @flow strict-local
|
|
8
|
+
* @format
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
// flowlint ambiguous-object-type:error
|
|
12
|
+
|
|
13
|
+
'use strict';
|
|
14
|
+
|
|
15
|
+
const invariant = require('invariant');
|
|
16
|
+
|
|
17
|
+
const {generateClientID} = require('../store/ClientID');
|
|
18
|
+
const {getStableStorageKey} = require('../store/RelayStoreUtils');
|
|
19
|
+
|
|
20
|
+
import type {RecordProxy} from '../store/RelayStoreTypes';
|
|
21
|
+
import type {Arguments} from '../store/RelayStoreUtils';
|
|
22
|
+
import type {DataID} from '../util/RelayRuntimeTypes';
|
|
23
|
+
import type RelayRecordSourceMutator from './RelayRecordSourceMutator';
|
|
24
|
+
import type RelayRecordSourceProxy from './RelayRecordSourceProxy';
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* @internal
|
|
28
|
+
*
|
|
29
|
+
* A helper class for manipulating a given record from a record source via an
|
|
30
|
+
* imperative/OO-style API.
|
|
31
|
+
*/
|
|
32
|
+
class RelayRecordProxy implements RecordProxy {
|
|
33
|
+
_dataID: DataID;
|
|
34
|
+
_mutator: RelayRecordSourceMutator;
|
|
35
|
+
_source: RelayRecordSourceProxy;
|
|
36
|
+
|
|
37
|
+
constructor(
|
|
38
|
+
source: RelayRecordSourceProxy,
|
|
39
|
+
mutator: RelayRecordSourceMutator,
|
|
40
|
+
dataID: DataID,
|
|
41
|
+
) {
|
|
42
|
+
this._dataID = dataID;
|
|
43
|
+
this._mutator = mutator;
|
|
44
|
+
this._source = source;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
copyFieldsFrom(source: RecordProxy): void {
|
|
48
|
+
this._mutator.copyFields(source.getDataID(), this._dataID);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
getDataID(): DataID {
|
|
52
|
+
return this._dataID;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
getType(): string {
|
|
56
|
+
const type = this._mutator.getType(this._dataID);
|
|
57
|
+
invariant(
|
|
58
|
+
type != null,
|
|
59
|
+
'RelayRecordProxy: Cannot get the type of deleted record `%s`.',
|
|
60
|
+
this._dataID,
|
|
61
|
+
);
|
|
62
|
+
return type;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
getValue(name: string, args?: ?Arguments): mixed {
|
|
66
|
+
const storageKey = getStableStorageKey(name, args);
|
|
67
|
+
return this._mutator.getValue(this._dataID, storageKey);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
setValue(value: mixed, name: string, args?: ?Arguments): RecordProxy {
|
|
71
|
+
invariant(
|
|
72
|
+
isValidLeafValue(value),
|
|
73
|
+
'RelayRecordProxy#setValue(): Expected a scalar or array of scalars, ' +
|
|
74
|
+
'got `%s`.',
|
|
75
|
+
JSON.stringify(value),
|
|
76
|
+
);
|
|
77
|
+
const storageKey = getStableStorageKey(name, args);
|
|
78
|
+
this._mutator.setValue(this._dataID, storageKey, value);
|
|
79
|
+
return this;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
getLinkedRecord(name: string, args?: ?Arguments): ?RecordProxy {
|
|
83
|
+
const storageKey = getStableStorageKey(name, args);
|
|
84
|
+
const linkedID = this._mutator.getLinkedRecordID(this._dataID, storageKey);
|
|
85
|
+
return linkedID != null ? this._source.get(linkedID) : linkedID;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
setLinkedRecord(
|
|
89
|
+
record: RecordProxy,
|
|
90
|
+
name: string,
|
|
91
|
+
args?: ?Arguments,
|
|
92
|
+
): RecordProxy {
|
|
93
|
+
invariant(
|
|
94
|
+
record instanceof RelayRecordProxy,
|
|
95
|
+
'RelayRecordProxy#setLinkedRecord(): Expected a record, got `%s`.',
|
|
96
|
+
record,
|
|
97
|
+
);
|
|
98
|
+
const storageKey = getStableStorageKey(name, args);
|
|
99
|
+
const linkedID = record.getDataID();
|
|
100
|
+
this._mutator.setLinkedRecordID(this._dataID, storageKey, linkedID);
|
|
101
|
+
return this;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
getOrCreateLinkedRecord(
|
|
105
|
+
name: string,
|
|
106
|
+
typeName: string,
|
|
107
|
+
args?: ?Arguments,
|
|
108
|
+
): RecordProxy {
|
|
109
|
+
let linkedRecord = this.getLinkedRecord(name, args);
|
|
110
|
+
if (!linkedRecord) {
|
|
111
|
+
const storageKey = getStableStorageKey(name, args);
|
|
112
|
+
const clientID = generateClientID(this.getDataID(), storageKey);
|
|
113
|
+
// NOTE: it's possible that a client record for this field exists
|
|
114
|
+
// but the field itself was unset.
|
|
115
|
+
linkedRecord =
|
|
116
|
+
this._source.get(clientID) ?? this._source.create(clientID, typeName);
|
|
117
|
+
this.setLinkedRecord(linkedRecord, name, args);
|
|
118
|
+
}
|
|
119
|
+
return linkedRecord;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
getLinkedRecords(name: string, args?: ?Arguments): ?Array<?RecordProxy> {
|
|
123
|
+
const storageKey = getStableStorageKey(name, args);
|
|
124
|
+
const linkedIDs = this._mutator.getLinkedRecordIDs(
|
|
125
|
+
this._dataID,
|
|
126
|
+
storageKey,
|
|
127
|
+
);
|
|
128
|
+
if (linkedIDs == null) {
|
|
129
|
+
return linkedIDs;
|
|
130
|
+
}
|
|
131
|
+
return linkedIDs.map(linkedID => {
|
|
132
|
+
return linkedID != null ? this._source.get(linkedID) : linkedID;
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
setLinkedRecords(
|
|
137
|
+
records: Array<?RecordProxy>,
|
|
138
|
+
name: string,
|
|
139
|
+
args?: ?Arguments,
|
|
140
|
+
): RecordProxy {
|
|
141
|
+
invariant(
|
|
142
|
+
Array.isArray(records),
|
|
143
|
+
'RelayRecordProxy#setLinkedRecords(): Expected records to be an array, got `%s`.',
|
|
144
|
+
records,
|
|
145
|
+
);
|
|
146
|
+
const storageKey = getStableStorageKey(name, args);
|
|
147
|
+
const linkedIDs = records.map(record => record && record.getDataID());
|
|
148
|
+
this._mutator.setLinkedRecordIDs(this._dataID, storageKey, linkedIDs);
|
|
149
|
+
return this;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
invalidateRecord(): void {
|
|
153
|
+
this._source.markIDForInvalidation(this._dataID);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
function isValidLeafValue(value: mixed): boolean {
|
|
158
|
+
return (
|
|
159
|
+
value == null ||
|
|
160
|
+
typeof value !== 'object' ||
|
|
161
|
+
(Array.isArray(value) && value.every(isValidLeafValue))
|
|
162
|
+
);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
module.exports = RelayRecordProxy;
|
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
7
|
+
* @flow strict-local
|
|
8
|
+
* @format
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
// flowlint ambiguous-object-type:error
|
|
12
|
+
|
|
13
|
+
'use strict';
|
|
14
|
+
|
|
15
|
+
const RelayModernRecord = require('../store/RelayModernRecord');
|
|
16
|
+
|
|
17
|
+
const invariant = require('invariant');
|
|
18
|
+
|
|
19
|
+
const {EXISTENT} = require('../store/RelayRecordState');
|
|
20
|
+
|
|
21
|
+
import type {RecordState} from '../store/RelayRecordState';
|
|
22
|
+
import type {
|
|
23
|
+
MutableRecordSource,
|
|
24
|
+
Record,
|
|
25
|
+
RecordSource,
|
|
26
|
+
} from '../store/RelayStoreTypes';
|
|
27
|
+
import type {DataID} from '../util/RelayRuntimeTypes';
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* @internal
|
|
31
|
+
*
|
|
32
|
+
* Wrapper API that is an amalgam of the `RelayModernRecord` API and
|
|
33
|
+
* `MutableRecordSource` interface, implementing copy-on-write semantics for records
|
|
34
|
+
* in a record source.
|
|
35
|
+
*
|
|
36
|
+
* Modifications are applied to fresh copies of records:
|
|
37
|
+
* - Records in `base` are never modified.
|
|
38
|
+
* - Modifications cause a fresh version of a record to be created in `sink`.
|
|
39
|
+
* These sink records contain only modified fields.
|
|
40
|
+
*/
|
|
41
|
+
class RelayRecordSourceMutator {
|
|
42
|
+
__sources: Array<RecordSource>;
|
|
43
|
+
_base: RecordSource;
|
|
44
|
+
_sink: MutableRecordSource;
|
|
45
|
+
|
|
46
|
+
constructor(base: RecordSource, sink: MutableRecordSource) {
|
|
47
|
+
this.__sources = [sink, base];
|
|
48
|
+
this._base = base;
|
|
49
|
+
this._sink = sink;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* **UNSTABLE**
|
|
54
|
+
* This method is likely to be removed in an upcoming release
|
|
55
|
+
* and should not be relied upon.
|
|
56
|
+
* TODO T41593196: Remove unstable_getRawRecordWithChanges
|
|
57
|
+
*/
|
|
58
|
+
unstable_getRawRecordWithChanges(dataID: DataID): ?Record {
|
|
59
|
+
const baseRecord = this._base.get(dataID);
|
|
60
|
+
const sinkRecord = this._sink.get(dataID);
|
|
61
|
+
if (sinkRecord === undefined) {
|
|
62
|
+
if (baseRecord == null) {
|
|
63
|
+
return baseRecord;
|
|
64
|
+
}
|
|
65
|
+
const nextRecord = RelayModernRecord.clone(baseRecord);
|
|
66
|
+
if (__DEV__) {
|
|
67
|
+
// Prevent mutation of a record from outside the store.
|
|
68
|
+
RelayModernRecord.freeze(nextRecord);
|
|
69
|
+
}
|
|
70
|
+
return nextRecord;
|
|
71
|
+
} else if (sinkRecord === null) {
|
|
72
|
+
return null;
|
|
73
|
+
} else if (baseRecord != null) {
|
|
74
|
+
const nextRecord = RelayModernRecord.update(baseRecord, sinkRecord);
|
|
75
|
+
if (__DEV__) {
|
|
76
|
+
if (nextRecord !== baseRecord) {
|
|
77
|
+
// Prevent mutation of a record from outside the store.
|
|
78
|
+
RelayModernRecord.freeze(nextRecord);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return nextRecord;
|
|
82
|
+
} else {
|
|
83
|
+
const nextRecord = RelayModernRecord.clone(sinkRecord);
|
|
84
|
+
if (__DEV__) {
|
|
85
|
+
// Prevent mutation of a record from outside the store.
|
|
86
|
+
RelayModernRecord.freeze(nextRecord);
|
|
87
|
+
}
|
|
88
|
+
return nextRecord;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
_getSinkRecord(dataID: DataID): Record {
|
|
93
|
+
let sinkRecord = this._sink.get(dataID);
|
|
94
|
+
if (!sinkRecord) {
|
|
95
|
+
const baseRecord = this._base.get(dataID);
|
|
96
|
+
invariant(
|
|
97
|
+
baseRecord,
|
|
98
|
+
'RelayRecordSourceMutator: Cannot modify non-existent record `%s`.',
|
|
99
|
+
dataID,
|
|
100
|
+
);
|
|
101
|
+
sinkRecord = RelayModernRecord.create(
|
|
102
|
+
dataID,
|
|
103
|
+
RelayModernRecord.getType(baseRecord),
|
|
104
|
+
);
|
|
105
|
+
this._sink.set(dataID, sinkRecord);
|
|
106
|
+
}
|
|
107
|
+
return sinkRecord;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
copyFields(sourceID: DataID, sinkID: DataID): void {
|
|
111
|
+
const sinkSource = this._sink.get(sourceID);
|
|
112
|
+
const baseSource = this._base.get(sourceID);
|
|
113
|
+
invariant(
|
|
114
|
+
sinkSource || baseSource,
|
|
115
|
+
'RelayRecordSourceMutator#copyFields(): Cannot copy fields from ' +
|
|
116
|
+
'non-existent record `%s`.',
|
|
117
|
+
sourceID,
|
|
118
|
+
);
|
|
119
|
+
const sink = this._getSinkRecord(sinkID);
|
|
120
|
+
if (baseSource) {
|
|
121
|
+
RelayModernRecord.copyFields(baseSource, sink);
|
|
122
|
+
}
|
|
123
|
+
if (sinkSource) {
|
|
124
|
+
RelayModernRecord.copyFields(sinkSource, sink);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
copyFieldsFromRecord(record: Record, sinkID: DataID): void {
|
|
129
|
+
const sink = this._getSinkRecord(sinkID);
|
|
130
|
+
RelayModernRecord.copyFields(record, sink);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
create(dataID: DataID, typeName: string): void {
|
|
134
|
+
invariant(
|
|
135
|
+
this._base.getStatus(dataID) !== EXISTENT &&
|
|
136
|
+
this._sink.getStatus(dataID) !== EXISTENT,
|
|
137
|
+
'RelayRecordSourceMutator#create(): Cannot create a record with id ' +
|
|
138
|
+
'`%s`, this record already exists.',
|
|
139
|
+
dataID,
|
|
140
|
+
);
|
|
141
|
+
const record = RelayModernRecord.create(dataID, typeName);
|
|
142
|
+
this._sink.set(dataID, record);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
delete(dataID: DataID): void {
|
|
146
|
+
this._sink.delete(dataID);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
getStatus(dataID: DataID): RecordState {
|
|
150
|
+
return this._sink.has(dataID)
|
|
151
|
+
? this._sink.getStatus(dataID)
|
|
152
|
+
: this._base.getStatus(dataID);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
getType(dataID: DataID): ?string {
|
|
156
|
+
for (let ii = 0; ii < this.__sources.length; ii++) {
|
|
157
|
+
const record = this.__sources[ii].get(dataID);
|
|
158
|
+
if (record) {
|
|
159
|
+
return RelayModernRecord.getType(record);
|
|
160
|
+
} else if (record === null) {
|
|
161
|
+
return null;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
getValue(dataID: DataID, storageKey: string): mixed {
|
|
167
|
+
for (let ii = 0; ii < this.__sources.length; ii++) {
|
|
168
|
+
const record = this.__sources[ii].get(dataID);
|
|
169
|
+
if (record) {
|
|
170
|
+
const value = RelayModernRecord.getValue(record, storageKey);
|
|
171
|
+
if (value !== undefined) {
|
|
172
|
+
return value;
|
|
173
|
+
}
|
|
174
|
+
} else if (record === null) {
|
|
175
|
+
return null;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
setValue(dataID: DataID, storageKey: string, value: mixed): void {
|
|
181
|
+
const sinkRecord = this._getSinkRecord(dataID);
|
|
182
|
+
RelayModernRecord.setValue(sinkRecord, storageKey, value);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
getLinkedRecordID(dataID: DataID, storageKey: string): ?DataID {
|
|
186
|
+
for (let ii = 0; ii < this.__sources.length; ii++) {
|
|
187
|
+
const record = this.__sources[ii].get(dataID);
|
|
188
|
+
if (record) {
|
|
189
|
+
const linkedID = RelayModernRecord.getLinkedRecordID(
|
|
190
|
+
record,
|
|
191
|
+
storageKey,
|
|
192
|
+
);
|
|
193
|
+
if (linkedID !== undefined) {
|
|
194
|
+
return linkedID;
|
|
195
|
+
}
|
|
196
|
+
} else if (record === null) {
|
|
197
|
+
return null;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
setLinkedRecordID(
|
|
203
|
+
dataID: DataID,
|
|
204
|
+
storageKey: string,
|
|
205
|
+
linkedID: DataID,
|
|
206
|
+
): void {
|
|
207
|
+
const sinkRecord = this._getSinkRecord(dataID);
|
|
208
|
+
RelayModernRecord.setLinkedRecordID(sinkRecord, storageKey, linkedID);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
getLinkedRecordIDs(dataID: DataID, storageKey: string): ?Array<?DataID> {
|
|
212
|
+
for (let ii = 0; ii < this.__sources.length; ii++) {
|
|
213
|
+
const record = this.__sources[ii].get(dataID);
|
|
214
|
+
if (record) {
|
|
215
|
+
const linkedIDs = RelayModernRecord.getLinkedRecordIDs(
|
|
216
|
+
record,
|
|
217
|
+
storageKey,
|
|
218
|
+
);
|
|
219
|
+
if (linkedIDs !== undefined) {
|
|
220
|
+
return linkedIDs;
|
|
221
|
+
}
|
|
222
|
+
} else if (record === null) {
|
|
223
|
+
return null;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
setLinkedRecordIDs(
|
|
229
|
+
dataID: DataID,
|
|
230
|
+
storageKey: string,
|
|
231
|
+
linkedIDs: Array<?DataID>,
|
|
232
|
+
): void {
|
|
233
|
+
const sinkRecord = this._getSinkRecord(dataID);
|
|
234
|
+
RelayModernRecord.setLinkedRecordIDs(sinkRecord, storageKey, linkedIDs);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
module.exports = RelayRecordSourceMutator;
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
7
|
+
* @flow
|
|
8
|
+
* @format
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
// flowlint ambiguous-object-type:error
|
|
12
|
+
|
|
13
|
+
'use strict';
|
|
14
|
+
|
|
15
|
+
const RelayModernRecord = require('../store/RelayModernRecord');
|
|
16
|
+
const RelayRecordProxy = require('./RelayRecordProxy');
|
|
17
|
+
|
|
18
|
+
const invariant = require('invariant');
|
|
19
|
+
|
|
20
|
+
const {EXISTENT, NONEXISTENT} = require('../store/RelayRecordState');
|
|
21
|
+
const {ROOT_ID, ROOT_TYPE} = require('../store/RelayStoreUtils');
|
|
22
|
+
|
|
23
|
+
import type {HandlerProvider} from '../handlers/RelayDefaultHandlerProvider';
|
|
24
|
+
import type {GetDataID} from '../store/RelayResponseNormalizer';
|
|
25
|
+
import type {
|
|
26
|
+
HandleFieldPayload,
|
|
27
|
+
RecordSource,
|
|
28
|
+
RecordProxy,
|
|
29
|
+
RecordSourceProxy,
|
|
30
|
+
} from '../store/RelayStoreTypes';
|
|
31
|
+
import type {DataID} from '../util/RelayRuntimeTypes';
|
|
32
|
+
import type RelayRecordSourceMutator from './RelayRecordSourceMutator';
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* @internal
|
|
36
|
+
*
|
|
37
|
+
* A helper for manipulating a `RecordSource` via an imperative/OO-style API.
|
|
38
|
+
*/
|
|
39
|
+
class RelayRecordSourceProxy implements RecordSourceProxy {
|
|
40
|
+
_handlerProvider: ?HandlerProvider;
|
|
41
|
+
__mutator: RelayRecordSourceMutator;
|
|
42
|
+
_proxies: {[dataID: DataID]: ?RelayRecordProxy, ...};
|
|
43
|
+
_getDataID: GetDataID;
|
|
44
|
+
_invalidatedStore: boolean;
|
|
45
|
+
_idsMarkedForInvalidation: Set<DataID>;
|
|
46
|
+
|
|
47
|
+
constructor(
|
|
48
|
+
mutator: RelayRecordSourceMutator,
|
|
49
|
+
getDataID: GetDataID,
|
|
50
|
+
handlerProvider?: ?HandlerProvider,
|
|
51
|
+
) {
|
|
52
|
+
this.__mutator = mutator;
|
|
53
|
+
this._handlerProvider = handlerProvider || null;
|
|
54
|
+
this._proxies = {};
|
|
55
|
+
this._getDataID = getDataID;
|
|
56
|
+
this._invalidatedStore = false;
|
|
57
|
+
this._idsMarkedForInvalidation = new Set();
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
publishSource(
|
|
61
|
+
source: RecordSource,
|
|
62
|
+
fieldPayloads?: ?Array<HandleFieldPayload>,
|
|
63
|
+
): void {
|
|
64
|
+
const dataIDs = source.getRecordIDs();
|
|
65
|
+
dataIDs.forEach(dataID => {
|
|
66
|
+
const status = source.getStatus(dataID);
|
|
67
|
+
if (status === EXISTENT) {
|
|
68
|
+
const sourceRecord = source.get(dataID);
|
|
69
|
+
if (sourceRecord) {
|
|
70
|
+
if (this.__mutator.getStatus(dataID) !== EXISTENT) {
|
|
71
|
+
this.create(dataID, RelayModernRecord.getType(sourceRecord));
|
|
72
|
+
}
|
|
73
|
+
this.__mutator.copyFieldsFromRecord(sourceRecord, dataID);
|
|
74
|
+
}
|
|
75
|
+
} else if (status === NONEXISTENT) {
|
|
76
|
+
this.delete(dataID);
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
if (fieldPayloads && fieldPayloads.length) {
|
|
81
|
+
fieldPayloads.forEach(fieldPayload => {
|
|
82
|
+
const handler =
|
|
83
|
+
this._handlerProvider && this._handlerProvider(fieldPayload.handle);
|
|
84
|
+
invariant(
|
|
85
|
+
handler,
|
|
86
|
+
'RelayModernEnvironment: Expected a handler to be provided for handle `%s`.',
|
|
87
|
+
fieldPayload.handle,
|
|
88
|
+
);
|
|
89
|
+
handler.update(this, fieldPayload);
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
create(dataID: DataID, typeName: string): RecordProxy {
|
|
95
|
+
this.__mutator.create(dataID, typeName);
|
|
96
|
+
delete this._proxies[dataID];
|
|
97
|
+
const record = this.get(dataID);
|
|
98
|
+
// For flow
|
|
99
|
+
invariant(
|
|
100
|
+
record,
|
|
101
|
+
'RelayRecordSourceProxy#create(): Expected the created record to exist.',
|
|
102
|
+
);
|
|
103
|
+
return record;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
delete(dataID: DataID): void {
|
|
107
|
+
invariant(
|
|
108
|
+
dataID !== ROOT_ID,
|
|
109
|
+
'RelayRecordSourceProxy#delete(): Cannot delete the root record.',
|
|
110
|
+
);
|
|
111
|
+
delete this._proxies[dataID];
|
|
112
|
+
this.__mutator.delete(dataID);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
get(dataID: DataID): ?RecordProxy {
|
|
116
|
+
if (!this._proxies.hasOwnProperty(dataID)) {
|
|
117
|
+
const status = this.__mutator.getStatus(dataID);
|
|
118
|
+
if (status === EXISTENT) {
|
|
119
|
+
this._proxies[dataID] = new RelayRecordProxy(
|
|
120
|
+
this,
|
|
121
|
+
this.__mutator,
|
|
122
|
+
dataID,
|
|
123
|
+
);
|
|
124
|
+
} else {
|
|
125
|
+
this._proxies[dataID] = status === NONEXISTENT ? null : undefined;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
return this._proxies[dataID];
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
getRoot(): RecordProxy {
|
|
132
|
+
let root = this.get(ROOT_ID);
|
|
133
|
+
if (!root) {
|
|
134
|
+
root = this.create(ROOT_ID, ROOT_TYPE);
|
|
135
|
+
}
|
|
136
|
+
invariant(
|
|
137
|
+
root && root.getType() === ROOT_TYPE,
|
|
138
|
+
'RelayRecordSourceProxy#getRoot(): Expected the source to contain a ' +
|
|
139
|
+
'root record, %s.',
|
|
140
|
+
root == null
|
|
141
|
+
? 'no root record found'
|
|
142
|
+
: `found a root record of type \`${root.getType()}\``,
|
|
143
|
+
);
|
|
144
|
+
return root;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
invalidateStore(): void {
|
|
148
|
+
this._invalidatedStore = true;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
isStoreMarkedForInvalidation(): boolean {
|
|
152
|
+
return this._invalidatedStore;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
markIDForInvalidation(dataID: DataID): void {
|
|
156
|
+
this._idsMarkedForInvalidation.add(dataID);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
getIDsMarkedForInvalidation(): Set<DataID> {
|
|
160
|
+
return this._idsMarkedForInvalidation;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
module.exports = RelayRecordSourceProxy;
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
7
|
+
* @flow strict-local
|
|
8
|
+
* @format
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
// flowlint ambiguous-object-type:error
|
|
12
|
+
|
|
13
|
+
'use strict';
|
|
14
|
+
|
|
15
|
+
const invariant = require('invariant');
|
|
16
|
+
|
|
17
|
+
const {getStorageKey, ROOT_TYPE} = require('../store/RelayStoreUtils');
|
|
18
|
+
|
|
19
|
+
import type {
|
|
20
|
+
RecordProxy,
|
|
21
|
+
RecordSourceProxy,
|
|
22
|
+
RecordSourceSelectorProxy,
|
|
23
|
+
SingularReaderSelector,
|
|
24
|
+
} from '../store/RelayStoreTypes';
|
|
25
|
+
import type {ReaderLinkedField} from '../util/ReaderNode';
|
|
26
|
+
import type {DataID} from '../util/RelayRuntimeTypes';
|
|
27
|
+
import type RelayRecordSourceMutator from './RelayRecordSourceMutator';
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* @internal
|
|
31
|
+
*
|
|
32
|
+
* A subclass of RecordSourceProxy that provides convenience methods for
|
|
33
|
+
* accessing the root fields of a given query/mutation. These fields accept
|
|
34
|
+
* complex arguments and it can be tedious to re-construct the correct sets of
|
|
35
|
+
* arguments to pass to e.g. `getRoot().getLinkedRecord()`.
|
|
36
|
+
*/
|
|
37
|
+
class RelayRecordSourceSelectorProxy implements RecordSourceSelectorProxy {
|
|
38
|
+
__mutator: RelayRecordSourceMutator;
|
|
39
|
+
__recordSource: RecordSourceProxy;
|
|
40
|
+
_readSelector: SingularReaderSelector;
|
|
41
|
+
|
|
42
|
+
constructor(
|
|
43
|
+
mutator: RelayRecordSourceMutator,
|
|
44
|
+
recordSource: RecordSourceProxy,
|
|
45
|
+
readSelector: SingularReaderSelector,
|
|
46
|
+
) {
|
|
47
|
+
this.__mutator = mutator;
|
|
48
|
+
this.__recordSource = recordSource;
|
|
49
|
+
this._readSelector = readSelector;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
create(dataID: DataID, typeName: string): RecordProxy {
|
|
53
|
+
return this.__recordSource.create(dataID, typeName);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
delete(dataID: DataID): void {
|
|
57
|
+
this.__recordSource.delete(dataID);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
get(dataID: DataID): ?RecordProxy {
|
|
61
|
+
return this.__recordSource.get(dataID);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
getRoot(): RecordProxy {
|
|
65
|
+
return this.__recordSource.getRoot();
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
getOperationRoot(): RecordProxy {
|
|
69
|
+
let root = this.__recordSource.get(this._readSelector.dataID);
|
|
70
|
+
if (!root) {
|
|
71
|
+
root = this.__recordSource.create(this._readSelector.dataID, ROOT_TYPE);
|
|
72
|
+
}
|
|
73
|
+
return root;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
_getRootField(
|
|
77
|
+
selector: SingularReaderSelector,
|
|
78
|
+
fieldName: string,
|
|
79
|
+
plural: boolean,
|
|
80
|
+
): ReaderLinkedField {
|
|
81
|
+
const field = selector.node.selections.find(
|
|
82
|
+
selection =>
|
|
83
|
+
selection.kind === 'LinkedField' && selection.name === fieldName,
|
|
84
|
+
);
|
|
85
|
+
invariant(
|
|
86
|
+
field && field.kind === 'LinkedField',
|
|
87
|
+
'RelayRecordSourceSelectorProxy#getRootField(): Cannot find root ' +
|
|
88
|
+
'field `%s`, no such field is defined on GraphQL document `%s`.',
|
|
89
|
+
fieldName,
|
|
90
|
+
selector.node.name,
|
|
91
|
+
);
|
|
92
|
+
invariant(
|
|
93
|
+
field.plural === plural,
|
|
94
|
+
'RelayRecordSourceSelectorProxy#getRootField(): Expected root field ' +
|
|
95
|
+
'`%s` to be %s.',
|
|
96
|
+
fieldName,
|
|
97
|
+
plural ? 'plural' : 'singular',
|
|
98
|
+
);
|
|
99
|
+
return field;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
getRootField(fieldName: string): ?RecordProxy {
|
|
103
|
+
const field = this._getRootField(this._readSelector, fieldName, false);
|
|
104
|
+
const storageKey = getStorageKey(field, this._readSelector.variables);
|
|
105
|
+
return this.getOperationRoot().getLinkedRecord(storageKey);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
getPluralRootField(fieldName: string): ?Array<?RecordProxy> {
|
|
109
|
+
const field = this._getRootField(this._readSelector, fieldName, true);
|
|
110
|
+
const storageKey = getStorageKey(field, this._readSelector.variables);
|
|
111
|
+
return this.getOperationRoot().getLinkedRecords(storageKey);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
invalidateStore(): void {
|
|
115
|
+
this.__recordSource.invalidateStore();
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
module.exports = RelayRecordSourceSelectorProxy;
|