@push.rocks/smartdb 1.0.1 → 2.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 (110) hide show
  1. package/.smartconfig.json +7 -4
  2. package/dist_rust/rustdb_linux_amd64 +0 -0
  3. package/dist_rust/rustdb_linux_arm64 +0 -0
  4. package/dist_ts/00_commitinfo_data.js +3 -3
  5. package/dist_ts/ts_local/classes.localsmartdb.d.ts +5 -5
  6. package/dist_ts/ts_local/classes.localsmartdb.js +5 -6
  7. package/dist_ts/ts_local/plugins.d.ts +1 -2
  8. package/dist_ts/ts_local/plugins.js +3 -3
  9. package/dist_ts/ts_smartdb/index.d.ts +1 -24
  10. package/dist_ts/ts_smartdb/index.js +4 -29
  11. package/dist_ts/ts_smartdb/plugins.d.ts +2 -10
  12. package/dist_ts/ts_smartdb/plugins.js +3 -13
  13. package/dist_ts/ts_smartdb/rust-db-bridge.d.ts +43 -0
  14. package/dist_ts/ts_smartdb/rust-db-bridge.js +98 -0
  15. package/dist_ts/ts_smartdb/server/SmartdbServer.d.ts +8 -37
  16. package/dist_ts/ts_smartdb/server/SmartdbServer.js +49 -204
  17. package/dist_ts/ts_smartdb/server/index.d.ts +0 -4
  18. package/dist_ts/ts_smartdb/server/index.js +1 -5
  19. package/license +3 -1
  20. package/package.json +9 -12
  21. package/readme.md +84 -171
  22. package/ts/00_commitinfo_data.ts +2 -2
  23. package/ts/ts_local/classes.localsmartdb.ts +5 -6
  24. package/ts/ts_local/plugins.ts +1 -3
  25. package/ts/ts_smartdb/index.ts +3 -41
  26. package/ts/ts_smartdb/plugins.ts +2 -15
  27. package/ts/ts_smartdb/rust-db-bridge.ts +138 -0
  28. package/ts/ts_smartdb/server/SmartdbServer.ts +53 -248
  29. package/ts/ts_smartdb/server/index.ts +0 -7
  30. package/dist_ts/ts_smartdb/engine/AggregationEngine.d.ts +0 -66
  31. package/dist_ts/ts_smartdb/engine/AggregationEngine.js +0 -189
  32. package/dist_ts/ts_smartdb/engine/IndexEngine.d.ts +0 -97
  33. package/dist_ts/ts_smartdb/engine/IndexEngine.js +0 -678
  34. package/dist_ts/ts_smartdb/engine/QueryEngine.d.ts +0 -54
  35. package/dist_ts/ts_smartdb/engine/QueryEngine.js +0 -271
  36. package/dist_ts/ts_smartdb/engine/QueryPlanner.d.ts +0 -64
  37. package/dist_ts/ts_smartdb/engine/QueryPlanner.js +0 -308
  38. package/dist_ts/ts_smartdb/engine/SessionEngine.d.ts +0 -117
  39. package/dist_ts/ts_smartdb/engine/SessionEngine.js +0 -232
  40. package/dist_ts/ts_smartdb/engine/TransactionEngine.d.ts +0 -85
  41. package/dist_ts/ts_smartdb/engine/TransactionEngine.js +0 -287
  42. package/dist_ts/ts_smartdb/engine/UpdateEngine.d.ts +0 -47
  43. package/dist_ts/ts_smartdb/engine/UpdateEngine.js +0 -461
  44. package/dist_ts/ts_smartdb/errors/SmartdbErrors.d.ts +0 -100
  45. package/dist_ts/ts_smartdb/errors/SmartdbErrors.js +0 -155
  46. package/dist_ts/ts_smartdb/server/CommandRouter.d.ts +0 -87
  47. package/dist_ts/ts_smartdb/server/CommandRouter.js +0 -222
  48. package/dist_ts/ts_smartdb/server/WireProtocol.d.ts +0 -117
  49. package/dist_ts/ts_smartdb/server/WireProtocol.js +0 -298
  50. package/dist_ts/ts_smartdb/server/handlers/AdminHandler.d.ts +0 -100
  51. package/dist_ts/ts_smartdb/server/handlers/AdminHandler.js +0 -668
  52. package/dist_ts/ts_smartdb/server/handlers/AggregateHandler.d.ts +0 -31
  53. package/dist_ts/ts_smartdb/server/handlers/AggregateHandler.js +0 -277
  54. package/dist_ts/ts_smartdb/server/handlers/DeleteHandler.d.ts +0 -8
  55. package/dist_ts/ts_smartdb/server/handlers/DeleteHandler.js +0 -95
  56. package/dist_ts/ts_smartdb/server/handlers/FindHandler.d.ts +0 -31
  57. package/dist_ts/ts_smartdb/server/handlers/FindHandler.js +0 -291
  58. package/dist_ts/ts_smartdb/server/handlers/HelloHandler.d.ts +0 -11
  59. package/dist_ts/ts_smartdb/server/handlers/HelloHandler.js +0 -62
  60. package/dist_ts/ts_smartdb/server/handlers/IndexHandler.d.ts +0 -20
  61. package/dist_ts/ts_smartdb/server/handlers/IndexHandler.js +0 -183
  62. package/dist_ts/ts_smartdb/server/handlers/InsertHandler.d.ts +0 -8
  63. package/dist_ts/ts_smartdb/server/handlers/InsertHandler.js +0 -79
  64. package/dist_ts/ts_smartdb/server/handlers/UpdateHandler.d.ts +0 -24
  65. package/dist_ts/ts_smartdb/server/handlers/UpdateHandler.js +0 -296
  66. package/dist_ts/ts_smartdb/server/handlers/index.d.ts +0 -8
  67. package/dist_ts/ts_smartdb/server/handlers/index.js +0 -10
  68. package/dist_ts/ts_smartdb/storage/FileStorageAdapter.d.ts +0 -85
  69. package/dist_ts/ts_smartdb/storage/FileStorageAdapter.js +0 -465
  70. package/dist_ts/ts_smartdb/storage/IStorageAdapter.d.ts +0 -145
  71. package/dist_ts/ts_smartdb/storage/IStorageAdapter.js +0 -2
  72. package/dist_ts/ts_smartdb/storage/MemoryStorageAdapter.d.ts +0 -67
  73. package/dist_ts/ts_smartdb/storage/MemoryStorageAdapter.js +0 -378
  74. package/dist_ts/ts_smartdb/storage/OpLog.d.ts +0 -93
  75. package/dist_ts/ts_smartdb/storage/OpLog.js +0 -221
  76. package/dist_ts/ts_smartdb/storage/WAL.d.ts +0 -117
  77. package/dist_ts/ts_smartdb/storage/WAL.js +0 -286
  78. package/dist_ts/ts_smartdb/types/interfaces.d.ts +0 -363
  79. package/dist_ts/ts_smartdb/types/interfaces.js +0 -2
  80. package/dist_ts/ts_smartdb/utils/checksum.d.ts +0 -30
  81. package/dist_ts/ts_smartdb/utils/checksum.js +0 -77
  82. package/dist_ts/ts_smartdb/utils/index.d.ts +0 -1
  83. package/dist_ts/ts_smartdb/utils/index.js +0 -2
  84. package/ts/ts_smartdb/engine/AggregationEngine.ts +0 -283
  85. package/ts/ts_smartdb/engine/IndexEngine.ts +0 -798
  86. package/ts/ts_smartdb/engine/QueryEngine.ts +0 -301
  87. package/ts/ts_smartdb/engine/QueryPlanner.ts +0 -393
  88. package/ts/ts_smartdb/engine/SessionEngine.ts +0 -292
  89. package/ts/ts_smartdb/engine/TransactionEngine.ts +0 -351
  90. package/ts/ts_smartdb/engine/UpdateEngine.ts +0 -506
  91. package/ts/ts_smartdb/errors/SmartdbErrors.ts +0 -181
  92. package/ts/ts_smartdb/server/CommandRouter.ts +0 -289
  93. package/ts/ts_smartdb/server/WireProtocol.ts +0 -416
  94. package/ts/ts_smartdb/server/handlers/AdminHandler.ts +0 -719
  95. package/ts/ts_smartdb/server/handlers/AggregateHandler.ts +0 -342
  96. package/ts/ts_smartdb/server/handlers/DeleteHandler.ts +0 -115
  97. package/ts/ts_smartdb/server/handlers/FindHandler.ts +0 -330
  98. package/ts/ts_smartdb/server/handlers/HelloHandler.ts +0 -78
  99. package/ts/ts_smartdb/server/handlers/IndexHandler.ts +0 -207
  100. package/ts/ts_smartdb/server/handlers/InsertHandler.ts +0 -97
  101. package/ts/ts_smartdb/server/handlers/UpdateHandler.ts +0 -344
  102. package/ts/ts_smartdb/server/handlers/index.ts +0 -10
  103. package/ts/ts_smartdb/storage/FileStorageAdapter.ts +0 -562
  104. package/ts/ts_smartdb/storage/IStorageAdapter.ts +0 -208
  105. package/ts/ts_smartdb/storage/MemoryStorageAdapter.ts +0 -455
  106. package/ts/ts_smartdb/storage/OpLog.ts +0 -282
  107. package/ts/ts_smartdb/storage/WAL.ts +0 -375
  108. package/ts/ts_smartdb/types/interfaces.ts +0 -433
  109. package/ts/ts_smartdb/utils/checksum.ts +0 -88
  110. package/ts/ts_smartdb/utils/index.ts +0 -1
