Files
30-seconds-of-code/node_modules/relay-runtime/lib/RelayModernQueryExecutor.js
2019-08-20 15:52:05 +02:00

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
};