@objectql/core 4.2.0 → 4.2.2

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 (116) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/CHANGELOG.md +34 -0
  3. package/README.md +5 -2
  4. package/dist/app.d.ts +61 -52
  5. package/dist/app.js +100 -435
  6. package/dist/app.js.map +1 -1
  7. package/dist/index.d.ts +14 -20
  8. package/dist/index.js +21 -20
  9. package/dist/index.js.map +1 -1
  10. package/dist/kernel-factory.d.ts +38 -0
  11. package/dist/kernel-factory.js +38 -0
  12. package/dist/kernel-factory.js.map +1 -0
  13. package/dist/plugin.d.ts +9 -16
  14. package/dist/plugin.js +71 -48
  15. package/dist/plugin.js.map +1 -1
  16. package/dist/repository.d.ts +4 -31
  17. package/dist/repository.js +7 -283
  18. package/dist/repository.js.map +1 -1
  19. package/dist/util.js +4 -2
  20. package/dist/util.js.map +1 -1
  21. package/package.json +14 -12
  22. package/src/app.ts +156 -539
  23. package/src/index.ts +18 -42
  24. package/src/kernel-factory.ts +47 -0
  25. package/src/plugin.ts +77 -85
  26. package/src/repository.ts +4 -320
  27. package/src/util.ts +5 -3
  28. package/test/__mocks__/@objectstack/core.ts +250 -1
  29. package/test/__mocks__/@objectstack/objectql.ts +273 -0
  30. package/test/__mocks__/@objectstack/runtime.ts +14 -5
  31. package/test/introspection.test.ts +1 -1
  32. package/test/mock-driver.ts +5 -5
  33. package/test/optimizations.test.ts +2 -2
  34. package/test/plugin-integration.test.ts +1 -3
  35. package/test/utils.ts +6 -6
  36. package/tsconfig.json +3 -1
  37. package/tsconfig.tsbuildinfo +1 -1
  38. package/dist/ai/index.d.ts +0 -8
  39. package/dist/ai/index.js +0 -25
  40. package/dist/ai/index.js.map +0 -1
  41. package/dist/ai/registry.d.ts +0 -23
  42. package/dist/ai/registry.js +0 -78
  43. package/dist/ai/registry.js.map +0 -1
  44. package/dist/gateway.d.ts +0 -37
  45. package/dist/gateway.js +0 -93
  46. package/dist/gateway.js.map +0 -1
  47. package/dist/optimizations/CompiledHookManager.d.ts +0 -56
  48. package/dist/optimizations/CompiledHookManager.js +0 -170
  49. package/dist/optimizations/CompiledHookManager.js.map +0 -1
  50. package/dist/optimizations/DependencyGraph.d.ts +0 -82
  51. package/dist/optimizations/DependencyGraph.js +0 -211
  52. package/dist/optimizations/DependencyGraph.js.map +0 -1
  53. package/dist/optimizations/GlobalConnectionPool.d.ts +0 -89
  54. package/dist/optimizations/GlobalConnectionPool.js +0 -193
  55. package/dist/optimizations/GlobalConnectionPool.js.map +0 -1
  56. package/dist/optimizations/LazyMetadataLoader.d.ts +0 -75
  57. package/dist/optimizations/LazyMetadataLoader.js +0 -149
  58. package/dist/optimizations/LazyMetadataLoader.js.map +0 -1
  59. package/dist/optimizations/OptimizedMetadataRegistry.d.ts +0 -26
  60. package/dist/optimizations/OptimizedMetadataRegistry.js +0 -117
  61. package/dist/optimizations/OptimizedMetadataRegistry.js.map +0 -1
  62. package/dist/optimizations/OptimizedValidationEngine.d.ts +0 -73
  63. package/dist/optimizations/OptimizedValidationEngine.js +0 -141
  64. package/dist/optimizations/OptimizedValidationEngine.js.map +0 -1
  65. package/dist/optimizations/QueryCompiler.d.ts +0 -51
  66. package/dist/optimizations/QueryCompiler.js +0 -216
  67. package/dist/optimizations/QueryCompiler.js.map +0 -1
  68. package/dist/optimizations/SQLQueryOptimizer.d.ts +0 -96
  69. package/dist/optimizations/SQLQueryOptimizer.js +0 -265
  70. package/dist/optimizations/SQLQueryOptimizer.js.map +0 -1
  71. package/dist/optimizations/index.d.ts +0 -32
  72. package/dist/optimizations/index.js +0 -44
  73. package/dist/optimizations/index.js.map +0 -1
  74. package/dist/protocol.d.ts +0 -191
  75. package/dist/protocol.js +0 -272
  76. package/dist/protocol.js.map +0 -1
  77. package/dist/query/filter-translator.d.ts +0 -24
  78. package/dist/query/filter-translator.js +0 -38
  79. package/dist/query/filter-translator.js.map +0 -1
  80. package/dist/query/index.d.ts +0 -22
  81. package/dist/query/index.js +0 -39
  82. package/dist/query/index.js.map +0 -1
  83. package/dist/query/query-analyzer.d.ts +0 -186
  84. package/dist/query/query-analyzer.js +0 -348
  85. package/dist/query/query-analyzer.js.map +0 -1
  86. package/dist/query/query-builder.d.ts +0 -27
  87. package/dist/query/query-builder.js +0 -69
  88. package/dist/query/query-builder.js.map +0 -1
  89. package/dist/query/query-service.d.ts +0 -151
  90. package/dist/query/query-service.js +0 -272
  91. package/dist/query/query-service.js.map +0 -1
  92. package/src/ai/index.ts +0 -9
  93. package/src/ai/registry.ts +0 -81
  94. package/src/gateway.ts +0 -105
  95. package/src/optimizations/CompiledHookManager.ts +0 -193
  96. package/src/optimizations/DependencyGraph.ts +0 -255
  97. package/src/optimizations/GlobalConnectionPool.ts +0 -251
  98. package/src/optimizations/LazyMetadataLoader.ts +0 -180
  99. package/src/optimizations/OptimizedMetadataRegistry.ts +0 -132
  100. package/src/optimizations/OptimizedValidationEngine.ts +0 -172
  101. package/src/optimizations/QueryCompiler.ts +0 -242
  102. package/src/optimizations/SQLQueryOptimizer.ts +0 -329
  103. package/src/optimizations/index.ts +0 -34
  104. package/src/protocol.ts +0 -304
  105. package/src/query/filter-translator.ts +0 -41
  106. package/src/query/index.ts +0 -24
  107. package/src/query/query-analyzer.ts +0 -532
  108. package/src/query/query-builder.ts +0 -64
  109. package/src/query/query-service.ts +0 -397
  110. package/test/ai-registry.test.ts +0 -42
  111. package/test/app.test.ts +0 -578
  112. package/test/filter-syntax.test.ts +0 -233
  113. package/test/gateway.test.ts +0 -88
  114. package/test/protocol.test.ts +0 -143
  115. package/test/repository-validation.test.ts +0 -351
  116. package/test/repository.test.ts +0 -151
