@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.
- package/dist_ts/00_commitinfo_data.js +1 -1
- package/dist_ts/index.d.ts +1 -1
- package/dist_ts/index.js +3 -3
- package/dist_ts/tsmdb/engine/AggregationEngine.js +189 -0
- package/dist_ts/{congodb → tsmdb}/engine/IndexEngine.d.ts +23 -3
- package/dist_ts/tsmdb/engine/IndexEngine.js +678 -0
- package/dist_ts/tsmdb/engine/QueryEngine.js +271 -0
- package/dist_ts/tsmdb/engine/QueryPlanner.d.ts +64 -0
- package/dist_ts/tsmdb/engine/QueryPlanner.js +308 -0
- package/dist_ts/tsmdb/engine/SessionEngine.d.ts +117 -0
- package/dist_ts/tsmdb/engine/SessionEngine.js +232 -0
- package/dist_ts/{congodb → tsmdb}/engine/TransactionEngine.d.ts +1 -1
- package/dist_ts/tsmdb/engine/TransactionEngine.js +287 -0
- package/dist_ts/tsmdb/engine/UpdateEngine.js +461 -0
- package/dist_ts/{congodb/errors/CongoErrors.d.ts → tsmdb/errors/TsmdbErrors.d.ts} +16 -16
- package/dist_ts/tsmdb/errors/TsmdbErrors.js +155 -0
- package/dist_ts/{congodb → tsmdb}/index.d.ts +11 -4
- package/dist_ts/tsmdb/index.js +31 -0
- package/dist_ts/tsmdb/server/CommandRouter.d.ts +87 -0
- package/dist_ts/tsmdb/server/CommandRouter.js +222 -0
- package/dist_ts/{congodb/server/CongoServer.d.ts → tsmdb/server/TsmdbServer.d.ts} +6 -6
- package/dist_ts/tsmdb/server/TsmdbServer.js +229 -0
- package/dist_ts/{congodb → tsmdb}/server/WireProtocol.d.ts +1 -1
- package/dist_ts/tsmdb/server/WireProtocol.js +298 -0
- package/dist_ts/{congodb → tsmdb}/server/handlers/AdminHandler.d.ts +1 -1
- package/dist_ts/tsmdb/server/handlers/AdminHandler.js +668 -0
- package/dist_ts/{congodb → tsmdb}/server/handlers/AggregateHandler.d.ts +1 -1
- package/dist_ts/tsmdb/server/handlers/AggregateHandler.js +277 -0
- package/dist_ts/{congodb → tsmdb}/server/handlers/DeleteHandler.d.ts +1 -1
- package/dist_ts/tsmdb/server/handlers/DeleteHandler.js +95 -0
- package/dist_ts/{congodb → tsmdb}/server/handlers/FindHandler.d.ts +1 -1
- package/dist_ts/tsmdb/server/handlers/FindHandler.js +291 -0
- package/dist_ts/{congodb → tsmdb}/server/handlers/HelloHandler.d.ts +1 -1
- package/dist_ts/{congodb → tsmdb}/server/handlers/HelloHandler.js +2 -2
- package/dist_ts/{congodb → tsmdb}/server/handlers/IndexHandler.d.ts +1 -1
- package/dist_ts/tsmdb/server/handlers/IndexHandler.js +183 -0
- package/dist_ts/{congodb → tsmdb}/server/handlers/InsertHandler.d.ts +1 -1
- package/dist_ts/tsmdb/server/handlers/InsertHandler.js +79 -0
- package/dist_ts/{congodb → tsmdb}/server/handlers/UpdateHandler.d.ts +1 -1
- package/dist_ts/tsmdb/server/handlers/UpdateHandler.js +296 -0
- package/dist_ts/tsmdb/server/handlers/index.js +10 -0
- package/dist_ts/{congodb → tsmdb}/server/index.d.ts +2 -2
- package/dist_ts/tsmdb/server/index.js +7 -0
- package/dist_ts/{congodb → tsmdb}/storage/FileStorageAdapter.d.ts +27 -3
- package/dist_ts/tsmdb/storage/FileStorageAdapter.js +465 -0
- package/dist_ts/{congodb → tsmdb}/storage/IStorageAdapter.d.ts +7 -2
- package/dist_ts/{congodb → tsmdb}/storage/IStorageAdapter.js +1 -1
- package/dist_ts/{congodb → tsmdb}/storage/MemoryStorageAdapter.d.ts +3 -2
- package/dist_ts/tsmdb/storage/MemoryStorageAdapter.js +378 -0
- package/dist_ts/{congodb → tsmdb}/storage/OpLog.d.ts +1 -1
- package/dist_ts/tsmdb/storage/OpLog.js +221 -0
- package/dist_ts/tsmdb/storage/WAL.d.ts +117 -0
- package/dist_ts/tsmdb/storage/WAL.js +286 -0
- package/dist_ts/tsmdb/tsmdb.plugins.js +14 -0
- package/dist_ts/{congodb → tsmdb}/types/interfaces.d.ts +3 -3
- package/dist_ts/{congodb → tsmdb}/types/interfaces.js +1 -1
- package/dist_ts/tsmdb/utils/checksum.d.ts +30 -0
- package/dist_ts/tsmdb/utils/checksum.js +77 -0
- package/dist_ts/tsmdb/utils/index.d.ts +1 -0
- package/dist_ts/tsmdb/utils/index.js +2 -0
- package/package.json +1 -1
- package/readme.hints.md +7 -12
- package/readme.md +25 -25
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/index.ts +2 -2
- package/ts/{congodb → tsmdb}/engine/AggregationEngine.ts +1 -1
- package/ts/tsmdb/engine/IndexEngine.ts +798 -0
- package/ts/{congodb → tsmdb}/engine/QueryEngine.ts +1 -1
- package/ts/tsmdb/engine/QueryPlanner.ts +393 -0
- package/ts/tsmdb/engine/SessionEngine.ts +292 -0
- package/ts/{congodb → tsmdb}/engine/TransactionEngine.ts +12 -12
- package/ts/{congodb → tsmdb}/engine/UpdateEngine.ts +1 -1
- package/ts/{congodb/errors/CongoErrors.ts → tsmdb/errors/TsmdbErrors.ts} +34 -34
- package/ts/{congodb → tsmdb}/index.ts +16 -7
- package/ts/{congodb → tsmdb}/server/CommandRouter.ts +114 -5
- package/ts/{congodb/server/CongoServer.ts → tsmdb/server/TsmdbServer.ts} +11 -8
- package/ts/{congodb → tsmdb}/server/WireProtocol.ts +1 -1
- package/ts/{congodb → tsmdb}/server/handlers/AdminHandler.ts +116 -11
- package/ts/{congodb → tsmdb}/server/handlers/AggregateHandler.ts +1 -1
- package/ts/{congodb → tsmdb}/server/handlers/DeleteHandler.ts +18 -3
- package/ts/{congodb → tsmdb}/server/handlers/FindHandler.ts +43 -14
- package/ts/{congodb → tsmdb}/server/handlers/HelloHandler.ts +1 -1
- package/ts/{congodb → tsmdb}/server/handlers/IndexHandler.ts +1 -1
- package/ts/{congodb → tsmdb}/server/handlers/InsertHandler.ts +7 -1
- package/ts/{congodb → tsmdb}/server/handlers/UpdateHandler.ts +34 -5
- package/ts/{congodb → tsmdb}/server/index.ts +2 -2
- package/ts/{congodb → tsmdb}/storage/FileStorageAdapter.ts +90 -7
- package/ts/{congodb → tsmdb}/storage/IStorageAdapter.ts +8 -2
- package/ts/{congodb → tsmdb}/storage/MemoryStorageAdapter.ts +14 -2
- package/ts/{congodb → tsmdb}/storage/OpLog.ts +1 -1
- package/ts/tsmdb/storage/WAL.ts +375 -0
- package/ts/{congodb → tsmdb}/types/interfaces.ts +3 -3
- package/ts/tsmdb/utils/checksum.ts +88 -0
- package/ts/tsmdb/utils/index.ts +1 -0
- package/dist_ts/congodb/congodb.plugins.js +0 -14
- package/dist_ts/congodb/engine/AggregationEngine.js +0 -189
- package/dist_ts/congodb/engine/IndexEngine.js +0 -376
- package/dist_ts/congodb/engine/QueryEngine.js +0 -271
- package/dist_ts/congodb/engine/TransactionEngine.js +0 -287
- package/dist_ts/congodb/engine/UpdateEngine.js +0 -461
- package/dist_ts/congodb/errors/CongoErrors.js +0 -155
- package/dist_ts/congodb/index.js +0 -26
- package/dist_ts/congodb/server/CommandRouter.d.ts +0 -51
- package/dist_ts/congodb/server/CommandRouter.js +0 -132
- package/dist_ts/congodb/server/CongoServer.js +0 -227
- package/dist_ts/congodb/server/WireProtocol.js +0 -298
- package/dist_ts/congodb/server/handlers/AdminHandler.js +0 -568
- package/dist_ts/congodb/server/handlers/AggregateHandler.js +0 -277
- package/dist_ts/congodb/server/handlers/DeleteHandler.js +0 -83
- package/dist_ts/congodb/server/handlers/FindHandler.js +0 -261
- package/dist_ts/congodb/server/handlers/IndexHandler.js +0 -183
- package/dist_ts/congodb/server/handlers/InsertHandler.js +0 -76
- package/dist_ts/congodb/server/handlers/UpdateHandler.js +0 -270
- package/dist_ts/congodb/server/handlers/index.js +0 -10
- package/dist_ts/congodb/server/index.js +0 -7
- package/dist_ts/congodb/storage/FileStorageAdapter.js +0 -396
- package/dist_ts/congodb/storage/MemoryStorageAdapter.js +0 -367
- package/dist_ts/congodb/storage/OpLog.js +0 -221
- package/ts/congodb/engine/IndexEngine.ts +0 -479
- /package/dist_ts/{congodb → tsmdb}/engine/AggregationEngine.d.ts +0 -0
- /package/dist_ts/{congodb → tsmdb}/engine/QueryEngine.d.ts +0 -0
- /package/dist_ts/{congodb → tsmdb}/engine/UpdateEngine.d.ts +0 -0
- /package/dist_ts/{congodb → tsmdb}/server/handlers/index.d.ts +0 -0
- /package/dist_ts/{congodb/congodb.plugins.d.ts → tsmdb/tsmdb.plugins.d.ts} +0 -0
- /package/ts/{congodb → tsmdb}/server/handlers/index.ts +0 -0
- /package/ts/{congodb/congodb.plugins.ts → tsmdb/tsmdb.plugins.ts} +0 -0
|
@@ -1,271 +0,0 @@
|
|
|
1
|
-
import * as plugins from '../congodb.plugins.js';
|
|
2
|
-
// Import mingo Query class
|
|
3
|
-
import { Query } from 'mingo';
|
|
4
|
-
/**
|
|
5
|
-
* Query engine using mingo for MongoDB-compatible query matching
|
|
6
|
-
*/
|
|
7
|
-
export class QueryEngine {
|
|
8
|
-
/**
|
|
9
|
-
* Filter documents by a MongoDB query filter
|
|
10
|
-
*/
|
|
11
|
-
static filter(documents, filter) {
|
|
12
|
-
if (!filter || Object.keys(filter).length === 0) {
|
|
13
|
-
return documents;
|
|
14
|
-
}
|
|
15
|
-
const query = new Query(filter);
|
|
16
|
-
return documents.filter(doc => query.test(doc));
|
|
17
|
-
}
|
|
18
|
-
/**
|
|
19
|
-
* Test if a single document matches a filter
|
|
20
|
-
*/
|
|
21
|
-
static matches(document, filter) {
|
|
22
|
-
if (!filter || Object.keys(filter).length === 0) {
|
|
23
|
-
return true;
|
|
24
|
-
}
|
|
25
|
-
const query = new Query(filter);
|
|
26
|
-
return query.test(document);
|
|
27
|
-
}
|
|
28
|
-
/**
|
|
29
|
-
* Find a single document matching the filter
|
|
30
|
-
*/
|
|
31
|
-
static findOne(documents, filter) {
|
|
32
|
-
if (!filter || Object.keys(filter).length === 0) {
|
|
33
|
-
return documents[0] || null;
|
|
34
|
-
}
|
|
35
|
-
const query = new Query(filter);
|
|
36
|
-
for (const doc of documents) {
|
|
37
|
-
if (query.test(doc)) {
|
|
38
|
-
return doc;
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
return null;
|
|
42
|
-
}
|
|
43
|
-
/**
|
|
44
|
-
* Sort documents by a sort specification
|
|
45
|
-
*/
|
|
46
|
-
static sort(documents, sort) {
|
|
47
|
-
if (!sort) {
|
|
48
|
-
return documents;
|
|
49
|
-
}
|
|
50
|
-
// Normalize sort specification to array of [field, direction] pairs
|
|
51
|
-
const sortFields = [];
|
|
52
|
-
if (Array.isArray(sort)) {
|
|
53
|
-
for (const [field, direction] of sort) {
|
|
54
|
-
sortFields.push([field, this.normalizeDirection(direction)]);
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
else {
|
|
58
|
-
for (const [field, direction] of Object.entries(sort)) {
|
|
59
|
-
sortFields.push([field, this.normalizeDirection(direction)]);
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
return [...documents].sort((a, b) => {
|
|
63
|
-
for (const [field, direction] of sortFields) {
|
|
64
|
-
const aVal = this.getNestedValue(a, field);
|
|
65
|
-
const bVal = this.getNestedValue(b, field);
|
|
66
|
-
const comparison = this.compareValues(aVal, bVal);
|
|
67
|
-
if (comparison !== 0) {
|
|
68
|
-
return comparison * direction;
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
return 0;
|
|
72
|
-
});
|
|
73
|
-
}
|
|
74
|
-
/**
|
|
75
|
-
* Apply projection to documents
|
|
76
|
-
*/
|
|
77
|
-
static project(documents, projection) {
|
|
78
|
-
if (!projection || Object.keys(projection).length === 0) {
|
|
79
|
-
return documents;
|
|
80
|
-
}
|
|
81
|
-
// Determine if this is inclusion or exclusion projection
|
|
82
|
-
const keys = Object.keys(projection);
|
|
83
|
-
const hasInclusion = keys.some(k => k !== '_id' && projection[k] === 1);
|
|
84
|
-
const hasExclusion = keys.some(k => k !== '_id' && projection[k] === 0);
|
|
85
|
-
// Can't mix inclusion and exclusion (except for _id)
|
|
86
|
-
if (hasInclusion && hasExclusion) {
|
|
87
|
-
throw new Error('Cannot mix inclusion and exclusion in projection');
|
|
88
|
-
}
|
|
89
|
-
return documents.map(doc => {
|
|
90
|
-
if (hasInclusion) {
|
|
91
|
-
// Inclusion projection
|
|
92
|
-
const result = {};
|
|
93
|
-
// Handle _id
|
|
94
|
-
if (projection._id !== 0 && projection._id !== false) {
|
|
95
|
-
result._id = doc._id;
|
|
96
|
-
}
|
|
97
|
-
for (const key of keys) {
|
|
98
|
-
if (key === '_id')
|
|
99
|
-
continue;
|
|
100
|
-
if (projection[key] === 1 || projection[key] === true) {
|
|
101
|
-
const value = this.getNestedValue(doc, key);
|
|
102
|
-
if (value !== undefined) {
|
|
103
|
-
this.setNestedValue(result, key, value);
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
return result;
|
|
108
|
-
}
|
|
109
|
-
else {
|
|
110
|
-
// Exclusion projection - start with copy and remove fields
|
|
111
|
-
const result = { ...doc };
|
|
112
|
-
for (const key of keys) {
|
|
113
|
-
if (projection[key] === 0 || projection[key] === false) {
|
|
114
|
-
this.deleteNestedValue(result, key);
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
return result;
|
|
118
|
-
}
|
|
119
|
-
});
|
|
120
|
-
}
|
|
121
|
-
/**
|
|
122
|
-
* Get distinct values for a field
|
|
123
|
-
*/
|
|
124
|
-
static distinct(documents, field, filter) {
|
|
125
|
-
let docs = documents;
|
|
126
|
-
if (filter && Object.keys(filter).length > 0) {
|
|
127
|
-
docs = this.filter(documents, filter);
|
|
128
|
-
}
|
|
129
|
-
const values = new Set();
|
|
130
|
-
for (const doc of docs) {
|
|
131
|
-
const value = this.getNestedValue(doc, field);
|
|
132
|
-
if (value !== undefined) {
|
|
133
|
-
if (Array.isArray(value)) {
|
|
134
|
-
// For arrays, add each element
|
|
135
|
-
for (const v of value) {
|
|
136
|
-
values.add(this.toComparable(v));
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
else {
|
|
140
|
-
values.add(this.toComparable(value));
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
return Array.from(values);
|
|
145
|
-
}
|
|
146
|
-
/**
|
|
147
|
-
* Normalize sort direction to 1 or -1
|
|
148
|
-
*/
|
|
149
|
-
static normalizeDirection(direction) {
|
|
150
|
-
if (typeof direction === 'number') {
|
|
151
|
-
return direction > 0 ? 1 : -1;
|
|
152
|
-
}
|
|
153
|
-
if (direction === 'asc' || direction === 'ascending') {
|
|
154
|
-
return 1;
|
|
155
|
-
}
|
|
156
|
-
return -1;
|
|
157
|
-
}
|
|
158
|
-
/**
|
|
159
|
-
* Get a nested value from an object using dot notation
|
|
160
|
-
*/
|
|
161
|
-
static getNestedValue(obj, path) {
|
|
162
|
-
const parts = path.split('.');
|
|
163
|
-
let current = obj;
|
|
164
|
-
for (const part of parts) {
|
|
165
|
-
if (current === null || current === undefined) {
|
|
166
|
-
return undefined;
|
|
167
|
-
}
|
|
168
|
-
if (Array.isArray(current)) {
|
|
169
|
-
// Handle array access
|
|
170
|
-
const index = parseInt(part, 10);
|
|
171
|
-
if (!isNaN(index)) {
|
|
172
|
-
current = current[index];
|
|
173
|
-
}
|
|
174
|
-
else {
|
|
175
|
-
// Get the field from all array elements
|
|
176
|
-
return current.map(item => this.getNestedValue(item, part)).flat();
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
else {
|
|
180
|
-
current = current[part];
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
return current;
|
|
184
|
-
}
|
|
185
|
-
/**
|
|
186
|
-
* Set a nested value in an object using dot notation
|
|
187
|
-
*/
|
|
188
|
-
static setNestedValue(obj, path, value) {
|
|
189
|
-
const parts = path.split('.');
|
|
190
|
-
let current = obj;
|
|
191
|
-
for (let i = 0; i < parts.length - 1; i++) {
|
|
192
|
-
const part = parts[i];
|
|
193
|
-
if (!(part in current)) {
|
|
194
|
-
current[part] = {};
|
|
195
|
-
}
|
|
196
|
-
current = current[part];
|
|
197
|
-
}
|
|
198
|
-
current[parts[parts.length - 1]] = value;
|
|
199
|
-
}
|
|
200
|
-
/**
|
|
201
|
-
* Delete a nested value from an object using dot notation
|
|
202
|
-
*/
|
|
203
|
-
static deleteNestedValue(obj, path) {
|
|
204
|
-
const parts = path.split('.');
|
|
205
|
-
let current = obj;
|
|
206
|
-
for (let i = 0; i < parts.length - 1; i++) {
|
|
207
|
-
const part = parts[i];
|
|
208
|
-
if (!(part in current)) {
|
|
209
|
-
return;
|
|
210
|
-
}
|
|
211
|
-
current = current[part];
|
|
212
|
-
}
|
|
213
|
-
delete current[parts[parts.length - 1]];
|
|
214
|
-
}
|
|
215
|
-
/**
|
|
216
|
-
* Compare two values for sorting
|
|
217
|
-
*/
|
|
218
|
-
static compareValues(a, b) {
|
|
219
|
-
// Handle undefined/null
|
|
220
|
-
if (a === undefined && b === undefined)
|
|
221
|
-
return 0;
|
|
222
|
-
if (a === undefined)
|
|
223
|
-
return -1;
|
|
224
|
-
if (b === undefined)
|
|
225
|
-
return 1;
|
|
226
|
-
if (a === null && b === null)
|
|
227
|
-
return 0;
|
|
228
|
-
if (a === null)
|
|
229
|
-
return -1;
|
|
230
|
-
if (b === null)
|
|
231
|
-
return 1;
|
|
232
|
-
// Handle ObjectId
|
|
233
|
-
if (a instanceof plugins.bson.ObjectId && b instanceof plugins.bson.ObjectId) {
|
|
234
|
-
return a.toHexString().localeCompare(b.toHexString());
|
|
235
|
-
}
|
|
236
|
-
// Handle dates
|
|
237
|
-
if (a instanceof Date && b instanceof Date) {
|
|
238
|
-
return a.getTime() - b.getTime();
|
|
239
|
-
}
|
|
240
|
-
// Handle numbers
|
|
241
|
-
if (typeof a === 'number' && typeof b === 'number') {
|
|
242
|
-
return a - b;
|
|
243
|
-
}
|
|
244
|
-
// Handle strings
|
|
245
|
-
if (typeof a === 'string' && typeof b === 'string') {
|
|
246
|
-
return a.localeCompare(b);
|
|
247
|
-
}
|
|
248
|
-
// Handle booleans
|
|
249
|
-
if (typeof a === 'boolean' && typeof b === 'boolean') {
|
|
250
|
-
return (a ? 1 : 0) - (b ? 1 : 0);
|
|
251
|
-
}
|
|
252
|
-
// Fall back to string comparison
|
|
253
|
-
return String(a).localeCompare(String(b));
|
|
254
|
-
}
|
|
255
|
-
/**
|
|
256
|
-
* Convert a value to a comparable form (for distinct)
|
|
257
|
-
*/
|
|
258
|
-
static toComparable(value) {
|
|
259
|
-
if (value instanceof plugins.bson.ObjectId) {
|
|
260
|
-
return value.toHexString();
|
|
261
|
-
}
|
|
262
|
-
if (value instanceof Date) {
|
|
263
|
-
return value.toISOString();
|
|
264
|
-
}
|
|
265
|
-
if (typeof value === 'object' && value !== null) {
|
|
266
|
-
return JSON.stringify(value);
|
|
267
|
-
}
|
|
268
|
-
return value;
|
|
269
|
-
}
|
|
270
|
-
}
|
|
271
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiUXVlcnlFbmdpbmUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi90cy9jb25nb2RiL2VuZ2luZS9RdWVyeUVuZ2luZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssT0FBTyxNQUFNLHVCQUF1QixDQUFDO0FBR2pELDJCQUEyQjtBQUMzQixPQUFPLEVBQUUsS0FBSyxFQUFFLE1BQU0sT0FBTyxDQUFDO0FBRTlCOztHQUVHO0FBQ0gsTUFBTSxPQUFPLFdBQVc7SUFDdEI7O09BRUc7SUFDSCxNQUFNLENBQUMsTUFBTSxDQUFDLFNBQTRCLEVBQUUsTUFBZ0I7UUFDMUQsSUFBSSxDQUFDLE1BQU0sSUFBSSxNQUFNLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxDQUFDLE1BQU0sS0FBSyxDQUFDLEVBQUUsQ0FBQztZQUNoRCxPQUFPLFNBQVMsQ0FBQztRQUNuQixDQUFDO1FBRUQsTUFBTSxLQUFLLEdBQUcsSUFBSSxLQUFLLENBQUMsTUFBTSxDQUFDLENBQUM7UUFDaEMsT0FBTyxTQUFTLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDO0lBQ2xELENBQUM7SUFFRDs7T0FFRztJQUNILE1BQU0sQ0FBQyxPQUFPLENBQUMsUUFBa0IsRUFBRSxNQUFnQjtRQUNqRCxJQUFJLENBQUMsTUFBTSxJQUFJLE1BQU0sQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLENBQUMsTUFBTSxLQUFLLENBQUMsRUFBRSxDQUFDO1lBQ2hELE9BQU8sSUFBSSxDQUFDO1FBQ2QsQ0FBQztRQUVELE1BQU0sS0FBSyxHQUFHLElBQUksS0FBSyxDQUFDLE1BQU0sQ0FBQyxDQUFDO1FBQ2hDLE9BQU8sS0FBSyxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsQ0FBQztJQUM5QixDQUFDO0lBRUQ7O09BRUc7SUFDSCxNQUFNLENBQUMsT0FBTyxDQUFDLFNBQTRCLEVB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
|
|
@@ -1,287 +0,0 @@
|
|
|
1
|
-
import * as plugins from '../congodb.plugins.js';
|
|
2
|
-
import { CongoTransactionError, CongoWriteConflictError } from '../errors/CongoErrors.js';
|
|
3
|
-
/**
|
|
4
|
-
* Transaction engine for ACID transaction support
|
|
5
|
-
*/
|
|
6
|
-
export class TransactionEngine {
|
|
7
|
-
storage;
|
|
8
|
-
transactions = new Map();
|
|
9
|
-
txnCounter = 0;
|
|
10
|
-
constructor(storage) {
|
|
11
|
-
this.storage = storage;
|
|
12
|
-
}
|
|
13
|
-
/**
|
|
14
|
-
* Start a new transaction
|
|
15
|
-
*/
|
|
16
|
-
startTransaction(sessionId, options) {
|
|
17
|
-
this.txnCounter++;
|
|
18
|
-
const txnId = `txn_${sessionId}_${this.txnCounter}`;
|
|
19
|
-
const transaction = {
|
|
20
|
-
id: txnId,
|
|
21
|
-
sessionId,
|
|
22
|
-
startTime: new plugins.bson.Timestamp({ t: Math.floor(Date.now() / 1000), i: this.txnCounter }),
|
|
23
|
-
status: 'active',
|
|
24
|
-
readSet: new Map(),
|
|
25
|
-
writeSet: new Map(),
|
|
26
|
-
snapshots: new Map(),
|
|
27
|
-
};
|
|
28
|
-
this.transactions.set(txnId, transaction);
|
|
29
|
-
return txnId;
|
|
30
|
-
}
|
|
31
|
-
/**
|
|
32
|
-
* Get a transaction by ID
|
|
33
|
-
*/
|
|
34
|
-
getTransaction(txnId) {
|
|
35
|
-
return this.transactions.get(txnId);
|
|
36
|
-
}
|
|
37
|
-
/**
|
|
38
|
-
* Check if a transaction is active
|
|
39
|
-
*/
|
|
40
|
-
isActive(txnId) {
|
|
41
|
-
const txn = this.transactions.get(txnId);
|
|
42
|
-
return txn?.status === 'active';
|
|
43
|
-
}
|
|
44
|
-
/**
|
|
45
|
-
* Get or create a snapshot for a namespace
|
|
46
|
-
*/
|
|
47
|
-
async getSnapshot(txnId, dbName, collName) {
|
|
48
|
-
const txn = this.transactions.get(txnId);
|
|
49
|
-
if (!txn || txn.status !== 'active') {
|
|
50
|
-
throw new CongoTransactionError('Transaction is not active');
|
|
51
|
-
}
|
|
52
|
-
const ns = `${dbName}.${collName}`;
|
|
53
|
-
if (!txn.snapshots.has(ns)) {
|
|
54
|
-
const snapshot = await this.storage.createSnapshot(dbName, collName);
|
|
55
|
-
txn.snapshots.set(ns, snapshot);
|
|
56
|
-
}
|
|
57
|
-
// Apply transaction writes to snapshot
|
|
58
|
-
const snapshot = txn.snapshots.get(ns);
|
|
59
|
-
const writes = txn.writeSet.get(ns);
|
|
60
|
-
if (!writes) {
|
|
61
|
-
return snapshot;
|
|
62
|
-
}
|
|
63
|
-
// Create a modified view of the snapshot
|
|
64
|
-
const result = [];
|
|
65
|
-
const deletedIds = new Set();
|
|
66
|
-
const modifiedDocs = new Map();
|
|
67
|
-
for (const [idStr, write] of writes) {
|
|
68
|
-
if (write.op === 'delete') {
|
|
69
|
-
deletedIds.add(idStr);
|
|
70
|
-
}
|
|
71
|
-
else if (write.op === 'update' || write.op === 'insert') {
|
|
72
|
-
if (write.doc) {
|
|
73
|
-
modifiedDocs.set(idStr, write.doc);
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
// Add existing documents (not deleted, possibly modified)
|
|
78
|
-
for (const doc of snapshot) {
|
|
79
|
-
const idStr = doc._id.toHexString();
|
|
80
|
-
if (deletedIds.has(idStr)) {
|
|
81
|
-
continue;
|
|
82
|
-
}
|
|
83
|
-
if (modifiedDocs.has(idStr)) {
|
|
84
|
-
result.push(modifiedDocs.get(idStr));
|
|
85
|
-
modifiedDocs.delete(idStr);
|
|
86
|
-
}
|
|
87
|
-
else {
|
|
88
|
-
result.push(doc);
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
// Add new documents (inserts)
|
|
92
|
-
for (const doc of modifiedDocs.values()) {
|
|
93
|
-
result.push(doc);
|
|
94
|
-
}
|
|
95
|
-
return result;
|
|
96
|
-
}
|
|
97
|
-
/**
|
|
98
|
-
* Record a read operation
|
|
99
|
-
*/
|
|
100
|
-
recordRead(txnId, dbName, collName, docIds) {
|
|
101
|
-
const txn = this.transactions.get(txnId);
|
|
102
|
-
if (!txn || txn.status !== 'active')
|
|
103
|
-
return;
|
|
104
|
-
const ns = `${dbName}.${collName}`;
|
|
105
|
-
if (!txn.readSet.has(ns)) {
|
|
106
|
-
txn.readSet.set(ns, new Set());
|
|
107
|
-
}
|
|
108
|
-
const readSet = txn.readSet.get(ns);
|
|
109
|
-
for (const id of docIds) {
|
|
110
|
-
readSet.add(id);
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
/**
|
|
114
|
-
* Record a write operation (insert)
|
|
115
|
-
*/
|
|
116
|
-
recordInsert(txnId, dbName, collName, doc) {
|
|
117
|
-
const txn = this.transactions.get(txnId);
|
|
118
|
-
if (!txn || txn.status !== 'active') {
|
|
119
|
-
throw new CongoTransactionError('Transaction is not active');
|
|
120
|
-
}
|
|
121
|
-
const ns = `${dbName}.${collName}`;
|
|
122
|
-
if (!txn.writeSet.has(ns)) {
|
|
123
|
-
txn.writeSet.set(ns, new Map());
|
|
124
|
-
}
|
|
125
|
-
txn.writeSet.get(ns).set(doc._id.toHexString(), {
|
|
126
|
-
op: 'insert',
|
|
127
|
-
doc,
|
|
128
|
-
});
|
|
129
|
-
}
|
|
130
|
-
/**
|
|
131
|
-
* Record a write operation (update)
|
|
132
|
-
*/
|
|
133
|
-
recordUpdate(txnId, dbName, collName, originalDoc, updatedDoc) {
|
|
134
|
-
const txn = this.transactions.get(txnId);
|
|
135
|
-
if (!txn || txn.status !== 'active') {
|
|
136
|
-
throw new CongoTransactionError('Transaction is not active');
|
|
137
|
-
}
|
|
138
|
-
const ns = `${dbName}.${collName}`;
|
|
139
|
-
if (!txn.writeSet.has(ns)) {
|
|
140
|
-
txn.writeSet.set(ns, new Map());
|
|
141
|
-
}
|
|
142
|
-
const idStr = originalDoc._id.toHexString();
|
|
143
|
-
const existing = txn.writeSet.get(ns).get(idStr);
|
|
144
|
-
// If we already have a write for this document, update it
|
|
145
|
-
if (existing) {
|
|
146
|
-
existing.doc = updatedDoc;
|
|
147
|
-
}
|
|
148
|
-
else {
|
|
149
|
-
txn.writeSet.get(ns).set(idStr, {
|
|
150
|
-
op: 'update',
|
|
151
|
-
doc: updatedDoc,
|
|
152
|
-
originalDoc,
|
|
153
|
-
});
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
/**
|
|
157
|
-
* Record a write operation (delete)
|
|
158
|
-
*/
|
|
159
|
-
recordDelete(txnId, dbName, collName, doc) {
|
|
160
|
-
const txn = this.transactions.get(txnId);
|
|
161
|
-
if (!txn || txn.status !== 'active') {
|
|
162
|
-
throw new CongoTransactionError('Transaction is not active');
|
|
163
|
-
}
|
|
164
|
-
const ns = `${dbName}.${collName}`;
|
|
165
|
-
if (!txn.writeSet.has(ns)) {
|
|
166
|
-
txn.writeSet.set(ns, new Map());
|
|
167
|
-
}
|
|
168
|
-
const idStr = doc._id.toHexString();
|
|
169
|
-
const existing = txn.writeSet.get(ns).get(idStr);
|
|
170
|
-
if (existing && existing.op === 'insert') {
|
|
171
|
-
// If we inserted and then deleted, just remove the write
|
|
172
|
-
txn.writeSet.get(ns).delete(idStr);
|
|
173
|
-
}
|
|
174
|
-
else {
|
|
175
|
-
txn.writeSet.get(ns).set(idStr, {
|
|
176
|
-
op: 'delete',
|
|
177
|
-
originalDoc: doc,
|
|
178
|
-
});
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
/**
|
|
182
|
-
* Commit a transaction
|
|
183
|
-
*/
|
|
184
|
-
async commitTransaction(txnId) {
|
|
185
|
-
const txn = this.transactions.get(txnId);
|
|
186
|
-
if (!txn) {
|
|
187
|
-
throw new CongoTransactionError('Transaction not found');
|
|
188
|
-
}
|
|
189
|
-
if (txn.status !== 'active') {
|
|
190
|
-
throw new CongoTransactionError(`Cannot commit transaction in state: ${txn.status}`);
|
|
191
|
-
}
|
|
192
|
-
// Check for write conflicts
|
|
193
|
-
for (const [ns, writes] of txn.writeSet) {
|
|
194
|
-
const [dbName, collName] = ns.split('.');
|
|
195
|
-
const ids = Array.from(writes.keys()).map(id => new plugins.bson.ObjectId(id));
|
|
196
|
-
const hasConflicts = await this.storage.hasConflicts(dbName, collName, ids, txn.startTime);
|
|
197
|
-
if (hasConflicts) {
|
|
198
|
-
txn.status = 'aborted';
|
|
199
|
-
throw new CongoWriteConflictError();
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
// Apply all writes
|
|
203
|
-
for (const [ns, writes] of txn.writeSet) {
|
|
204
|
-
const [dbName, collName] = ns.split('.');
|
|
205
|
-
for (const [idStr, write] of writes) {
|
|
206
|
-
switch (write.op) {
|
|
207
|
-
case 'insert':
|
|
208
|
-
if (write.doc) {
|
|
209
|
-
await this.storage.insertOne(dbName, collName, write.doc);
|
|
210
|
-
}
|
|
211
|
-
break;
|
|
212
|
-
case 'update':
|
|
213
|
-
if (write.doc) {
|
|
214
|
-
await this.storage.updateById(dbName, collName, new plugins.bson.ObjectId(idStr), write.doc);
|
|
215
|
-
}
|
|
216
|
-
break;
|
|
217
|
-
case 'delete':
|
|
218
|
-
await this.storage.deleteById(dbName, collName, new plugins.bson.ObjectId(idStr));
|
|
219
|
-
break;
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
txn.status = 'committed';
|
|
224
|
-
}
|
|
225
|
-
/**
|
|
226
|
-
* Abort a transaction
|
|
227
|
-
*/
|
|
228
|
-
async abortTransaction(txnId) {
|
|
229
|
-
const txn = this.transactions.get(txnId);
|
|
230
|
-
if (!txn) {
|
|
231
|
-
throw new CongoTransactionError('Transaction not found');
|
|
232
|
-
}
|
|
233
|
-
if (txn.status !== 'active') {
|
|
234
|
-
// Already committed or aborted, just return
|
|
235
|
-
return;
|
|
236
|
-
}
|
|
237
|
-
// Simply discard all buffered writes
|
|
238
|
-
txn.writeSet.clear();
|
|
239
|
-
txn.readSet.clear();
|
|
240
|
-
txn.snapshots.clear();
|
|
241
|
-
txn.status = 'aborted';
|
|
242
|
-
}
|
|
243
|
-
/**
|
|
244
|
-
* End a transaction (cleanup)
|
|
245
|
-
*/
|
|
246
|
-
endTransaction(txnId) {
|
|
247
|
-
this.transactions.delete(txnId);
|
|
248
|
-
}
|
|
249
|
-
/**
|
|
250
|
-
* Get all pending writes for a namespace
|
|
251
|
-
*/
|
|
252
|
-
getPendingWrites(txnId, dbName, collName) {
|
|
253
|
-
const txn = this.transactions.get(txnId);
|
|
254
|
-
if (!txn)
|
|
255
|
-
return undefined;
|
|
256
|
-
const ns = `${dbName}.${collName}`;
|
|
257
|
-
return txn.writeSet.get(ns);
|
|
258
|
-
}
|
|
259
|
-
/**
|
|
260
|
-
* Execute a callback within a transaction, with automatic retry on conflict
|
|
261
|
-
*/
|
|
262
|
-
async withTransaction(sessionId, callback, options) {
|
|
263
|
-
const maxRetries = options?.maxRetries ?? 3;
|
|
264
|
-
let lastError;
|
|
265
|
-
for (let attempt = 0; attempt < maxRetries; attempt++) {
|
|
266
|
-
const txnId = this.startTransaction(sessionId, options);
|
|
267
|
-
try {
|
|
268
|
-
const result = await callback(txnId);
|
|
269
|
-
await this.commitTransaction(txnId);
|
|
270
|
-
this.endTransaction(txnId);
|
|
271
|
-
return result;
|
|
272
|
-
}
|
|
273
|
-
catch (error) {
|
|
274
|
-
await this.abortTransaction(txnId);
|
|
275
|
-
this.endTransaction(txnId);
|
|
276
|
-
if (error instanceof CongoWriteConflictError && attempt < maxRetries - 1) {
|
|
277
|
-
// Retry on write conflict
|
|
278
|
-
lastError = error;
|
|
279
|
-
continue;
|
|
280
|
-
}
|
|
281
|
-
throw error;
|
|
282
|
-
}
|
|
283
|
-
}
|
|
284
|
-
throw lastError || new CongoTransactionError('Transaction failed after max retries');
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiVHJhbnNhY3Rpb25FbmdpbmUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi90cy9jb25nb2RiL2VuZ2luZS9UcmFuc2FjdGlvbkVuZ2luZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssT0FBTyxNQUFNLHVCQUF1QixDQUFDO0FBR2pELE9BQU8sRUFBRSxxQkFBcUIsRUFBRSx1QkFBdUIsRUFBRSxNQUFNLDBCQUEwQixDQUFDO0FBZTFGOztHQUVHO0FBQ0gsTUFBTSxPQUFPLGlCQUFpQjtJQUNwQixPQUFPLENBQWtCO0lBQ3pCLFlBQVksR0FBbUMsSUFBSSxHQUFHLEVBQUUsQ0FBQztJQUN6RCxVQUFVLEdBQUcsQ0FBQyxDQUFDO0lBRXZCLFlBQVksT0FBd0I7UUFDbEMsSUFBSSxDQUFDLE9BQU8sR0FBRyxPQUFPLENBQUM7SUFDekIsQ0FBQztJQUVEOztPQUVHO0lBQ0gsZ0JBQWdCLENBQUMsU0FBaUIsRUFBRSxPQUE2QjtRQUMvRCxJQUFJLENBQUMsVUFBVSxFQUFFLENBQUM7UUFDbEIsTUFBTSxLQUFLLEdBQUcsT0FBTyxTQUFTLElBQUksSUFBSSxDQUFDLFVBQVUsRUFBRSxDQUFDO1FBRXBELE1BQU0sV0FBVyxHQUFzQjtZQUNyQyxFQUFFLEVBQUUsS0FBSztZQUNULFNBQVM7WUFDVCxTQUFTLEVBQUUsSUFBSSxPQUFPLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxFQUFFLENBQUMsRUFBRSxJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxHQUFHLEVBQUUsR0FBRyxJQUFJLENBQUMsRUFBRSxDQUFDLEVBQUUsSUFBSSxDQUFDLFVBQVUsRUFBRSxDQUFDO1lBQy9GLE1BQU0sRUFBRSxRQUFRO1lBQ2hCLE9BQU8sRUFBRSxJQUFJLEdBQUcsRUFBRTtZQUNsQixRQUFRLEVBQUUsSUFBSSxHQUFHLEVBQUU7WUFDbkIsU0FBUyxFQUFFLElBQUksR0FBRyxFQUFFO1NBQ3JCLENBQUM7UUFFRixJQUFJ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
|