@push.rocks/smartmongo 2.2.0 → 4.0.0

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.
Files changed (126) hide show
  1. package/dist_ts/00_commitinfo_data.js +1 -1
  2. package/dist_ts/index.d.ts +1 -1
  3. package/dist_ts/index.js +3 -3
  4. package/dist_ts/tsmdb/engine/AggregationEngine.js +189 -0
  5. package/dist_ts/{congodb → tsmdb}/engine/IndexEngine.d.ts +23 -3
  6. package/dist_ts/tsmdb/engine/IndexEngine.js +678 -0
  7. package/dist_ts/tsmdb/engine/QueryEngine.js +271 -0
  8. package/dist_ts/tsmdb/engine/QueryPlanner.d.ts +64 -0
  9. package/dist_ts/tsmdb/engine/QueryPlanner.js +308 -0
  10. package/dist_ts/tsmdb/engine/SessionEngine.d.ts +117 -0
  11. package/dist_ts/tsmdb/engine/SessionEngine.js +232 -0
  12. package/dist_ts/{congodb → tsmdb}/engine/TransactionEngine.d.ts +1 -1
  13. package/dist_ts/tsmdb/engine/TransactionEngine.js +287 -0
  14. package/dist_ts/tsmdb/engine/UpdateEngine.js +461 -0
  15. package/dist_ts/{congodb/errors/CongoErrors.d.ts → tsmdb/errors/TsmdbErrors.d.ts} +16 -16
  16. package/dist_ts/tsmdb/errors/TsmdbErrors.js +155 -0
  17. package/dist_ts/{congodb → tsmdb}/index.d.ts +11 -4
  18. package/dist_ts/tsmdb/index.js +31 -0
  19. package/dist_ts/tsmdb/server/CommandRouter.d.ts +87 -0
  20. package/dist_ts/tsmdb/server/CommandRouter.js +222 -0
  21. package/dist_ts/{congodb/server/CongoServer.d.ts → tsmdb/server/TsmdbServer.d.ts} +6 -6
  22. package/dist_ts/tsmdb/server/TsmdbServer.js +229 -0
  23. package/dist_ts/{congodb → tsmdb}/server/WireProtocol.d.ts +1 -1
  24. package/dist_ts/tsmdb/server/WireProtocol.js +298 -0
  25. package/dist_ts/{congodb → tsmdb}/server/handlers/AdminHandler.d.ts +1 -1
  26. package/dist_ts/tsmdb/server/handlers/AdminHandler.js +668 -0
  27. package/dist_ts/{congodb → tsmdb}/server/handlers/AggregateHandler.d.ts +1 -1
  28. package/dist_ts/tsmdb/server/handlers/AggregateHandler.js +277 -0
  29. package/dist_ts/{congodb → tsmdb}/server/handlers/DeleteHandler.d.ts +1 -1
  30. package/dist_ts/tsmdb/server/handlers/DeleteHandler.js +95 -0
  31. package/dist_ts/{congodb → tsmdb}/server/handlers/FindHandler.d.ts +1 -1
  32. package/dist_ts/tsmdb/server/handlers/FindHandler.js +291 -0
  33. package/dist_ts/{congodb → tsmdb}/server/handlers/HelloHandler.d.ts +1 -1
  34. package/dist_ts/{congodb → tsmdb}/server/handlers/HelloHandler.js +2 -2
  35. package/dist_ts/{congodb → tsmdb}/server/handlers/IndexHandler.d.ts +1 -1
  36. package/dist_ts/tsmdb/server/handlers/IndexHandler.js +183 -0
  37. package/dist_ts/{congodb → tsmdb}/server/handlers/InsertHandler.d.ts +1 -1
  38. package/dist_ts/tsmdb/server/handlers/InsertHandler.js +79 -0
  39. package/dist_ts/{congodb → tsmdb}/server/handlers/UpdateHandler.d.ts +1 -1
  40. package/dist_ts/tsmdb/server/handlers/UpdateHandler.js +296 -0
  41. package/dist_ts/tsmdb/server/handlers/index.js +10 -0
  42. package/dist_ts/{congodb → tsmdb}/server/index.d.ts +2 -2
  43. package/dist_ts/tsmdb/server/index.js +7 -0
  44. package/dist_ts/{congodb → tsmdb}/storage/FileStorageAdapter.d.ts +27 -3
  45. package/dist_ts/tsmdb/storage/FileStorageAdapter.js +465 -0
  46. package/dist_ts/{congodb → tsmdb}/storage/IStorageAdapter.d.ts +7 -2
  47. package/dist_ts/{congodb → tsmdb}/storage/IStorageAdapter.js +1 -1
  48. package/dist_ts/{congodb → tsmdb}/storage/MemoryStorageAdapter.d.ts +3 -2
  49. package/dist_ts/tsmdb/storage/MemoryStorageAdapter.js +378 -0
  50. package/dist_ts/{congodb → tsmdb}/storage/OpLog.d.ts +1 -1
  51. package/dist_ts/tsmdb/storage/OpLog.js +221 -0
  52. package/dist_ts/tsmdb/storage/WAL.d.ts +117 -0
  53. package/dist_ts/tsmdb/storage/WAL.js +286 -0
  54. package/dist_ts/tsmdb/tsmdb.plugins.js +14 -0
  55. package/dist_ts/{congodb → tsmdb}/types/interfaces.d.ts +3 -3
  56. package/dist_ts/{congodb → tsmdb}/types/interfaces.js +1 -1
  57. package/dist_ts/tsmdb/utils/checksum.d.ts +30 -0
  58. package/dist_ts/tsmdb/utils/checksum.js +77 -0
  59. package/dist_ts/tsmdb/utils/index.d.ts +1 -0
  60. package/dist_ts/tsmdb/utils/index.js +2 -0
  61. package/package.json +1 -1
  62. package/readme.hints.md +7 -12
  63. package/readme.md +25 -25
  64. package/ts/00_commitinfo_data.ts +1 -1
  65. package/ts/index.ts +2 -2
  66. package/ts/{congodb → tsmdb}/engine/AggregationEngine.ts +1 -1
  67. package/ts/tsmdb/engine/IndexEngine.ts +798 -0
  68. package/ts/{congodb → tsmdb}/engine/QueryEngine.ts +1 -1
  69. package/ts/tsmdb/engine/QueryPlanner.ts +393 -0
  70. package/ts/tsmdb/engine/SessionEngine.ts +292 -0
  71. package/ts/{congodb → tsmdb}/engine/TransactionEngine.ts +12 -12
  72. package/ts/{congodb → tsmdb}/engine/UpdateEngine.ts +1 -1
  73. package/ts/{congodb/errors/CongoErrors.ts → tsmdb/errors/TsmdbErrors.ts} +34 -34
  74. package/ts/{congodb → tsmdb}/index.ts +16 -7
  75. package/ts/{congodb → tsmdb}/server/CommandRouter.ts +114 -5
  76. package/ts/{congodb/server/CongoServer.ts → tsmdb/server/TsmdbServer.ts} +11 -8
  77. package/ts/{congodb → tsmdb}/server/WireProtocol.ts +1 -1
  78. package/ts/{congodb → tsmdb}/server/handlers/AdminHandler.ts +116 -11
  79. package/ts/{congodb → tsmdb}/server/handlers/AggregateHandler.ts +1 -1
  80. package/ts/{congodb → tsmdb}/server/handlers/DeleteHandler.ts +18 -3
  81. package/ts/{congodb → tsmdb}/server/handlers/FindHandler.ts +43 -14
  82. package/ts/{congodb → tsmdb}/server/handlers/HelloHandler.ts +1 -1
  83. package/ts/{congodb → tsmdb}/server/handlers/IndexHandler.ts +1 -1
  84. package/ts/{congodb → tsmdb}/server/handlers/InsertHandler.ts +7 -1
  85. package/ts/{congodb → tsmdb}/server/handlers/UpdateHandler.ts +34 -5
  86. package/ts/{congodb → tsmdb}/server/index.ts +2 -2
  87. package/ts/{congodb → tsmdb}/storage/FileStorageAdapter.ts +90 -7
  88. package/ts/{congodb → tsmdb}/storage/IStorageAdapter.ts +8 -2
  89. package/ts/{congodb → tsmdb}/storage/MemoryStorageAdapter.ts +14 -2
  90. package/ts/{congodb → tsmdb}/storage/OpLog.ts +1 -1
  91. package/ts/tsmdb/storage/WAL.ts +375 -0
  92. package/ts/{congodb → tsmdb}/types/interfaces.ts +3 -3
  93. package/ts/tsmdb/utils/checksum.ts +88 -0
  94. package/ts/tsmdb/utils/index.ts +1 -0
  95. package/dist_ts/congodb/congodb.plugins.js +0 -14
  96. package/dist_ts/congodb/engine/AggregationEngine.js +0 -189
  97. package/dist_ts/congodb/engine/IndexEngine.js +0 -376
  98. package/dist_ts/congodb/engine/QueryEngine.js +0 -271
  99. package/dist_ts/congodb/engine/TransactionEngine.js +0 -287
  100. package/dist_ts/congodb/engine/UpdateEngine.js +0 -461
  101. package/dist_ts/congodb/errors/CongoErrors.js +0 -155
  102. package/dist_ts/congodb/index.js +0 -26
  103. package/dist_ts/congodb/server/CommandRouter.d.ts +0 -51
  104. package/dist_ts/congodb/server/CommandRouter.js +0 -132
  105. package/dist_ts/congodb/server/CongoServer.js +0 -227
  106. package/dist_ts/congodb/server/WireProtocol.js +0 -298
  107. package/dist_ts/congodb/server/handlers/AdminHandler.js +0 -568
  108. package/dist_ts/congodb/server/handlers/AggregateHandler.js +0 -277
  109. package/dist_ts/congodb/server/handlers/DeleteHandler.js +0 -83
  110. package/dist_ts/congodb/server/handlers/FindHandler.js +0 -261
  111. package/dist_ts/congodb/server/handlers/IndexHandler.js +0 -183
  112. package/dist_ts/congodb/server/handlers/InsertHandler.js +0 -76
  113. package/dist_ts/congodb/server/handlers/UpdateHandler.js +0 -270
  114. package/dist_ts/congodb/server/handlers/index.js +0 -10
  115. package/dist_ts/congodb/server/index.js +0 -7
  116. package/dist_ts/congodb/storage/FileStorageAdapter.js +0 -396
  117. package/dist_ts/congodb/storage/MemoryStorageAdapter.js +0 -367
  118. package/dist_ts/congodb/storage/OpLog.js +0 -221
  119. package/ts/congodb/engine/IndexEngine.ts +0 -479
  120. /package/dist_ts/{congodb → tsmdb}/engine/AggregationEngine.d.ts +0 -0
  121. /package/dist_ts/{congodb → tsmdb}/engine/QueryEngine.d.ts +0 -0
  122. /package/dist_ts/{congodb → tsmdb}/engine/UpdateEngine.d.ts +0 -0
  123. /package/dist_ts/{congodb → tsmdb}/server/handlers/index.d.ts +0 -0
  124. /package/dist_ts/{congodb/congodb.plugins.d.ts → tsmdb/tsmdb.plugins.d.ts} +0 -0
  125. /package/ts/{congodb → tsmdb}/server/handlers/index.ts +0 -0
  126. /package/ts/{congodb/congodb.plugins.ts → tsmdb/tsmdb.plugins.ts} +0 -0