@@ -1,397 +0,0 @@
1
- /**
2
- * ObjectQL Query Service
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 {
10
- Driver,
11
- ObjectConfig,
12
- UnifiedQuery,
13
- Filter,
14
- MetadataRegistry
15
- } from '@objectql/types';
16
- import { QueryAST } from '@objectql/types';
17
- import { QueryBuilder } from './query-builder';
18
- import { QueryCompiler } from '../optimizations/QueryCompiler';
19
-
20
- /**
21
- * Options for query execution
22
- */
23
- export interface QueryOptions {
24
- /**
25
- * Transaction handle for transactional queries
26
- */
27
- transaction?: any;
28
-
29
- /**
30
- * Skip validation (for system operations)
31
- */
32
- skipValidation?: boolean;
33
-
34
- /**
35
- * Include profiling information
36
- */
37
- profile?: boolean;
38
-
39
- /**
40
- * Custom driver options
41
- */
42
- driverOptions?: Record<string, unknown>;
43
- }
44
-
45
- /**
46
- * Result of a query execution with optional profiling data
47
- */
48
- export interface QueryResult<T = any> {
49
- /**
50
- * The query results
51
- */
52
- value: T;
53
-
54
- /**
55
- * Total count (for paginated queries)
56
- */
57
- count?: number;
58
-
59
- /**
60
- * Profiling information (if profile option was enabled)
61
- */
62
- profile?: QueryProfile;
63
- }
64
-
65
- /**
66
- * Profiling information for a query
67
- */
68
- export interface QueryProfile {
69
- /**
70
- * Execution time in milliseconds
71
- */
72
- executionTime: number;
73
-
74
- /**
75
- * Number of rows scanned
76
- */
77
- rowsScanned?: number;
78
-
79
- /**
80
- * Whether an index was used
81
- */
82
- indexUsed?: boolean;
83
-
84
- /**
85
- * The generated QueryAST
86
- */
87
- ast?: QueryAST;
88
- }
89
-
90
- /**
91
- * Query Service
92
- *
93
- * Handles all query execution logic, separating query concerns from
94
- * the repository pattern. This service is responsible for:
95
- * - Building QueryAST from UnifiedQuery
96
- * - Executing queries via drivers
97
- * - Optional query profiling and analysis
98
- *
99
- * The QueryService is registered as a service in the ObjectQLPlugin
100
- * and can be used by Repository for all read operations.
101
- */
102
- export class QueryService {
103
- private queryBuilder: QueryBuilder;
104
- private queryCompiler: QueryCompiler;
105
-
106
- constructor(
107
- private datasources: Record<string, Driver>,
108
- private metadata: MetadataRegistry
109
- ) {
110
- this.queryBuilder = new QueryBuilder();
111
- this.queryCompiler = new QueryCompiler(1000);
112
- }
113
-
114
- /**
115
- * Get the driver for a specific object
116
- * @private
117
- */
118
- private getDriver(objectName: string): Driver {
119
- const obj = this.getSchema(objectName);
120
- const datasourceName = obj.datasource || 'default';
121
- const driver = this.datasources[datasourceName];
122
-
123
- if (!driver) {
124
- throw new Error(`Datasource '${datasourceName}' not found for object '${objectName}'`);
125
- }
126
-
127
- return driver;
128
- }
129
-
130
- /**
131
- * Get the schema for an object
132
- * @private
133
- */
134
- private getSchema(objectName: string): ObjectConfig {
135
- const obj = this.metadata.get('object', objectName);
136
- if (!obj) {
137
- throw new Error(`Object '${objectName}' not found in metadata`);
138
- }
139
- return obj;
140
- }
141
-
142
- /**
143
- * Build QueryAST from UnifiedQuery
144
- * @private
145
- */
146
- private buildQueryAST(objectName: string, query: UnifiedQuery): QueryAST {
147
- const ast = this.queryBuilder.build(objectName, query);
148
- const compiled = this.queryCompiler.compile(objectName, ast);
149
- return compiled.ast;
150
- }
151
-
152
- /**
153
- * Execute a find query
154
- *
155
- * @param objectName - The object to query
156
- * @param query - The unified query
157
- * @param options - Query execution options
158
- * @returns Array of matching records
159
- */
160
- async find(
161
- objectName: string,
162
- query: UnifiedQuery = {},
163
- options: QueryOptions = {}
164
- ): Promise<QueryResult<any[]>> {
165
- const driver = this.getDriver(objectName);
166
- const startTime = options.profile ? Date.now() : 0;
167
-
168
- // Build QueryAST
169
- const ast = this.buildQueryAST(objectName, query);
170
-
171
- // Execute query via driver
172
- const driverOptions = {
173
- transaction: options.transaction,
174
- ...options.driverOptions
175
- };
176
-
177
- let results: any[];
178
- let count: number | undefined;
179
-
180
- if (driver.find) {
181
- // Legacy driver interface
182
- const result: any = await driver.find(objectName, query, driverOptions);
183
- results = Array.isArray(result) ? result : (result?.value || []);
184
- count = (typeof result === 'object' && !Array.isArray(result) && result?.count !== undefined) ? result.count : undefined;
185
- } else if (driver.executeQuery) {
186
- // New DriverInterface
187
- const result = await driver.executeQuery(ast, driverOptions);
188
- results = result.value || [];
189
- count = result.count;
190
- } else {
191
- throw new Error(`Driver does not support query execution`);
192
- }
193
-
194
- const executionTime = options.profile ? Date.now() - startTime : 0;
195
-
196
- return {
197
- value: results,
198
- count,
199
- profile: options.profile ? {
200
- executionTime,
201
- ast,
202
- rowsScanned: results.length,
203
- } : undefined
204
- };
205
- }
206
-
207
- /**
208
- * Execute a findOne query by ID
209
- *
210
- * @param objectName - The object to query
211
- * @param id - The record ID
212
- * @param options - Query execution options
213
- * @returns The matching record or undefined
214
- */
215
- async findOne(
216
- objectName: string,
217
- id: string | number,
218
- options: QueryOptions = {}
219
- ): Promise<QueryResult<any>> {
220
- const driver = this.getDriver(objectName);
221
- const startTime = options.profile ? Date.now() : 0;
222
-
223
- const driverOptions = {
224
- transaction: options.transaction,
225
- ...options.driverOptions
226
- };
227
-
228
- let result: any;
229
-
230
- if (driver.findOne) {
231
- // Legacy driver interface
232
- result = await driver.findOne(objectName, id, driverOptions);
233
- } else if (driver.get) {
234
- // Alternative method name
235
- result = await driver.get(objectName, String(id), driverOptions);
236
- } else if (driver.executeQuery) {
237
- // Fallback to query with ID filter
238
- const query: UnifiedQuery = {
239
- where: { _id: id }
240
- };
241
- const ast = this.buildQueryAST(objectName, query);
242
- const queryResult = await driver.executeQuery(ast, driverOptions);
243
- result = queryResult.value?.[0];
244
- } else {
245
- throw new Error(`Driver does not support findOne operation`);
246
- }
247
-
248
- const executionTime = options.profile ? Date.now() - startTime : 0;
249
-
250
- return {
251
- value: result,
252
- profile: options.profile ? {
253
- executionTime,
254
- rowsScanned: result ? 1 : 0,
255
- } : undefined
256
- };
257
- }
258
-
259
- /**
260
- * Execute a count query
261
- *
262
- * @param objectName - The object to query
263
- * @param where - Optional filter condition
264
- * @param options - Query execution options
265
- * @returns Count of matching records
266
- */
267
- async count(
268
- objectName: string,
269
- where?: Filter,
270
- options: QueryOptions = {}
271
- ): Promise<QueryResult<number>> {
272
- const driver = this.getDriver(objectName);
273
- const startTime = options.profile ? Date.now() : 0;
274
-
275
- const query: UnifiedQuery = where ? { where } : {};
276
- const ast = this.buildQueryAST(objectName, query);
277
-
278
- const driverOptions = {
279
- transaction: options.transaction,
280
- ...options.driverOptions
281
- };
282
-
283
- let count: number;
284
-
285
- if (driver.count) {
286
- // Legacy driver interface
287
- count = await driver.count(objectName, where || {}, driverOptions);
288
- } else if (driver.executeQuery) {
289
- // Use executeQuery and count results
290
- // Note: This is inefficient for large datasets
291
- // Ideally, driver should support count-specific optimization
292
- const result = await driver.executeQuery(ast, driverOptions);
293
- count = result.count ?? result.value?.length ?? 0;
294
- } else {
295
- throw new Error(`Driver does not support count operation`);
296
- }
297
-
298
- const executionTime = options.profile ? Date.now() - startTime : 0;
299
-
300
- return {
301
- value: count,
302
- profile: options.profile ? {
303
- executionTime,
304
- ast,
305
- } : undefined
306
- };
307
- }
308
-
309
- /**
310
- * Execute an aggregate query
311
- *
312
- * @param objectName - The object to query
313
- * @param query - The aggregation query using UnifiedQuery format
314
- * @param options - Query execution options
315
- * @returns Aggregation results
316
- */
317
- async aggregate(
318
- objectName: string,
319
- query: UnifiedQuery,
320
- options: QueryOptions = {}
321
- ): Promise<QueryResult<any[]>> {
322
- const driver = this.getDriver(objectName);
323
- const startTime = options.profile ? Date.now() : 0;
324
-
325
- const driverOptions = {
326
- transaction: options.transaction,
327
- ...options.driverOptions
328
- };
329
-
330
- let results: any[];
331
-
332
- if (driver.aggregate) {
333
- // Driver supports aggregation
334
- results = await driver.aggregate(objectName, query, driverOptions);
335
- } else {
336
- // Driver doesn't support aggregation
337
- throw new Error(`Driver does not support aggregate operations. Consider using a driver that supports aggregation.`);
338
- }
339
-
340
- const executionTime = options.profile ? Date.now() - startTime : 0;
341
-
342
- return {
343
- value: results,
344
- profile: options.profile ? {
345
- executionTime,
346
- rowsScanned: results.length,
347
- } : undefined
348
- };
349
- }
350
-
351
- /**
352
- * Execute a direct SQL/query passthrough
353
- *
354
- * This bypasses ObjectQL's query builder and executes raw queries.
355
- * Use with caution as it bypasses security and validation.
356
- *
357
- * @param objectName - The object (determines which datasource to use)
358
- * @param queryString - Raw query string (SQL, MongoDB query, etc.)
359
- * @param params - Query parameters (for parameterized queries)
360
- * @param options - Query execution options
361
- * @returns Query results
362
- */
363
- async directQuery(
364
- objectName: string,
365
- queryString: string,
366
- params?: any[],
367
- options: QueryOptions = {}
368
- ): Promise<QueryResult<any>> {
369
- const driver = this.getDriver(objectName);
370
- const startTime = options.profile ? Date.now() : 0;
371
-
372
- const driverOptions = {
373
- transaction: options.transaction,
374
- ...options.driverOptions
375
- };
376
-
377
- let results: any;
378
-
379
- if (driver.directQuery) {
380
- results = await driver.directQuery(queryString, params);
381
- } else if (driver.query) {
382
- // Alternative method name
383
- results = await driver.query(queryString, params);
384
- } else {
385
- throw new Error(`Driver does not support direct query execution`);
386
- }
387
-
388
- const executionTime = options.profile ? Date.now() - startTime : 0;
389
-
390
- return {
391
- value: results,
392
- profile: options.profile ? {
393
- executionTime,
394
- } : undefined
395
- };
396
- }
397
- }
@@ -1,42 +0,0 @@
1
- /**
2
- * ObjectQL - AI Registry Tests
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 { createDefaultAiRegistry } from '../src/ai';
10
-
11
- describe('AI Registry', () => {
12
- it('registers and retrieves models', () => {
13
- const registry = createDefaultAiRegistry();
14
-
15
- registry.models.register({
16
- id: 'embed-small',
17
- provider: 'openai',
18
- model: 'text-embedding-3-small',
19
- type: 'embedding',
20
- embeddingDimensions: 1536,
21
- });
22
-
23
- const model = registry.models.get('embed-small');
24
- expect(model?.model).toBe('text-embedding-3-small');
25
- expect(registry.models.list().length).toBe(1);
26
- });
27
-
28
- it('registers and retrieves prompt templates', () => {
29
- const registry = createDefaultAiRegistry();
30
-
31
- registry.prompts.register({
32
- id: 'greeting',
33
- template: 'Hello, {{name}}!',
34
- variables: ['name'],
35
- version: 'v1',
36
- });
37
-
38
- const prompt = registry.prompts.get('greeting', 'v1');
39
- expect(prompt?.template).toBe('Hello, {{name}}!');
40
- expect(registry.prompts.list('greeting').length).toBe(1);
41
- });
42
- });