@objectstack/objectql 1.0.11 → 1.1.0
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 +10 -10
- package/CHANGELOG.md +9 -0
- package/dist/index.d.mts +713 -33
- package/dist/index.d.ts +713 -33
- package/dist/index.js +585 -67
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +580 -67
- package/dist/index.mjs.map +1 -1
- package/package.json +11 -4
- package/src/engine.test.ts +60 -3
- package/src/engine.ts +115 -8
- package/src/index.ts +9 -1
- package/src/plugin.ts +3 -1
- package/src/protocol.ts +63 -22
- package/src/registry.test.ts +456 -25
- package/src/registry.ts +609 -53
package/src/registry.test.ts
CHANGED
|
@@ -1,27 +1,458 @@
|
|
|
1
|
-
import { describe, it, expect } from 'vitest';
|
|
2
|
-
import { SchemaRegistry } from './registry';
|
|
1
|
+
import { describe, it, expect, beforeEach } from 'vitest';
|
|
2
|
+
import { SchemaRegistry, computeFQN, parseFQN, RESERVED_NAMESPACES } from './registry';
|
|
3
3
|
|
|
4
4
|
describe('SchemaRegistry', () => {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
});
|
|
27
|
-
|
|
5
|
+
beforeEach(() => {
|
|
6
|
+
SchemaRegistry.reset();
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
// ==========================================
|
|
10
|
+
// FQN Computation Tests
|
|
11
|
+
// ==========================================
|
|
12
|
+
describe('computeFQN', () => {
|
|
13
|
+
it('should compute FQN with namespace prefix', () => {
|
|
14
|
+
expect(computeFQN('crm', 'account')).toBe('crm__account');
|
|
15
|
+
expect(computeFQN('todo', 'task')).toBe('todo__task');
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it('should not prefix reserved namespaces', () => {
|
|
19
|
+
expect(computeFQN('base', 'user')).toBe('user');
|
|
20
|
+
expect(computeFQN('system', 'organization')).toBe('organization');
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it('should not prefix undefined namespace', () => {
|
|
24
|
+
expect(computeFQN(undefined, 'task')).toBe('task');
|
|
25
|
+
});
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
describe('parseFQN', () => {
|
|
29
|
+
it('should parse FQN with namespace', () => {
|
|
30
|
+
expect(parseFQN('crm__account')).toEqual({ namespace: 'crm', shortName: 'account' });
|
|
31
|
+
expect(parseFQN('todo__task')).toEqual({ namespace: 'todo', shortName: 'task' });
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it('should parse unprefixed names', () => {
|
|
35
|
+
expect(parseFQN('user')).toEqual({ namespace: undefined, shortName: 'user' });
|
|
36
|
+
expect(parseFQN('task')).toEqual({ namespace: undefined, shortName: 'task' });
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
// ==========================================
|
|
41
|
+
// Namespace Management Tests
|
|
42
|
+
// ==========================================
|
|
43
|
+
describe('Namespace Management', () => {
|
|
44
|
+
it('should register namespace', () => {
|
|
45
|
+
SchemaRegistry.registerNamespace('crm', 'com.example.crm');
|
|
46
|
+
expect(SchemaRegistry.getNamespaceOwner('crm')).toBe('com.example.crm');
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it('should allow same package to re-register namespace', () => {
|
|
50
|
+
SchemaRegistry.registerNamespace('crm', 'com.example.crm');
|
|
51
|
+
expect(() => {
|
|
52
|
+
SchemaRegistry.registerNamespace('crm', 'com.example.crm');
|
|
53
|
+
}).not.toThrow();
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it('should throw on namespace conflict', () => {
|
|
57
|
+
SchemaRegistry.registerNamespace('crm', 'com.example.crm');
|
|
58
|
+
expect(() => {
|
|
59
|
+
SchemaRegistry.registerNamespace('crm', 'com.other.crm');
|
|
60
|
+
}).toThrow(/already registered/);
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it('should unregister namespace', () => {
|
|
64
|
+
SchemaRegistry.registerNamespace('crm', 'com.example.crm');
|
|
65
|
+
SchemaRegistry.unregisterNamespace('crm', 'com.example.crm');
|
|
66
|
+
expect(SchemaRegistry.getNamespaceOwner('crm')).toBeUndefined();
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
// ==========================================
|
|
71
|
+
// Object Ownership Tests
|
|
72
|
+
// ==========================================
|
|
73
|
+
describe('Object Ownership', () => {
|
|
74
|
+
it('should register owned object with FQN', () => {
|
|
75
|
+
const obj = { name: 'account', fields: { name: { type: 'text' } } };
|
|
76
|
+
const fqn = SchemaRegistry.registerObject(obj as any, 'com.example.crm', 'crm', 'own');
|
|
77
|
+
|
|
78
|
+
expect(fqn).toBe('crm__account');
|
|
79
|
+
const resolved = SchemaRegistry.getObject('crm__account');
|
|
80
|
+
expect(resolved).toBeDefined();
|
|
81
|
+
expect(resolved?.name).toBe('crm__account');
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it('should register object without namespace (legacy)', () => {
|
|
85
|
+
const obj = { name: 'task', fields: {} };
|
|
86
|
+
const fqn = SchemaRegistry.registerObject(obj as any, 'com.example.app');
|
|
87
|
+
|
|
88
|
+
expect(fqn).toBe('task');
|
|
89
|
+
expect(SchemaRegistry.getObject('task')).toBeDefined();
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
it('should allow only one owner per FQN', () => {
|
|
93
|
+
// Register first owner
|
|
94
|
+
const obj = { name: 'shared', fields: {} };
|
|
95
|
+
SchemaRegistry.registerObject(obj as any, 'com.vendor.a', 'vendor_a', 'own');
|
|
96
|
+
|
|
97
|
+
// Second vendor tries to own the same FQN via extension targeting
|
|
98
|
+
// They cannot own an object that's already owned by another package
|
|
99
|
+
const obj2 = { name: 'vendor_a__shared', fields: {} };
|
|
100
|
+
expect(() => {
|
|
101
|
+
SchemaRegistry.registerObject(obj2 as any, 'com.vendor.b', undefined, 'own');
|
|
102
|
+
}).toThrow(/already owned/);
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
it('should allow re-registration by same owner', () => {
|
|
106
|
+
const obj = { name: 'account', fields: { v1: { type: 'text' } } };
|
|
107
|
+
SchemaRegistry.registerObject(obj as any, 'com.example.crm', 'crm', 'own');
|
|
108
|
+
|
|
109
|
+
const obj2 = { name: 'account', fields: { v2: { type: 'text' } } };
|
|
110
|
+
expect(() => {
|
|
111
|
+
SchemaRegistry.registerObject(obj2 as any, 'com.example.crm', 'crm', 'own');
|
|
112
|
+
}).not.toThrow();
|
|
113
|
+
|
|
114
|
+
// Should have new fields
|
|
115
|
+
const resolved = SchemaRegistry.getObject('crm__account');
|
|
116
|
+
expect(resolved?.fields).toHaveProperty('v2');
|
|
117
|
+
});
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
// ==========================================
|
|
121
|
+
// Object Extension Tests
|
|
122
|
+
// ==========================================
|
|
123
|
+
describe('Object Extension', () => {
|
|
124
|
+
it('should merge extension fields into owner', () => {
|
|
125
|
+
const owner = { name: 'contact', fields: { email: { type: 'text' } } };
|
|
126
|
+
SchemaRegistry.registerObject(owner as any, 'com.base', 'base', 'own');
|
|
127
|
+
|
|
128
|
+
const ext = { name: 'contact', fields: { phone: { type: 'text' } } };
|
|
129
|
+
SchemaRegistry.registerObject(ext as any, 'com.crm', undefined, 'extend', 200);
|
|
130
|
+
|
|
131
|
+
const resolved = SchemaRegistry.getObject('contact');
|
|
132
|
+
expect(resolved?.fields).toHaveProperty('email');
|
|
133
|
+
expect(resolved?.fields).toHaveProperty('phone');
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
it('should apply priority order (higher wins)', () => {
|
|
137
|
+
const owner = { name: 'task', label: 'Task', fields: {} };
|
|
138
|
+
SchemaRegistry.registerObject(owner as any, 'com.base', 'base', 'own', 100);
|
|
139
|
+
|
|
140
|
+
const ext1 = { name: 'task', label: 'Extended Task', fields: {} };
|
|
141
|
+
SchemaRegistry.registerObject(ext1 as any, 'com.ext1', undefined, 'extend', 150);
|
|
142
|
+
|
|
143
|
+
const ext2 = { name: 'task', label: 'Final Task', fields: {} };
|
|
144
|
+
SchemaRegistry.registerObject(ext2 as any, 'com.ext2', undefined, 'extend', 250);
|
|
145
|
+
|
|
146
|
+
const resolved = SchemaRegistry.getObject('task');
|
|
147
|
+
expect(resolved?.label).toBe('Final Task'); // Higher priority wins
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
it('should merge validations additively', () => {
|
|
151
|
+
const owner = { name: 'order', fields: {}, validations: [{ type: 'required', field: 'id' }] };
|
|
152
|
+
SchemaRegistry.registerObject(owner as any, 'com.base', 'base', 'own');
|
|
153
|
+
|
|
154
|
+
const ext = { name: 'order', fields: {}, validations: [{ type: 'required', field: 'status' }] };
|
|
155
|
+
SchemaRegistry.registerObject(ext as any, 'com.ext', undefined, 'extend');
|
|
156
|
+
|
|
157
|
+
const resolved = SchemaRegistry.getObject('order');
|
|
158
|
+
expect(resolved?.validations).toHaveLength(2);
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
it('should fail extension without owner', () => {
|
|
162
|
+
const ext = { name: 'phantom', fields: {} };
|
|
163
|
+
SchemaRegistry.registerObject(ext as any, 'com.ext', undefined, 'extend');
|
|
164
|
+
|
|
165
|
+
// Should not be resolvable (no owner)
|
|
166
|
+
const resolved = SchemaRegistry.getObject('phantom');
|
|
167
|
+
expect(resolved).toBeUndefined();
|
|
168
|
+
});
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
// ==========================================
|
|
172
|
+
// Object Resolution Tests
|
|
173
|
+
// ==========================================
|
|
174
|
+
describe('Object Resolution', () => {
|
|
175
|
+
it('should resolve by FQN', () => {
|
|
176
|
+
const obj = { name: 'deal', fields: {} };
|
|
177
|
+
SchemaRegistry.registerObject(obj as any, 'com.crm', 'crm', 'own');
|
|
178
|
+
|
|
179
|
+
expect(SchemaRegistry.resolveObject('crm__deal')).toBeDefined();
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
it('should resolve by short name (fallback)', () => {
|
|
183
|
+
const obj = { name: 'task', fields: {} };
|
|
184
|
+
SchemaRegistry.registerObject(obj as any, 'com.todo', 'todo', 'own');
|
|
185
|
+
|
|
186
|
+
// Should find via fallback scan
|
|
187
|
+
expect(SchemaRegistry.getObject('task')).toBeDefined();
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
it('should cache merged objects', () => {
|
|
191
|
+
const obj = { name: 'cached', fields: {} };
|
|
192
|
+
SchemaRegistry.registerObject(obj as any, 'com.test', 'test', 'own');
|
|
193
|
+
|
|
194
|
+
const first = SchemaRegistry.resolveObject('test__cached');
|
|
195
|
+
const second = SchemaRegistry.resolveObject('test__cached');
|
|
196
|
+
expect(first).toBe(second); // Same reference (cached)
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
it('should invalidate cache on re-registration', () => {
|
|
200
|
+
const obj = { name: 'evolve', fields: { v1: { type: 'text' } } };
|
|
201
|
+
SchemaRegistry.registerObject(obj as any, 'com.test', 'test', 'own');
|
|
202
|
+
|
|
203
|
+
const first = SchemaRegistry.resolveObject('test__evolve');
|
|
204
|
+
|
|
205
|
+
const obj2 = { name: 'evolve', fields: { v2: { type: 'text' } } };
|
|
206
|
+
SchemaRegistry.registerObject(obj2 as any, 'com.test', 'test', 'own');
|
|
207
|
+
|
|
208
|
+
const second = SchemaRegistry.resolveObject('test__evolve');
|
|
209
|
+
expect(first).not.toBe(second); // Different reference (cache invalidated)
|
|
210
|
+
expect(second?.fields).toHaveProperty('v2');
|
|
211
|
+
});
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
// ==========================================
|
|
215
|
+
// getAllObjects Tests
|
|
216
|
+
// ==========================================
|
|
217
|
+
describe('getAllObjects', () => {
|
|
218
|
+
it('should return all merged objects', () => {
|
|
219
|
+
SchemaRegistry.registerObject({ name: 'a', fields: {} } as any, 'com.pkg1', 'pkg1', 'own');
|
|
220
|
+
SchemaRegistry.registerObject({ name: 'b', fields: {} } as any, 'com.pkg2', 'pkg2', 'own');
|
|
221
|
+
|
|
222
|
+
const all = SchemaRegistry.getAllObjects();
|
|
223
|
+
expect(all).toHaveLength(2);
|
|
224
|
+
expect(all.map(o => o.name).sort()).toEqual(['pkg1__a', 'pkg2__b']);
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
it('should filter by packageId', () => {
|
|
228
|
+
SchemaRegistry.registerObject({ name: 'a', fields: {} } as any, 'com.pkg1', 'pkg1', 'own');
|
|
229
|
+
SchemaRegistry.registerObject({ name: 'b', fields: {} } as any, 'com.pkg2', 'pkg2', 'own');
|
|
230
|
+
|
|
231
|
+
const filtered = SchemaRegistry.getAllObjects('com.pkg1');
|
|
232
|
+
expect(filtered).toHaveLength(1);
|
|
233
|
+
expect(filtered[0].name).toBe('pkg1__a');
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
it('should include objects where package is extender', () => {
|
|
237
|
+
SchemaRegistry.registerObject({ name: 'base_obj', fields: {} } as any, 'com.owner', 'base', 'own');
|
|
238
|
+
SchemaRegistry.registerObject({ name: 'base_obj', fields: { ext: { type: 'text' } } } as any, 'com.extender', undefined, 'extend');
|
|
239
|
+
|
|
240
|
+
// Extender should see the object
|
|
241
|
+
const filtered = SchemaRegistry.getAllObjects('com.extender');
|
|
242
|
+
expect(filtered).toHaveLength(1);
|
|
243
|
+
});
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
// ==========================================
|
|
247
|
+
// Uninstall Tests
|
|
248
|
+
// ==========================================
|
|
249
|
+
describe('Uninstall', () => {
|
|
250
|
+
it('should remove owner contribution', () => {
|
|
251
|
+
SchemaRegistry.registerObject({ name: 'removable', fields: {} } as any, 'com.pkg', 'pkg', 'own');
|
|
252
|
+
expect(SchemaRegistry.getObject('pkg__removable')).toBeDefined();
|
|
253
|
+
|
|
254
|
+
SchemaRegistry.unregisterObjectsByPackage('com.pkg');
|
|
255
|
+
expect(SchemaRegistry.getObject('pkg__removable')).toBeUndefined();
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
it('should remove extension contribution', () => {
|
|
259
|
+
SchemaRegistry.registerObject({ name: 'target', fields: { base: { type: 'text' } } } as any, 'com.owner', 'base', 'own');
|
|
260
|
+
SchemaRegistry.registerObject({ name: 'target', fields: { ext: { type: 'text' } } } as any, 'com.ext', undefined, 'extend');
|
|
261
|
+
|
|
262
|
+
SchemaRegistry.unregisterObjectsByPackage('com.ext');
|
|
263
|
+
|
|
264
|
+
const resolved = SchemaRegistry.getObject('target');
|
|
265
|
+
expect(resolved?.fields).toHaveProperty('base');
|
|
266
|
+
expect(resolved?.fields).not.toHaveProperty('ext');
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
it('should prevent uninstall of owner with active extenders', () => {
|
|
270
|
+
SchemaRegistry.registerObject({ name: 'important', fields: {} } as any, 'com.owner', 'base', 'own');
|
|
271
|
+
SchemaRegistry.registerObject({ name: 'important', fields: {} } as any, 'com.ext', undefined, 'extend');
|
|
272
|
+
|
|
273
|
+
expect(() => {
|
|
274
|
+
SchemaRegistry.unregisterObjectsByPackage('com.owner');
|
|
275
|
+
}).toThrow(/extended by/);
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
it('should allow force uninstall of owner with extenders', () => {
|
|
279
|
+
SchemaRegistry.registerObject({ name: 'forced', fields: {} } as any, 'com.owner', 'base', 'own');
|
|
280
|
+
SchemaRegistry.registerObject({ name: 'forced', fields: {} } as any, 'com.ext', undefined, 'extend');
|
|
281
|
+
|
|
282
|
+
expect(() => {
|
|
283
|
+
SchemaRegistry.unregisterObjectsByPackage('com.owner', true);
|
|
284
|
+
}).not.toThrow();
|
|
285
|
+
});
|
|
286
|
+
});
|
|
287
|
+
|
|
288
|
+
// ==========================================
|
|
289
|
+
// Contributors API Tests
|
|
290
|
+
// ==========================================
|
|
291
|
+
describe('Contributors API', () => {
|
|
292
|
+
it('should return all contributors for object', () => {
|
|
293
|
+
SchemaRegistry.registerObject({ name: 'multi', fields: {} } as any, 'com.owner', 'pkg', 'own', 100);
|
|
294
|
+
SchemaRegistry.registerObject({ name: 'pkg__multi', fields: {} } as any, 'com.ext1', undefined, 'extend', 200);
|
|
295
|
+
SchemaRegistry.registerObject({ name: 'pkg__multi', fields: {} } as any, 'com.ext2', undefined, 'extend', 300);
|
|
296
|
+
|
|
297
|
+
const contribs = SchemaRegistry.getObjectContributors('pkg__multi');
|
|
298
|
+
expect(contribs).toHaveLength(3);
|
|
299
|
+
expect(contribs[0].priority).toBe(100); // Sorted by priority
|
|
300
|
+
expect(contribs[1].priority).toBe(200);
|
|
301
|
+
expect(contribs[2].priority).toBe(300);
|
|
302
|
+
});
|
|
303
|
+
|
|
304
|
+
it('should return owner contributor', () => {
|
|
305
|
+
SchemaRegistry.registerObject({ name: 'owned', fields: {} } as any, 'com.owner', 'pkg', 'own');
|
|
306
|
+
|
|
307
|
+
const owner = SchemaRegistry.getObjectOwner('pkg__owned');
|
|
308
|
+
expect(owner).toBeDefined();
|
|
309
|
+
expect(owner?.packageId).toBe('com.owner');
|
|
310
|
+
expect(owner?.ownership).toBe('own');
|
|
311
|
+
});
|
|
312
|
+
});
|
|
313
|
+
|
|
314
|
+
// ==========================================
|
|
315
|
+
// Generic Metadata Tests (Non-Object)
|
|
316
|
+
// ==========================================
|
|
317
|
+
describe('Generic Metadata', () => {
|
|
318
|
+
it('should register and retrieve generic items', () => {
|
|
319
|
+
const item = { name: 'test_action', type: 'custom' };
|
|
320
|
+
SchemaRegistry.registerItem('actions', item, 'name', 'com.pkg');
|
|
321
|
+
|
|
322
|
+
const retrieved = SchemaRegistry.getItem('actions', 'test_action');
|
|
323
|
+
expect(retrieved).toEqual(item);
|
|
324
|
+
});
|
|
325
|
+
|
|
326
|
+
it('should list items by type with package filter', () => {
|
|
327
|
+
SchemaRegistry.registerItem('actions', { name: 'a1' }, 'name', 'com.pkg1');
|
|
328
|
+
SchemaRegistry.registerItem('actions', { name: 'a2' }, 'name', 'com.pkg2');
|
|
329
|
+
|
|
330
|
+
const filtered = SchemaRegistry.listItems('actions', 'com.pkg1');
|
|
331
|
+
expect(filtered).toHaveLength(1);
|
|
332
|
+
});
|
|
333
|
+
});
|
|
334
|
+
|
|
335
|
+
// ==========================================
|
|
336
|
+
// Package Management Tests
|
|
337
|
+
// ==========================================
|
|
338
|
+
describe('Package Management', () => {
|
|
339
|
+
it('should install package with namespace', () => {
|
|
340
|
+
const manifest = { id: 'com.test', name: 'Test', namespace: 'test', version: '1.0.0' };
|
|
341
|
+
const pkg = SchemaRegistry.installPackage(manifest as any);
|
|
342
|
+
|
|
343
|
+
expect(pkg.status).toBe('installed');
|
|
344
|
+
expect(SchemaRegistry.getNamespaceOwner('test')).toBe('com.test');
|
|
345
|
+
});
|
|
346
|
+
|
|
347
|
+
it('should uninstall package and release namespace', () => {
|
|
348
|
+
const manifest = { id: 'com.test', name: 'Test', namespace: 'test', version: '1.0.0' };
|
|
349
|
+
SchemaRegistry.installPackage(manifest as any);
|
|
350
|
+
|
|
351
|
+
SchemaRegistry.uninstallPackage('com.test');
|
|
352
|
+
expect(SchemaRegistry.getPackage('com.test')).toBeUndefined();
|
|
353
|
+
expect(SchemaRegistry.getNamespaceOwner('test')).toBeUndefined();
|
|
354
|
+
});
|
|
355
|
+
});
|
|
356
|
+
|
|
357
|
+
// ==========================================
|
|
358
|
+
// Reset Tests
|
|
359
|
+
// ==========================================
|
|
360
|
+
describe('Reset', () => {
|
|
361
|
+
it('should clear all state', () => {
|
|
362
|
+
SchemaRegistry.registerObject({ name: 'obj', fields: {} } as any, 'com.pkg', 'pkg', 'own');
|
|
363
|
+
SchemaRegistry.registerItem('actions', { name: 'act' }, 'name');
|
|
364
|
+
|
|
365
|
+
SchemaRegistry.reset();
|
|
366
|
+
|
|
367
|
+
expect(SchemaRegistry.getAllObjects()).toHaveLength(0);
|
|
368
|
+
expect(SchemaRegistry.listItems('actions')).toHaveLength(0);
|
|
369
|
+
});
|
|
370
|
+
});
|
|
371
|
+
|
|
372
|
+
// ==========================================
|
|
373
|
+
// listItems/getItem for 'object' type Tests
|
|
374
|
+
// ==========================================
|
|
375
|
+
describe('listItems and getItem for object type', () => {
|
|
376
|
+
it('listItems("object") should return all registered objects', () => {
|
|
377
|
+
SchemaRegistry.registerObject(
|
|
378
|
+
{ name: 'account', label: 'Account', fields: {} } as any,
|
|
379
|
+
'com.crm',
|
|
380
|
+
'crm',
|
|
381
|
+
'own'
|
|
382
|
+
);
|
|
383
|
+
SchemaRegistry.registerObject(
|
|
384
|
+
{ name: 'contact', label: 'Contact', fields: {} } as any,
|
|
385
|
+
'com.crm',
|
|
386
|
+
'crm',
|
|
387
|
+
'own'
|
|
388
|
+
);
|
|
389
|
+
|
|
390
|
+
const objects = SchemaRegistry.listItems('object');
|
|
391
|
+
expect(objects).toHaveLength(2);
|
|
392
|
+
expect(objects.map((o: any) => o.name).sort()).toEqual(['crm__account', 'crm__contact']);
|
|
393
|
+
});
|
|
394
|
+
|
|
395
|
+
it('listItems("objects") should return all registered objects (plural alias)', () => {
|
|
396
|
+
SchemaRegistry.registerObject(
|
|
397
|
+
{ name: 'task', label: 'Task', fields: {} } as any,
|
|
398
|
+
'com.todo',
|
|
399
|
+
'todo',
|
|
400
|
+
'own'
|
|
401
|
+
);
|
|
402
|
+
|
|
403
|
+
const objects = SchemaRegistry.listItems('objects');
|
|
404
|
+
expect(objects).toHaveLength(1);
|
|
405
|
+
expect((objects[0] as any).name).toBe('todo__task');
|
|
406
|
+
});
|
|
407
|
+
|
|
408
|
+
it('getItem("object", fqn) should return object by FQN', () => {
|
|
409
|
+
SchemaRegistry.registerObject(
|
|
410
|
+
{ name: 'lead', label: 'Lead', fields: { status: { type: 'text' } } } as any,
|
|
411
|
+
'com.crm',
|
|
412
|
+
'crm',
|
|
413
|
+
'own'
|
|
414
|
+
);
|
|
415
|
+
|
|
416
|
+
const obj = SchemaRegistry.getItem('object', 'crm__lead');
|
|
417
|
+
expect(obj).toBeDefined();
|
|
418
|
+
expect((obj as any).name).toBe('crm__lead');
|
|
419
|
+
expect((obj as any).label).toBe('Lead');
|
|
420
|
+
});
|
|
421
|
+
|
|
422
|
+
it('getItem("object", shortName) should return object by short name fallback', () => {
|
|
423
|
+
SchemaRegistry.registerObject(
|
|
424
|
+
{ name: 'opportunity', label: 'Opportunity', fields: {} } as any,
|
|
425
|
+
'com.crm',
|
|
426
|
+
'crm',
|
|
427
|
+
'own'
|
|
428
|
+
);
|
|
429
|
+
|
|
430
|
+
const obj = SchemaRegistry.getItem('object', 'opportunity');
|
|
431
|
+
expect(obj).toBeDefined();
|
|
432
|
+
expect((obj as any).name).toBe('crm__opportunity');
|
|
433
|
+
});
|
|
434
|
+
|
|
435
|
+
it('listItems("object", packageId) should filter by package', () => {
|
|
436
|
+
SchemaRegistry.registerObject(
|
|
437
|
+
{ name: 'account', fields: {} } as any,
|
|
438
|
+
'com.crm',
|
|
439
|
+
'crm',
|
|
440
|
+
'own'
|
|
441
|
+
);
|
|
442
|
+
SchemaRegistry.registerObject(
|
|
443
|
+
{ name: 'task', fields: {} } as any,
|
|
444
|
+
'com.todo',
|
|
445
|
+
'todo',
|
|
446
|
+
'own'
|
|
447
|
+
);
|
|
448
|
+
|
|
449
|
+
const crmObjects = SchemaRegistry.listItems('object', 'com.crm');
|
|
450
|
+
expect(crmObjects).toHaveLength(1);
|
|
451
|
+
expect((crmObjects[0] as any).name).toBe('crm__account');
|
|
452
|
+
|
|
453
|
+
const todoObjects = SchemaRegistry.listItems('object', 'com.todo');
|
|
454
|
+
expect(todoObjects).toHaveLength(1);
|
|
455
|
+
expect((todoObjects[0] as any).name).toBe('todo__task');
|
|
456
|
+
});
|
|
457
|
+
});
|
|
458
|
+
});
|