@bridgerust/embex 0.1.13 → 0.1.14
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/README.md +70 -97
- package/bin/embex.js +0 -0
- package/bun.lockb +0 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +17 -0
- package/dist/src/index.d.ts +8 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +26 -0
- package/dist/src/tests/integration/adapters.test.d.ts +13 -0
- package/dist/src/tests/integration/adapters.test.d.ts.map +1 -0
- package/dist/src/tests/integration/adapters.test.js +372 -0
- package/dist/src/tests/integration/aggregations.test.d.ts +6 -0
- package/dist/src/tests/integration/aggregations.test.d.ts.map +1 -0
- package/dist/src/tests/integration/aggregations.test.js +96 -0
- package/dist/src/tests/integration/api_parity.test.d.ts +6 -0
- package/dist/src/tests/integration/api_parity.test.d.ts.map +1 -0
- package/dist/src/tests/integration/api_parity.test.js +99 -0
- package/dist/src/tests/integration/batch.test.d.ts +2 -0
- package/dist/src/tests/integration/batch.test.d.ts.map +1 -0
- package/dist/src/tests/integration/batch.test.js +53 -0
- package/dist/src/tests/integration/errors.test.d.ts +6 -0
- package/dist/src/tests/integration/errors.test.d.ts.map +1 -0
- package/dist/src/tests/integration/errors.test.js +133 -0
- package/dist/src/tests/integration/features.test.d.ts +2 -0
- package/dist/src/tests/integration/features.test.d.ts.map +1 -0
- package/dist/src/tests/integration/features.test.js +37 -0
- package/dist/src/tests/integration/filters.test.d.ts +6 -0
- package/dist/src/tests/integration/filters.test.d.ts.map +1 -0
- package/dist/src/tests/integration/filters.test.js +296 -0
- package/dist/src/tests/integration/metadata.test.d.ts +6 -0
- package/dist/src/tests/integration/metadata.test.d.ts.map +1 -0
- package/dist/src/tests/integration/metadata.test.js +167 -0
- package/dist/src/tests/integration/migrations.test.d.ts +2 -0
- package/dist/src/tests/integration/migrations.test.d.ts.map +1 -0
- package/dist/src/tests/integration/migrations.test.js +55 -0
- package/dist/src/tests/integration/pooling.test.d.ts +6 -0
- package/dist/src/tests/integration/pooling.test.d.ts.map +1 -0
- package/dist/src/tests/integration/pooling.test.js +56 -0
- package/dist/src/tests/integration/search.test.d.ts +2 -0
- package/dist/src/tests/integration/search.test.d.ts.map +1 -0
- package/dist/src/tests/integration/search.test.js +37 -0
- package/dist/src/tests/integration/streaming.test.d.ts +2 -0
- package/dist/src/tests/integration/streaming.test.d.ts.map +1 -0
- package/dist/src/tests/integration/streaming.test.js +42 -0
- package/dist/src/tests/unit/basic.test.d.ts +2 -0
- package/dist/src/tests/unit/basic.test.d.ts.map +1 -0
- package/dist/src/tests/unit/basic.test.js +23 -0
- package/dist/src/tests/unit/errors.test.d.ts +2 -0
- package/dist/src/tests/unit/errors.test.d.ts.map +1 -0
- package/dist/src/tests/unit/errors.test.js +19 -0
- package/package.json +7 -6
- package/tsconfig.json +2 -0
package/README.md
CHANGED
|
@@ -1,139 +1,112 @@
|
|
|
1
1
|
# Embex (Node.js)
|
|
2
2
|
|
|
3
|
-
**The
|
|
3
|
+
**The fastest way to add vector search to your app.**
|
|
4
4
|
|
|
5
|
-
Embex is a
|
|
5
|
+
Embex is a universal vector database client that lets you start with zero setup and scale to production without rewriting code.
|
|
6
6
|
|
|
7
7
|
## 🚀 Features
|
|
8
8
|
|
|
9
|
-
- **
|
|
10
|
-
- **
|
|
9
|
+
- **Start Simple**: Use LanceDB (embedded) for zero-setup local development.
|
|
10
|
+
- **Unified API**: Switch to Qdrant, Pinecone, or Milvus just by changing the config.
|
|
11
|
+
- **Performance**: Powered by a shared Rust core with SIMD acceleration.
|
|
11
12
|
- **Type Safety**: Full TypeScript support.
|
|
12
13
|
|
|
13
14
|
## 📦 Installation
|
|
14
15
|
|
|
15
16
|
```bash
|
|
16
|
-
npm install @bridgerust/embex
|
|
17
|
-
```
|
|
18
|
-
|
|
19
|
-
```bash
|
|
20
|
-
yarn add @bridgerust/embex
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
-
```bash
|
|
24
|
-
bun add @bridgerust/embex
|
|
17
|
+
npm install @bridgerust/embex lancedb @xenova/transformers
|
|
25
18
|
```
|
|
26
19
|
|
|
27
20
|
## ⚡ Quick Start
|
|
28
21
|
|
|
29
|
-
|
|
22
|
+
Build semantic search in 5 minutes using **LanceDB** (embedded) and local embeddings. No API keys or Docker needed!
|
|
30
23
|
|
|
31
24
|
```typescript
|
|
32
|
-
import { EmbexClient } from "@bridgerust/embex";
|
|
25
|
+
import { EmbexClient, Vector } from "@bridgerust/embex";
|
|
26
|
+
import { pipeline } from "@xenova/transformers";
|
|
33
27
|
|
|
34
28
|
async function main() {
|
|
35
|
-
//
|
|
36
|
-
const
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
//
|
|
52
|
-
|
|
53
|
-
|
|
29
|
+
// 1. Setup Embedding Model
|
|
30
|
+
const generateEmbedding = await pipeline(
|
|
31
|
+
"feature-extraction",
|
|
32
|
+
"Xenova/all-MiniLM-L6-v2"
|
|
33
|
+
);
|
|
34
|
+
const embed = async (text: string) => {
|
|
35
|
+
const output = await generateEmbedding(text, {
|
|
36
|
+
pooling: "mean",
|
|
37
|
+
normalize: true,
|
|
38
|
+
});
|
|
39
|
+
return Array.from(output.data);
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
// 2. Initialize Client (uses LanceDB embedded)
|
|
43
|
+
const client = await EmbexClient.newAsync("lancedb://./data");
|
|
44
|
+
|
|
45
|
+
// 3. Create Collection (384 dimensions for MiniLM)
|
|
46
|
+
await client.createCollection("products", 384);
|
|
47
|
+
|
|
48
|
+
// 4. Insert Data
|
|
49
|
+
const documents = [
|
|
50
|
+
{ id: "1", text: "Apple iPhone 15", category: "electronics" },
|
|
51
|
+
{ id: "2", text: "Samsung Galaxy S24", category: "electronics" },
|
|
52
|
+
];
|
|
53
|
+
|
|
54
|
+
const vectors: Vector[] = [];
|
|
55
|
+
for (const doc of documents) {
|
|
56
|
+
vectors.push({
|
|
57
|
+
id: doc.id,
|
|
58
|
+
vector: await embed(doc.text),
|
|
59
|
+
metadata: { text: doc.text },
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
await client.insert("products", vectors);
|
|
64
|
+
|
|
65
|
+
// 5. Search
|
|
66
|
+
const query = "smartphone";
|
|
67
|
+
const results = await client.search({
|
|
68
|
+
collection_name: "products",
|
|
69
|
+
vector: await embed(query),
|
|
70
|
+
limit: 1,
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
console.log(`Query: '${query}'`);
|
|
74
|
+
console.log(`Match: ${results[0].metadata.text}`);
|
|
54
75
|
}
|
|
55
76
|
|
|
56
77
|
main();
|
|
57
78
|
```
|
|
58
79
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
### All Provider Quick Starts
|
|
80
|
+
## 🗺️ Development → Production Roadmap
|
|
62
81
|
|
|
63
|
-
|
|
82
|
+
| Stage | Recommendation | Why? |
|
|
83
|
+
| :------------------ | :-------------------- | :---------------------------------- |
|
|
84
|
+
| **Day 1: Learning** | **LanceDB** | Embedded. Zero setup. Free. |
|
|
85
|
+
| **Week 2: Staging** | **Qdrant / Pinecone** | Managed cloud. Connection pooling. |
|
|
86
|
+
| **Month 1: Scale** | **Milvus** | Distributed. Billion-scale vectors. |
|
|
87
|
+
| **Anytime** | **PgVector** | You already use PostgreSQL. |
|
|
64
88
|
|
|
65
|
-
|
|
66
|
-
| ------------ | --------------- | ---------------------------------------------- |
|
|
67
|
-
| **LanceDB** | None (embedded) | `npx tsx examples/lancedb/node/quickstart.ts` |
|
|
68
|
-
| **Qdrant** | Docker server | `npx tsx examples/qdrant/node/quickstart.ts` |
|
|
69
|
-
| **Pinecone** | API key | `npx tsx examples/pinecone/node/quickstart.ts` |
|
|
70
|
-
| **Chroma** | Optional server | `npx tsx examples/chroma/node/quickstart.ts` |
|
|
89
|
+
## ☁️ Switch Provider (Zero Code Changes)
|
|
71
90
|
|
|
72
|
-
|
|
91
|
+
Ready for production? Just change the initialization line.
|
|
73
92
|
|
|
74
|
-
|
|
93
|
+
**From LanceDB (Dev):**
|
|
75
94
|
|
|
76
95
|
```typescript
|
|
77
|
-
const
|
|
78
|
-
.limit(10)
|
|
79
|
-
.filter({
|
|
80
|
-
course: "CS101"
|
|
81
|
-
})
|
|
82
|
-
.execute();
|
|
96
|
+
const client = await EmbexClient.newAsync("lancedb://./data");
|
|
83
97
|
```
|
|
84
98
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
To connect to managed services like Pinecone, Qdrant Cloud, or Zilliz (Milvus), simply provide your API key and endpoint URL.
|
|
99
|
+
**To Qdrant Cloud (Prod):**
|
|
88
100
|
|
|
89
101
|
```typescript
|
|
90
|
-
import { EmbexClient } from "@bridgerust/embex";
|
|
91
|
-
|
|
92
|
-
// Connect to Pinecone
|
|
93
102
|
const client = new EmbexClient(
|
|
94
|
-
"pinecone",
|
|
95
|
-
"https://index-name.svc.pinecone.io",
|
|
96
|
-
process.env.PINECONE_API_KEY
|
|
97
|
-
);
|
|
98
|
-
|
|
99
|
-
// Connect to Qdrant Cloud
|
|
100
|
-
const qdrantClient = new EmbexClient(
|
|
101
103
|
"qdrant",
|
|
102
|
-
"https://
|
|
104
|
+
"https://your-cluster.qdrant.io",
|
|
103
105
|
process.env.QDRANT_API_KEY
|
|
104
106
|
);
|
|
105
107
|
```
|
|
106
108
|
|
|
107
|
-
### Official Documentation & API Keys
|
|
108
|
-
|
|
109
|
-
Need help finding your API key? Check the official provider documentation:
|
|
110
|
-
|
|
111
|
-
- **Pinecone**: [Authentication & API Keys](https://docs.pinecone.io/guides/get-started/quickstart#2-get-an-api-key)
|
|
112
|
-
- **Qdrant**: [Cloud Authentication](https://qdrant.tech/documentation/cloud/authentication/)
|
|
113
|
-
- **Milvus (Zilliz)**: [Manage Credentials](https://docs.zilliz.com/docs/manage-api-keys)
|
|
114
|
-
- **Weaviate**: [Authentication](https://weaviate.io/developers/weaviate/configuration/authentication)
|
|
115
|
-
- **Chroma**: [Auth & Client Settings](https://docs.trychroma.com/guides#authentication)
|
|
116
|
-
|
|
117
|
-
## 🔌 Supported Providers
|
|
118
|
-
|
|
119
|
-
| Provider | Key | Async Init? |
|
|
120
|
-
| -------- | ---------- | ----------- |
|
|
121
|
-
| Qdrant | `qdrant` | No |
|
|
122
|
-
| Chroma | `chroma` | No |
|
|
123
|
-
| Pinecone | `pinecone` | No |
|
|
124
|
-
| Weaviate | `weaviate` | No |
|
|
125
|
-
| LanceDB | `lancedb` | **Yes** |
|
|
126
|
-
| Milvus | `milvus` | **Yes** |
|
|
127
|
-
| PgVector | `pgvector` | **Yes** |
|
|
128
|
-
|
|
129
|
-
## ⭐ Star Us
|
|
130
|
-
|
|
131
|
-
If you find Embex useful, please star the repository! It helps others discover the project.
|
|
132
|
-
|
|
133
|
-
[⭐ Star on GitHub](https://github.com/bridgerust/bridgerust)
|
|
134
|
-
|
|
135
109
|
## 🔗 Resources
|
|
136
110
|
|
|
137
|
-
- **
|
|
138
|
-
- **
|
|
139
|
-
- **Documentation**: [Full Docs](https://github.com/bridgerust/bridgerust/tree/main/bindings/node/%40bridgerust/embex)
|
|
111
|
+
- **Full Documentation**: [bridgerust.dev/embex](https://bridgerust.dev/embex/introduction)
|
|
112
|
+
- **GitHub**: [bridgerust/bridgerust](https://github.com/bridgerust/bridgerust)
|
package/bin/embex.js
CHANGED
|
File without changes
|
package/bun.lockb
CHANGED
|
Binary file
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA,cAAc,OAAO,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./src"), exports);
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { Collection, EmbexClient, QueryBuilder, SearchBuilder, cli, Point } from "../native";
|
|
2
|
+
declare module "../native" {
|
|
3
|
+
interface Collection {
|
|
4
|
+
insertStream(points: AsyncIterable<Point>, parallel?: number): Promise<void>;
|
|
5
|
+
}
|
|
6
|
+
}
|
|
7
|
+
export { Collection, EmbexClient, QueryBuilder, SearchBuilder, cli, Point };
|
|
8
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,UAAU,EACV,WAAW,EACX,YAAY,EACZ,aAAa,EAEb,GAAG,EACH,KAAK,EACN,MAAM,WAAW,CAAC;AAEnB,OAAO,QAAQ,WAAW,CAAC;IACzB,UAAU,UAAU;QAClB,YAAY,CACV,MAAM,EAAE,aAAa,CAAC,KAAK,CAAC,EAC5B,QAAQ,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC,IAAI,CAAC,CAAC;KAClB;CACF;AAwBD,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,YAAY,EAAE,aAAa,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.cli = exports.SearchBuilder = exports.QueryBuilder = exports.EmbexClient = exports.Collection = void 0;
|
|
4
|
+
const native_1 = require("../native");
|
|
5
|
+
Object.defineProperty(exports, "Collection", { enumerable: true, get: function () { return native_1.Collection; } });
|
|
6
|
+
Object.defineProperty(exports, "EmbexClient", { enumerable: true, get: function () { return native_1.EmbexClient; } });
|
|
7
|
+
Object.defineProperty(exports, "QueryBuilder", { enumerable: true, get: function () { return native_1.QueryBuilder; } });
|
|
8
|
+
Object.defineProperty(exports, "SearchBuilder", { enumerable: true, get: function () { return native_1.SearchBuilder; } });
|
|
9
|
+
Object.defineProperty(exports, "cli", { enumerable: true, get: function () { return
|
|
10
|
+
// @ts-ignore
|
|
11
|
+
native_1.cli; } });
|
|
12
|
+
// Monkey patch
|
|
13
|
+
native_1.Collection.prototype.insertStream = async function (points, parallel = 5) {
|
|
14
|
+
const BATCH_SIZE = 100;
|
|
15
|
+
let batch = [];
|
|
16
|
+
for await (const point of points) {
|
|
17
|
+
batch.push(point);
|
|
18
|
+
if (batch.length >= BATCH_SIZE) {
|
|
19
|
+
await this.insertBatch(batch, BATCH_SIZE, parallel);
|
|
20
|
+
batch = [];
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
if (batch.length > 0) {
|
|
24
|
+
await this.insertBatch(batch, BATCH_SIZE, parallel);
|
|
25
|
+
}
|
|
26
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Embex Integration Tests - Node.js
|
|
3
|
+
* Tests all adapter implementations against real database instances.
|
|
4
|
+
*
|
|
5
|
+
* Run Docker Compose first: docker-compose up -d
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* cd bindings/node/@bridgerust/embex
|
|
9
|
+
* npm run build
|
|
10
|
+
* npm test tests/integration/
|
|
11
|
+
*/
|
|
12
|
+
export {};
|
|
13
|
+
//# sourceMappingURL=adapters.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adapters.test.d.ts","sourceRoot":"","sources":["../../../../src/tests/integration/adapters.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG"}
|
|
@@ -0,0 +1,372 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Embex Integration Tests - Node.js
|
|
4
|
+
* Tests all adapter implementations against real database instances.
|
|
5
|
+
*
|
|
6
|
+
* Run Docker Compose first: docker-compose up -d
|
|
7
|
+
*
|
|
8
|
+
* Usage:
|
|
9
|
+
* cd bindings/node/@bridgerust/embex
|
|
10
|
+
* npm run build
|
|
11
|
+
* npm test tests/integration/
|
|
12
|
+
*/
|
|
13
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
14
|
+
const vitest_1 = require("vitest");
|
|
15
|
+
const index_1 = require("../../index");
|
|
16
|
+
const crypto_1 = require("crypto");
|
|
17
|
+
const os_1 = require("os");
|
|
18
|
+
const path_1 = require("path");
|
|
19
|
+
const TEST_DIMENSION = 128;
|
|
20
|
+
const TEST_COLLECTION = "embex_integration_test_node";
|
|
21
|
+
function randomVector(dim = TEST_DIMENSION) {
|
|
22
|
+
return Array.from({ length: dim }, () => Math.random());
|
|
23
|
+
}
|
|
24
|
+
(0, vitest_1.describe)("Qdrant Adapter", () => {
|
|
25
|
+
let client;
|
|
26
|
+
let collection;
|
|
27
|
+
(0, vitest_1.beforeAll)(() => {
|
|
28
|
+
client = new index_1.EmbexClient("qdrant", "http://localhost:6334");
|
|
29
|
+
collection = client.collection(TEST_COLLECTION);
|
|
30
|
+
});
|
|
31
|
+
(0, vitest_1.afterAll)(async () => {
|
|
32
|
+
try {
|
|
33
|
+
await collection.deleteCollection();
|
|
34
|
+
}
|
|
35
|
+
catch (e) { }
|
|
36
|
+
});
|
|
37
|
+
(0, vitest_1.it)("should create collection", async () => {
|
|
38
|
+
try {
|
|
39
|
+
await collection.deleteCollection();
|
|
40
|
+
}
|
|
41
|
+
catch (e) { }
|
|
42
|
+
await collection.create(TEST_DIMENSION, "cosine");
|
|
43
|
+
});
|
|
44
|
+
(0, vitest_1.it)("should insert and search points", async () => {
|
|
45
|
+
try {
|
|
46
|
+
await collection.deleteCollection();
|
|
47
|
+
}
|
|
48
|
+
catch (e) { }
|
|
49
|
+
await collection.create(TEST_DIMENSION, "cosine");
|
|
50
|
+
const points = [
|
|
51
|
+
{ id: (0, crypto_1.randomUUID)(), vector: randomVector(), metadata: { category: "A" } },
|
|
52
|
+
{ id: (0, crypto_1.randomUUID)(), vector: randomVector(), metadata: { category: "B" } },
|
|
53
|
+
{ id: (0, crypto_1.randomUUID)(), vector: randomVector(), metadata: { category: "A" } },
|
|
54
|
+
];
|
|
55
|
+
await collection.insert(points);
|
|
56
|
+
const results = await collection.query(randomVector(), { limit: 2 });
|
|
57
|
+
(0, vitest_1.expect)(results.results.length).toBe(2);
|
|
58
|
+
});
|
|
59
|
+
(0, vitest_1.it)("should use search() method with direct parameters", async () => {
|
|
60
|
+
try {
|
|
61
|
+
await collection.deleteCollection();
|
|
62
|
+
}
|
|
63
|
+
catch (e) { }
|
|
64
|
+
await collection.create(TEST_DIMENSION, "cosine");
|
|
65
|
+
const points = [
|
|
66
|
+
{ id: (0, crypto_1.randomUUID)(), vector: randomVector(), metadata: { category: "A" } },
|
|
67
|
+
{ id: (0, crypto_1.randomUUID)(), vector: randomVector(), metadata: { category: "B" } },
|
|
68
|
+
];
|
|
69
|
+
await collection.insert(points);
|
|
70
|
+
const results = await collection.search(randomVector(), 2, null, true, false);
|
|
71
|
+
(0, vitest_1.expect)(results.results.length).toBe(2);
|
|
72
|
+
(0, vitest_1.expect)(results.results[0].id).toBeDefined();
|
|
73
|
+
(0, vitest_1.expect)(results.results[0].score).toBeDefined();
|
|
74
|
+
});
|
|
75
|
+
(0, vitest_1.it)("should search with filters", async () => {
|
|
76
|
+
try {
|
|
77
|
+
await collection.deleteCollection();
|
|
78
|
+
}
|
|
79
|
+
catch (e) { }
|
|
80
|
+
await collection.create(TEST_DIMENSION, "cosine");
|
|
81
|
+
const points = [
|
|
82
|
+
{
|
|
83
|
+
id: (0, crypto_1.randomUUID)(),
|
|
84
|
+
vector: randomVector(),
|
|
85
|
+
metadata: { status: "active", score: 10 },
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
id: (0, crypto_1.randomUUID)(),
|
|
89
|
+
vector: randomVector(),
|
|
90
|
+
metadata: { status: "inactive", score: 20 },
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
id: (0, crypto_1.randomUUID)(),
|
|
94
|
+
vector: randomVector(),
|
|
95
|
+
metadata: { status: "active", score: 30 },
|
|
96
|
+
},
|
|
97
|
+
];
|
|
98
|
+
await collection.insert(points);
|
|
99
|
+
const filter = {
|
|
100
|
+
op: "key",
|
|
101
|
+
args: ["status", { eq: "active" }],
|
|
102
|
+
};
|
|
103
|
+
const results = await collection.search(randomVector(), 10, filter, true, false);
|
|
104
|
+
(0, vitest_1.expect)(results.results.length).toBeGreaterThanOrEqual(2);
|
|
105
|
+
results.results.forEach((r) => {
|
|
106
|
+
(0, vitest_1.expect)(r.metadata?.status).toBe("active");
|
|
107
|
+
});
|
|
108
|
+
});
|
|
109
|
+
(0, vitest_1.it)("should use search builder pattern", async () => {
|
|
110
|
+
try {
|
|
111
|
+
await collection.deleteCollection();
|
|
112
|
+
}
|
|
113
|
+
catch (e) { }
|
|
114
|
+
await collection.create(TEST_DIMENSION, "cosine");
|
|
115
|
+
const points = [
|
|
116
|
+
{ id: (0, crypto_1.randomUUID)(), vector: randomVector(), metadata: { type: "test" } },
|
|
117
|
+
];
|
|
118
|
+
await collection.insert(points);
|
|
119
|
+
const builder = collection.buildSearch(randomVector());
|
|
120
|
+
const results = await builder
|
|
121
|
+
.limit(5)
|
|
122
|
+
.includeMetadata(true)
|
|
123
|
+
.includeVector(false)
|
|
124
|
+
.execute();
|
|
125
|
+
(0, vitest_1.expect)(results.results).toBeDefined();
|
|
126
|
+
(0, vitest_1.expect)(Array.isArray(results.results)).toBe(true);
|
|
127
|
+
});
|
|
128
|
+
(0, vitest_1.it)("should insert batch with parallel option", async () => {
|
|
129
|
+
try {
|
|
130
|
+
await collection.deleteCollection();
|
|
131
|
+
}
|
|
132
|
+
catch (e) { }
|
|
133
|
+
await collection.create(TEST_DIMENSION, "cosine");
|
|
134
|
+
const points = Array.from({ length: 50 }, () => ({
|
|
135
|
+
id: (0, crypto_1.randomUUID)(),
|
|
136
|
+
vector: randomVector(),
|
|
137
|
+
metadata: { batch: "test" },
|
|
138
|
+
}));
|
|
139
|
+
await collection.insertBatch(points, 10, 3);
|
|
140
|
+
const results = await collection.query(randomVector(), { limit: 50 });
|
|
141
|
+
(0, vitest_1.expect)(results.results.length).toBeGreaterThanOrEqual(50);
|
|
142
|
+
});
|
|
143
|
+
(0, vitest_1.it)("should delete points", async () => {
|
|
144
|
+
try {
|
|
145
|
+
await collection.deleteCollection();
|
|
146
|
+
}
|
|
147
|
+
catch (e) { }
|
|
148
|
+
await collection.create(TEST_DIMENSION, "cosine");
|
|
149
|
+
const delId = (0, crypto_1.randomUUID)();
|
|
150
|
+
await collection.insert([
|
|
151
|
+
{ id: delId, vector: randomVector(), metadata: {} },
|
|
152
|
+
]);
|
|
153
|
+
await collection.delete([delId]);
|
|
154
|
+
const results = await collection.query(randomVector(), { limit: 10 });
|
|
155
|
+
const ids = results.results.map((r) => r.id);
|
|
156
|
+
(0, vitest_1.expect)(ids).not.toContain(delId);
|
|
157
|
+
});
|
|
158
|
+
});
|
|
159
|
+
(0, vitest_1.describe)("Chroma Adapter", () => {
|
|
160
|
+
let client;
|
|
161
|
+
let collection;
|
|
162
|
+
(0, vitest_1.beforeAll)(() => {
|
|
163
|
+
client = new index_1.EmbexClient("chroma", "http://localhost:8000");
|
|
164
|
+
collection = client.collection(TEST_COLLECTION);
|
|
165
|
+
});
|
|
166
|
+
(0, vitest_1.afterAll)(async () => {
|
|
167
|
+
try {
|
|
168
|
+
await collection.deleteCollection();
|
|
169
|
+
}
|
|
170
|
+
catch (e) { }
|
|
171
|
+
});
|
|
172
|
+
(0, vitest_1.it)("should perform CRUD operations", async () => {
|
|
173
|
+
try {
|
|
174
|
+
await collection.deleteCollection();
|
|
175
|
+
}
|
|
176
|
+
catch (e) { }
|
|
177
|
+
await collection.create(TEST_DIMENSION, "cosine");
|
|
178
|
+
const points = [
|
|
179
|
+
{ id: "c1", vector: randomVector(), metadata: { type: "test" } },
|
|
180
|
+
{ id: "c2", vector: randomVector(), metadata: { type: "test" } },
|
|
181
|
+
];
|
|
182
|
+
await collection.insert(points);
|
|
183
|
+
const results = await collection.query(randomVector(), { limit: 2 });
|
|
184
|
+
(0, vitest_1.expect)(results.results.length).toBe(2);
|
|
185
|
+
});
|
|
186
|
+
(0, vitest_1.it)("should use search() method", async () => {
|
|
187
|
+
try {
|
|
188
|
+
await collection.deleteCollection();
|
|
189
|
+
}
|
|
190
|
+
catch (e) { }
|
|
191
|
+
await collection.create(TEST_DIMENSION, "cosine");
|
|
192
|
+
const points = [
|
|
193
|
+
{ id: "c3", vector: randomVector(), metadata: { type: "search" } },
|
|
194
|
+
];
|
|
195
|
+
await collection.insert(points);
|
|
196
|
+
const results = await collection.search(randomVector(), 1);
|
|
197
|
+
(0, vitest_1.expect)(results.results.length).toBeGreaterThanOrEqual(1);
|
|
198
|
+
});
|
|
199
|
+
(0, vitest_1.it)("should create collection with auto dimension inference", async () => {
|
|
200
|
+
try {
|
|
201
|
+
await collection.deleteCollection();
|
|
202
|
+
}
|
|
203
|
+
catch (e) { }
|
|
204
|
+
await collection.createAuto(undefined, "cosine");
|
|
205
|
+
const points = [
|
|
206
|
+
{ id: "c4", vector: randomVector(), metadata: { type: "auto" } },
|
|
207
|
+
{ id: "c5", vector: randomVector(), metadata: { type: "auto" } },
|
|
208
|
+
];
|
|
209
|
+
await collection.insert(points);
|
|
210
|
+
const results = await collection.query(randomVector(), { limit: 2 });
|
|
211
|
+
(0, vitest_1.expect)(results.results.length).toBe(2);
|
|
212
|
+
await collection.deleteCollection();
|
|
213
|
+
});
|
|
214
|
+
});
|
|
215
|
+
(0, vitest_1.describe)("Weaviate Adapter", () => {
|
|
216
|
+
let client;
|
|
217
|
+
let collection;
|
|
218
|
+
(0, vitest_1.beforeAll)(() => {
|
|
219
|
+
client = new index_1.EmbexClient("weaviate", "http://localhost:8080");
|
|
220
|
+
collection = client.collection("EmbexNodeTest");
|
|
221
|
+
});
|
|
222
|
+
(0, vitest_1.afterAll)(async () => {
|
|
223
|
+
try {
|
|
224
|
+
await collection.deleteCollection();
|
|
225
|
+
}
|
|
226
|
+
catch (e) { }
|
|
227
|
+
});
|
|
228
|
+
(0, vitest_1.it)("should perform CRUD operations", async () => {
|
|
229
|
+
try {
|
|
230
|
+
await collection.deleteCollection();
|
|
231
|
+
}
|
|
232
|
+
catch (e) { }
|
|
233
|
+
await collection.create(TEST_DIMENSION, "cosine");
|
|
234
|
+
const points = [
|
|
235
|
+
{ id: "w1", vector: randomVector(), metadata: { name: "test1" } },
|
|
236
|
+
{ id: "w2", vector: randomVector(), metadata: { name: "test2" } },
|
|
237
|
+
];
|
|
238
|
+
await collection.insert(points);
|
|
239
|
+
const results = await collection.query(randomVector(), { limit: 2 });
|
|
240
|
+
(0, vitest_1.expect)(results.results.length).toBeGreaterThanOrEqual(1);
|
|
241
|
+
});
|
|
242
|
+
});
|
|
243
|
+
(0, vitest_1.describe)("Milvus Adapter", () => {
|
|
244
|
+
let client;
|
|
245
|
+
let collection;
|
|
246
|
+
(0, vitest_1.beforeAll)(async () => {
|
|
247
|
+
// Milvus requires async initialization
|
|
248
|
+
client = await index_1.EmbexClient.newAsync("milvus", "http://localhost:19530");
|
|
249
|
+
collection = client.collection(TEST_COLLECTION);
|
|
250
|
+
});
|
|
251
|
+
(0, vitest_1.afterAll)(async () => {
|
|
252
|
+
try {
|
|
253
|
+
await collection.deleteCollection();
|
|
254
|
+
}
|
|
255
|
+
catch (e) { }
|
|
256
|
+
});
|
|
257
|
+
(0, vitest_1.it)("should perform CRUD operations", async () => {
|
|
258
|
+
try {
|
|
259
|
+
await collection.deleteCollection();
|
|
260
|
+
}
|
|
261
|
+
catch (e) { }
|
|
262
|
+
await collection.create(TEST_DIMENSION, "cosine");
|
|
263
|
+
const points = [
|
|
264
|
+
{ id: "m1", vector: randomVector(), metadata: {} },
|
|
265
|
+
{ id: "m2", vector: randomVector(), metadata: {} },
|
|
266
|
+
];
|
|
267
|
+
await collection.insert(points);
|
|
268
|
+
const results = await collection.query(randomVector(), { limit: 2 });
|
|
269
|
+
(0, vitest_1.expect)(results.results.length).toBeGreaterThanOrEqual(1);
|
|
270
|
+
});
|
|
271
|
+
(0, vitest_1.it)("should use search() method", async () => {
|
|
272
|
+
try {
|
|
273
|
+
await collection.deleteCollection();
|
|
274
|
+
}
|
|
275
|
+
catch (e) { }
|
|
276
|
+
await collection.create(TEST_DIMENSION, "cosine");
|
|
277
|
+
const points = [
|
|
278
|
+
{ id: "m3", vector: randomVector(), metadata: { test: "milvus" } },
|
|
279
|
+
];
|
|
280
|
+
await collection.insert(points);
|
|
281
|
+
const results = await collection.search(randomVector(), 1);
|
|
282
|
+
(0, vitest_1.expect)(results.results.length).toBeGreaterThanOrEqual(1);
|
|
283
|
+
});
|
|
284
|
+
});
|
|
285
|
+
(0, vitest_1.describe)("pgvector Adapter", () => {
|
|
286
|
+
let client;
|
|
287
|
+
let collection;
|
|
288
|
+
(0, vitest_1.beforeAll)(async () => {
|
|
289
|
+
// pgvector requires async initialization
|
|
290
|
+
client = await index_1.EmbexClient.newAsync("pgvector", "postgresql://embex:embex_test@localhost:5432/embex_test");
|
|
291
|
+
collection = client.collection(TEST_COLLECTION);
|
|
292
|
+
});
|
|
293
|
+
(0, vitest_1.afterAll)(async () => {
|
|
294
|
+
try {
|
|
295
|
+
await collection.deleteCollection();
|
|
296
|
+
}
|
|
297
|
+
catch (e) { }
|
|
298
|
+
});
|
|
299
|
+
(0, vitest_1.it)("should perform CRUD operations", async () => {
|
|
300
|
+
try {
|
|
301
|
+
await collection.deleteCollection();
|
|
302
|
+
}
|
|
303
|
+
catch (e) { }
|
|
304
|
+
await collection.create(TEST_DIMENSION, "cosine");
|
|
305
|
+
const points = [
|
|
306
|
+
{ id: "pg1", vector: randomVector(), metadata: { info: "test" } },
|
|
307
|
+
{ id: "pg2", vector: randomVector(), metadata: { info: "test" } },
|
|
308
|
+
];
|
|
309
|
+
await collection.insert(points);
|
|
310
|
+
const results = await collection.query(randomVector(), { limit: 2 });
|
|
311
|
+
(0, vitest_1.expect)(results.results.length).toBeGreaterThanOrEqual(1);
|
|
312
|
+
});
|
|
313
|
+
(0, vitest_1.it)("should use search() method with filters", async () => {
|
|
314
|
+
try {
|
|
315
|
+
await collection.deleteCollection();
|
|
316
|
+
}
|
|
317
|
+
catch (e) { }
|
|
318
|
+
await collection.create(TEST_DIMENSION, "cosine");
|
|
319
|
+
const points = [
|
|
320
|
+
{ id: "pg3", vector: randomVector(), metadata: { status: "active" } },
|
|
321
|
+
];
|
|
322
|
+
await collection.insert(points);
|
|
323
|
+
const filter = {
|
|
324
|
+
op: "key",
|
|
325
|
+
args: ["status", { eq: "active" }],
|
|
326
|
+
};
|
|
327
|
+
const results = await collection.search(randomVector(), 5, filter, true, false);
|
|
328
|
+
(0, vitest_1.expect)(results.results.length).toBeGreaterThanOrEqual(1);
|
|
329
|
+
});
|
|
330
|
+
});
|
|
331
|
+
(0, vitest_1.describe)("LanceDB Adapter", () => {
|
|
332
|
+
let client;
|
|
333
|
+
let collection;
|
|
334
|
+
const dbPath = (0, path_1.join)((0, os_1.tmpdir)(), `lancedb_node_test_${Date.now()}`);
|
|
335
|
+
(0, vitest_1.beforeAll)(async () => {
|
|
336
|
+
client = await index_1.EmbexClient.newAsync("lancedb", dbPath);
|
|
337
|
+
collection = client.collection(TEST_COLLECTION);
|
|
338
|
+
});
|
|
339
|
+
(0, vitest_1.afterAll)(async () => {
|
|
340
|
+
try {
|
|
341
|
+
await collection.deleteCollection();
|
|
342
|
+
}
|
|
343
|
+
catch (e) { }
|
|
344
|
+
});
|
|
345
|
+
(0, vitest_1.it)("should perform CRUD operations", async () => {
|
|
346
|
+
try {
|
|
347
|
+
await collection.deleteCollection();
|
|
348
|
+
}
|
|
349
|
+
catch (e) { }
|
|
350
|
+
await collection.create(TEST_DIMENSION, "cosine");
|
|
351
|
+
const points = [
|
|
352
|
+
{ id: "l1", vector: randomVector(), metadata: { name: "lance1" } },
|
|
353
|
+
{ id: "l2", vector: randomVector(), metadata: { name: "lance2" } },
|
|
354
|
+
];
|
|
355
|
+
await collection.insert(points);
|
|
356
|
+
const results = await collection.query(randomVector(), { limit: 2 });
|
|
357
|
+
(0, vitest_1.expect)(results.results.length).toBeGreaterThanOrEqual(1);
|
|
358
|
+
});
|
|
359
|
+
(0, vitest_1.it)("should use search() method", async () => {
|
|
360
|
+
try {
|
|
361
|
+
await collection.deleteCollection();
|
|
362
|
+
}
|
|
363
|
+
catch (e) { }
|
|
364
|
+
await collection.create(TEST_DIMENSION, "cosine");
|
|
365
|
+
const points = [
|
|
366
|
+
{ id: "l3", vector: randomVector(), metadata: { name: "lance3" } },
|
|
367
|
+
];
|
|
368
|
+
await collection.insert(points);
|
|
369
|
+
const results = await collection.search(randomVector(), 1, null, true, false);
|
|
370
|
+
(0, vitest_1.expect)(results.results.length).toBeGreaterThanOrEqual(1);
|
|
371
|
+
});
|
|
372
|
+
});
|