relay-runtime 0.0.0-main-2abce249 → 0.0.0-main-f74fe29f

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.
@@ -43,7 +43,7 @@ import type {
43
43
  SingularReaderSelector,
44
44
  Snapshot,
45
45
  } from './RelayStoreTypes';
46
- import type {ResolverCache} from './ResolverCache';
46
+ import type {EvaluationResult, ResolverCache} from './ResolverCache';
47
47
 
48
48
  const {
49
49
  ACTOR_CHANGE,
@@ -536,54 +536,26 @@ class RelayReader {
536
536
  // Found when reading the resolver fragment, which can happen either when
537
537
  // evaluating the resolver and it calls readFragment, or when checking if the
538
538
  // inputs have changed since a previous evaluation:
539
- let fragmentValue;
540
- let fragmentReaderSelector;
541
- let fragmentMissingRequiredFields: ?MissingRequiredFields;
542
- let previousMissingRequriedFields: ?MissingRequiredFields;
543
-
544
- let currentResolverErrors: RelayResolverErrors = [];
545
- let previousResolverErrors: RelayResolverErrors;
546
- const fragmentSeenRecordIDs = new Set();
539
+ let snapshot: ?Snapshot;
547
540
 
548
541
  const getDataForResolverFragment = singularReaderSelector => {
549
- if (fragmentValue != null) {
542
+ if (snapshot != null) {
550
543
  // It was already read when checking for input staleness; no need to read it again.
551
544
  // Note that the variables like fragmentSeenRecordIDs in the outer closure will have
552
545
  // already been set and will still be used in this case.
553
- return fragmentValue;
554
- }
555
- fragmentReaderSelector = singularReaderSelector;
556
- const existingSeenRecords = this._seenRecords;
557
- try {
558
- this._seenRecords = fragmentSeenRecordIDs;
559
- const resolverFragmentData = {};
560
- previousMissingRequriedFields = this._missingRequiredFields;
561
- this._missingRequiredFields = null;
562
-
563
- previousResolverErrors = this._resolverErrors;
564
- this._resolverErrors = [];
565
- this._createInlineDataOrResolverFragmentPointer(
566
- singularReaderSelector.node,
567
- record,
568
- resolverFragmentData,
569
- );
570
- fragmentMissingRequiredFields = this._missingRequiredFields;
571
- currentResolverErrors = this._resolverErrors;
572
- fragmentValue = resolverFragmentData[FRAGMENTS_KEY]?.[fragment.name];
573
- invariant(
574
- typeof fragmentValue === 'object' && fragmentValue !== null,
575
- `Expected reader data to contain a __fragments property with a property for the fragment named ${fragment.name}, but it is missing.`,
576
- );
577
- return fragmentValue;
578
- } finally {
579
- this._seenRecords = existingSeenRecords;
580
- this._missingRequiredFields = previousMissingRequriedFields;
581
- this._resolverErrors = previousResolverErrors;
546
+ return snapshot.data;
582
547
  }
548
+
549
+ snapshot = read(
550
+ this._recordSource,
551
+ singularReaderSelector,
552
+ this._resolverCache,
553
+ );
554
+ return snapshot.data;
583
555
  };
584
556
  const resolverContext = {getDataForResolverFragment};
585
557
 
586
- const evaluate = () => {
558
+ const evaluate = (): EvaluationResult<mixed> => {
587
559
  const key = {
588
560
  __id: RelayModernRecord.getDataID(record),
589
561
  __fragmentOwner: this._owner,
@@ -593,30 +565,29 @@ class RelayReader {
593
565
  };
594
566
  return withResolverContext(resolverContext, () => {
595
567
  let resolverResult = null;
568
+ let resolverError = null;
596
569
  try {
597
570
  // $FlowFixMe[prop-missing] - resolver module's type signature is a lie
598
571
  resolverResult = resolverModule(key);
599
572
  } catch (e) {
600
573
  // `field.path` is typed as nullable while we rollout compiler changes.
601
574
  const path = field.path ?? '[UNKNOWN]';
602
- currentResolverErrors.push({
575
+ resolverError = {
603
576
  field: {path, owner: this._fragmentName},
604
577
  error: e,
605
- });
578
+ };
606
579
  }
580
+
607
581
  return {
608
582
  resolverResult,
609
- errors: currentResolverErrors,
610
- fragmentValue,
583
+ snapshot: snapshot,
611
584
  resolverID,
612
- seenRecordIDs: fragmentSeenRecordIDs,
613
- readerSelector: fragmentReaderSelector,
614
- missingRequiredFields: fragmentMissingRequiredFields,
585
+ error: resolverError,
615
586
  };
616
587
  });
617
588
  };
618
589
 
619
- const [result, seenRecord, resolverErrors, missingRequiredFields] =
590
+ const [result, seenRecord, resolverError, cachedSnapshot] =
620
591
  this._resolverCache.readFromCacheOrEvaluate(
621
592
  record,
622
593
  field,
@@ -625,11 +596,22 @@ class RelayReader {
625
596
  getDataForResolverFragment,
626
597
  );
627
598
 
628
- for (const resolverError of resolverErrors) {
629
- this._resolverErrors.push(resolverError);
599
+ if (cachedSnapshot != null) {
600
+ if (cachedSnapshot.missingRequiredFields != null) {
601
+ this._addMissingRequiredFields(cachedSnapshot.missingRequiredFields);
602
+ }
603
+ if (cachedSnapshot.missingClientEdges != null) {
604
+ for (const missing of cachedSnapshot.missingClientEdges) {
605
+ this._missingClientEdges.push(missing);
606
+ }
607
+ }
608
+ for (const error of cachedSnapshot.relayResolverErrors) {
609
+ this._resolverErrors.push(error);
610
+ }
611
+ this._isMissingData = this._isMissingData || cachedSnapshot.isMissingData;
630
612
  }
631
- if (missingRequiredFields != null) {
632
- this._addMissingRequiredFields(missingRequiredFields);
613
+ if (resolverError) {
614
+ this._resolverErrors.push(resolverError);
633
615
  }
634
616
  if (seenRecord != null) {
635
617
  this._seenRecords.add(seenRecord);
@@ -217,9 +217,7 @@ const RelayStoreUtils = {
217
217
  IS_WITHIN_UNMATCHED_TYPE_REFINEMENT: '__isWithinUnmatchedTypeRefinement',
218
218
  RELAY_RESOLVER_VALUE_KEY: '__resolverValue',
219
219
  RELAY_RESOLVER_INVALIDATION_KEY: '__resolverValueMayBeInvalid',
220
- RELAY_RESOLVER_INPUTS_KEY: '__resolverInputValues',
221
- RELAY_RESOLVER_READER_SELECTOR_KEY: '__resolverReaderSelector',
222
- RELAY_RESOLVER_MISSING_REQUIRED_FIELDS_KEY: '__resolverMissingRequiredFields',
220
+ RELAY_RESOLVER_SNAPSHOT_KEY: '__resolverSnapshot',
223
221
  RELAY_RESOLVER_ERROR_KEY: '__resolverError',
224
222
 
225
223
  formatStorageKey,
@@ -18,11 +18,11 @@ import type {
18
18
  } from '../util/ReaderNode';
19
19
  import type {DataID, Variables} from '../util/RelayRuntimeTypes';
20
20
  import type {
21
- MissingRequiredFields,
22
21
  MutableRecordSource,
23
22
  Record,
24
- RelayResolverErrors,
23
+ RelayResolverError,
25
24
  SingularReaderSelector,
25
+ Snapshot,
26
26
  } from './RelayStoreTypes';
27
27
 
28
28
  const recycleNodesInto = require('../util/recycleNodesInto');
@@ -31,10 +31,8 @@ const {generateClientID} = require('./ClientID');
31
31
  const RelayModernRecord = require('./RelayModernRecord');
32
32
  const {
33
33
  RELAY_RESOLVER_ERROR_KEY,
34
- RELAY_RESOLVER_INPUTS_KEY,
35
34
  RELAY_RESOLVER_INVALIDATION_KEY,
36
- RELAY_RESOLVER_MISSING_REQUIRED_FIELDS_KEY,
37
- RELAY_RESOLVER_READER_SELECTOR_KEY,
35
+ RELAY_RESOLVER_SNAPSHOT_KEY,
38
36
  RELAY_RESOLVER_VALUE_KEY,
39
37
  getStorageKey,
40
38
  } = require('./RelayStoreUtils');
@@ -43,14 +41,11 @@ const warning = require('warning');
43
41
 
44
42
  type ResolverID = string;
45
43
 
46
- type EvaluationResult<T> = {|
44
+ export type EvaluationResult<T> = {|
47
45
  resolverResult: T,
48
- fragmentValue: {...},
49
46
  resolverID: ResolverID,
50
- seenRecordIDs: Set<DataID>,
51
- readerSelector: SingularReaderSelector,
52
- errors: RelayResolverErrors,
53
- missingRequiredFields: ?MissingRequiredFields,
47
+ snapshot: ?Snapshot,
48
+ error: ?RelayResolverError,
54
49
  |};
55
50
 
56
51
  export interface ResolverCache {
@@ -63,8 +58,8 @@ export interface ResolverCache {
63
58
  ): [
64
59
  T /* Answer */,
65
60
  ?DataID /* Seen record */,
66
- RelayResolverErrors,
67
- ?MissingRequiredFields,
61
+ ?RelayResolverError,
62
+ ?Snapshot,
68
63
  ];
69
64
  invalidateDataIDs(
70
65
  updatedDataIDs: Set<DataID>, // Mutated in place
@@ -85,15 +80,16 @@ class NoopResolverCache implements ResolverCache {
85
80
  ): [
86
81
  T /* Answer */,
87
82
  ?DataID /* Seen record */,
88
- RelayResolverErrors,
89
- ?MissingRequiredFields,
83
+ ?RelayResolverError,
84
+ ?Snapshot,
90
85
  ] {
91
86
  invariant(
92
87
  field.kind !== RELAY_LIVE_RESOLVER,
93
88
  'This store does not support Live Resolvers',
94
89
  );
95
- const {resolverResult, missingRequiredFields, errors} = evaluate();
96
- return [resolverResult, undefined, errors, missingRequiredFields];
90
+ const {resolverResult, snapshot, error} = evaluate();
91
+
92
+ return [resolverResult, undefined, error, snapshot];
97
93
  }
98
94
  invalidateDataIDs(updatedDataIDs: Set<DataID>): void {}
99
95
  createClientRecord(id: string, typeName: string): string {
@@ -138,8 +134,8 @@ class RecordResolverCache implements ResolverCache {
138
134
  ): [
139
135
  T /* Answer */,
140
136
  ?DataID /* Seen record */,
141
- RelayResolverErrors,
142
- ?MissingRequiredFields,
137
+ ?RelayResolverError,
138
+ ?Snapshot,
143
139
  ] {
144
140
  const recordSource = this._getRecordSource();
145
141
  const recordID = RelayModernRecord.getDataID(record);
@@ -163,23 +159,13 @@ class RecordResolverCache implements ResolverCache {
163
159
  );
164
160
  RelayModernRecord.setValue(
165
161
  linkedRecord,
166
- RELAY_RESOLVER_INPUTS_KEY,
167
- evaluationResult.fragmentValue,
168
- );
169
- RelayModernRecord.setValue(
170
- linkedRecord,
171
- RELAY_RESOLVER_READER_SELECTOR_KEY,
172
- evaluationResult.readerSelector,
173
- );
174
- RelayModernRecord.setValue(
175
- linkedRecord,
176
- RELAY_RESOLVER_MISSING_REQUIRED_FIELDS_KEY,
177
- evaluationResult.missingRequiredFields,
162
+ RELAY_RESOLVER_SNAPSHOT_KEY,
163
+ evaluationResult.snapshot,
178
164
  );
179
165
  RelayModernRecord.setValue(
180
166
  linkedRecord,
181
167
  RELAY_RESOLVER_ERROR_KEY,
182
- evaluationResult.errors,
168
+ evaluationResult.error,
183
169
  );
184
170
  recordSource.set(linkedID, linkedRecord);
185
171
 
@@ -192,25 +178,26 @@ class RecordResolverCache implements ResolverCache {
192
178
  const resolverID = evaluationResult.resolverID;
193
179
  addDependencyEdge(this._resolverIDToRecordIDs, resolverID, linkedID);
194
180
  addDependencyEdge(this._recordIDToResolverIDs, recordID, resolverID);
195
- for (const seenRecordID of evaluationResult.seenRecordIDs) {
196
- addDependencyEdge(
197
- this._recordIDToResolverIDs,
198
- seenRecordID,
199
- resolverID,
200
- );
181
+ const seenRecordIds = evaluationResult.snapshot?.seenRecords;
182
+ if (seenRecordIds != null) {
183
+ for (const seenRecordID of seenRecordIds) {
184
+ addDependencyEdge(
185
+ this._recordIDToResolverIDs,
186
+ seenRecordID,
187
+ resolverID,
188
+ );
189
+ }
201
190
  }
202
191
  }
203
192
 
204
193
  // $FlowFixMe[incompatible-type] - will always be empty
205
194
  const answer: T = linkedRecord[RELAY_RESOLVER_VALUE_KEY];
206
-
207
- const missingRequiredFields: ?MissingRequiredFields =
208
- // $FlowFixMe[incompatible-type] - casting mixed
209
- linkedRecord[RELAY_RESOLVER_MISSING_REQUIRED_FIELDS_KEY];
210
-
211
195
  // $FlowFixMe[incompatible-type] - casting mixed
212
- const errors: RelayResolverErrors = linkedRecord[RELAY_RESOLVER_ERROR_KEY];
213
- return [answer, linkedID, errors, missingRequiredFields];
196
+ const snapshot: ?Snapshot = linkedRecord[RELAY_RESOLVER_SNAPSHOT_KEY];
197
+ // $FlowFixMe[incompatible-type] - casting mixed
198
+ const error: ?RelayResolverError = linkedRecord[RELAY_RESOLVER_ERROR_KEY];
199
+
200
+ return [answer, linkedID, error, snapshot];
214
201
  }
215
202
 
216
203
  invalidateDataIDs(
@@ -272,15 +259,13 @@ class RecordResolverCache implements ResolverCache {
272
259
  if (!RelayModernRecord.getValue(record, RELAY_RESOLVER_INVALIDATION_KEY)) {
273
260
  return false;
274
261
  }
275
- const originalInputs = RelayModernRecord.getValue(
276
- record,
277
- RELAY_RESOLVER_INPUTS_KEY,
278
- );
279
262
  // $FlowFixMe[incompatible-type] - storing values in records is not typed
280
- const readerSelector: ?SingularReaderSelector = RelayModernRecord.getValue(
263
+ const snapshot: ?Snapshot = RelayModernRecord.getValue(
281
264
  record,
282
- RELAY_RESOLVER_READER_SELECTOR_KEY,
265
+ RELAY_RESOLVER_SNAPSHOT_KEY,
283
266
  );
267
+ const originalInputs = snapshot?.data;
268
+ const readerSelector: ?SingularReaderSelector = snapshot?.selector;
284
269
  if (originalInputs == null || readerSelector == null) {
285
270
  warning(
286
271
  false,
@@ -18,13 +18,13 @@ import type {
18
18
  } from '../../util/ReaderNode';
19
19
  import type {DataID, Variables} from '../../util/RelayRuntimeTypes';
20
20
  import type {
21
- MissingRequiredFields,
22
21
  MutableRecordSource,
23
22
  Record,
24
- RelayResolverErrors,
23
+ RelayResolverError,
25
24
  SingularReaderSelector,
25
+ Snapshot,
26
26
  } from '../RelayStoreTypes';
27
- import type {ResolverCache} from '../ResolverCache';
27
+ import type {EvaluationResult, ResolverCache} from '../ResolverCache';
28
28
  import type {LiveState} from './LiveResolverStore';
29
29
 
30
30
  const recycleNodesInto = require('../../util/recycleNodesInto');
@@ -34,10 +34,8 @@ const RelayModernRecord = require('../RelayModernRecord');
34
34
  const RelayRecordSource = require('../RelayRecordSource');
35
35
  const {
36
36
  RELAY_RESOLVER_ERROR_KEY,
37
- RELAY_RESOLVER_INPUTS_KEY,
38
37
  RELAY_RESOLVER_INVALIDATION_KEY,
39
- RELAY_RESOLVER_MISSING_REQUIRED_FIELDS_KEY,
40
- RELAY_RESOLVER_READER_SELECTOR_KEY,
38
+ RELAY_RESOLVER_SNAPSHOT_KEY,
41
39
  RELAY_RESOLVER_VALUE_KEY,
42
40
  getStorageKey,
43
41
  } = require('../RelayStoreUtils');
@@ -59,16 +57,6 @@ const RELAY_RESOLVER_LIVE_STATE_DIRTY = '__resolverLiveStateDirty';
59
57
 
60
58
  type ResolverID = string;
61
59
 
62
- type EvaluationResult<T> = {|
63
- resolverResult: T,
64
- fragmentValue: {...},
65
- resolverID: ResolverID,
66
- seenRecordIDs: Set<DataID>,
67
- readerSelector: SingularReaderSelector,
68
- errors: RelayResolverErrors,
69
- missingRequiredFields: ?MissingRequiredFields,
70
- |};
71
-
72
60
  // $FlowFixMe[unclear-type] - will always be empty
73
61
  const emptySet: $ReadOnlySet<any> = new Set();
74
62
 
@@ -111,8 +99,8 @@ class LiveResolverCache implements ResolverCache {
111
99
  ): [
112
100
  T /* Answer */,
113
101
  ?DataID /* Seen record */,
114
- RelayResolverErrors,
115
- ?MissingRequiredFields,
102
+ ?RelayResolverError,
103
+ ?Snapshot,
116
104
  ] {
117
105
  const recordSource = this._getRecordSource();
118
106
  const recordID = RelayModernRecord.getDataID(record);
@@ -151,23 +139,13 @@ class LiveResolverCache implements ResolverCache {
151
139
  }
152
140
  RelayModernRecord.setValue(
153
141
  linkedRecord,
154
- RELAY_RESOLVER_INPUTS_KEY,
155
- evaluationResult.fragmentValue,
156
- );
157
- RelayModernRecord.setValue(
158
- linkedRecord,
159
- RELAY_RESOLVER_READER_SELECTOR_KEY,
160
- evaluationResult.readerSelector,
161
- );
162
- RelayModernRecord.setValue(
163
- linkedRecord,
164
- RELAY_RESOLVER_MISSING_REQUIRED_FIELDS_KEY,
165
- evaluationResult.missingRequiredFields,
142
+ RELAY_RESOLVER_SNAPSHOT_KEY,
143
+ evaluationResult.snapshot,
166
144
  );
167
145
  RelayModernRecord.setValue(
168
146
  linkedRecord,
169
147
  RELAY_RESOLVER_ERROR_KEY,
170
- evaluationResult.errors,
148
+ evaluationResult.error,
171
149
  );
172
150
  recordSource.set(linkedID, linkedRecord);
173
151
 
@@ -180,12 +158,15 @@ class LiveResolverCache implements ResolverCache {
180
158
  const resolverID = evaluationResult.resolverID;
181
159
  addDependencyEdge(this._resolverIDToRecordIDs, resolverID, linkedID);
182
160
  addDependencyEdge(this._recordIDToResolverIDs, recordID, resolverID);
183
- for (const seenRecordID of evaluationResult.seenRecordIDs) {
184
- addDependencyEdge(
185
- this._recordIDToResolverIDs,
186
- seenRecordID,
187
- resolverID,
188
- );
161
+ const seenRecordIds = evaluationResult.snapshot?.seenRecords;
162
+ if (seenRecordIds != null) {
163
+ for (const seenRecordID of seenRecordIds) {
164
+ addDependencyEdge(
165
+ this._recordIDToResolverIDs,
166
+ seenRecordID,
167
+ resolverID,
168
+ );
169
+ }
189
170
  }
190
171
  } else if (
191
172
  field.kind === RELAY_LIVE_RESOLVER &&
@@ -219,14 +200,12 @@ class LiveResolverCache implements ResolverCache {
219
200
 
220
201
  // $FlowFixMe[incompatible-type] - will always be empty
221
202
  const answer: T = linkedRecord[RELAY_RESOLVER_VALUE_KEY];
222
-
223
- const missingRequiredFields: ?MissingRequiredFields =
224
- // $FlowFixMe[incompatible-type] - casting mixed
225
- linkedRecord[RELAY_RESOLVER_MISSING_REQUIRED_FIELDS_KEY];
226
-
227
203
  // $FlowFixMe[incompatible-type] - casting mixed
228
- const errors: RelayResolverErrors = linkedRecord[RELAY_RESOLVER_ERROR_KEY];
229
- return [answer, linkedID, errors, missingRequiredFields];
204
+ const snapshot: ?Snapshot = linkedRecord[RELAY_RESOLVER_SNAPSHOT_KEY];
205
+ // $FlowFixMe[incompatible-type] - casting mixed
206
+ const error: ?RelayResolverError = linkedRecord[RELAY_RESOLVER_ERROR_KEY];
207
+
208
+ return [answer, linkedID, error, snapshot];
230
209
  }
231
210
 
232
211
  // Register a new Live State object in the store, subscribing to future
@@ -371,15 +350,13 @@ class LiveResolverCache implements ResolverCache {
371
350
  if (!RelayModernRecord.getValue(record, RELAY_RESOLVER_INVALIDATION_KEY)) {
372
351
  return false;
373
352
  }
374
- const originalInputs = RelayModernRecord.getValue(
375
- record,
376
- RELAY_RESOLVER_INPUTS_KEY,
377
- );
378
353
  // $FlowFixMe[incompatible-type] - storing values in records is not typed
379
- const readerSelector: ?SingularReaderSelector = RelayModernRecord.getValue(
354
+ const snapshot: ?Snapshot = RelayModernRecord.getValue(
380
355
  record,
381
- RELAY_RESOLVER_READER_SELECTOR_KEY,
356
+ RELAY_RESOLVER_SNAPSHOT_KEY,
382
357
  );
358
+ const originalInputs = snapshot?.data;
359
+ const readerSelector: ?SingularReaderSelector = snapshot?.selector;
383
360
  if (originalInputs == null || readerSelector == null) {
384
361
  warning(
385
362
  false,