dataply 0.0.26-alpha.13 → 0.0.26-alpha.15

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
@@ -2341,8 +2341,8 @@ function deleteEntry(ops, ctx, node, key, comparator) {
2341
2341
  } else {
2342
2342
  pointerP0 = siblingNode.keys.splice(0, 1)[0];
2343
2343
  pointerK0 = siblingNode.values.splice(0, 1)[0];
2344
- node.keys = node.keys.concat(pointerP0);
2345
- node.values = node.values.concat(pointerK0);
2344
+ node.keys = [...node.keys, pointerP0];
2345
+ node.values = [...node.values, pointerK0];
2346
2346
  parentNode = cloneNode(ops.getNode(node.parent));
2347
2347
  const pointerIndex = parentNode.keys.indexOf(siblingNode.id);
2348
2348
  if (pointerIndex > 0) {
@@ -2422,6 +2422,13 @@ function deleteOp(ops, ctx, key, comparator, value) {
2422
2422
  break;
2423
2423
  }
2424
2424
  }
2425
+ function batchDeleteOp(ops, ctx, entries, comparator) {
2426
+ if (entries.length === 0) return;
2427
+ for (let i = 0, len = entries.length; i < len; i++) {
2428
+ const [key, value] = entries[i];
2429
+ deleteOp(ops, ctx, key, comparator, value);
2430
+ }
2431
+ }
2425
2432
  function batchInsertOp(ops, ctx, entries, comparator) {
2426
2433
  if (entries.length === 0) return;
2427
2434
  const sorted = [...entries].sort((a, b) => comparator.asc(a[1], b[1]));
@@ -3393,6 +3400,9 @@ var BPTreeSyncTransaction = class extends BPTreeTransaction {
3393
3400
  delete(key, value) {
3394
3401
  deleteOp(this._ops, this._ctx, key, this.comparator, value);
3395
3402
  }
3403
+ batchDelete(entries) {
3404
+ batchDeleteOp(this._ops, this._ctx, entries, this.comparator);
3405
+ }
3396
3406
  // ─── Head Data ───────────────────────────────────────────────────
3397
3407
  getHeadData() {
3398
3408
  const head = this._readHead();
@@ -3514,6 +3524,14 @@ var BPTreeSync = class extends BPTreeSyncTransaction {
3514
3524
  throw new Error(`Transaction failed: ${result.error || "Commit failed due to conflict"}`);
3515
3525
  }
3516
3526
  }
3527
+ batchDelete(entries) {
3528
+ const tx = this.createTransaction();
3529
+ tx.batchDelete(entries);
3530
+ const result = tx.commit();
3531
+ if (!result.success) {
3532
+ throw new Error(`Transaction failed: ${result.error || "Commit failed due to conflict"}`);
3533
+ }
3534
+ }
3517
3535
  batchInsert(entries) {
3518
3536
  const tx = this.createTransaction();
3519
3537
  tx.batchInsert(entries);
@@ -4332,8 +4350,8 @@ async function deleteEntryAsync(ops, ctx, node, key, comparator) {
4332
4350
  } else {
4333
4351
  pointerP0 = siblingNode.keys.splice(0, 1)[0];
4334
4352
  pointerK0 = siblingNode.values.splice(0, 1)[0];
4335
- node.keys = node.keys.concat(pointerP0);
4336
- node.values = node.values.concat(pointerK0);
4353
+ node.keys = [...node.keys, pointerP0];
4354
+ node.values = [...node.values, pointerK0];
4337
4355
  parentNode = cloneNode(await ops.getNode(node.parent));
4338
4356
  const pi = parentNode.keys.indexOf(siblingNode.id);
4339
4357
  if (pi > 0) {
@@ -4405,6 +4423,13 @@ async function deleteOpAsync(ops, ctx, key, comparator, value) {
4405
4423
  break;
4406
4424
  }
4407
4425
  }
4426
+ async function batchDeleteOpAsync(ops, ctx, entries, comparator) {
4427
+ if (entries.length === 0) return;
4428
+ for (let i = 0, len = entries.length; i < len; i++) {
4429
+ const [key, value] = entries[i];
4430
+ await deleteOpAsync(ops, ctx, key, comparator, value);
4431
+ }
4432
+ }
4408
4433
  async function batchInsertOpAsync(ops, ctx, entries, comparator) {
4409
4434
  if (entries.length === 0) return;
4410
4435
  const sorted = [...entries].sort((a, b) => comparator.asc(a[1], b[1]));
@@ -4827,6 +4852,12 @@ var BPTreeAsyncTransaction = class extends BPTreeTransaction {
4827
4852
  await deleteOpAsync(this._ops, this._ctx, key, this.comparator, value);
4828
4853
  });
4829
4854
  }
4855
+ async batchDelete(entries) {
4856
+ if (entries.length === 0) return;
4857
+ return this.writeLock(0, async () => {
4858
+ await batchDeleteOpAsync(this._ops, this._ctx, entries, this.comparator);
4859
+ });
4860
+ }
4830
4861
  // ─── Head Data ───────────────────────────────────────────────────
4831
4862
  async getHeadData() {
4832
4863
  const head = await this._readHead();
@@ -4952,6 +4983,16 @@ var BPTreeAsync = class extends BPTreeAsyncTransaction {
4952
4983
  }
4953
4984
  });
4954
4985
  }
4986
+ async batchDelete(entries) {
4987
+ return this.writeLock(1, async () => {
4988
+ const tx = await this.createTransaction();
4989
+ await tx.batchDelete(entries);
4990
+ const result = await tx.commit();
4991
+ if (!result.success) {
4992
+ throw new Error(`Transaction failed: ${result.error || "Commit failed due to conflict"}`);
4993
+ }
4994
+ });
4995
+ }
4955
4996
  async batchInsert(entries) {
4956
4997
  return this.writeLock(1, async () => {
4957
4998
  const tx = await this.createTransaction();
@@ -5057,6 +5098,7 @@ var BPTreePureSync = class {
5057
5098
  };
5058
5099
  function flush() {
5059
5100
  for (const id of deleteBuffer) {
5101
+ writeBuffer.delete(id);
5060
5102
  strategy.delete(id);
5061
5103
  }
5062
5104
  for (const [id, node] of writeBuffer) {
@@ -5193,6 +5235,12 @@ var BPTreePureSync = class {
5193
5235
  deleteOp(ops, ctx, key, this.comparator, value);
5194
5236
  flush();
5195
5237
  }
5238
+ batchDelete(entries) {
5239
+ const { ops, flush } = this._createBufferedOps();
5240
+ const ctx = this._createCtx();
5241
+ batchDeleteOp(ops, ctx, entries, this.comparator);
5242
+ flush();
5243
+ }
5196
5244
  batchInsert(entries) {
5197
5245
  const { ops, flush } = this._createBufferedOps();
5198
5246
  const ctx = this._createCtx();
@@ -5309,6 +5357,7 @@ var BPTreePureAsync = class {
5309
5357
  };
5310
5358
  async function flush() {
5311
5359
  for (const id of deleteBuffer) {
5360
+ writeBuffer.delete(id);
5312
5361
  await strategy.delete(id);
5313
5362
  }
5314
5363
  for (const [id, node] of writeBuffer) {
@@ -5477,6 +5526,14 @@ var BPTreePureAsync = class {
5477
5526
  await flush();
5478
5527
  });
5479
5528
  }
5529
+ async batchDelete(entries) {
5530
+ return this.writeLock(async () => {
5531
+ const { ops, flush } = this._createBufferedOps();
5532
+ const ctx = await this._createCtx();
5533
+ await batchDeleteOpAsync(ops, ctx, entries, this.comparator);
5534
+ await flush();
5535
+ });
5536
+ }
5480
5537
  async bulkLoad(entries) {
5481
5538
  return this.writeLock(async () => {
5482
5539
  const { ops, flush } = this._createBufferedOps();
@@ -10812,6 +10869,82 @@ var RowTableEngine = class {
10812
10869
  await this.pfs.freeChain(pageId, tx);
10813
10870
  }
10814
10871
  }
10872
+ /**
10873
+ * Deletes multiple data in batch.
10874
+ * @param pks Array of PKs to delete
10875
+ * @param decrementRowCount Whether to decrement the row count to metadata
10876
+ * @param tx Transaction
10877
+ */
10878
+ async deleteBatch(pks, decrementRowCount, tx) {
10879
+ this.logger.debug(`Batch deleting ${pks.length} rows`);
10880
+ if (pks.length === 0) {
10881
+ return;
10882
+ }
10883
+ await tx.__acquireWriteLock(0);
10884
+ const collections = await this.collectItemsByPage(pks, tx);
10885
+ if (collections.size === 0) {
10886
+ return;
10887
+ }
10888
+ const metadataPage = await this.pfs.getMetadata(false, tx);
10889
+ const lastInsertPageId = this.metadataPageManager.getLastInsertPageId(metadataPage);
10890
+ const batchDeleteData = [];
10891
+ const pagesToFree = [];
10892
+ let deletedCount = 0;
10893
+ for (const [pageId, items] of collections) {
10894
+ const page = await this.pfs.get(pageId, true, tx);
10895
+ if (!this.factory.isDataPage(page)) {
10896
+ continue;
10897
+ }
10898
+ let pageModified = false;
10899
+ for (const item of items) {
10900
+ const row = this.dataPageManager.getRow(page, item.slotIndex);
10901
+ if (this.rowManager.getDeletedFlag(row)) {
10902
+ continue;
10903
+ }
10904
+ if (this.rowManager.getOverflowFlag(row)) {
10905
+ const overflowPageId = bytesToNumber(this.rowManager.getBody(row));
10906
+ await this.pfs.freeChain(overflowPageId, tx);
10907
+ }
10908
+ this.rowManager.setDeletedFlag(row, true);
10909
+ pageModified = true;
10910
+ this.setRID(pageId, item.slotIndex);
10911
+ batchDeleteData.push([this.getRID(), item.pk]);
10912
+ deletedCount++;
10913
+ }
10914
+ if (pageModified) {
10915
+ await this.pfs.setPage(pageId, page, tx);
10916
+ }
10917
+ if (pageId !== lastInsertPageId) {
10918
+ const insertedRowCount = this.dataPageManager.getInsertedRowCount(page);
10919
+ let allDeleted = true;
10920
+ let i = 0;
10921
+ while (i < insertedRowCount) {
10922
+ const slotRow = this.dataPageManager.getRow(page, i);
10923
+ if (!this.rowManager.getDeletedFlag(slotRow)) {
10924
+ allDeleted = false;
10925
+ break;
10926
+ }
10927
+ i++;
10928
+ }
10929
+ if (allDeleted) {
10930
+ pagesToFree.push(pageId);
10931
+ }
10932
+ }
10933
+ }
10934
+ if (batchDeleteData.length === 0) {
10935
+ return;
10936
+ }
10937
+ await this.bptree.batchDelete(batchDeleteData);
10938
+ if (decrementRowCount) {
10939
+ const freshMetadataPage = await this.pfs.getMetadata(true, tx);
10940
+ const currentRowCount = this.metadataPageManager.getRowCount(freshMetadataPage);
10941
+ this.metadataPageManager.setRowCount(freshMetadataPage, currentRowCount - deletedCount);
10942
+ await this.pfs.setMetadata(freshMetadataPage, tx);
10943
+ }
10944
+ for (const pageId of pagesToFree) {
10945
+ await this.pfs.freeChain(pageId, tx);
10946
+ }
10947
+ }
10815
10948
  /**
10816
10949
  * Looks up the RID corresponding to the PK in the B+ Tree and returns the actual row.
10817
10950
  * @param pk Primary key of the row
@@ -10953,11 +11086,6 @@ var RowTableEngine = class {
10953
11086
  }
10954
11087
  };
10955
11088
 
10956
- // src/utils/catchPromise.ts
10957
- async function catchPromise(promise) {
10958
- return promise.then((res) => [void 0, res]).catch((reason) => [reason]);
10959
- }
10960
-
10961
11089
  // src/core/transaction/LockManager.ts
10962
11090
  var LockManager = class {
10963
11091
  lock;
@@ -11493,41 +11621,41 @@ var DataplyAPI = class {
11493
11621
  const release = await this.acquireWriteLock();
11494
11622
  const internalTx = this.createTransaction();
11495
11623
  internalTx.__setWriteLockRelease(release);
11496
- const [error2, result2] = await catchPromise(this.txContext.run(internalTx, () => callback(internalTx)));
11497
- if (error2) {
11624
+ try {
11625
+ const result = await this.txContext.run(internalTx, () => callback(internalTx));
11626
+ await internalTx.commit();
11627
+ return result;
11628
+ } catch (error) {
11498
11629
  await internalTx.rollback();
11499
- throw error2;
11630
+ throw error;
11500
11631
  }
11501
- await internalTx.commit();
11502
- return result2;
11503
11632
  }
11504
11633
  if (!tx.__hasWriteLockRelease()) {
11505
11634
  const release = await this.acquireWriteLock();
11506
11635
  tx.__setWriteLockRelease(release);
11507
11636
  }
11508
- const [error, result] = await catchPromise(this.txContext.run(tx, () => callback(tx)));
11509
- if (error) {
11510
- throw error;
11637
+ if (this.txContext.get() === tx) {
11638
+ return callback(tx);
11511
11639
  }
11512
- return result;
11640
+ return this.txContext.run(tx, () => callback(tx));
11513
11641
  }
11514
11642
  async withReadTransaction(callback, tx) {
11515
11643
  this.logger.debug("Running with read transaction");
11516
- const isInternalTx = !tx;
11517
11644
  if (!tx) {
11518
- tx = this.createTransaction();
11519
- }
11520
- const [error, result] = await catchPromise(this.txContext.run(tx, () => callback(tx)));
11521
- if (error) {
11522
- if (isInternalTx) {
11523
- await tx.rollback();
11645
+ const internalTx = this.createTransaction();
11646
+ try {
11647
+ const result = await this.txContext.run(internalTx, () => callback(internalTx));
11648
+ await internalTx.commit();
11649
+ return result;
11650
+ } catch (error) {
11651
+ await internalTx.rollback();
11652
+ throw error;
11524
11653
  }
11525
- throw error;
11526
11654
  }
11527
- if (isInternalTx) {
11528
- await tx.commit();
11655
+ if (this.txContext.get() === tx) {
11656
+ return callback(tx);
11529
11657
  }
11530
- return result;
11658
+ return this.txContext.run(tx, () => callback(tx));
11531
11659
  }
11532
11660
  /**
11533
11661
  * Runs a generator callback function within a transaction context.
@@ -11671,6 +11799,23 @@ var DataplyAPI = class {
11671
11799
  await this.rowTableEngine.delete(pk, decrementRowCount, tx2);
11672
11800
  }, tx);
11673
11801
  }
11802
+ /**
11803
+ * Deletes multiple data in batch.
11804
+ * If a transaction is not provided, it internally creates a single transaction to process.
11805
+ * @param pks Array of PKs to delete
11806
+ * @param decrementRowCount Whether to decrement the row count to metadata
11807
+ * @param tx Transaction
11808
+ */
11809
+ async deleteBatch(pks, decrementRowCount, tx) {
11810
+ this.logger.debug(`Deleting batch data: ${pks.length} items`);
11811
+ if (!this.initialized) {
11812
+ throw new Error("Dataply instance is not initialized");
11813
+ }
11814
+ return this.withWriteTransaction(async (tx2) => {
11815
+ decrementRowCount = decrementRowCount ?? true;
11816
+ await this.rowTableEngine.deleteBatch(pks, decrementRowCount, tx2);
11817
+ }, tx);
11818
+ }
11674
11819
  async select(pk, asRaw = false, tx) {
11675
11820
  this.logger.debug(`Selecting data for PK: ${pk}`);
11676
11821
  if (!this.initialized) {
@@ -11796,6 +11941,15 @@ var Dataply = class {
11796
11941
  async delete(pk, tx) {
11797
11942
  return this.api.delete(pk, true, tx);
11798
11943
  }
11944
+ /**
11945
+ * Deletes multiple data in batch.
11946
+ * If a transaction is not provided, it internally creates a single transaction to process.
11947
+ * @param pks Array of PKs to delete
11948
+ * @param tx Transaction
11949
+ */
11950
+ async deleteBatch(pks, tx) {
11951
+ return this.api.deleteBatch(pks, true, tx);
11952
+ }
11799
11953
  async select(pk, asRaw = false, tx) {
11800
11954
  return this.api.select(pk, asRaw, tx);
11801
11955
  }
@@ -63,6 +63,13 @@ export declare class Dataply {
63
63
  * @param tx Transaction
64
64
  */
65
65
  delete(pk: number, tx?: Transaction): Promise<void>;
66
+ /**
67
+ * Deletes multiple data in batch.
68
+ * If a transaction is not provided, it internally creates a single transaction to process.
69
+ * @param pks Array of PKs to delete
70
+ * @param tx Transaction
71
+ */
72
+ deleteBatch(pks: number[], tx?: Transaction): Promise<void>;
66
73
  /**
67
74
  * Selects data.
68
75
  * @param pk PK of the data to select
@@ -162,6 +162,14 @@ export declare class DataplyAPI {
162
162
  * @param tx Transaction
163
163
  */
164
164
  delete(pk: number, decrementRowCount?: boolean, tx?: Transaction): Promise<void>;
165
+ /**
166
+ * Deletes multiple data in batch.
167
+ * If a transaction is not provided, it internally creates a single transaction to process.
168
+ * @param pks Array of PKs to delete
169
+ * @param decrementRowCount Whether to decrement the row count to metadata
170
+ * @param tx Transaction
171
+ */
172
+ deleteBatch(pks: number[], decrementRowCount?: boolean, tx?: Transaction): Promise<void>;
165
173
  /**
166
174
  * Selects data.
167
175
  * @param pk PK of the data to select
@@ -111,6 +111,13 @@ export declare class RowTableEngine {
111
111
  * @param tx Transaction
112
112
  */
113
113
  delete(pk: number, decrementRowCount: boolean, tx: Transaction): Promise<void>;
114
+ /**
115
+ * Deletes multiple data in batch.
116
+ * @param pks Array of PKs to delete
117
+ * @param decrementRowCount Whether to decrement the row count to metadata
118
+ * @param tx Transaction
119
+ */
120
+ deleteBatch(pks: number[], decrementRowCount: boolean, tx: Transaction): Promise<void>;
114
121
  /**
115
122
  * Looks up the RID corresponding to the PK in the B+ Tree and returns the actual row.
116
123
  * @param pk Primary key of the row
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dataply",
3
- "version": "0.0.26-alpha.13",
3
+ "version": "0.0.26-alpha.15",
4
4
  "description": "A lightweight storage engine for Node.js with support for MVCC, WAL.",
5
5
  "license": "MIT",
6
6
  "author": "izure <admin@izure.org>",
@@ -49,6 +49,6 @@
49
49
  "hookall": "^2.2.0",
50
50
  "mvcc-api": "^1.3.7",
51
51
  "ryoiki": "^1.2.0",
52
- "serializable-bptree": "^9.0.4-alpha.2"
52
+ "serializable-bptree": "^9.0.4-alpha.3"
53
53
  }
54
54
  }