Skip to content

Commit 8e96e01

Browse files
Copilothotlong
andcommitted
Add test files for 8 contract/interface files in packages/spec/src/contracts/
Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
1 parent a6051e6 commit 8e96e01

8 files changed

Lines changed: 1313 additions & 0 deletions
Lines changed: 209 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,209 @@
1+
import { describe, it, expect } from 'vitest';
2+
import type { IDataEngine, DriverInterface } from './data-engine';
3+
4+
describe('Data Engine Contract', () => {
5+
describe('IDataEngine interface', () => {
6+
it('should allow a minimal implementation with required methods', () => {
7+
const engine: IDataEngine = {
8+
find: async (_objectName, _query?) => [],
9+
findOne: async (_objectName, _query?) => null,
10+
insert: async (_objectName, data, _options?) => data,
11+
update: async (_objectName, data, _options?) => data,
12+
delete: async (_objectName, _options?) => { return { deleted: 1 }; },
13+
count: async (_objectName, _query?) => 0,
14+
aggregate: async (_objectName, _query) => [],
15+
};
16+
17+
expect(typeof engine.find).toBe('function');
18+
expect(typeof engine.findOne).toBe('function');
19+
expect(typeof engine.insert).toBe('function');
20+
expect(typeof engine.update).toBe('function');
21+
expect(typeof engine.delete).toBe('function');
22+
expect(typeof engine.count).toBe('function');
23+
expect(typeof engine.aggregate).toBe('function');
24+
});
25+
26+
it('should perform CRUD operations', async () => {
27+
const store: any[] = [];
28+
29+
const engine: IDataEngine = {
30+
find: async () => [...store],
31+
findOne: async () => store[0] || null,
32+
insert: async (_obj, data) => {
33+
store.push(data);
34+
return data;
35+
},
36+
update: async (_obj, data) => data,
37+
delete: async () => ({ deleted: 1 }),
38+
count: async () => store.length,
39+
aggregate: async () => [],
40+
};
41+
42+
await engine.insert('users', { id: 1, name: 'Alice' });
43+
await engine.insert('users', { id: 2, name: 'Bob' });
44+
45+
const all = await engine.find('users');
46+
expect(all).toHaveLength(2);
47+
48+
const first = await engine.findOne('users');
49+
expect(first).toEqual({ id: 1, name: 'Alice' });
50+
51+
const count = await engine.count('users');
52+
expect(count).toBe(2);
53+
});
54+
55+
it('should support optional vectorFind', async () => {
56+
const engine: IDataEngine = {
57+
find: async () => [],
58+
findOne: async () => null,
59+
insert: async (_obj, data) => data,
60+
update: async (_obj, data) => data,
61+
delete: async () => ({}),
62+
count: async () => 0,
63+
aggregate: async () => [],
64+
vectorFind: async (_objectName, _vector, options?) => {
65+
return [{ id: 1, score: 0.95 }].slice(0, options?.limit ?? 10);
66+
},
67+
};
68+
69+
expect(engine.vectorFind).toBeDefined();
70+
const results = await engine.vectorFind!('documents', [0.1, 0.2, 0.3], {
71+
limit: 5,
72+
threshold: 0.8,
73+
});
74+
expect(results).toHaveLength(1);
75+
expect(results[0].score).toBe(0.95);
76+
});
77+
78+
it('should support optional batch operations', async () => {
79+
const engine: IDataEngine = {
80+
find: async () => [],
81+
findOne: async () => null,
82+
insert: async (_obj, data) => data,
83+
update: async (_obj, data) => data,
84+
delete: async () => ({}),
85+
count: async () => 0,
86+
aggregate: async () => [],
87+
batch: async (requests, options?) => {
88+
return requests.map(() => ({ success: true }));
89+
},
90+
};
91+
92+
expect(engine.batch).toBeDefined();
93+
const results = await engine.batch!(
94+
[
95+
{ object: 'users', operation: 'insert', data: { name: 'Alice' } } as any,
96+
{ object: 'users', operation: 'insert', data: { name: 'Bob' } } as any,
97+
],
98+
{ transaction: true }
99+
);
100+
expect(results).toHaveLength(2);
101+
});
102+
103+
it('should support optional execute (escape hatch)', async () => {
104+
const engine: IDataEngine = {
105+
find: async () => [],
106+
findOne: async () => null,
107+
insert: async (_obj, data) => data,
108+
update: async (_obj, data) => data,
109+
delete: async () => ({}),
110+
count: async () => 0,
111+
aggregate: async () => [],
112+
execute: async (command, options?) => {
113+
return { raw: true, command };
114+
},
115+
};
116+
117+
expect(engine.execute).toBeDefined();
118+
const result = await engine.execute!('SELECT * FROM users', { timeout: 5000 });
119+
expect(result.raw).toBe(true);
120+
});
121+
});
122+
123+
describe('DriverInterface', () => {
124+
it('should allow a minimal implementation with required methods', () => {
125+
const driver: DriverInterface = {
126+
name: 'postgres',
127+
version: '1.0.0',
128+
connect: async () => {},
129+
disconnect: async () => {},
130+
find: async (_object, _query, _options?) => [],
131+
findOne: async (_object, _query, _options?) => null,
132+
create: async (_object, data, _options?) => data,
133+
update: async (_object, _id, data, _options?) => data,
134+
delete: async (_object, _id, _options?) => ({ deleted: true }),
135+
};
136+
137+
expect(driver.name).toBe('postgres');
138+
expect(driver.version).toBe('1.0.0');
139+
expect(typeof driver.connect).toBe('function');
140+
expect(typeof driver.disconnect).toBe('function');
141+
});
142+
143+
it('should connect and disconnect', async () => {
144+
let connected = false;
145+
146+
const driver: DriverInterface = {
147+
name: 'mongo',
148+
version: '2.0.0',
149+
connect: async () => { connected = true; },
150+
disconnect: async () => { connected = false; },
151+
find: async () => [],
152+
findOne: async () => null,
153+
create: async (_obj, data) => data,
154+
update: async (_obj, _id, data) => data,
155+
delete: async () => ({}),
156+
};
157+
158+
await driver.connect();
159+
expect(connected).toBe(true);
160+
161+
await driver.disconnect();
162+
expect(connected).toBe(false);
163+
});
164+
165+
it('should support optional bulk operations', async () => {
166+
const driver: DriverInterface = {
167+
name: 'postgres',
168+
version: '1.0.0',
169+
connect: async () => {},
170+
disconnect: async () => {},
171+
find: async () => [],
172+
findOne: async () => null,
173+
create: async (_obj, data) => data,
174+
update: async (_obj, _id, data) => data,
175+
delete: async () => ({}),
176+
bulkCreate: async (_obj, data) => data,
177+
updateMany: async (_obj, _query, _data) => ({ modified: 5 }),
178+
deleteMany: async (_obj, _query) => ({ deleted: 3 }),
179+
};
180+
181+
expect(driver.bulkCreate).toBeDefined();
182+
expect(driver.updateMany).toBeDefined();
183+
expect(driver.deleteMany).toBeDefined();
184+
185+
const bulk = await driver.bulkCreate!('users', [{ name: 'A' }, { name: 'B' }]);
186+
expect(bulk).toHaveLength(2);
187+
});
188+
189+
it('should support optional count and execute', async () => {
190+
const driver: DriverInterface = {
191+
name: 'sqlite',
192+
version: '3.0.0',
193+
connect: async () => {},
194+
disconnect: async () => {},
195+
find: async () => [],
196+
findOne: async () => null,
197+
create: async (_obj, data) => data,
198+
update: async (_obj, _id, data) => data,
199+
delete: async () => ({}),
200+
count: async (_obj, _query) => 42,
201+
execute: async (command, _params?) => ({ rows: [], command }),
202+
};
203+
204+
expect(await driver.count!('users', {} as any)).toBe(42);
205+
const result = await driver.execute!('PRAGMA table_info(users)');
206+
expect(result.command).toBe('PRAGMA table_info(users)');
207+
});
208+
});
209+
});

0 commit comments

Comments
 (0)