@objectql/core 4.2.0 → 4.2.1

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 (115) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/CHANGELOG.md +23 -0
  3. package/dist/app.d.ts +61 -52
  4. package/dist/app.js +101 -435
  5. package/dist/app.js.map +1 -1
  6. package/dist/index.d.ts +4 -18
  7. package/dist/index.js +11 -18
  8. package/dist/index.js.map +1 -1
  9. package/dist/kernel-factory.d.ts +38 -0
  10. package/dist/kernel-factory.js +38 -0
  11. package/dist/kernel-factory.js.map +1 -0
  12. package/dist/plugin.d.ts +9 -16
  13. package/dist/plugin.js +71 -48
  14. package/dist/plugin.js.map +1 -1
  15. package/dist/repository.d.ts +4 -31
  16. package/dist/repository.js +7 -283
  17. package/dist/repository.js.map +1 -1
  18. package/dist/util.js +4 -2
  19. package/dist/util.js.map +1 -1
  20. package/package.json +12 -11
  21. package/src/app.ts +157 -539
  22. package/src/index.ts +8 -40
  23. package/src/kernel-factory.ts +47 -0
  24. package/src/plugin.ts +77 -85
  25. package/src/repository.ts +4 -320
  26. package/src/util.ts +5 -3
  27. package/test/__mocks__/@objectstack/core.ts +250 -1
  28. package/test/__mocks__/@objectstack/objectql.ts +127 -0
  29. package/test/__mocks__/@objectstack/runtime.ts +14 -5
  30. package/test/introspection.test.ts +1 -1
  31. package/test/mock-driver.ts +5 -5
  32. package/test/optimizations.test.ts +2 -2
  33. package/test/plugin-integration.test.ts +1 -3
  34. package/test/utils.ts +6 -6
  35. package/tsconfig.json +3 -1
  36. package/tsconfig.tsbuildinfo +1 -1
  37. package/dist/ai/index.d.ts +0 -8
  38. package/dist/ai/index.js +0 -25
  39. package/dist/ai/index.js.map +0 -1
  40. package/dist/ai/registry.d.ts +0 -23
  41. package/dist/ai/registry.js +0 -78
  42. package/dist/ai/registry.js.map +0 -1
  43. package/dist/gateway.d.ts +0 -37
  44. package/dist/gateway.js +0 -93
  45. package/dist/gateway.js.map +0 -1
  46. package/dist/optimizations/CompiledHookManager.d.ts +0 -56
  47. package/dist/optimizations/CompiledHookManager.js +0 -170
  48. package/dist/optimizations/CompiledHookManager.js.map +0 -1
  49. package/dist/optimizations/DependencyGraph.d.ts +0 -82
  50. package/dist/optimizations/DependencyGraph.js +0 -211
  51. package/dist/optimizations/DependencyGraph.js.map +0 -1
  52. package/dist/optimizations/GlobalConnectionPool.d.ts +0 -89
  53. package/dist/optimizations/GlobalConnectionPool.js +0 -193
  54. package/dist/optimizations/GlobalConnectionPool.js.map +0 -1
  55. package/dist/optimizations/LazyMetadataLoader.d.ts +0 -75
  56. package/dist/optimizations/LazyMetadataLoader.js +0 -149
  57. package/dist/optimizations/LazyMetadataLoader.js.map +0 -1
  58. package/dist/optimizations/OptimizedMetadataRegistry.d.ts +0 -26
  59. package/dist/optimizations/OptimizedMetadataRegistry.js +0 -117
  60. package/dist/optimizations/OptimizedMetadataRegistry.js.map +0 -1
  61. package/dist/optimizations/OptimizedValidationEngine.d.ts +0 -73
  62. package/dist/optimizations/OptimizedValidationEngine.js +0 -141
  63. package/dist/optimizations/OptimizedValidationEngine.js.map +0 -1
  64. package/dist/optimizations/QueryCompiler.d.ts +0 -51
  65. package/dist/optimizations/QueryCompiler.js +0 -216
  66. package/dist/optimizations/QueryCompiler.js.map +0 -1
  67. package/dist/optimizations/SQLQueryOptimizer.d.ts +0 -96
  68. package/dist/optimizations/SQLQueryOptimizer.js +0 -265
  69. package/dist/optimizations/SQLQueryOptimizer.js.map +0 -1
  70. package/dist/optimizations/index.d.ts +0 -32
  71. package/dist/optimizations/index.js +0 -44
  72. package/dist/optimizations/index.js.map +0 -1
  73. package/dist/protocol.d.ts +0 -191
  74. package/dist/protocol.js +0 -272
  75. package/dist/protocol.js.map +0 -1
  76. package/dist/query/filter-translator.d.ts +0 -24
  77. package/dist/query/filter-translator.js +0 -38
  78. package/dist/query/filter-translator.js.map +0 -1
  79. package/dist/query/index.d.ts +0 -22
  80. package/dist/query/index.js +0 -39
  81. package/dist/query/index.js.map +0 -1
  82. package/dist/query/query-analyzer.d.ts +0 -186
  83. package/dist/query/query-analyzer.js +0 -348
  84. package/dist/query/query-analyzer.js.map +0 -1
  85. package/dist/query/query-builder.d.ts +0 -27
  86. package/dist/query/query-builder.js +0 -69
  87. package/dist/query/query-builder.js.map +0 -1
  88. package/dist/query/query-service.d.ts +0 -151
  89. package/dist/query/query-service.js +0 -272
  90. package/dist/query/query-service.js.map +0 -1
  91. package/src/ai/index.ts +0 -9
  92. package/src/ai/registry.ts +0 -81
  93. package/src/gateway.ts +0 -105
  94. package/src/optimizations/CompiledHookManager.ts +0 -193
  95. package/src/optimizations/DependencyGraph.ts +0 -255
  96. package/src/optimizations/GlobalConnectionPool.ts +0 -251
  97. package/src/optimizations/LazyMetadataLoader.ts +0 -180
  98. package/src/optimizations/OptimizedMetadataRegistry.ts +0 -132
  99. package/src/optimizations/OptimizedValidationEngine.ts +0 -172
  100. package/src/optimizations/QueryCompiler.ts +0 -242
  101. package/src/optimizations/SQLQueryOptimizer.ts +0 -329
  102. package/src/optimizations/index.ts +0 -34
  103. package/src/protocol.ts +0 -304
  104. package/src/query/filter-translator.ts +0 -41
  105. package/src/query/index.ts +0 -24
  106. package/src/query/query-analyzer.ts +0 -532
  107. package/src/query/query-builder.ts +0 -64
  108. package/src/query/query-service.ts +0 -397
  109. package/test/ai-registry.test.ts +0 -42
  110. package/test/app.test.ts +0 -578
  111. package/test/filter-syntax.test.ts +0 -233
  112. package/test/gateway.test.ts +0 -88
  113. package/test/protocol.test.ts +0 -143
  114. package/test/repository-validation.test.ts +0 -351
  115. package/test/repository.test.ts +0 -151
