Skip to content

Commit

Permalink
Handle missing fields in readUpdatableQuery/Fragment
Browse files Browse the repository at this point in the history
Summary:
# Why

* Currently, if one reads a field, like `node(id: 4)`, in a typesafe updater, if that linked field is undefined in the store, the user will receive `undefined`.
* This is true even if the user has provided a missing field handler that could provide that field.
* This is annoying, because it violates users' expectations.

# Fix

* In `createUpdatableProxy`, whenever a field is read and is undefined, we attempt to have missing field handlers provide that record.
* This requires passing the missing field handlers from where they are defined (e.g. on the environment) through to `RelayRecordSourceProxy`, etc.

Reviewed By: alunyov

Differential Revision:
D40840474

LaMa Project: L1125407

fbshipit-source-id: 66df283e67a079b82a392950ef316b4054a9e38e
  • Loading branch information
Robert Balicki authored and facebook-github-bot committed Nov 1, 2022
1 parent 6092ddb commit c0d0198
Show file tree
Hide file tree
Showing 14 changed files with 634 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import type {INetwork} from '../network/RelayNetworkTypes';
import type RelayObservable from '../network/RelayObservable';
import type {
ExecuteMutationConfig,
MissingFieldHandler,
LogFunction,
MutationParameters,
OperationAvailability,
Expand Down Expand Up @@ -54,6 +55,7 @@ export type ActorSpecificEnvironmentConfig = $ReadOnly<{
network: INetwork,
requiredFieldLogger: RequiredFieldLogger,
store: Store,
missingFieldHandlers: $ReadOnlyArray<MissingFieldHandler>,
}>;

class ActorSpecificEnvironment implements IActorEnvironment {
Expand Down Expand Up @@ -83,6 +85,7 @@ class ActorSpecificEnvironment implements IActorEnvironment {
config.store,
config.handlerProvider,
defaultGetDataID,
config.missingFieldHandlers,
);
this._defaultRenderPolicy = config.defaultRenderPolicy;
// TODO:T92305692 Remove `options` in favor of directly using `actorIdentifier` on the environment
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ class MultiActorEnvironment implements IMultiActorEnvironment {
+_handlerProvider: HandlerProvider;
+_isServer: boolean;
+_logFn: LogFunction;
+_missingFieldHandlers: ?$ReadOnlyArray<MissingFieldHandler>;
+_missingFieldHandlers: $ReadOnlyArray<MissingFieldHandler>;
+_operationExecutions: Map<string, ActiveState>;
+_operationLoader: ?OperationLoader;
+_reactFlightPayloadDeserializer: ?ReactFlightPayloadDeserializer;
Expand All @@ -109,7 +109,7 @@ class MultiActorEnvironment implements IMultiActorEnvironment {
this._shouldProcessClientComponents = config.shouldProcessClientComponents;
this._treatMissingFieldsAsNull = config.treatMissingFieldsAsNull ?? false;
this._isServer = config.isServer ?? false;
this._missingFieldHandlers = config.missingFieldHandlers;
this._missingFieldHandlers = config.missingFieldHandlers ?? [];
this._createStoreForActor = config.createStoreForActor;
this._reactFlightPayloadDeserializer =
config.reactFlightPayloadDeserializer;
Expand Down Expand Up @@ -141,6 +141,7 @@ class MultiActorEnvironment implements IMultiActorEnvironment {
network: this._createNetworkForActor(actorIdentifier),
handlerProvider: this._handlerProvider,
defaultRenderPolicy: this._defaultRenderPolicy,
missingFieldHandlers: this._missingFieldHandlers,
});
this._actorEnvironments.set(actorIdentifier, newEnvironment);
return newEnvironment;
Expand Down
12 changes: 11 additions & 1 deletion packages/relay-runtime/mutations/RelayRecordSourceProxy.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import type {
RecordSource,
RecordSourceProxy,
UpdatableData,
MissingFieldHandler,
} from '../store/RelayStoreTypes';
import type {
DataID,
Expand Down Expand Up @@ -55,18 +56,21 @@ class RelayRecordSourceProxy implements RecordSourceProxy {
_getDataID: GetDataID;
_invalidatedStore: boolean;
_idsMarkedForInvalidation: DataIDSet;
_missingFieldHandlers: $ReadOnlyArray<MissingFieldHandler>;

constructor(
mutator: RelayRecordSourceMutator,
getDataID: GetDataID,
handlerProvider?: ?HandlerProvider,
missingFieldHandlers: $ReadOnlyArray<MissingFieldHandler>,
) {
this.__mutator = mutator;
this._handlerProvider = handlerProvider || null;
this._proxies = {};
this._getDataID = getDataID;
this._invalidatedStore = false;
this._idsMarkedForInvalidation = new Set();
this._missingFieldHandlers = missingFieldHandlers;
}

publishSource(
Expand Down Expand Up @@ -176,7 +180,12 @@ class RelayRecordSourceProxy implements RecordSourceProxy {
query: UpdatableQuery<TVariables, TData>,
variables: TVariables,
): UpdatableData<TData> {
return readUpdatableQuery_EXPERIMENTAL(query, variables, this);
return readUpdatableQuery_EXPERIMENTAL(
query,
variables,
this,
this._missingFieldHandlers,
);
}

readUpdatableFragment_EXPERIMENTAL<TFragmentType: FragmentType, TData>(
Expand All @@ -187,6 +196,7 @@ class RelayRecordSourceProxy implements RecordSourceProxy {
fragment,
fragmentReference,
this,
this._missingFieldHandlers,
);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import type {
RecordProxy,
RecordSourceProxy,
RecordSourceSelectorProxy,
MissingFieldHandler,
SingularReaderSelector,
UpdatableData,
} from '../store/RelayStoreTypes';
Expand Down Expand Up @@ -50,15 +51,18 @@ class RelayRecordSourceSelectorProxy implements RecordSourceSelectorProxy {
__mutator: RelayRecordSourceMutator;
__recordSource: RecordSourceProxy;
_readSelector: SingularReaderSelector;
_missingFieldHandlers: $ReadOnlyArray<MissingFieldHandler>;

constructor(
mutator: RelayRecordSourceMutator,
recordSource: RecordSourceProxy,
readSelector: SingularReaderSelector,
missingFieldHandlers: $ReadOnlyArray<MissingFieldHandler>,
) {
this.__mutator = mutator;
this.__recordSource = recordSource;
this._readSelector = readSelector;
this._missingFieldHandlers = missingFieldHandlers;
}

create(dataID: DataID, typeName: string): RecordProxy {
Expand Down Expand Up @@ -136,7 +140,12 @@ class RelayRecordSourceSelectorProxy implements RecordSourceSelectorProxy {
query: UpdatableQuery<TVariables, TData>,
variables: TVariables,
): UpdatableData<TData> {
return readUpdatableQuery_EXPERIMENTAL(query, variables, this);
return readUpdatableQuery_EXPERIMENTAL(
query,
variables,
this,
this._missingFieldHandlers,
);
}

readUpdatableFragment_EXPERIMENTAL<TFragmentType: FragmentType, TData>(
Expand All @@ -147,6 +156,7 @@ class RelayRecordSourceSelectorProxy implements RecordSourceSelectorProxy {
fragment,
fragmentReference,
this,
this._missingFieldHandlers,
);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,12 @@ describe('RelayRecordSourceProxy', () => {
baseSource = new RelayRecordSource(simpleClone(initialData));
sinkSource = new RelayRecordSource({});
mutator = new RelayRecordSourceMutator(baseSource, sinkSource);
store = new RelayRecordSourceProxy(mutator, defaultGetDataID);
store = new RelayRecordSourceProxy(
mutator,
defaultGetDataID,
undefined,
[],
);
});

describe('get()', () => {
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit c0d0198

Please sign in to comment.