@@ -1,330 +0,0 @@
1
- import * as plugins from '../../plugins.js';
2
- import type { ICommandHandler, IHandlerContext, ICursorState } from '../CommandRouter.js';
3
- import type { IStoredDocument } from '../../types/interfaces.js';
4
- import { QueryEngine } from '../../engine/QueryEngine.js';
5
-
6
- /**
7
- * FindHandler - Handles find, getMore, killCursors, count, distinct commands
8
- */
9
- export class FindHandler implements ICommandHandler {
10
- private cursors: Map<bigint, ICursorState>;
11
- private nextCursorId: () => bigint;
12
-
13
- constructor(
14
- cursors: Map<bigint, ICursorState>,
15
- nextCursorId: () => bigint
16
- ) {
17
- this.cursors = cursors;
18
- this.nextCursorId = nextCursorId;
19
- }
20
-
21
- async handle(context: IHandlerContext): Promise<plugins.bson.Document> {
22
- const { command } = context;
23
-
24
- // Determine which operation to perform
25
- if (command.find) {
26
- return this.handleFind(context);
27
- } else if (command.getMore !== undefined) {
28
- return this.handleGetMore(context);
29
- } else if (command.killCursors) {
30
- return this.handleKillCursors(context);
31
- } else if (command.count) {
32
- return this.handleCount(context);
33
- } else if (command.distinct) {
34
- return this.handleDistinct(context);
35
- }
36
-
37
- return {
38
- ok: 0,
39
- errmsg: 'Unknown find-related command',
40
- code: 59,
41
- codeName: 'CommandNotFound',
42
- };
43
- }
44
-
45
- /**
46
- * Handle find command
47
- */
48
- private async handleFind(context: IHandlerContext): Promise<plugins.bson.Document> {
49
- const { storage, database, command, getIndexEngine } = context;
50
-
51
- const collection = command.find;
52
- const filter = command.filter || {};
53
- const projection = command.projection;
54
- const sort = command.sort;
55
- const skip = command.skip || 0;
56
- const limit = command.limit || 0;
57
- const batchSize = command.batchSize || 101;
58
- const singleBatch = command.singleBatch || false;
59
-
60
- // Ensure collection exists
61
- const exists = await storage.collectionExists(database, collection);
62
- if (!exists) {
63
- // Return empty cursor for non-existent collection
64
- return {
65
- ok: 1,
66
- cursor: {
67
- id: plugins.bson.Long.fromNumber(0),
68
- ns: `${database}.${collection}`,
69
- firstBatch: [],
70
- },
71
- };
72
- }
73
-
74
- // Try to use index-accelerated query
75
- const indexEngine = getIndexEngine(collection);
76
- const candidateIds = await indexEngine.findCandidateIds(filter);
77
-
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
- }
90
-
91
- // Apply sort
92
- if (sort) {
93
- documents = QueryEngine.sort(documents, sort);
94
- }
95
-
96
- // Apply skip
97
- if (skip > 0) {
98
- documents = documents.slice(skip);
99
- }
100
-
101
- // Apply limit
102
- if (limit > 0) {
103
- documents = documents.slice(0, limit);
104
- }
105
-
106
- // Apply projection
107
- if (projection) {
108
- documents = QueryEngine.project(documents, projection) as any[];
109
- }
110
-
111
- // Determine how many documents to return in first batch
112
- const effectiveBatchSize = Math.min(batchSize, documents.length);
113
- const firstBatch = documents.slice(0, effectiveBatchSize);
114
- const remaining = documents.slice(effectiveBatchSize);
115
-
116
- // Create cursor if there are more documents
117
- let cursorId = BigInt(0);
118
- if (remaining.length > 0 && !singleBatch) {
119
- cursorId = this.nextCursorId();
120
- this.cursors.set(cursorId, {
121
- id: cursorId,
122
- database,
123
- collection,
124
- documents: remaining,
125
- position: 0,
126
- batchSize,
127
- createdAt: new Date(),
128
- });
129
- }
130
-
131
- return {
132
- ok: 1,
133
- cursor: {
134
- id: plugins.bson.Long.fromBigInt(cursorId),
135
- ns: `${database}.${collection}`,
136
- firstBatch,
137
- },
138
- };
139
- }
140
-
141
- /**
142
- * Handle getMore command
143
- */
144
- private async handleGetMore(context: IHandlerContext): Promise<plugins.bson.Document> {
145
- const { database, command } = context;
146
-
147
- const cursorIdInput = command.getMore;
148
- const collection = command.collection;
149
- const batchSize = command.batchSize || 101;
150
-
151
- // Convert cursorId to bigint
152
- let cursorId: bigint;
153
- if (typeof cursorIdInput === 'bigint') {
154
- cursorId = cursorIdInput;
155
- } else if (cursorIdInput instanceof plugins.bson.Long) {
156
- cursorId = cursorIdInput.toBigInt();
157
- } else {
158
- cursorId = BigInt(cursorIdInput);
159
- }
160
-
161
- const cursor = this.cursors.get(cursorId);
162
- if (!cursor) {
163
- return {
164
- ok: 0,
165
- errmsg: `cursor id ${cursorId} not found`,
166
- code: 43,
167
- codeName: 'CursorNotFound',
168
- };
169
- }
170
-
171
- // Verify namespace
172
- if (cursor.database !== database || cursor.collection !== collection) {
173
- return {
174
- ok: 0,
175
- errmsg: 'cursor namespace mismatch',
176
- code: 43,
177
- codeName: 'CursorNotFound',
178
- };
179
- }
180
-
181
- // Get next batch
182
- const start = cursor.position;
183
- const end = Math.min(start + batchSize, cursor.documents.length);
184
- const nextBatch = cursor.documents.slice(start, end);
185
- cursor.position = end;
186
-
187
- // Check if cursor is exhausted
188
- let returnCursorId = cursorId;
189
- if (cursor.position >= cursor.documents.length) {
190
- this.cursors.delete(cursorId);
191
- returnCursorId = BigInt(0);
192
- }
193
-
194
- return {
195
- ok: 1,
196
- cursor: {
197
- id: plugins.bson.Long.fromBigInt(returnCursorId),
198
- ns: `${database}.${collection}`,
199
- nextBatch,
200
- },
201
- };
202
- }
203
-
204
- /**
205
- * Handle killCursors command
206
- */
207
- private async handleKillCursors(context: IHandlerContext): Promise<plugins.bson.Document> {
208
- const { command } = context;
209
-
210
- const collection = command.killCursors;
211
- const cursorIds = command.cursors || [];
212
-
213
- const cursorsKilled: plugins.bson.Long[] = [];
214
- const cursorsNotFound: plugins.bson.Long[] = [];
215
- const cursorsUnknown: plugins.bson.Long[] = [];
216
-
217
- for (const idInput of cursorIds) {
218
- let cursorId: bigint;
219
- if (typeof idInput === 'bigint') {
220
- cursorId = idInput;
221
- } else if (idInput instanceof plugins.bson.Long) {
222
- cursorId = idInput.toBigInt();
223
- } else {
224
- cursorId = BigInt(idInput);
225
- }
226
-
227
- if (this.cursors.has(cursorId)) {
228
- this.cursors.delete(cursorId);
229
- cursorsKilled.push(plugins.bson.Long.fromBigInt(cursorId));
230
- } else {
231
- cursorsNotFound.push(plugins.bson.Long.fromBigInt(cursorId));
232
- }
233
- }
234
-
235
- return {
236
- ok: 1,
237
- cursorsKilled,
238
- cursorsNotFound,
239
- cursorsUnknown,
240
- cursorsAlive: [],
241
- };
242
- }
243
-
244
- /**
245
- * Handle count command
246
- */
247
- private async handleCount(context: IHandlerContext): Promise<plugins.bson.Document> {
248
- const { storage, database, command, getIndexEngine } = context;
249
-
250
- const collection = command.count;
251
- const query = command.query || {};
252
- const skip = command.skip || 0;
253
- const limit = command.limit || 0;
254
-
255
- // Check if collection exists
256
- const exists = await storage.collectionExists(database, collection);
257
- if (!exists) {
258
- return { ok: 1, n: 0 };
259
- }
260
-
261
- // Try to use index-accelerated query
262
- const indexEngine = getIndexEngine(collection);
263
- const candidateIds = await indexEngine.findCandidateIds(query);
264
-
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
- }
275
-
276
- // Apply skip
277
- if (skip > 0) {
278
- documents = documents.slice(skip);
279
- }
280
-
281
- // Apply limit
282
- if (limit > 0) {
283
- documents = documents.slice(0, limit);
284
- }
285
-
286
- return { ok: 1, n: documents.length };
287
- }
288
-
289
- /**
290
- * Handle distinct command
291
- */
292
- private async handleDistinct(context: IHandlerContext): Promise<plugins.bson.Document> {
293
- const { storage, database, command, getIndexEngine } = context;
294
-
295
- const collection = command.distinct;
296
- const key = command.key;
297
- const query = command.query || {};
298
-
299
- if (!key) {
300
- return {
301
- ok: 0,
302
- errmsg: 'distinct requires a key',
303
- code: 2,
304
- codeName: 'BadValue',
305
- };
306
- }
307
-
308
- // Check if collection exists
309
- const exists = await storage.collectionExists(database, collection);
310
- if (!exists) {
311
- return { ok: 1, values: [] };
312
- }
313
-
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
- }
324
-
325
- // Get distinct values
326
- const values = QueryEngine.distinct(documents, key, query);
327
-
328
- return { ok: 1, values };
329
- }
330
- }
@@ -1,78 +0,0 @@
1
- import * as plugins from '../../plugins.js';
2
- import type { ICommandHandler, IHandlerContext } from '../CommandRouter.js';
3
-
4
- /**
5
- * HelloHandler - Handles hello/isMaster handshake commands
6
- *
7
- * This is the first command sent by MongoDB drivers to establish a connection.
8
- * It returns server capabilities and configuration.
9
- */
10
- export class HelloHandler implements ICommandHandler {
11
- async handle(context: IHandlerContext): Promise<plugins.bson.Document> {
12
- const { command, server } = context;
13
-
14
- // Build response with server capabilities
15
- const response: plugins.bson.Document = {
16
- ismaster: true,
17
- ok: 1,
18
-
19
- // Maximum sizes
20
- maxBsonObjectSize: 16777216, // 16 MB
21
- maxMessageSizeBytes: 48000000, // 48 MB
22
- maxWriteBatchSize: 100000, // 100k documents per batch
23
-
24
- // Timestamps
25
- localTime: new Date(),
26
-
27
- // Session support
28
- logicalSessionTimeoutMinutes: 30,
29
-
30
- // Connection info
31
- connectionId: 1,
32
-
33
- // Wire protocol versions (support MongoDB 3.6 through 7.0)
34
- minWireVersion: 0,
35
- maxWireVersion: 21,
36
-
37
- // Server mode
38
- readOnly: false,
39
-
40
- // Topology info (standalone mode)
41
- isWritablePrimary: true,
42
-
43
- // Additional info
44
- topologyVersion: {
45
- processId: new plugins.bson.ObjectId(),
46
- counter: plugins.bson.Long.fromNumber(0),
47
- },
48
- };
49
-
50
- // Handle hello-specific fields
51
- if (command.hello || command.hello === 1) {
52
- response.helloOk = true;
53
- }
54
-
55
- // Handle client metadata
56
- if (command.client) {
57
- // Client is providing metadata about itself
58
- // We just acknowledge it - no need to do anything special
59
- }
60
-
61
- // Handle SASL mechanisms query
62
- if (command.saslSupportedMechs) {
63
- response.saslSupportedMechs = [
64
- // We don't actually support auth, but the driver needs to see this
65
- ];
66
- }
67
-
68
- // Compression support (none for now)
69
- if (command.compression) {
70
- response.compression = [];
71
- }
72
-
73
- // Server version info
74
- response.version = '7.0.0';
75
-
76
- return response;
77
- }
78
- }
@@ -1,207 +0,0 @@
1
- import * as plugins from '../../plugins.js';
2
- import type { ICommandHandler, IHandlerContext } from '../CommandRouter.js';
3
- import { IndexEngine } from '../../engine/IndexEngine.js';
4
-
5
- // Cache of index engines per collection
6
- const indexEngines: Map<string, IndexEngine> = new Map();
7
-
8
- /**
9
- * Get or create an IndexEngine for a collection
10
- */
11
- function getIndexEngine(storage: any, database: string, collection: string): IndexEngine {
12
- const key = `${database}.${collection}`;
13
- let engine = indexEngines.get(key);
14
-
15
- if (!engine) {
16
- engine = new IndexEngine(database, collection, storage);
17
- indexEngines.set(key, engine);
18
- }
19
-
20
- return engine;
21
- }
22
-
23
- /**
24
- * IndexHandler - Handles createIndexes, dropIndexes, listIndexes commands
25
- */
26
- export class IndexHandler implements ICommandHandler {
27
- async handle(context: IHandlerContext): Promise<plugins.bson.Document> {
28
- const { command } = context;
29
-
30
- if (command.createIndexes) {
31
- return this.handleCreateIndexes(context);
32
- } else if (command.dropIndexes) {
33
- return this.handleDropIndexes(context);
34
- } else if (command.listIndexes) {
35
- return this.handleListIndexes(context);
36
- }
37
-
38
- return {
39
- ok: 0,
40
- errmsg: 'Unknown index command',
41
- code: 59,
42
- codeName: 'CommandNotFound',
43
- };
44
- }
45
-
46
- /**
47
- * Handle createIndexes command
48
- */
49
- private async handleCreateIndexes(context: IHandlerContext): Promise<plugins.bson.Document> {
50
- const { storage, database, command } = context;
51
-
52
- const collection = command.createIndexes;
53
- const indexes = command.indexes || [];
54
-
55
- if (!Array.isArray(indexes)) {
56
- return {
57
- ok: 0,
58
- errmsg: 'indexes must be an array',
59
- code: 2,
60
- codeName: 'BadValue',
61
- };
62
- }
63
-
64
- // Ensure collection exists
65
- await storage.createCollection(database, collection);
66
-
67
- const indexEngine = getIndexEngine(storage, database, collection);
68
- const createdNames: string[] = [];
69
- let numIndexesBefore = 0;
70
- let numIndexesAfter = 0;
71
-
72
- try {
73
- const existingIndexes = await indexEngine.listIndexes();
74
- numIndexesBefore = existingIndexes.length;
75
-
76
- for (const indexSpec of indexes) {
77
- const key = indexSpec.key;
78
- const options = {
79
- name: indexSpec.name,
80
- unique: indexSpec.unique,
81
- sparse: indexSpec.sparse,
82
- expireAfterSeconds: indexSpec.expireAfterSeconds,
83
- background: indexSpec.background,
84
- partialFilterExpression: indexSpec.partialFilterExpression,
85
- };
86
-
87
- const name = await indexEngine.createIndex(key, options);
88
- createdNames.push(name);
89
- }
90
-
91
- const finalIndexes = await indexEngine.listIndexes();
92
- numIndexesAfter = finalIndexes.length;
93
- } catch (error: any) {
94
- return {
95
- ok: 0,
96
- errmsg: error.message || 'Failed to create index',
97
- code: error.code || 1,
98
- codeName: error.codeName || 'InternalError',
99
- };
100
- }
101
-
102
- return {
103
- ok: 1,
104
- numIndexesBefore,
105
- numIndexesAfter,
106
- createdCollectionAutomatically: false,
107
- commitQuorum: 'votingMembers',
108
- };
109
- }
110
-
111
- /**
112
- * Handle dropIndexes command
113
- */
114
- private async handleDropIndexes(context: IHandlerContext): Promise<plugins.bson.Document> {
115
- const { storage, database, command } = context;
116
-
117
- const collection = command.dropIndexes;
118
- const indexName = command.index;
119
-
120
- // Check if collection exists
121
- const exists = await storage.collectionExists(database, collection);
122
- if (!exists) {
123
- return {
124
- ok: 0,
125
- errmsg: `ns not found ${database}.${collection}`,
126
- code: 26,
127
- codeName: 'NamespaceNotFound',
128
- };
129
- }
130
-
131
- const indexEngine = getIndexEngine(storage, database, collection);
132
-
133
- try {
134
- if (indexName === '*') {
135
- // Drop all indexes except _id
136
- await indexEngine.dropAllIndexes();
137
- } else if (typeof indexName === 'string') {
138
- // Drop specific index by name
139
- await indexEngine.dropIndex(indexName);
140
- } else if (typeof indexName === 'object') {
141
- // Drop index by key specification
142
- const indexes = await indexEngine.listIndexes();
143
- const keyStr = JSON.stringify(indexName);
144
-
145
- for (const idx of indexes) {
146
- if (JSON.stringify(idx.key) === keyStr) {
147
- await indexEngine.dropIndex(idx.name);
148
- break;
149
- }
150
- }
151
- }
152
-
153
- return { ok: 1, nIndexesWas: 1 };
154
- } catch (error: any) {
155
- return {
156
- ok: 0,
157
- errmsg: error.message || 'Failed to drop index',
158
- code: error.code || 27,
159
- codeName: error.codeName || 'IndexNotFound',
160
- };
161
- }
162
- }
163
-
164
- /**
165
- * Handle listIndexes command
166
- */
167
- private async handleListIndexes(context: IHandlerContext): Promise<plugins.bson.Document> {
168
- const { storage, database, command } = context;
169
-
170
- const collection = command.listIndexes;
171
- const cursor = command.cursor || {};
172
- const batchSize = cursor.batchSize || 101;
173
-
174
- // Check if collection exists
175
- const exists = await storage.collectionExists(database, collection);
176
- if (!exists) {
177
- return {
178
- ok: 0,
179
- errmsg: `ns not found ${database}.${collection}`,
180
- code: 26,
181
- codeName: 'NamespaceNotFound',
182
- };
183
- }
184
-
185
- const indexEngine = getIndexEngine(storage, database, collection);
186
- const indexes = await indexEngine.listIndexes();
187
-
188
- // Format indexes for response
189
- const indexDocs = indexes.map(idx => ({
190
- v: idx.v || 2,
191
- key: idx.key,
192
- name: idx.name,
193
- ...(idx.unique ? { unique: idx.unique } : {}),
194
- ...(idx.sparse ? { sparse: idx.sparse } : {}),
195
- ...(idx.expireAfterSeconds !== undefined ? { expireAfterSeconds: idx.expireAfterSeconds } : {}),
196
- }));
197
-
198
- return {
199
- ok: 1,
200
- cursor: {
201
- id: plugins.bson.Long.fromNumber(0),
202
- ns: `${database}.${collection}`,
203
- firstBatch: indexDocs,
204
- },
205
- };
206
- }
207
- }
@@ -1,97 +0,0 @@
1
- import * as plugins from '../../plugins.js';
2
- import type { ICommandHandler, IHandlerContext } from '../CommandRouter.js';
3
- import type { IStoredDocument } from '../../types/interfaces.js';
4
-
5
- /**
6
- * InsertHandler - Handles insert commands
7
- */
8
- export class InsertHandler implements ICommandHandler {
9
- async handle(context: IHandlerContext): Promise<plugins.bson.Document> {
10
- const { storage, database, command, documentSequences } = context;
11
-
12
- const collection = command.insert;
13
- if (typeof collection !== 'string') {
14
- return {
15
- ok: 0,
16
- errmsg: 'insert command requires a collection name',
17
- code: 2,
18
- codeName: 'BadValue',
19
- };
20
- }
21
-
22
- // Get documents from command or document sequences
23
- let documents: plugins.bson.Document[] = command.documents || [];
24
-
25
- // Check for OP_MSG document sequences (for bulk inserts)
26
- if (documentSequences && documentSequences.has('documents')) {
27
- documents = documentSequences.get('documents')!;
28
- }
29
-
30
- if (!Array.isArray(documents) || documents.length === 0) {
31
- return {
32
- ok: 0,
33
- errmsg: 'insert command requires documents array',
34
- code: 2,
35
- codeName: 'BadValue',
36
- };
37
- }
38
-
39
- const ordered = command.ordered !== false;
40
- const writeErrors: plugins.bson.Document[] = [];
41
- let insertedCount = 0;
42
-
43
- // Ensure collection exists
44
- await storage.createCollection(database, collection);
45
-
46
- const indexEngine = context.getIndexEngine(collection);
47
-
48
- // Insert documents
49
- for (let i = 0; i < documents.length; i++) {
50
- const doc = documents[i];
51
-
52
- try {
53
- // Ensure _id exists
54
- if (!doc._id) {
55
- doc._id = new plugins.bson.ObjectId();
56
- }
57
-
58
- // Check index constraints before insert (doc now has _id)
59
- await indexEngine.onInsert(doc as IStoredDocument);
60
-
61
- await storage.insertOne(database, collection, doc);
62
- insertedCount++;
63
- } catch (error: any) {
64
- const writeError: plugins.bson.Document = {
65
- index: i,
66
- code: error.code || 11000,
67
- errmsg: error.message || 'Insert failed',
68
- };
69
-
70
- // Check for duplicate key error
71
- if (error.message?.includes('Duplicate key')) {
72
- writeError.code = 11000;
73
- writeError.keyPattern = { _id: 1 };
74
- writeError.keyValue = { _id: doc._id };
75
- }
76
-
77
- writeErrors.push(writeError);
78
-
79
- if (ordered) {
80
- // Stop on first error for ordered inserts
81
- break;
82
- }
83
- }
84
- }
85
-
86
- const response: plugins.bson.Document = {
87
- ok: 1,
88
- n: insertedCount,
89
- };
90
-
91
- if (writeErrors.length > 0) {
92
- response.writeErrors = writeErrors;
93
- }
94
-
95
- return response;
96
- }
97
- }