@openland/foundationdb-core
Version:
Node.js bindings for the FoundationDB database
221 lines • 10.2 kB
JavaScript
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __asyncValues = (this && this.__asyncValues) || function (o) {
if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
var m = o[Symbol.asyncIterator], i;
return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i);
function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }
function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }
};
var __await = (this && this.__await) || function (v) { return this instanceof __await ? (this.v = v, this) : new __await(v); }
var __asyncGenerator = (this && this.__asyncGenerator) || function (thisArg, _arguments, generator) {
if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
var g = generator.apply(thisArg, _arguments || []), i, q = [];
return i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i;
function verb(n) { if (g[n]) i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; }
function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } }
function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); }
function fulfill(value) { resume("next", value); }
function reject(value) { resume("throw", value); }
function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); }
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const keySelector_1 = __importDefault(require("./keySelector"));
const opts_1 = require("./opts");
const opts_g_1 = require("./opts.g");
const byteZero = Buffer.alloc(1);
byteZero.writeUInt8(0, 0);
const doNothing = () => { };
// NativeValue is string | Buffer because the C code accepts either format.
// But all values returned from methods will actually just be Buffer.
class Transaction {
constructor(tn, snapshot, opts) {
this._tn = tn;
this.isSnapshot = snapshot;
if (opts) {
opts_1.eachOption(opts_g_1.transactionOptionData, opts, (code, val) => tn.setOption(code, val));
}
}
// Usually you should pass options when the transaction is constructed.
// Options are shared between a transaction object and any other aliases
// (snapshots, transactions in other scopes)
setOption(opt, value) {
// TODO: Check type of passed option is valid.
this._tn.setOption(opt, (value == null) ? null : value);
}
// Returns a mirror transaction which does snapshot reads.
snapshot() {
return new Transaction(this._tn, true);
}
rawCommit() {
return __awaiter(this, void 0, void 0, function* () {
yield this._tn.commit();
});
}
rawReset() { this._tn.reset(); }
rawCancel() { this._tn.cancel(); }
rawOnError(code) {
return __awaiter(this, void 0, void 0, function* () {
return this._tn.onError(code);
});
}
get(key) {
return this._tn.get(key, this.isSnapshot);
}
getKey(_sel) {
const sel = keySelector_1.default.from(_sel);
return this._tn.getKey(sel.key, sel.orEqual, sel.offset, this.isSnapshot);
}
set(key, val) {
this._tn.set(key, val);
}
clear(key) {
this._tn.clear(key);
}
/**
* Range reads
* @param start start key
* @param end end key
* @param opts options
*/
getRangeAll(start, end, opts = {}) {
var e_1, _a;
return __awaiter(this, void 0, void 0, function* () {
const childOpts = Object.assign({}, opts);
if (childOpts.streamingMode == null) {
childOpts.streamingMode = opts_g_1.StreamingMode.WantAll;
}
const result = [];
try {
for (var _b = __asyncValues(this.getRangeBatch(start, end, childOpts)), _c; _c = yield _b.next(), !_c.done;) {
const batch = _c.value;
result.push.apply(result, batch);
}
}
catch (e_1_1) { e_1 = { error: e_1_1 }; }
finally {
try {
if (_c && !_c.done && (_a = _b.return)) yield _a.call(_b);
}
finally { if (e_1) throw e_1.error; }
}
return result;
});
}
getRangeNative(start, end, limit, targetBytes, streamingMode, iter, reverse) {
return this._tn.getRange(start.key, start.orEqual, start.offset, end.key, end.orEqual, end.offset, limit, targetBytes, streamingMode, iter, this.isSnapshot, reverse);
}
getRangeBatch(_start, // Consider also supporting string / buffers for these.
_end, // If not specified, start is used as a prefix.
opts = {}) {
return __asyncGenerator(this, arguments, function* getRangeBatch_1() {
let start = keySelector_1.default.from(_start);
let end = keySelector_1.default.from(_end);
let limit = opts.limit || 0;
const streamingMode = opts.streamingMode == null ? opts_g_1.StreamingMode.Iterator : opts.streamingMode;
let iter = 0;
while (1) {
const { results, more } = yield __await(this.getRangeNative(start, end, limit, 0, streamingMode, ++iter, opts.reverse || false));
if (results.length) {
if (!opts.reverse) {
start = keySelector_1.default.firstGreaterThan(results[results.length - 1][0]);
}
else {
end = keySelector_1.default.firstGreaterOrEqual(results[results.length - 1][0]);
}
}
yield yield __await(results);
if (!more) {
break;
}
if (limit) {
limit -= results.length;
if (limit <= 0) {
break;
}
}
}
});
}
clearRange(start, end) {
this._tn.clearRange(start, end);
}
watch(key, opts) {
const throwAll = opts && opts.throwAllErrors;
const watch = this._tn.watch(key, !throwAll);
// Suppress the global unhandledRejection handler when a watch errors
watch.promise.catch(doNothing);
return watch;
}
/**
* Read conflict range
* @param start
* @param end
*/
addReadConflictRange(start, end) {
this._tn.addReadConflictRange(start, end);
}
addWriteConflictRange(start, end) {
this._tn.addWriteConflictRange(start, end);
}
// version must be 8 bytes
setReadVersion(v) {
this._tn.setReadVersion(v);
}
getReadVersion() {
return this._tn.getReadVersion();
}
getCommittedVersion() {
return this._tn.getCommittedVersion();
}
// Note: This promise can't be directly returned via the return value of a
// transaction.
getVersionstamp() {
// This one is surprisingly tricky:
//
// - If we return the promise as normal, you'll deadlock if you try to
// return it via your async tn function (since JS automatically
// flatmaps promises)
// - Also if the tn conflicts, this promise will also generate an error.
// By default node will crash your program when it sees this error.
// We'll allow the error naturally, but suppress node's default
// response by adding an empty catch function
const promise = this._tn.getVersionstamp();
promise.catch(doNothing);
return { promise };
}
getAddressesForKey(key) {
return this._tn.getAddressesForKey(key);
}
// **** Atomic operations
atomicOp(opType, key, oper) {
this._tn.atomicOp(opType, key, oper);
}
// Does little-endian addition on encoded values. Value transformer should encode to some
// little endian type.
add(key, oper) { this.atomicOp(opts_g_1.MutationType.Add, key, oper); }
max(key, oper) { this.atomicOp(opts_g_1.MutationType.Max, key, oper); }
min(key, oper) { this.atomicOp(opts_g_1.MutationType.Min, key, oper); }
// Raw buffer variants are provided here to support fancy bit packing semantics.
bitAnd(key, oper) { this.atomicOp(opts_g_1.MutationType.BitAnd, key, oper); }
bitOr(key, oper) { this.atomicOp(opts_g_1.MutationType.BitOr, key, oper); }
bitXor(key, oper) { this.atomicOp(opts_g_1.MutationType.BitXor, key, oper); }
// Performs lexicographic comparison of byte strings. Sets the value in the
// database to the lexographical min / max of its current value and the
// value supplied as a parameter. If the key does not exist in the database
// this is the same as set().
byteMin(key, val) { this.atomicOp(opts_g_1.MutationType.ByteMin, key, val); }
byteMax(key, val) { this.atomicOp(opts_g_1.MutationType.ByteMax, key, val); }
}
exports.default = Transaction;
//# sourceMappingURL=transaction.js.map
;