@push.rocks/smartmongo 2.0.12 → 2.1.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.
- package/dist_ts/00_commitinfo_data.js +2 -2
- package/dist_ts/congodb/congodb.plugins.d.ts +10 -0
- package/dist_ts/congodb/congodb.plugins.js +14 -0
- package/dist_ts/congodb/engine/AggregationEngine.d.ts +66 -0
- package/dist_ts/congodb/engine/AggregationEngine.js +189 -0
- package/dist_ts/congodb/engine/IndexEngine.d.ts +77 -0
- package/dist_ts/congodb/engine/IndexEngine.js +376 -0
- package/dist_ts/congodb/engine/QueryEngine.d.ts +54 -0
- package/dist_ts/congodb/engine/QueryEngine.js +271 -0
- package/dist_ts/congodb/engine/TransactionEngine.d.ts +85 -0
- package/dist_ts/congodb/engine/TransactionEngine.js +287 -0
- package/dist_ts/congodb/engine/UpdateEngine.d.ts +47 -0
- package/dist_ts/congodb/engine/UpdateEngine.js +461 -0
- package/dist_ts/congodb/errors/CongoErrors.d.ts +100 -0
- package/dist_ts/congodb/errors/CongoErrors.js +155 -0
- package/dist_ts/congodb/index.d.ts +19 -0
- package/dist_ts/congodb/index.js +26 -0
- package/dist_ts/congodb/server/CommandRouter.d.ts +51 -0
- package/dist_ts/congodb/server/CommandRouter.js +132 -0
- package/dist_ts/congodb/server/CongoServer.d.ts +95 -0
- package/dist_ts/congodb/server/CongoServer.js +227 -0
- package/dist_ts/congodb/server/WireProtocol.d.ts +117 -0
- package/dist_ts/congodb/server/WireProtocol.js +298 -0
- package/dist_ts/congodb/server/handlers/AdminHandler.d.ts +100 -0
- package/dist_ts/congodb/server/handlers/AdminHandler.js +568 -0
- package/dist_ts/congodb/server/handlers/AggregateHandler.d.ts +31 -0
- package/dist_ts/congodb/server/handlers/AggregateHandler.js +277 -0
- package/dist_ts/congodb/server/handlers/DeleteHandler.d.ts +8 -0
- package/dist_ts/congodb/server/handlers/DeleteHandler.js +83 -0
- package/dist_ts/congodb/server/handlers/FindHandler.d.ts +31 -0
- package/dist_ts/congodb/server/handlers/FindHandler.js +261 -0
- package/dist_ts/congodb/server/handlers/HelloHandler.d.ts +11 -0
- package/dist_ts/congodb/server/handlers/HelloHandler.js +62 -0
- package/dist_ts/congodb/server/handlers/IndexHandler.d.ts +20 -0
- package/dist_ts/congodb/server/handlers/IndexHandler.js +183 -0
- package/dist_ts/congodb/server/handlers/InsertHandler.d.ts +8 -0
- package/dist_ts/congodb/server/handlers/InsertHandler.js +76 -0
- package/dist_ts/congodb/server/handlers/UpdateHandler.d.ts +24 -0
- package/dist_ts/congodb/server/handlers/UpdateHandler.js +270 -0
- package/dist_ts/congodb/server/handlers/index.d.ts +8 -0
- package/dist_ts/congodb/server/handlers/index.js +10 -0
- package/dist_ts/congodb/server/index.d.ts +6 -0
- package/dist_ts/congodb/server/index.js +7 -0
- package/dist_ts/congodb/storage/FileStorageAdapter.d.ts +61 -0
- package/dist_ts/congodb/storage/FileStorageAdapter.js +396 -0
- package/dist_ts/congodb/storage/IStorageAdapter.d.ts +140 -0
- package/dist_ts/congodb/storage/IStorageAdapter.js +2 -0
- package/dist_ts/congodb/storage/MemoryStorageAdapter.d.ts +66 -0
- package/dist_ts/congodb/storage/MemoryStorageAdapter.js +367 -0
- package/dist_ts/congodb/storage/OpLog.d.ts +93 -0
- package/dist_ts/congodb/storage/OpLog.js +221 -0
- package/dist_ts/congodb/types/interfaces.d.ts +363 -0
- package/dist_ts/congodb/types/interfaces.js +2 -0
- package/dist_ts/index.d.ts +1 -0
- package/dist_ts/index.js +8 -6
- package/dist_ts/smartmongo.plugins.d.ts +1 -1
- package/dist_ts/smartmongo.plugins.js +2 -2
- package/npmextra.json +17 -7
- package/package.json +20 -12
- package/readme.hints.md +89 -1
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/congodb/congodb.plugins.ts +17 -0
- package/ts/congodb/engine/AggregationEngine.ts +283 -0
- package/ts/congodb/engine/IndexEngine.ts +479 -0
- package/ts/congodb/engine/QueryEngine.ts +301 -0
- package/ts/congodb/engine/TransactionEngine.ts +351 -0
- package/ts/congodb/engine/UpdateEngine.ts +506 -0
- package/ts/congodb/errors/CongoErrors.ts +181 -0
- package/ts/congodb/index.ts +37 -0
- package/ts/congodb/server/CommandRouter.ts +180 -0
- package/ts/congodb/server/CongoServer.ts +298 -0
- package/ts/congodb/server/WireProtocol.ts +416 -0
- package/ts/congodb/server/handlers/AdminHandler.ts +614 -0
- package/ts/congodb/server/handlers/AggregateHandler.ts +342 -0
- package/ts/congodb/server/handlers/DeleteHandler.ts +100 -0
- package/ts/congodb/server/handlers/FindHandler.ts +301 -0
- package/ts/congodb/server/handlers/HelloHandler.ts +78 -0
- package/ts/congodb/server/handlers/IndexHandler.ts +207 -0
- package/ts/congodb/server/handlers/InsertHandler.ts +91 -0
- package/ts/congodb/server/handlers/UpdateHandler.ts +315 -0
- package/ts/congodb/server/handlers/index.ts +10 -0
- package/ts/congodb/server/index.ts +10 -0
- package/ts/congodb/storage/FileStorageAdapter.ts +479 -0
- package/ts/congodb/storage/IStorageAdapter.ts +202 -0
- package/ts/congodb/storage/MemoryStorageAdapter.ts +443 -0
- package/ts/congodb/storage/OpLog.ts +282 -0
- package/ts/congodb/types/interfaces.ts +433 -0
- package/ts/index.ts +3 -0
- package/ts/smartmongo.plugins.ts +1 -1
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import * as plugins from '../../congodb.plugins.js';
|
|
2
|
+
import type { ICommandHandler, IHandlerContext, ICursorState } from '../CommandRouter.js';
|
|
3
|
+
/**
|
|
4
|
+
* AggregateHandler - Handles aggregate command
|
|
5
|
+
*/
|
|
6
|
+
export declare class AggregateHandler implements ICommandHandler {
|
|
7
|
+
private cursors;
|
|
8
|
+
private nextCursorId;
|
|
9
|
+
constructor(cursors: Map<bigint, ICursorState>, nextCursorId: () => bigint);
|
|
10
|
+
handle(context: IHandlerContext): Promise<plugins.bson.Document>;
|
|
11
|
+
/**
|
|
12
|
+
* Preprocess pipeline to handle cross-collection lookups
|
|
13
|
+
*/
|
|
14
|
+
private preprocessPipeline;
|
|
15
|
+
/**
|
|
16
|
+
* Check if pipeline has stages that need special handling
|
|
17
|
+
*/
|
|
18
|
+
private hasSpecialStages;
|
|
19
|
+
/**
|
|
20
|
+
* Execute pipeline with special stage handling
|
|
21
|
+
*/
|
|
22
|
+
private executeWithSpecialStages;
|
|
23
|
+
/**
|
|
24
|
+
* Handle $out stage - write results to a collection
|
|
25
|
+
*/
|
|
26
|
+
private handleOut;
|
|
27
|
+
/**
|
|
28
|
+
* Handle $merge stage - merge results into a collection
|
|
29
|
+
*/
|
|
30
|
+
private handleMerge;
|
|
31
|
+
}
|
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
import * as plugins from '../../congodb.plugins.js';
|
|
2
|
+
import { AggregationEngine } from '../../engine/AggregationEngine.js';
|
|
3
|
+
/**
|
|
4
|
+
* AggregateHandler - Handles aggregate command
|
|
5
|
+
*/
|
|
6
|
+
export class AggregateHandler {
|
|
7
|
+
cursors;
|
|
8
|
+
nextCursorId;
|
|
9
|
+
constructor(cursors, nextCursorId) {
|
|
10
|
+
this.cursors = cursors;
|
|
11
|
+
this.nextCursorId = nextCursorId;
|
|
12
|
+
}
|
|
13
|
+
async handle(context) {
|
|
14
|
+
const { storage, database, command } = context;
|
|
15
|
+
const collection = command.aggregate;
|
|
16
|
+
const pipeline = command.pipeline || [];
|
|
17
|
+
const cursor = command.cursor || {};
|
|
18
|
+
const batchSize = cursor.batchSize || 101;
|
|
19
|
+
// Validate
|
|
20
|
+
if (typeof collection !== 'string' && collection !== 1) {
|
|
21
|
+
return {
|
|
22
|
+
ok: 0,
|
|
23
|
+
errmsg: 'aggregate command requires a collection name or 1',
|
|
24
|
+
code: 2,
|
|
25
|
+
codeName: 'BadValue',
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
if (!Array.isArray(pipeline)) {
|
|
29
|
+
return {
|
|
30
|
+
ok: 0,
|
|
31
|
+
errmsg: 'pipeline must be an array',
|
|
32
|
+
code: 2,
|
|
33
|
+
codeName: 'BadValue',
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
try {
|
|
37
|
+
// Get source documents
|
|
38
|
+
let documents = [];
|
|
39
|
+
if (collection === 1 || collection === '1') {
|
|
40
|
+
// Database-level aggregation (e.g., $listLocalSessions)
|
|
41
|
+
documents = [];
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
// Collection-level aggregation
|
|
45
|
+
const exists = await storage.collectionExists(database, collection);
|
|
46
|
+
if (exists) {
|
|
47
|
+
documents = await storage.findAll(database, collection);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
// Handle $lookup and $graphLookup stages that reference other collections
|
|
51
|
+
const processedPipeline = await this.preprocessPipeline(storage, database, pipeline, documents);
|
|
52
|
+
// Run aggregation
|
|
53
|
+
let results;
|
|
54
|
+
// Check for special stages that we handle manually
|
|
55
|
+
if (this.hasSpecialStages(pipeline)) {
|
|
56
|
+
results = await this.executeWithSpecialStages(storage, database, documents, pipeline);
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
results = AggregationEngine.aggregate(documents, processedPipeline);
|
|
60
|
+
}
|
|
61
|
+
// Handle $out and $merge stages
|
|
62
|
+
const lastStage = pipeline[pipeline.length - 1];
|
|
63
|
+
if (lastStage && lastStage.$out) {
|
|
64
|
+
await this.handleOut(storage, database, results, lastStage.$out);
|
|
65
|
+
return { ok: 1, cursor: { id: plugins.bson.Long.fromNumber(0), ns: `${database}.${collection}`, firstBatch: [] } };
|
|
66
|
+
}
|
|
67
|
+
if (lastStage && lastStage.$merge) {
|
|
68
|
+
await this.handleMerge(storage, database, results, lastStage.$merge);
|
|
69
|
+
return { ok: 1, cursor: { id: plugins.bson.Long.fromNumber(0), ns: `${database}.${collection}`, firstBatch: [] } };
|
|
70
|
+
}
|
|
71
|
+
// Build cursor response
|
|
72
|
+
const effectiveBatchSize = Math.min(batchSize, results.length);
|
|
73
|
+
const firstBatch = results.slice(0, effectiveBatchSize);
|
|
74
|
+
const remaining = results.slice(effectiveBatchSize);
|
|
75
|
+
let cursorId = BigInt(0);
|
|
76
|
+
if (remaining.length > 0) {
|
|
77
|
+
cursorId = this.nextCursorId();
|
|
78
|
+
this.cursors.set(cursorId, {
|
|
79
|
+
id: cursorId,
|
|
80
|
+
database,
|
|
81
|
+
collection: typeof collection === 'string' ? collection : '$cmd.aggregate',
|
|
82
|
+
documents: remaining,
|
|
83
|
+
position: 0,
|
|
84
|
+
batchSize,
|
|
85
|
+
createdAt: new Date(),
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
return {
|
|
89
|
+
ok: 1,
|
|
90
|
+
cursor: {
|
|
91
|
+
id: plugins.bson.Long.fromBigInt(cursorId),
|
|
92
|
+
ns: `${database}.${typeof collection === 'string' ? collection : '$cmd.aggregate'}`,
|
|
93
|
+
firstBatch,
|
|
94
|
+
},
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
catch (error) {
|
|
98
|
+
return {
|
|
99
|
+
ok: 0,
|
|
100
|
+
errmsg: error.message || 'Aggregation failed',
|
|
101
|
+
code: 1,
|
|
102
|
+
codeName: 'InternalError',
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Preprocess pipeline to handle cross-collection lookups
|
|
108
|
+
*/
|
|
109
|
+
async preprocessPipeline(storage, database, pipeline, documents) {
|
|
110
|
+
// For now, return the pipeline as-is
|
|
111
|
+
// Cross-collection lookups are handled in executeWithSpecialStages
|
|
112
|
+
return pipeline;
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Check if pipeline has stages that need special handling
|
|
116
|
+
*/
|
|
117
|
+
hasSpecialStages(pipeline) {
|
|
118
|
+
return pipeline.some(stage => stage.$lookup ||
|
|
119
|
+
stage.$graphLookup ||
|
|
120
|
+
stage.$unionWith);
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Execute pipeline with special stage handling
|
|
124
|
+
*/
|
|
125
|
+
async executeWithSpecialStages(storage, database, documents, pipeline) {
|
|
126
|
+
let results = [...documents];
|
|
127
|
+
for (const stage of pipeline) {
|
|
128
|
+
if (stage.$lookup) {
|
|
129
|
+
const lookupSpec = stage.$lookup;
|
|
130
|
+
const fromCollection = lookupSpec.from;
|
|
131
|
+
// Get foreign collection documents
|
|
132
|
+
const foreignExists = await storage.collectionExists(database, fromCollection);
|
|
133
|
+
const foreignDocs = foreignExists
|
|
134
|
+
? await storage.findAll(database, fromCollection)
|
|
135
|
+
: [];
|
|
136
|
+
results = AggregationEngine.executeLookup(results, lookupSpec, foreignDocs);
|
|
137
|
+
}
|
|
138
|
+
else if (stage.$graphLookup) {
|
|
139
|
+
const graphLookupSpec = stage.$graphLookup;
|
|
140
|
+
const fromCollection = graphLookupSpec.from;
|
|
141
|
+
const foreignExists = await storage.collectionExists(database, fromCollection);
|
|
142
|
+
const foreignDocs = foreignExists
|
|
143
|
+
? await storage.findAll(database, fromCollection)
|
|
144
|
+
: [];
|
|
145
|
+
results = AggregationEngine.executeGraphLookup(results, graphLookupSpec, foreignDocs);
|
|
146
|
+
}
|
|
147
|
+
else if (stage.$unionWith) {
|
|
148
|
+
let unionSpec = stage.$unionWith;
|
|
149
|
+
let unionColl;
|
|
150
|
+
let unionPipeline;
|
|
151
|
+
if (typeof unionSpec === 'string') {
|
|
152
|
+
unionColl = unionSpec;
|
|
153
|
+
}
|
|
154
|
+
else {
|
|
155
|
+
unionColl = unionSpec.coll;
|
|
156
|
+
unionPipeline = unionSpec.pipeline;
|
|
157
|
+
}
|
|
158
|
+
const unionExists = await storage.collectionExists(database, unionColl);
|
|
159
|
+
const unionDocs = unionExists
|
|
160
|
+
? await storage.findAll(database, unionColl)
|
|
161
|
+
: [];
|
|
162
|
+
results = AggregationEngine.executeUnionWith(results, unionDocs, unionPipeline);
|
|
163
|
+
}
|
|
164
|
+
else if (stage.$facet) {
|
|
165
|
+
// Execute each facet pipeline separately
|
|
166
|
+
const facetResults = {};
|
|
167
|
+
for (const [facetName, facetPipeline] of Object.entries(stage.$facet)) {
|
|
168
|
+
const facetDocs = await this.executeWithSpecialStages(storage, database, results, facetPipeline);
|
|
169
|
+
facetResults[facetName] = facetDocs;
|
|
170
|
+
}
|
|
171
|
+
results = [facetResults];
|
|
172
|
+
}
|
|
173
|
+
else {
|
|
174
|
+
// Regular stage - pass to mingo
|
|
175
|
+
results = AggregationEngine.aggregate(results, [stage]);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
return results;
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Handle $out stage - write results to a collection
|
|
182
|
+
*/
|
|
183
|
+
async handleOut(storage, database, results, outSpec) {
|
|
184
|
+
let targetDb = database;
|
|
185
|
+
let targetColl;
|
|
186
|
+
if (typeof outSpec === 'string') {
|
|
187
|
+
targetColl = outSpec;
|
|
188
|
+
}
|
|
189
|
+
else {
|
|
190
|
+
targetDb = outSpec.db || database;
|
|
191
|
+
targetColl = outSpec.coll;
|
|
192
|
+
}
|
|
193
|
+
// Drop existing collection
|
|
194
|
+
await storage.dropCollection(targetDb, targetColl);
|
|
195
|
+
// Create new collection and insert results
|
|
196
|
+
await storage.createCollection(targetDb, targetColl);
|
|
197
|
+
for (const doc of results) {
|
|
198
|
+
if (!doc._id) {
|
|
199
|
+
doc._id = new plugins.bson.ObjectId();
|
|
200
|
+
}
|
|
201
|
+
await storage.insertOne(targetDb, targetColl, doc);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* Handle $merge stage - merge results into a collection
|
|
206
|
+
*/
|
|
207
|
+
async handleMerge(storage, database, results, mergeSpec) {
|
|
208
|
+
let targetDb = database;
|
|
209
|
+
let targetColl;
|
|
210
|
+
if (typeof mergeSpec === 'string') {
|
|
211
|
+
targetColl = mergeSpec;
|
|
212
|
+
}
|
|
213
|
+
else if (typeof mergeSpec.into === 'string') {
|
|
214
|
+
targetColl = mergeSpec.into;
|
|
215
|
+
}
|
|
216
|
+
else {
|
|
217
|
+
targetDb = mergeSpec.into.db || database;
|
|
218
|
+
targetColl = mergeSpec.into.coll;
|
|
219
|
+
}
|
|
220
|
+
const on = mergeSpec.on || '_id';
|
|
221
|
+
const whenMatched = mergeSpec.whenMatched || 'merge';
|
|
222
|
+
const whenNotMatched = mergeSpec.whenNotMatched || 'insert';
|
|
223
|
+
// Ensure target collection exists
|
|
224
|
+
await storage.createCollection(targetDb, targetColl);
|
|
225
|
+
for (const doc of results) {
|
|
226
|
+
// Find matching document
|
|
227
|
+
const existingDocs = await storage.findAll(targetDb, targetColl);
|
|
228
|
+
const onFields = Array.isArray(on) ? on : [on];
|
|
229
|
+
let matchingDoc = null;
|
|
230
|
+
for (const existing of existingDocs) {
|
|
231
|
+
let matches = true;
|
|
232
|
+
for (const field of onFields) {
|
|
233
|
+
if (JSON.stringify(existing[field]) !== JSON.stringify(doc[field])) {
|
|
234
|
+
matches = false;
|
|
235
|
+
break;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
if (matches) {
|
|
239
|
+
matchingDoc = existing;
|
|
240
|
+
break;
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
if (matchingDoc) {
|
|
244
|
+
// Handle whenMatched
|
|
245
|
+
if (whenMatched === 'replace') {
|
|
246
|
+
await storage.updateById(targetDb, targetColl, matchingDoc._id, doc);
|
|
247
|
+
}
|
|
248
|
+
else if (whenMatched === 'keepExisting') {
|
|
249
|
+
// Do nothing
|
|
250
|
+
}
|
|
251
|
+
else if (whenMatched === 'merge') {
|
|
252
|
+
const merged = { ...matchingDoc, ...doc };
|
|
253
|
+
await storage.updateById(targetDb, targetColl, matchingDoc._id, merged);
|
|
254
|
+
}
|
|
255
|
+
else if (whenMatched === 'fail') {
|
|
256
|
+
throw new Error('Document matched but whenMatched is fail');
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
else {
|
|
260
|
+
// Handle whenNotMatched
|
|
261
|
+
if (whenNotMatched === 'insert') {
|
|
262
|
+
if (!doc._id) {
|
|
263
|
+
doc._id = new plugins.bson.ObjectId();
|
|
264
|
+
}
|
|
265
|
+
await storage.insertOne(targetDb, targetColl, doc);
|
|
266
|
+
}
|
|
267
|
+
else if (whenNotMatched === 'discard') {
|
|
268
|
+
// Do nothing
|
|
269
|
+
}
|
|
270
|
+
else if (whenNotMatched === 'fail') {
|
|
271
|
+
throw new Error('Document not matched but whenNotMatched is fail');
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQWdncmVnYXRlSGFuZGxlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3RzL2NvbmdvZGIvc2VydmVyL2hhbmRsZXJzL0FnZ3JlZ2F0ZUhhbmRsZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLE9BQU8sTUFBTSwwQkFBMEIsQ0FBQztBQUVwRCxPQUFPLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSxtQ0FBbUMsQ0FBQztBQUV0RTs7R0FFRztBQUNILE1BQU0sT0FBTyxnQkFBZ0I7SUFDbkIsT0FBTyxDQUE0QjtJQUNuQyxZQUFZLENBQWU7SUFFbkMsWUFDRSxPQUFrQyxFQUNsQyxZQUEwQjtRQUUxQixJQUFJLENBQUMsT0FBTyxHQUFHLE9BQU8sQ0FBQztRQUN2QixJQUFJLENBQUMsWUFBWSxHQUFHLFlBQVksQ0FBQztJQUNuQyxDQUFDO0lBRUQsS0FBSyxDQUFDLE1BQU0sQ0FBQyxPQUF3QjtRQUNuQyxNQUFNLEVBQUUsT0FBTyxFQUFFLFFBQVEsRUFBRSxPQUFPLEVBQUUsR0FBRyxPQUFPLENBQUM7UUFFL0MsTUFBTSxVQUFVLEdBQUcsT0FBTyxDQUFDLFNBQVMsQ0FBQztRQUNyQyxNQUFNLFFBQVEsR0FBRyxPQUFPLENBQUMsUUFBUSxJQUFJLEVBQUUsQ0FBQztRQUN4QyxNQUFNLE1BQU0sR0FBRyxPQUFPLENBQUMsTUFBTSxJQUFJLEVBQUUsQ0FBQztRQUNwQyxNQUFNLFNBQVMsR0FBRyxNQUFNLENBQUMsU0FBUyxJQUFJLEdBQUcsQ0FBQztRQUUxQyxXQUFXO1FBQ1gsSUFBSSxPQUFPLFVBQVUsS0FBSyxRQUFRLElBQUksVUFBVSxLQUFLLENBQUMsRUFBRSxDQUFDO1lBQ3ZELE9BQU87Z0JBQ0wsRUFBRSxFQUFFLENBQUM7Z0JBQ0wsTUFBTSxFQUFFLG1EQUFtRDtnQkFDM0QsSUFBSSxFQUFFLENBQUM7Z0JBQ1AsUUFBUSxFQUFFLFVBQVU7YUFDckIsQ0FBQztRQUNKLENBQUM7UUFFRCxJQUFJ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
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import * as plugins from '../../congodb.plugins.js';
|
|
2
|
+
import type { ICommandHandler, IHandlerContext } from '../CommandRouter.js';
|
|
3
|
+
/**
|
|
4
|
+
* DeleteHandler - Handles delete commands
|
|
5
|
+
*/
|
|
6
|
+
export declare class DeleteHandler implements ICommandHandler {
|
|
7
|
+
handle(context: IHandlerContext): Promise<plugins.bson.Document>;
|
|
8
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import * as plugins from '../../congodb.plugins.js';
|
|
2
|
+
import { QueryEngine } from '../../engine/QueryEngine.js';
|
|
3
|
+
/**
|
|
4
|
+
* DeleteHandler - Handles delete commands
|
|
5
|
+
*/
|
|
6
|
+
export class DeleteHandler {
|
|
7
|
+
async handle(context) {
|
|
8
|
+
const { storage, database, command, documentSequences } = context;
|
|
9
|
+
const collection = command.delete;
|
|
10
|
+
if (typeof collection !== 'string') {
|
|
11
|
+
return {
|
|
12
|
+
ok: 0,
|
|
13
|
+
errmsg: 'delete command requires a collection name',
|
|
14
|
+
code: 2,
|
|
15
|
+
codeName: 'BadValue',
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
// Get deletes from command or document sequences
|
|
19
|
+
let deletes = command.deletes || [];
|
|
20
|
+
// Check for OP_MSG document sequences
|
|
21
|
+
if (documentSequences && documentSequences.has('deletes')) {
|
|
22
|
+
deletes = documentSequences.get('deletes');
|
|
23
|
+
}
|
|
24
|
+
if (!Array.isArray(deletes) || deletes.length === 0) {
|
|
25
|
+
return {
|
|
26
|
+
ok: 0,
|
|
27
|
+
errmsg: 'delete command requires deletes array',
|
|
28
|
+
code: 2,
|
|
29
|
+
codeName: 'BadValue',
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
const ordered = command.ordered !== false;
|
|
33
|
+
const writeErrors = [];
|
|
34
|
+
let totalDeleted = 0;
|
|
35
|
+
// Check if collection exists
|
|
36
|
+
const exists = await storage.collectionExists(database, collection);
|
|
37
|
+
if (!exists) {
|
|
38
|
+
// Collection doesn't exist, return success with 0 deleted
|
|
39
|
+
return { ok: 1, n: 0 };
|
|
40
|
+
}
|
|
41
|
+
for (let i = 0; i < deletes.length; i++) {
|
|
42
|
+
const deleteSpec = deletes[i];
|
|
43
|
+
const filter = deleteSpec.q || deleteSpec.filter || {};
|
|
44
|
+
const limit = deleteSpec.limit;
|
|
45
|
+
// limit: 0 means delete all matching, limit: 1 means delete one
|
|
46
|
+
const deleteAll = limit === 0;
|
|
47
|
+
try {
|
|
48
|
+
// Get all documents
|
|
49
|
+
const documents = await storage.findAll(database, collection);
|
|
50
|
+
// Apply filter
|
|
51
|
+
const matchingDocs = QueryEngine.filter(documents, filter);
|
|
52
|
+
if (matchingDocs.length === 0) {
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
// Determine which documents to delete
|
|
56
|
+
const docsToDelete = deleteAll ? matchingDocs : matchingDocs.slice(0, 1);
|
|
57
|
+
// Delete the documents
|
|
58
|
+
const idsToDelete = docsToDelete.map(doc => doc._id);
|
|
59
|
+
const deleted = await storage.deleteByIds(database, collection, idsToDelete);
|
|
60
|
+
totalDeleted += deleted;
|
|
61
|
+
}
|
|
62
|
+
catch (error) {
|
|
63
|
+
writeErrors.push({
|
|
64
|
+
index: i,
|
|
65
|
+
code: error.code || 1,
|
|
66
|
+
errmsg: error.message || 'Delete failed',
|
|
67
|
+
});
|
|
68
|
+
if (ordered) {
|
|
69
|
+
break;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
const response = {
|
|
74
|
+
ok: 1,
|
|
75
|
+
n: totalDeleted,
|
|
76
|
+
};
|
|
77
|
+
if (writeErrors.length > 0) {
|
|
78
|
+
response.writeErrors = writeErrors;
|
|
79
|
+
}
|
|
80
|
+
return response;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiRGVsZXRlSGFuZGxlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3RzL2NvbmdvZGIvc2VydmVyL2hhbmRsZXJzL0RlbGV0ZUhhbmRsZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLE9BQU8sTUFBTSwwQkFBMEIsQ0FBQztBQUVwRCxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0sNkJBQTZCLENBQUM7QUFFMUQ7O0dBRUc7QUFDSCxNQUFNLE9BQU8sYUFBYTtJQUN4QixLQUFLLENBQUMsTUFBTSxDQUFDLE9BQXdCO1FBQ25DLE1BQU0sRUFBRSxPQUFPLEVBQUUsUUFBUSxFQUFFLE9BQU8sRUFBRSxpQkFBaUIsRUFBRSxHQUFHLE9BQU8sQ0FBQztRQUVsRSxNQUFNLFVBQVUsR0FBRyxPQUFPLENBQUMsTUFBTSxDQUFDO1FBQ2xDLElBQUksT0FBTyxVQUFVLEtBQUssUUFBUSxFQUFFLENBQUM7WUFDbkMsT0FBTztnQkFDTCxFQUFFLEVBQUUsQ0FBQztnQkFDTCxNQUFNLEVBQUUsMkNBQTJDO2dCQUNuRCxJQUFJLEVBQUUsQ0FBQztnQkFDUCxRQUFRLEVBQUUsVUFBVTthQUNyQixDQUFDO1FBQ0osQ0FBQztRQUVELGlEQUFpRDtRQUNqRCxJQUFJLE9BQU8sR0FBNEIsT0FBTyxDQUFDLE9BQU8sSUFBSSxFQUFFLENBQUM7UUFFN0Qsc0NBQXNDO1FBQ3RDLElBQUksaUJBQWlCLElBQUksaUJBQWlCLENBQUMsR0FBRyxDQUFDLFNBQVMsQ0FBQyxFQUFFLENBQUM7WUFDMUQsT0FBTyxHQUFHLGlCQUFpQixDQUFDLEdBQUcsQ0FBQyxTQUFTLENBQUUsQ0FBQztRQUM5QyxDQUFDO1FBRUQsSUFBSSxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDLElBQUksT0FBTyxDQUFDLE1BQU0sS0FBSyxDQUFDLEVBQUUsQ0FBQztZQUNwRCxPQUFPO2dCQUNMLEVBQUUsRUFBRSxDQUFDO2dCQUNMLE1BQU0sRUFBRSx1Q0FBdUM7Z0JBQy9DLElBQUksRUFBRSxDQUFDO2dCQUNQLFFBQVEsRUFBRSxVQUFVO2FBQ3JCLENBQUM7UUFDSixDQUFDO1FBRUQsTUFBTSxPQUFPLEdBQUcsT0FBTyxDQUFDLE9BQU8sS0FBSyxLQUFLLENBQUM7UUFDMUMsTUFBTSxXQUFXLEdBQTRCLEVBQUUsQ0FBQztRQUNoRCxJQUFJLFlBQVksR0FBRyxDQUFDLENBQUM7UUFFckIsNkJBQTZCO1FBQzdCLE1BQU0sTUFBTSxHQUFHLE1BQU0sT0FBTyxDQUFDLGdCQUFnQixDQUFDLFFBQVEsRUFBRSxVQUFVLENBQUMsQ0FBQztRQUNwRSxJQUFJLENBQUMsTUFBTSxFQUFFLENBQUM7WUFDWiwwREFBMEQ7WUFDMUQsT0FBTyxFQUFFLEVBQUUsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDO1FBQ3pCLENBQUM7UUFFRCxLQUFLLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsT0FBTyxDQUFDLE1BQU0sRUFBRSxDQUFDLEVBQUUsRUFBRSxDQUFDO1lBQ3hDLE1BQU0sVUFBVSxHQUFHLE9BQU8sQ0FBQyxDQUFDLENBQUMsQ0FBQztZQUM5QixNQUFNLE1BQU0sR0FBRyxVQUFVLENBQUMsQ0FBQyxJQUFJLFVBQVUsQ0FBQyxNQUFNLElBQUksRUFBRSxDQUFDO1lBQ3ZELE1BQU0sS0FBSyxHQUFHLFVBQVUsQ0FBQyxLQUFLLENBQUM7WUFFL0IsZ0VBQWdFO1lBQ2hFLE1BQU0sU0FBUyxHQUFHLEtBQUssS0FBSyxDQUFDLENBQUM7WUFFOUIsSUFBSSxDQUFDO2dCQUNILG9CQUFvQjtnQkFDcEIsTUFBTSxTQUFTLEdBQUcsTUFBTSxPQUFPLENBQUMsT0FBTyxDQUFDLFFBQVEsRUFBRSxVQUFVLENBQUMsQ0FBQztnQkFFOUQsZUFBZTtnQkFDZixNQUFNLFlBQVksR0FBRyxXQUFXLENBQUMsTUFBTSxDQUFDLFNBQVMsRUFBRSxNQUFNLENBQUMsQ0FBQztnQkFFM0QsSUFBSSxZQUFZLENBQUMsTUFBTSxLQUFLLENBQUMsRUFBRSxDQUFDO29CQUM5QixTQUFTO2dCQUNYLENBQUM7Z0JBRUQsc0NBQXNDO2dCQUN0QyxNQUFNLFlBQVksR0FBRyxTQUFTLENBQUMsQ0FBQyxDQUFDLFlBQVksQ0FBQyxDQUFDLENBQUMsWUFBWSxDQUFDLEtBQUssQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUM7Z0JBRXpFLHVCQUF1QjtnQkFDdkIsTUFBTSxXQUFXLEdBQUcsWUFBWSxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsQ0FBQztnQkFDckQsTUFBTSxPQUFPLEdBQUcsTUFBTSxPQUFPLENBQUMsV0FBVyxDQUFDLFFBQVEsRUFBRSxVQUFVLEVBQUUsV0FBVyxDQUFDLENBQUM7Z0JBQzdFLFlBQVksSUFBSSxPQUFPLENBQUM7WUFDMUIsQ0FBQztZQUFDLE9BQU8sS0FBVSxFQUFFLENBQUM7Z0JBQ3BCLFdBQVcsQ0FBQyxJQUFJLENBQUM7b0JBQ2YsS0FBSyxFQUFFLENBQUM7b0JBQ1IsSUFBSSxFQUFFLEtBQUssQ0FBQyxJQUFJLElBQUksQ0FBQztvQkFDckIsTUFBTSxFQUFFLEtBQUssQ0FBQyxPQUFPLElBQUksZUFBZTtpQkFDekMsQ0FBQyxDQUFDO2dCQUVILElBQUksT0FBTyxFQUFFLENBQUM7b0JBQ1osTUFBTTtnQkFDUixDQUFDO1lBQ0gsQ0FBQztRQUNILENBQUM7UUFFRCxNQUFNLFFBQVEsR0FBMEI7WUFDdEMsRUFBRSxFQUFFLENBQUM7WUFDTCxDQUFDLEVBQUUsWUFBWTtTQUNoQixDQUFDO1FBRUYsSUFBSSxXQUFXLENBQUMsTUFBTSxHQUFHLENBQUMsRUFBRSxDQUFDO1lBQzNCLFFBQVEsQ0FBQyxXQUFXLEdBQUcsV0FBVyxDQUFDO1FBQ3JDLENBQUM7UUFFRCxPQUFPLFFBQVEsQ0FBQztJQUNsQixDQUFDO0NBQ0YifQ==
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import * as plugins from '../../congodb.plugins.js';
|
|
2
|
+
import type { ICommandHandler, IHandlerContext, ICursorState } from '../CommandRouter.js';
|
|
3
|
+
/**
|
|
4
|
+
* FindHandler - Handles find, getMore, killCursors, count, distinct commands
|
|
5
|
+
*/
|
|
6
|
+
export declare class FindHandler implements ICommandHandler {
|
|
7
|
+
private cursors;
|
|
8
|
+
private nextCursorId;
|
|
9
|
+
constructor(cursors: Map<bigint, ICursorState>, nextCursorId: () => bigint);
|
|
10
|
+
handle(context: IHandlerContext): Promise<plugins.bson.Document>;
|
|
11
|
+
/**
|
|
12
|
+
* Handle find command
|
|
13
|
+
*/
|
|
14
|
+
private handleFind;
|
|
15
|
+
/**
|
|
16
|
+
* Handle getMore command
|
|
17
|
+
*/
|
|
18
|
+
private handleGetMore;
|
|
19
|
+
/**
|
|
20
|
+
* Handle killCursors command
|
|
21
|
+
*/
|
|
22
|
+
private handleKillCursors;
|
|
23
|
+
/**
|
|
24
|
+
* Handle count command
|
|
25
|
+
*/
|
|
26
|
+
private handleCount;
|
|
27
|
+
/**
|
|
28
|
+
* Handle distinct command
|
|
29
|
+
*/
|
|
30
|
+
private handleDistinct;
|
|
31
|
+
}
|