301 lines
8.0 KiB
JavaScript
301 lines
8.0 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
|
|
*/
|
|
'use strict';
|
|
|
|
var _objectSpread2 = require("@babel/runtime/helpers/interopRequireDefault")(require("@babel/runtime/helpers/objectSpread"));
|
|
|
|
/**
|
|
* @public
|
|
*
|
|
* An implementation of the `Store` interface defined in `RelayStoreTypes`.
|
|
*
|
|
* Note that a Store takes ownership of all records provided to it: other
|
|
* objects may continue to hold a reference to such records but may not mutate
|
|
* them. The static Relay core is architected to avoid mutating records that may have been
|
|
* passed to a store: operations that mutate records will either create fresh
|
|
* records or clone existing records and modify the clones. Record immutability
|
|
* is also enforced in development mode by freezing all records passed to a store.
|
|
*/
|
|
var RelayModernStore =
|
|
/*#__PURE__*/
|
|
function () {
|
|
function RelayModernStore(source) {
|
|
var gcScheduler = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : require("fbjs/lib/resolveImmediate");
|
|
var operationLoader = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null;
|
|
|
|
// Prevent mutation of a record from outside the store.
|
|
if (process.env.NODE_ENV !== "production") {
|
|
var storeIDs = source.getRecordIDs();
|
|
|
|
for (var ii = 0; ii < storeIDs.length; ii++) {
|
|
var record = source.get(storeIDs[ii]);
|
|
|
|
if (record) {
|
|
require("./RelayModernRecord").freeze(record);
|
|
}
|
|
}
|
|
}
|
|
|
|
this._gcScheduler = gcScheduler;
|
|
this._hasScheduledGC = false;
|
|
this._index = 0;
|
|
this._operationLoader = operationLoader;
|
|
this._recordSource = source;
|
|
this._roots = new Map();
|
|
this._subscriptions = new Set();
|
|
this._updatedRecordIDs = {};
|
|
this._gcHoldCounter = 0;
|
|
this._shouldScheduleGC = false;
|
|
}
|
|
|
|
var _proto = RelayModernStore.prototype;
|
|
|
|
_proto.getSource = function getSource() {
|
|
return this._recordSource;
|
|
};
|
|
|
|
_proto.check = function check(selector) {
|
|
return require("./DataChecker").check(this._recordSource, this._recordSource, selector, [], this._operationLoader);
|
|
};
|
|
|
|
_proto.retain = function retain(selector) {
|
|
var _this = this;
|
|
|
|
var index = this._index++;
|
|
|
|
var dispose = function dispose() {
|
|
_this._roots["delete"](index);
|
|
|
|
_this._scheduleGC();
|
|
};
|
|
|
|
this._roots.set(index, selector);
|
|
|
|
return {
|
|
dispose: dispose
|
|
};
|
|
};
|
|
|
|
_proto.lookup = function lookup(selector, owner) {
|
|
var snapshot = require("./RelayReader").read(this._recordSource, selector, owner);
|
|
|
|
if (process.env.NODE_ENV !== "production") {
|
|
require("./deepFreeze")(snapshot);
|
|
}
|
|
|
|
return snapshot;
|
|
};
|
|
|
|
_proto.notify = function notify() {
|
|
var _this2 = this;
|
|
|
|
this._subscriptions.forEach(function (subscription) {
|
|
_this2._updateSubscription(subscription);
|
|
});
|
|
|
|
this._updatedRecordIDs = {};
|
|
};
|
|
|
|
_proto.publish = function publish(source) {
|
|
updateTargetFromSource(this._recordSource, source, this._updatedRecordIDs);
|
|
};
|
|
|
|
_proto.subscribe = function subscribe(snapshot, callback) {
|
|
var _this3 = this;
|
|
|
|
var subscription = {
|
|
callback: callback,
|
|
snapshot: snapshot
|
|
};
|
|
|
|
var dispose = function dispose() {
|
|
_this3._subscriptions["delete"](subscription);
|
|
};
|
|
|
|
this._subscriptions.add(subscription);
|
|
|
|
return {
|
|
dispose: dispose
|
|
};
|
|
};
|
|
|
|
_proto.holdGC = function holdGC() {
|
|
var _this4 = this;
|
|
|
|
this._gcHoldCounter++;
|
|
|
|
var dispose = function dispose() {
|
|
if (_this4._gcHoldCounter > 0) {
|
|
_this4._gcHoldCounter--;
|
|
|
|
if (_this4._gcHoldCounter === 0 && _this4._shouldScheduleGC) {
|
|
_this4._scheduleGC();
|
|
|
|
_this4._shouldScheduleGC = false;
|
|
}
|
|
}
|
|
};
|
|
|
|
return {
|
|
dispose: dispose
|
|
};
|
|
};
|
|
|
|
_proto.toJSON = function toJSON() {
|
|
return 'RelayModernStore()';
|
|
}; // Internal API
|
|
|
|
|
|
_proto.__getUpdatedRecordIDs = function __getUpdatedRecordIDs() {
|
|
return this._updatedRecordIDs;
|
|
};
|
|
|
|
_proto._updateSubscription = function _updateSubscription(subscription) {
|
|
var callback = subscription.callback,
|
|
snapshot = subscription.snapshot;
|
|
|
|
if (!require("./hasOverlappingIDs")(snapshot, this._updatedRecordIDs)) {
|
|
return;
|
|
}
|
|
|
|
var _RelayReader$read = require("./RelayReader").read(this._recordSource, snapshot, snapshot.owner),
|
|
data = _RelayReader$read.data,
|
|
seenRecords = _RelayReader$read.seenRecords;
|
|
|
|
var nextData = require("./recycleNodesInto")(snapshot.data, data);
|
|
|
|
var nextSnapshot = (0, _objectSpread2["default"])({}, snapshot, {
|
|
data: nextData,
|
|
seenRecords: seenRecords
|
|
});
|
|
|
|
if (process.env.NODE_ENV !== "production") {
|
|
require("./deepFreeze")(nextSnapshot);
|
|
}
|
|
|
|
subscription.snapshot = nextSnapshot;
|
|
|
|
if (nextSnapshot.data !== snapshot.data) {
|
|
callback(nextSnapshot);
|
|
}
|
|
};
|
|
|
|
_proto._scheduleGC = function _scheduleGC() {
|
|
var _this5 = this;
|
|
|
|
if (this._gcHoldCounter > 0) {
|
|
this._shouldScheduleGC = true;
|
|
return;
|
|
}
|
|
|
|
if (this._hasScheduledGC) {
|
|
return;
|
|
}
|
|
|
|
this._hasScheduledGC = true;
|
|
|
|
this._gcScheduler(function () {
|
|
_this5.__gc();
|
|
|
|
_this5._hasScheduledGC = false;
|
|
});
|
|
};
|
|
|
|
_proto.__gc = function __gc() {
|
|
var _this6 = this;
|
|
|
|
var references = new Set(); // Mark all records that are traversable from a root
|
|
|
|
this._roots.forEach(function (selector) {
|
|
require("./RelayReferenceMarker").mark(_this6._recordSource, selector, references, _this6._operationLoader);
|
|
}); // Short-circuit if *nothing* is referenced
|
|
|
|
|
|
if (!references.size) {
|
|
this._recordSource.clear();
|
|
|
|
return;
|
|
} // Evict any unreferenced nodes
|
|
|
|
|
|
var storeIDs = this._recordSource.getRecordIDs();
|
|
|
|
for (var ii = 0; ii < storeIDs.length; ii++) {
|
|
var dataID = storeIDs[ii];
|
|
|
|
if (!references.has(dataID)) {
|
|
this._recordSource.remove(dataID);
|
|
}
|
|
}
|
|
};
|
|
|
|
return RelayModernStore;
|
|
}();
|
|
/**
|
|
* Updates the target with information from source, also updating a mapping of
|
|
* which records in the target were changed as a result.
|
|
*/
|
|
|
|
|
|
function updateTargetFromSource(target, source, updatedRecordIDs) {
|
|
var dataIDs = source.getRecordIDs();
|
|
|
|
for (var ii = 0; ii < dataIDs.length; ii++) {
|
|
var dataID = dataIDs[ii];
|
|
var sourceRecord = source.get(dataID);
|
|
var targetRecord = target.get(dataID); // Prevent mutation of a record from outside the store.
|
|
|
|
if (process.env.NODE_ENV !== "production") {
|
|
if (sourceRecord) {
|
|
require("./RelayModernRecord").freeze(sourceRecord);
|
|
}
|
|
}
|
|
|
|
if (sourceRecord === require("./RelayStoreUtils").UNPUBLISH_RECORD_SENTINEL) {
|
|
// Unpublish a record
|
|
target.remove(dataID);
|
|
updatedRecordIDs[dataID] = true;
|
|
} else if (sourceRecord && targetRecord) {
|
|
var nextRecord = require("./RelayModernRecord").update(targetRecord, sourceRecord);
|
|
|
|
if (nextRecord !== targetRecord) {
|
|
// Prevent mutation of a record from outside the store.
|
|
if (process.env.NODE_ENV !== "production") {
|
|
require("./RelayModernRecord").freeze(nextRecord);
|
|
}
|
|
|
|
updatedRecordIDs[dataID] = true;
|
|
target.set(dataID, nextRecord);
|
|
}
|
|
} else if (sourceRecord === null) {
|
|
target["delete"](dataID);
|
|
|
|
if (targetRecord !== null) {
|
|
updatedRecordIDs[dataID] = true;
|
|
}
|
|
} else if (sourceRecord) {
|
|
target.set(dataID, sourceRecord);
|
|
updatedRecordIDs[dataID] = true;
|
|
} // don't add explicit undefined
|
|
|
|
}
|
|
}
|
|
|
|
require("./RelayProfiler").instrumentMethods(RelayModernStore.prototype, {
|
|
lookup: 'RelayModernStore.prototype.lookup',
|
|
notify: 'RelayModernStore.prototype.notify',
|
|
publish: 'RelayModernStore.prototype.publish',
|
|
retain: 'RelayModernStore.prototype.retain',
|
|
subscribe: 'RelayModernStore.prototype.subscribe',
|
|
__gc: 'RelayModernStore.prototype.__gc',
|
|
holdGC: 'RelayModernStore.prototype.holdGC'
|
|
});
|
|
|
|
module.exports = RelayModernStore; |