UNPKG

@openland/foundationdb-core

Version:

Node.js bindings for the FoundationDB database

221 lines 10.2 kB
"use strict"; 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