@push.rocks/smartmongo 2.2.0 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (126) hide show
  1. package/dist_ts/00_commitinfo_data.js +1 -1
  2. package/dist_ts/index.d.ts +1 -1
  3. package/dist_ts/index.js +3 -3
  4. package/dist_ts/tsmdb/engine/AggregationEngine.js +189 -0
  5. package/dist_ts/{congodb → tsmdb}/engine/IndexEngine.d.ts +23 -3
  6. package/dist_ts/tsmdb/engine/IndexEngine.js +678 -0
  7. package/dist_ts/tsmdb/engine/QueryEngine.js +271 -0
  8. package/dist_ts/tsmdb/engine/QueryPlanner.d.ts +64 -0
  9. package/dist_ts/tsmdb/engine/QueryPlanner.js +308 -0
  10. package/dist_ts/tsmdb/engine/SessionEngine.d.ts +117 -0
  11. package/dist_ts/tsmdb/engine/SessionEngine.js +232 -0
  12. package/dist_ts/{congodb → tsmdb}/engine/TransactionEngine.d.ts +1 -1
  13. package/dist_ts/tsmdb/engine/TransactionEngine.js +287 -0
  14. package/dist_ts/tsmdb/engine/UpdateEngine.js +461 -0
  15. package/dist_ts/{congodb/errors/CongoErrors.d.ts → tsmdb/errors/TsmdbErrors.d.ts} +16 -16
  16. package/dist_ts/tsmdb/errors/TsmdbErrors.js +155 -0
  17. package/dist_ts/{congodb → tsmdb}/index.d.ts +11 -4
  18. package/dist_ts/tsmdb/index.js +31 -0
  19. package/dist_ts/tsmdb/server/CommandRouter.d.ts +87 -0
  20. package/dist_ts/tsmdb/server/CommandRouter.js +222 -0
  21. package/dist_ts/{congodb/server/CongoServer.d.ts → tsmdb/server/TsmdbServer.d.ts} +6 -6
  22. package/dist_ts/tsmdb/server/TsmdbServer.js +229 -0
  23. package/dist_ts/{congodb → tsmdb}/server/WireProtocol.d.ts +1 -1
  24. package/dist_ts/tsmdb/server/WireProtocol.js +298 -0
  25. package/dist_ts/{congodb → tsmdb}/server/handlers/AdminHandler.d.ts +1 -1
  26. package/dist_ts/tsmdb/server/handlers/AdminHandler.js +668 -0
  27. package/dist_ts/{congodb → tsmdb}/server/handlers/AggregateHandler.d.ts +1 -1
  28. package/dist_ts/tsmdb/server/handlers/AggregateHandler.js +277 -0
  29. package/dist_ts/{congodb → tsmdb}/server/handlers/DeleteHandler.d.ts +1 -1
  30. package/dist_ts/tsmdb/server/handlers/DeleteHandler.js +95 -0
  31. package/dist_ts/{congodb → tsmdb}/server/handlers/FindHandler.d.ts +1 -1
  32. package/dist_ts/tsmdb/server/handlers/FindHandler.js +291 -0
  33. package/dist_ts/{congodb → tsmdb}/server/handlers/HelloHandler.d.ts +1 -1
  34. package/dist_ts/{congodb → tsmdb}/server/handlers/HelloHandler.js +2 -2
  35. package/dist_ts/{congodb → tsmdb}/server/handlers/IndexHandler.d.ts +1 -1
  36. package/dist_ts/tsmdb/server/handlers/IndexHandler.js +183 -0
  37. package/dist_ts/{congodb → tsmdb}/server/handlers/InsertHandler.d.ts +1 -1
  38. package/dist_ts/tsmdb/server/handlers/InsertHandler.js +79 -0
  39. package/dist_ts/{congodb → tsmdb}/server/handlers/UpdateHandler.d.ts +1 -1
  40. package/dist_ts/tsmdb/server/handlers/UpdateHandler.js +296 -0
  41. package/dist_ts/tsmdb/server/handlers/index.js +10 -0
  42. package/dist_ts/{congodb → tsmdb}/server/index.d.ts +2 -2
  43. package/dist_ts/tsmdb/server/index.js +7 -0
  44. package/dist_ts/{congodb → tsmdb}/storage/FileStorageAdapter.d.ts +27 -3
  45. package/dist_ts/tsmdb/storage/FileStorageAdapter.js +465 -0
  46. package/dist_ts/{congodb → tsmdb}/storage/IStorageAdapter.d.ts +7 -2
  47. package/dist_ts/{congodb → tsmdb}/storage/IStorageAdapter.js +1 -1
  48. package/dist_ts/{congodb → tsmdb}/storage/MemoryStorageAdapter.d.ts +3 -2
  49. package/dist_ts/tsmdb/storage/MemoryStorageAdapter.js +378 -0
  50. package/dist_ts/{congodb → tsmdb}/storage/OpLog.d.ts +1 -1
  51. package/dist_ts/tsmdb/storage/OpLog.js +221 -0
  52. package/dist_ts/tsmdb/storage/WAL.d.ts +117 -0
  53. package/dist_ts/tsmdb/storage/WAL.js +286 -0
  54. package/dist_ts/tsmdb/tsmdb.plugins.js +14 -0
  55. package/dist_ts/{congodb → tsmdb}/types/interfaces.d.ts +3 -3
  56. package/dist_ts/{congodb → tsmdb}/types/interfaces.js +1 -1
  57. package/dist_ts/tsmdb/utils/checksum.d.ts +30 -0
  58. package/dist_ts/tsmdb/utils/checksum.js +77 -0
  59. package/dist_ts/tsmdb/utils/index.d.ts +1 -0
  60. package/dist_ts/tsmdb/utils/index.js +2 -0
  61. package/package.json +1 -1
  62. package/readme.hints.md +7 -12
  63. package/readme.md +25 -25
  64. package/ts/00_commitinfo_data.ts +1 -1
  65. package/ts/index.ts +2 -2
  66. package/ts/{congodb → tsmdb}/engine/AggregationEngine.ts +1 -1
  67. package/ts/tsmdb/engine/IndexEngine.ts +798 -0
  68. package/ts/{congodb → tsmdb}/engine/QueryEngine.ts +1 -1
  69. package/ts/tsmdb/engine/QueryPlanner.ts +393 -0
  70. package/ts/tsmdb/engine/SessionEngine.ts +292 -0
  71. package/ts/{congodb → tsmdb}/engine/TransactionEngine.ts +12 -12
  72. package/ts/{congodb → tsmdb}/engine/UpdateEngine.ts +1 -1
  73. package/ts/{congodb/errors/CongoErrors.ts → tsmdb/errors/TsmdbErrors.ts} +34 -34
  74. package/ts/{congodb → tsmdb}/index.ts +16 -7
  75. package/ts/{congodb → tsmdb}/server/CommandRouter.ts +114 -5
  76. package/ts/{congodb/server/CongoServer.ts → tsmdb/server/TsmdbServer.ts} +11 -8
  77. package/ts/{congodb → tsmdb}/server/WireProtocol.ts +1 -1
  78. package/ts/{congodb → tsmdb}/server/handlers/AdminHandler.ts +116 -11
  79. package/ts/{congodb → tsmdb}/server/handlers/AggregateHandler.ts +1 -1
  80. package/ts/{congodb → tsmdb}/server/handlers/DeleteHandler.ts +18 -3
  81. package/ts/{congodb → tsmdb}/server/handlers/FindHandler.ts +43 -14
  82. package/ts/{congodb → tsmdb}/server/handlers/HelloHandler.ts +1 -1
  83. package/ts/{congodb → tsmdb}/server/handlers/IndexHandler.ts +1 -1
  84. package/ts/{congodb → tsmdb}/server/handlers/InsertHandler.ts +7 -1
  85. package/ts/{congodb → tsmdb}/server/handlers/UpdateHandler.ts +34 -5
  86. package/ts/{congodb → tsmdb}/server/index.ts +2 -2
  87. package/ts/{congodb → tsmdb}/storage/FileStorageAdapter.ts +90 -7
  88. package/ts/{congodb → tsmdb}/storage/IStorageAdapter.ts +8 -2
  89. package/ts/{congodb → tsmdb}/storage/MemoryStorageAdapter.ts +14 -2
  90. package/ts/{congodb → tsmdb}/storage/OpLog.ts +1 -1
  91. package/ts/tsmdb/storage/WAL.ts +375 -0
  92. package/ts/{congodb → tsmdb}/types/interfaces.ts +3 -3
  93. package/ts/tsmdb/utils/checksum.ts +88 -0
  94. package/ts/tsmdb/utils/index.ts +1 -0
  95. package/dist_ts/congodb/congodb.plugins.js +0 -14
  96. package/dist_ts/congodb/engine/AggregationEngine.js +0 -189
  97. package/dist_ts/congodb/engine/IndexEngine.js +0 -376
  98. package/dist_ts/congodb/engine/QueryEngine.js +0 -271
  99. package/dist_ts/congodb/engine/TransactionEngine.js +0 -287
  100. package/dist_ts/congodb/engine/UpdateEngine.js +0 -461
  101. package/dist_ts/congodb/errors/CongoErrors.js +0 -155
  102. package/dist_ts/congodb/index.js +0 -26
  103. package/dist_ts/congodb/server/CommandRouter.d.ts +0 -51
  104. package/dist_ts/congodb/server/CommandRouter.js +0 -132
  105. package/dist_ts/congodb/server/CongoServer.js +0 -227
  106. package/dist_ts/congodb/server/WireProtocol.js +0 -298
  107. package/dist_ts/congodb/server/handlers/AdminHandler.js +0 -568
  108. package/dist_ts/congodb/server/handlers/AggregateHandler.js +0 -277
  109. package/dist_ts/congodb/server/handlers/DeleteHandler.js +0 -83
  110. package/dist_ts/congodb/server/handlers/FindHandler.js +0 -261
  111. package/dist_ts/congodb/server/handlers/IndexHandler.js +0 -183
  112. package/dist_ts/congodb/server/handlers/InsertHandler.js +0 -76
  113. package/dist_ts/congodb/server/handlers/UpdateHandler.js +0 -270
  114. package/dist_ts/congodb/server/handlers/index.js +0 -10
  115. package/dist_ts/congodb/server/index.js +0 -7
  116. package/dist_ts/congodb/storage/FileStorageAdapter.js +0 -396
  117. package/dist_ts/congodb/storage/MemoryStorageAdapter.js +0 -367
  118. package/dist_ts/congodb/storage/OpLog.js +0 -221
  119. package/ts/congodb/engine/IndexEngine.ts +0 -479
  120. /package/dist_ts/{congodb → tsmdb}/engine/AggregationEngine.d.ts +0 -0
  121. /package/dist_ts/{congodb → tsmdb}/engine/QueryEngine.d.ts +0 -0
  122. /package/dist_ts/{congodb → tsmdb}/engine/UpdateEngine.d.ts +0 -0
  123. /package/dist_ts/{congodb → tsmdb}/server/handlers/index.d.ts +0 -0
  124. /package/dist_ts/{congodb/congodb.plugins.d.ts → tsmdb/tsmdb.plugins.d.ts} +0 -0
  125. /package/ts/{congodb → tsmdb}/server/handlers/index.ts +0 -0
  126. /package/ts/{congodb/congodb.plugins.ts → tsmdb/tsmdb.plugins.ts} +0 -0
