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