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