@push.rocks/smartmongo 2.2.0 → 3.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/tsmdb/engine/IndexEngine.js +376 -0
- package/dist_ts/tsmdb/engine/QueryEngine.js +271 -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 +4 -4
- package/dist_ts/tsmdb/index.js +26 -0
- package/dist_ts/{congodb → tsmdb}/server/CommandRouter.d.ts +4 -4
- package/dist_ts/tsmdb/server/CommandRouter.js +132 -0
- package/dist_ts/{congodb/server/CongoServer.d.ts → tsmdb/server/TsmdbServer.d.ts} +6 -6
- package/dist_ts/tsmdb/server/TsmdbServer.js +227 -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 +568 -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 +83 -0
- package/dist_ts/{congodb → tsmdb}/server/handlers/FindHandler.d.ts +1 -1
- package/dist_ts/tsmdb/server/handlers/FindHandler.js +261 -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 +76 -0
- package/dist_ts/{congodb → tsmdb}/server/handlers/UpdateHandler.d.ts +1 -1
- package/dist_ts/tsmdb/server/handlers/UpdateHandler.js +270 -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 +2 -2
- package/dist_ts/tsmdb/storage/FileStorageAdapter.js +396 -0
- package/dist_ts/{congodb → tsmdb}/storage/IStorageAdapter.d.ts +2 -2
- package/dist_ts/{congodb → tsmdb}/storage/IStorageAdapter.js +1 -1
- package/dist_ts/{congodb → tsmdb}/storage/MemoryStorageAdapter.d.ts +2 -2
- package/dist_ts/tsmdb/storage/MemoryStorageAdapter.js +367 -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/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/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/{congodb → tsmdb}/engine/IndexEngine.ts +7 -7
- package/ts/{congodb → tsmdb}/engine/QueryEngine.ts +1 -1
- 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 +7 -7
- package/ts/{congodb → tsmdb}/server/CommandRouter.ts +5 -5
- package/ts/{congodb/server/CongoServer.ts → tsmdb/server/TsmdbServer.ts} +8 -8
- package/ts/{congodb → tsmdb}/server/WireProtocol.ts +1 -1
- package/ts/{congodb → tsmdb}/server/handlers/AdminHandler.ts +6 -6
- package/ts/{congodb → tsmdb}/server/handlers/AggregateHandler.ts +1 -1
- package/ts/{congodb → tsmdb}/server/handlers/DeleteHandler.ts +1 -1
- package/ts/{congodb → tsmdb}/server/handlers/FindHandler.ts +1 -1
- 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 +1 -1
- package/ts/{congodb → tsmdb}/server/handlers/UpdateHandler.ts +1 -1
- package/ts/{congodb → tsmdb}/server/index.ts +2 -2
- package/ts/{congodb → tsmdb}/storage/FileStorageAdapter.ts +2 -2
- package/ts/{congodb → tsmdb}/storage/IStorageAdapter.ts +2 -2
- package/ts/{congodb → tsmdb}/storage/MemoryStorageAdapter.ts +2 -2
- package/ts/{congodb → tsmdb}/storage/OpLog.ts +1 -1
- package/ts/{congodb → tsmdb}/types/interfaces.ts +3 -3
- 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.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/dist_ts/{congodb → tsmdb}/engine/AggregationEngine.d.ts +0 -0
- /package/dist_ts/{congodb → tsmdb}/engine/IndexEngine.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
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
export const commitinfo = {
|
|
5
5
|
name: '@push.rocks/smartmongo',
|
|
6
|
-
version: '
|
|
6
|
+
version: '3.0.0',
|
|
7
7
|
description: 'A module for creating and managing a local MongoDB instance for testing purposes.'
|
|
8
8
|
};
|
|
9
9
|
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiMDBfY29tbWl0aW5mb19kYXRhLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHMvMDBfY29tbWl0aW5mb19kYXRhLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOztHQUVHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sVUFBVSxHQUFHO0lBQ3hCLElBQUksRUFBRSx3QkFBd0I7SUFDOUIsT0FBTyxFQUFFLE9BQU87SUFDaEIsV0FBVyxFQUFFLG1GQUFtRjtDQUNqRyxDQUFBIn0=
|
package/dist_ts/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as plugins from './smartmongo.plugins.js';
|
|
2
|
-
export * as
|
|
2
|
+
export * as tsmdb from './tsmdb/index.js';
|
|
3
3
|
export declare class SmartMongo {
|
|
4
4
|
static createAndStart(replCountArg?: number): Promise<SmartMongo>;
|
|
5
5
|
private _readyDeferred;
|
package/dist_ts/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { commitinfo } from './00_commitinfo_data.js';
|
|
2
2
|
import * as plugins from './smartmongo.plugins.js';
|
|
3
|
-
// Export
|
|
4
|
-
export * as
|
|
3
|
+
// Export TsmDB module
|
|
4
|
+
export * as tsmdb from './tsmdb/index.js';
|
|
5
5
|
export class SmartMongo {
|
|
6
6
|
// STATIC
|
|
7
7
|
static async createAndStart(replCountArg = 1) {
|
|
@@ -58,4 +58,4 @@ export class SmartMongo {
|
|
|
58
58
|
await this.stop();
|
|
59
59
|
}
|
|
60
60
|
}
|
|
61
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
61
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90cy9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0seUJBQXlCLENBQUM7QUFDckQsT0FBTyxLQUFLLE9BQU8sTUFBTSx5QkFBeUIsQ0FBQztBQUVuRCxzQkFBc0I7QUFDdEIsT0FBTyxLQUFLLEtBQUssTUFBTSxrQkFBa0IsQ0FBQztBQUUxQyxNQUFNLE9BQU8sVUFBVTtJQUNyQixTQUFTO0lBQ0YsTUFBTSxDQUFDLEtBQUssQ0FBQyxjQUFjLENBQUMsZUFBdUIsQ0FBQztRQUN6RCxNQUFNLGtCQUFrQixHQUFHLElBQUksVUFBVSxFQUFFLENBQUM7UUFDNUMsTUFBTSxrQkFBa0IsQ0FBQyxLQUFLLENBQUMsWUFBWSxDQUFDLENBQUM7UUFDN0MsT0FBTyxrQkFBa0IsQ0FBQztJQUM1QixDQUFDO0lBRUQsV0FBVztJQUNILGNBQWMsR0FBRyxPQUFPLENBQUMsWUFBWSxDQUFDLEtBQUssRUFBRSxDQUFDO0lBQy9DLFlBQVksR0FBRyxJQUFJLENBQUMsY0FBYyxDQUFDLE9BQU8sQ0FBQztJQUMzQyxlQUFlLENBQXlDO0lBRS9ELGdCQUFlLENBQUM7SUFFVCxLQUFLLENBQUMsS0FBSyxDQUFDLFdBQW1CLENBQUM7UUFDckMsSUFBSSxDQUFDLGVBQWUsR0FBRyxNQUFNLE9BQU8sQ0FBQyxXQUFXLENBQUMsa0JBQWtCLENBQUMsTUFBTSxDQUFDO1lBQ3pFLE9BQU8sRUFBRSxFQUFFLEtBQUssRUFBRSxRQUFRLEVBQUU7WUFDNUIsWUFBWSxFQUFFO2dCQUNaO29CQUNFLGFBQWEsRUFBRSxZQUFZO2lCQUM1QjthQUNGO1NBQ0YsQ0FBQyxDQUFDO1FBQ0gsSUFBSSxDQUFDLGNBQWMsQ0FBQyxPQUFPLEVBQUUsQ0FBQztRQUM5QixPQUFPLENBQUMsR0FBRyxDQUFDLHdCQUF3QixRQUFRLG9CQUFvQixDQUFDLENBQUM7UUFDbEUsT0FBTyxDQUFDLEdBQUcsQ0FBQyxpQ0FBaUMsVUFBVSxDQUFDLE9BQU8sRUFBRSxDQUFDLENBQUM7SUFDckUsQ0FBQztJQUVEOzs7T0FHRztJQUNJLEtBQUssQ0FBQyxrQkFBa0I7UUFDN0IsTUFBTSxJQUFJLENBQUMsWUFBWSxDQUFDO1FBQ3hCLE9BQU87WUFDTCxXQUFXLEVBQUUseUJBQXlCO1lBQ3RDLFVBQVUsRUFBRSxJQUFJLENBQUMsZUFBZSxDQUFDLE1BQU0sRUFBRTtTQUMxQyxDQUFDO0lBQ0osQ0FBQztJQUVEOzs7T0FHRztJQUNJLEtBQUssQ0FBQyxJQUFJO1FBQ2YsTUFBTSxJQUFJLENBQUMsZUFBZSxDQUFDLElBQUksRUFBRSxDQUFDO1FBQ2xDLE1BQU0sSUFBSSxDQUFDLGVBQWUsQ0FBQyxPQUFPLEVBQUUsQ0FBQztJQUN2QyxDQUFDO0lBRUQ7OztPQUdHO0lBQ0ksS0FBSyxDQUFDLGdCQUFnQixDQUMzQixNQUFjLEVBQ2QsZUFBc0MsRUFDdEMsV0FBVyxHQUFHLElBQUk7UUFFbEIsTUFBTSxpQkFBaUIsR0FBRyxJQUFJLE9BQU8sQ0FBQyxTQUFTLENBQUMsU0FBUyxFQUFFLENBQUM7UUFDNUQsTUFBTSxlQUFlLEdBQUcsTUFBTSxpQkFBaUIsQ0FBQywrQkFBK0IsQ0FDN0UsTUFBTSxJQUFJLENBQUMsa0JBQWtCLEVBQUUsQ0FDaEMsQ0FBQztRQUNGLE1BQU0sZUFBZSxDQUFDLHVCQUF1QixDQUFDLE1BQU0sRUFBRSxlQUFlLEVBQUUsV0FBVyxDQUFDLENBQUM7UUFDcEYsTUFBTSxpQkFBaUIsQ0FBQyxJQUFJLEVBQUUsQ0FBQztRQUMvQixNQUFNLElBQUksQ0FBQyxJQUFJLEVBQUUsQ0FBQztJQUNwQixDQUFDO0NBQ0YifQ==
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
import * as plugins from '../tsmdb.plugins.js';
|
|
2
|
+
// Import mingo Aggregator
|
|
3
|
+
import { Aggregator } from 'mingo';
|
|
4
|
+
/**
|
|
5
|
+
* Aggregation engine using mingo for MongoDB-compatible aggregation pipeline execution
|
|
6
|
+
*/
|
|
7
|
+
export class AggregationEngine {
|
|
8
|
+
/**
|
|
9
|
+
* Execute an aggregation pipeline on a collection of documents
|
|
10
|
+
*/
|
|
11
|
+
static aggregate(documents, pipeline, options) {
|
|
12
|
+
if (!pipeline || pipeline.length === 0) {
|
|
13
|
+
return documents;
|
|
14
|
+
}
|
|
15
|
+
// Create mingo aggregator with the pipeline
|
|
16
|
+
const aggregator = new Aggregator(pipeline, {
|
|
17
|
+
collation: options?.collation,
|
|
18
|
+
});
|
|
19
|
+
// Run the aggregation
|
|
20
|
+
const result = aggregator.run(documents);
|
|
21
|
+
return Array.isArray(result) ? result : [];
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Execute aggregation and return an iterator for lazy evaluation
|
|
25
|
+
*/
|
|
26
|
+
static *aggregateIterator(documents, pipeline, options) {
|
|
27
|
+
const aggregator = new Aggregator(pipeline, {
|
|
28
|
+
collation: options?.collation,
|
|
29
|
+
});
|
|
30
|
+
// Get the cursor from mingo
|
|
31
|
+
const cursor = aggregator.stream(documents);
|
|
32
|
+
for (const doc of cursor) {
|
|
33
|
+
yield doc;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Execute a $lookup stage manually (for cross-collection lookups)
|
|
38
|
+
* This is used when the lookup references another collection in the same database
|
|
39
|
+
*/
|
|
40
|
+
static executeLookup(documents, lookupSpec, foreignCollection) {
|
|
41
|
+
const { localField, foreignField, as } = lookupSpec;
|
|
42
|
+
return documents.map(doc => {
|
|
43
|
+
const localValue = this.getNestedValue(doc, localField);
|
|
44
|
+
const matches = foreignCollection.filter(foreignDoc => {
|
|
45
|
+
const foreignValue = this.getNestedValue(foreignDoc, foreignField);
|
|
46
|
+
return this.valuesMatch(localValue, foreignValue);
|
|
47
|
+
});
|
|
48
|
+
return {
|
|
49
|
+
...doc,
|
|
50
|
+
[as]: matches,
|
|
51
|
+
};
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Execute a $graphLookup stage manually
|
|
56
|
+
*/
|
|
57
|
+
static executeGraphLookup(documents, graphLookupSpec, foreignCollection) {
|
|
58
|
+
const { startWith, connectFromField, connectToField, as, maxDepth = 10, depthField, restrictSearchWithMatch, } = graphLookupSpec;
|
|
59
|
+
return documents.map(doc => {
|
|
60
|
+
const startValue = typeof startWith === 'string' && startWith.startsWith('$')
|
|
61
|
+
? this.getNestedValue(doc, startWith.slice(1))
|
|
62
|
+
: startWith;
|
|
63
|
+
const results = [];
|
|
64
|
+
const visited = new Set();
|
|
65
|
+
const queue = [];
|
|
66
|
+
// Initialize with start value(s)
|
|
67
|
+
const startValues = Array.isArray(startValue) ? startValue : [startValue];
|
|
68
|
+
for (const val of startValues) {
|
|
69
|
+
queue.push({ value: val, depth: 0 });
|
|
70
|
+
}
|
|
71
|
+
while (queue.length > 0) {
|
|
72
|
+
const { value, depth } = queue.shift();
|
|
73
|
+
if (depth > maxDepth)
|
|
74
|
+
continue;
|
|
75
|
+
const valueKey = JSON.stringify(value);
|
|
76
|
+
if (visited.has(valueKey))
|
|
77
|
+
continue;
|
|
78
|
+
visited.add(valueKey);
|
|
79
|
+
// Find matching documents
|
|
80
|
+
for (const foreignDoc of foreignCollection) {
|
|
81
|
+
const foreignValue = this.getNestedValue(foreignDoc, connectToField);
|
|
82
|
+
if (this.valuesMatch(value, foreignValue)) {
|
|
83
|
+
// Check restrictSearchWithMatch
|
|
84
|
+
if (restrictSearchWithMatch) {
|
|
85
|
+
const matchQuery = new plugins.mingo.Query(restrictSearchWithMatch);
|
|
86
|
+
if (!matchQuery.test(foreignDoc))
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
const resultDoc = depthField
|
|
90
|
+
? { ...foreignDoc, [depthField]: depth }
|
|
91
|
+
: { ...foreignDoc };
|
|
92
|
+
// Avoid duplicates in results
|
|
93
|
+
const docKey = foreignDoc._id.toHexString();
|
|
94
|
+
if (!results.some(r => r._id?.toHexString?.() === docKey)) {
|
|
95
|
+
results.push(resultDoc);
|
|
96
|
+
// Add connected values to queue
|
|
97
|
+
const nextValue = this.getNestedValue(foreignDoc, connectFromField);
|
|
98
|
+
if (nextValue !== undefined) {
|
|
99
|
+
const nextValues = Array.isArray(nextValue) ? nextValue : [nextValue];
|
|
100
|
+
for (const nv of nextValues) {
|
|
101
|
+
queue.push({ value: nv, depth: depth + 1 });
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
return {
|
|
109
|
+
...doc,
|
|
110
|
+
[as]: results,
|
|
111
|
+
};
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Execute a $facet stage manually
|
|
116
|
+
*/
|
|
117
|
+
static executeFacet(documents, facetSpec) {
|
|
118
|
+
const result = {};
|
|
119
|
+
for (const [facetName, pipeline] of Object.entries(facetSpec)) {
|
|
120
|
+
result[facetName] = this.aggregate(documents, pipeline);
|
|
121
|
+
}
|
|
122
|
+
return result;
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Execute a $unionWith stage
|
|
126
|
+
*/
|
|
127
|
+
static executeUnionWith(documents, otherDocuments, pipeline) {
|
|
128
|
+
let unionDocs = otherDocuments;
|
|
129
|
+
if (pipeline && pipeline.length > 0) {
|
|
130
|
+
unionDocs = this.aggregate(otherDocuments, pipeline);
|
|
131
|
+
}
|
|
132
|
+
return [...documents, ...unionDocs];
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Execute a $merge stage (output to another collection)
|
|
136
|
+
* Returns the documents that would be inserted/updated
|
|
137
|
+
*/
|
|
138
|
+
static prepareMerge(documents, mergeSpec) {
|
|
139
|
+
const onField = mergeSpec.on || '_id';
|
|
140
|
+
const whenMatched = mergeSpec.whenMatched || 'merge';
|
|
141
|
+
const whenNotMatched = mergeSpec.whenNotMatched || 'insert';
|
|
142
|
+
return {
|
|
143
|
+
toInsert: [],
|
|
144
|
+
toUpdate: [],
|
|
145
|
+
onField,
|
|
146
|
+
whenMatched,
|
|
147
|
+
whenNotMatched,
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
// ============================================================================
|
|
151
|
+
// Helper Methods
|
|
152
|
+
// ============================================================================
|
|
153
|
+
static getNestedValue(obj, path) {
|
|
154
|
+
const parts = path.split('.');
|
|
155
|
+
let current = obj;
|
|
156
|
+
for (const part of parts) {
|
|
157
|
+
if (current === null || current === undefined) {
|
|
158
|
+
return undefined;
|
|
159
|
+
}
|
|
160
|
+
current = current[part];
|
|
161
|
+
}
|
|
162
|
+
return current;
|
|
163
|
+
}
|
|
164
|
+
static valuesMatch(a, b) {
|
|
165
|
+
if (a === b)
|
|
166
|
+
return true;
|
|
167
|
+
// Handle ObjectId comparison
|
|
168
|
+
if (a instanceof plugins.bson.ObjectId && b instanceof plugins.bson.ObjectId) {
|
|
169
|
+
return a.equals(b);
|
|
170
|
+
}
|
|
171
|
+
// Handle array contains check
|
|
172
|
+
if (Array.isArray(a)) {
|
|
173
|
+
return a.some(item => this.valuesMatch(item, b));
|
|
174
|
+
}
|
|
175
|
+
if (Array.isArray(b)) {
|
|
176
|
+
return b.some(item => this.valuesMatch(a, item));
|
|
177
|
+
}
|
|
178
|
+
// Handle Date comparison
|
|
179
|
+
if (a instanceof Date && b instanceof Date) {
|
|
180
|
+
return a.getTime() === b.getTime();
|
|
181
|
+
}
|
|
182
|
+
// Handle object comparison
|
|
183
|
+
if (typeof a === 'object' && typeof b === 'object' && a !== null && b !== null) {
|
|
184
|
+
return JSON.stringify(a) === JSON.stringify(b);
|
|
185
|
+
}
|
|
186
|
+
return false;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQWdncmVnYXRpb25FbmdpbmUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi90cy90c21kYi9lbmdpbmUvQWdncmVnYXRpb25FbmdpbmUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLE9BQU8sTUFBTSxxQkFBcUIsQ0FBQztBQUcvQywwQkFBMEI7QUFDMUIsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLE9BQU8sQ0FBQztBQUVuQzs7R0FFRztBQUNILE1BQU0sT0FBTyxpQkFBaUI7SUFDNUI7O09BRUc7SUFDSCxNQUFNLENBQUMsU0FBUyxDQUNkLFNBQTRCLEVBQzVCLFFBQW9CLEVBQ3BCLE9BQTJCO1FBRTNCLElBQUksQ0FBQyxRQUFRLElBQUksUUFBUSxDQUFDLE1BQU0sS0FBSyxDQUFDLEVBQUUsQ0FBQztZQUN2QyxPQUFPLFNBQVMsQ0FBQztRQUNuQixDQUFDO1FBRUQsNENBQTRDO1FBQzVDLE1BQU0sVUFBVSxHQUFHLElBQUksVUFBVSxDQUFDLFFBQVEsRUFBRTtZQUMxQyxTQUFTLEVBQUUsT0FBTyxFQUFFLFNBQWdCO1NBQ3JDLENBQUMsQ0FBQztRQUVILHNCQUFzQjtRQUN0QixNQUFNLE1BQU0sR0FBRyxVQUFVLENBQUMsR0FBRyxDQUFDLFNBQVMsQ0FBQyxDQUFDO1FBRXpDLE9BQU8sS0FBSyxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUM7SUFDN0MsQ0FBQztJQUVEOztPQUVHO0lBQ0gsTUFBTSxDQUFDLENBQUMsaUJBQWlCLENBQ3ZCLFNBQTRCLEVBQzVCLFFBQW9CLEVBQ3BCLE9BQTJCO1FBRTNCLE1BQU0sVUFBVSxHQUFHLElBQUksVUFBVSxDQUFDLFFBQVEsRUFBRTtZQUMxQyxTQUFTLEVBQUUsT0FBTyxFQUFFLFNBQWdCO1NBQ3JDLENBQUMsQ0FBQztRQUVILDRCQUE0QjtRQUM1QixNQUFNLE1BQU0sR0FBRyxV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
|
|
@@ -0,0 +1,376 @@
|
|
|
1
|
+
import * as plugins from '../tsmdb.plugins.js';
|
|
2
|
+
import { TsmdbDuplicateKeyError, TsmdbIndexError } from '../errors/TsmdbErrors.js';
|
|
3
|
+
import { QueryEngine } from './QueryEngine.js';
|
|
4
|
+
/**
|
|
5
|
+
* Index engine for managing indexes and query optimization
|
|
6
|
+
*/
|
|
7
|
+
export class IndexEngine {
|
|
8
|
+
dbName;
|
|
9
|
+
collName;
|
|
10
|
+
storage;
|
|
11
|
+
indexes = new Map();
|
|
12
|
+
initialized = false;
|
|
13
|
+
constructor(dbName, collName, storage) {
|
|
14
|
+
this.dbName = dbName;
|
|
15
|
+
this.collName = collName;
|
|
16
|
+
this.storage = storage;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Initialize indexes from storage
|
|
20
|
+
*/
|
|
21
|
+
async initialize() {
|
|
22
|
+
if (this.initialized)
|
|
23
|
+
return;
|
|
24
|
+
const storedIndexes = await this.storage.getIndexes(this.dbName, this.collName);
|
|
25
|
+
const documents = await this.storage.findAll(this.dbName, this.collName);
|
|
26
|
+
for (const indexSpec of storedIndexes) {
|
|
27
|
+
const indexData = {
|
|
28
|
+
name: indexSpec.name,
|
|
29
|
+
key: indexSpec.key,
|
|
30
|
+
unique: indexSpec.unique || false,
|
|
31
|
+
sparse: indexSpec.sparse || false,
|
|
32
|
+
expireAfterSeconds: indexSpec.expireAfterSeconds,
|
|
33
|
+
entries: new Map(),
|
|
34
|
+
};
|
|
35
|
+
// Build index entries
|
|
36
|
+
for (const doc of documents) {
|
|
37
|
+
const keyValue = this.extractKeyValue(doc, indexSpec.key);
|
|
38
|
+
if (keyValue !== null || !indexData.sparse) {
|
|
39
|
+
const keyStr = JSON.stringify(keyValue);
|
|
40
|
+
if (!indexData.entries.has(keyStr)) {
|
|
41
|
+
indexData.entries.set(keyStr, new Set());
|
|
42
|
+
}
|
|
43
|
+
indexData.entries.get(keyStr).add(doc._id.toHexString());
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
this.indexes.set(indexSpec.name, indexData);
|
|
47
|
+
}
|
|
48
|
+
this.initialized = true;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Create a new index
|
|
52
|
+
*/
|
|
53
|
+
async createIndex(key, options) {
|
|
54
|
+
await this.initialize();
|
|
55
|
+
// Generate index name if not provided
|
|
56
|
+
const name = options?.name || this.generateIndexName(key);
|
|
57
|
+
// Check if index already exists
|
|
58
|
+
if (this.indexes.has(name)) {
|
|
59
|
+
return name;
|
|
60
|
+
}
|
|
61
|
+
// Create index data structure
|
|
62
|
+
const indexData = {
|
|
63
|
+
name,
|
|
64
|
+
key: key,
|
|
65
|
+
unique: options?.unique || false,
|
|
66
|
+
sparse: options?.sparse || false,
|
|
67
|
+
expireAfterSeconds: options?.expireAfterSeconds,
|
|
68
|
+
entries: new Map(),
|
|
69
|
+
};
|
|
70
|
+
// Build index from existing documents
|
|
71
|
+
const documents = await this.storage.findAll(this.dbName, this.collName);
|
|
72
|
+
for (const doc of documents) {
|
|
73
|
+
const keyValue = this.extractKeyValue(doc, key);
|
|
74
|
+
if (keyValue === null && indexData.sparse) {
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
const keyStr = JSON.stringify(keyValue);
|
|
78
|
+
if (indexData.unique && indexData.entries.has(keyStr)) {
|
|
79
|
+
throw new TsmdbDuplicateKeyError(`E11000 duplicate key error index: ${this.dbName}.${this.collName}.$${name}`, key, keyValue);
|
|
80
|
+
}
|
|
81
|
+
if (!indexData.entries.has(keyStr)) {
|
|
82
|
+
indexData.entries.set(keyStr, new Set());
|
|
83
|
+
}
|
|
84
|
+
indexData.entries.get(keyStr).add(doc._id.toHexString());
|
|
85
|
+
}
|
|
86
|
+
// Store index
|
|
87
|
+
this.indexes.set(name, indexData);
|
|
88
|
+
await this.storage.saveIndex(this.dbName, this.collName, name, {
|
|
89
|
+
key,
|
|
90
|
+
unique: options?.unique,
|
|
91
|
+
sparse: options?.sparse,
|
|
92
|
+
expireAfterSeconds: options?.expireAfterSeconds,
|
|
93
|
+
});
|
|
94
|
+
return name;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Drop an index
|
|
98
|
+
*/
|
|
99
|
+
async dropIndex(name) {
|
|
100
|
+
await this.initialize();
|
|
101
|
+
if (name === '_id_') {
|
|
102
|
+
throw new TsmdbIndexError('cannot drop _id index');
|
|
103
|
+
}
|
|
104
|
+
if (!this.indexes.has(name)) {
|
|
105
|
+
throw new TsmdbIndexError(`index not found: ${name}`);
|
|
106
|
+
}
|
|
107
|
+
this.indexes.delete(name);
|
|
108
|
+
await this.storage.dropIndex(this.dbName, this.collName, name);
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Drop all indexes except _id
|
|
112
|
+
*/
|
|
113
|
+
async dropAllIndexes() {
|
|
114
|
+
await this.initialize();
|
|
115
|
+
const names = Array.from(this.indexes.keys()).filter(n => n !== '_id_');
|
|
116
|
+
for (const name of names) {
|
|
117
|
+
this.indexes.delete(name);
|
|
118
|
+
await this.storage.dropIndex(this.dbName, this.collName, name);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* List all indexes
|
|
123
|
+
*/
|
|
124
|
+
async listIndexes() {
|
|
125
|
+
await this.initialize();
|
|
126
|
+
return Array.from(this.indexes.values()).map(idx => ({
|
|
127
|
+
v: 2,
|
|
128
|
+
key: idx.key,
|
|
129
|
+
name: idx.name,
|
|
130
|
+
unique: idx.unique || undefined,
|
|
131
|
+
sparse: idx.sparse || undefined,
|
|
132
|
+
expireAfterSeconds: idx.expireAfterSeconds,
|
|
133
|
+
}));
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Check if an index exists
|
|
137
|
+
*/
|
|
138
|
+
async indexExists(name) {
|
|
139
|
+
await this.initialize();
|
|
140
|
+
return this.indexes.has(name);
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Update index entries after document insert
|
|
144
|
+
*/
|
|
145
|
+
async onInsert(doc) {
|
|
146
|
+
await this.initialize();
|
|
147
|
+
for (const [name, indexData] of this.indexes) {
|
|
148
|
+
const keyValue = this.extractKeyValue(doc, indexData.key);
|
|
149
|
+
if (keyValue === null && indexData.sparse) {
|
|
150
|
+
continue;
|
|
151
|
+
}
|
|
152
|
+
const keyStr = JSON.stringify(keyValue);
|
|
153
|
+
// Check unique constraint
|
|
154
|
+
if (indexData.unique) {
|
|
155
|
+
const existing = indexData.entries.get(keyStr);
|
|
156
|
+
if (existing && existing.size > 0) {
|
|
157
|
+
throw new TsmdbDuplicateKeyError(`E11000 duplicate key error collection: ${this.dbName}.${this.collName} index: ${name}`, indexData.key, keyValue);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
if (!indexData.entries.has(keyStr)) {
|
|
161
|
+
indexData.entries.set(keyStr, new Set());
|
|
162
|
+
}
|
|
163
|
+
indexData.entries.get(keyStr).add(doc._id.toHexString());
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Update index entries after document update
|
|
168
|
+
*/
|
|
169
|
+
async onUpdate(oldDoc, newDoc) {
|
|
170
|
+
await this.initialize();
|
|
171
|
+
for (const [name, indexData] of this.indexes) {
|
|
172
|
+
const oldKeyValue = this.extractKeyValue(oldDoc, indexData.key);
|
|
173
|
+
const newKeyValue = this.extractKeyValue(newDoc, indexData.key);
|
|
174
|
+
const oldKeyStr = JSON.stringify(oldKeyValue);
|
|
175
|
+
const newKeyStr = JSON.stringify(newKeyValue);
|
|
176
|
+
// Remove old entry if key changed
|
|
177
|
+
if (oldKeyStr !== newKeyStr) {
|
|
178
|
+
if (oldKeyValue !== null || !indexData.sparse) {
|
|
179
|
+
const oldSet = indexData.entries.get(oldKeyStr);
|
|
180
|
+
if (oldSet) {
|
|
181
|
+
oldSet.delete(oldDoc._id.toHexString());
|
|
182
|
+
if (oldSet.size === 0) {
|
|
183
|
+
indexData.entries.delete(oldKeyStr);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
// Add new entry
|
|
188
|
+
if (newKeyValue !== null || !indexData.sparse) {
|
|
189
|
+
// Check unique constraint
|
|
190
|
+
if (indexData.unique) {
|
|
191
|
+
const existing = indexData.entries.get(newKeyStr);
|
|
192
|
+
if (existing && existing.size > 0) {
|
|
193
|
+
throw new TsmdbDuplicateKeyError(`E11000 duplicate key error collection: ${this.dbName}.${this.collName} index: ${name}`, indexData.key, newKeyValue);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
if (!indexData.entries.has(newKeyStr)) {
|
|
197
|
+
indexData.entries.set(newKeyStr, new Set());
|
|
198
|
+
}
|
|
199
|
+
indexData.entries.get(newKeyStr).add(newDoc._id.toHexString());
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* Update index entries after document delete
|
|
206
|
+
*/
|
|
207
|
+
async onDelete(doc) {
|
|
208
|
+
await this.initialize();
|
|
209
|
+
for (const indexData of this.indexes.values()) {
|
|
210
|
+
const keyValue = this.extractKeyValue(doc, indexData.key);
|
|
211
|
+
if (keyValue === null && indexData.sparse) {
|
|
212
|
+
continue;
|
|
213
|
+
}
|
|
214
|
+
const keyStr = JSON.stringify(keyValue);
|
|
215
|
+
const set = indexData.entries.get(keyStr);
|
|
216
|
+
if (set) {
|
|
217
|
+
set.delete(doc._id.toHexString());
|
|
218
|
+
if (set.size === 0) {
|
|
219
|
+
indexData.entries.delete(keyStr);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
/**
|
|
225
|
+
* Find the best index for a query
|
|
226
|
+
*/
|
|
227
|
+
selectIndex(filter) {
|
|
228
|
+
if (!filter || Object.keys(filter).length === 0) {
|
|
229
|
+
return null;
|
|
230
|
+
}
|
|
231
|
+
// Get filter fields
|
|
232
|
+
const filterFields = new Set(this.getFilterFields(filter));
|
|
233
|
+
// Score each index
|
|
234
|
+
let bestIndex = null;
|
|
235
|
+
let bestScore = 0;
|
|
236
|
+
for (const [name, indexData] of this.indexes) {
|
|
237
|
+
const indexFields = Object.keys(indexData.key);
|
|
238
|
+
let score = 0;
|
|
239
|
+
// Count how many index fields are in the filter
|
|
240
|
+
for (const field of indexFields) {
|
|
241
|
+
if (filterFields.has(field)) {
|
|
242
|
+
score++;
|
|
243
|
+
}
|
|
244
|
+
else {
|
|
245
|
+
break; // Index fields must be contiguous
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
// Prefer unique indexes
|
|
249
|
+
if (indexData.unique && score > 0) {
|
|
250
|
+
score += 0.5;
|
|
251
|
+
}
|
|
252
|
+
if (score > bestScore) {
|
|
253
|
+
bestScore = score;
|
|
254
|
+
bestIndex = { name, data: indexData };
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
return bestIndex;
|
|
258
|
+
}
|
|
259
|
+
/**
|
|
260
|
+
* Use index to find candidate document IDs
|
|
261
|
+
*/
|
|
262
|
+
async findCandidateIds(filter) {
|
|
263
|
+
await this.initialize();
|
|
264
|
+
const index = this.selectIndex(filter);
|
|
265
|
+
if (!index)
|
|
266
|
+
return null;
|
|
267
|
+
// Try to use the index for equality matches
|
|
268
|
+
const indexFields = Object.keys(index.data.key);
|
|
269
|
+
const equalityValues = {};
|
|
270
|
+
for (const field of indexFields) {
|
|
271
|
+
const filterValue = this.getFilterValue(filter, field);
|
|
272
|
+
if (filterValue === undefined)
|
|
273
|
+
break;
|
|
274
|
+
// Only use equality matches for index lookup
|
|
275
|
+
if (typeof filterValue === 'object' && filterValue !== null) {
|
|
276
|
+
if (filterValue.$eq !== undefined) {
|
|
277
|
+
equalityValues[field] = filterValue.$eq;
|
|
278
|
+
}
|
|
279
|
+
else if (filterValue.$in !== undefined) {
|
|
280
|
+
// Handle $in with multiple lookups
|
|
281
|
+
const results = new Set();
|
|
282
|
+
for (const val of filterValue.$in) {
|
|
283
|
+
equalityValues[field] = val;
|
|
284
|
+
const keyStr = JSON.stringify(this.buildKeyValue(equalityValues, index.data.key));
|
|
285
|
+
const ids = index.data.entries.get(keyStr);
|
|
286
|
+
if (ids) {
|
|
287
|
+
for (const id of ids) {
|
|
288
|
+
results.add(id);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
return results;
|
|
293
|
+
}
|
|
294
|
+
else {
|
|
295
|
+
break; // Non-equality operator, stop here
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
else {
|
|
299
|
+
equalityValues[field] = filterValue;
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
if (Object.keys(equalityValues).length === 0) {
|
|
303
|
+
return null;
|
|
304
|
+
}
|
|
305
|
+
const keyStr = JSON.stringify(this.buildKeyValue(equalityValues, index.data.key));
|
|
306
|
+
return index.data.entries.get(keyStr) || new Set();
|
|
307
|
+
}
|
|
308
|
+
// ============================================================================
|
|
309
|
+
// Helper Methods
|
|
310
|
+
// ============================================================================
|
|
311
|
+
generateIndexName(key) {
|
|
312
|
+
return Object.entries(key)
|
|
313
|
+
.map(([field, dir]) => `${field}_${dir}`)
|
|
314
|
+
.join('_');
|
|
315
|
+
}
|
|
316
|
+
extractKeyValue(doc, key) {
|
|
317
|
+
const values = [];
|
|
318
|
+
for (const field of Object.keys(key)) {
|
|
319
|
+
const value = QueryEngine.getNestedValue(doc, field);
|
|
320
|
+
values.push(value === undefined ? null : value);
|
|
321
|
+
}
|
|
322
|
+
// For single-field index, return the value directly
|
|
323
|
+
if (values.length === 1) {
|
|
324
|
+
return values[0];
|
|
325
|
+
}
|
|
326
|
+
return values;
|
|
327
|
+
}
|
|
328
|
+
buildKeyValue(values, key) {
|
|
329
|
+
const result = [];
|
|
330
|
+
for (const field of Object.keys(key)) {
|
|
331
|
+
result.push(values[field] !== undefined ? values[field] : null);
|
|
332
|
+
}
|
|
333
|
+
if (result.length === 1) {
|
|
334
|
+
return result[0];
|
|
335
|
+
}
|
|
336
|
+
return result;
|
|
337
|
+
}
|
|
338
|
+
getFilterFields(filter, prefix = '') {
|
|
339
|
+
const fields = [];
|
|
340
|
+
for (const [key, value] of Object.entries(filter)) {
|
|
341
|
+
if (key.startsWith('$')) {
|
|
342
|
+
// Logical operator
|
|
343
|
+
if (key === '$and' || key === '$or' || key === '$nor') {
|
|
344
|
+
for (const subFilter of value) {
|
|
345
|
+
fields.push(...this.getFilterFields(subFilter, prefix));
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
else {
|
|
350
|
+
const fullKey = prefix ? `${prefix}.${key}` : key;
|
|
351
|
+
fields.push(fullKey);
|
|
352
|
+
// Check for nested filters
|
|
353
|
+
if (typeof value === 'object' && value !== null && !Array.isArray(value)) {
|
|
354
|
+
const subKeys = Object.keys(value);
|
|
355
|
+
if (subKeys.length > 0 && !subKeys[0].startsWith('$')) {
|
|
356
|
+
fields.push(...this.getFilterFields(value, fullKey));
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
return fields;
|
|
362
|
+
}
|
|
363
|
+
getFilterValue(filter, field) {
|
|
364
|
+
// Handle dot notation
|
|
365
|
+
const parts = field.split('.');
|
|
366
|
+
let current = filter;
|
|
367
|
+
for (const part of parts) {
|
|
368
|
+
if (current === null || current === undefined) {
|
|
369
|
+
return undefined;
|
|
370
|
+
}
|
|
371
|
+
current = current[part];
|
|
372
|
+
}
|
|
373
|
+
return current;
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiSW5kZXhFbmdpbmUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi90cy90c21kYi9lbmdpbmUvSW5kZXhFbmdpbmUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLE9BQU8sTUFBTSxxQkFBcUIsQ0FBQztBQVMvQyxPQUFPLEVBQUUsc0JBQXNCLEVBQUUsZUFBZSxFQUFFLE1BQU0sMEJBQTBCLENBQUM7QUFDbkYsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLGtCQUFrQixDQUFDO0FBZS9DOztHQUVHO0FBQ0gsTUFBTSxPQUFPLFdBQVc7SUFDZCxNQUFNLENBQVM7SUFDZixRQUFRLENBQVM7SUFDakIsT0FBTyxDQUFrQjtJQUN6QixPQUFPLEdBQTRCLElBQUksR0FBRyxFQUFFLENBQUM7SUFDN0MsV0FBVyxHQUFHLEtBQUssQ0FBQztJQUU1QixZQUFZLE1BQWMsRUFBRSxRQUFnQixFQUFFLE9BQXdCO1FBQ3BFLElBQUksQ0FBQyxNQUFNLEdBQUcsTUFBTSxDQUFDO1FBQ3JCLElBQUksQ0FBQyxRQUFRLEdBQUcsUUFBUSxDQUFDO1FBQ3pCLElBQUksQ0FBQyxPQUFPLEdBQUcsT0FBTyxDQUFDO0lBQ3pCLENBQUM7SUFFRDs7T0FFRztJQUNILEtBQUssQ0FBQyxVQUFVO1FBQ2QsSUFBSSxJQUFJLENBQUMsV0FBVztZQUFFLE9BQU87UUFFN0IsTUFBTSxhQUFhLEdBQUcsTUFBTSxJQUFJLENBQUMsT0FBTyxDQUFDLFVBQVUsQ0FBQyxJQUFJLENBQUMsTUFBTSxFQUFFLElBQUksQ0FBQyxRQUFRLENBQUMsQ0FBQztRQUNoRixNQUFNLFNBQVMsR0FBRyxNQUFNLElBQUksQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxNQUFNLEVBQUUsSUFBSSxDQUFDLFFBQVEsQ0FBQyxDQUFDO1FBRXpFLEtBQUssTUFBTSxTQUFTLElBQUksYUFBYSxFQUFFLENBQUM7WUFDdEMsTUFBTSxTQUFTLEdBQWU7Z0JBQzVC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
|