@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.
- package/.turbo/turbo-build.log +1 -1
- package/CHANGELOG.md +34 -0
- package/README.md +5 -2
- package/dist/app.d.ts +61 -52
- package/dist/app.js +100 -435
- package/dist/app.js.map +1 -1
- package/dist/index.d.ts +14 -20
- package/dist/index.js +21 -20
- package/dist/index.js.map +1 -1
- package/dist/kernel-factory.d.ts +38 -0
- package/dist/kernel-factory.js +38 -0
- package/dist/kernel-factory.js.map +1 -0
- package/dist/plugin.d.ts +9 -16
- package/dist/plugin.js +71 -48
- package/dist/plugin.js.map +1 -1
- package/dist/repository.d.ts +4 -31
- package/dist/repository.js +7 -283
- package/dist/repository.js.map +1 -1
- package/dist/util.js +4 -2
- package/dist/util.js.map +1 -1
- package/package.json +14 -12
- package/src/app.ts +156 -539
- package/src/index.ts +18 -42
- package/src/kernel-factory.ts +47 -0
- package/src/plugin.ts +77 -85
- package/src/repository.ts +4 -320
- package/src/util.ts +5 -3
- package/test/__mocks__/@objectstack/core.ts +250 -1
- package/test/__mocks__/@objectstack/objectql.ts +273 -0
- package/test/__mocks__/@objectstack/runtime.ts +14 -5
- package/test/introspection.test.ts +1 -1
- package/test/mock-driver.ts +5 -5
- package/test/optimizations.test.ts +2 -2
- package/test/plugin-integration.test.ts +1 -3
- package/test/utils.ts +6 -6
- package/tsconfig.json +3 -1
- package/tsconfig.tsbuildinfo +1 -1
- package/dist/ai/index.d.ts +0 -8
- package/dist/ai/index.js +0 -25
- package/dist/ai/index.js.map +0 -1
- package/dist/ai/registry.d.ts +0 -23
- package/dist/ai/registry.js +0 -78
- package/dist/ai/registry.js.map +0 -1
- package/dist/gateway.d.ts +0 -37
- package/dist/gateway.js +0 -93
- package/dist/gateway.js.map +0 -1
- package/dist/optimizations/CompiledHookManager.d.ts +0 -56
- package/dist/optimizations/CompiledHookManager.js +0 -170
- package/dist/optimizations/CompiledHookManager.js.map +0 -1
- package/dist/optimizations/DependencyGraph.d.ts +0 -82
- package/dist/optimizations/DependencyGraph.js +0 -211
- package/dist/optimizations/DependencyGraph.js.map +0 -1
- package/dist/optimizations/GlobalConnectionPool.d.ts +0 -89
- package/dist/optimizations/GlobalConnectionPool.js +0 -193
- package/dist/optimizations/GlobalConnectionPool.js.map +0 -1
- package/dist/optimizations/LazyMetadataLoader.d.ts +0 -75
- package/dist/optimizations/LazyMetadataLoader.js +0 -149
- package/dist/optimizations/LazyMetadataLoader.js.map +0 -1
- package/dist/optimizations/OptimizedMetadataRegistry.d.ts +0 -26
- package/dist/optimizations/OptimizedMetadataRegistry.js +0 -117
- package/dist/optimizations/OptimizedMetadataRegistry.js.map +0 -1
- package/dist/optimizations/OptimizedValidationEngine.d.ts +0 -73
- package/dist/optimizations/OptimizedValidationEngine.js +0 -141
- package/dist/optimizations/OptimizedValidationEngine.js.map +0 -1
- package/dist/optimizations/QueryCompiler.d.ts +0 -51
- package/dist/optimizations/QueryCompiler.js +0 -216
- package/dist/optimizations/QueryCompiler.js.map +0 -1
- package/dist/optimizations/SQLQueryOptimizer.d.ts +0 -96
- package/dist/optimizations/SQLQueryOptimizer.js +0 -265
- package/dist/optimizations/SQLQueryOptimizer.js.map +0 -1
- package/dist/optimizations/index.d.ts +0 -32
- package/dist/optimizations/index.js +0 -44
- package/dist/optimizations/index.js.map +0 -1
- package/dist/protocol.d.ts +0 -191
- package/dist/protocol.js +0 -272
- package/dist/protocol.js.map +0 -1
- package/dist/query/filter-translator.d.ts +0 -24
- package/dist/query/filter-translator.js +0 -38
- package/dist/query/filter-translator.js.map +0 -1
- package/dist/query/index.d.ts +0 -22
- package/dist/query/index.js +0 -39
- package/dist/query/index.js.map +0 -1
- package/dist/query/query-analyzer.d.ts +0 -186
- package/dist/query/query-analyzer.js +0 -348
- package/dist/query/query-analyzer.js.map +0 -1
- package/dist/query/query-builder.d.ts +0 -27
- package/dist/query/query-builder.js +0 -69
- package/dist/query/query-builder.js.map +0 -1
- package/dist/query/query-service.d.ts +0 -151
- package/dist/query/query-service.js +0 -272
- package/dist/query/query-service.js.map +0 -1
- package/src/ai/index.ts +0 -9
- package/src/ai/registry.ts +0 -81
- package/src/gateway.ts +0 -105
- package/src/optimizations/CompiledHookManager.ts +0 -193
- package/src/optimizations/DependencyGraph.ts +0 -255
- package/src/optimizations/GlobalConnectionPool.ts +0 -251
- package/src/optimizations/LazyMetadataLoader.ts +0 -180
- package/src/optimizations/OptimizedMetadataRegistry.ts +0 -132
- package/src/optimizations/OptimizedValidationEngine.ts +0 -172
- package/src/optimizations/QueryCompiler.ts +0 -242
- package/src/optimizations/SQLQueryOptimizer.ts +0 -329
- package/src/optimizations/index.ts +0 -34
- package/src/protocol.ts +0 -304
- package/src/query/filter-translator.ts +0 -41
- package/src/query/index.ts +0 -24
- package/src/query/query-analyzer.ts +0 -532
- package/src/query/query-builder.ts +0 -64
- package/src/query/query-service.ts +0 -397
- package/test/ai-registry.test.ts +0 -42
- package/test/app.test.ts +0 -578
- package/test/filter-syntax.test.ts +0 -233
- package/test/gateway.test.ts +0 -88
- package/test/protocol.test.ts +0 -143
- package/test/repository-validation.test.ts +0 -351
- package/test/repository.test.ts +0 -151
|
@@ -1,233 +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/index';
|
|
10
|
-
import { MockDriver } from './mock-driver';
|
|
11
|
-
import { ObjectConfig } from '@objectql/types';
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Modern Filter Syntax Tests
|
|
15
|
-
*
|
|
16
|
-
* Tests the new object-based filter syntax from @objectstack/spec FilterCondition.
|
|
17
|
-
* This replaces the old array-based FilterExpression syntax.
|
|
18
|
-
*
|
|
19
|
-
* Note: These tests verify filter translation logic. Full filter functionality
|
|
20
|
-
* is tested in driver integration tests.
|
|
21
|
-
*/
|
|
22
|
-
|
|
23
|
-
const productObject: ObjectConfig = {
|
|
24
|
-
name: 'product',
|
|
25
|
-
fields: {
|
|
26
|
-
name: { type: 'text' },
|
|
27
|
-
price: { type: 'number' },
|
|
28
|
-
category: { type: 'text' },
|
|
29
|
-
status: { type: 'text' }
|
|
30
|
-
}
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
describe('Modern Filter Syntax - Translation', () => {
|
|
34
|
-
let app: ObjectQL;
|
|
35
|
-
let driver: MockDriver;
|
|
36
|
-
|
|
37
|
-
beforeEach(async () => {
|
|
38
|
-
driver = new MockDriver();
|
|
39
|
-
app = new ObjectQL({
|
|
40
|
-
datasources: {
|
|
41
|
-
default: driver
|
|
42
|
-
},
|
|
43
|
-
objects: {
|
|
44
|
-
product: productObject
|
|
45
|
-
}
|
|
46
|
-
});
|
|
47
|
-
await app.init();
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
describe('Filter Translation to Kernel', () => {
|
|
51
|
-
it('should accept object-based filter syntax', async () => {
|
|
52
|
-
const ctx = app.createContext({ userId: 'test', isSystem: true });
|
|
53
|
-
const repo = ctx.object('product');
|
|
54
|
-
|
|
55
|
-
// This should not throw - it accepts the new syntax
|
|
56
|
-
await expect(repo.find({
|
|
57
|
-
filters: { category: 'Electronics' }
|
|
58
|
-
})).resolves.toBeDefined();
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
it('should accept $eq operator', async () => {
|
|
62
|
-
const ctx = app.createContext({ userId: 'test', isSystem: true });
|
|
63
|
-
const repo = ctx.object('product');
|
|
64
|
-
|
|
65
|
-
await expect(repo.find({
|
|
66
|
-
filters: { status: { $eq: 'active' } }
|
|
67
|
-
})).resolves.toBeDefined();
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
it('should accept $ne operator', async () => {
|
|
71
|
-
const ctx = app.createContext({ userId: 'test', isSystem: true });
|
|
72
|
-
const repo = ctx.object('product');
|
|
73
|
-
|
|
74
|
-
await expect(repo.find({
|
|
75
|
-
filters: { status: { $ne: 'inactive' } }
|
|
76
|
-
})).resolves.toBeDefined();
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
it('should accept comparison operators', async () => {
|
|
80
|
-
const ctx = app.createContext({ userId: 'test', isSystem: true });
|
|
81
|
-
const repo = ctx.object('product');
|
|
82
|
-
|
|
83
|
-
await expect(repo.find({
|
|
84
|
-
filters: { price: { $gt: 100 } }
|
|
85
|
-
})).resolves.toBeDefined();
|
|
86
|
-
|
|
87
|
-
await expect(repo.find({
|
|
88
|
-
filters: { price: { $gte: 100 } }
|
|
89
|
-
})).resolves.toBeDefined();
|
|
90
|
-
|
|
91
|
-
await expect(repo.find({
|
|
92
|
-
filters: { price: { $lt: 500 } }
|
|
93
|
-
})).resolves.toBeDefined();
|
|
94
|
-
|
|
95
|
-
await expect(repo.find({
|
|
96
|
-
filters: { price: { $lte: 500 } }
|
|
97
|
-
})).resolves.toBeDefined();
|
|
98
|
-
});
|
|
99
|
-
|
|
100
|
-
it('should accept $in operator', async () => {
|
|
101
|
-
const ctx = app.createContext({ userId: 'test', isSystem: true });
|
|
102
|
-
const repo = ctx.object('product');
|
|
103
|
-
|
|
104
|
-
await expect(repo.find({
|
|
105
|
-
filters: { status: { $in: ['active', 'pending'] } }
|
|
106
|
-
})).resolves.toBeDefined();
|
|
107
|
-
});
|
|
108
|
-
|
|
109
|
-
it('should accept $nin operator', async () => {
|
|
110
|
-
const ctx = app.createContext({ userId: 'test', isSystem: true });
|
|
111
|
-
const repo = ctx.object('product');
|
|
112
|
-
|
|
113
|
-
await expect(repo.find({
|
|
114
|
-
filters: { status: { $nin: ['inactive', 'deleted'] } }
|
|
115
|
-
})).resolves.toBeDefined();
|
|
116
|
-
});
|
|
117
|
-
|
|
118
|
-
it('should accept $and operator', async () => {
|
|
119
|
-
const ctx = app.createContext({ userId: 'test', isSystem: true });
|
|
120
|
-
const repo = ctx.object('product');
|
|
121
|
-
|
|
122
|
-
await expect(repo.find({
|
|
123
|
-
filters: {
|
|
124
|
-
$and: [
|
|
125
|
-
{ category: 'Electronics' },
|
|
126
|
-
{ status: 'active' }
|
|
127
|
-
]
|
|
128
|
-
}
|
|
129
|
-
})).resolves.toBeDefined();
|
|
130
|
-
});
|
|
131
|
-
|
|
132
|
-
it('should accept $or operator', async () => {
|
|
133
|
-
const ctx = app.createContext({ userId: 'test', isSystem: true });
|
|
134
|
-
const repo = ctx.object('product');
|
|
135
|
-
|
|
136
|
-
await expect(repo.find({
|
|
137
|
-
filters: {
|
|
138
|
-
$or: [
|
|
139
|
-
{ category: 'Electronics' },
|
|
140
|
-
{ category: 'Furniture' }
|
|
141
|
-
]
|
|
142
|
-
}
|
|
143
|
-
})).resolves.toBeDefined();
|
|
144
|
-
});
|
|
145
|
-
|
|
146
|
-
it('should accept nested logical operators', async () => {
|
|
147
|
-
const ctx = app.createContext({ userId: 'test', isSystem: true });
|
|
148
|
-
const repo = ctx.object('product');
|
|
149
|
-
|
|
150
|
-
await expect(repo.find({
|
|
151
|
-
filters: {
|
|
152
|
-
$and: [
|
|
153
|
-
{
|
|
154
|
-
$or: [
|
|
155
|
-
{ category: 'Electronics' },
|
|
156
|
-
{ category: 'Furniture' }
|
|
157
|
-
]
|
|
158
|
-
},
|
|
159
|
-
{ status: 'active' }
|
|
160
|
-
]
|
|
161
|
-
}
|
|
162
|
-
})).resolves.toBeDefined();
|
|
163
|
-
});
|
|
164
|
-
|
|
165
|
-
it('should accept multiple operators on same field', async () => {
|
|
166
|
-
const ctx = app.createContext({ userId: 'test', isSystem: true });
|
|
167
|
-
const repo = ctx.object('product');
|
|
168
|
-
|
|
169
|
-
await expect(repo.find({
|
|
170
|
-
filters: {
|
|
171
|
-
price: {
|
|
172
|
-
$gte: 100,
|
|
173
|
-
$lte: 500
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
})).resolves.toBeDefined();
|
|
177
|
-
});
|
|
178
|
-
|
|
179
|
-
it('should accept mixed implicit and explicit syntax', async () => {
|
|
180
|
-
const ctx = app.createContext({ userId: 'test', isSystem: true });
|
|
181
|
-
const repo = ctx.object('product');
|
|
182
|
-
|
|
183
|
-
await expect(repo.find({
|
|
184
|
-
filters: {
|
|
185
|
-
category: 'Electronics',
|
|
186
|
-
price: { $gte: 100 }
|
|
187
|
-
}
|
|
188
|
-
})).resolves.toBeDefined();
|
|
189
|
-
});
|
|
190
|
-
});
|
|
191
|
-
|
|
192
|
-
describe('Backward Compatibility', () => {
|
|
193
|
-
it('should still support legacy array-based filter syntax', async () => {
|
|
194
|
-
const ctx = app.createContext({ userId: 'test', isSystem: true });
|
|
195
|
-
const repo = ctx.object('product');
|
|
196
|
-
|
|
197
|
-
// Old syntax should still work
|
|
198
|
-
await expect(repo.find({
|
|
199
|
-
filters: [['category', '=', 'Electronics']] as any
|
|
200
|
-
})).resolves.toBeDefined();
|
|
201
|
-
});
|
|
202
|
-
|
|
203
|
-
it('should support legacy complex filters with logical operators', async () => {
|
|
204
|
-
const ctx = app.createContext({ userId: 'test', isSystem: true });
|
|
205
|
-
const repo = ctx.object('product');
|
|
206
|
-
|
|
207
|
-
await expect(repo.find({
|
|
208
|
-
filters: [
|
|
209
|
-
['category', '=', 'Electronics'],
|
|
210
|
-
'and',
|
|
211
|
-
['status', '=', 'active']
|
|
212
|
-
] as any
|
|
213
|
-
})).resolves.toBeDefined();
|
|
214
|
-
});
|
|
215
|
-
|
|
216
|
-
it('should support legacy nested filter groups', async () => {
|
|
217
|
-
const ctx = app.createContext({ userId: 'test', isSystem: true });
|
|
218
|
-
const repo = ctx.object('product');
|
|
219
|
-
|
|
220
|
-
await expect(repo.find({
|
|
221
|
-
filters: [
|
|
222
|
-
[
|
|
223
|
-
['category', '=', 'Electronics'],
|
|
224
|
-
'or',
|
|
225
|
-
['category', '=', 'Furniture']
|
|
226
|
-
],
|
|
227
|
-
'and',
|
|
228
|
-
['status', '=', 'active']
|
|
229
|
-
] as any
|
|
230
|
-
})).resolves.toBeDefined();
|
|
231
|
-
});
|
|
232
|
-
});
|
|
233
|
-
});
|
package/test/gateway.test.ts
DELETED
|
@@ -1,88 +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 { ObjectGateway } from '../src/gateway';
|
|
10
|
-
import { ApiRequest, ApiResponse, GatewayProtocol } from '@objectql/types';
|
|
11
|
-
|
|
12
|
-
describe('ObjectGateway', () => {
|
|
13
|
-
let gateway: ObjectGateway;
|
|
14
|
-
let mockProtocol: GatewayProtocol;
|
|
15
|
-
|
|
16
|
-
beforeEach(() => {
|
|
17
|
-
gateway = new ObjectGateway();
|
|
18
|
-
mockProtocol = {
|
|
19
|
-
name: 'mock',
|
|
20
|
-
route: jest.fn().mockReturnValue(true),
|
|
21
|
-
handle: jest.fn().mockResolvedValue({ status: 200, body: 'ok' })
|
|
22
|
-
};
|
|
23
|
-
gateway.registerProtocol(mockProtocol);
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
it('should route request to registered protocol', async () => {
|
|
27
|
-
const req: ApiRequest = {
|
|
28
|
-
path: '/test',
|
|
29
|
-
method: 'GET',
|
|
30
|
-
headers: {},
|
|
31
|
-
query: {}
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
const response = await gateway.handle(req);
|
|
35
|
-
|
|
36
|
-
expect(mockProtocol.route).toHaveBeenCalledWith(req);
|
|
37
|
-
expect(mockProtocol.handle).toHaveBeenCalledWith(req);
|
|
38
|
-
expect(response.status).toBe(200);
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
it('should return 404 if no protocol matches', async () => {
|
|
42
|
-
const specializedGateway = new ObjectGateway();
|
|
43
|
-
const response = await specializedGateway.handle({
|
|
44
|
-
path: '/unknown',
|
|
45
|
-
method: 'GET',
|
|
46
|
-
headers: {},
|
|
47
|
-
query: {}
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
expect(response.status).toBe(404);
|
|
51
|
-
expect(response.body.error.code).toBe('PROTOCOL_NOT_FOUND');
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
it('should apply request transformers', async () => {
|
|
55
|
-
const req: ApiRequest = {
|
|
56
|
-
path: '/original',
|
|
57
|
-
method: 'GET',
|
|
58
|
-
headers: {},
|
|
59
|
-
query: {}
|
|
60
|
-
};
|
|
61
|
-
|
|
62
|
-
gateway.addRequestTransform(async (r) => {
|
|
63
|
-
return { ...r, path: '/transformed' };
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
await gateway.handle(req);
|
|
67
|
-
|
|
68
|
-
// Protocol should see the transformed request
|
|
69
|
-
expect(mockProtocol.route).toHaveBeenCalledWith(expect.objectContaining({ path: '/transformed' }));
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
it('should apply response transformers', async () => {
|
|
73
|
-
const req: ApiRequest = {
|
|
74
|
-
path: '/test',
|
|
75
|
-
method: 'GET',
|
|
76
|
-
headers: {},
|
|
77
|
-
query: {}
|
|
78
|
-
};
|
|
79
|
-
|
|
80
|
-
gateway.addResponseTransform(async (res) => {
|
|
81
|
-
return { ...res, headers: { ...res.headers, 'X-Custom': 'Added' } };
|
|
82
|
-
});
|
|
83
|
-
|
|
84
|
-
const response = await gateway.handle(req);
|
|
85
|
-
|
|
86
|
-
expect(response.headers?.['X-Custom']).toBe('Added');
|
|
87
|
-
});
|
|
88
|
-
});
|
package/test/protocol.test.ts
DELETED
|
@@ -1,143 +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 { ObjectStackProtocolImplementation } from '../src/protocol';
|
|
10
|
-
import { IObjectQL } from '@objectql/types';
|
|
11
|
-
|
|
12
|
-
describe('ObjectStackProtocolImplementation', () => {
|
|
13
|
-
let mockEngine: Partial<IObjectQL>;
|
|
14
|
-
let protocol: ObjectStackProtocolImplementation;
|
|
15
|
-
|
|
16
|
-
beforeEach(() => {
|
|
17
|
-
mockEngine = {
|
|
18
|
-
metadata: {
|
|
19
|
-
getTypes: jest.fn().mockReturnValue(['object']),
|
|
20
|
-
list: jest.fn().mockReturnValue([{ name: 'testObject', label: 'Test Object' }]),
|
|
21
|
-
get: jest.fn().mockReturnValue({ name: 'testObject', fields: {} }),
|
|
22
|
-
} as any,
|
|
23
|
-
// Mock kernel-like direct methods
|
|
24
|
-
find: jest.fn(),
|
|
25
|
-
get: jest.fn(),
|
|
26
|
-
create: jest.fn(),
|
|
27
|
-
update: jest.fn(),
|
|
28
|
-
delete: jest.fn(),
|
|
29
|
-
};
|
|
30
|
-
protocol = new ObjectStackProtocolImplementation(mockEngine as IObjectQL);
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
describe('Meta Operations', () => {
|
|
34
|
-
it('getMetaTypes should return types from engine metadata', async () => {
|
|
35
|
-
const result = await protocol.getMetaTypes({});
|
|
36
|
-
expect(result).toEqual({ types: ['object'] });
|
|
37
|
-
expect(mockEngine.metadata?.getTypes).toHaveBeenCalled();
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
it('getMetaItems should return items for a type', async () => {
|
|
41
|
-
const result = await protocol.getMetaItems({ type: 'object' });
|
|
42
|
-
expect(result).toEqual({
|
|
43
|
-
type: 'object',
|
|
44
|
-
items: [{ name: 'testObject', label: 'Test Object' }]
|
|
45
|
-
});
|
|
46
|
-
expect(mockEngine.metadata?.list).toHaveBeenCalledWith('object');
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
it('getMetaItem should return specific item definition', async () => {
|
|
50
|
-
const result = await protocol.getMetaItem({ type: 'object', name: 'testObject' });
|
|
51
|
-
expect(result).toEqual({ name: 'testObject', fields: {} });
|
|
52
|
-
expect(mockEngine.metadata?.get).toHaveBeenCalledWith('object', 'testObject');
|
|
53
|
-
});
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
describe('Data Operations (Direct Kernel Mode)', () => {
|
|
57
|
-
it('findData should delegate to engine.find', async () => {
|
|
58
|
-
const mockData = [{ id: '1', name: 'Test' }];
|
|
59
|
-
(mockEngine as any).find.mockResolvedValue(mockData);
|
|
60
|
-
|
|
61
|
-
const result = await protocol.findData({ object: 'testObject', query: {} });
|
|
62
|
-
expect(result).toBe(mockData);
|
|
63
|
-
expect((mockEngine as any).find).toHaveBeenCalledWith('testObject', {});
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
it('getData should delegate to engine.get', async () => {
|
|
67
|
-
const mockRecord = { id: '1', name: 'Test' };
|
|
68
|
-
(mockEngine as any).get.mockResolvedValue(mockRecord);
|
|
69
|
-
|
|
70
|
-
const result = await protocol.getData({ object: 'testObject', id: '1' });
|
|
71
|
-
expect(result).toBe(mockRecord);
|
|
72
|
-
expect((mockEngine as any).get).toHaveBeenCalledWith('testObject', '1');
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
it('createData should delegate to engine.create', async () => {
|
|
76
|
-
const newData = { name: 'New' };
|
|
77
|
-
const createdRecord = { id: '2', ...newData };
|
|
78
|
-
(mockEngine as any).create.mockResolvedValue(createdRecord);
|
|
79
|
-
|
|
80
|
-
const result = await protocol.createData({ object: 'testObject', data: newData });
|
|
81
|
-
expect(result).toBe(createdRecord);
|
|
82
|
-
expect((mockEngine as any).create).toHaveBeenCalledWith('testObject', newData);
|
|
83
|
-
});
|
|
84
|
-
|
|
85
|
-
it('updateData should delegate to engine.update', async () => {
|
|
86
|
-
const updateData = { name: 'Updated' };
|
|
87
|
-
const updatedRecord = { id: '1', ...updateData };
|
|
88
|
-
(mockEngine as any).update.mockResolvedValue(updatedRecord);
|
|
89
|
-
|
|
90
|
-
const result = await protocol.updateData({ object: 'testObject', id: '1', data: updateData });
|
|
91
|
-
expect(result).toBe(updatedRecord);
|
|
92
|
-
expect((mockEngine as any).update).toHaveBeenCalledWith('testObject', '1', updateData);
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
it('deleteData should delegate to engine.delete', async () => {
|
|
96
|
-
(mockEngine as any).delete.mockResolvedValue(true);
|
|
97
|
-
|
|
98
|
-
const result = await protocol.deleteData({ object: 'testObject', id: '1' });
|
|
99
|
-
expect(result).toEqual({ object: 'testObject', id: '1', success: true });
|
|
100
|
-
expect((mockEngine as any).delete).toHaveBeenCalledWith('testObject', '1');
|
|
101
|
-
});
|
|
102
|
-
});
|
|
103
|
-
|
|
104
|
-
describe('Legacy Mode (IObjectQL Context)', () => {
|
|
105
|
-
let mockRepo: any;
|
|
106
|
-
|
|
107
|
-
beforeEach(() => {
|
|
108
|
-
// Remove direct methods to force legacy path
|
|
109
|
-
delete (mockEngine as any).find;
|
|
110
|
-
delete (mockEngine as any).get;
|
|
111
|
-
delete (mockEngine as any).create;
|
|
112
|
-
delete (mockEngine as any).update;
|
|
113
|
-
delete (mockEngine as any).delete;
|
|
114
|
-
|
|
115
|
-
mockRepo = {
|
|
116
|
-
find: jest.fn(),
|
|
117
|
-
findOne: jest.fn(),
|
|
118
|
-
create: jest.fn(),
|
|
119
|
-
update: jest.fn(),
|
|
120
|
-
delete: jest.fn(),
|
|
121
|
-
};
|
|
122
|
-
|
|
123
|
-
(mockEngine as any).createContext = jest.fn().mockReturnValue({
|
|
124
|
-
object: jest.fn().mockReturnValue(mockRepo)
|
|
125
|
-
});
|
|
126
|
-
});
|
|
127
|
-
|
|
128
|
-
it('findData should use repo.find in legacy mode', async () => {
|
|
129
|
-
const mockData = [{ id: '1' }];
|
|
130
|
-
mockRepo.find.mockResolvedValue(mockData);
|
|
131
|
-
|
|
132
|
-
await protocol.findData({ object: 'testObject' });
|
|
133
|
-
expect(mockRepo.find).toHaveBeenCalled();
|
|
134
|
-
});
|
|
135
|
-
|
|
136
|
-
it('deleteData should use repo.delete in legacy mode', async () => {
|
|
137
|
-
mockRepo.delete.mockResolvedValue(true);
|
|
138
|
-
const result = await protocol.deleteData({ object: 'testObject', id: '1' });
|
|
139
|
-
expect(result.success).toBe(true);
|
|
140
|
-
expect(mockRepo.delete).toHaveBeenCalledWith('1');
|
|
141
|
-
});
|
|
142
|
-
});
|
|
143
|
-
});
|