jexidb 1.0.4 → 1.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -62,7 +62,7 @@ await db.insert({ id: 2, name: 'Jane Doe', anyArbitraryField: '1' });
62
62
  The `query` method allows you to retrieve data based on specific criteria. You can specify criteria for multiple fields.
63
63
 
64
64
  ```javascript
65
- const results = await db.query({ name: 'John Doe' });
65
+ const results = await db.query({ name: 'John Doe' }, { caseInsensitive: true });
66
66
  console.log(results); // [{ id: 1, name: 'John Doe' }]
67
67
  ```
68
68
 
package/dist/Database.cjs CHANGED
@@ -10,12 +10,11 @@ var _IndexManager = _interopRequireDefault(require("./IndexManager.mjs"));
10
10
  var _Serializer = _interopRequireDefault(require("./Serializer.mjs"));
11
11
  var _fs = _interopRequireDefault(require("fs"));
12
12
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { "default": e }; }
13
- function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t["return"] || t["return"](); } finally { if (u) throw o; } } }; }
14
13
  function _slicedToArray(r, e) { return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || _unsupportedIterableToArray(r, e) || _nonIterableRest(); }
15
14
  function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
16
15
  function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t["return"] && (u = t["return"](), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } }
17
16
  function _arrayWithHoles(r) { if (Array.isArray(r)) return r; }
18
- function _readOnlyError(r) { throw new TypeError('"' + r + '" is read-only'); }
17
+ function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t["return"] || t["return"](); } finally { if (u) throw o; } } }; }
19
18
  function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
20
19
  function _regeneratorRuntime() { "use strict"; /*! regenerator-runtime -- Copyright (c) 2014-present, Facebook, Inc. -- license (MIT): https://github.com/facebook/regenerator/blob/main/LICENSE */ _regeneratorRuntime = function _regeneratorRuntime() { return e; }; var t, e = {}, r = Object.prototype, n = r.hasOwnProperty, o = Object.defineProperty || function (t, e, r) { t[e] = r.value; }, i = "function" == typeof Symbol ? Symbol : {}, a = i.iterator || "@@iterator", c = i.asyncIterator || "@@asyncIterator", u = i.toStringTag || "@@toStringTag"; function define(t, e, r) { return Object.defineProperty(t, e, { value: r, enumerable: !0, configurable: !0, writable: !0 }), t[e]; } try { define({}, ""); } catch (t) { define = function define(t, e, r) { return t[e] = r; }; } function wrap(t, e, r, n) { var i = e && e.prototype instanceof Generator ? e : Generator, a = Object.create(i.prototype), c = new Context(n || []); return o(a, "_invoke", { value: makeInvokeMethod(t, r, c) }), a; } function tryCatch(t, e, r) { try { return { type: "normal", arg: t.call(e, r) }; } catch (t) { return { type: "throw", arg: t }; } } e.wrap = wrap; var h = "suspendedStart", l = "suspendedYield", f = "executing", s = "completed", y = {}; function Generator() {} function GeneratorFunction() {} function GeneratorFunctionPrototype() {} var p = {}; define(p, a, function () { return this; }); var d = Object.getPrototypeOf, v = d && d(d(values([]))); v && v !== r && n.call(v, a) && (p = v); var g = GeneratorFunctionPrototype.prototype = Generator.prototype = Object.create(p); function defineIteratorMethods(t) { ["next", "throw", "return"].forEach(function (e) { define(t, e, function (t) { return this._invoke(e, t); }); }); } function AsyncIterator(t, e) { function invoke(r, o, i, a) { var c = tryCatch(t[r], t, o); if ("throw" !== c.type) { var u = c.arg, h = u.value; return h && "object" == _typeof(h) && n.call(h, "__await") ? e.resolve(h.__await).then(function (t) { invoke("next", t, i, a); }, function (t) { invoke("throw", t, i, a); }) : e.resolve(h).then(function (t) { u.value = t, i(u); }, function (t) { return invoke("throw", t, i, a); }); } a(c.arg); } var r; o(this, "_invoke", { value: function value(t, n) { function callInvokeWithMethodAndArg() { return new e(function (e, r) { invoke(t, n, e, r); }); } return r = r ? r.then(callInvokeWithMethodAndArg, callInvokeWithMethodAndArg) : callInvokeWithMethodAndArg(); } }); } function makeInvokeMethod(e, r, n) { var o = h; return function (i, a) { if (o === f) throw Error("Generator is already running"); if (o === s) { if ("throw" === i) throw a; return { value: t, done: !0 }; } for (n.method = i, n.arg = a;;) { var c = n.delegate; if (c) { var u = maybeInvokeDelegate(c, n); if (u) { if (u === y) continue; return u; } } if ("next" === n.method) n.sent = n._sent = n.arg;else if ("throw" === n.method) { if (o === h) throw o = s, n.arg; n.dispatchException(n.arg); } else "return" === n.method && n.abrupt("return", n.arg); o = f; var p = tryCatch(e, r, n); if ("normal" === p.type) { if (o = n.done ? s : l, p.arg === y) continue; return { value: p.arg, done: n.done }; } "throw" === p.type && (o = s, n.method = "throw", n.arg = p.arg); } }; } function maybeInvokeDelegate(e, r) { var n = r.method, o = e.iterator[n]; if (o === t) return r.delegate = null, "throw" === n && e.iterator["return"] && (r.method = "return", r.arg = t, maybeInvokeDelegate(e, r), "throw" === r.method) || "return" !== n && (r.method = "throw", r.arg = new TypeError("The iterator does not provide a '" + n + "' method")), y; var i = tryCatch(o, e.iterator, r.arg); if ("throw" === i.type) return r.method = "throw", r.arg = i.arg, r.delegate = null, y; var a = i.arg; return a ? a.done ? (r[e.resultName] = a.value, r.next = e.nextLoc, "return" !== r.method && (r.method = "next", r.arg = t), r.delegate = null, y) : a : (r.method = "throw", r.arg = new TypeError("iterator result is not an object"), r.delegate = null, y); } function pushTryEntry(t) { var e = { tryLoc: t[0] }; 1 in t && (e.catchLoc = t[1]), 2 in t && (e.finallyLoc = t[2], e.afterLoc = t[3]), this.tryEntries.push(e); } function resetTryEntry(t) { var e = t.completion || {}; e.type = "normal", delete e.arg, t.completion = e; } function Context(t) { this.tryEntries = [{ tryLoc: "root" }], t.forEach(pushTryEntry, this), this.reset(!0); } function values(e) { if (e || "" === e) { var r = e[a]; if (r) return r.call(e); if ("function" == typeof e.next) return e; if (!isNaN(e.length)) { var o = -1, i = function next() { for (; ++o < e.length;) if (n.call(e, o)) return next.value = e[o], next.done = !1, next; return next.value = t, next.done = !0, next; }; return i.next = i; } } throw new TypeError(_typeof(e) + " is not iterable"); } return GeneratorFunction.prototype = GeneratorFunctionPrototype, o(g, "constructor", { value: GeneratorFunctionPrototype, configurable: !0 }), o(GeneratorFunctionPrototype, "constructor", { value: GeneratorFunction, configurable: !0 }), GeneratorFunction.displayName = define(GeneratorFunctionPrototype, u, "GeneratorFunction"), e.isGeneratorFunction = function (t) { var e = "function" == typeof t && t.constructor; return !!e && (e === GeneratorFunction || "GeneratorFunction" === (e.displayName || e.name)); }, e.mark = function (t) { return Object.setPrototypeOf ? Object.setPrototypeOf(t, GeneratorFunctionPrototype) : (t.__proto__ = GeneratorFunctionPrototype, define(t, u, "GeneratorFunction")), t.prototype = Object.create(g), t; }, e.awrap = function (t) { return { __await: t }; }, defineIteratorMethods(AsyncIterator.prototype), define(AsyncIterator.prototype, c, function () { return this; }), e.AsyncIterator = AsyncIterator, e.async = function (t, r, n, o, i) { void 0 === i && (i = Promise); var a = new AsyncIterator(wrap(t, r, n, o), i); return e.isGeneratorFunction(r) ? a : a.next().then(function (t) { return t.done ? t.value : a.next(); }); }, defineIteratorMethods(g), define(g, u, "Generator"), define(g, a, function () { return this; }), define(g, "toString", function () { return "[object Generator]"; }), e.keys = function (t) { var e = Object(t), r = []; for (var n in e) r.push(n); return r.reverse(), function next() { for (; r.length;) { var t = r.pop(); if (t in e) return next.value = t, next.done = !1, next; } return next.done = !0, next; }; }, e.values = values, Context.prototype = { constructor: Context, reset: function reset(e) { if (this.prev = 0, this.next = 0, this.sent = this._sent = t, this.done = !1, this.delegate = null, this.method = "next", this.arg = t, this.tryEntries.forEach(resetTryEntry), !e) for (var r in this) "t" === r.charAt(0) && n.call(this, r) && !isNaN(+r.slice(1)) && (this[r] = t); }, stop: function stop() { this.done = !0; var t = this.tryEntries[0].completion; if ("throw" === t.type) throw t.arg; return this.rval; }, dispatchException: function dispatchException(e) { if (this.done) throw e; var r = this; function handle(n, o) { return a.type = "throw", a.arg = e, r.next = n, o && (r.method = "next", r.arg = t), !!o; } for (var o = this.tryEntries.length - 1; o >= 0; --o) { var i = this.tryEntries[o], a = i.completion; if ("root" === i.tryLoc) return handle("end"); if (i.tryLoc <= this.prev) { var c = n.call(i, "catchLoc"), u = n.call(i, "finallyLoc"); if (c && u) { if (this.prev < i.catchLoc) return handle(i.catchLoc, !0); if (this.prev < i.finallyLoc) return handle(i.finallyLoc); } else if (c) { if (this.prev < i.catchLoc) return handle(i.catchLoc, !0); } else { if (!u) throw Error("try statement without catch or finally"); if (this.prev < i.finallyLoc) return handle(i.finallyLoc); } } } }, abrupt: function abrupt(t, e) { for (var r = this.tryEntries.length - 1; r >= 0; --r) { var o = this.tryEntries[r]; if (o.tryLoc <= this.prev && n.call(o, "finallyLoc") && this.prev < o.finallyLoc) { var i = o; break; } } i && ("break" === t || "continue" === t) && i.tryLoc <= e && e <= i.finallyLoc && (i = null); var a = i ? i.completion : {}; return a.type = t, a.arg = e, i ? (this.method = "next", this.next = i.finallyLoc, y) : this.complete(a); }, complete: function complete(t, e) { if ("throw" === t.type) throw t.arg; return "break" === t.type || "continue" === t.type ? this.next = t.arg : "return" === t.type ? (this.rval = this.arg = t.arg, this.method = "return", this.next = "end") : "normal" === t.type && e && (this.next = e), y; }, finish: function finish(t) { for (var e = this.tryEntries.length - 1; e >= 0; --e) { var r = this.tryEntries[e]; if (r.finallyLoc === t) return this.complete(r.completion, r.afterLoc), resetTryEntry(r), y; } }, "catch": function _catch(t) { for (var e = this.tryEntries.length - 1; e >= 0; --e) { var r = this.tryEntries[e]; if (r.tryLoc === t) { var n = r.completion; if ("throw" === n.type) { var o = n.arg; resetTryEntry(r); } return o; } } throw Error("illegal catch attempt"); }, delegateYield: function delegateYield(e, r, n) { return this.delegate = { iterator: values(e), resultName: r, nextLoc: n }, "next" === this.method && (this.arg = t), y; } }, e; }
