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

316 lines
11 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.
*
*
* @format
*/
'use strict';
var _objectSpread2 = require("@babel/runtime/helpers/interopRequireDefault")(require("@babel/runtime/helpers/objectSpread"));
/**
* @public
*
* Low-level record manipulation methods.
*
* A note about perf: we use long-hand property access rather than computed
* properties in this file for speed ie.
*
* const object = {};
* object[KEY] = value;
* record[storageKey] = object;
*
* instead of:
*
* record[storageKey] = {
* [KEY]: value,
* };
*
* The latter gets transformed by Babel into something like:
*
* function _defineProperty(obj, key, value) {
* if (key in obj) {
* Object.defineProperty(obj, key, {
* value: value,
* enumerable: true,
* configurable: true,
* writable: true,
* });
* } else {
* obj[key] = value;
* }
* return obj;
* }
*
* record[storageKey] = _defineProperty({}, KEY, value);
*
* A quick benchmark shows that computed property access is an order of
* magnitude slower (times in seconds for 100,000 iterations):
*
* best avg sd
* computed 0.02175 0.02292 0.00113
* manual 0.00110 0.00123 0.00008
*/
/**
* @public
*
* Clone a record.
*/
function clone(record) {
return (0, _objectSpread2["default"])({}, record);
}
/**
* @public
*
* Copies all fields from `source` to `sink`, excluding `__id` and `__typename`.
*
* NOTE: This function does not treat `id` specially. To preserve the id,
* manually reset it after calling this function. Also note that values are
* copied by reference and not value; callers should ensure that values are
* copied on write.
*/
function copyFields(source, sink) {
for (var key in source) {
if (source.hasOwnProperty(key)) {
if (key !== require("./RelayStoreUtils").ID_KEY && key !== require("./RelayStoreUtils").TYPENAME_KEY) {
sink[key] = source[key];
}
}
}
}
/**
* @public
*
* Create a new record.
*/
function create(dataID, typeName) {
// See perf note above for why we aren't using computed property access.
var record = {};
record[require("./RelayStoreUtils").ID_KEY] = dataID;
record[require("./RelayStoreUtils").TYPENAME_KEY] = typeName;
return record;
}
/**
* @public
*
* Get the record's `id` if available or the client-generated identifier.
*/
function getDataID(record) {
return record[require("./RelayStoreUtils").ID_KEY];
}
/**
* @public
*
* Get the concrete type of the record.
*/
function getType(record) {
return record[require("./RelayStoreUtils").TYPENAME_KEY];
}
/**
* @public
*
* Get a scalar (non-link) field value.
*/
function getValue(record, storageKey) {
var value = record[storageKey];
if (value && typeof value === 'object') {
!(!value.hasOwnProperty(require("./RelayStoreUtils").REF_KEY) && !value.hasOwnProperty(require("./RelayStoreUtils").REFS_KEY)) ? process.env.NODE_ENV !== "production" ? require("fbjs/lib/invariant")(false, 'RelayModernRecord.getValue(): Expected a scalar (non-link) value for `%s.%s` ' + 'but found %s.', record[require("./RelayStoreUtils").ID_KEY], storageKey, value.hasOwnProperty(require("./RelayStoreUtils").REF_KEY) ? 'a linked record' : 'plural linked records') : require("fbjs/lib/invariant")(false) : void 0;
}
return value;
}
/**
* @public
*
* Get the value of a field as a reference to another record. Throws if the
* field has a different type.
*/
function getLinkedRecordID(record, storageKey) {
var link = record[storageKey];
if (link == null) {
return link;
}
!(typeof link === 'object' && link && typeof link[require("./RelayStoreUtils").REF_KEY] === 'string') ? process.env.NODE_ENV !== "production" ? require("fbjs/lib/invariant")(false, 'RelayModernRecord.getLinkedRecordID(): Expected `%s.%s` to be a linked ID, ' + 'was `%s`.', record[require("./RelayStoreUtils").ID_KEY], storageKey, JSON.stringify(link)) : require("fbjs/lib/invariant")(false) : void 0;
return link[require("./RelayStoreUtils").REF_KEY];
}
/**
* @public
*
* Get the value of a field as a list of references to other records. Throws if
* the field has a different type.
*/
function getLinkedRecordIDs(record, storageKey) {
var links = record[storageKey];
if (links == null) {
return links;
}
!(typeof links === 'object' && Array.isArray(links[require("./RelayStoreUtils").REFS_KEY])) ? process.env.NODE_ENV !== "production" ? require("fbjs/lib/invariant")(false, 'RelayModernRecord.getLinkedRecordIDs(): Expected `%s.%s` to contain an array ' + 'of linked IDs, got `%s`.', record[require("./RelayStoreUtils").ID_KEY], storageKey, JSON.stringify(links)) : require("fbjs/lib/invariant")(false) : void 0; // assume items of the array are ids
return links[require("./RelayStoreUtils").REFS_KEY];
}
/**
* @public
*
* Compares the fields of a previous and new record, returning either the
* previous record if all fields are equal or a new record (with merged fields)
* if any fields have changed.
*/
function update(prevRecord, nextRecord) {
if (process.env.NODE_ENV !== "production") {
var _getType, _getType2;
var prevID = getDataID(prevRecord);
var nextID = getDataID(nextRecord);
process.env.NODE_ENV !== "production" ? require("fbjs/lib/warning")(prevID === nextID, 'RelayModernRecord: Invalid record update, expected both versions of ' + 'the record to have the same id, got `%s` and `%s`.', prevID, nextID) : void 0; // note: coalesce null/undefined to null
var prevType = (_getType = getType(prevRecord)) !== null && _getType !== void 0 ? _getType : null;
var nextType = (_getType2 = getType(nextRecord)) !== null && _getType2 !== void 0 ? _getType2 : null;
process.env.NODE_ENV !== "production" ? require("fbjs/lib/warning")(prevType === nextType, 'RelayModernRecord: Invalid record update, expected both versions of ' + 'record `%s` to have the same `%s` but got conflicting types `%s` ' + 'and `%s`. The GraphQL server likely violated the globally unique ' + 'id requirement by returning the same id for different objects.', prevID, require("./RelayStoreUtils").TYPENAME_KEY, prevType, nextType) : void 0;
}
var updated = null;
var keys = Object.keys(nextRecord);
for (var ii = 0; ii < keys.length; ii++) {
var key = keys[ii];
if (updated || !require("fbjs/lib/areEqual")(prevRecord[key], nextRecord[key])) {
updated = updated !== null ? updated : (0, _objectSpread2["default"])({}, prevRecord);
if (nextRecord[key] !== require("./RelayStoreUtils").UNPUBLISH_FIELD_SENTINEL) {
updated[key] = nextRecord[key];
} else {
delete updated[key];
}
}
}
return updated !== null ? updated : prevRecord;
}
/**
* @public
*
* Returns a new record with the contents of the given records. Fields in the
* second record will overwrite identical fields in the first record.
*/
function merge(record1, record2) {
if (process.env.NODE_ENV !== "production") {
var _getType3, _getType4;
var prevID = getDataID(record1);
var nextID = getDataID(record2);
process.env.NODE_ENV !== "production" ? require("fbjs/lib/warning")(prevID === nextID, 'RelayModernRecord: Invalid record merge, expected both versions of ' + 'the record to have the same id, got `%s` and `%s`.', prevID, nextID) : void 0; // note: coalesce null/undefined to null
var prevType = (_getType3 = getType(record1)) !== null && _getType3 !== void 0 ? _getType3 : null;
var nextType = (_getType4 = getType(record2)) !== null && _getType4 !== void 0 ? _getType4 : null;
process.env.NODE_ENV !== "production" ? require("fbjs/lib/warning")(prevType === nextType, 'RelayModernRecord: Invalid record merge, expected both versions of ' + 'record `%s` to have the same `%s` but got conflicting types `%s` ' + 'and `%s`. The GraphQL server likely violated the globally unique ' + 'id requirement by returning the same id for different objects.', prevID, require("./RelayStoreUtils").TYPENAME_KEY, prevType, nextType) : void 0;
}
return Object.assign({}, record1, record2);
}
/**
* @public
*
* Prevent modifications to the record. Attempts to call `set*` functions on a
* frozen record will fatal at runtime.
*/
function freeze(record) {
require("./deepFreeze")(record);
}
/**
* @public
*
* Set the value of a storageKey to a scalar.
*/
function setValue(record, storageKey, value) {
if (process.env.NODE_ENV !== "production") {
var prevID = getDataID(record);
if (storageKey === require("./RelayStoreUtils").ID_KEY) {
process.env.NODE_ENV !== "production" ? require("fbjs/lib/warning")(prevID === value, 'RelayModernRecord: Invalid field update, expected both versions of ' + 'the record to have the same id, got `%s` and `%s`.', prevID, value) : void 0;
} else if (storageKey === require("./RelayStoreUtils").TYPENAME_KEY) {
var _getType5, _value;
// note: coalesce null/undefined to null
var prevType = (_getType5 = getType(record)) !== null && _getType5 !== void 0 ? _getType5 : null;
var nextType = (_value = value) !== null && _value !== void 0 ? _value : null;
process.env.NODE_ENV !== "production" ? require("fbjs/lib/warning")(prevType === nextType, 'RelayModernRecord: Invalid field update, expected both versions of ' + 'record `%s` to have the same `%s` but got conflicting types `%s` ' + 'and `%s`. The GraphQL server likely violated the globally unique ' + 'id requirement by returning the same id for different objects.', prevID, require("./RelayStoreUtils").TYPENAME_KEY, prevType, nextType) : void 0;
}
}
record[storageKey] = value;
}
/**
* @public
*
* Set the value of a field to a reference to another record.
*/
function setLinkedRecordID(record, storageKey, linkedID) {
// See perf note above for why we aren't using computed property access.
var link = {};
link[require("./RelayStoreUtils").REF_KEY] = linkedID;
record[storageKey] = link;
}
/**
* @public
*
* Set the value of a field to a list of references other records.
*/
function setLinkedRecordIDs(record, storageKey, linkedIDs) {
// See perf note above for why we aren't using computed property access.
var links = {};
links[require("./RelayStoreUtils").REFS_KEY] = linkedIDs;
record[storageKey] = links;
}
module.exports = {
clone: clone,
copyFields: copyFields,
create: create,
freeze: freeze,
getDataID: getDataID,
getLinkedRecordID: getLinkedRecordID,
getLinkedRecordIDs: getLinkedRecordIDs,
getType: getType,
getValue: getValue,
merge: merge,
setValue: setValue,
setLinkedRecordID: setLinkedRecordID,
setLinkedRecordIDs: setLinkedRecordIDs,
update: update
};