@@ -1,41 +0,0 @@
1
- /**
2
- * ObjectQL
3
- * Copyright (c) 2026-present ObjectStack Inc.
4
- *
5
- * This source code is licensed under the MIT license found in the
6
- * LICENSE file in the root directory of this source tree.
7
- */
8
-
9
- import type { Filter } from '@objectql/types';
10
- import { Data } from '@objectstack/spec';
11
- import { z } from 'zod';
12
- import { ObjectQLError } from '@objectql/types';
13
-
14
- /**
15
- * Filter Translator
16
- *
17
- * Translates ObjectQL Filter to ObjectStack FilterCondition format.
18
- * Since both now use the same format, this is mostly a pass-through.
19
- *
20
- * @example
21
- * Input: { age: { $gte: 18 }, $or: [{ status: "active" }, { role: "admin" }] }
22
- * Output: { age: { $gte: 18 }, $or: [{ status: "active" }, { role: "admin" }] }
23
- */
24
- export class FilterTranslator {
25
- /**
26
- * Translate filters from ObjectQL format to ObjectStack FilterCondition format
27
- */
28
- translate(filters?: Filter): Filter | undefined {
29
- if (!filters) {
30
- return undefined;
31
- }
32
-
33
- // If it's an empty object, return undefined
34
- if (typeof filters === 'object' && Object.keys(filters).length === 0) {
35
- return undefined;
36
- }
37
-
38
- // Both ObjectQL Filter and ObjectStack FilterCondition use the same format now
39
- return filters;
40
- }
41
- }
@@ -1,24 +0,0 @@
1
- /**
2
- * ObjectQL
3
- * Copyright (c) 2026-present ObjectStack Inc.
4
- *
5
- * This source code is licensed under the MIT license found in the
6
- * LICENSE file in the root directory of this source tree.
7
- */
8
-
9
- /**
10
- * Query Module
11
- *
12
- * This module contains ObjectQL's query-specific functionality:
13
- * - FilterTranslator: Converts ObjectQL filters to ObjectStack FilterNode
14
- * - QueryBuilder: Builds ObjectStack QueryAST from ObjectQL UnifiedQuery
15
- * - QueryService: Executes queries via drivers with profiling support
16
- * - QueryAnalyzer: Provides query performance analysis and optimization suggestions
17
- *
18
- * These are the core components that differentiate ObjectQL from generic runtime systems.
19
- */
20
-
21
- export * from './filter-translator';
22
- export * from './query-builder';
23
- export * from './query-service';
24
- export * from './query-analyzer';
@@ -1,532 +0,0 @@
1
- /**
2
- * ObjectQL Query Analyzer
3
- * Copyright (c) 2026-present ObjectStack Inc.
4
- *
5
- * This source code is licensed under the MIT license found in the
6
- * LICENSE file in the root directory of this source tree.
7
- */
8
-
9
- import type { UnifiedQuery, ObjectConfig, MetadataRegistry } from '@objectql/types';
10
- import { QueryAST } from '@objectql/types';
11
- import { QueryService, QueryOptions } from './query-service';
12
-
13
- /**
14
- * Query execution plan
15
- */
16
- export interface QueryPlan {
17
- /**
18
- * The compiled QueryAST
19
- */
20
- ast: QueryAST;
21
-
22
- /**
23
- * Estimated number of rows to be scanned
24
- */
25
- estimatedRows?: number;
26
-
27
- /**
28
- * Indexes that could be used for this query
29
- */
30
- indexes: string[];
31
-
32
- /**
33
- * Warnings about potential performance issues
34
- */
35
- warnings: string[];
36
-
37
- /**
38
- * Suggestions for optimization
39
- */
40
- suggestions: string[];
41
-
42
- /**
43
- * Complexity score (0-100, higher is more complex)
44
- */
45
- complexity: number;
46
- }
47
-
48
- /**
49
- * Query profile result with execution statistics
50
- */
51
- export interface ProfileResult {
52
- /**
53
- * Execution time in milliseconds
54
- */
55
- executionTime: number;
56
-
57
- /**
58
- * Number of rows scanned by the database
59
- */
60
- rowsScanned: number;
61
-
62
- /**
63
- * Number of rows returned
64
- */
65
- rowsReturned: number;
66
-
67
- /**
68
- * Whether an index was used
69
- */
70
- indexUsed: boolean;
71
-
72
- /**
73
- * The query plan
74
- */
75
- plan: QueryPlan;
76
-
77
- /**
78
- * Efficiency ratio (rowsReturned / rowsScanned)
79
- * Higher is better (1.0 is perfect, 0.0 is worst)
80
- */
81
- efficiency: number;
82
- }
83
-
84
- /**
85
- * Aggregated query statistics
86
- */
87
- export interface QueryStats {
88
- /**
89
- * Total number of queries executed
90
- */
91
- totalQueries: number;
92
-
93
- /**
94
- * Average execution time in milliseconds
95
- */
96
- avgExecutionTime: number;
97
-
98
- /**
99
- * Slowest query execution time
100
- */
101
- slowestQuery: number;
102
-
103
- /**
104
- * Fastest query execution time
105
- */
106
- fastestQuery: number;
107
-
108
- /**
109
- * Queries by object
110
- */
111
- byObject: Record<string, {
112
- count: number;
113
- avgTime: number;
114
- }>;
115
-
116
- /**
117
- * Top slow queries
118
- */
119
- slowQueries: Array<{
120
- objectName: string;
121
- executionTime: number;
122
- query: UnifiedQuery;
123
- timestamp: Date;
124
- }>;
125
- }
126
-
127
- /**
128
- * Query Analyzer
129
- *
130
- * Provides query performance analysis and profiling capabilities.
131
- * This class helps developers optimize queries by:
132
- * - Analyzing query plans
133
- * - Profiling execution performance
134
- * - Tracking statistics
135
- * - Providing optimization suggestions
136
- */
137
- export class QueryAnalyzer {
138
- private stats: QueryStats = {
139
- totalQueries: 0,
140
- avgExecutionTime: 0,
141
- slowestQuery: 0,
142
- fastestQuery: Number.MAX_VALUE,
143
- byObject: {},
144
- slowQueries: []
145
- };
146
-
147
- private executionTimes: number[] = [];
148
- private readonly MAX_SLOW_QUERIES = 10;
149
-
150
- constructor(
151
- private queryService: QueryService,
152
- private metadata: MetadataRegistry
153
- ) {}
154
-
155
- /**
156
- * Analyze a query and generate an execution plan
157
- *
158
- * @param objectName - The object to query
159
- * @param query - The unified query
160
- * @returns Query plan with optimization suggestions
161
- */
162
- async explain(objectName: string, query: UnifiedQuery): Promise<QueryPlan> {
163
- const schema = this.getSchema(objectName);
164
-
165
- // Build the QueryAST (without executing)
166
- const ast: QueryAST = {
167
- object: objectName,
168
- where: query.where as any, // FilterCondition format
169
- orderBy: query.orderBy as any, // Will be converted to SortNode[] format
170
- limit: query.limit,
171
- offset: query.offset,
172
- fields: query.fields
173
- };
174
-
175
- // Analyze filters for index usage
176
- const indexes = this.findApplicableIndexes(schema, query);
177
-
178
- // Detect potential issues
179
- const warnings = this.analyzeWarnings(schema, query);
180
-
181
- // Generate suggestions
182
- const suggestions = this.generateSuggestions(schema, query, indexes);
183
-
184
- // Calculate complexity
185
- const complexity = this.calculateComplexity(query);
186
-
187
- // Try to estimate rows (basic heuristic)
188
- const estimatedRows = this.estimateRows(schema, query);
189
-
190
- return {
191
- ast,
192
- estimatedRows,
193
- indexes,
194
- warnings,
195
- suggestions,
196
- complexity
197
- };
198
- }
199
-
200
- /**
201
- * Profile a query execution
202
- *
203
- * @param objectName - The object to query
204
- * @param query - The unified query
205
- * @param options - Query execution options
206
- * @returns Profile result with execution statistics
207
- */
208
- async profile(
209
- objectName: string,
210
- query: UnifiedQuery,
211
- options: QueryOptions = {}
212
- ): Promise<ProfileResult> {
213
- // Get the query plan first
214
- const plan = await this.explain(objectName, query);
215
-
216
- // Execute with profiling enabled
217
- const result = await this.queryService.find(objectName, query, {
218
- ...options,
219
- profile: true
220
- });
221
-
222
- const executionTime = result.profile?.executionTime || 0;
223
- const rowsReturned = result.value.length;
224
- const rowsScanned = result.profile?.rowsScanned || rowsReturned;
225
-
226
- // Calculate efficiency
227
- const efficiency = rowsScanned > 0 ? rowsReturned / rowsScanned : 0;
228
-
229
- // Determine if index was used (heuristic)
230
- const indexUsed = plan.indexes.length > 0 && efficiency > 0.5;
231
-
232
- // Update statistics
233
- this.recordExecution(objectName, executionTime, query);
234
-
235
- return {
236
- executionTime,
237
- rowsScanned,
238
- rowsReturned,
239
- indexUsed,
240
- plan,
241
- efficiency
242
- };
243
- }
244
-
245
- /**
246
- * Get aggregated query statistics
247
- *
248
- * @returns Current query statistics
249
- */
250
- getStatistics(): QueryStats {
251
- return { ...this.stats };
252
- }
253
-
254
- /**
255
- * Reset statistics
256
- */
257
- resetStatistics(): void {
258
- this.stats = {
259
- totalQueries: 0,
260
- avgExecutionTime: 0,
261
- slowestQuery: 0,
262
- fastestQuery: Number.MAX_VALUE,
263
- byObject: {},
264
- slowQueries: []
265
- };
266
- this.executionTimes = [];
267
- }
268
-
269
- /**
270
- * Get schema for an object
271
- * @private
272
- */
273
- private getSchema(objectName: string): ObjectConfig {
274
- const obj = this.metadata.get('object', objectName);
275
- if (!obj) {
276
- throw new Error(`Object '${objectName}' not found`);
277
- }
278
- return obj;
279
- }
280
-
281
- /**
282
- * Find indexes that could be used for the query
283
- * @private
284
- */
285
- private findApplicableIndexes(schema: ObjectConfig, query: UnifiedQuery): string[] {
286
- const indexes: string[] = [];
287
-
288
- if (!schema.indexes || !query.where) {
289
- return indexes;
290
- }
291
-
292
- // Extract fields used in filters
293
- const filterFields = new Set<string>();
294
-
295
- // FilterCondition is an object-based filter (e.g., { field: value } or { field: { $eq: value } })
296
- // We need to extract field names from the filter object
297
- const extractFieldsFromFilter = (filter: any): void => {
298
- if (!filter || typeof filter !== 'object') return;
299
-
300
- for (const key of Object.keys(filter)) {
301
- // Skip logical operators
302
- if (key.startsWith('$')) {
303
- // Logical operators contain nested filters
304
- if (key === '$and' || key === '$or') {
305
- const nested = filter[key];
306
- if (Array.isArray(nested)) {
307
- nested.forEach(extractFieldsFromFilter);
308
- }
309
- }
310
- continue;
311
- }
312
- // This is a field name
313
- filterFields.add(key);
314
- }
315
- };
316
-
317
- extractFieldsFromFilter(query.where);
318
-
319
- // Check which indexes could be used
320
- const indexesArray = Array.isArray(schema.indexes) ? schema.indexes : Object.values(schema.indexes || {});
321
- for (const index of indexesArray) {
322
- const indexFields = Array.isArray(index.fields)
323
- ? index.fields
324
- : [index.fields];
325
-
326
- // Simple heuristic: index is applicable if first field is in filter
327
- if (indexFields.length > 0 && filterFields.has(indexFields[0])) {
328
- const indexName = index.name || indexFields.join('_');
329
- indexes.push(indexName);
330
- }
331
- }
332
-
333
- return indexes;
334
- }
335
-
336
- /**
337
- * Analyze query for potential issues
338
- * @private
339
- */
340
- private analyzeWarnings(schema: ObjectConfig, query: UnifiedQuery): string[] {
341
- const warnings: string[] = [];
342
-
343
- // Warning: No filters (full table scan)
344
- if (!query.where || Object.keys(query.where).length === 0) {
345
- warnings.push('No filters specified - this will scan all records');
346
- }
347
-
348
- // Warning: No limit on potentially large dataset
349
- if (!query.limit) {
350
- warnings.push('No limit specified - consider adding pagination');
351
- }
352
-
353
- // Warning: Selecting all fields
354
- if (!query.fields || query.fields.length === 0) {
355
- const fieldCount = Object.keys(schema.fields || {}).length;
356
- if (fieldCount > 10) {
357
- warnings.push(`Selecting all ${fieldCount} fields - consider selecting only needed fields`);
358
- }
359
- }
360
-
361
- // Warning: Complex filters without indexes
362
- if (query.where && Object.keys(query.where).length > 5) {
363
- const indexes = this.findApplicableIndexes(schema, query);
364
- if (indexes.length === 0) {
365
- warnings.push('Complex filters without matching indexes - consider adding indexes');
366
- }
367
- }
368
-
369
- return warnings;
370
- }
371
-
372
- /**
373
- * Generate optimization suggestions
374
- * @private
375
- */
376
- private generateSuggestions(
377
- schema: ObjectConfig,
378
- query: UnifiedQuery,
379
- indexes: string[]
380
- ): string[] {
381
- const suggestions: string[] = [];
382
-
383
- // Suggest adding limit
384
- if (!query.limit) {
385
- suggestions.push('Add a limit clause to restrict result set size');
386
- }
387
-
388
- // Suggest adding indexes
389
- if (query.where && Object.keys(query.where).length > 0 && indexes.length === 0) {
390
- const filterFields = Object.keys(query.where).filter(k => !k.startsWith('$'));
391
-
392
- if (filterFields.length > 0) {
393
- suggestions.push(`Consider adding an index on: ${filterFields.join(', ')}`);
394
- }
395
- }
396
-
397
- // Suggest field selection
398
- if (!query.fields || query.fields.length === 0) {
399
- suggestions.push('Select only required fields to reduce data transfer');
400
- }
401
-
402
- // Suggest composite index for multiple filters
403
- if (query.where && Object.keys(query.where).length > 1 && indexes.length < 2) {
404
- const filterFields = Object.keys(query.where)
405
- .filter(k => !k.startsWith('$'))
406
- .slice(0, 3); // Top 3 fields
407
-
408
- if (filterFields.length > 1) {
409
- suggestions.push(`Consider a composite index on: (${filterFields.join(', ')})`);
410
- }
411
- }
412
-
413
- return suggestions;
414
- }
415
-
416
- /**
417
- * Calculate query complexity score (0-100)
418
- * @private
419
- */
420
- private calculateComplexity(query: UnifiedQuery): number {
421
- let complexity = 0;
422
-
423
- // Base complexity
424
- complexity += 10;
425
-
426
- // Filters add complexity
427
- if (query.where) {
428
- const filterCount = Object.keys(query.where).length;
429
- complexity += filterCount * 5;
430
-
431
- // Nested filters (OR/AND conditions) add more
432
- const hasLogicalOps = query.where.$and || query.where.$or;
433
- if (hasLogicalOps) {
434
- complexity += 15;
435
- }
436
- }
437
-
438
- // Sorting adds complexity
439
- if (query.orderBy && query.orderBy.length > 0) {
440
- complexity += query.orderBy.length * 3;
441
- }
442
-
443
- // Field selection reduces complexity slightly
444
- if (query.fields && query.fields.length > 0 && query.fields.length < 10) {
445
- complexity -= 5;
446
- }
447
-
448
- // Pagination reduces complexity
449
- if (query.limit) {
450
- complexity -= 5;
451
- }
452
-
453
- // Cap at 100
454
- return Math.min(Math.max(complexity, 0), 100);
455
- }
456
-
457
- /**
458
- * Estimate number of rows (very rough heuristic)
459
- * @private
460
- */
461
- private estimateRows(schema: ObjectConfig, query: UnifiedQuery): number {
462
- // This is a placeholder - real implementation would need statistics
463
- // from the database (row count, index selectivity, etc.)
464
-
465
- // Default to unknown
466
- if (!query.where || Object.keys(query.where).length === 0) {
467
- return -1; // Unknown, full scan
468
- }
469
-
470
- // Very rough estimate based on filter count
471
- const baseEstimate = 1000;
472
- const filterCount = Object.keys(query.where).length;
473
- const filterReduction = Math.pow(0.5, filterCount);
474
- const estimated = Math.floor(baseEstimate * filterReduction);
475
-
476
- // Apply limit if present
477
- if (query.limit) {
478
- return Math.min(estimated, query.limit);
479
- }
480
-
481
- return estimated;
482
- }
483
-
484
- /**
485
- * Record a query execution for statistics
486
- * @private
487
- */
488
- private recordExecution(
489
- objectName: string,
490
- executionTime: number,
491
- query: UnifiedQuery
492
- ): void {
493
- // Update totals
494
- this.stats.totalQueries++;
495
- this.executionTimes.push(executionTime);
496
-
497
- // Update average
498
- this.stats.avgExecutionTime =
499
- this.executionTimes.reduce((sum, t) => sum + t, 0) / this.executionTimes.length;
500
-
501
- // Update min/max
502
- this.stats.slowestQuery = Math.max(this.stats.slowestQuery, executionTime);
503
- this.stats.fastestQuery = Math.min(this.stats.fastestQuery, executionTime);
504
-
505
- // Update per-object stats
506
- if (!this.stats.byObject[objectName]) {
507
- this.stats.byObject[objectName] = { count: 0, avgTime: 0 };
508
- }
509
- const objStats = this.stats.byObject[objectName];
510
- objStats.count++;
511
- objStats.avgTime = ((objStats.avgTime * (objStats.count - 1)) + executionTime) / objStats.count;
512
-
513
- // Track slow queries
514
- if (this.stats.slowQueries.length < this.MAX_SLOW_QUERIES) {
515
- this.stats.slowQueries.push({
516
- objectName,
517
- executionTime,
518
- query,
519
- timestamp: new Date()
520
- });
521
- this.stats.slowQueries.sort((a, b) => b.executionTime - a.executionTime);
522
- } else if (executionTime > this.stats.slowQueries[this.MAX_SLOW_QUERIES - 1].executionTime) {
523
- this.stats.slowQueries[this.MAX_SLOW_QUERIES - 1] = {
524
- objectName,
525
- executionTime,
526
- query,
527
- timestamp: new Date()
528
- };
529
- this.stats.slowQueries.sort((a, b) => b.executionTime - a.executionTime);
530
- }
531
- }
532
- }
@@ -1,64 +0,0 @@
1
- /**
2
- * ObjectQL
3
- * Copyright (c) 2026-present ObjectStack Inc.
4
- *
5
- * This source code is licensed under the MIT license found in the
6
- * LICENSE file in the root directory of this source tree.
7
- */
8
-
9
- import type { UnifiedQuery, QueryAST } from '@objectql/types';
10
- // import { QueryAST } from './types'; (Removed)
11
-
12
- // Local QueryAST type extension to include all properties we need
13
- // interface QueryAST extends Data.QueryAST {
14
- // top?: number;
15
- // expand?: Record<string, any>;
16
- // aggregations?: any[];
17
- // having?: any;
18
- // }
19
-
20
- import { FilterTranslator } from './filter-translator';
21
-
22
- /**
23
- * Query Builder
24
- *
25
- * Builds ObjectStack QueryAST from ObjectQL UnifiedQuery.
26
- * Since UnifiedQuery now uses the standard protocol format directly,
27
- * this is now a simple pass-through with object name injection.
28
- */
29
- export class QueryBuilder {
30
- private filterTranslator: FilterTranslator;
31
-
32
- constructor() {
33
- this.filterTranslator = new FilterTranslator();
34
- }
35
-
36
- /**
37
- * Build a QueryAST from a UnifiedQuery
38
- *
39
- * @param objectName - Target object name
40
- * @param query - ObjectQL UnifiedQuery (now in standard QueryAST format)
41
- * @returns ObjectStack QueryAST
42
- */
43
- build(objectName: string, query: UnifiedQuery): QueryAST {
44
- // UnifiedQuery now uses the same format as QueryAST
45
- // Just add the object name and pass through
46
- const ast: QueryAST = {
47
- object: objectName
48
- };
49
-
50
- // Map UnifiedQuery properties to QueryAST
51
- if (query.fields) ast.fields = query.fields;
52
- if (query.where) ast.where = this.filterTranslator.translate(query.where);
53
- if (query.orderBy) ast.orderBy = query.orderBy;
54
- if (query.offset !== undefined) ast.offset = query.offset;
55
- if (query.limit !== undefined) ast.top = query.limit; // UnifiedQuery uses 'limit', QueryAST uses 'top'
56
- if (query.expand) ast.expand = query.expand;
57
- if (query.groupBy) ast.groupBy = query.groupBy;
58
- if (query.aggregations) ast.aggregations = query.aggregations;
59
- if (query.having) ast.having = query.having;
60
- if (query.distinct) ast.distinct = query.distinct;
61
-
62
- return ast;
63
- }
64
- }