@plures/pluresdb 1.4.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/LICENSE +72 -0
- package/README.md +450 -0
- package/dist/.tsbuildinfo +1 -0
- package/dist/better-sqlite3-shared.d.ts +12 -0
- package/dist/better-sqlite3-shared.d.ts.map +1 -0
- package/dist/better-sqlite3-shared.js +143 -0
- package/dist/better-sqlite3-shared.js.map +1 -0
- package/dist/better-sqlite3.d.ts +4 -0
- package/dist/better-sqlite3.d.ts.map +1 -0
- package/dist/better-sqlite3.js +8 -0
- package/dist/better-sqlite3.js.map +1 -0
- package/dist/cli.d.ts +7 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +258 -0
- package/dist/cli.js.map +1 -0
- package/dist/node-index.d.ts +148 -0
- package/dist/node-index.d.ts.map +1 -0
- package/dist/node-index.js +665 -0
- package/dist/node-index.js.map +1 -0
- package/dist/node-wrapper.d.ts +44 -0
- package/dist/node-wrapper.d.ts.map +1 -0
- package/dist/node-wrapper.js +296 -0
- package/dist/node-wrapper.js.map +1 -0
- package/dist/types/index.d.ts +28 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +3 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/node-types.d.ts +71 -0
- package/dist/types/node-types.d.ts.map +1 -0
- package/dist/types/node-types.js +6 -0
- package/dist/types/node-types.js.map +1 -0
- package/dist/vscode/extension.d.ts +81 -0
- package/dist/vscode/extension.d.ts.map +1 -0
- package/dist/vscode/extension.js +309 -0
- package/dist/vscode/extension.js.map +1 -0
- package/examples/basic-usage.d.ts +2 -0
- package/examples/basic-usage.d.ts.map +1 -0
- package/examples/basic-usage.js +26 -0
- package/examples/basic-usage.js.map +1 -0
- package/examples/basic-usage.ts +29 -0
- package/examples/vscode-extension-example/README.md +95 -0
- package/examples/vscode-extension-example/package.json +49 -0
- package/examples/vscode-extension-example/src/extension.ts +172 -0
- package/examples/vscode-extension-example/tsconfig.json +12 -0
- package/examples/vscode-extension-integration.d.ts +31 -0
- package/examples/vscode-extension-integration.d.ts.map +1 -0
- package/examples/vscode-extension-integration.js +319 -0
- package/examples/vscode-extension-integration.js.map +1 -0
- package/examples/vscode-extension-integration.ts +41 -0
- package/legacy/benchmarks/memory-benchmarks.ts +350 -0
- package/legacy/benchmarks/run-benchmarks.ts +315 -0
- package/legacy/better-sqlite3-shared.ts +157 -0
- package/legacy/better-sqlite3.ts +4 -0
- package/legacy/cli.ts +241 -0
- package/legacy/config.ts +50 -0
- package/legacy/core/crdt.ts +107 -0
- package/legacy/core/database.ts +529 -0
- package/legacy/healthcheck.ts +162 -0
- package/legacy/http/api-server.ts +438 -0
- package/legacy/index.ts +28 -0
- package/legacy/logic/rules.ts +46 -0
- package/legacy/main.rs +3 -0
- package/legacy/main.ts +197 -0
- package/legacy/network/websocket-server.ts +115 -0
- package/legacy/node-index.ts +823 -0
- package/legacy/node-wrapper.ts +329 -0
- package/legacy/sqlite-compat.ts +633 -0
- package/legacy/sqlite3-compat.ts +55 -0
- package/legacy/storage/kv-storage.ts +73 -0
- package/legacy/tests/core.test.ts +305 -0
- package/legacy/tests/fixtures/performance-data.json +71 -0
- package/legacy/tests/fixtures/test-data.json +129 -0
- package/legacy/tests/integration/api-server.test.ts +334 -0
- package/legacy/tests/integration/mesh-network.test.ts +303 -0
- package/legacy/tests/logic.test.ts +34 -0
- package/legacy/tests/performance/load.test.ts +290 -0
- package/legacy/tests/security/input-validation.test.ts +286 -0
- package/legacy/tests/unit/core.test.ts +226 -0
- package/legacy/tests/unit/subscriptions.test.ts +135 -0
- package/legacy/tests/unit/vector-search.test.ts +173 -0
- package/legacy/tests/vscode_extension_test.ts +281 -0
- package/legacy/types/index.ts +32 -0
- package/legacy/types/node-types.ts +80 -0
- package/legacy/util/debug.ts +14 -0
- package/legacy/vector/index.ts +59 -0
- package/legacy/vscode/extension.ts +387 -0
- package/package.json +127 -0
- package/scripts/compiled-crud-verify.ts +30 -0
- package/scripts/dogfood.ts +297 -0
- package/scripts/postinstall.js +156 -0
- package/scripts/release-check.js +190 -0
- package/scripts/run-tests.ts +178 -0
- package/scripts/setup-libclang.ps1 +209 -0
- package/scripts/update-changelog.js +214 -0
- package/web/README.md +27 -0
- package/web/svelte/package.json +31 -0
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
// @ts-nocheck
|
|
2
|
+
import {
|
|
3
|
+
assertEquals,
|
|
4
|
+
assertExists,
|
|
5
|
+
assertRejects,
|
|
6
|
+
} from "jsr:@std/assert@1.0.14";
|
|
7
|
+
import { GunDB } from "../../core/database.ts";
|
|
8
|
+
import { mergeNodes } from "../../core/crdt.ts";
|
|
9
|
+
import type { NodeRecord } from "../../types/index.ts";
|
|
10
|
+
|
|
11
|
+
Deno.test("Core Database - Basic CRUD Operations", async () => {
|
|
12
|
+
const db = new GunDB();
|
|
13
|
+
try {
|
|
14
|
+
const kvPath = await Deno.makeTempFile({
|
|
15
|
+
prefix: "kv_",
|
|
16
|
+
suffix: ".sqlite",
|
|
17
|
+
});
|
|
18
|
+
await db.ready(kvPath);
|
|
19
|
+
|
|
20
|
+
// Test put and get
|
|
21
|
+
const user = { name: "Alice", age: 30, email: "alice@example.com" };
|
|
22
|
+
await db.put("user:alice", user as unknown as Record<string, unknown>);
|
|
23
|
+
const got = await db.get<typeof user>("user:alice");
|
|
24
|
+
|
|
25
|
+
assertEquals(got?.name, "Alice");
|
|
26
|
+
assertEquals(got?.age, 30);
|
|
27
|
+
assertEquals(got?.email, "alice@example.com");
|
|
28
|
+
|
|
29
|
+
// Test update
|
|
30
|
+
await db.put("user:alice", { ...user, age: 31 });
|
|
31
|
+
const updated = await db.get<typeof user>("user:alice");
|
|
32
|
+
assertEquals(updated?.age, 31);
|
|
33
|
+
|
|
34
|
+
// Test delete
|
|
35
|
+
await db.delete("user:alice");
|
|
36
|
+
const deleted = await db.get<typeof user>("user:alice");
|
|
37
|
+
assertEquals(deleted, null);
|
|
38
|
+
} finally {
|
|
39
|
+
await db.close();
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
Deno.test("Core Database - Vector Clock Increments", async () => {
|
|
44
|
+
const db = new GunDB();
|
|
45
|
+
try {
|
|
46
|
+
const kvPath = await Deno.makeTempFile({
|
|
47
|
+
prefix: "kv_",
|
|
48
|
+
suffix: ".sqlite",
|
|
49
|
+
});
|
|
50
|
+
await db.ready(kvPath);
|
|
51
|
+
|
|
52
|
+
const id = "vc:test";
|
|
53
|
+
await db.put(id, { value: 1 });
|
|
54
|
+
await db.put(id, { value: 2 });
|
|
55
|
+
await db.put(id, { value: 3 });
|
|
56
|
+
|
|
57
|
+
// Inspect underlying record
|
|
58
|
+
const { KvStorage } = await import("../../storage/kv-storage.ts");
|
|
59
|
+
const kv = new KvStorage();
|
|
60
|
+
await kv.open(kvPath);
|
|
61
|
+
const node = await kv.getNode(id);
|
|
62
|
+
await kv.close();
|
|
63
|
+
|
|
64
|
+
assertExists(node);
|
|
65
|
+
const clockValues = Object.values(node.vectorClock);
|
|
66
|
+
assertEquals(clockValues.length, 1);
|
|
67
|
+
assertEquals(clockValues[0], 3);
|
|
68
|
+
} finally {
|
|
69
|
+
await db.close();
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
Deno.test("Core Database - Type System", async () => {
|
|
74
|
+
const db = new GunDB();
|
|
75
|
+
try {
|
|
76
|
+
const kvPath = await Deno.makeTempFile({
|
|
77
|
+
prefix: "kv_",
|
|
78
|
+
suffix: ".sqlite",
|
|
79
|
+
});
|
|
80
|
+
await db.ready(kvPath);
|
|
81
|
+
|
|
82
|
+
// Test setType and instancesOf
|
|
83
|
+
await db.put("person:1", { name: "Alice" });
|
|
84
|
+
await db.setType("person:1", "Person");
|
|
85
|
+
|
|
86
|
+
await db.put("company:1", { name: "Acme Corp" });
|
|
87
|
+
await db.setType("company:1", "Company");
|
|
88
|
+
|
|
89
|
+
const people = await db.instancesOf("Person");
|
|
90
|
+
assertEquals(people.length, 1);
|
|
91
|
+
assertEquals(people[0].id, "person:1");
|
|
92
|
+
|
|
93
|
+
const companies = await db.instancesOf("Company");
|
|
94
|
+
assertEquals(companies.length, 1);
|
|
95
|
+
assertEquals(companies[0].id, "company:1");
|
|
96
|
+
} finally {
|
|
97
|
+
await db.close();
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
Deno.test("Core Database - Vector Search", async () => {
|
|
102
|
+
const db = new GunDB();
|
|
103
|
+
try {
|
|
104
|
+
const kvPath = await Deno.makeTempFile({
|
|
105
|
+
prefix: "kv_",
|
|
106
|
+
suffix: ".sqlite",
|
|
107
|
+
});
|
|
108
|
+
await db.ready(kvPath);
|
|
109
|
+
|
|
110
|
+
// Add documents with text content
|
|
111
|
+
await db.put("doc:1", {
|
|
112
|
+
text: "Machine learning and artificial intelligence",
|
|
113
|
+
});
|
|
114
|
+
await db.put("doc:2", { text: "Cooking recipes and food preparation" });
|
|
115
|
+
await db.put("doc:3", { text: "Deep learning neural networks" });
|
|
116
|
+
|
|
117
|
+
// Test vector search
|
|
118
|
+
const results = await db.vectorSearch("machine learning", 2);
|
|
119
|
+
assertExists(results);
|
|
120
|
+
assertEquals(results.length, 2);
|
|
121
|
+
|
|
122
|
+
// Should find the most relevant documents
|
|
123
|
+
const docIds = results.map((r) => r.id);
|
|
124
|
+
assertExists(docIds.includes("doc:1"));
|
|
125
|
+
assertExists(docIds.includes("doc:3"));
|
|
126
|
+
} finally {
|
|
127
|
+
await db.close();
|
|
128
|
+
}
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
Deno.test("CRDT Merge - Equal Timestamps", () => {
|
|
132
|
+
const timestamp = Date.now();
|
|
133
|
+
const local: NodeRecord = {
|
|
134
|
+
id: "test:1",
|
|
135
|
+
data: { a: 1, shared: 1, nested: { x: 1, y: 1 } },
|
|
136
|
+
vector: [0.1, 0.2],
|
|
137
|
+
type: "TestType",
|
|
138
|
+
timestamp,
|
|
139
|
+
vectorClock: { peerA: 2 },
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
const incoming: NodeRecord = {
|
|
143
|
+
id: "test:1",
|
|
144
|
+
data: { b: 2, shared: 2, nested: { y: 2, z: 3 } },
|
|
145
|
+
timestamp,
|
|
146
|
+
vectorClock: { peerB: 3 },
|
|
147
|
+
} as unknown as NodeRecord;
|
|
148
|
+
|
|
149
|
+
const merged = mergeNodes(local, incoming);
|
|
150
|
+
|
|
151
|
+
assertEquals(merged.id, "test:1");
|
|
152
|
+
assertEquals(merged.timestamp, timestamp);
|
|
153
|
+
assertEquals(merged.data, {
|
|
154
|
+
a: 1,
|
|
155
|
+
shared: 2,
|
|
156
|
+
b: 2,
|
|
157
|
+
nested: { x: 1, y: 2, z: 3 },
|
|
158
|
+
});
|
|
159
|
+
assertEquals(merged.type, "TestType");
|
|
160
|
+
assertEquals(merged.vector, [0.1, 0.2]);
|
|
161
|
+
assertEquals(merged.vectorClock.peerA, 2);
|
|
162
|
+
assertEquals(merged.vectorClock.peerB, 3);
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
Deno.test("CRDT Merge - LWW on Different Timestamps", () => {
|
|
166
|
+
const t1 = 1000;
|
|
167
|
+
const t2 = 2000;
|
|
168
|
+
|
|
169
|
+
const older: NodeRecord = {
|
|
170
|
+
id: "test:2",
|
|
171
|
+
data: { a: 1, b: 1 },
|
|
172
|
+
timestamp: t1,
|
|
173
|
+
vectorClock: { p1: 1 },
|
|
174
|
+
} as unknown as NodeRecord;
|
|
175
|
+
|
|
176
|
+
const newer: NodeRecord = {
|
|
177
|
+
id: "test:2",
|
|
178
|
+
data: { a: 999, b: 2, c: 3 },
|
|
179
|
+
timestamp: t2,
|
|
180
|
+
vectorClock: { p2: 1 },
|
|
181
|
+
} as unknown as NodeRecord;
|
|
182
|
+
|
|
183
|
+
const merged = mergeNodes(older, newer);
|
|
184
|
+
|
|
185
|
+
assertEquals(merged.data, { a: 999, b: 2, c: 3 });
|
|
186
|
+
assertEquals(merged.timestamp, t2);
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
Deno.test("Core Database - Error Handling", async () => {
|
|
190
|
+
const db = new GunDB();
|
|
191
|
+
|
|
192
|
+
// Test operations before ready
|
|
193
|
+
await assertRejects(
|
|
194
|
+
() => db.put("test", { value: 1 }),
|
|
195
|
+
Error,
|
|
196
|
+
"Database not ready",
|
|
197
|
+
);
|
|
198
|
+
|
|
199
|
+
await assertRejects(() => db.get("test"), Error, "Database not ready");
|
|
200
|
+
|
|
201
|
+
await assertRejects(() => db.delete("test"), Error, "Database not ready");
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
Deno.test("Core Database - Persistence Across Restarts", async () => {
|
|
205
|
+
const kvPath = await Deno.makeTempFile({
|
|
206
|
+
prefix: "kv_",
|
|
207
|
+
suffix: ".sqlite",
|
|
208
|
+
});
|
|
209
|
+
const id = "persist:test";
|
|
210
|
+
|
|
211
|
+
// First session
|
|
212
|
+
const db1 = new GunDB();
|
|
213
|
+
await db1.ready(kvPath);
|
|
214
|
+
await db1.put(id, { value: 123, text: "persistent data" });
|
|
215
|
+
await db1.close();
|
|
216
|
+
|
|
217
|
+
// Second session
|
|
218
|
+
const db2 = new GunDB();
|
|
219
|
+
await db2.ready(kvPath);
|
|
220
|
+
const got = await db2.get<{ value: number; text: string }>(id);
|
|
221
|
+
await db2.close();
|
|
222
|
+
|
|
223
|
+
assertExists(got);
|
|
224
|
+
assertEquals(got.value, 123);
|
|
225
|
+
assertEquals(got.text, "persistent data");
|
|
226
|
+
});
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
// @ts-nocheck
|
|
2
|
+
import { assertEquals, assertThrows } from "jsr:@std/assert@1.0.14";
|
|
3
|
+
import { GunDB } from "../../core/database.ts";
|
|
4
|
+
|
|
5
|
+
Deno.test("Subscriptions - Basic Update Events", async () => {
|
|
6
|
+
const db = new GunDB();
|
|
7
|
+
try {
|
|
8
|
+
const kvPath = await Deno.makeTempFile({
|
|
9
|
+
prefix: "kv_",
|
|
10
|
+
suffix: ".sqlite",
|
|
11
|
+
});
|
|
12
|
+
await db.ready(kvPath);
|
|
13
|
+
|
|
14
|
+
const id = "user:test";
|
|
15
|
+
let updateCount = 0;
|
|
16
|
+
let lastData: any = null;
|
|
17
|
+
|
|
18
|
+
const unsubscribe = db.on(id, (node) => {
|
|
19
|
+
updateCount++;
|
|
20
|
+
lastData = node?.data;
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
// Test initial put
|
|
24
|
+
await db.put(id, { name: "Alice", age: 30 });
|
|
25
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
26
|
+
assertEquals(updateCount, 1);
|
|
27
|
+
assertEquals(lastData?.name, "Alice");
|
|
28
|
+
|
|
29
|
+
// Test update
|
|
30
|
+
await db.put(id, { name: "Alice", age: 31 });
|
|
31
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
32
|
+
assertEquals(updateCount, 2);
|
|
33
|
+
assertEquals(lastData?.age, 31);
|
|
34
|
+
|
|
35
|
+
// Test unsubscribe
|
|
36
|
+
unsubscribe();
|
|
37
|
+
await db.put(id, { name: "Alice", age: 32 });
|
|
38
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
39
|
+
assertEquals(updateCount, 2); // Should not increment
|
|
40
|
+
} finally {
|
|
41
|
+
await db.close();
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
Deno.test("Subscriptions - Delete Events", async () => {
|
|
46
|
+
const db = new GunDB();
|
|
47
|
+
try {
|
|
48
|
+
const kvPath = await Deno.makeTempFile({
|
|
49
|
+
prefix: "kv_",
|
|
50
|
+
suffix: ".sqlite",
|
|
51
|
+
});
|
|
52
|
+
await db.ready(kvPath);
|
|
53
|
+
|
|
54
|
+
const id = "user:delete";
|
|
55
|
+
let deleteReceived = false;
|
|
56
|
+
|
|
57
|
+
const unsubscribe = db.on(id, (node) => {
|
|
58
|
+
if (node === null) {
|
|
59
|
+
deleteReceived = true;
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
await db.put(id, { name: "Bob" });
|
|
64
|
+
await db.delete(id);
|
|
65
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
66
|
+
|
|
67
|
+
assertEquals(deleteReceived, true);
|
|
68
|
+
unsubscribe();
|
|
69
|
+
} finally {
|
|
70
|
+
await db.close();
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
Deno.test("Subscriptions - Multiple Subscribers", async () => {
|
|
75
|
+
const db = new GunDB();
|
|
76
|
+
try {
|
|
77
|
+
const kvPath = await Deno.makeTempFile({
|
|
78
|
+
prefix: "kv_",
|
|
79
|
+
suffix: ".sqlite",
|
|
80
|
+
});
|
|
81
|
+
await db.ready(kvPath);
|
|
82
|
+
|
|
83
|
+
const id = "user:multi";
|
|
84
|
+
let subscriber1Count = 0;
|
|
85
|
+
let subscriber2Count = 0;
|
|
86
|
+
|
|
87
|
+
const unsubscribe1 = db.on(id, () => subscriber1Count++);
|
|
88
|
+
const unsubscribe2 = db.on(id, () => subscriber2Count++);
|
|
89
|
+
|
|
90
|
+
await db.put(id, { name: "Charlie" });
|
|
91
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
92
|
+
|
|
93
|
+
assertEquals(subscriber1Count, 1);
|
|
94
|
+
assertEquals(subscriber2Count, 1);
|
|
95
|
+
|
|
96
|
+
unsubscribe1();
|
|
97
|
+
unsubscribe2();
|
|
98
|
+
} finally {
|
|
99
|
+
await db.close();
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
Deno.test("Subscriptions - Error Handling", () => {
|
|
104
|
+
const db = new GunDB();
|
|
105
|
+
|
|
106
|
+
// Test subscription before ready
|
|
107
|
+
assertThrows(() => db.on("test", () => {}), Error, "Database not ready");
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
Deno.test("Subscriptions - Off Method", async () => {
|
|
111
|
+
const db = new GunDB();
|
|
112
|
+
try {
|
|
113
|
+
const kvPath = await Deno.makeTempFile({
|
|
114
|
+
prefix: "kv_",
|
|
115
|
+
suffix: ".sqlite",
|
|
116
|
+
});
|
|
117
|
+
await db.ready(kvPath);
|
|
118
|
+
|
|
119
|
+
const id = "user:off";
|
|
120
|
+
let called = false;
|
|
121
|
+
|
|
122
|
+
const callback = () => {
|
|
123
|
+
called = true;
|
|
124
|
+
};
|
|
125
|
+
db.on(id, callback);
|
|
126
|
+
db.off(id, callback);
|
|
127
|
+
|
|
128
|
+
await db.put(id, { name: "Dave" });
|
|
129
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
130
|
+
|
|
131
|
+
assertEquals(called, false);
|
|
132
|
+
} finally {
|
|
133
|
+
await db.close();
|
|
134
|
+
}
|
|
135
|
+
});
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
// @ts-nocheck
|
|
2
|
+
import { assertEquals, assertExists } from "jsr:@std/assert@1.0.14";
|
|
3
|
+
import { GunDB } from "../../core/database.ts";
|
|
4
|
+
|
|
5
|
+
Deno.test("Vector Search - Basic Functionality", async () => {
|
|
6
|
+
const db = new GunDB();
|
|
7
|
+
try {
|
|
8
|
+
const kvPath = await Deno.makeTempFile({
|
|
9
|
+
prefix: "kv_",
|
|
10
|
+
suffix: ".sqlite",
|
|
11
|
+
});
|
|
12
|
+
await db.ready(kvPath);
|
|
13
|
+
|
|
14
|
+
// Add documents with different content
|
|
15
|
+
await db.put("doc:1", {
|
|
16
|
+
text: "Machine learning and artificial intelligence algorithms",
|
|
17
|
+
content: "Deep learning neural networks for pattern recognition",
|
|
18
|
+
});
|
|
19
|
+
await db.put("doc:2", {
|
|
20
|
+
text: "Cooking recipes and food preparation techniques",
|
|
21
|
+
content: "Italian pasta recipes and cooking methods",
|
|
22
|
+
});
|
|
23
|
+
await db.put("doc:3", {
|
|
24
|
+
text: "Web development and JavaScript programming",
|
|
25
|
+
content: "React and TypeScript for modern web applications",
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
// Test search with text field
|
|
29
|
+
const results1 = await db.vectorSearch("machine learning", 2);
|
|
30
|
+
assertExists(results1);
|
|
31
|
+
assertEquals(results1.length, 2);
|
|
32
|
+
|
|
33
|
+
// Test search with content field
|
|
34
|
+
const results2 = await db.vectorSearch("neural networks", 1);
|
|
35
|
+
assertExists(results2);
|
|
36
|
+
assertEquals(results2.length, 1);
|
|
37
|
+
assertEquals(results2[0].id, "doc:1");
|
|
38
|
+
|
|
39
|
+
// Test search with different query
|
|
40
|
+
const results3 = await db.vectorSearch("cooking food", 1);
|
|
41
|
+
assertExists(results3);
|
|
42
|
+
assertEquals(results3.length, 1);
|
|
43
|
+
assertEquals(results3[0].id, "doc:2");
|
|
44
|
+
} finally {
|
|
45
|
+
await db.close();
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
Deno.test("Vector Search - Similarity Scoring", async () => {
|
|
50
|
+
const db = new GunDB();
|
|
51
|
+
try {
|
|
52
|
+
const kvPath = await Deno.makeTempFile({
|
|
53
|
+
prefix: "kv_",
|
|
54
|
+
suffix: ".sqlite",
|
|
55
|
+
});
|
|
56
|
+
await db.ready(kvPath);
|
|
57
|
+
|
|
58
|
+
await db.put("doc:1", { text: "Machine learning algorithms" });
|
|
59
|
+
await db.put("doc:2", { text: "Machine learning and AI" });
|
|
60
|
+
await db.put("doc:3", { text: "Cooking recipes" });
|
|
61
|
+
|
|
62
|
+
const results = await db.vectorSearch("machine learning", 3);
|
|
63
|
+
assertExists(results);
|
|
64
|
+
assertEquals(results.length, 3);
|
|
65
|
+
|
|
66
|
+
// Results should be ordered by similarity (highest first)
|
|
67
|
+
assertExists(results[0].similarity);
|
|
68
|
+
assertExists(results[1].similarity);
|
|
69
|
+
assertExists(results[2].similarity);
|
|
70
|
+
|
|
71
|
+
// First result should have highest similarity
|
|
72
|
+
assertEquals(results[0].similarity >= results[1].similarity, true);
|
|
73
|
+
assertEquals(results[1].similarity >= results[2].similarity, true);
|
|
74
|
+
} finally {
|
|
75
|
+
await db.close();
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
Deno.test("Vector Search - Limit Parameter", async () => {
|
|
80
|
+
const db = new GunDB();
|
|
81
|
+
try {
|
|
82
|
+
const kvPath = await Deno.makeTempFile({
|
|
83
|
+
prefix: "kv_",
|
|
84
|
+
suffix: ".sqlite",
|
|
85
|
+
});
|
|
86
|
+
await db.ready(kvPath);
|
|
87
|
+
|
|
88
|
+
// Add multiple documents
|
|
89
|
+
for (let i = 1; i <= 10; i++) {
|
|
90
|
+
await db.put(`doc:${i}`, {
|
|
91
|
+
text: `Document ${i} about machine learning and AI`,
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Test different limits
|
|
96
|
+
const results1 = await db.vectorSearch("machine learning", 3);
|
|
97
|
+
assertEquals(results1.length, 3);
|
|
98
|
+
|
|
99
|
+
const results2 = await db.vectorSearch("machine learning", 5);
|
|
100
|
+
assertEquals(results2.length, 5);
|
|
101
|
+
|
|
102
|
+
const results3 = await db.vectorSearch("machine learning", 1);
|
|
103
|
+
assertEquals(results3.length, 1);
|
|
104
|
+
} finally {
|
|
105
|
+
await db.close();
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
Deno.test("Vector Search - Empty Results", async () => {
|
|
110
|
+
const db = new GunDB();
|
|
111
|
+
try {
|
|
112
|
+
const kvPath = await Deno.makeTempFile({
|
|
113
|
+
prefix: "kv_",
|
|
114
|
+
suffix: ".sqlite",
|
|
115
|
+
});
|
|
116
|
+
await db.ready(kvPath);
|
|
117
|
+
|
|
118
|
+
// Search in empty database
|
|
119
|
+
const results = await db.vectorSearch("anything", 5);
|
|
120
|
+
assertEquals(results.length, 0);
|
|
121
|
+
} finally {
|
|
122
|
+
await db.close();
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
Deno.test("Vector Search - Custom Vector Input", async () => {
|
|
127
|
+
const db = new GunDB();
|
|
128
|
+
try {
|
|
129
|
+
const kvPath = await Deno.makeTempFile({
|
|
130
|
+
prefix: "kv_",
|
|
131
|
+
suffix: ".sqlite",
|
|
132
|
+
});
|
|
133
|
+
await db.ready(kvPath);
|
|
134
|
+
|
|
135
|
+
// Add document with custom vector
|
|
136
|
+
const customVector = [0.1, 0.2, 0.3, 0.4, 0.5];
|
|
137
|
+
await db.put("doc:custom", {
|
|
138
|
+
text: "Custom vector document",
|
|
139
|
+
vector: customVector,
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
// Search with custom vector
|
|
143
|
+
const results = await db.vectorSearch(customVector, 1);
|
|
144
|
+
assertExists(results);
|
|
145
|
+
assertEquals(results.length, 1);
|
|
146
|
+
assertEquals(results[0].id, "doc:custom");
|
|
147
|
+
} finally {
|
|
148
|
+
await db.close();
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
Deno.test("Vector Search - No Text Content", async () => {
|
|
153
|
+
const db = new GunDB();
|
|
154
|
+
try {
|
|
155
|
+
const kvPath = await Deno.makeTempFile({
|
|
156
|
+
prefix: "kv_",
|
|
157
|
+
suffix: ".sqlite",
|
|
158
|
+
});
|
|
159
|
+
await db.ready(kvPath);
|
|
160
|
+
|
|
161
|
+
// Add document without text or content
|
|
162
|
+
await db.put("doc:no-text", {
|
|
163
|
+
name: "Document without text",
|
|
164
|
+
value: 123,
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
// Search should return empty results
|
|
168
|
+
const results = await db.vectorSearch("anything", 5);
|
|
169
|
+
assertEquals(results.length, 0);
|
|
170
|
+
} finally {
|
|
171
|
+
await db.close();
|
|
172
|
+
}
|
|
173
|
+
});
|