172 lines
6.1 KiB
JavaScript
172 lines
6.1 KiB
JavaScript
/**
|
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
*
|
|
* This source code is licensed under the MIT license found in the
|
|
* LICENSE file in the root directory of this source tree.
|
|
*
|
|
* strict-local
|
|
* @format
|
|
* @emails oncall+relay
|
|
*/
|
|
'use strict';
|
|
|
|
/**
|
|
* Coordinates the execution of a query, handling network callbacks
|
|
* including optimistic payloads, standard payloads, resolution of match
|
|
* dependencies, etc.
|
|
*/
|
|
function execute(_ref) {
|
|
var network = _ref.network,
|
|
publishQueue = _ref.publishQueue,
|
|
operation = _ref.operation,
|
|
operationLoader = _ref.operationLoader,
|
|
cacheConfig = _ref.cacheConfig,
|
|
updater = _ref.updater;
|
|
return require("./RelayObservable").create(function (sink) {
|
|
var optimisticResponse = null;
|
|
var subscriptions = new Set();
|
|
|
|
function start(subscription) {
|
|
// NOTE: store the subscription object on the observer so that it
|
|
// can be cleaned up in complete() or the dispose function.
|
|
this._subscription = subscription;
|
|
subscriptions.add(subscription);
|
|
}
|
|
|
|
function complete() {
|
|
subscriptions["delete"](this._subscription);
|
|
|
|
if (subscriptions.size === 0) {
|
|
sink.complete();
|
|
}
|
|
} // Convert each GraphQLResponse from the network to a RelayResponsePayload
|
|
// and process it
|
|
|
|
|
|
function next(response) {
|
|
var _response$extensions;
|
|
|
|
var payload = require("./normalizePayload")(operation, response);
|
|
|
|
var isOptimistic = ((_response$extensions = response.extensions) === null || _response$extensions === void 0 ? void 0 : _response$extensions.isOptimistic) === true;
|
|
processRelayPayload(payload, operation, updater, isOptimistic);
|
|
sink.next(response);
|
|
} // Each RelayResponsePayload contains both data to publish to the store
|
|
// immediately, but may also contain matchPayloads that need to be
|
|
// asynchronously normalized into RelayResponsePayloads, which may
|
|
// themselves have matchPayloads: this function is recursive and relies
|
|
// on GraphQL queries *disallowing* recursion to ensure termination.
|
|
|
|
|
|
var processRelayPayload = function processRelayPayload(payload) {
|
|
var operationDescriptor = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
|
|
var payloadUpdater = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null;
|
|
var isOptimistic = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
|
|
var matchPayloads = payload.matchPayloads;
|
|
|
|
if (matchPayloads && matchPayloads.length) {
|
|
!operationLoader ? process.env.NODE_ENV !== "production" ? require("fbjs/lib/invariant")(false, 'RelayModernEnvironment: Expected an operationLoader to be ' + 'configured when using `@match`.') : require("fbjs/lib/invariant")(false) : void 0;
|
|
matchPayloads.forEach(function (matchPayload) {
|
|
processMatchPayload(processRelayPayload, operationLoader, matchPayload).subscribe({
|
|
complete: complete,
|
|
error: sink.error,
|
|
start: start
|
|
});
|
|
});
|
|
}
|
|
|
|
if (isOptimistic) {
|
|
!(optimisticResponse === null) ? process.env.NODE_ENV !== "production" ? require("fbjs/lib/invariant")(false, 'environment.execute: only support one optimistic response per ' + 'execute.') : require("fbjs/lib/invariant")(false) : void 0;
|
|
optimisticResponse = {
|
|
source: payload.source,
|
|
fieldPayloads: payload.fieldPayloads
|
|
};
|
|
publishQueue.applyUpdate(optimisticResponse);
|
|
publishQueue.run();
|
|
} else {
|
|
if (optimisticResponse !== null) {
|
|
publishQueue.revertUpdate(optimisticResponse);
|
|
optimisticResponse = null;
|
|
}
|
|
|
|
if (operationDescriptor && payloadUpdater) {
|
|
publishQueue.commitPayload(operationDescriptor, payload, payloadUpdater);
|
|
} else {
|
|
publishQueue.commitRelayPayload(payload);
|
|
}
|
|
|
|
publishQueue.run();
|
|
}
|
|
};
|
|
|
|
var node = operation.node;
|
|
network.execute(node.params, operation.variables, cacheConfig || {}).subscribe({
|
|
complete: complete,
|
|
next: next,
|
|
error: sink.error,
|
|
start: start
|
|
});
|
|
return function () {
|
|
if (subscriptions.size !== 0) {
|
|
subscriptions.forEach(function (sub) {
|
|
return sub.unsubscribe();
|
|
});
|
|
subscriptions.clear();
|
|
}
|
|
|
|
if (optimisticResponse !== null) {
|
|
publishQueue.revertUpdate(optimisticResponse);
|
|
optimisticResponse = null;
|
|
publishQueue.run();
|
|
}
|
|
};
|
|
});
|
|
}
|
|
/**
|
|
* Processes a MatchFieldPayload, asynchronously resolving the fragment,
|
|
* using it to normalize the field data into a RelayResponsePayload.
|
|
* Because @match fields may contain other @match fields, the result of
|
|
* normalizing `matchPayload` may contain *other* MatchFieldPayloads:
|
|
* the processRelayPayload() callback is responsible for publishing
|
|
* both the normalize payload's source as well as recursively calling
|
|
* this function for any matchPayloads it contains.
|
|
*
|
|
* @private
|
|
*/
|
|
|
|
|
|
function processMatchPayload(processRelayPayload, operationLoader, matchPayload) {
|
|
return require("./RelayObservable").from(new Promise(function (resolve, reject) {
|
|
operationLoader.load(matchPayload.operationReference).then(resolve, reject);
|
|
})).map(function (operation) {
|
|
if (operation == null) {
|
|
return;
|
|
}
|
|
|
|
var selector = {
|
|
dataID: matchPayload.dataID,
|
|
variables: matchPayload.variables,
|
|
node: operation
|
|
};
|
|
var source = new (require("./RelayInMemoryRecordSource"))();
|
|
|
|
var matchRecord = require("./RelayModernRecord").create(matchPayload.dataID, matchPayload.typeName);
|
|
|
|
source.set(matchPayload.dataID, matchRecord);
|
|
|
|
var normalizeResult = require("./RelayResponseNormalizer").normalize(source, selector, matchPayload.data);
|
|
|
|
var relayPayload = {
|
|
errors: null,
|
|
// Errors are handled as part of the parent GraphQLResponse
|
|
fieldPayloads: normalizeResult.fieldPayloads,
|
|
matchPayloads: normalizeResult.matchPayloads,
|
|
source: source
|
|
};
|
|
processRelayPayload(relayPayload);
|
|
});
|
|
}
|
|
|
|
module.exports = {
|
|
execute: execute
|
|
}; |