relay-runtime
Version:
A core runtime for building GraphQL-driven applications.
267 lines (266 loc) • 11.7 kB
JavaScript
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault")["default"];
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.GraphModeNormalizer = void 0;
exports.normalizeResponse = normalizeResponse;
exports.normalizeResponseWithMetadata = normalizeResponseWithMetadata;
var _createForOfIteratorHelper2 = _interopRequireDefault(require("@babel/runtime/helpers/createForOfIteratorHelper"));
var _objectSpread2 = _interopRequireDefault(require("@babel/runtime/helpers/objectSpread2"));
var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
var _require = require('../util/RelayConcreteNode'),
CLIENT_EXTENSION = _require.CLIENT_EXTENSION,
CONDITION = _require.CONDITION,
DEFER = _require.DEFER,
FRAGMENT_SPREAD = _require.FRAGMENT_SPREAD,
INLINE_FRAGMENT = _require.INLINE_FRAGMENT,
LINKED_FIELD = _require.LINKED_FIELD,
LINKED_HANDLE = _require.LINKED_HANDLE,
SCALAR_FIELD = _require.SCALAR_FIELD,
SCALAR_HANDLE = _require.SCALAR_HANDLE;
var _require2 = require('./RelayConcreteVariables'),
getLocalVariables = _require2.getLocalVariables;
var _require3 = require('./RelayModernSelector'),
createNormalizationSelector = _require3.createNormalizationSelector;
var _require4 = require('./RelayStoreUtils'),
ROOT_TYPE = _require4.ROOT_TYPE,
TYPENAME_KEY = _require4.TYPENAME_KEY,
getStorageKey = _require4.getStorageKey;
var invariant = require('invariant');
var _require5 = require('relay-runtime'),
generateClientID = _require5.generateClientID;
function normalizeResponse(response, selector, options) {
var node = selector.node,
variables = selector.variables,
dataID = selector.dataID;
var normalizer = new GraphModeNormalizer(variables, options);
return normalizer.normalizeResponse(node, dataID, response);
}
function normalizeResponseWithMetadata(response, selector, options) {
var node = selector.node,
variables = selector.variables,
dataID = selector.dataID;
var normalizer = new GraphModeNormalizer(variables, options);
var chunks = Array.from(normalizer.normalizeResponse(node, dataID, response));
return [chunks, {
duplicateFieldsAvoided: normalizer.duplicateFieldsAvoided
}];
}
var GraphModeNormalizer = /*#__PURE__*/function () {
function GraphModeNormalizer(variables, options) {
this._actorIdentifier = options.actorIdentifier;
this._path = options.path ? (0, _toConsumableArray2["default"])(options.path) : [];
this._getDataID = options.getDataID;
this._cacheKeyToStreamID = new Map();
this._sentFields = new Map();
this._nextStreamID = 0;
this._variables = variables;
this.duplicateFieldsAvoided = 0;
}
var _proto = GraphModeNormalizer.prototype;
_proto._getStreamID = function _getStreamID() {
return this._nextStreamID++;
};
_proto._getSentFields = function _getSentFields(cacheKey) {
var maybeSent = this._sentFields.get(cacheKey);
if (maybeSent != null) {
return maybeSent;
}
var sent = new Set();
this._sentFields.set(cacheKey, sent);
return sent;
};
_proto._getObjectType = function _getObjectType(data) {
var typeName = data[TYPENAME_KEY];
!(typeName != null) ? process.env.NODE_ENV !== "production" ? invariant(false, 'Expected a typename for record `%s`.', JSON.stringify(data, null, 2)) : invariant(false) : void 0;
return typeName;
};
_proto._getStorageKey = function _getStorageKey(selection) {
return getStorageKey(selection, this._variables);
};
_proto._getVariableValue = function _getVariableValue(name) {
!this._variables.hasOwnProperty(name) ? process.env.NODE_ENV !== "production" ? invariant(false, 'Unexpected undefined variable `%s`.', name) : invariant(false) : void 0;
return this._variables[name];
};
_proto.normalizeResponse = function* normalizeResponse(node, dataID, data) {
var rootFields = {};
yield* this._traverseSelections(node, data, rootFields, dataID, new Set());
var $streamID = this._getStreamID();
yield (0, _objectSpread2["default"])((0, _objectSpread2["default"])({}, rootFields), {}, {
$kind: 'Record',
$streamID: $streamID,
__id: dataID,
__typename: ROOT_TYPE
});
yield {
$kind: 'Complete'
};
};
_proto._flushFields = function* _flushFields(cacheKey, typename, fields) {
var maybeStreamID = this._cacheKeyToStreamID.get(cacheKey);
var $streamID = maybeStreamID !== null && maybeStreamID !== void 0 ? maybeStreamID : this._getStreamID();
if (maybeStreamID == null) {
this._cacheKeyToStreamID.set(cacheKey, $streamID);
yield (0, _objectSpread2["default"])((0, _objectSpread2["default"])({}, fields), {}, {
$kind: 'Record',
__typename: typename,
__id: cacheKey,
$streamID: $streamID
});
} else if (Object.keys(fields).length > 0) {
yield (0, _objectSpread2["default"])((0, _objectSpread2["default"])({}, fields), {}, {
$kind: 'Extend',
$streamID: $streamID
});
}
return $streamID;
};
_proto._traverseSelections = function* _traverseSelections(node, data, parentFields, parentID, sentFields) {
var selections = node.selections;
var _iterator = (0, _createForOfIteratorHelper2["default"])(selections),
_step;
try {
for (_iterator.s(); !(_step = _iterator.n()).done;) {
var selection = _step.value;
switch (selection.kind) {
case LINKED_FIELD:
{
var _selection$alias;
var responseKey = (_selection$alias = selection.alias) !== null && _selection$alias !== void 0 ? _selection$alias : selection.name;
var fieldData = data[responseKey];
var storageKey = this._getStorageKey(selection);
this._path.push(responseKey);
var fieldValue = yield* this._traverseLinkedField(selection.plural, fieldData, storageKey, selection, parentID);
this._path.pop();
if (sentFields.has(storageKey)) {
this.duplicateFieldsAvoided++;
break;
}
parentFields[storageKey] = fieldValue;
sentFields.add(storageKey);
break;
}
case SCALAR_FIELD:
{
var _selection$alias2;
var _responseKey = (_selection$alias2 = selection.alias) !== null && _selection$alias2 !== void 0 ? _selection$alias2 : selection.name;
var _storageKey = this._getStorageKey(selection);
if (sentFields.has(_storageKey)) {
this.duplicateFieldsAvoided++;
break;
}
var _fieldData = data[_responseKey];
parentFields[_storageKey] = _fieldData;
sentFields.add(_storageKey);
break;
}
case INLINE_FRAGMENT:
{
var objType = this._getObjectType(data);
var abstractKey = selection.abstractKey;
if (abstractKey == null) {
if (objType !== selection.type) {
break;
}
} else if (!data.hasOwnProperty(abstractKey)) {
break;
}
yield* this._traverseSelections(selection, data, parentFields, parentID, sentFields);
break;
}
case FRAGMENT_SPREAD:
{
var prevVariables = this._variables;
this._variables = getLocalVariables(this._variables, selection.fragment.argumentDefinitions, selection.args);
yield* this._traverseSelections(selection.fragment, data, parentFields, parentID, sentFields);
this._variables = prevVariables;
break;
}
case CONDITION:
var conditionValue = Boolean(this._getVariableValue(selection.condition));
if (conditionValue === selection.passingValue) {
yield* this._traverseSelections(selection, data, parentFields, parentID, sentFields);
}
break;
case DEFER:
var isDeferred = selection["if"] === null || this._getVariableValue(selection["if"]);
if (isDeferred === false) {
yield* this._traverseSelections(selection, data, parentFields, parentID, sentFields);
} else {
this._incrementalPlaceholders.push({
kind: 'defer',
data: data,
label: selection.label,
path: (0, _toConsumableArray2["default"])(this._path),
selector: createNormalizationSelector(selection, parentID, this._variables),
typeName: this._getObjectType(data),
actorIdentifier: this._actorIdentifier
});
}
break;
case CLIENT_EXTENSION:
break;
case SCALAR_HANDLE:
case LINKED_HANDLE:
break;
default:
throw new Error("Unexpected selection type: ".concat(selection.kind));
}
}
} catch (err) {
_iterator.e(err);
} finally {
_iterator.f();
}
};
_proto._traverseLinkedField = function* _traverseLinkedField(plural, fieldData, storageKey, selection, parentID, index) {
var _selection$concreteTy;
if (fieldData == null) {
return null;
}
if (plural) {
!Array.isArray(fieldData) ? process.env.NODE_ENV !== "production" ? invariant(false, "Expected fieldData to be an array. Got ".concat(JSON.stringify(fieldData))) : invariant(false) : void 0;
var fieldValue = [];
var _iterator2 = (0, _createForOfIteratorHelper2["default"])(fieldData.entries()),
_step2;
try {
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
var _step2$value = _step2.value,
i = _step2$value[0],
itemData = _step2$value[1];
this._path.push(String(i));
var itemValue = yield* this._traverseLinkedField(false, itemData, storageKey, selection, parentID, i);
this._path.pop();
fieldValue.push(itemValue);
}
} catch (err) {
_iterator2.e(err);
} finally {
_iterator2.f();
}
var ids = fieldValue.map(function (value) {
if (value == null) {
return null;
}
!(typeof value.__id === 'number') ? process.env.NODE_ENV !== "production" ? invariant(false, 'Expected objects in a plural linked field to have an __id.') : invariant(false) : void 0;
return value.__id;
});
return {
__ids: ids
};
}
!(typeof fieldData === 'object') ? process.env.NODE_ENV !== "production" ? invariant(false, 'Expected data for field `%s` to be an object.', storageKey) : invariant(false) : void 0;
var objType = (_selection$concreteTy = selection.concreteType) !== null && _selection$concreteTy !== void 0 ? _selection$concreteTy : this._getObjectType(fieldData);
var nextID = this._getDataID(fieldData, objType) || generateClientID(parentID, storageKey, index);
!(typeof nextID === 'string') ? process.env.NODE_ENV !== "production" ? invariant(false, 'Expected id on field `%s` to be a string.', storageKey) : invariant(false) : void 0;
var fields = {};
yield* this._traverseSelections(selection, fieldData, fields, nextID, this._getSentFields(nextID));
var $streamID = yield* this._flushFields(nextID, objType, fields);
return {
__id: $streamID
};
};
return GraphModeNormalizer;
}();
exports.GraphModeNormalizer = GraphModeNormalizer;