@@ -0,0 +1,271 @@
1
+ import * as plugins from '../tsmdb.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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiUXVlcnlFbmdpbmUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi90cy90c21kYi9lbmdpbmUvUXVlcnlFbmdpbmUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLE9BQU8sTUFBTSxxQkFBcUIsQ0FBQztBQUcvQywyQkFBMkI7QUFDM0IsT0FBTyxFQUFFLEtBQUssRUFBRSxNQUFNLE9BQU8sQ0FBQztBQUU5Qjs7R0FFRztBQUNILE1BQU0sT0FBTyxXQUFXO0lBQ3RCOztPQUVHO0lBQ0gsTUFBTSxDQUFDLE1BQU0sQ0FBQyxTQUE0QixFQUFFLE1BQWdCO1FBQzFELElBQUksQ0FBQyxNQUFNLElBQUksTUFBTSxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsQ0FBQyxNQUFNLEtBQUssQ0FBQyxFQUFFLENBQUM7WUFDaEQsT0FBTyxTQUFTLENBQUM7UUFDbkIsQ0FBQztRQUVELE1BQU0sS0FBSyxHQUFHLElBQUksS0FBSyxDQUFDLE1BQU0sQ0FBQyxDQUFDO1FBQ2hDLE9BQU8sU0FBUyxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQztJQUNsRCxDQUFDO0lBRUQ7O09BRUc7SUFDSCxNQUFNLENBQUMsT0FBTyxDQUFDLFFBQWtCLEVBQUUsTUFBZ0I7UUFDakQsSUFBSSxDQUFDLE1BQU0sSUFBSSxNQUFNLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxDQUFDLE1BQU0sS0FBSyxDQUFDLEVBQUUsQ0FBQztZQUNoRCxPQUFPLElBQUksQ0FBQztRQUNkLENBQUM7UUFFRCxNQUFNLEtBQUssR0FBRyxJQUFJLEtBQUssQ0FBQyxNQUFNLENBQUMsQ0FBQztRQUNoQyxPQUFPLEtBQUssQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLENBQUM7SUFDOUIsQ0FBQztJQUVEOztPQUVHO0lBQ0gsTUFBTSxDQUFDLE9BQU8sQ0FBQyxTQUE0QixFQUFF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
@@ -0,0 +1,64 @@
1
+ import type { Document } from '../types/interfaces.js';
2
+ import { IndexEngine } from './IndexEngine.js';
3
+ /**
4
+ * Query execution plan types
5
+ */
6
+ export type TQueryPlanType = 'IXSCAN' | 'COLLSCAN' | 'FETCH' | 'IXSCAN_RANGE';
7
+ /**
8
+ * Represents a query execution plan
9
+ */
10
+ export interface IQueryPlan {
11
+ /** The type of scan used */
12
+ type: TQueryPlanType;
13
+ /** Index name if using an index */
14
+ indexName?: string;
15
+ /** Index key specification */
16
+ indexKey?: Record<string, 1 | -1 | string>;
17
+ /** Whether the query can be fully satisfied by the index */
18
+ indexCovering: boolean;
19
+ /** Estimated selectivity (0-1, lower is more selective) */
20
+ selectivity: number;
21
+ /** Whether range operators are used */
22
+ usesRange: boolean;
23
+ /** Fields used from the index */
24
+ indexFieldsUsed: string[];
25
+ /** Filter conditions that must be applied post-index lookup */
26
+ residualFilter?: Document;
27
+ /** Explanation for debugging */
28
+ explanation: string;
29
+ }
30
+ /**
31
+ * QueryPlanner - Analyzes queries and selects optimal execution plans
32
+ */
33
+ export declare class QueryPlanner {
34
+ private indexEngine;
35
+ constructor(indexEngine: IndexEngine);
36
+ /**
37
+ * Generate an execution plan for a query filter
38
+ */
39
+ plan(filter: Document): Promise<IQueryPlan>;
40
+ /**
41
+ * Analyze filter to extract operator information per field
42
+ */
43
+ private analyzeFilter;
44
+ /**
45
+ * Score an index for the given filter
46
+ */
47
+ private scoreIndex;
48
+ /**
49
+ * Calculate overall score for a plan (higher is better)
50
+ */
51
+ private calculateScore;
52
+ /**
53
+ * Explain a query - returns detailed plan information
54
+ */
55
+ explain(filter: Document): Promise<{
56
+ queryPlanner: {
57
+ plannerVersion: number;
58
+ namespace: string;
59
+ indexFilterSet: boolean;
60
+ winningPlan: IQueryPlan;
61
+ rejectedPlans: IQueryPlan[];
62
+ };
63
+ }>;
64
+ }
@@ -0,0 +1,308 @@
1
+ import * as plugins from '../tsmdb.plugins.js';
2
+ import { IndexEngine } from './IndexEngine.js';
3
+ /**
4
+ * QueryPlanner - Analyzes queries and selects optimal execution plans
5
+ */
6
+ export class QueryPlanner {
7
+ indexEngine;
8
+ constructor(indexEngine) {
9
+ this.indexEngine = indexEngine;
10
+ }
11
+ /**
12
+ * Generate an execution plan for a query filter
13
+ */
14
+ async plan(filter) {
15
+ await this.indexEngine['initialize']();
16
+ // Empty filter = full collection scan
17
+ if (!filter || Object.keys(filter).length === 0) {
18
+ return {
19
+ type: 'COLLSCAN',
20
+ indexCovering: false,
21
+ selectivity: 1.0,
22
+ usesRange: false,
23
+ indexFieldsUsed: [],
24
+ explanation: 'No filter specified, full collection scan required',
25
+ };
26
+ }
27
+ // Analyze the filter
28
+ const operatorInfo = this.analyzeFilter(filter);
29
+ // Get available indexes
30
+ const indexes = await this.indexEngine.listIndexes();
31
+ // Score each index
32
+ let bestPlan = null;
33
+ let bestScore = -1;
34
+ for (const index of indexes) {
35
+ const plan = this.scoreIndex(index, operatorInfo, filter);
36
+ if (plan.selectivity < 1.0) {
37
+ const score = this.calculateScore(plan);
38
+ if (score > bestScore) {
39
+ bestScore = score;
40
+ bestPlan = plan;
41
+ }
42
+ }
43
+ }
44
+ // If no suitable index found, fall back to collection scan
45
+ if (!bestPlan || bestScore <= 0) {
46
+ return {
47
+ type: 'COLLSCAN',
48
+ indexCovering: false,
49
+ selectivity: 1.0,
50
+ usesRange: false,
51
+ indexFieldsUsed: [],
52
+ explanation: 'No suitable index found for this query',
53
+ };
54
+ }
55
+ return bestPlan;
56
+ }
57
+ /**
58
+ * Analyze filter to extract operator information per field
59
+ */
60
+ analyzeFilter(filter, prefix = '') {
61
+ const result = new Map();
62
+ for (const [key, value] of Object.entries(filter)) {
63
+ // Skip logical operators at the top level
64
+ if (key.startsWith('$')) {
65
+ if (key === '$and' && Array.isArray(value)) {
66
+ // Merge $and conditions
67
+ for (const subFilter of value) {
68
+ const subInfo = this.analyzeFilter(subFilter, prefix);
69
+ for (const [field, info] of subInfo) {
70
+ if (result.has(field)) {
71
+ // Merge operators
72
+ const existing = result.get(field);
73
+ existing.operators.push(...info.operators);
74
+ existing.equality = existing.equality || info.equality;
75
+ existing.range = existing.range || info.range;
76
+ existing.in = existing.in || info.in;
77
+ Object.assign(existing.values, info.values);
78
+ }
79
+ else {
80
+ result.set(field, info);
81
+ }
82
+ }
83
+ }
84
+ }
85
+ continue;
86
+ }
87
+ const fullKey = prefix ? `${prefix}.${key}` : key;
88
+ const info = {
89
+ field: fullKey,
90
+ operators: [],
91
+ equality: false,
92
+ range: false,
93
+ in: false,
94
+ exists: false,
95
+ regex: false,
96
+ values: {},
97
+ };
98
+ if (typeof value !== 'object' || value === null || value instanceof plugins.bson.ObjectId || value instanceof Date) {
99
+ // Direct equality
100
+ info.equality = true;
101
+ info.operators.push('$eq');
102
+ info.values['$eq'] = value;
103
+ }
104
+ else if (Array.isArray(value)) {
105
+ // Array equality (rare, but possible)
106
+ info.equality = true;
107
+ info.operators.push('$eq');
108
+ info.values['$eq'] = value;
109
+ }
110
+ else {
111
+ // Operator object
112
+ for (const [op, opValue] of Object.entries(value)) {
113
+ if (op.startsWith('$')) {
114
+ info.operators.push(op);
115
+ info.values[op] = opValue;
116
+ switch (op) {
117
+ case '$eq':
118
+ info.equality = true;
119
+ break;
120
+ case '$ne':
121
+ case '$not':
122
+ // These can use indexes but with low selectivity
123
+ break;
124
+ case '$in':
125
+ info.in = true;
126
+ break;
127
+ case '$nin':
128
+ // Can't efficiently use indexes
129
+ break;
130
+ case '$gt':
131
+ case '$gte':
132
+ case '$lt':
133
+ case '$lte':
134
+ info.range = true;
135
+ break;
136
+ case '$exists':
137
+ info.exists = true;
138
+ break;
139
+ case '$regex':
140
+ info.regex = true;
141
+ break;
142
+ }
143
+ }
144
+ else {
145
+ // Nested object - recurse
146
+ const nestedInfo = this.analyzeFilter({ [op]: opValue }, fullKey);
147
+ for (const [nestedField, nestedFieldInfo] of nestedInfo) {
148
+ result.set(nestedField, nestedFieldInfo);
149
+ }
150
+ }
151
+ }
152
+ }
153
+ if (info.operators.length > 0) {
154
+ result.set(fullKey, info);
155
+ }
156
+ }
157
+ return result;
158
+ }
159
+ /**
160
+ * Score an index for the given filter
161
+ */
162
+ scoreIndex(index, operatorInfo, filter) {
163
+ const indexFields = Object.keys(index.key);
164
+ const usedFields = [];
165
+ let usesRange = false;
166
+ let canUseIndex = true;
167
+ let selectivity = 1.0;
168
+ let residualFilter;
169
+ // Check each index field in order
170
+ for (const field of indexFields) {
171
+ const info = operatorInfo.get(field);
172
+ if (!info) {
173
+ // Index field not in filter - stop here
174
+ break;
175
+ }
176
+ usedFields.push(field);
177
+ // Calculate selectivity based on operator
178
+ if (info.equality) {
179
+ // Equality has high selectivity
180
+ selectivity *= 0.01; // Assume 1% match
181
+ }
182
+ else if (info.in) {
183
+ // $in selectivity depends on array size
184
+ const inValues = info.values['$in'];
185
+ if (Array.isArray(inValues)) {
186
+ selectivity *= Math.min(0.5, inValues.length * 0.01);
187
+ }
188
+ else {
189
+ selectivity *= 0.1;
190
+ }
191
+ }
192
+ else if (info.range) {
193
+ // Range queries have moderate selectivity
194
+ selectivity *= 0.25;
195
+ usesRange = true;
196
+ // After range, can't use more index fields efficiently
197
+ break;
198
+ }
199
+ else if (info.exists) {
200
+ // $exists can use sparse indexes
201
+ selectivity *= 0.5;
202
+ }
203
+ else {
204
+ // Other operators may not be indexable
205
+ canUseIndex = false;
206
+ break;
207
+ }
208
+ }
209
+ if (!canUseIndex || usedFields.length === 0) {
210
+ return {
211
+ type: 'COLLSCAN',
212
+ indexCovering: false,
213
+ selectivity: 1.0,
214
+ usesRange: false,
215
+ indexFieldsUsed: [],
216
+ explanation: `Index ${index.name} cannot be used for this query`,
217
+ };
218
+ }
219
+ // Build residual filter for conditions not covered by index
220
+ const coveredFields = new Set(usedFields);
221
+ const residualConditions = {};
222
+ for (const [field, info] of operatorInfo) {
223
+ if (!coveredFields.has(field)) {
224
+ // This field isn't covered by the index
225
+ if (info.equality) {
226
+ residualConditions[field] = info.values['$eq'];
227
+ }
228
+ else {
229
+ residualConditions[field] = info.values;
230
+ }
231
+ }
232
+ }
233
+ if (Object.keys(residualConditions).length > 0) {
234
+ residualFilter = residualConditions;
235
+ }
236
+ // Unique indexes have better selectivity for equality
237
+ if (index.unique && usedFields.length === indexFields.length) {
238
+ selectivity = Math.min(selectivity, 0.001); // At most 1 document
239
+ }
240
+ return {
241
+ type: usesRange ? 'IXSCAN_RANGE' : 'IXSCAN',
242
+ indexName: index.name,
243
+ indexKey: index.key,
244
+ indexCovering: Object.keys(residualConditions).length === 0,
245
+ selectivity,
246
+ usesRange,
247
+ indexFieldsUsed: usedFields,
248
+ residualFilter,
249
+ explanation: `Using index ${index.name} on fields [${usedFields.join(', ')}]`,
250
+ };
251
+ }
252
+ /**
253
+ * Calculate overall score for a plan (higher is better)
254
+ */
255
+ calculateScore(plan) {
256
+ let score = 0;
257
+ // Lower selectivity is better (fewer documents to fetch)
258
+ score += (1 - plan.selectivity) * 100;
259
+ // Index covering queries are best
260
+ if (plan.indexCovering) {
261
+ score += 50;
262
+ }
263
+ // More index fields used is better
264
+ score += plan.indexFieldsUsed.length * 10;
265
+ // Equality scans are better than range scans
266
+ if (!plan.usesRange) {
267
+ score += 20;
268
+ }
269
+ return score;
270
+ }
271
+ /**
272
+ * Explain a query - returns detailed plan information
273
+ */
274
+ async explain(filter) {
275
+ await this.indexEngine['initialize']();
276
+ // Analyze the filter
277
+ const operatorInfo = this.analyzeFilter(filter);
278
+ // Get available indexes
279
+ const indexes = await this.indexEngine.listIndexes();
280
+ // Score all indexes
281
+ const plans = [];
282
+ for (const index of indexes) {
283
+ const plan = this.scoreIndex(index, operatorInfo, filter);
284
+ plans.push(plan);
285
+ }
286
+ // Add collection scan as fallback
287
+ plans.push({
288
+ type: 'COLLSCAN',
289
+ indexCovering: false,
290
+ selectivity: 1.0,
291
+ usesRange: false,
292
+ indexFieldsUsed: [],
293
+ explanation: 'Full collection scan',
294
+ });
295
+ // Sort by score (best first)
296
+ plans.sort((a, b) => this.calculateScore(b) - this.calculateScore(a));
297
+ return {
298
+ queryPlanner: {
299
+ plannerVersion: 1,
300
+ namespace: `${this.indexEngine['dbName']}.${this.indexEngine['collName']}`,
301
+ indexFilterSet: false,
302
+ winningPlan: plans[0],
303
+ rejectedPlans: plans.slice(1),
304
+ },
305
+ };
306
+ }
307
+ }
308
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiUXVlcnlQbGFubmVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vdHMvdHNtZGIvZW5naW5lL1F1ZXJ5UGxhbm5lci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssT0FBTyxNQUFNLHFCQUFxQixDQUFDO0FBRS9DLE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSxrQkFBa0IsQ0FBQztBQTZDL0M7O0dBRUc7QUFDSCxNQUFNLE9BQU8sWUFBWTtJQUNmLFdBQVcsQ0FBYztJQUVqQyxZQUFZLFdBQXdCO1FBQ2xDLElBQUksQ0FBQyxXQUFXLEdBQUcsV0FBVyxDQUFDO0lBQ2pDLENBQUM7SUFFRDs7T0FFRztJQUNILEtBQUssQ0FBQyxJQUFJLENBQUMsTUFBZ0I7UUFDekIsTUFBTSxJQUFJLENBQUMsV0FBVyxDQUFDLFlBQVksQ0FBQyxFQUFFLENBQUM7UUFFdkMsc0NBQXNDO1FBQ3RDLElBQUksQ0FBQyxNQUFNLElBQUksTUFBTSxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsQ0FBQyxNQUFNLEtBQUssQ0FBQyxFQUFFLENBQUM7WUFDaEQsT0FBTztnQkFDTCxJQUFJLEVBQUUsVUFBVTtnQkFDaEIsYUFBYSxFQUFFLEtBQUs7Z0JBQ3BCLFdBQVcsRUFBRSxHQUFHO2dCQUNoQixTQUFTLEVBQUUsS0FBSztnQkFDaEIsZUFBZSxFQUFFLEVBQUU7Z0JBQ25CLFdBQVcsRUFBRSxvREFBb0Q7YUFDbEUsQ0FBQztRQUNKLENBQUM7UUFFRCxxQkFBcUI7UUFDckIsTUFBTSxZQUFZLEdBQUcsSUFBSSxDQUFDLGFBQWEsQ0FBQyxNQUFNLENBQUMsQ0FBQztRQUVoRCx3QkFBd0I7UUFDeEIsTUFBTSxPQUFPLEdBQUcsTUFBTSxJQUFJLENBQUMsV0FBVyxDQUFDLFdBQVcsRUFBRSxDQUFDO1FBRXJELG1CQUFtQjtRQUNuQixJQUFJLFFBQVEsR0FBc0IsSUFBSSxDQUFDO1FBQ3ZDLElBQUksU0FBUyxHQUFHLENBQUMsQ0FBQyxD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