@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
package/test/app.test.ts DELETED
@@ -1,578 +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 { ObjectQL } from '../src/app';
10
- import { MockDriver } from './mock-driver';
11
- import { ObjectConfig, HookContext, ActionContext, Metadata } from '@objectql/types';
12
- import type { Kernel } from '@objectstack/spec';
13
- type PluginDefinition = Kernel.PluginDefinition;
14
-
15
- const todoObject: ObjectConfig = {
16
- name: 'todo',
17
- fields: {
18
- title: { type: 'text', required: true },
19
- completed: { type: 'boolean', defaultValue: false }
20
- }
21
- };
22
-
23
- const projectObject: ObjectConfig = {
24
- name: 'project',
25
- fields: {
26
- name: { type: 'text', required: true },
27
- status: { type: 'select', options: ['active', 'completed'] }
28
- }
29
- };
30
-
31
- describe('ObjectQL App', () => {
32
- describe('Constructor', () => {
33
- it('should create instance with minimal config', () => {
34
- const app = new ObjectQL({ datasources: {} });
35
- expect(app).toBeDefined();
36
- expect(app.metadata).toBeDefined();
37
- });
38
-
39
- it('should accept datasources configuration', () => {
40
- const driver = new MockDriver();
41
- const app = new ObjectQL({
42
- datasources: {
43
- default: driver,
44
- secondary: driver
45
- }
46
- });
47
- expect(app.datasource('default')).toBe(driver);
48
- expect(app.datasource('secondary')).toBe(driver);
49
- });
50
-
51
- it('should throw error for connection string', () => {
52
- expect(() => {
53
- new ObjectQL({
54
- datasources: {},
55
- connection: 'sqlite://memory'
56
- } as any);
57
- }).toThrow('Connection strings are not supported in core');
58
- });
59
-
60
- it('should throw error for string plugins', () => {
61
- expect(() => {
62
- new ObjectQL({
63
- datasources: {},
64
- plugins: ['some-plugin'] as any
65
- });
66
- }).toThrow('String plugins are not supported in core');
67
- });
68
-
69
- it('should accept plugin instances', () => {
70
- const mockPlugin: PluginDefinition = {
71
- id: 'test-plugin',
72
- onEnable: jest.fn()
73
- };
74
- const app = new ObjectQL({
75
- datasources: {},
76
- plugins: [mockPlugin]
77
- });
78
- expect(app).toBeDefined();
79
- });
80
- });
81
-
82
- describe('Object Registration', () => {
83
- let app: ObjectQL;
84
-
85
- beforeEach(() => {
86
- app = new ObjectQL({ datasources: {} });
87
- });
88
-
89
- it('should register an object', () => {
90
- app.registerObject(todoObject);
91
- const retrieved = app.getObject('todo');
92
- expect(retrieved).toBeDefined();
93
- expect(retrieved?.name).toBe('todo');
94
- });
95
-
96
- it('should unregister an object', () => {
97
- app.registerObject(todoObject);
98
- app.unregisterObject('todo');
99
- const retrieved = app.getObject('todo');
100
- expect(retrieved).toBeUndefined();
101
- });
102
-
103
- it('should get all configs', () => {
104
- app.registerObject(todoObject);
105
- app.registerObject(projectObject);
106
- const configs = app.getConfigs();
107
- expect(Object.keys(configs)).toHaveLength(2);
108
- expect(configs.todo).toBeDefined();
109
- expect(configs.project).toBeDefined();
110
- });
111
-
112
- it('should return undefined for non-existent object', () => {
113
- const retrieved = app.getObject('nonexistent');
114
- expect(retrieved).toBeUndefined();
115
- });
116
- });
117
-
118
- describe('Datasource Management', () => {
119
- it('should get datasource by name', () => {
120
- const driver = new MockDriver();
121
- const app = new ObjectQL({
122
- datasources: { default: driver }
123
- });
124
- expect(app.datasource('default')).toBe(driver);
125
- });
126
-
127
- it('should throw error for non-existent datasource', () => {
128
- const app = new ObjectQL({ datasources: {} });
129
- expect(() => app.datasource('nonexistent')).toThrow(
130
- "Datasource 'nonexistent' not found"
131
- );
132
- });
133
- });
134
-
135
- describe('Context Creation', () => {
136
- let app: ObjectQL;
137
-
138
- beforeEach(() => {
139
- app = new ObjectQL({ datasources: {} });
140
- });
141
-
142
- it('should create context with userId', () => {
143
- const ctx = app.createContext({ userId: 'user1' });
144
- expect(ctx.userId).toBe('user1');
145
- expect(ctx.isSystem).toBeFalsy();
146
- });
147
-
148
- it('should create system context', () => {
149
- const ctx = app.createContext({ userId: 'user1', isSystem: true });
150
- expect(ctx.isSystem).toBe(true);
151
- });
152
-
153
- it('should create context with roles', () => {
154
- const ctx = app.createContext({
155
- userId: 'user1',
156
- roles: ['admin', 'user']
157
- });
158
- expect(ctx.roles).toEqual(['admin', 'user']);
159
- });
160
-
161
- it('should create context with spaceId', () => {
162
- const ctx = app.createContext({
163
- userId: 'user1',
164
- spaceId: 'space1'
165
- });
166
- expect(ctx.spaceId).toBe('space1');
167
- });
168
-
169
- it('should provide object repository through context', () => {
170
- app.registerObject(todoObject);
171
- const ctx = app.createContext({ userId: 'user1', isSystem: true });
172
- const repo = ctx.object('todo');
173
- expect(repo).toBeDefined();
174
- });
175
-
176
- it('should provide sudo method to elevate privileges', () => {
177
- const ctx = app.createContext({ userId: 'user1', isSystem: false });
178
- expect(ctx.isSystem).toBe(false);
179
-
180
- const sudoCtx = ctx.sudo();
181
- expect(sudoCtx.isSystem).toBe(true);
182
- expect(sudoCtx.userId).toBe('user1');
183
- });
184
- });
185
-
186
- describe('Hook Management', () => {
187
- let app: ObjectQL;
188
-
189
- beforeEach(() => {
190
- app = new ObjectQL({ datasources: {} });
191
- app.registerObject(todoObject);
192
- });
193
-
194
- it('should register a hook', () => {
195
- const handler = jest.fn();
196
- app.on('beforeCreate', 'todo', handler);
197
- expect(handler).not.toHaveBeenCalled();
198
- });
199
-
200
- it('should trigger registered hook', async () => {
201
- const handler = jest.fn();
202
- app.on('beforeCreate', 'todo', handler);
203
-
204
- const hookCtx: HookContext = {
205
- objectName: 'todo',
206
- data: { title: 'Test' },
207
- userId: 'user1',
208
- isSystem: false
209
- };
210
-
211
- await app.triggerHook('beforeCreate', 'todo', hookCtx);
212
- expect(handler).toHaveBeenCalledWith(hookCtx);
213
- });
214
-
215
- it('should register hook with package name', () => {
216
- const handler = jest.fn();
217
- app.on('beforeCreate', 'todo', handler, 'test-package');
218
- expect(handler).not.toHaveBeenCalled();
219
- });
220
- });
221
-
222
- describe('Action Management', () => {
223
- let app: ObjectQL;
224
-
225
- beforeEach(() => {
226
- app = new ObjectQL({ datasources: {} });
227
- app.registerObject(todoObject);
228
- });
229
-
230
- it('should register an action', () => {
231
- const handler = jest.fn().mockResolvedValue({ success: true });
232
- app.registerAction('todo', 'complete', handler);
233
- expect(handler).not.toHaveBeenCalled();
234
- });
235
-
236
- it('should execute registered action', async () => {
237
- const handler = jest.fn().mockResolvedValue({ success: true });
238
- app.registerAction('todo', 'complete', handler);
239
-
240
- const actionCtx: ActionContext = {
241
- objectName: 'todo',
242
- input: { id: '1' },
243
- userId: 'user1',
244
- isSystem: false
245
- };
246
-
247
- const result = await app.executeAction('todo', 'complete', actionCtx);
248
- expect(handler).toHaveBeenCalledWith(actionCtx);
249
- expect(result).toEqual({ success: true });
250
- });
251
-
252
- it('should register action with package name', () => {
253
- const handler = jest.fn().mockResolvedValue({ success: true });
254
- app.registerAction('todo', 'complete', handler, 'test-package');
255
- expect(handler).not.toHaveBeenCalled();
256
- });
257
- });
258
-
259
- describe('Package Management', () => {
260
- let app: ObjectQL;
261
-
262
- beforeEach(() => {
263
- app = new ObjectQL({ datasources: {} });
264
- });
265
-
266
- it('should remove package and its metadata', () => {
267
- // Register object with package name
268
- const obj: ObjectConfig = { ...todoObject };
269
- const entry: Metadata = {
270
- type: 'object',
271
- id: 'todo',
272
- // @ts-expect-error - SchemaRegistry typing limitation
273
- name: 'todo', // Ensure SchemaRegistry keys it correctly
274
- package: 'test-package',
275
- content: obj
276
- };
277
- app.metadata.register('object', entry);
278
-
279
- // Register hook
280
- app.on('beforeCreate', 'todo', jest.fn(), 'test-package');
281
-
282
- // Register action
283
- app.registerAction('todo', 'complete', jest.fn(), 'test-package');
284
-
285
- // Verify object is registered
286
- expect(app.getObject('todo')).toBeDefined();
287
-
288
- // Remove package
289
- app.removePackage('test-package');
290
-
291
- // Verify removal
292
- expect(app.getObject('todo')).toBeUndefined();
293
- });
294
- });
295
-
296
- describe('Plugin System', () => {
297
- it('should initialize runtime plugins on init', async () => {
298
- const installFn = jest.fn();
299
- const onStartFn = jest.fn();
300
- const mockPlugin = {
301
- name: 'test-plugin',
302
- install: installFn,
303
- onStart: onStartFn
304
- };
305
-
306
- const app = new ObjectQL({
307
- datasources: {},
308
- plugins: [mockPlugin]
309
- });
310
-
311
- await app.init();
312
- expect(installFn).toHaveBeenCalled();
313
- expect(onStartFn).toHaveBeenCalled();
314
- });
315
-
316
- it('should use plugin method', () => {
317
- const mockPlugin = {
318
- name: 'test-plugin',
319
- init: jest.fn()
320
- };
321
-
322
- const app = new ObjectQL({ datasources: {} });
323
- app.use(mockPlugin);
324
- expect(app).toBeDefined();
325
- });
326
- });
327
-
328
- describe('Initialization', () => {
329
- it('should initialize with objects config', async () => {
330
- const app = new ObjectQL({
331
- datasources: {},
332
- objects: {
333
- todo: todoObject,
334
- project: projectObject
335
- }
336
- });
337
-
338
- await app.init();
339
-
340
- expect(app.getObject('todo')).toBeDefined();
341
- expect(app.getObject('project')).toBeDefined();
342
- });
343
-
344
- it('should initialize datasources', async () => {
345
- const driver = new MockDriver();
346
- driver.init = jest.fn().mockResolvedValue(undefined);
347
-
348
- const app = new ObjectQL({
349
- datasources: { default: driver },
350
- objects: { todo: todoObject }
351
- });
352
-
353
- await app.init();
354
- expect(driver.init).toHaveBeenCalled();
355
- });
356
-
357
- it('should process initial data', async () => {
358
- const driver = new MockDriver();
359
- const app = new ObjectQL({
360
- datasources: { default: driver },
361
- objects: { todo: todoObject }
362
- });
363
-
364
- // Register initial data
365
- app.metadata.register('data', {
366
- type: 'data',
367
- id: 'todo-data',
368
- content: {
369
- object: 'todo',
370
- records: [
371
- { title: 'Initial Task 1' },
372
- { title: 'Initial Task 2' }
373
- ]
374
- }
375
- });
376
-
377
- await app.init();
378
-
379
- // Verify data was created by checking the driver's internal data store
380
- const todoData = (driver as any).getData('todo');
381
- expect(todoData.length).toBe(2);
382
- });
383
-
384
- it('should handle array format initial data', async () => {
385
- const driver = new MockDriver();
386
- const app = new ObjectQL({
387
- datasources: { default: driver },
388
- objects: { todo: todoObject }
389
- });
390
-
391
- // Register initial data in array format
392
- const dataArray = [
393
- { title: 'Task 1' },
394
- { title: 'Task 2' }
395
- ];
396
- (dataArray as any).name = 'todo';
397
-
398
- app.metadata.register('data', {
399
- type: 'data',
400
- id: 'todo-data',
401
- content: dataArray
402
- });
403
-
404
- await app.init();
405
-
406
- // Verify data was created by checking the driver's internal data store
407
- const todoData = (driver as any).getData('todo');
408
- expect(todoData.length).toBe(2);
409
- });
410
-
411
- it('should skip invalid data entries', async () => {
412
- const consoleWarnSpy = jest.spyOn(console, 'warn').mockImplementation();
413
- const driver = new MockDriver();
414
- const app = new ObjectQL({
415
- datasources: { default: driver }
416
- });
417
-
418
- app.metadata.register('data', {
419
- type: 'data',
420
- id: 'invalid-data',
421
- content: { invalid: true }
422
- });
423
-
424
- await app.init();
425
-
426
- expect(consoleWarnSpy).toHaveBeenCalled();
427
- consoleWarnSpy.mockRestore();
428
- });
429
- });
430
-
431
- describe('Transaction Support', () => {
432
- it('should execute callback in transaction', async () => {
433
- const driver = new MockDriver();
434
- driver.beginTransaction = jest.fn().mockResolvedValue('trx-handle');
435
- driver.commitTransaction = jest.fn().mockResolvedValue(undefined);
436
-
437
- const app = new ObjectQL({
438
- datasources: { default: driver }
439
- });
440
-
441
- const ctx = app.createContext({ userId: 'user1', isSystem: true });
442
-
443
- let trxCtx: any;
444
- await ctx.transaction(async (txCtx) => {
445
- trxCtx = txCtx;
446
- expect(txCtx.transactionHandle).toBe('trx-handle');
447
- });
448
-
449
- expect(driver.beginTransaction).toHaveBeenCalled();
450
- expect(driver.commitTransaction).toHaveBeenCalledWith('trx-handle');
451
- });
452
-
453
- it('should rollback transaction on error', async () => {
454
- const driver = new MockDriver();
455
- driver.beginTransaction = jest.fn().mockResolvedValue('trx-handle');
456
- driver.rollbackTransaction = jest.fn().mockResolvedValue(undefined);
457
-
458
- const app = new ObjectQL({
459
- datasources: { default: driver }
460
- });
461
-
462
- const ctx = app.createContext({ userId: 'user1', isSystem: true });
463
-
464
- await expect(
465
- ctx.transaction(async () => {
466
- throw new Error('Test error');
467
- })
468
- ).rejects.toThrow('Test error');
469
-
470
- expect(driver.beginTransaction).toHaveBeenCalled();
471
- expect(driver.rollbackTransaction).toHaveBeenCalledWith('trx-handle');
472
- });
473
-
474
- it('should handle no transaction support', async () => {
475
- const driver = new MockDriver();
476
- // MockDriver has transaction support by default, so we create one without it
477
- const noTrxDriver: any = {
478
- ...driver,
479
- beginTransaction: undefined,
480
- commitTransaction: undefined,
481
- rollbackTransaction: undefined
482
- };
483
-
484
- const app = new ObjectQL({
485
- datasources: { default: noTrxDriver }
486
- });
487
-
488
- const ctx = app.createContext({ userId: 'user1', isSystem: true });
489
-
490
- let called = false;
491
- let capturedCtx: any;
492
- await ctx.transaction(async (txCtx) => {
493
- called = true;
494
- capturedCtx = txCtx;
495
- });
496
-
497
- expect(called).toBe(true);
498
- expect(capturedCtx.transactionHandle).toBeUndefined();
499
- });
500
- });
501
-
502
- describe('Schema Introspection', () => {
503
- it('should introspect and register objects', async () => {
504
- const driver = new MockDriver();
505
- driver.introspectSchema = jest.fn().mockResolvedValue({
506
- tables: {
507
- users: {
508
- columns: [
509
- { name: 'id', type: 'INTEGER', nullable: false, isUnique: true },
510
- { name: 'name', type: 'VARCHAR', nullable: false, isUnique: false },
511
- { name: 'email', type: 'VARCHAR', nullable: false, isUnique: true }
512
- ],
513
- foreignKeys: []
514
- }
515
- }
516
- });
517
-
518
- const app = new ObjectQL({
519
- datasources: { default: driver }
520
- });
521
-
522
- const objects = await app.introspectAndRegister('default');
523
-
524
- expect(objects).toHaveLength(1);
525
- expect(objects[0].name).toBe('users');
526
- expect(app.getObject('users')).toBeDefined();
527
- });
528
-
529
- it('should throw error if driver does not support introspection', async () => {
530
- const driver = new MockDriver();
531
- const app = new ObjectQL({
532
- datasources: { default: driver }
533
- });
534
-
535
- await expect(app.introspectAndRegister('default')).rejects.toThrow(
536
- 'does not support schema introspection'
537
- );
538
- });
539
-
540
- it('should throw error for non-existent datasource', async () => {
541
- const app = new ObjectQL({ datasources: {} });
542
-
543
- await expect(app.introspectAndRegister('nonexistent')).rejects.toThrow(
544
- "Datasource 'nonexistent' not found"
545
- );
546
- });
547
- });
548
-
549
- describe('Close', () => {
550
- it('should disconnect all datasources', async () => {
551
- const driver1 = new MockDriver();
552
- const driver2 = new MockDriver();
553
- driver1.disconnect = jest.fn().mockResolvedValue(undefined);
554
- driver2.disconnect = jest.fn().mockResolvedValue(undefined);
555
-
556
- const app = new ObjectQL({
557
- datasources: {
558
- default: driver1,
559
- secondary: driver2
560
- }
561
- });
562
-
563
- await app.close();
564
-
565
- expect(driver1.disconnect).toHaveBeenCalled();
566
- expect(driver2.disconnect).toHaveBeenCalled();
567
- });
568
-
569
- it('should handle datasources without disconnect method', async () => {
570
- const driver = new MockDriver();
571
- const app = new ObjectQL({
572
- datasources: { default: driver }
573
- });
574
-
575
- await expect(app.close()).resolves.not.toThrow();
576
- });
577
- });
578
- });