document-dataply 0.0.5-alpha.1 → 0.0.5

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/dist/cjs/index.js CHANGED
@@ -5716,31 +5716,31 @@ var require_cjs = __commonJS({
5716
5716
  }
5717
5717
  return buffer;
5718
5718
  }
5719
+ var tempBuffer = new ArrayBuffer(8);
5720
+ var tempView = new DataView(tempBuffer);
5721
+ var tempArray = new Uint8Array(tempBuffer);
5719
5722
  function bytesToNumber(bytes, offset = 0, length = bytes.length) {
5720
- if (length === 4) {
5721
- return (bytes[offset] | bytes[offset + 1] << 8 | bytes[offset + 2] << 16 | bytes[offset + 3] << 24) >>> 0;
5722
- }
5723
- if (length === 8) {
5724
- const low2 = (bytes[offset] | bytes[offset + 1] << 8 | bytes[offset + 2] << 16 | bytes[offset + 3] << 24) >>> 0;
5725
- const high = (bytes[offset + 4] | bytes[offset + 5] << 8 | bytes[offset + 6] << 16 | bytes[offset + 7] << 24) >>> 0;
5726
- return low2 + high * 4294967296;
5723
+ tempArray.set(bytes.subarray(offset, offset + length));
5724
+ switch (length) {
5725
+ case 1:
5726
+ return tempView.getUint8(0);
5727
+ case 2:
5728
+ return tempView.getUint16(0, true);
5729
+ case 3:
5730
+ return tempView.getUint16(0, true) + (tempView.getUint8(2) << 16);
5731
+ case 4:
5732
+ return tempView.getUint32(0, true);
5733
+ case 5:
5734
+ return tempView.getUint32(0, true) + tempView.getUint8(4) * 4294967296;
5735
+ case 6:
5736
+ return tempView.getUint32(0, true) + tempView.getUint16(4, true) * 4294967296;
5737
+ case 7:
5738
+ return tempView.getUint32(0, true) + (tempView.getUint16(4, true) + (tempView.getUint8(6) << 16)) * 4294967296;
5739
+ case 8:
5740
+ return tempView.getUint32(0, true) + tempView.getUint32(4, true) * 4294967296;
5741
+ default:
5742
+ return 0;
5727
5743
  }
5728
- let low = 0;
5729
- const lenLow = length < 4 ? length : 4;
5730
- for (let i = 0; i < lenLow; i++) {
5731
- low |= bytes[offset + i] << i * 8;
5732
- }
5733
- low >>>= 0;
5734
- if (length > 4) {
5735
- let high = 0;
5736
- const lenHigh = length < 8 ? length : 8;
5737
- for (let i = 4; i < lenHigh; i++) {
5738
- high |= bytes[offset + i] << (i - 4) * 8;
5739
- }
5740
- high >>>= 0;
5741
- return low + high * 4294967296;
5742
- }
5743
- return low;
5744
5744
  }
5745
5745
  function setBit(value, bitPos, flag) {
5746
5746
  if (flag) {
@@ -8681,8 +8681,7 @@ var require_cjs = __commonJS({
8681
8681
  }
8682
8682
  const pkIndexMap = /* @__PURE__ */ new Map();
8683
8683
  for (let i = 0, len = pks.length; i < len; i++) {
8684
- const pk = pks[i];
8685
- pkIndexMap.set(pk, i);
8684
+ pkIndexMap.set(pks[i], i);
8686
8685
  }
8687
8686
  const minPk = Math.min(...pks);
8688
8687
  const maxPk = Math.max(...pks);
@@ -9526,7 +9525,7 @@ __export(src_exports, {
9526
9525
  });
9527
9526
  module.exports = __toCommonJS(src_exports);
9528
9527
 
9529
- // src/core/document.ts
9528
+ // src/core/documentAPI.ts
9530
9529
  var os = __toESM(require("node:os"));
9531
9530
  var import_dataply3 = __toESM(require_cjs());
9532
9531
 
@@ -9617,17 +9616,99 @@ async function catchPromise(promise) {
9617
9616
  return promise.then((res) => [void 0, res]).catch((reason) => [reason]);
9618
9617
  }
9619
9618
 
9620
- // src/core/document.ts
9619
+ // src/utils/heap.ts
9620
+ var BinaryHeap = class {
9621
+ constructor(comparator) {
9622
+ this.comparator = comparator;
9623
+ }
9624
+ heap = [];
9625
+ get size() {
9626
+ return this.heap.length;
9627
+ }
9628
+ peek() {
9629
+ return this.heap[0];
9630
+ }
9631
+ push(value) {
9632
+ this.heap.push(value);
9633
+ this.bubbleUp(this.heap.length - 1);
9634
+ }
9635
+ pop() {
9636
+ if (this.size === 0) return void 0;
9637
+ const top = this.heap[0];
9638
+ const bottom = this.heap.pop();
9639
+ if (this.size > 0) {
9640
+ this.heap[0] = bottom;
9641
+ this.sinkDown(0);
9642
+ }
9643
+ return top;
9644
+ }
9645
+ /**
9646
+ * Replace the root element with a new value and re-heapify.
9647
+ * Faster than pop() followed by push().
9648
+ */
9649
+ replace(value) {
9650
+ const top = this.heap[0];
9651
+ this.heap[0] = value;
9652
+ this.sinkDown(0);
9653
+ return top;
9654
+ }
9655
+ toArray() {
9656
+ return [...this.heap];
9657
+ }
9658
+ bubbleUp(index) {
9659
+ while (index > 0) {
9660
+ const parentIndex = Math.floor((index - 1) / 2);
9661
+ if (this.comparator(this.heap[index], this.heap[parentIndex]) >= 0) break;
9662
+ [this.heap[index], this.heap[parentIndex]] = [this.heap[parentIndex], this.heap[index]];
9663
+ index = parentIndex;
9664
+ }
9665
+ }
9666
+ sinkDown(index) {
9667
+ while (true) {
9668
+ let smallest = index;
9669
+ const left = 2 * index + 1;
9670
+ const right = 2 * index + 2;
9671
+ if (left < this.size && this.comparator(this.heap[left], this.heap[smallest]) < 0) {
9672
+ smallest = left;
9673
+ }
9674
+ if (right < this.size && this.comparator(this.heap[right], this.heap[smallest]) < 0) {
9675
+ smallest = right;
9676
+ }
9677
+ if (smallest === index) break;
9678
+ [this.heap[index], this.heap[smallest]] = [this.heap[smallest], this.heap[index]];
9679
+ index = smallest;
9680
+ }
9681
+ }
9682
+ };
9683
+
9684
+ // src/core/documentAPI.ts
9621
9685
  var DocumentDataplyAPI = class extends import_dataply3.DataplyAPI {
9622
9686
  indices = {};
9623
9687
  trees = /* @__PURE__ */ new Map();
9624
9688
  comparator = new DocumentValueComparator();
9625
9689
  pendingBackfillFields = [];
9626
9690
  lock;
9691
+ indexedFields;
9692
+ operatorConverters = {
9693
+ equal: "primaryEqual",
9694
+ notEqual: "primaryNotEqual",
9695
+ lt: "primaryLt",
9696
+ lte: "primaryLte",
9697
+ gt: "primaryGt",
9698
+ gte: "primaryGte",
9699
+ or: "primaryOr",
9700
+ like: "like"
9701
+ };
9627
9702
  constructor(file, options) {
9628
9703
  super(file, options);
9629
9704
  this.trees = /* @__PURE__ */ new Map();
9630
9705
  this.lock = new import_dataply3.Ryoiki();
9706
+ this.indexedFields = /* @__PURE__ */ new Set(["_id"]);
9707
+ if (options?.indices) {
9708
+ for (const field of Object.keys(options.indices)) {
9709
+ this.indexedFields.add(field);
9710
+ }
9711
+ }
9631
9712
  this.hook.onceAfter("init", async (tx, isNewlyCreated) => {
9632
9713
  if (isNewlyCreated) {
9633
9714
  await this.initializeDocumentFile(tx);
@@ -9837,81 +9918,6 @@ var DocumentDataplyAPI = class extends import_dataply3.DataplyAPI {
9837
9918
  async updateDocumentInnerMetadata(metadata, tx) {
9838
9919
  await this.update(1, JSON.stringify(metadata), tx);
9839
9920
  }
9840
- };
9841
- var DocumentDataply = class _DocumentDataply {
9842
- /**
9843
- * Starts the database definition by setting the document type.
9844
- * This is used to ensure TypeScript type inference works correctly for the document structure.
9845
- * @template T The structure of the document to be stored.
9846
- */
9847
- static Define() {
9848
- return {
9849
- /**
9850
- * Sets the options for the database, such as index configurations and WAL settings.
9851
- * @template IC The configuration of indices.
9852
- * @param options The database initialization options.
9853
- */
9854
- Options: (options) => _DocumentDataply.Options(options)
9855
- };
9856
- }
9857
- /**
9858
- * Internal method used by the Define-chain to pass options.
9859
- */
9860
- static Options(options) {
9861
- return {
9862
- /**
9863
- * Creates or opens the database instance with the specified file path.
9864
- * @param file The path to the database file.
9865
- */
9866
- Open: (file) => _DocumentDataply.Open(file, options)
9867
- };
9868
- }
9869
- /**
9870
- * Internal method used to finalize construction and create the instance.
9871
- */
9872
- static Open(file, options) {
9873
- return new _DocumentDataply(file, options);
9874
- }
9875
- api;
9876
- indexedFields;
9877
- operatorConverters = {
9878
- equal: "primaryEqual",
9879
- notEqual: "primaryNotEqual",
9880
- lt: "primaryLt",
9881
- lte: "primaryLte",
9882
- gt: "primaryGt",
9883
- gte: "primaryGte",
9884
- or: "primaryOr",
9885
- like: "like"
9886
- };
9887
- constructor(file, options) {
9888
- this.api = new DocumentDataplyAPI(file, options ?? {});
9889
- this.indexedFields = /* @__PURE__ */ new Set(["_id"]);
9890
- if (options?.indices) {
9891
- for (const field of Object.keys(options.indices)) {
9892
- this.indexedFields.add(field);
9893
- }
9894
- }
9895
- }
9896
- /**
9897
- * Initialize the document database
9898
- */
9899
- async init() {
9900
- await this.api.init();
9901
- await this.api.backfillIndices();
9902
- }
9903
- /**
9904
- * Get the metadata of the document database
9905
- */
9906
- async getMetadata(tx) {
9907
- return this.api.runWithDefault((tx2) => this.api.getDocumentMetadata(tx2), tx);
9908
- }
9909
- /**
9910
- * Create a transaction
9911
- */
9912
- createTransaction() {
9913
- return this.api.createTransaction();
9914
- }
9915
9921
  verboseQuery(query) {
9916
9922
  const result = {};
9917
9923
  for (const field in query) {
@@ -9948,7 +9954,7 @@ var DocumentDataply = class _DocumentDataply {
9948
9954
  async getSelectivityCandidate(query, orderByField) {
9949
9955
  const candidates = [];
9950
9956
  for (const field in query) {
9951
- const tree = this.api.trees.get(field);
9957
+ const tree = this.trees.get(field);
9952
9958
  if (!tree) continue;
9953
9959
  const condition = query[field];
9954
9960
  const treeTx = await tree.createTransaction();
@@ -9984,6 +9990,17 @@ var DocumentDataply = class _DocumentDataply {
9984
9990
  rollback
9985
9991
  };
9986
9992
  }
9993
+ /**
9994
+ * Get Free Memory Chunk Size
9995
+ * @returns { verySmallChunkSize, smallChunkSize }
9996
+ */
9997
+ getFreeMemoryChunkSize() {
9998
+ const freeMem = os.freemem();
9999
+ const safeLimit = freeMem * 0.2;
10000
+ const verySmallChunkSize = safeLimit * 0.05;
10001
+ const smallChunkSize = safeLimit * 0.3;
10002
+ return { verySmallChunkSize, smallChunkSize };
10003
+ }
9987
10004
  /**
9988
10005
  * Get Primary Keys based on query and index selection.
9989
10006
  * Internal common method to unify query optimization.
@@ -10015,14 +10032,14 @@ var DocumentDataply = class _DocumentDataply {
10015
10032
  return new Float64Array(keysSet);
10016
10033
  }
10017
10034
  }
10018
- async insertDocument(document, tx) {
10019
- const metadata = await this.api.getDocumentInnerMetadata(tx);
10035
+ async insertDocumentInternal(document, tx) {
10036
+ const metadata = await this.getDocumentInnerMetadata(tx);
10020
10037
  const id = ++metadata.lastId;
10021
- await this.api.updateDocumentInnerMetadata(metadata, tx);
10038
+ await this.updateDocumentInnerMetadata(metadata, tx);
10022
10039
  const dataplyDocument = Object.assign({
10023
10040
  _id: id
10024
10041
  }, document);
10025
- const pk = await this.api.insert(JSON.stringify(dataplyDocument), true, tx);
10042
+ const pk = await super.insert(JSON.stringify(dataplyDocument), true, tx);
10026
10043
  return {
10027
10044
  pk,
10028
10045
  id,
@@ -10035,12 +10052,12 @@ var DocumentDataply = class _DocumentDataply {
10035
10052
  * @param tx The transaction to use
10036
10053
  * @returns The primary key of the inserted document
10037
10054
  */
10038
- async insert(document, tx) {
10039
- return this.api.writeLock(() => this.api.runWithDefault(async (tx2) => {
10040
- const { pk, document: dataplyDocument } = await this.insertDocument(document, tx2);
10041
- const flattenDocument = this.api.flattenDocument(dataplyDocument);
10055
+ async insertSingleDocument(document, tx) {
10056
+ return this.writeLock(() => this.runWithDefault(async (tx2) => {
10057
+ const { pk, document: dataplyDocument } = await this.insertDocumentInternal(document, tx2);
10058
+ const flattenDocument = this.flattenDocument(dataplyDocument);
10042
10059
  for (const field in flattenDocument) {
10043
- const tree = this.api.trees.get(field);
10060
+ const tree = this.trees.get(field);
10044
10061
  if (!tree) continue;
10045
10062
  const v = flattenDocument[field];
10046
10063
  const [error] = await catchPromise(tree.insert(pk, { k: pk, v }));
@@ -10057,12 +10074,12 @@ var DocumentDataply = class _DocumentDataply {
10057
10074
  * @param tx The transaction to use
10058
10075
  * @returns The primary keys of the inserted documents
10059
10076
  */
10060
- async insertBatch(documents, tx) {
10061
- return this.api.writeLock(() => this.api.runWithDefault(async (tx2) => {
10062
- const metadata = await this.api.getDocumentInnerMetadata(tx2);
10077
+ async insertBatchDocuments(documents, tx) {
10078
+ return this.writeLock(() => this.runWithDefault(async (tx2) => {
10079
+ const metadata = await this.getDocumentInnerMetadata(tx2);
10063
10080
  const startId = metadata.lastId + 1;
10064
10081
  metadata.lastId += documents.length;
10065
- await this.api.updateDocumentInnerMetadata(metadata, tx2);
10082
+ await this.updateDocumentInnerMetadata(metadata, tx2);
10066
10083
  const ids = [];
10067
10084
  const dataplyDocuments = [];
10068
10085
  const flattenedData = [];
@@ -10073,15 +10090,15 @@ var DocumentDataply = class _DocumentDataply {
10073
10090
  }, documents[i]);
10074
10091
  const stringified = JSON.stringify(dataplyDocument);
10075
10092
  dataplyDocuments.push(stringified);
10076
- const flattenDocument = this.api.flattenDocument(dataplyDocument);
10093
+ const flattenDocument = this.flattenDocument(dataplyDocument);
10077
10094
  flattenedData.push({ pk: -1, data: flattenDocument });
10078
10095
  ids.push(id);
10079
10096
  }
10080
- const pks = await this.api.insertBatch(dataplyDocuments, true, tx2);
10097
+ const pks = await super.insertBatch(dataplyDocuments, true, tx2);
10081
10098
  for (let i = 0, len = pks.length; i < len; i++) {
10082
10099
  flattenedData[i].pk = pks[i];
10083
10100
  }
10084
- for (const [field, tree] of this.api.trees) {
10101
+ for (const [field, tree] of this.trees) {
10085
10102
  const treeTx = await tree.createTransaction();
10086
10103
  for (let i = 0, len = flattenedData.length; i < len; i++) {
10087
10104
  const item = flattenedData[i];
@@ -10111,17 +10128,17 @@ var DocumentDataply = class _DocumentDataply {
10111
10128
  const pks = await this.getKeys(query);
10112
10129
  let updatedCount = 0;
10113
10130
  const treeTxs = /* @__PURE__ */ new Map();
10114
- for (const [field, tree] of this.api.trees) {
10131
+ for (const [field, tree] of this.trees) {
10115
10132
  treeTxs.set(field, await tree.createTransaction());
10116
10133
  }
10117
10134
  treeTxs.delete("_id");
10118
10135
  for (let i = 0, len = pks.length; i < len; i++) {
10119
10136
  const pk = pks[i];
10120
- const doc = await this.api.getDocument(pk, tx);
10137
+ const doc = await this.getDocument(pk, tx);
10121
10138
  if (!doc) continue;
10122
10139
  const updatedDoc = computeUpdatedDoc(doc);
10123
- const oldFlatDoc = this.api.flattenDocument(doc);
10124
- const newFlatDoc = this.api.flattenDocument(updatedDoc);
10140
+ const oldFlatDoc = this.flattenDocument(doc);
10141
+ const newFlatDoc = this.flattenDocument(updatedDoc);
10125
10142
  for (const [field, treeTx] of treeTxs) {
10126
10143
  const oldV = oldFlatDoc[field];
10127
10144
  const newV = newFlatDoc[field];
@@ -10133,7 +10150,7 @@ var DocumentDataply = class _DocumentDataply {
10133
10150
  await treeTx.insert(pk, { k: pk, v: newV });
10134
10151
  }
10135
10152
  }
10136
- await this.api.update(pk, JSON.stringify(updatedDoc), tx);
10153
+ await this.update(pk, JSON.stringify(updatedDoc), tx);
10137
10154
  updatedCount++;
10138
10155
  }
10139
10156
  for (const [field, treeTx] of treeTxs) {
@@ -10155,7 +10172,7 @@ var DocumentDataply = class _DocumentDataply {
10155
10172
  * @returns The number of updated documents
10156
10173
  */
10157
10174
  async fullUpdate(query, newRecord, tx) {
10158
- return await this.api.writeLock(() => this.api.runWithDefault(async (tx2) => {
10175
+ return await this.writeLock(() => this.runWithDefault(async (tx2) => {
10159
10176
  return this.updateInternal(query, (doc) => {
10160
10177
  const newDoc = typeof newRecord === "function" ? newRecord(doc) : newRecord;
10161
10178
  return { _id: doc._id, ...newDoc };
@@ -10170,11 +10187,12 @@ var DocumentDataply = class _DocumentDataply {
10170
10187
  * @returns The number of updated documents
10171
10188
  */
10172
10189
  async partialUpdate(query, newRecord, tx) {
10173
- return this.api.writeLock(() => this.api.runWithDefault(async (tx2) => {
10190
+ return this.writeLock(() => this.runWithDefault(async (tx2) => {
10174
10191
  return this.updateInternal(query, (doc) => {
10175
- const partialUpdate = typeof newRecord === "function" ? newRecord(doc) : newRecord;
10176
- delete partialUpdate._id;
10177
- return { ...doc, ...partialUpdate };
10192
+ const partialUpdateContent = typeof newRecord === "function" ? newRecord(doc) : newRecord;
10193
+ const finalUpdate = { ...partialUpdateContent };
10194
+ delete finalUpdate._id;
10195
+ return { ...doc, ...finalUpdate };
10178
10196
  }, tx2);
10179
10197
  }, tx));
10180
10198
  }
@@ -10184,21 +10202,21 @@ var DocumentDataply = class _DocumentDataply {
10184
10202
  * @param tx The transaction to use
10185
10203
  * @returns The number of deleted documents
10186
10204
  */
10187
- async delete(query, tx) {
10188
- return this.api.writeLock(() => this.api.runWithDefault(async (tx2) => {
10205
+ async deleteDocuments(query, tx) {
10206
+ return this.writeLock(() => this.runWithDefault(async (tx2) => {
10189
10207
  const pks = await this.getKeys(query);
10190
10208
  let deletedCount = 0;
10191
10209
  for (let i = 0, len = pks.length; i < len; i++) {
10192
10210
  const pk = pks[i];
10193
- const doc = await this.api.getDocument(pk, tx2);
10211
+ const doc = await this.getDocument(pk, tx2);
10194
10212
  if (!doc) continue;
10195
- const flatDoc = this.api.flattenDocument(doc);
10196
- for (const [field, tree] of this.api.trees) {
10213
+ const flatDoc = this.flattenDocument(doc);
10214
+ for (const [field, tree] of this.trees) {
10197
10215
  const v = flatDoc[field];
10198
10216
  if (v === void 0) continue;
10199
10217
  await tree.delete(pk, { k: pk, v });
10200
10218
  }
10201
- await this.api.delete(pk, true, tx2);
10219
+ await super.delete(pk, true, tx2);
10202
10220
  deletedCount++;
10203
10221
  }
10204
10222
  return deletedCount;
@@ -10210,8 +10228,8 @@ var DocumentDataply = class _DocumentDataply {
10210
10228
  * @param tx The transaction to use
10211
10229
  * @returns The number of documents that match the query
10212
10230
  */
10213
- async count(query, tx) {
10214
- return this.api.readLock(() => this.api.runWithDefault(async (tx2) => {
10231
+ async countDocuments(query, tx) {
10232
+ return this.readLock(() => this.runWithDefault(async (tx2) => {
10215
10233
  const pks = await this.getKeys(query);
10216
10234
  return pks.length;
10217
10235
  }, tx));
@@ -10224,7 +10242,7 @@ var DocumentDataply = class _DocumentDataply {
10224
10242
  * @returns The documents that match the query
10225
10243
  * @throws Error if query or orderBy contains non-indexed fields
10226
10244
  */
10227
- select(query, options = {}, tx) {
10245
+ selectDocuments(query, options = {}, tx) {
10228
10246
  for (const field of Object.keys(query)) {
10229
10247
  if (!this.indexedFields.has(field)) {
10230
10248
  throw new Error(`Query field "${field}" is not indexed. Available indexed fields: ${Array.from(this.indexedFields).join(", ")}`);
@@ -10241,7 +10259,7 @@ var DocumentDataply = class _DocumentDataply {
10241
10259
  orderBy: orderByField
10242
10260
  } = options;
10243
10261
  const self = this;
10244
- const stream = this.api.streamWithDefault(async function* (tx2) {
10262
+ const stream = this.streamWithDefault(async function* (tx2) {
10245
10263
  const keys = await self.getKeys(query, orderByField, sortOrder);
10246
10264
  const totalKeys = keys.length;
10247
10265
  if (totalKeys === 0) return;
@@ -10253,42 +10271,73 @@ var DocumentDataply = class _DocumentDataply {
10253
10271
  if (selectivity) {
10254
10272
  selectivity.rollback();
10255
10273
  }
10256
- let currentChunkSize = self.api.options.pageSize;
10274
+ let currentChunkSize = self.options.pageSize;
10257
10275
  if (!isDriverOrderByField && orderByField) {
10276
+ const topK = limit === Infinity ? Infinity : offset + limit;
10277
+ let heap = null;
10278
+ if (topK !== Infinity) {
10279
+ const heapComparator = (a, b) => {
10280
+ const aVal = a[orderByField] ?? a._id;
10281
+ const bVal = b[orderByField] ?? b._id;
10282
+ const cmp = aVal < bVal ? -1 : aVal > bVal ? 1 : 0;
10283
+ return sortOrder === "asc" ? -cmp : cmp;
10284
+ };
10285
+ heap = new BinaryHeap(heapComparator);
10286
+ }
10258
10287
  const results = [];
10259
10288
  let i = 0;
10260
10289
  let nextChunkPromise = null;
10261
10290
  if (i < totalKeys) {
10262
10291
  const endIdx = Math.min(i + currentChunkSize, totalKeys);
10263
10292
  const chunkKeys = keys.subarray(i, endIdx);
10264
- nextChunkPromise = self.api.selectMany(chunkKeys, false, tx2);
10293
+ nextChunkPromise = self.selectMany(chunkKeys, false, tx2);
10265
10294
  i = endIdx;
10266
10295
  }
10267
10296
  while (nextChunkPromise) {
10268
10297
  const rawResults = await nextChunkPromise;
10269
10298
  nextChunkPromise = null;
10270
- const freeMem = os.freemem();
10271
- const safeLimit = freeMem * 0.2;
10299
+ const { verySmallChunkSize, smallChunkSize } = self.getFreeMemoryChunkSize();
10272
10300
  if (i < totalKeys) {
10273
10301
  const endIdx = Math.min(i + currentChunkSize, totalKeys);
10274
10302
  const chunkKeys = keys.subarray(i, endIdx);
10275
- nextChunkPromise = self.api.selectMany(chunkKeys, false, tx2);
10303
+ nextChunkPromise = self.selectMany(chunkKeys, false, tx2);
10276
10304
  i = endIdx;
10277
10305
  }
10278
10306
  let chunkTotalSize = 0;
10279
10307
  for (let j = 0, len = rawResults.length; j < len; j++) {
10280
10308
  const s = rawResults[j];
10281
10309
  if (s) {
10282
- results.push(JSON.parse(s));
10310
+ const doc = JSON.parse(s);
10283
10311
  chunkTotalSize += s.length * 2;
10312
+ if (heap) {
10313
+ if (heap.size < topK) heap.push(doc);
10314
+ else {
10315
+ const top = heap.peek();
10316
+ if (top) {
10317
+ const aVal = doc[orderByField] ?? doc._id;
10318
+ const bVal = top[orderByField] ?? top._id;
10319
+ const cmp = aVal < bVal ? -1 : aVal > bVal ? 1 : 0;
10320
+ const isBetter = sortOrder === "asc" ? cmp < 0 : cmp > 0;
10321
+ if (isBetter) {
10322
+ heap.replace(doc);
10323
+ }
10324
+ }
10325
+ }
10326
+ } else {
10327
+ results.push(doc);
10328
+ }
10284
10329
  }
10285
10330
  }
10286
10331
  if (chunkTotalSize > 0) {
10287
- if (chunkTotalSize < safeLimit * 0.05) currentChunkSize = currentChunkSize * 2;
10288
- else if (chunkTotalSize > safeLimit * 0.3) currentChunkSize = Math.max(Math.floor(currentChunkSize / 2), 20);
10332
+ if (chunkTotalSize < verySmallChunkSize) {
10333
+ currentChunkSize = currentChunkSize * 2;
10334
+ } else if (chunkTotalSize > smallChunkSize) {
10335
+ currentChunkSize = Math.max(Math.floor(currentChunkSize / 2), 20);
10336
+ }
10289
10337
  }
10290
10338
  }
10291
- results.sort((a, b) => {
10339
+ const finalDocs = heap ? heap.toArray() : results;
10340
+ finalDocs.sort((a, b) => {
10292
10341
  const aVal = a[orderByField] ?? a._id;
10293
10342
  const bVal = b[orderByField] ?? b._id;
10294
10343
  const cmp = aVal < bVal ? -1 : aVal > bVal ? 1 : 0;
@@ -10296,7 +10345,7 @@ var DocumentDataply = class _DocumentDataply {
10296
10345
  });
10297
10346
  const start = offset;
10298
10347
  const end = limit === Infinity ? void 0 : start + limit;
10299
- const limitedResults = results.slice(start, end);
10348
+ const limitedResults = finalDocs.slice(start, end);
10300
10349
  for (let j = 0, len = limitedResults.length; j < len; j++) {
10301
10350
  yield limitedResults[j];
10302
10351
  }
@@ -10307,18 +10356,17 @@ var DocumentDataply = class _DocumentDataply {
10307
10356
  if (yieldedCount < limit && i < totalKeys) {
10308
10357
  const endIdx = Math.min(i + currentChunkSize, totalKeys);
10309
10358
  const chunkKeys = keys.subarray(i, endIdx);
10310
- nextChunkPromise = self.api.selectMany(chunkKeys, false, tx2);
10359
+ nextChunkPromise = self.selectMany(chunkKeys, false, tx2);
10311
10360
  i = endIdx;
10312
10361
  }
10313
10362
  while (nextChunkPromise) {
10314
10363
  const rawResults = await nextChunkPromise;
10315
10364
  nextChunkPromise = null;
10316
- const freeMem = os.freemem();
10317
- const safeLimit = freeMem * 0.2;
10365
+ const { verySmallChunkSize, smallChunkSize } = self.getFreeMemoryChunkSize();
10318
10366
  if (yieldedCount < limit && i < totalKeys) {
10319
10367
  const endIdx = Math.min(i + currentChunkSize, totalKeys);
10320
10368
  const chunkKeys = keys.subarray(i, endIdx);
10321
- nextChunkPromise = self.api.selectMany(chunkKeys, false, tx2);
10369
+ nextChunkPromise = self.selectMany(chunkKeys, false, tx2);
10322
10370
  i = endIdx;
10323
10371
  }
10324
10372
  let chunkTotalSize = 0;
@@ -10333,8 +10381,11 @@ var DocumentDataply = class _DocumentDataply {
10333
10381
  }
10334
10382
  }
10335
10383
  if (chunkTotalSize > 0) {
10336
- if (chunkTotalSize < safeLimit * 0.05) currentChunkSize = currentChunkSize * 2;
10337
- else if (chunkTotalSize > safeLimit * 0.3) currentChunkSize = Math.max(Math.floor(currentChunkSize / 2), 20);
10384
+ if (chunkTotalSize < verySmallChunkSize) {
10385
+ currentChunkSize = currentChunkSize * 2;
10386
+ } else if (chunkTotalSize > smallChunkSize) {
10387
+ currentChunkSize = Math.max(Math.floor(currentChunkSize / 2), 20);
10388
+ }
10338
10389
  }
10339
10390
  }
10340
10391
  }
@@ -10348,6 +10399,133 @@ var DocumentDataply = class _DocumentDataply {
10348
10399
  };
10349
10400
  return { stream, drain };
10350
10401
  }
10402
+ };
10403
+
10404
+ // src/core/document.ts
10405
+ var DocumentDataply = class _DocumentDataply {
10406
+ /**
10407
+ * Starts the database definition by setting the document type.
10408
+ * This is used to ensure TypeScript type inference works correctly for the document structure.
10409
+ * @template T The structure of the document to be stored.
10410
+ */
10411
+ static Define() {
10412
+ return {
10413
+ /**
10414
+ * Sets the options for the database, such as index configurations and WAL settings.
10415
+ * @template IC The configuration of indices.
10416
+ * @param options The database initialization options.
10417
+ */
10418
+ Options: (options) => _DocumentDataply.Options(options)
10419
+ };
10420
+ }
10421
+ /**
10422
+ * Internal method used by the Define-chain to pass options.
10423
+ */
10424
+ static Options(options) {
10425
+ return {
10426
+ /**
10427
+ * Creates or opens the database instance with the specified file path.
10428
+ * @param file The path to the database file.
10429
+ */
10430
+ Open: (file) => _DocumentDataply.Open(file, options)
10431
+ };
10432
+ }
10433
+ /**
10434
+ * Internal method used to finalize construction and create the instance.
10435
+ */
10436
+ static Open(file, options) {
10437
+ return new _DocumentDataply(file, options);
10438
+ }
10439
+ api;
10440
+ constructor(file, options) {
10441
+ this.api = new DocumentDataplyAPI(file, options ?? {});
10442
+ }
10443
+ /**
10444
+ * Initialize the document database
10445
+ */
10446
+ async init() {
10447
+ await this.api.init();
10448
+ await this.api.backfillIndices();
10449
+ }
10450
+ /**
10451
+ * Get the metadata of the document database
10452
+ */
10453
+ async getMetadata(tx) {
10454
+ return this.api.runWithDefault((tx2) => this.api.getDocumentMetadata(tx2), tx);
10455
+ }
10456
+ /**
10457
+ * Create a transaction
10458
+ */
10459
+ createTransaction() {
10460
+ return this.api.createTransaction();
10461
+ }
10462
+ /**
10463
+ * Insert a document into the database
10464
+ * @param document The document to insert
10465
+ * @param tx The transaction to use
10466
+ * @returns The primary key of the inserted document
10467
+ */
10468
+ async insert(document, tx) {
10469
+ return this.api.insertSingleDocument(document, tx);
10470
+ }
10471
+ /**
10472
+ * Insert a batch of documents into the database
10473
+ * @param documents The documents to insert
10474
+ * @param tx The transaction to use
10475
+ * @returns The primary keys of the inserted documents
10476
+ */
10477
+ async insertBatch(documents, tx) {
10478
+ return this.api.insertBatchDocuments(documents, tx);
10479
+ }
10480
+ /**
10481
+ * Fully update documents from the database that match the query
10482
+ * @param query The query to use (only indexed fields + _id allowed)
10483
+ * @param newRecord Complete document to replace with, or function that receives current document and returns new document
10484
+ * @param tx The transaction to use
10485
+ * @returns The number of updated documents
10486
+ */
10487
+ async fullUpdate(query, newRecord, tx) {
10488
+ return this.api.fullUpdate(query, newRecord, tx);
10489
+ }
10490
+ /**
10491
+ * Partially update documents from the database that match the query
10492
+ * @param query The query to use (only indexed fields + _id allowed)
10493
+ * @param newRecord Partial document to merge, or function that receives current document and returns partial update
10494
+ * @param tx The transaction to use
10495
+ * @returns The number of updated documents
10496
+ */
10497
+ async partialUpdate(query, newRecord, tx) {
10498
+ return this.api.partialUpdate(query, newRecord, tx);
10499
+ }
10500
+ /**
10501
+ * Delete documents from the database that match the query
10502
+ * @param query The query to use (only indexed fields + _id allowed)
10503
+ * @param tx The transaction to use
10504
+ * @returns The number of deleted documents
10505
+ */
10506
+ async delete(query, tx) {
10507
+ return this.api.deleteDocuments(query, tx);
10508
+ }
10509
+ /**
10510
+ * Count documents from the database that match the query
10511
+ * @param query The query to use (only indexed fields + _id allowed)
10512
+ * @param tx The transaction to use
10513
+ * @returns The number of documents that match the query
10514
+ */
10515
+ async count(query, tx) {
10516
+ return this.api.countDocuments(query, tx);
10517
+ }
10518
+ /**
10519
+ * Select documents from the database
10520
+ * @param query The query to use (only indexed fields + _id allowed)
10521
+ * @param options The options to use
10522
+ * @param tx The transaction to use
10523
+ * @returns The documents that match the query
10524
+ * @throws Error if query or orderBy contains non-indexed fields
10525
+ */
10526
+ select(query, options = {}, tx) {
10527
+ return this.api.selectDocuments(query, options, tx);
10528
+ }
10351
10529
  /**
10352
10530
  * Close the document database
10353
10531
  */
@@ -1,6 +1,6 @@
1
1
  import type { DataplyTreeValue, Primitive } from '../../types';
2
2
  import { BPTreeNode, SerializeStrategyAsync, type SerializeStrategyHead } from 'dataply';
3
- import { DocumentDataplyAPI } from '../document';
3
+ import { DocumentDataplyAPI } from '../documentAPI';
4
4
  export declare class DocumentSerializeStrategyAsync<T extends Primitive> extends SerializeStrategyAsync<number, DataplyTreeValue<T>> {
5
5
  protected readonly api: DocumentDataplyAPI<any, any>;
6
6
  protected readonly txContext: DocumentDataplyAPI<any, any>['txContext'];
@@ -1,39 +1,6 @@
1
- import type { DataplyTreeValue, DocumentDataplyInnerMetadata, DocumentDataplyOptions, DocumentJSON, FlattenedDocumentJSON, Primitive, DocumentDataplyQuery, DocumentDataplyIndexedQuery, DocumentDataplyCondition, DataplyDocument, DocumentDataplyMetadata, DocumentDataplyQueryOptions, IndexConfig } from '../types';
2
- import { DataplyAPI, Transaction, BPTreeAsync } from 'dataply';
3
- import { DocumentValueComparator } from './bptree/documentComparator';
4
- export declare class DocumentDataplyAPI<T extends DocumentJSON, IC extends IndexConfig<T>> extends DataplyAPI {
5
- runWithDefault: <T_1>(callback: (tx: Transaction) => Promise<T_1>, tx?: Transaction) => Promise<T_1>;
6
- streamWithDefault: <T_1>(callback: (tx: Transaction) => AsyncGenerator<T_1>, tx?: Transaction) => AsyncGenerator<T_1>;
7
- indices: DocumentDataplyInnerMetadata['indices'];
8
- readonly trees: Map<string, BPTreeAsync<number, DataplyTreeValue<Primitive>>>;
9
- readonly comparator: DocumentValueComparator<DataplyTreeValue<Primitive>, Primitive>;
10
- private pendingBackfillFields;
11
- private readonly lock;
12
- constructor(file: string, options: DocumentDataplyOptions<T, IC>);
13
- getDocument(pk: number, tx?: Transaction): Promise<DataplyDocument<T>>;
14
- readLock<T>(fn: () => T): Promise<T>;
15
- writeLock<T>(fn: () => T): Promise<T>;
16
- /**
17
- * Backfill indices for fields that were added with `true` option after data was inserted.
18
- * This method should be called after `init()` if you want to index existing documents
19
- * for newly added index fields.
20
- *
21
- * @returns Number of documents that were backfilled
22
- */
23
- backfillIndices(tx?: Transaction): Promise<number>;
24
- createDocumentInnerMetadata(indices: DocumentDataplyInnerMetadata['indices']): DocumentDataplyInnerMetadata;
25
- initializeDocumentFile(tx: Transaction): Promise<void>;
26
- verifyDocumentFile(tx: Transaction): Promise<boolean>;
27
- /**
28
- * returns flattened document
29
- * @param document
30
- * @returns
31
- */
32
- flattenDocument(document: T): FlattenedDocumentJSON;
33
- getDocumentMetadata(tx: Transaction): Promise<DocumentDataplyMetadata>;
34
- getDocumentInnerMetadata(tx: Transaction): Promise<DocumentDataplyInnerMetadata>;
35
- updateDocumentInnerMetadata(metadata: DocumentDataplyInnerMetadata, tx: Transaction): Promise<void>;
36
- }
1
+ import type { DocumentDataplyOptions, DocumentJSON, DocumentDataplyIndexedQuery, DataplyDocument, DocumentDataplyMetadata, DocumentDataplyQueryOptions, IndexConfig } from '../types';
2
+ import { Transaction } from 'dataply';
3
+ import { DocumentDataplyAPI } from './documentAPI';
37
4
  export declare class DocumentDataply<T extends DocumentJSON, IC extends IndexConfig<T>> {
38
5
  /**
39
6
  * Starts the database definition by setting the document type.
@@ -63,8 +30,6 @@ export declare class DocumentDataply<T extends DocumentJSON, IC extends IndexCon
63
30
  */
64
31
  private static Open;
65
32
  protected readonly api: DocumentDataplyAPI<T, IC>;
66
- private readonly indexedFields;
67
- private readonly operatorConverters;
68
33
  protected constructor(file: string, options?: DocumentDataplyOptions<T, IC>);
69
34
  /**
70
35
  * Initialize the document database
@@ -78,32 +43,6 @@ export declare class DocumentDataply<T extends DocumentJSON, IC extends IndexCon
78
43
  * Create a transaction
79
44
  */
80
45
  createTransaction(): Transaction;
81
- private verboseQuery;
82
- /**
83
- * Get the selectivity candidate for the given query
84
- * @param query The query conditions
85
- * @param orderByField Optional field name for orderBy optimization
86
- * @returns Driver and other candidates for query execution
87
- */
88
- getSelectivityCandidate<U extends Partial<DocumentDataplyIndexedQuery<T, IC>>, V extends DataplyTreeValue<U>>(query: Partial<DocumentDataplyQuery<V>>, orderByField?: string): Promise<{
89
- driver: {
90
- tree: BPTreeAsync<number, V>;
91
- condition: Partial<DocumentDataplyCondition<U>>;
92
- field: string;
93
- };
94
- others: {
95
- tree: BPTreeAsync<number, V>;
96
- condition: Partial<DocumentDataplyCondition<U>>;
97
- field: string;
98
- }[];
99
- rollback: () => void;
100
- } | null>;
101
- /**
102
- * Get Primary Keys based on query and index selection.
103
- * Internal common method to unify query optimization.
104
- */
105
- private getKeys;
106
- private insertDocument;
107
46
  /**
108
47
  * Insert a document into the database
109
48
  * @param document The document to insert
@@ -118,14 +57,6 @@ export declare class DocumentDataply<T extends DocumentJSON, IC extends IndexCon
118
57
  * @returns The primary keys of the inserted documents
119
58
  */
120
59
  insertBatch(documents: T[], tx?: Transaction): Promise<number[]>;
121
- /**
122
- * Internal update method used by both fullUpdate and partialUpdate
123
- * @param query The query to use
124
- * @param computeUpdatedDoc Function that computes the updated document from the original
125
- * @param tx The transaction to use
126
- * @returns The number of updated documents
127
- */
128
- private updateInternal;
129
60
  /**
130
61
  * Fully update documents from the database that match the query
131
62
  * @param query The query to use (only indexed fields + _id allowed)
@@ -0,0 +1,136 @@
1
+ import type { DataplyTreeValue, DocumentDataplyInnerMetadata, DocumentDataplyOptions, DocumentJSON, FlattenedDocumentJSON, Primitive, DataplyDocument, DocumentDataplyMetadata, IndexConfig, DocumentDataplyQuery, DocumentDataplyIndexedQuery, DocumentDataplyCondition, DocumentDataplyQueryOptions } from '../types';
2
+ import { DataplyAPI, Transaction, BPTreeAsync } from 'dataply';
3
+ import { DocumentValueComparator } from './bptree/documentComparator';
4
+ export declare class DocumentDataplyAPI<T extends DocumentJSON, IC extends IndexConfig<T>> extends DataplyAPI {
5
+ runWithDefault: <T_1>(callback: (tx: Transaction) => Promise<T_1>, tx?: Transaction) => Promise<T_1>;
6
+ streamWithDefault: <T_1>(callback: (tx: Transaction) => AsyncGenerator<T_1>, tx?: Transaction) => AsyncGenerator<T_1>;
7
+ indices: DocumentDataplyInnerMetadata['indices'];
8
+ readonly trees: Map<string, BPTreeAsync<number, DataplyTreeValue<Primitive>>>;
9
+ readonly comparator: DocumentValueComparator<DataplyTreeValue<Primitive>, Primitive>;
10
+ private pendingBackfillFields;
11
+ private readonly lock;
12
+ readonly indexedFields: Set<string>;
13
+ private readonly operatorConverters;
14
+ constructor(file: string, options: DocumentDataplyOptions<T, IC>);
15
+ getDocument(pk: number, tx?: Transaction): Promise<DataplyDocument<T>>;
16
+ readLock<T>(fn: () => T): Promise<T>;
17
+ writeLock<T>(fn: () => T): Promise<T>;
18
+ /**
19
+ * Backfill indices for fields that were added with `true` option after data was inserted.
20
+ * This method should be called after `init()` if you want to index existing documents
21
+ * for newly added index fields.
22
+ *
23
+ * @returns Number of documents that were backfilled
24
+ */
25
+ backfillIndices(tx?: Transaction): Promise<number>;
26
+ createDocumentInnerMetadata(indices: DocumentDataplyInnerMetadata['indices']): DocumentDataplyInnerMetadata;
27
+ initializeDocumentFile(tx: Transaction): Promise<void>;
28
+ verifyDocumentFile(tx: Transaction): Promise<boolean>;
29
+ /**
30
+ * returns flattened document
31
+ * @param document
32
+ * @returns
33
+ */
34
+ flattenDocument(document: T): FlattenedDocumentJSON;
35
+ getDocumentMetadata(tx: Transaction): Promise<DocumentDataplyMetadata>;
36
+ getDocumentInnerMetadata(tx: Transaction): Promise<DocumentDataplyInnerMetadata>;
37
+ updateDocumentInnerMetadata(metadata: DocumentDataplyInnerMetadata, tx: Transaction): Promise<void>;
38
+ verboseQuery<U extends Partial<DocumentDataplyIndexedQuery<T, IC>>, V extends DataplyTreeValue<U>>(query: Partial<DocumentDataplyQuery<U>>): Partial<DocumentDataplyQuery<V>>;
39
+ /**
40
+ * Get the selectivity candidate for the given query
41
+ * @param query The query conditions
42
+ * @param orderByField Optional field name for orderBy optimization
43
+ * @returns Driver and other candidates for query execution
44
+ */
45
+ getSelectivityCandidate<U extends Partial<DocumentDataplyIndexedQuery<T, IC>>, V extends DataplyTreeValue<U>>(query: Partial<DocumentDataplyQuery<V>>, orderByField?: string): Promise<{
46
+ driver: {
47
+ tree: BPTreeAsync<number, V>;
48
+ condition: Partial<DocumentDataplyCondition<U>>;
49
+ field: string;
50
+ };
51
+ others: {
52
+ tree: BPTreeAsync<number, V>;
53
+ condition: Partial<DocumentDataplyCondition<U>>;
54
+ field: string;
55
+ }[];
56
+ rollback: () => void;
57
+ } | null>;
58
+ /**
59
+ * Get Free Memory Chunk Size
60
+ * @returns { verySmallChunkSize, smallChunkSize }
61
+ */
62
+ getFreeMemoryChunkSize(): {
63
+ verySmallChunkSize: number;
64
+ smallChunkSize: number;
65
+ };
66
+ /**
67
+ * Get Primary Keys based on query and index selection.
68
+ * Internal common method to unify query optimization.
69
+ */
70
+ getKeys(query: Partial<DocumentDataplyIndexedQuery<T, IC>>, orderBy?: keyof IC | '_id', sortOrder?: 'asc' | 'desc'): Promise<Float64Array>;
71
+ private insertDocumentInternal;
72
+ /**
73
+ * Insert a document into the database
74
+ * @param document The document to insert
75
+ * @param tx The transaction to use
76
+ * @returns The primary key of the inserted document
77
+ */
78
+ insertSingleDocument(document: T, tx?: Transaction): Promise<number>;
79
+ /**
80
+ * Insert a batch of documents into the database
81
+ * @param documents The documents to insert
82
+ * @param tx The transaction to use
83
+ * @returns The primary keys of the inserted documents
84
+ */
85
+ insertBatchDocuments(documents: T[], tx?: Transaction): Promise<number[]>;
86
+ /**
87
+ * Internal update method used by both fullUpdate and partialUpdate
88
+ * @param query The query to use
89
+ * @param computeUpdatedDoc Function that computes the updated document from the original
90
+ * @param tx The transaction to use
91
+ * @returns The number of updated documents
92
+ */
93
+ private updateInternal;
94
+ /**
95
+ * Fully update documents from the database that match the query
96
+ * @param query The query to use (only indexed fields + _id allowed)
97
+ * @param newRecord Complete document to replace with, or function that receives current document and returns new document
98
+ * @param tx The transaction to use
99
+ * @returns The number of updated documents
100
+ */
101
+ fullUpdate(query: Partial<DocumentDataplyIndexedQuery<T, IC>>, newRecord: T | ((document: DataplyDocument<T>) => T), tx?: Transaction): Promise<number>;
102
+ /**
103
+ * Partially update documents from the database that match the query
104
+ * @param query The query to use (only indexed fields + _id allowed)
105
+ * @param newRecord Partial document to merge, or function that receives current document and returns partial update
106
+ * @param tx The transaction to use
107
+ * @returns The number of updated documents
108
+ */
109
+ partialUpdate(query: Partial<DocumentDataplyIndexedQuery<T, IC>>, newRecord: Partial<DataplyDocument<T>> | ((document: DataplyDocument<T>) => Partial<DataplyDocument<T>>), tx?: Transaction): Promise<number>;
110
+ /**
111
+ * Delete documents from the database that match the query
112
+ * @param query The query to use (only indexed fields + _id allowed)
113
+ * @param tx The transaction to use
114
+ * @returns The number of deleted documents
115
+ */
116
+ deleteDocuments(query: Partial<DocumentDataplyIndexedQuery<T, IC>>, tx?: Transaction): Promise<number>;
117
+ /**
118
+ * Count documents from the database that match the query
119
+ * @param query The query to use (only indexed fields + _id allowed)
120
+ * @param tx The transaction to use
121
+ * @returns The number of documents that match the query
122
+ */
123
+ countDocuments(query: Partial<DocumentDataplyIndexedQuery<T, IC>>, tx?: Transaction): Promise<number>;
124
+ /**
125
+ * Select documents from the database
126
+ * @param query The query to use (only indexed fields + _id allowed)
127
+ * @param options The options to use
128
+ * @param tx The transaction to use
129
+ * @returns The documents that match the query
130
+ * @throws Error if query or orderBy contains non-indexed fields
131
+ */
132
+ selectDocuments(query: Partial<DocumentDataplyIndexedQuery<T, IC>>, options?: DocumentDataplyQueryOptions<T, IC>, tx?: Transaction): {
133
+ stream: AsyncIterableIterator<DataplyDocument<T>>;
134
+ drain: () => Promise<DataplyDocument<T>[]>;
135
+ };
136
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "document-dataply",
3
- "version": "0.0.5-alpha.1",
3
+ "version": "0.0.5",
4
4
  "description": "Simple and powerful JSON document database supporting complex queries and flexible indexing policies.",
5
5
  "license": "MIT",
6
6
  "author": "izure <admin@izure.org>",
@@ -42,7 +42,7 @@
42
42
  "dataply"
43
43
  ],
44
44
  "dependencies": {
45
- "dataply": "^0.0.21-alpha.1"
45
+ "dataply": "^0.0.21"
46
46
  },
47
47
  "devDependencies": {
48
48
  "@types/jest": "^30.0.0",