3box
Version:
Interact with user data
596 lines (494 loc) • 19.1 kB
JavaScript
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator"));
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));
var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { (0, _defineProperty2["default"])(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
var _require = require('./utils/index'),
throwIfUndefined = _require.throwIfUndefined,
throwIfNotEqualLenArrays = _require.throwIfNotEqualLenArrays;
var KeyValueStore = /*#__PURE__*/function () {
/**
* Please use **box.public** or **box.private** to get the instance of this class
*/
function KeyValueStore(name, replicator, threeId) {
(0, _classCallCheck2["default"])(this, KeyValueStore);
this._name = name;
this._replicator = replicator;
if (this._name.startsWith('3box.space.')) {
this._space = this._name.split('.')[2];
}
this._3id = threeId;
}
/**
* Get the value and optionally metadata of the given key
*
* @param {String} key the key
* @param {Object} opts optional parameters
* @param {Boolean} opts.metadata return both value and metadata
* @return {String|{value: String, timestamp: Number}} the value associated with the key, undefined if there's no such key
*/
(0, _createClass2["default"])(KeyValueStore, [{
key: "get",
value: function () {
var _get2 = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee(key) {
var opts,
x,
metadata,
_args = arguments;
return _regenerator["default"].wrap(function _callee$(_context) {
while (1) {
switch (_context.prev = _context.next) {
case 0:
opts = _args.length > 1 && _args[1] !== undefined ? _args[1] : {};
_context.next = 3;
return this._get(key);
case 3:
x = _context.sent;
if (x) {
_context.next = 6;
break;
}
return _context.abrupt("return", x);
case 6:
if (!opts.metadata) {
_context.next = 9;
break;
}
metadata = this._extractMetadata(x);
return _context.abrupt("return", _objectSpread(_objectSpread({}, metadata), {}, {
value: x.value
}));
case 9:
return _context.abrupt("return", x.value);
case 10:
case "end":
return _context.stop();
}
}
}, _callee, this);
}));
function get(_x) {
return _get2.apply(this, arguments);
}
return get;
}()
/**
* Get metadata for for a given key
*
* @param {String} key the key
* @return {Metadata} Metadata for the key, undefined if there's no such key
*/
}, {
key: "getMetadata",
value: function () {
var _getMetadata = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee2(key) {
var x;
return _regenerator["default"].wrap(function _callee2$(_context2) {
while (1) {
switch (_context2.prev = _context2.next) {
case 0:
_context2.next = 2;
return this._get(key);
case 2:
x = _context2.sent;
if (x) {
_context2.next = 5;
break;
}
return _context2.abrupt("return", x);
case 5:
return _context2.abrupt("return", this._extractMetadata(x));
case 6:
case "end":
return _context2.stop();
}
}
}, _callee2, this);
}));
function getMetadata(_x2) {
return _getMetadata.apply(this, arguments);
}
return getMetadata;
}()
/**
* Set a value for the given key
*
* @param {String} key the key
* @param {String} value the value
* @return {Boolean} true if successful
*/
}, {
key: "set",
value: function () {
var _set = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee3(key, value) {
var timeStamp;
return _regenerator["default"].wrap(function _callee3$(_context3) {
while (1) {
switch (_context3.prev = _context3.next) {
case 0:
throwIfUndefined(key, 'key');
this._requireLoad();
this._replicator.ensureConnected(this._db.address.toString());
timeStamp = new Date().getTime();
_context3.next = 6;
return this._db.put(key, {
value: value,
timeStamp: timeStamp
});
case 6:
return _context3.abrupt("return", true);
case 7:
case "end":
return _context3.stop();
}
}
}, _callee3, this);
}));
function set(_x3, _x4) {
return _set.apply(this, arguments);
}
return set;
}()
/**
* Set multiple values for multiple keys
*
* @param {Array<String>} keys the keys
* @param {Array<String>} values the values
* @return {Boolean} true if successful, throw error if not
*/
}, {
key: "setMultiple",
value: function () {
var _setMultiple = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee5(keys, values) {
var _this = this;
return _regenerator["default"].wrap(function _callee5$(_context5) {
while (1) {
switch (_context5.prev = _context5.next) {
case 0:
throwIfNotEqualLenArrays(keys, values);
this._requireLoad();
this._replicator.ensureConnected(this._db.address.toString());
_context5.prev = 3;
_context5.next = 6;
return keys.reduce( /*#__PURE__*/function () {
var _ref = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee4(previousPromise, nextKey, index) {
var timeStamp;
return _regenerator["default"].wrap(function _callee4$(_context4) {
while (1) {
switch (_context4.prev = _context4.next) {
case 0:
_context4.next = 2;
return previousPromise;
case 2:
throwIfUndefined(nextKey, 'key');
timeStamp = new Date().getTime();
return _context4.abrupt("return", _this._db.put(nextKey, {
value: values[index],
timeStamp: timeStamp
}));
case 5:
case "end":
return _context4.stop();
}
}
}, _callee4);
}));
return function (_x7, _x8, _x9) {
return _ref.apply(this, arguments);
};
}(), Promise.resolve());
case 6:
return _context5.abrupt("return", true);
case 9:
_context5.prev = 9;
_context5.t0 = _context5["catch"](3);
throw new Error(_context5.t0);
case 12:
case "end":
return _context5.stop();
}
}
}, _callee5, this, [[3, 9]]);
}));
function setMultiple(_x5, _x6) {
return _setMultiple.apply(this, arguments);
}
return setMultiple;
}()
/**
* Remove the value for the given key
*
* @param {String} key the key
* @return {Boolean} true if successful
*/
}, {
key: "remove",
value: function () {
var _remove = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee6(key) {
return _regenerator["default"].wrap(function _callee6$(_context6) {
while (1) {
switch (_context6.prev = _context6.next) {
case 0:
throwIfUndefined(key, 'key');
this._requireLoad();
this._replicator.ensureConnected(this._db.address.toString());
_context6.next = 5;
return this._db.del(key);
case 5:
return _context6.abrupt("return", true);
case 6:
case "end":
return _context6.stop();
}
}
}, _callee6, this);
}));
function remove(_x10) {
return _remove.apply(this, arguments);
}
return remove;
}()
/**
* Extract metadata from store object
* @private
* @param x {Object} data from store
* @return {Metadata} store metadata
*/
}, {
key: "_extractMetadata",
value: function _extractMetadata(x) {
// ms -> seconds, see issue #396 for details
var timestamp = Math.floor(x.timeStamp / 1000);
return {
timestamp: timestamp
};
}
/**
* Get the raw value of the given key
* @private
*
* @param {String} key the key
* @return {String} the value associated with the key
*/
}, {
key: "_get",
value: function () {
var _get3 = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee7(key) {
return _regenerator["default"].wrap(function _callee7$(_context7) {
while (1) {
switch (_context7.prev = _context7.next) {
case 0:
this._requireLoad();
return _context7.abrupt("return", this._db.get(key));
case 2:
case "end":
return _context7.stop();
}
}
}, _callee7, this);
}));
function _get(_x11) {
return _get3.apply(this, arguments);
}
return _get;
}()
}, {
key: "_sync",
value: function () {
var _sync2 = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee8() {
return _regenerator["default"].wrap(function _callee8$(_context8) {
while (1) {
switch (_context8.prev = _context8.next) {
case 0:
this._requireLoad();
_context8.next = 3;
return this._replicator.syncDB(this._db);
case 3:
return _context8.abrupt("return", this._db.address.toString());
case 4:
case "end":
return _context8.stop();
}
}
}, _callee8, this);
}));
function _sync() {
return _sync2.apply(this, arguments);
}
return _sync;
}()
}, {
key: "_load",
value: function () {
var _load2 = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee9(threeId) {
var _this2 = this;
var odbAddress, key, odbIdentity;
return _regenerator["default"].wrap(function _callee9$(_context9) {
while (1) {
switch (_context9.prev = _context9.next) {
case 0:
this._3id = threeId || this._3id;
odbAddress = this._replicator.listStoreAddresses().find(function (odbAddress) {
return odbAddress.includes(_this2._name);
});
if (!odbAddress) {
_context9.next = 8;
break;
}
_context9.next = 5;
return this._replicator.getStore(odbAddress);
case 5:
this._db = _context9.sent;
_context9.next = 14;
break;
case 8:
_context9.next = 10;
return this._3id.getPublicKeys(this._space, true);
case 10:
key = _context9.sent.signingKey;
_context9.next = 13;
return this._replicator.addKVStore(this._name, key, Boolean(this._space), this._3id.getSubDID(this._space));
case 13:
this._db = _context9.sent;
case 14:
_context9.next = 16;
return this._3id.getOdbId(this._space);
case 16:
odbIdentity = _context9.sent;
this._db.setIdentity(odbIdentity);
return _context9.abrupt("return", this._db.address.toString());
case 19:
case "end":
return _context9.stop();
}
}
}, _callee9, this);
}));
function _load(_x12) {
return _load2.apply(this, arguments);
}
return _load;
}()
}, {
key: "_requireLoad",
value: function _requireLoad() {
if (!this._db) throw new Error('_load must be called before interacting with the store');
}
}, {
key: "close",
value: function () {
var _close = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee10() {
return _regenerator["default"].wrap(function _callee10$(_context10) {
while (1) {
switch (_context10.prev = _context10.next) {
case 0:
this._requireLoad();
_context10.next = 3;
return this._db.close();
case 3:
case "end":
return _context10.stop();
}
}
}, _callee10, this);
}));
function close() {
return _close.apply(this, arguments);
}
return close;
}()
/**
* Get all values and optionally metadata
*
* @param {Object} opts optional parameters
* @param {Boolean} opts.metadata return both values and metadata
* @return {Array<String|{value: String, timestamp: Number}>} the values
*/
}, {
key: "all",
value: function () {
var _all = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee11() {
var _this3 = this;
var opts,
entries,
allSimple,
_args11 = arguments;
return _regenerator["default"].wrap(function _callee11$(_context11) {
while (1) {
switch (_context11.prev = _context11.next) {
case 0:
opts = _args11.length > 0 && _args11[0] !== undefined ? _args11[0] : {};
this._requireLoad();
entries = this._db.all;
allSimple = {};
Object.keys(entries).map(function (key) {
var entry = entries[key];
if (opts.metadata) {
allSimple[key] = _objectSpread(_objectSpread({}, _this3._extractMetadata(entry)), {}, {
value: entry.value
});
} else {
allSimple[key] = entry.value;
}
});
return _context11.abrupt("return", allSimple);
case 6:
case "end":
return _context11.stop();
}
}
}, _callee11, this);
}));
function all() {
return _all.apply(this, arguments);
}
return all;
}()
/**
* Returns array of underlying log entries. In linearized order according to their Lamport clocks.
* Useful for generating a complete history of all operations on store.
*
* @example
* const log = store.log
* const entry = log[0]
* console.log(entry)
* // { op: 'PUT', key: 'Name', value: 'Botbot', timeStamp: '1538575416068' }
*
* @return {Array<Object>} Array of ordered log entry objects
*/
}, {
key: "log",
value: function () {
var _log = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee12() {
return _regenerator["default"].wrap(function _callee12$(_context12) {
while (1) {
switch (_context12.prev = _context12.next) {
case 0:
return _context12.abrupt("return", this._db._oplog.values.map(function (obj) {
return {
op: obj.payload.op,
key: obj.payload.key,
value: obj.payload.value ? obj.payload.value.value : null,
timeStamp: obj.payload.value ? obj.payload.value.timeStamp : null
};
}));
case 1:
case "end":
return _context12.stop();
}
}
}, _callee12, this);
}));
function log() {
return _log.apply(this, arguments);
}
return log;
}()
}]);
return KeyValueStore;
}();
module.exports = KeyValueStore;