@@ -1,5 +1,6 @@
1
- import * as plugins from '../../congodb.plugins.js';
1
+ import * as plugins from '../../tsmdb.plugins.js';
2
2
  import type { ICommandHandler, IHandlerContext } from '../CommandRouter.js';
3
+ import { SessionEngine } from '../../engine/SessionEngine.js';
3
4
 
4
5
  /**
5
6
  * AdminHandler - Handles administrative commands
@@ -237,16 +238,18 @@ export class AdminHandler implements ICommandHandler {
237
238
  * Handle serverStatus command
238
239
  */
239
240
  private async handleServerStatus(context: IHandlerContext): Promise<plugins.bson.Document> {
240
- const { server } = context;
241
+ const { server, sessionEngine } = context;
241
242
 
242
243
  const uptime = server.getUptime();
243
244
  const connections = server.getConnectionCount();
245
+ const sessions = sessionEngine.listSessions();
246
+ const sessionsWithTxn = sessionEngine.getSessionsWithTransactions();
244
247
 
245
248
  return {
246
249
  ok: 1,
247
250
  host: `${server.host}:${server.port}`,
248
251
  version: '7.0.0',
249
- process: 'congodb',
252
+ process: 'tsmdb',
250
253
  pid: process.pid,
251
254
  uptime,
252
255
  uptimeMillis: uptime * 1000,
@@ -263,13 +266,33 @@ export class AdminHandler implements ICommandHandler {
263
266
  totalCreated: connections,
264
267
  active: connections,
265
268
  },
269
+ logicalSessionRecordCache: {
270
+ activeSessionsCount: sessions.length,
271
+ sessionsCollectionJobCount: 0,
272
+ lastSessionsCollectionJobDurationMillis: 0,
273
+ lastSessionsCollectionJobTimestamp: new Date(),
274
+ transactionReaperJobCount: 0,
275
+ lastTransactionReaperJobDurationMillis: 0,
276
+ lastTransactionReaperJobTimestamp: new Date(),
277
+ },
278
+ transactions: {
279
+ retriedCommandsCount: 0,
280
+ retriedStatementsCount: 0,
281
+ transactionsCollectionWriteCount: 0,
282
+ currentActive: sessionsWithTxn.length,
283
+ currentInactive: 0,
284
+ currentOpen: sessionsWithTxn.length,
285
+ totalStarted: sessionsWithTxn.length,
286
+ totalCommitted: 0,
287
+ totalAborted: 0,
288
+ },
266
289
  network: {
267
290
  bytesIn: 0,
268
291
  bytesOut: 0,
269
292
  numRequests: 0,
270
293
  },
271
294
  storageEngine: {
272
- name: 'congodb',
295
+ name: 'tsmdb',
273
296
  supportsCommittedReads: true,
274
297
  persistent: false,
275
298
  },
@@ -283,7 +306,7 @@ export class AdminHandler implements ICommandHandler {
283
306
  return {
284
307
  ok: 1,
285
308
  version: '7.0.0',
286
- gitVersion: 'congodb',
309
+ gitVersion: 'tsmdb',
287
310
  modules: [],
288
311
  allocator: 'system',
289
312
  javascriptEngine: 'none',
@@ -294,7 +317,7 @@ export class AdminHandler implements ICommandHandler {
294
317
  compiled: 'disabled',
295
318
  },
296
319
  buildEnvironment: {
297
- distmod: 'congodb',
320
+ distmod: 'tsmdb',
298
321
  distarch: process.arch,
299
322
  cc: '',
300
323
  ccflags: '',
@@ -307,7 +330,7 @@ export class AdminHandler implements ICommandHandler {
307
330
  bits: 64,
308
331
  debug: false,
309
332
  maxBsonObjectSize: 16777216,
310
- storageEngines: ['congodb'],
333
+ storageEngines: ['tsmdb'],
311
334
  };
312
335
  }
313
336
 
@@ -409,6 +432,17 @@ export class AdminHandler implements ICommandHandler {
409
432
  * Handle endSessions command
410
433
  */
411
434
  private async handleEndSessions(context: IHandlerContext): Promise<plugins.bson.Document> {
435
+ const { command, sessionEngine } = context;
436
+
437
+ // End each session in the array
438
+ const sessions = command.endSessions || [];
439
+ for (const sessionSpec of sessions) {
440
+ const sessionId = SessionEngine.extractSessionId(sessionSpec);
441
+ if (sessionId) {
442
+ await sessionEngine.endSession(sessionId);
443
+ }
444
+ }
445
+
412
446
  return { ok: 1 };
413
447
  }
414
448
 
@@ -416,16 +450,87 @@ export class AdminHandler implements ICommandHandler {
416
450
  * Handle abortTransaction command
417
451
  */
418
452
  private async handleAbortTransaction(context: IHandlerContext): Promise<plugins.bson.Document> {
419
- // Transactions are not fully supported, but acknowledge the command
420
- return { ok: 1 };
453
+ const { transactionEngine, sessionEngine, txnId, sessionId } = context;
454
+
455
+ if (!txnId) {
456
+ return {
457
+ ok: 0,
458
+ errmsg: 'No transaction started',
459
+ code: 251,
460
+ codeName: 'NoSuchTransaction',
461
+ };
462
+ }
463
+
464
+ try {
465
+ await transactionEngine.abortTransaction(txnId);
466
+ transactionEngine.endTransaction(txnId);
467
+ // Update session state
468
+ if (sessionId) {
469
+ sessionEngine.endTransaction(sessionId);
470
+ }
471
+ return { ok: 1 };
472
+ } catch (error: any) {
473
+ return {
474
+ ok: 0,
475
+ errmsg: error.message || 'Abort transaction failed',
476
+ code: error.code || 1,
477
+ codeName: error.codeName || 'UnknownError',
478
+ };
479
+ }
421
480
  }
422
481
 
423
482
  /**
424
483
  * Handle commitTransaction command
425
484
  */
426
485
  private async handleCommitTransaction(context: IHandlerContext): Promise<plugins.bson.Document> {
427
- // Transactions are not fully supported, but acknowledge the command
428
- return { ok: 1 };
486
+ const { transactionEngine, sessionEngine, txnId, sessionId } = context;
487
+
488
+ if (!txnId) {
489
+ return {
490
+ ok: 0,
491
+ errmsg: 'No transaction started',
492
+ code: 251,
493
+ codeName: 'NoSuchTransaction',
494
+ };
495
+ }
496
+
497
+ try {
498
+ await transactionEngine.commitTransaction(txnId);
499
+ transactionEngine.endTransaction(txnId);
500
+ // Update session state
501
+ if (sessionId) {
502
+ sessionEngine.endTransaction(sessionId);
503
+ }
504
+ return { ok: 1 };
505
+ } catch (error: any) {
506
+ // If commit fails, transaction should be aborted
507
+ try {
508
+ await transactionEngine.abortTransaction(txnId);
509
+ transactionEngine.endTransaction(txnId);
510
+ if (sessionId) {
511
+ sessionEngine.endTransaction(sessionId);
512
+ }
513
+ } catch {
514
+ // Ignore abort errors
515
+ }
516
+
517
+ if (error.code === 112) {
518
+ // Write conflict
519
+ return {
520
+ ok: 0,
521
+ errmsg: error.message || 'Write conflict during commit',
522
+ code: 112,
523
+ codeName: 'WriteConflict',
524
+ };
525
+ }
526
+
527
+ return {
528
+ ok: 0,
529
+ errmsg: error.message || 'Commit transaction failed',
530
+ code: error.code || 1,
531
+ codeName: error.codeName || 'UnknownError',
532
+ };
533
+ }
429
534
  }
430
535
 
431
536
  /**
@@ -1,4 +1,4 @@
1
- import * as plugins from '../../congodb.plugins.js';
1
+ import * as plugins from '../../tsmdb.plugins.js';
2
2
  import type { ICommandHandler, IHandlerContext, ICursorState } from '../CommandRouter.js';
3
3
  import { AggregationEngine } from '../../engine/AggregationEngine.js';
4
4
 
@@ -1,5 +1,6 @@
1
- import * as plugins from '../../congodb.plugins.js';
1
+ import * as plugins from '../../tsmdb.plugins.js';
2
2
  import type { ICommandHandler, IHandlerContext } from '../CommandRouter.js';
3
+ import type { IStoredDocument } from '../../types/interfaces.js';
3
4
  import { QueryEngine } from '../../engine/QueryEngine.js';
4
5
 
5
6
  /**
@@ -47,6 +48,8 @@ export class DeleteHandler implements ICommandHandler {
47
48
  return { ok: 1, n: 0 };
48
49
  }
49
50
 
51
+ const indexEngine = context.getIndexEngine(collection);
52
+
50
53
  for (let i = 0; i < deletes.length; i++) {
51
54
  const deleteSpec = deletes[i];
52
55
  const filter = deleteSpec.q || deleteSpec.filter || {};
@@ -56,8 +59,15 @@ export class DeleteHandler implements ICommandHandler {
56
59
  const deleteAll = limit === 0;
57
60
 
58
61
  try {
59
- // Get all documents
60
- const documents = await storage.findAll(database, collection);
62
+ // Try to use index-accelerated query
63
+ const candidateIds = await indexEngine.findCandidateIds(filter);
64
+
65
+ let documents: IStoredDocument[];
66
+ if (candidateIds !== null) {
67
+ documents = await storage.findByIds(database, collection, candidateIds);
68
+ } else {
69
+ documents = await storage.findAll(database, collection);
70
+ }
61
71
 
62
72
  // Apply filter
63
73
  const matchingDocs = QueryEngine.filter(documents, filter);
@@ -69,6 +79,11 @@ export class DeleteHandler implements ICommandHandler {
69
79
  // Determine which documents to delete
70
80
  const docsToDelete = deleteAll ? matchingDocs : matchingDocs.slice(0, 1);
71
81
 
82
+ // Update indexes for deleted documents
83
+ for (const doc of docsToDelete) {
84
+ await indexEngine.onDelete(doc as any);
85
+ }
86
+
72
87
  // Delete the documents
73
88
  const idsToDelete = docsToDelete.map(doc => doc._id);
74
89
  const deleted = await storage.deleteByIds(database, collection, idsToDelete);
@@ -1,5 +1,6 @@
1
- import * as plugins from '../../congodb.plugins.js';
1
+ import * as plugins from '../../tsmdb.plugins.js';
2
2
  import type { ICommandHandler, IHandlerContext, ICursorState } from '../CommandRouter.js';
3
+ import type { IStoredDocument } from '../../types/interfaces.js';
3
4
  import { QueryEngine } from '../../engine/QueryEngine.js';
4
5
 
5
6
  /**
@@ -45,7 +46,7 @@ export class FindHandler implements ICommandHandler {
45
46
  * Handle find command
46
47
  */
47
48
  private async handleFind(context: IHandlerContext): Promise<plugins.bson.Document> {
48
- const { storage, database, command } = context;
49
+ const { storage, database, command, getIndexEngine } = context;
49
50
 
50
51
  const collection = command.find;
51
52
  const filter = command.filter || {};
@@ -70,11 +71,22 @@ export class FindHandler implements ICommandHandler {
70
71
  };
71
72
  }
72
73
 
73
- // Get all documents
74
- let documents = await storage.findAll(database, collection);
74
+ // Try to use index-accelerated query
75
+ const indexEngine = getIndexEngine(collection);
76
+ const candidateIds = await indexEngine.findCandidateIds(filter);
75
77
 
76
- // Apply filter
77
- documents = QueryEngine.filter(documents, filter);
78
+ let documents: IStoredDocument[];
79
+ if (candidateIds !== null) {
80
+ // Index hit - fetch only candidate documents
81
+ documents = await storage.findByIds(database, collection, candidateIds);
82
+ // Still apply filter for any conditions the index couldn't fully satisfy
83
+ documents = QueryEngine.filter(documents, filter);
84
+ } else {
85
+ // No suitable index - full collection scan
86
+ documents = await storage.findAll(database, collection);
87
+ // Apply filter
88
+ documents = QueryEngine.filter(documents, filter);
89
+ }
78
90
 
79
91
  // Apply sort
80
92
  if (sort) {
@@ -233,7 +245,7 @@ export class FindHandler implements ICommandHandler {
233
245
  * Handle count command
234
246
  */
235
247
  private async handleCount(context: IHandlerContext): Promise<plugins.bson.Document> {
236
- const { storage, database, command } = context;
248
+ const { storage, database, command, getIndexEngine } = context;
237
249
 
238
250
  const collection = command.count;
239
251
  const query = command.query || {};
@@ -246,11 +258,20 @@ export class FindHandler implements ICommandHandler {
246
258
  return { ok: 1, n: 0 };
247
259
  }
248
260
 
249
- // Get all documents
250
- let documents = await storage.findAll(database, collection);
261
+ // Try to use index-accelerated query
262
+ const indexEngine = getIndexEngine(collection);
263
+ const candidateIds = await indexEngine.findCandidateIds(query);
251
264
 
252
- // Apply filter
253
- documents = QueryEngine.filter(documents, query);
265
+ let documents: IStoredDocument[];
266
+ if (candidateIds !== null) {
267
+ // Index hit - fetch only candidate documents
268
+ documents = await storage.findByIds(database, collection, candidateIds);
269
+ documents = QueryEngine.filter(documents, query);
270
+ } else {
271
+ // No suitable index - full collection scan
272
+ documents = await storage.findAll(database, collection);
273
+ documents = QueryEngine.filter(documents, query);
274
+ }
254
275
 
255
276
  // Apply skip
256
277
  if (skip > 0) {
@@ -269,7 +290,7 @@ export class FindHandler implements ICommandHandler {
269
290
  * Handle distinct command
270
291
  */
271
292
  private async handleDistinct(context: IHandlerContext): Promise<plugins.bson.Document> {
272
- const { storage, database, command } = context;
293
+ const { storage, database, command, getIndexEngine } = context;
273
294
 
274
295
  const collection = command.distinct;
275
296
  const key = command.key;
@@ -290,8 +311,16 @@ export class FindHandler implements ICommandHandler {
290
311
  return { ok: 1, values: [] };
291
312
  }
292
313
 
293
- // Get all documents
294
- const documents = await storage.findAll(database, collection);
314
+ // Try to use index-accelerated query
315
+ const indexEngine = getIndexEngine(collection);
316
+ const candidateIds = await indexEngine.findCandidateIds(query);
317
+
318
+ let documents: IStoredDocument[];
319
+ if (candidateIds !== null) {
320
+ documents = await storage.findByIds(database, collection, candidateIds);
321
+ } else {
322
+ documents = await storage.findAll(database, collection);
323
+ }
295
324
 
296
325
  // Get distinct values
297
326
  const values = QueryEngine.distinct(documents, key, query);
@@ -1,4 +1,4 @@
1
- import * as plugins from '../../congodb.plugins.js';
1
+ import * as plugins from '../../tsmdb.plugins.js';
2
2
  import type { ICommandHandler, IHandlerContext } from '../CommandRouter.js';
3
3
 
4
4
  /**
@@ -1,4 +1,4 @@
1
- import * as plugins from '../../congodb.plugins.js';
1
+ import * as plugins from '../../tsmdb.plugins.js';
2
2
  import type { ICommandHandler, IHandlerContext } from '../CommandRouter.js';
3
3
  import { IndexEngine } from '../../engine/IndexEngine.js';
4
4
 
@@ -1,5 +1,6 @@
1
- import * as plugins from '../../congodb.plugins.js';
1
+ import * as plugins from '../../tsmdb.plugins.js';
2
2
  import type { ICommandHandler, IHandlerContext } from '../CommandRouter.js';
3
+ import type { IStoredDocument } from '../../types/interfaces.js';
3
4
 
4
5
  /**
5
6
  * InsertHandler - Handles insert commands
@@ -42,6 +43,8 @@ export class InsertHandler implements ICommandHandler {
42
43
  // Ensure collection exists
43
44
  await storage.createCollection(database, collection);
44
45
 
46
+ const indexEngine = context.getIndexEngine(collection);
47
+
45
48
  // Insert documents
46
49
  for (let i = 0; i < documents.length; i++) {
47
50
  const doc = documents[i];
@@ -52,6 +55,9 @@ export class InsertHandler implements ICommandHandler {
52
55
  doc._id = new plugins.bson.ObjectId();
53
56
  }
54
57
 
58
+ // Check index constraints before insert (doc now has _id)
59
+ await indexEngine.onInsert(doc as IStoredDocument);
60
+
55
61
  await storage.insertOne(database, collection, doc);
56
62
  insertedCount++;
57
63
  } catch (error: any) {
@@ -1,5 +1,6 @@
1
- import * as plugins from '../../congodb.plugins.js';
1
+ import * as plugins from '../../tsmdb.plugins.js';
2
2
  import type { ICommandHandler, IHandlerContext } from '../CommandRouter.js';
3
+ import type { IStoredDocument } from '../../types/interfaces.js';
3
4
  import { QueryEngine } from '../../engine/QueryEngine.js';
4
5
  import { UpdateEngine } from '../../engine/UpdateEngine.js';
5
6
 
@@ -69,6 +70,8 @@ export class UpdateHandler implements ICommandHandler {
69
70
  // Ensure collection exists
70
71
  await storage.createCollection(database, collection);
71
72
 
73
+ const indexEngine = context.getIndexEngine(collection);
74
+
72
75
  for (let i = 0; i < updates.length; i++) {
73
76
  const updateSpec = updates[i];
74
77
  const filter = updateSpec.q || updateSpec.filter || {};
@@ -78,8 +81,15 @@ export class UpdateHandler implements ICommandHandler {
78
81
  const arrayFilters = updateSpec.arrayFilters;
79
82
 
80
83
  try {
81
- // Get all documents
82
- let documents = await storage.findAll(database, collection);
84
+ // Try to use index-accelerated query
85
+ const candidateIds = await indexEngine.findCandidateIds(filter);
86
+
87
+ let documents: IStoredDocument[];
88
+ if (candidateIds !== null) {
89
+ documents = await storage.findByIds(database, collection, candidateIds);
90
+ } else {
91
+ documents = await storage.findAll(database, collection);
92
+ }
83
93
 
84
94
  // Apply filter
85
95
  let matchingDocs = QueryEngine.filter(documents, filter);
@@ -99,6 +109,8 @@ export class UpdateHandler implements ICommandHandler {
99
109
  Object.assign(updatedDoc, update.$setOnInsert);
100
110
  }
101
111
 
112
+ // Update index for the new document
113
+ await indexEngine.onInsert(updatedDoc);
102
114
  await storage.insertOne(database, collection, updatedDoc);
103
115
  totalUpserted++;
104
116
  upserted.push({ index: i, _id: updatedDoc._id });
@@ -113,6 +125,8 @@ export class UpdateHandler implements ICommandHandler {
113
125
  // Check if document actually changed
114
126
  const changed = JSON.stringify(doc) !== JSON.stringify(updatedDoc);
115
127
  if (changed) {
128
+ // Update index
129
+ await indexEngine.onUpdate(doc as any, updatedDoc);
116
130
  await storage.updateById(database, collection, doc._id, updatedDoc);
117
131
  totalModified++;
118
132
  }
@@ -186,8 +200,17 @@ export class UpdateHandler implements ICommandHandler {
186
200
  // Ensure collection exists
187
201
  await storage.createCollection(database, collection);
188
202
 
189
- // Get matching documents
190
- let documents = await storage.findAll(database, collection);
203
+ // Try to use index-accelerated query
204
+ const indexEngine = context.getIndexEngine(collection);
205
+ const candidateIds = await indexEngine.findCandidateIds(query);
206
+
207
+ let documents: IStoredDocument[];
208
+ if (candidateIds !== null) {
209
+ documents = await storage.findByIds(database, collection, candidateIds);
210
+ } else {
211
+ documents = await storage.findAll(database, collection);
212
+ }
213
+
191
214
  let matchingDocs = QueryEngine.filter(documents, query);
192
215
 
193
216
  // Apply sort if specified
@@ -203,6 +226,8 @@ export class UpdateHandler implements ICommandHandler {
203
226
  return { ok: 1, value: null };
204
227
  }
205
228
 
229
+ // Update index for delete
230
+ await indexEngine.onDelete(doc as any);
206
231
  await storage.deleteById(database, collection, doc._id);
207
232
 
208
233
  let result = doc;
@@ -231,6 +256,8 @@ export class UpdateHandler implements ICommandHandler {
231
256
  // Update existing
232
257
  originalDoc = { ...doc };
233
258
  resultDoc = UpdateEngine.applyUpdate(doc, update, arrayFilters);
259
+ // Update index
260
+ await indexEngine.onUpdate(doc as any, resultDoc as any);
234
261
  await storage.updateById(database, collection, doc._id, resultDoc as any);
235
262
  } else {
236
263
  // Upsert
@@ -243,6 +270,8 @@ export class UpdateHandler implements ICommandHandler {
243
270
  Object.assign(resultDoc, update.$setOnInsert);
244
271
  }
245
272
 
273
+ // Update index for insert
274
+ await indexEngine.onInsert(resultDoc as any);
246
275
  await storage.insertOne(database, collection, resultDoc);
247
276
  }
248
277
 
@@ -1,7 +1,7 @@
1
1
  // Server module exports
2
2
 
3
- export { CongoServer } from './CongoServer.js';
4
- export type { ICongoServerOptions } from './CongoServer.js';
3
+ export { TsmdbServer } from './TsmdbServer.js';
4
+ export type { ITsmdbServerOptions } from './TsmdbServer.js';
5
5
  export { WireProtocol } from './WireProtocol.js';
6
6
  export { CommandRouter } from './CommandRouter.js';
7
7
  export type { ICommandHandler, IHandlerContext, ICursorState } from './CommandRouter.js';
@@ -1,9 +1,20 @@
1
- import * as plugins from '../congodb.plugins.js';
1
+ import * as plugins from '../tsmdb.plugins.js';
2
2
  import type { IStorageAdapter } from './IStorageAdapter.js';
3
3
  import type { IStoredDocument, IOpLogEntry, Document } from '../types/interfaces.js';
4
+ import { calculateDocumentChecksum, verifyChecksum } from '../utils/checksum.js';
4
5
 
5
6
  /**
6
- * File-based storage adapter for CongoDB
7
+ * File storage adapter options
8
+ */
9
+ export interface IFileStorageAdapterOptions {
10
+ /** Enable checksum verification for data integrity */
11
+ enableChecksums?: boolean;
12
+ /** Throw error on checksum mismatch (default: false, just log warning) */
13
+ strictChecksums?: boolean;
14
+ }
15
+
16
+ /**
17
+ * File-based storage adapter for TsmDB
7
18
  * Stores data in JSON files on disk for persistence
8
19
  */
9
20
  export class FileStorageAdapter implements IStorageAdapter {
@@ -11,9 +22,13 @@ export class FileStorageAdapter implements IStorageAdapter {
11
22
  private opLogCounter = 0;
12
23
  private initialized = false;
13
24
  private fs = new plugins.smartfs.SmartFs(new plugins.smartfs.SmartFsProviderNode());
25
+ private enableChecksums: boolean;
26
+ private strictChecksums: boolean;
14
27
 
15
- constructor(basePath: string) {
28
+ constructor(basePath: string, options?: IFileStorageAdapterOptions) {
16
29
  this.basePath = basePath;
30
+ this.enableChecksums = options?.enableChecksums ?? false;
31
+ this.strictChecksums = options?.strictChecksums ?? false;
17
32
  }
18
33
 
19
34
  // ============================================================================
@@ -68,6 +83,45 @@ export class FileStorageAdapter implements IStorageAdapter {
68
83
  return doc;
69
84
  }
70
85
 
86
+ /**
87
+ * Verify document checksum and handle errors
88
+ */
89
+ private verifyDocumentChecksum(doc: any): boolean {
90
+ if (!this.enableChecksums || !doc._checksum) {
91
+ return true;
92
+ }
93
+
94
+ const isValid = verifyChecksum(doc);
95
+ if (!isValid) {
96
+ const errorMsg = `Checksum mismatch for document ${doc._id}`;
97
+ if (this.strictChecksums) {
98
+ throw new Error(errorMsg);
99
+ } else {
100
+ console.warn(`WARNING: ${errorMsg}`);
101
+ }
102
+ }
103
+ return isValid;
104
+ }
105
+
106
+ /**
107
+ * Add checksum to document before storing
108
+ */
109
+ private prepareDocumentForStorage(doc: any): any {
110
+ if (!this.enableChecksums) {
111
+ return doc;
112
+ }
113
+ const checksum = calculateDocumentChecksum(doc);
114
+ return { ...doc, _checksum: checksum };
115
+ }
116
+
117
+ /**
118
+ * Remove internal checksum field before returning to user
119
+ */
120
+ private cleanDocumentForReturn(doc: any): IStoredDocument {
121
+ const { _checksum, ...cleanDoc } = doc;
122
+ return this.restoreObjectIds(cleanDoc);
123
+ }
124
+
71
125
  // ============================================================================
72
126
  // Initialization
73
127
  // ============================================================================
@@ -233,7 +287,9 @@ export class FileStorageAdapter implements IStorageAdapter {
233
287
  throw new Error(`Duplicate key error: _id ${idStr}`);
234
288
  }
235
289
 
236
- docs.push(storedDoc);
290
+ // Add checksum if enabled
291
+ const docToStore = this.prepareDocumentForStorage(storedDoc);
292
+ docs.push(docToStore);
237
293
  await this.writeJsonFile(collPath, docs);
238
294
  return storedDoc;
239
295
  }
@@ -258,7 +314,9 @@ export class FileStorageAdapter implements IStorageAdapter {
258
314
  }
259
315
 
260
316
  existingIds.add(idStr);
261
- docs.push(storedDoc);
317
+ // Add checksum if enabled
318
+ const docToStore = this.prepareDocumentForStorage(storedDoc);
319
+ docs.push(docToStore);
262
320
  results.push(storedDoc);
263
321
  }
264
322
 
@@ -270,10 +328,33 @@ export class FileStorageAdapter implements IStorageAdapter {
270
328
  await this.createCollection(dbName, collName);
271
329
  const collPath = this.getCollectionPath(dbName, collName);
272
330
  const docs = await this.readJsonFile<any[]>(collPath, []);
273
- return docs.map(doc => this.restoreObjectIds(doc));
331
+ return docs.map(doc => {
332
+ // Verify checksum if enabled
333
+ this.verifyDocumentChecksum(doc);
334
+ // Clean and return document without internal checksum field
335
+ return this.cleanDocumentForReturn(doc);
336
+ });
337
+ }
338
+
339
+ async findByIds(dbName: string, collName: string, ids: Set<string>): Promise<IStoredDocument[]> {
340
+ await this.createCollection(dbName, collName);
341
+ const collPath = this.getCollectionPath(dbName, collName);
342
+ const docs = await this.readJsonFile<any[]>(collPath, []);
343
+ const results: IStoredDocument[] = [];
344
+ for (const doc of docs) {
345
+ // Verify checksum if enabled
346
+ this.verifyDocumentChecksum(doc);
347
+ // Clean and restore document
348
+ const cleaned = this.cleanDocumentForReturn(doc);
349
+ if (ids.has(cleaned._id.toHexString())) {
350
+ results.push(cleaned);
351
+ }
352
+ }
353
+ return results;
274
354
  }
275
355
 
276
356
  async findById(dbName: string, collName: string, id: plugins.bson.ObjectId): Promise<IStoredDocument | null> {
357
+ // Use findAll which already handles checksum verification
277
358
  const docs = await this.findAll(dbName, collName);
278
359
  const idStr = id.toHexString();
279
360
  return docs.find(d => d._id.toHexString() === idStr) || null;
@@ -291,7 +372,9 @@ export class FileStorageAdapter implements IStorageAdapter {
291
372
 
292
373
  if (idx === -1) return false;
293
374
 
294
- docs[idx] = doc;
375
+ // Add checksum if enabled
376
+ const docToStore = this.prepareDocumentForStorage(doc);
377
+ docs[idx] = docToStore;
295
378
  await this.writeJsonFile(collPath, docs);
296
379
  return true;
297
380
  }
@@ -1,8 +1,8 @@
1
- import type * as plugins from '../congodb.plugins.js';
1
+ import type * as plugins from '../tsmdb.plugins.js';
2
2
  import type { IStoredDocument, IOpLogEntry, Document } from '../types/interfaces.js';
3
3
 
4
4
  /**
5
- * Storage adapter interface for CongoDB
5
+ * Storage adapter interface for TsmDB
6
6
  * Implementations can provide different storage backends (memory, file, etc.)
7
7
  */
8
8
  export interface IStorageAdapter {
@@ -90,6 +90,12 @@ export interface IStorageAdapter {
90
90
  */
91
91
  findAll(dbName: string, collName: string): Promise<IStoredDocument[]>;
92
92
 
93
+ /**
94
+ * Find documents by a set of _id strings (hex format)
95
+ * Used for index-accelerated queries
96
+ */
97
+ findByIds(dbName: string, collName: string, ids: Set<string>): Promise<IStoredDocument[]>;
98
+
93
99
  /**
94
100
  * Find a document by _id
95
101
  */