21
20
  function _toConsumableArray(r) { return _arrayWithoutHoles(r) || _iterableToArray(r) || _unsupportedIterableToArray(r) || _nonIterableSpread(); }
@@ -43,6 +42,8 @@ function _wrapAsyncGenerator(e) { return function () { return new AsyncGenerator
43
42
  function AsyncGenerator(e) { var r, t; function resume(r, t) { try { var n = e[r](t), o = n.value, u = o instanceof _OverloadYield; Promise.resolve(u ? o.v : o).then(function (t) { if (u) { var i = "return" === r ? "return" : "next"; if (!o.k || t.done) return resume(i, t); t = e[i](t).value; } settle(n.done ? "return" : "normal", t); }, function (e) { resume("throw", e); }); } catch (e) { settle("throw", e); } } function settle(e, n) { switch (e) { case "return": r.resolve({ value: n, done: !0 }); break; case "throw": r.reject(n); break; default: r.resolve({ value: n, done: !1 }); } (r = r.next) ? resume(r.key, r.arg) : t = null; } this._invoke = function (e, n) { return new Promise(function (o, u) { var i = { key: e, arg: n, resolve: o, reject: u, next: null }; t ? t = t.next = i : (r = t = i, resume(e, n)); }); }, "function" != typeof e["return"] && (this["return"] = void 0); }
44
43
  AsyncGenerator.prototype["function" == typeof Symbol && Symbol.asyncIterator || "@@asyncIterator"] = function () { return this; }, AsyncGenerator.prototype.next = function (e) { return this._invoke("next", e); }, AsyncGenerator.prototype["throw"] = function (e) { return this._invoke("throw", e); }, AsyncGenerator.prototype["return"] = function (e) { return this._invoke("return", e); };
45
44
  function _OverloadYield(e, d) { this.v = e, this.k = d; }
45
+ function _asyncIterator(r) { var n, t, o, e = 2; for ("undefined" != typeof Symbol && (t = Symbol.asyncIterator, o = Symbol.iterator); e--;) { if (t && null != (n = r[t])) return n.call(r); if (o && null != (n = r[o])) return new AsyncFromSyncIterator(n.call(r)); t = "@@asyncIterator", o = "@@iterator"; } throw new TypeError("Object is not async iterable"); }
46
+ function AsyncFromSyncIterator(r) { function AsyncFromSyncIteratorContinuation(r) { if (Object(r) !== r) return Promise.reject(new TypeError(r + " is not an object.")); var n = r.done; return Promise.resolve(r.value).then(function (r) { return { value: r, done: n }; }); } return AsyncFromSyncIterator = function AsyncFromSyncIterator(r) { this.s = r, this.n = r.next; }, AsyncFromSyncIterator.prototype = { s: null, n: null, next: function next() { return AsyncFromSyncIteratorContinuation(this.n.apply(this.s, arguments)); }, "return": function _return(r) { var n = this.s["return"]; return void 0 === n ? Promise.resolve({ value: r, done: !0 }) : AsyncFromSyncIteratorContinuation(n.apply(this.s, arguments)); }, "throw": function _throw(r) { var n = this.s["return"]; return void 0 === n ? Promise.reject(r) : AsyncFromSyncIteratorContinuation(n.apply(this.s, arguments)); } }, new AsyncFromSyncIterator(r); }
46
47
  var Database = exports.Database = /*#__PURE__*/function (_EventEmitter) {
47
48
  function Database(file) {
48
49
  var _this2;
@@ -549,124 +550,153 @@ var Database = exports.Database = /*#__PURE__*/function (_EventEmitter) {
549
550
  var _this = this;
550
551
  var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
551
552
  return _wrapAsyncGenerator(/*#__PURE__*/_regeneratorRuntime().mark(function _callee7() {
552
- var ranges, partitionedRanges, currentPartition, line, m, _i, _partitionedRanges, _ranges, lines, _loop, _line;
553
- return _regeneratorRuntime().wrap(function _callee7$(_context8) {
554
- while (1) switch (_context8.prev = _context8.next) {
553
+ var ranges, readSize, groupedRanges, fd, _iterator2, _step2, groupedRange, _iteratorAbruptCompletion, _didIteratorError, _iteratorError, _iterator, _step, row, entry;
554
+ return _regeneratorRuntime().wrap(function _callee7$(_context7) {
555
+ while (1) switch (_context7.prev = _context7.next) {
555
556
  case 0:
556
557
  if (!_this.destroyed) {
557
- _context8.next = 2;
558
+ _context7.next = 2;
558
559
  break;
559
560
  }
560
561
  throw new Error('Database is destroyed');
561
562
  case 2:
562
563
  if (_this.initialized) {
563
- _context8.next = 5;
564
+ _context7.next = 5;
564
565
  break;
565
566
  }
566
- _context8.next = 5;
567
+ _context7.next = 5;
567
568
  return _awaitAsyncGenerator(_this.init());
568
569
  case 5:
569
- _context8.t0 = _this.shouldSave;
570
- if (!_context8.t0) {
571
- _context8.next = 9;
570
+ _context7.t0 = _this.shouldSave;
571
+ if (!_context7.t0) {
572
+ _context7.next = 9;
572
573
  break;
573
574
  }
574
- _context8.next = 9;
575
+ _context7.next = 9;
575
576
  return _awaitAsyncGenerator(_this.save()["catch"](console.error));
576
577
  case 9:
577
578
  if (!(_this.indexOffset === 0)) {
578
- _context8.next = 11;
579
+ _context7.next = 11;
579
580
  break;
580
581
  }
581
- return _context8.abrupt("return");
582
+ return _context7.abrupt("return");
582
583
  case 11:
583
584
  if (!Array.isArray(map)) {
584
585
  if (map instanceof Set) {
585
586
  map = _toConsumableArray(map);
586
587
  } else if (map && _typeof(map) === 'object') {
587
- map = _toConsumableArray(_this.indexManager.query(map, options.matchAny));
588
+ map = _toConsumableArray(_this.indexManager.query(map, options));
588
589
  } else {
589
590
  map = _toConsumableArray(Array(_this.offsets.length).keys());
590
591
  }
591
592
  }
592
593
  ranges = _this.getRanges(map);
593
- partitionedRanges = [], currentPartition = 0;
594
- for (line in ranges) {
595
- if (partitionedRanges[currentPartition] === undefined) {
596
- partitionedRanges[currentPartition] = [];
597
- }
598
- partitionedRanges[currentPartition].push(ranges[line]);
599
- if (partitionedRanges[currentPartition].length >= _this.opts.maxMemoryUsage) {
600
- +currentPartition, _readOnlyError("currentPartition");
601
- }
594
+ readSize = 512 * 1024; // 512KB
595
+ _context7.next = 16;
596
+ return _awaitAsyncGenerator(_this.fileHandler.groupedRanges(ranges));
597
+ case 16:
598
+ groupedRanges = _context7.sent;
599
+ _context7.next = 19;
600
+ return _awaitAsyncGenerator(_fs["default"].promises.open(_this.fileHandler.file, 'r'));
601
+ case 19:
602
+ fd = _context7.sent;
603
+ _iterator2 = _createForOfIteratorHelper(groupedRanges);
604
+ _context7.prev = 21;
605
+ _iterator2.s();
606
+ case 23:
607
+ if ((_step2 = _iterator2.n()).done) {
608
+ _context7.next = 64;
609
+ break;
602
610
  }
603
- m = 0;
604
- _i = 0, _partitionedRanges = partitionedRanges;
605
- case 17:
606
- if (!(_i < _partitionedRanges.length)) {
607
- _context8.next = 34;
611
+ groupedRange = _step2.value;
612
+ _iteratorAbruptCompletion = false;
613
+ _didIteratorError = false;
614
+ _context7.prev = 27;
615
+ _iterator = _asyncIterator(_this.fileHandler.readGroupedRange(groupedRange, fd));
616
+ case 29:
617
+ _context7.next = 31;
618
+ return _awaitAsyncGenerator(_iterator.next());
619
+ case 31:
620
+ if (!(_iteratorAbruptCompletion = !(_step = _context7.sent).done)) {
621
+ _context7.next = 46;
608
622
  break;
609
623
  }
610
- _ranges = _partitionedRanges[_i];
611
- _context8.next = 21;
612
- return _awaitAsyncGenerator(_this.fileHandler.readRanges(_ranges));
613
- case 21:
614
- lines = _context8.sent;
615
- _loop = /*#__PURE__*/_regeneratorRuntime().mark(function _loop() {
616
- var err, entry;
617
- return _regeneratorRuntime().wrap(function _loop$(_context7) {
618
- while (1) switch (_context7.prev = _context7.next) {
619
- case 0:
620
- _context7.next = 2;
621
- return _awaitAsyncGenerator(_this.serializer.deserialize(lines[_line])["catch"](function (e) {
622
- return console.error(err = e);
623
- }));
624
- case 2:
625
- entry = _context7.sent;
626
- if (!err) {
627
- _context7.next = 5;
628
- break;
629
- }
630
- return _context7.abrupt("return", 1);
631
- case 5:
632
- if (entry._ === undefined) {
633
- while (_this.offsets[m] != _line && m < map.length) m++; // weak comparison as 'start' is a string
634
- entry._ = m++;
635
- }
636
- _context7.next = 8;
637
- return entry;
638
- case 8:
639
- case "end":
640
- return _context7.stop();
641
- }
642
- }, _loop);
643
- });
644
- _context8.t1 = _regeneratorRuntime().keys(lines);
645
- case 24:
646
- if ((_context8.t2 = _context8.t1()).done) {
647
- _context8.next = 31;
624
+ row = _step.value;
625
+ _context7.next = 35;
626
+ return _awaitAsyncGenerator(_this.serializer.deserialize(row.line, {
627
+ compress: _this.opts.compress
628
+ }));
629
+ case 35:
630
+ entry = _context7.sent;
631
+ if (!options.includeOffsets) {
632
+ _context7.next = 41;
648
633
  break;
649
634
  }
650
- _line = _context8.t2.value;
651
- return _context8.delegateYield(_loop(), "t3", 27);
652
- case 27:
653
- if (!_context8.t3) {
654
- _context8.next = 29;
635
+ _context7.next = 39;
636
+ return {
637
+ entry: entry,
638
+ start: row.start
639
+ };
640
+ case 39:
641
+ _context7.next = 43;
642
+ break;
643
+ case 41:
644
+ _context7.next = 43;
645
+ return entry;
646
+ case 43:
647
+ _iteratorAbruptCompletion = false;
648
+ _context7.next = 29;
649
+ break;
650
+ case 46:
651
+ _context7.next = 52;
652
+ break;
653
+ case 48:
654
+ _context7.prev = 48;
655
+ _context7.t1 = _context7["catch"](27);
656
+ _didIteratorError = true;
657
+ _iteratorError = _context7.t1;
658
+ case 52:
659
+ _context7.prev = 52;
660
+ _context7.prev = 53;
661
+ if (!(_iteratorAbruptCompletion && _iterator["return"] != null)) {
662
+ _context7.next = 57;
655
663
  break;
656
664
  }
657
- return _context8.abrupt("continue", 24);
658
- case 29:
659
- _context8.next = 24;
665
+ _context7.next = 57;
666
+ return _awaitAsyncGenerator(_iterator["return"]());
667
+ case 57:
668
+ _context7.prev = 57;
669
+ if (!_didIteratorError) {
670
+ _context7.next = 60;
671
+ break;
672
+ }
673
+ throw _iteratorError;
674
+ case 60:
675
+ return _context7.finish(57);
676
+ case 61:
677
+ return _context7.finish(52);
678
+ case 62:
679
+ _context7.next = 23;
660
680
  break;
661
- case 31:
662
- _i++;
663
- _context8.next = 17;
681
+ case 64:
682
+ _context7.next = 69;
664
683
  break;
665
- case 34:
684
+ case 66:
685
+ _context7.prev = 66;
686
+ _context7.t2 = _context7["catch"](21);
687
+ _iterator2.e(_context7.t2);
688
+ case 69:
689
+ _context7.prev = 69;
690
+ _iterator2.f();
691
+ return _context7.finish(69);
692
+ case 72:
693
+ _context7.next = 74;
694
+ return _awaitAsyncGenerator(fd.close());
695
+ case 74:
666
696
  case "end":
667
- return _context8.stop();
697
+ return _context7.stop();
668
698
  }
669
- }, _callee7);
699
+ }, _callee7, null, [[21, 66, 69, 72], [27, 48, 52, 62], [53,, 57, 61]]);
670
700
  }))();
671
701
  }
672
702
  }, {
@@ -681,40 +711,40 @@ var Database = exports.Database = /*#__PURE__*/function (_EventEmitter) {
681
711
  _options$orderBy$spli3,
682
712
  direction,
683
713
  matchingLines,
684
- _args9 = arguments;
685
- return _regeneratorRuntime().wrap(function _callee8$(_context9) {
686
- while (1) switch (_context9.prev = _context9.next) {
714
+ _args8 = arguments;
715
+ return _regeneratorRuntime().wrap(function _callee8$(_context8) {
716
+ while (1) switch (_context8.prev = _context8.next) {
687
717
  case 0:
688
- options = _args9.length > 1 && _args9[1] !== undefined ? _args9[1] : {};
718
+ options = _args8.length > 1 && _args8[1] !== undefined ? _args8[1] : {};
689
719
  if (!this.destroyed) {
690
- _context9.next = 3;
720
+ _context8.next = 3;
691
721
  break;
692
722
  }
693
723
  throw new Error('Database is destroyed');
694
724
  case 3:
695
725
  if (this.initialized) {
696
- _context9.next = 6;
726
+ _context8.next = 6;
697
727
  break;
698
728
  }
699
- _context9.next = 6;
729
+ _context8.next = 6;
700
730
  return this.init();
701
731
  case 6:
702
- _context9.t0 = this.shouldSave;
703
- if (!_context9.t0) {
704
- _context9.next = 10;
732
+ _context8.t0 = this.shouldSave;
733
+ if (!_context8.t0) {
734
+ _context8.next = 10;
705
735
  break;
706
736
  }
707
- _context9.next = 10;
737
+ _context8.next = 10;
708
738
  return this.save()["catch"](console.error);
709
739
  case 10:
710
740
  if (!Array.isArray(criteria)) {
711
- _context9.next = 19;
741
+ _context8.next = 19;
712
742
  break;
713
743
  }
714
- _context9.next = 13;
744
+ _context8.next = 13;
715
745
  return this.readLines(criteria);
716
746
  case 13:
717
- results = _context9.sent;
747
+ results = _context8.sent;
718
748
  if (options.orderBy) {
719
749
  _options$orderBy$spli = options.orderBy.split(' '), _options$orderBy$spli2 = _slicedToArray(_options$orderBy$spli, 2), field = _options$orderBy$spli2[0], _options$orderBy$spli3 = _options$orderBy$spli2[1], direction = _options$orderBy$spli3 === void 0 ? 'asc' : _options$orderBy$spli3;
720
750
  results.sort(function (a, b) {
@@ -726,25 +756,25 @@ var Database = exports.Database = /*#__PURE__*/function (_EventEmitter) {
726
756
  if (options.limit) {
727
757
  results = results.slice(0, options.limit);
728
758
  }
729
- return _context9.abrupt("return", results);
759
+ return _context8.abrupt("return", results);
730
760
  case 19:
731
- _context9.next = 21;
732
- return this.indexManager.query(criteria, options.matchAny);
761
+ _context8.next = 21;
762
+ return this.indexManager.query(criteria, options);
733
763
  case 21:
734
- matchingLines = _context9.sent;
764
+ matchingLines = _context8.sent;
735
765
  if (!(!matchingLines || !matchingLines.size)) {
736
- _context9.next = 24;
766
+ _context8.next = 24;
737
767
  break;
738
768
  }
739
- return _context9.abrupt("return", []);
769
+ return _context8.abrupt("return", []);
740
770
  case 24:
741
- _context9.next = 26;
771
+ _context8.next = 26;
742
772
  return this.query(_toConsumableArray(matchingLines), options);
743
773
  case 26:
744
- return _context9.abrupt("return", _context9.sent);
774
+ return _context8.abrupt("return", _context8.sent);
745
775
  case 27:
746
776
  case "end":
747
- return _context9.stop();
777
+ return _context8.stop();
748
778
  }
749
779
  }, _callee8, this);
750
780
  }));
@@ -764,110 +794,110 @@ var Database = exports.Database = /*#__PURE__*/function (_EventEmitter) {
764
794
  validMatchingLines,
765
795
  entries,
766
796
  lines,
767
- _iterator,
768
- _step,
769
- _loop2,
797
+ _iterator3,
798
+ _step3,
799
+ _loop,
770
800
  offsets,
771
801
  byteOffset,
772
802
  k,
773
- _args11 = arguments;
774
- return _regeneratorRuntime().wrap(function _callee9$(_context11) {
775
- while (1) switch (_context11.prev = _context11.next) {
803
+ _args10 = arguments;
804
+ return _regeneratorRuntime().wrap(function _callee9$(_context10) {
805
+ while (1) switch (_context10.prev = _context10.next) {
776
806
  case 0:
777
- options = _args11.length > 2 && _args11[2] !== undefined ? _args11[2] : {};
807
+ options = _args10.length > 2 && _args10[2] !== undefined ? _args10[2] : {};
778
808
  if (this.shouldTruncate) {
779
809
  this.writeBuffer.push(this.indexOffset);
780
810
  this.shouldTruncate = false;
781
811
  }
782
812
  if (!this.destroyed) {
783
- _context11.next = 4;
813
+ _context10.next = 4;
784
814
  break;
785
815
  }
786
816
  throw new Error('Database is destroyed');
787
817
  case 4:
788
818
  if (this.initialized) {
789
- _context11.next = 7;
819
+ _context10.next = 7;
790
820
  break;
791
821
  }
792
- _context11.next = 7;
822
+ _context10.next = 7;
793
823
  return this.init();
794
824
  case 7:
795
- _context11.t0 = this.shouldSave;
796
- if (!_context11.t0) {
797
- _context11.next = 11;
825
+ _context10.t0 = this.shouldSave;
826
+ if (!_context10.t0) {
827
+ _context10.next = 11;
798
828
  break;
799
829
  }
800
- _context11.next = 11;
830
+ _context10.next = 11;
801
831
  return this.save()["catch"](console.error);
802
832
  case 11:
803
- _context11.next = 13;
804
- return this.indexManager.query(criteria, options.matchAny);
833
+ _context10.next = 13;
834
+ return this.indexManager.query(criteria, options);
805
835
  case 13:
806
- matchingLines = _context11.sent;
836
+ matchingLines = _context10.sent;
807
837
  if (!(!matchingLines || !matchingLines.size)) {
808
- _context11.next = 16;
838
+ _context10.next = 16;
809
839
  break;
810
840
  }
811
- return _context11.abrupt("return", []);
841
+ return _context10.abrupt("return", []);
812
842
  case 16:
813
843
  ranges = this.getRanges(_toConsumableArray(matchingLines));
814
844
  validMatchingLines = new Set(ranges.map(function (r) {
815
845
  return r.index;
816
846
  }));
817
847
  if (validMatchingLines.size) {
818
- _context11.next = 20;
848
+ _context10.next = 20;
819
849
  break;
820
850
  }
821
- return _context11.abrupt("return", []);
851
+ return _context10.abrupt("return", []);
822
852
  case 20:
823
- _context11.next = 22;
853
+ _context10.next = 22;
824
854
  return this.readLines(_toConsumableArray(validMatchingLines), ranges);
825
855
  case 22:
826
- entries = _context11.sent;
856
+ entries = _context10.sent;
827
857
  lines = [];
828
- _iterator = _createForOfIteratorHelper(entries);
829
- _context11.prev = 25;
830
- _loop2 = /*#__PURE__*/_regeneratorRuntime().mark(function _loop2() {
858
+ _iterator3 = _createForOfIteratorHelper(entries);
859
+ _context10.prev = 25;
860
+ _loop = /*#__PURE__*/_regeneratorRuntime().mark(function _loop() {
831
861
  var entry, err, updated, ret;
832
- return _regeneratorRuntime().wrap(function _loop2$(_context10) {
833
- while (1) switch (_context10.prev = _context10.next) {
862
+ return _regeneratorRuntime().wrap(function _loop$(_context9) {
863
+ while (1) switch (_context9.prev = _context9.next) {
834
864
  case 0:
835
- entry = _step.value;
865
+ entry = _step3.value;
836
866
  updated = Object.assign(entry, data);
837
- _context10.next = 4;
867
+ _context9.next = 4;
838
868
  return _this8.serializer.serialize(updated)["catch"](function (e) {
839
869
  return err = e;
840
870
  });
841
871
  case 4:
842
- ret = _context10.sent;
872
+ ret = _context9.sent;
843
873
  err || lines.push(ret);
844
874
  case 6:
845
875
  case "end":
846
- return _context10.stop();
876
+ return _context9.stop();
847
877
  }
848
- }, _loop2);
878
+ }, _loop);
849
879
  });
850
- _iterator.s();
880
+ _iterator3.s();
851
881
  case 28:
852
- if ((_step = _iterator.n()).done) {
853
- _context11.next = 32;
882
+ if ((_step3 = _iterator3.n()).done) {
883
+ _context10.next = 32;
854
884
  break;
855
885
  }
856
- return _context11.delegateYield(_loop2(), "t1", 30);
886
+ return _context10.delegateYield(_loop(), "t1", 30);
857
887
  case 30:
858
- _context11.next = 28;
888
+ _context10.next = 28;
859
889
  break;
860
890
  case 32:
861
- _context11.next = 37;
891
+ _context10.next = 37;
862
892
  break;
863
893
  case 34:
864
- _context11.prev = 34;
865
- _context11.t2 = _context11["catch"](25);
866
- _iterator.e(_context11.t2);
894
+ _context10.prev = 34;
895
+ _context10.t2 = _context10["catch"](25);
896
+ _iterator3.e(_context10.t2);
867
897
  case 37:
868
- _context11.prev = 37;
869
- _iterator.f();
870
- return _context11.finish(37);
898
+ _context10.prev = 37;
899
+ _iterator3.f();
900
+ return _context10.finish(37);
871
901
  case 40:
872
902
  offsets = [];
873
903
  byteOffset = 0, k = 0;
@@ -882,7 +912,7 @@ var Database = exports.Database = /*#__PURE__*/function (_EventEmitter) {
882
912
  });
883
913
  this.offsets = offsets;
884
914
  this.indexOffset += byteOffset;
885
- _context11.next = 47;
915
+ _context10.next = 47;
886
916
  return this.fileHandler.replaceLines(ranges, lines);
887
917
  case 47:
888
918
  _toConsumableArray(validMatchingLines).forEach(function (lineNumber, i) {
@@ -890,10 +920,10 @@ var Database = exports.Database = /*#__PURE__*/function (_EventEmitter) {
890
920
  _this8.indexManager.add(entries[i], lineNumber);
891
921
  });
892
922
  this.shouldSave = true;
893
- return _context11.abrupt("return", entries);
923
+ return _context10.abrupt("return", entries);
894
924
  case 50:
895
925
  case "end":
896
- return _context11.stop();
926
+ return _context10.stop();
897
927
  }
898
928
  }, _callee9, this, [[25, 34, 37, 40]]);
899
929
  }));
@@ -913,51 +943,51 @@ var Database = exports.Database = /*#__PURE__*/function (_EventEmitter) {
913
943
  offsets,
914
944
  byteOffset,
915
945
  k,
916
- _args12 = arguments;
917
- return _regeneratorRuntime().wrap(function _callee10$(_context12) {
918
- while (1) switch (_context12.prev = _context12.next) {
946
+ _args11 = arguments;
947
+ return _regeneratorRuntime().wrap(function _callee10$(_context11) {
948
+ while (1) switch (_context11.prev = _context11.next) {
919
949
  case 0:
920
- options = _args12.length > 1 && _args12[1] !== undefined ? _args12[1] : {};
950
+ options = _args11.length > 1 && _args11[1] !== undefined ? _args11[1] : {};
921
951
  if (this.shouldTruncate) {
922
952
  this.writeBuffer.push(this.indexOffset);
923
953
  this.shouldTruncate = false;
924
954
  }
925
955
  if (!this.destroyed) {
926
- _context12.next = 4;
956
+ _context11.next = 4;
927
957
  break;
928
958
  }
929
959
  throw new Error('Database is destroyed');
930
960
  case 4:
931
961
  if (this.initialized) {
932
- _context12.next = 7;
962
+ _context11.next = 7;
933
963
  break;
934
964
  }
935
- _context12.next = 7;
965
+ _context11.next = 7;
936
966
  return this.init();
937
967
  case 7:
938
- _context12.t0 = this.shouldSave;
939
- if (!_context12.t0) {
940
- _context12.next = 11;
968
+ _context11.t0 = this.shouldSave;
969
+ if (!_context11.t0) {
970
+ _context11.next = 11;
941
971
  break;
942
972
  }
943
- _context12.next = 11;
973
+ _context11.next = 11;
944
974
  return this.save()["catch"](console.error);
945
975
  case 11:
946
- _context12.next = 13;
947
- return this.indexManager.query(criteria, options.matchAny);
976
+ _context11.next = 13;
977
+ return this.indexManager.query(criteria, options);
948
978
  case 13:
949
- matchingLines = _context12.sent;
979
+ matchingLines = _context11.sent;
950
980
  if (!(!matchingLines || !matchingLines.size)) {
951
- _context12.next = 16;
981
+ _context11.next = 16;
952
982
  break;
953
983
  }
954
- return _context12.abrupt("return", 0);
984
+ return _context11.abrupt("return", 0);
955
985
  case 16:
956
986
  ranges = this.getRanges(_toConsumableArray(matchingLines));
957
987
  validMatchingLines = new Set(ranges.map(function (r) {
958
988
  return r.index;
959
989
  }));
960
- _context12.next = 20;
990
+ _context11.next = 20;
961
991
  return this.fileHandler.replaceLines(ranges, []);
962
992
  case 20:
963
993
  offsets = [];
@@ -975,10 +1005,10 @@ var Database = exports.Database = /*#__PURE__*/function (_EventEmitter) {
975
1005
  this.indexOffset += byteOffset;
976
1006
  this.indexManager.remove(_toConsumableArray(validMatchingLines));
977
1007
  this.shouldSave = true;
978
- return _context12.abrupt("return", ranges.length);
1008
+ return _context11.abrupt("return", ranges.length);
979
1009
  case 28:
980
1010
  case "end":
981
- return _context12.stop();
1011
+ return _context11.stop();
982
1012
  }
983
1013
  }, _callee10, this);
984
1014
  }));
@@ -991,15 +1021,15 @@ var Database = exports.Database = /*#__PURE__*/function (_EventEmitter) {
991
1021
  key: "destroy",
992
1022
  value: function () {
993
1023
  var _destroy = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime().mark(function _callee11() {
994
- return _regeneratorRuntime().wrap(function _callee11$(_context13) {
995
- while (1) switch (_context13.prev = _context13.next) {
1024
+ return _regeneratorRuntime().wrap(function _callee11$(_context12) {
1025
+ while (1) switch (_context12.prev = _context12.next) {
996
1026
  case 0:
997
- _context13.t0 = this.shouldSave;
998
- if (!_context13.t0) {
999
- _context13.next = 4;
1027
+ _context12.t0 = this.shouldSave;
1028
+ if (!_context12.t0) {
1029
+ _context12.next = 4;
1000
1030
  break;
1001
1031
  }
1002
- _context13.next = 4;
1032
+ _context12.next = 4;
1003
1033
  return this.save()["catch"](console.error);
1004
1034
  case 4:
1005
1035
  this.destroyed = true;
@@ -1010,7 +1040,7 @@ var Database = exports.Database = /*#__PURE__*/function (_EventEmitter) {
1010
1040
  this.fileHandler.destroy();
1011
1041
  case 10:
1012
1042
  case "end":
1013
- return _context13.stop();
1043
+ return _context12.stop();
1014
1044
  }
1015
1045
  }, _callee11, this);
1016
1046
  }));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jexidb",
3
- "version": "1.0.4",
3
+ "version": "1.0.6",
4
4
  "description": "JexiDB is a pure JS NPM library for managing data on disk using JSONL efficiently, without the need for a server.",
5
5
  "main": "./dist/Database.cjs",
6
6
  "module": "./src/Database.mjs",
package/src/Database.mjs CHANGED
@@ -217,36 +217,26 @@ export class Database extends EventEmitter {
217
217
  if (map instanceof Set) {
218
218
  map = [...map]
219
219
  } else if(map && typeof map === 'object') {
220
- map = [...this.indexManager.query(map, options.matchAny)]
220
+ map = [...this.indexManager.query(map, options)]
221
221
  } else {
222
222
  map = [...Array(this.offsets.length).keys()]
223
223
  }
224
224
  }
225
225
  const ranges = this.getRanges(map)
226
- const partitionedRanges = [], currentPartition = 0
227
- for (const line in ranges) {
228
- if (partitionedRanges[currentPartition] === undefined) {
229
- partitionedRanges[currentPartition] = []
230
- }
231
- partitionedRanges[currentPartition].push(ranges[line])
232
- if (partitionedRanges[currentPartition].length >= this.opts.maxMemoryUsage) {
233
- currentPartition++
234
- }
235
- }
236
- let m = 0
237
- for (const ranges of partitionedRanges) {
238
- const lines = await this.fileHandler.readRanges(ranges)
239
- for (const line in lines) {
240
- let err
241
- const entry = await this.serializer.deserialize(lines[line]).catch(e => console.error(err = e))
242
- if (err) continue
243
- if (entry._ === undefined) {
244
- while(this.offsets[m] != line && m < map.length) m++ // weak comparison as 'start' is a string
245
- entry._ = m++
226
+ const readSize = 512 * 1024 // 512KB
227
+ const groupedRanges = await this.fileHandler.groupedRanges(ranges)
228
+ const fd = await fs.promises.open(this.fileHandler.file, 'r')
229
+ for(const groupedRange of groupedRanges) {
230
+ for await (const row of this.fileHandler.readGroupedRange(groupedRange, fd)) {
231
+ const entry = await this.serializer.deserialize(row.line, {compress: this.opts.compress})
232
+ if(options.includeOffsets) {
233
+ yield {entry, start: row.start}
234
+ } else {
235
+ yield entry
246
236
  }
247
- yield entry
248
237
  }
249
238
  }
239
+ await fd.close()
250
240
  }
251
241
 
252
242
  async query(criteria, options={}) {
@@ -268,7 +258,7 @@ export class Database extends EventEmitter {
268
258
  }
269
259
  return results
270
260
  } else {
271
- const matchingLines = await this.indexManager.query(criteria, options.matchAny)
261
+ const matchingLines = await this.indexManager.query(criteria, options)
272
262
  if (!matchingLines || !matchingLines.size) {
273
263
  return []
274
264
  }
@@ -284,7 +274,7 @@ export class Database extends EventEmitter {
284
274
  if(this.destroyed) throw new Error('Database is destroyed')
285
275
  if(!this.initialized) await this.init()
286
276
  this.shouldSave && await this.save().catch(console.error)
287
- const matchingLines = await this.indexManager.query(criteria, options.matchAny)
277
+ const matchingLines = await this.indexManager.query(criteria, options)
288
278
  if (!matchingLines || !matchingLines.size) {
289
279
  return []
290
280
  }
@@ -331,7 +321,7 @@ export class Database extends EventEmitter {
331
321
  if(this.destroyed) throw new Error('Database is destroyed')
332
322
  if(!this.initialized) await this.init()
333
323
  this.shouldSave && await this.save().catch(console.error)
334
- const matchingLines = await this.indexManager.query(criteria, options.matchAny)
324
+ const matchingLines = await this.indexManager.query(criteria, options)
335
325
  if (!matchingLines || !matchingLines.size) {
336
326
  return 0
337
327
  }
@@ -28,18 +28,13 @@ export default class FileHandler {
28
28
  async readRanges(ranges, mapper) {
29
29
  const lines = {}, limit = pLimit(4)
30
30
  const fd = await fs.promises.open(this.file, 'r')
31
+ const groupedRanges = await this.groupedRanges(ranges)
31
32
  try {
32
- const tasks = ranges.map(r => {
33
- return async () => {
34
- let err
35
- const length = r.end - r.start
36
- let buffer = Buffer.alloc(length)
37
- const { bytesRead } = await fd.read(buffer, 0, length, r.start).catch(e => err = e)
38
- if (buffer.length > bytesRead) buffer = buffer.subarray(0, bytesRead)
39
- lines[r.start] = mapper ? (await mapper(buffer, r)) : buffer
33
+ for(const groupedRange of groupedRanges) {
34
+ for await (const row of this.readGroupedRange(groupedRange, fd)) {
35
+ lines[row.start] = mapper ? (await mapper(row.line, groupedRange)) : row.line
40
36
  }
41
- })
42
- await Promise.allSettled(tasks.map(limit))
37
+ }
43
38
  } catch (e) {
44
39
  console.error('Error reading ranges:', e)
45
40
  } finally {
@@ -48,6 +43,61 @@ export default class FileHandler {
48
43
  return lines
49
44
  }
50
45
 
46
+ async groupedRanges(ranges) {
47
+ const readSize = 512 * 1024 // 512KB
48
+ const groupedRanges = []
49
+ let currentGroup = []
50
+ let currentSize = 0
51
+
52
+ // each range is a {start: number, end: number} object
53
+ for(const range of ranges) {
54
+ const rangeSize = range.end - range.start
55
+
56
+ if(currentGroup.length > 0) {
57
+ const lastRange = currentGroup[currentGroup.length - 1]
58
+ if(lastRange.end !== range.start || currentSize + rangeSize > readSize) {
59
+ groupedRanges.push(currentGroup)
60
+ currentGroup = []
61
+ currentSize = 0
62
+ }
63
+ }
64
+
65
+ currentGroup.push(range)
66
+ currentSize += rangeSize
67
+ }
68
+
69
+ if(currentGroup.length > 0) {
70
+ groupedRanges.push(currentGroup)
71
+ }
72
+
73
+ return groupedRanges
74
+ }
75
+
76
+ async *readGroupedRange(groupedRange, fd) {
77
+ const options = {start: groupedRange[0].start, end: groupedRange[groupedRange.length - 1].end}
78
+
79
+ let i = 0, buffer = Buffer.alloc(options.end - options.start)
80
+ const results = {}, { bytesRead } = await fd.read(buffer, 0, options.end - options.start, options.start)
81
+ if(buffer.length > bytesRead) buffer = buffer.subarray(0, bytesRead)
82
+ for(const range of groupedRange) {
83
+ const line = buffer.subarray(range.start, range.end)
84
+ yield {line, start: range.start}
85
+ }
86
+
87
+ return results
88
+ }
89
+
90
+ async *walk(ranges, options={}) {
91
+ const fd = await fs.promises.open(this.file, 'r')
92
+ const groupedRanges = await this.groupedRanges(ranges)
93
+ for(const groupedRange of groupedRanges) {
94
+ for await (const row of this.readGroupedRange(groupedRange, fd)) {
95
+ yield row
96
+ }
97
+ }
98
+ await fd.close()
99
+ }
100
+
51
101
  async replaceLines(ranges, lines) {
52
102
  let closed
53
103
  const tmpFile = this.file + '.tmp'
@@ -83,23 +83,29 @@ export default class IndexManager {
83
83
  }
84
84
  }
85
85
 
86
- query(criteria, matchAny=false) {
87
- if (!criteria) throw new Error('No query criteria provided')
88
- const fields = Object.keys(criteria)
89
- if (!fields.length) throw new Error('No valid query criteria provided')
90
- let matchingLines = matchAny ? new Set() : null
86
+ query(criteria, options = {}) {
87
+ if (typeof options === 'boolean') {
88
+ options = { matchAny: options };
89
+ }
90
+ const { matchAny = false, caseInsensitive = false } = options;
91
+ if (!criteria) throw new Error('No query criteria provided');
92
+ const fields = Object.keys(criteria);
93
+ if (!fields.length) throw new Error('No valid query criteria provided');
94
+ let matchingLines = matchAny ? new Set() : null;
95
+
91
96
  for (const field of fields) {
92
- if (typeof(this.index.data[field]) == 'undefined') continue
93
- const criteriaValue = criteria[field]
94
- let lineNumbersForField = new Set()
95
- const isNumericField = this.opts.indexes[field] === 'number'
96
- if (typeof(criteriaValue) === 'object' && !Array.isArray(criteriaValue)) {
97
+ if (typeof this.index.data[field] === 'undefined') continue;
98
+ const criteriaValue = criteria[field];
99
+ let lineNumbersForField = new Set();
100
+ const isNumericField = this.opts.indexes[field] === 'number';
101
+
102
+ if (typeof criteriaValue === 'object' && !Array.isArray(criteriaValue)) {
97
103
  const fieldIndex = this.index.data[field];
98
104
  for (const value in fieldIndex) {
99
- let includeValue = true
105
+ let includeValue = true;
100
106
  if (isNumericField) {
101
107
  const numericValue = parseFloat(value);
102
- if (!isNaN(numericValue)) {
108
+ if (!isNaN(numericValue)) {
103
109
  if (criteriaValue['>'] !== undefined && numericValue <= criteriaValue['>']) {
104
110
  includeValue = false;
105
111
  }
@@ -113,7 +119,9 @@ export default class IndexManager {
113
119
  includeValue = false;
114
120
  }
115
121
  if (criteriaValue['!='] !== undefined) {
116
- const excludeValues = Array.isArray(criteriaValue['!=']) ? criteriaValue['!='] : [criteriaValue['!=']];
122
+ const excludeValues = Array.isArray(criteriaValue['!='])
123
+ ? criteriaValue['!=']
124
+ : [criteriaValue['!=']];
117
125
  if (excludeValues.includes(numericValue)) {
118
126
  includeValue = false;
119
127
  }
@@ -121,24 +129,45 @@ export default class IndexManager {
121
129
  }
122
130
  } else {
123
131
  if (criteriaValue['contains'] !== undefined && typeof value === 'string') {
124
- if (!value.includes(criteriaValue['contains'])) {
125
- includeValue = false;
132
+ const term = String(criteriaValue['contains']);
133
+ if (caseInsensitive) {
134
+ if (!value.toLowerCase().includes(term.toLowerCase())) {
135
+ includeValue = false;
136
+ }
137
+ } else {
138
+ if (!value.includes(term)) {
139
+ includeValue = false;
140
+ }
126
141
  }
127
142
  }
128
- if (criteriaValue['regex'] !== undefined && typeof value === 'string') {
129
- const regex = new RegExp(criteriaValue['regex']);
130
- if (!regex.test(value)) {
143
+ if (criteriaValue['regex'] !== undefined) {
144
+ let regex;
145
+ if (typeof criteriaValue['regex'] === 'string') {
146
+ regex = new RegExp(criteriaValue['regex'], caseInsensitive ? 'i' : '');
147
+ } else if (criteriaValue['regex'] instanceof RegExp) {
148
+ if (caseInsensitive && !criteriaValue['regex'].ignoreCase) {
149
+ const flags = criteriaValue['regex'].flags.includes('i')
150
+ ? criteriaValue['regex'].flags
151
+ : criteriaValue['regex'].flags + 'i';
152
+ regex = new RegExp(criteriaValue['regex'].source, flags);
153
+ } else {
154
+ regex = criteriaValue['regex'];
155
+ }
156
+ }
157
+ if (regex && !regex.test(value)) {
131
158
  includeValue = false;
132
159
  }
133
160
  }
134
161
  if (criteriaValue['!='] !== undefined) {
135
- const excludeValues = Array.isArray(criteriaValue['!=']) ? criteriaValue['!='] : [criteriaValue['!=']];
162
+ const excludeValues = Array.isArray(criteriaValue['!='])
163
+ ? criteriaValue['!=']
164
+ : [criteriaValue['!=']];
136
165
  if (excludeValues.includes(value)) {
137
166
  includeValue = false;
138
167
  }
139
168
  }
140
169
  }
141
-
170
+
142
171
  if (includeValue) {
143
172
  for (const lineNumber of fieldIndex[value]) {
144
173
  lineNumbersForField.add(lineNumber);
@@ -146,31 +175,46 @@ export default class IndexManager {
146
175
  }
147
176
  }
148
177
  } else {
178
+ // Comparação simples de igualdade
149
179
  const values = Array.isArray(criteriaValue) ? criteriaValue : [criteriaValue];
150
- for (const value of values) {
151
- if (this.index.data[field][value]) {
152
- for (const lineNumber of this.index.data[field][value]) {
153
- lineNumbersForField.add(lineNumber);
180
+ const fieldData = this.index.data[field];
181
+ for (const searchValue of values) {
182
+ for (const key in fieldData) {
183
+ let match = false;
184
+ if (isNumericField) {
185
+ // Converter ambas as partes para número
186
+ match = Number(key) === Number(searchValue);
187
+ } else {
188
+ match = caseInsensitive
189
+ ? key.toLowerCase() === String(searchValue).toLowerCase()
190
+ : key === searchValue;
191
+ }
192
+ if (match) {
193
+ for (const lineNumber of fieldData[key]) {
194
+ lineNumbersForField.add(lineNumber);
195
+ }
154
196
  }
155
197
  }
156
198
  }
157
199
  }
200
+
201
+ // Consolida os resultados de cada campo
158
202
  if (matchAny) {
159
203
  matchingLines = new Set([...matchingLines, ...lineNumbersForField]);
160
204
  } else {
161
205
  if (matchingLines === null) {
162
- matchingLines = lineNumbersForField
206
+ matchingLines = lineNumbersForField;
163
207
  } else {
164
208
  matchingLines = new Set([...matchingLines].filter(n => lineNumbersForField.has(n)));
165
209
  }
166
210
  if (!matchingLines.size) {
167
- return new Set()
211
+ return new Set();
168
212
  }
169
213
  }
170
214
  }
171
215
  return matchingLines || new Set();
172
- }
173
-
216
+ }
217
+
174
218
  load(index) {
175
219
  for(const field in index.data) {
176
220
  for(const term in index.data[field]) {
@@ -23,7 +23,7 @@ export default class Serializer extends EventEmitter {
23
23
  header |= 0x02 // set V8
24
24
  line = v8.serialize(data)
25
25
  } else {
26
- let json = JSON.stringify(data)
26
+ const json = JSON.stringify(data)
27
27
  line = Buffer.from(json, 'utf-8')
28
28
  }
29
29
  if (compress) {
Binary file