Skip to content

Commit

Permalink
Support Graph Mode GraphQL response data processing
Browse files Browse the repository at this point in the history
Reviewed By: voideanvalue

Differential Revision: D48698421

fbshipit-source-id: 6259e5468e9d14b856f2881294ba5f07f4144811
  • Loading branch information
Wenting Hu authored and facebook-github-bot committed Sep 12, 2023
1 parent 79ba933 commit bb50fdf
Show file tree
Hide file tree
Showing 5 changed files with 75 additions and 28 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ const RelayDefaultHandlerProvider = require('../handlers/RelayDefaultHandlerProv
const RelayObservable = require('../network/RelayObservable');
const defaultGetDataID = require('../store/defaultGetDataID');
const defaultRequiredFieldLogger = require('../store/defaultRequiredFieldLogger');
const normalizeResponse = require('../store/normalizeResponse');
const OperationExecutor = require('../store/OperationExecutor');
const RelayModernStore = require('../store/RelayModernStore');
const RelayRecordSource = require('../store/RelayRecordSource');
Expand Down Expand Up @@ -469,6 +470,7 @@ class MultiActorEnvironment implements IMultiActorEnvironment {
treatMissingFieldsAsNull: this._treatMissingFieldsAsNull,
updater,
log: this._logFn,
normalizeResponse: normalizeResponse,
});
return () => executor.cancel();
});
Expand Down
38 changes: 10 additions & 28 deletions packages/relay-runtime/store/OperationExecutor.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ import type {
import type {DataID, Disposable, Variables} from '../util/RelayRuntimeTypes';
import type {GetDataID} from './RelayResponseNormalizer';
import type {NormalizationOptions} from './RelayResponseNormalizer';

Check warning on line 53 in packages/relay-runtime/store/OperationExecutor.js

View workflow job for this annotation

GitHub Actions / JS Lint

'NormalizationOptions' is defined but never used
import type {NormalizeResponseFunction} from './RelayStoreTypes';

const RelayObservable = require('../network/RelayObservable');
const generateID = require('../util/generateID');
Expand All @@ -77,6 +78,7 @@ export type ExecuteConfig<TMutation: MutationParameters> = {
+getDataID: GetDataID,
+getPublishQueue: (actorIdentifier: ActorIdentifier) => PublishQueue,
+getStore: (actorIdentifier: ActorIdentifier) => Store,
+normalizeResponse: NormalizeResponseFunction,
+isClientPayload?: boolean,
+operation: OperationDescriptor,
+operationExecutions: Map<string, ActiveState>,
Expand Down Expand Up @@ -157,6 +159,7 @@ class Executor<TMutation: MutationParameters> {
+_isClientPayload: boolean;
+_isSubscriptionOperation: boolean;
+_seenActors: Set<ActorIdentifier>;
_normalizeResponse: NormalizeResponseFunction;

constructor({
actorIdentifier,
Expand All @@ -176,6 +179,7 @@ class Executor<TMutation: MutationParameters> {
treatMissingFieldsAsNull,
updater,
log,
normalizeResponse,
}: ExecuteConfig<TMutation>): void {
this._actorIdentifier = actorIdentifier;
this._getDataID = getDataID;
Expand Down Expand Up @@ -207,6 +211,7 @@ class Executor<TMutation: MutationParameters> {
this._retainDisposables = new Map();
this._seenActors = new Set();
this._completeFns = [];
this._normalizeResponse = normalizeResponse;

const id = this._nextSubscriptionId++;
source.subscribe({
Expand Down Expand Up @@ -575,7 +580,7 @@ class Executor<TMutation: MutationParameters> {
}
const optimisticUpdates: Array<OptimisticUpdate<TMutation>> = [];
if (response) {
const payload = normalizeResponse(
const payload = this._normalizeResponse(
response,
this._operation.root,
ROOT_TYPE,
Expand Down Expand Up @@ -684,7 +689,7 @@ class Executor<TMutation: MutationParameters> {
followupPayload.dataID,
variables,
);
return normalizeResponse(
return this._normalizeResponse(
{data: followupPayload.data},
selector,
followupPayload.typeName,
Expand Down Expand Up @@ -762,7 +767,7 @@ class Executor<TMutation: MutationParameters> {
this._incrementalResults.clear();
this._source.clear();
return responses.map(payloadPart => {
const relayPayload = normalizeResponse(
const relayPayload = this._normalizeResponse(
payloadPart,
this._operation.root,
ROOT_TYPE,
Expand Down Expand Up @@ -1215,7 +1220,7 @@ class Executor<TMutation: MutationParameters> {
const prevActorIdentifier = this._actorIdentifier;
this._actorIdentifier =
placeholder.actorIdentifier ?? this._actorIdentifier;
const relayPayload = normalizeResponse(
const relayPayload = this._normalizeResponse(
response,
placeholder.selector,
placeholder.typeName,
Expand Down Expand Up @@ -1446,7 +1451,7 @@ class Executor<TMutation: MutationParameters> {
record: nextParentRecord,
fieldPayloads,
});
const relayPayload = normalizeResponse(response, selector, typeName, {
const relayPayload = this._normalizeResponse(response, selector, typeName, {
actorIdentifier: this._actorIdentifier,
getDataID: this._getDataID,
path: [...normalizationPath, responseKey, String(itemIndex)],
Expand Down Expand Up @@ -1582,29 +1587,6 @@ function partitionGraphQLResponses(
return [nonIncrementalResponses, incrementalResponses];
}

function normalizeResponse(
response: GraphQLResponseWithData,
selector: NormalizationSelector,
typeName: string,
options: NormalizationOptions,
): RelayResponsePayload {
const {data, errors} = response;
const source = RelayRecordSource.create();
const record = RelayModernRecord.create(selector.dataID, typeName);
source.set(selector.dataID, record);
const relayPayload = RelayResponseNormalizer.normalize(
source,
selector,
data,
options,
);
return {
...relayPayload,
errors,
isFinal: response.extensions?.is_final === true,
};
}

function stableStringify(value: mixed): string {
return JSON.stringify(stableCopy(value)) ?? ''; // null-check for flow
}
Expand Down
6 changes: 6 additions & 0 deletions packages/relay-runtime/store/RelayModernEnvironment.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import type {
LogFunction,
MissingFieldHandler,
MutationParameters,
NormalizeResponseFunction,
OperationAvailability,
OperationDescriptor,
OperationLoader,
Expand Down Expand Up @@ -55,6 +56,7 @@ const RelayOperationTracker = require('../store/RelayOperationTracker');
const registerEnvironmentWithDevTools = require('../util/registerEnvironmentWithDevTools');
const defaultGetDataID = require('./defaultGetDataID');
const defaultRequiredFieldLogger = require('./defaultRequiredFieldLogger');
const normalizeResponse = require('./normalizeResponse');
const OperationExecutor = require('./OperationExecutor');
const RelayPublishQueue = require('./RelayPublishQueue');
const RelayRecordSource = require('./RelayRecordSource');
Expand All @@ -67,6 +69,7 @@ export type EnvironmentConfig = {
+log?: ?LogFunction,
+operationLoader?: ?OperationLoader,
+network: INetwork,
+normalizeResponse?: ?NormalizeResponseFunction,
+scheduler?: ?TaskScheduler,
+store: Store,
+missingFieldHandlers?: ?$ReadOnlyArray<MissingFieldHandler>,
Expand Down Expand Up @@ -97,6 +100,7 @@ class RelayModernEnvironment implements IEnvironment {
+options: mixed;
+_isServer: boolean;
requiredFieldLogger: RequiredFieldLogger;
_normalizeResponse: NormalizeResponseFunction;

constructor(config: EnvironmentConfig) {
this.configName = config.configName;
Expand Down Expand Up @@ -134,6 +138,7 @@ class RelayModernEnvironment implements IEnvironment {
this._store = config.store;
this.options = config.options;
this._isServer = config.isServer ?? false;
this._normalizeResponse = config.normalizeResponse ?? normalizeResponse;

(this: any).__setNet = newNet =>
(this._network = wrapNetworkWithLogObserver(this, newNet));
Expand Down Expand Up @@ -481,6 +486,7 @@ class RelayModernEnvironment implements IEnvironment {
},
treatMissingFieldsAsNull: this._treatMissingFieldsAsNull,
updater,
normalizeResponse: this._normalizeResponse,
});
return () => executor.cancel();
});
Expand Down
9 changes: 9 additions & 0 deletions packages/relay-runtime/store/RelayStoreTypes.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import type {
} from '../multi-actor-environment';
import type {
GraphQLResponse,
GraphQLResponseWithData,
INetwork,
PayloadData,
PayloadError,
Expand Down Expand Up @@ -56,6 +57,7 @@ import type {
import type {InvalidationState} from './RelayModernStore';
import type RelayOperationTracker from './RelayOperationTracker';
import type {RecordState} from './RelayRecordState';
import type {NormalizationOptions} from './RelayResponseNormalizer';

export opaque type FragmentType = empty;
export type OperationTracker = RelayOperationTracker;
Expand Down Expand Up @@ -1071,6 +1073,13 @@ export type StreamPlaceholder = {
};
export type IncrementalDataPlaceholder = DeferPlaceholder | StreamPlaceholder;

export type NormalizeResponseFunction = (
response: GraphQLResponseWithData,
selector: NormalizationSelector,
typeName: string,
options: NormalizationOptions,
) => RelayResponsePayload;

/**
* A user-supplied object to load a generated operation (SplitOperation or
* ConcreteRequest) AST by a module reference. The exact format of a module
Expand Down
48 changes: 48 additions & 0 deletions packages/relay-runtime/store/normalizeResponse.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict-local
* @format
* @oncall relay
*/

'use strict';

import type {GraphQLResponseWithData} from '../network/RelayNetworkTypes';
import type {NormalizationOptions} from './RelayResponseNormalizer';
import type {
NormalizationSelector,
RelayResponsePayload,
} from './RelayStoreTypes';

import RelayModernRecord from './RelayModernRecord';
import RelayRecordSource from './RelayRecordSource';
import RelayResponseNormalizer from './RelayResponseNormalizer';

function normalizeResponse(
response: GraphQLResponseWithData,
selector: NormalizationSelector,
typeName: string,
options: NormalizationOptions,
): RelayResponsePayload {
const {data, errors} = response;
const source = RelayRecordSource.create();
const record = RelayModernRecord.create(selector.dataID, typeName);
source.set(selector.dataID, record);
const relayPayload = RelayResponseNormalizer.normalize(
source,
selector,
data,
options,
);
return {
...relayPayload,
errors,
isFinal: response.extensions?.is_final === true,
};
}

module.exports = normalizeResponse;

0 comments on commit bb50fdf

Please sign in to comment.