pomaidb 0.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/README.md +44 -0
- package/index.d.ts +73 -0
- package/index.js +400 -0
- package/lib/libpomai_c.dll +0 -0
- package/package.json +34 -0
package/README.md
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# PomaiDB JavaScript / Node.js Bindings
|
|
2
|
+
|
|
3
|
+
Official Node.js bindings for **PomaiDB**, an embedded vector database for Edge AI.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install pomaidb
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Quick Start
|
|
12
|
+
|
|
13
|
+
```javascript
|
|
14
|
+
import { Database, MetricType, QuantType } from "pomaidb";
|
|
15
|
+
|
|
16
|
+
// 1. Open Database
|
|
17
|
+
const db = Database.open({
|
|
18
|
+
path: "./test_db",
|
|
19
|
+
dim: 4,
|
|
20
|
+
metric: MetricType.L2
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
// 2. Put vectors
|
|
24
|
+
db.put(1, [1.0, 0.0, 0.0, 0.0]);
|
|
25
|
+
db.createMembrane("docs", 4);
|
|
26
|
+
db.openMembrane("docs");
|
|
27
|
+
db.put(2, [0.0, 1.0, 0.0, 0.0], {
|
|
28
|
+
membrane: "docs",
|
|
29
|
+
timestamp: Date.now(),
|
|
30
|
+
payload: Buffer.from("metadata_json")
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
// 3. Search
|
|
34
|
+
const hits = db.search([1.0, 0.0, 0.0, 0.0], 5);
|
|
35
|
+
console.log("Search hits:", hits);
|
|
36
|
+
|
|
37
|
+
// 4. Retrieve Record
|
|
38
|
+
const rec = db.get(2, "docs");
|
|
39
|
+
console.log("Retrieved record:", rec);
|
|
40
|
+
|
|
41
|
+
// 5. Cleanup
|
|
42
|
+
db.flush();
|
|
43
|
+
db.close();
|
|
44
|
+
```
|
package/index.d.ts
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
export enum MetricType {
|
|
2
|
+
L2 = 0,
|
|
3
|
+
InnerProduct = 1,
|
|
4
|
+
Cosine = 2,
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export enum QuantType {
|
|
8
|
+
None = 0,
|
|
9
|
+
SQ8 = 1,
|
|
10
|
+
FP16 = 2,
|
|
11
|
+
Bit = 3,
|
|
12
|
+
PQ8 = 4,
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface DatabaseOptions {
|
|
16
|
+
path: string;
|
|
17
|
+
dim: number;
|
|
18
|
+
shards?: number;
|
|
19
|
+
metric?: MetricType;
|
|
20
|
+
quantType?: QuantType;
|
|
21
|
+
memoryBudgetBytes?: number;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface PutOptions {
|
|
25
|
+
membrane?: string;
|
|
26
|
+
timestamp?: number;
|
|
27
|
+
payload?: Uint8Array | Buffer;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export interface SearchOptions {
|
|
31
|
+
filterJson?: string;
|
|
32
|
+
asOfTs?: number;
|
|
33
|
+
asOfLsn?: number;
|
|
34
|
+
membrane?: string;
|
|
35
|
+
startTime?: number;
|
|
36
|
+
endTime?: number;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export interface SearchHit {
|
|
40
|
+
id: number;
|
|
41
|
+
score: number;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export interface RecordView {
|
|
45
|
+
id: number;
|
|
46
|
+
vector: number[];
|
|
47
|
+
dim: number;
|
|
48
|
+
timestamp: number;
|
|
49
|
+
payload: Buffer | null;
|
|
50
|
+
membrane: string | null;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export class Database {
|
|
54
|
+
constructor(handle: any);
|
|
55
|
+
static open(options: DatabaseOptions): Database;
|
|
56
|
+
close(): void;
|
|
57
|
+
put(id: number | bigint, vector: number[], options?: PutOptions): void;
|
|
58
|
+
get(id: number | bigint, membrane?: string | null): RecordView | null;
|
|
59
|
+
exists(id: number | bigint, membrane?: string | null): boolean;
|
|
60
|
+
delete(id: number | bigint, membrane?: string | null): void;
|
|
61
|
+
search(queryVector: number[], topK?: number, options?: SearchOptions): SearchHit[];
|
|
62
|
+
flush(): void;
|
|
63
|
+
freeze(membrane?: string | null): void;
|
|
64
|
+
compact(membrane?: string | null): void;
|
|
65
|
+
createMembrane(name: string, dim: number, shardCount?: number): void;
|
|
66
|
+
dropMembrane(name: string): void;
|
|
67
|
+
openMembrane(name: string): void;
|
|
68
|
+
closeMembrane(name: string): void;
|
|
69
|
+
listMembranes(): string[];
|
|
70
|
+
getStats(): Record<string, any>;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export default Database;
|
package/index.js
ADDED
|
@@ -0,0 +1,400 @@
|
|
|
1
|
+
import koffi from "koffi";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import fs from "fs";
|
|
4
|
+
import { fileURLToPath } from "url";
|
|
5
|
+
|
|
6
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
7
|
+
|
|
8
|
+
function findLibrary() {
|
|
9
|
+
if (process.env.POMAI_C_LIB && fs.existsSync(process.env.POMAI_C_LIB)) {
|
|
10
|
+
return process.env.POMAI_C_LIB;
|
|
11
|
+
}
|
|
12
|
+
const candidates = [
|
|
13
|
+
path.join(__dirname, "lib", "libpomai_c.dll"),
|
|
14
|
+
path.join(__dirname, "lib", "pomai_c.dll"),
|
|
15
|
+
path.join(__dirname, "lib", "libpomai_c.so"),
|
|
16
|
+
path.join(__dirname, "lib", "libpomai_c.dylib"),
|
|
17
|
+
path.join(__dirname, "..", "..", "build", "libpomai_c.dll"),
|
|
18
|
+
path.join(__dirname, "..", "..", "build", "libpomai_c.so"),
|
|
19
|
+
path.join(__dirname, "..", "..", "build", "libpomai_c.dylib")
|
|
20
|
+
];
|
|
21
|
+
for (const c of candidates) {
|
|
22
|
+
if (fs.existsSync(c)) return c;
|
|
23
|
+
}
|
|
24
|
+
throw new Error("Could not locate PomaiDB native library (libpomai_c). Set POMAI_C_LIB.");
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const libPath = findLibrary();
|
|
28
|
+
const lib = koffi.load(libPath);
|
|
29
|
+
|
|
30
|
+
// Struct definitions
|
|
31
|
+
const PomaiOptions = koffi.struct("pomai_options_t", {
|
|
32
|
+
struct_size: "uint32_t",
|
|
33
|
+
path: "str",
|
|
34
|
+
shards: "uint32_t",
|
|
35
|
+
dim: "uint32_t",
|
|
36
|
+
search_threads: "uint32_t",
|
|
37
|
+
fsync_policy: "int",
|
|
38
|
+
memory_budget_bytes: "uint64_t",
|
|
39
|
+
deadline_ms: "uint32_t",
|
|
40
|
+
index_type: "uint8_t",
|
|
41
|
+
hnsw_m: "uint32_t",
|
|
42
|
+
hnsw_ef_construction: "uint32_t",
|
|
43
|
+
hnsw_ef_search: "uint32_t",
|
|
44
|
+
adaptive_threshold: "uint32_t",
|
|
45
|
+
metric: "uint8_t",
|
|
46
|
+
edge_profile: "uint8_t",
|
|
47
|
+
tick_max_ops: "uint32_t",
|
|
48
|
+
tick_max_ms: "uint32_t",
|
|
49
|
+
strict_deterministic: "bool",
|
|
50
|
+
quant_type: "uint8_t",
|
|
51
|
+
pq_m: "uint32_t",
|
|
52
|
+
memtable_flush_threshold_mb: "uint32_t",
|
|
53
|
+
auto_freeze_on_pressure: "bool",
|
|
54
|
+
max_memtable_mb: "uint32_t",
|
|
55
|
+
write_coalesce_window_us: "uint32_t",
|
|
56
|
+
write_coalesce_batch_size: "uint32_t",
|
|
57
|
+
enable_encryption_at_rest: "bool",
|
|
58
|
+
encryption_key_hex: "str"
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
const PomaiUpsert = koffi.struct("pomai_upsert_t", {
|
|
62
|
+
struct_size: "uint32_t",
|
|
63
|
+
id: "uint64_t",
|
|
64
|
+
vector: "float*",
|
|
65
|
+
dim: "uint32_t",
|
|
66
|
+
metadata: "uint8_t*",
|
|
67
|
+
metadata_len: "uint32_t",
|
|
68
|
+
membrane: "str",
|
|
69
|
+
timestamp: "uint64_t",
|
|
70
|
+
payload: "uint8_t*",
|
|
71
|
+
payload_len: "uint32_t"
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
const PomaiQuery = koffi.struct("pomai_query_t", {
|
|
75
|
+
struct_size: "uint32_t",
|
|
76
|
+
vector: "float*",
|
|
77
|
+
dim: "uint32_t",
|
|
78
|
+
topk: "uint32_t",
|
|
79
|
+
filter_expression: "str",
|
|
80
|
+
partition_device_id: "str",
|
|
81
|
+
partition_location_id: "str",
|
|
82
|
+
deadline_ms: "uint32_t",
|
|
83
|
+
flags: "uint32_t",
|
|
84
|
+
membrane: "str",
|
|
85
|
+
as_of_ts: "uint64_t",
|
|
86
|
+
as_of_lsn: "uint64_t"
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
const PomaiRecord = koffi.struct("pomai_record_t", {
|
|
90
|
+
struct_size: "uint32_t",
|
|
91
|
+
id: "uint64_t",
|
|
92
|
+
dim: "uint32_t",
|
|
93
|
+
vector: "float*",
|
|
94
|
+
metadata: "uint8_t*",
|
|
95
|
+
metadata_len: "uint32_t",
|
|
96
|
+
is_deleted: "bool",
|
|
97
|
+
timestamp: "uint64_t",
|
|
98
|
+
payload: "uint8_t*",
|
|
99
|
+
payload_len: "uint32_t"
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
const PomaiSearchResults = koffi.struct("pomai_search_results_t", {
|
|
103
|
+
struct_size: "uint32_t",
|
|
104
|
+
count: "size_t",
|
|
105
|
+
ids: "uint64_t*",
|
|
106
|
+
scores: "float*",
|
|
107
|
+
shard_ids: "uint32_t*",
|
|
108
|
+
total_shards_count: "uint32_t",
|
|
109
|
+
pruned_shards_count: "uint32_t",
|
|
110
|
+
zero_copy_pointers: "void*"
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
const PomaiStatusPtr = koffi.opaque("pomai_status_t");
|
|
114
|
+
|
|
115
|
+
// Function bindings
|
|
116
|
+
const pomai_status_free = lib.func("void pomai_status_free(pomai_status_t* status)");
|
|
117
|
+
const pomai_status_code = lib.func("int pomai_status_code(pomai_status_t* status)");
|
|
118
|
+
const pomai_status_message = lib.func("str pomai_status_message(pomai_status_t* status)");
|
|
119
|
+
|
|
120
|
+
const pomai_options_init = lib.func("void pomai_options_init(_Out_ pomai_options_t* opts)");
|
|
121
|
+
const pomai_open = lib.func("pomai_status_t* pomai_open(pomai_options_t* opts, _Out_ void** out_db)");
|
|
122
|
+
const pomai_close = lib.func("pomai_status_t* pomai_close(void* db)");
|
|
123
|
+
const pomai_flush = lib.func("pomai_status_t* pomai_flush(void* db)");
|
|
124
|
+
const pomai_freeze = lib.func("pomai_status_t* pomai_freeze(void* db)");
|
|
125
|
+
const pomai_freeze_membrane = lib.func("pomai_status_t* pomai_freeze_membrane(void* db, str membrane)");
|
|
126
|
+
const pomai_compact = lib.func("pomai_status_t* pomai_compact(void* db)");
|
|
127
|
+
const pomai_compact_membrane = lib.func("pomai_status_t* pomai_compact_membrane(void* db, str membrane_name)");
|
|
128
|
+
const pomai_get_stats_json = lib.func("pomai_status_t* pomai_get_stats_json(void* db, _Out_ void** out_json, _Out_ size_t* out_len)");
|
|
129
|
+
|
|
130
|
+
const pomai_put = lib.func("pomai_status_t* pomai_put(void* db, pomai_upsert_t* item)");
|
|
131
|
+
const pomai_put_membrane = lib.func("pomai_status_t* pomai_put_membrane(void* db, str membrane, pomai_upsert_t* item)");
|
|
132
|
+
const pomai_delete = lib.func("pomai_status_t* pomai_delete(void* db, uint64_t id)");
|
|
133
|
+
const pomai_delete_membrane = lib.func("pomai_status_t* pomai_delete_membrane(void* db, str membrane, uint64_t id)");
|
|
134
|
+
const pomai_exists = lib.func("pomai_status_t* pomai_exists(void* db, uint64_t id, _Out_ bool* out_exists)");
|
|
135
|
+
const pomai_exists_membrane = lib.func("pomai_status_t* pomai_exists_membrane(void* db, str membrane, uint64_t id, _Out_ bool* out_exists)");
|
|
136
|
+
const pomai_get = lib.func("pomai_status_t* pomai_get(void* db, uint64_t id, _Out_ void** out_record)");
|
|
137
|
+
const pomai_get_membrane = lib.func("pomai_status_t* pomai_get_membrane(void* db, str membrane, uint64_t id, _Out_ void** out_record)");
|
|
138
|
+
const pomai_record_free = lib.func("void pomai_record_free(void* record)");
|
|
139
|
+
|
|
140
|
+
const pomai_search = lib.func("pomai_status_t* pomai_search(void* db, pomai_query_t* query, _Out_ void** out)");
|
|
141
|
+
const pomai_search_membrane = lib.func("pomai_status_t* pomai_search_membrane(void* db, str membrane, pomai_query_t* query, _Out_ void** out)");
|
|
142
|
+
const pomai_search_results_free = lib.func("void pomai_search_results_free(void* results)");
|
|
143
|
+
|
|
144
|
+
const pomai_create_membrane_kind = lib.func("pomai_status_t* pomai_create_membrane_kind(void* db, str name, uint32_t dim, uint32_t shard_count, uint32_t kind)");
|
|
145
|
+
const pomai_drop_membrane = lib.func("pomai_status_t* pomai_drop_membrane(void* db, str membrane_name)");
|
|
146
|
+
const pomai_open_membrane = lib.func("pomai_status_t* pomai_open_membrane(void* db, str membrane_name)");
|
|
147
|
+
const pomai_close_membrane = lib.func("pomai_status_t* pomai_close_membrane(void* db, str membrane_name)");
|
|
148
|
+
const pomai_list_membranes_json = lib.func("pomai_status_t* pomai_list_membranes_json(void* db, _Out_ void** out_json, _Out_ size_t* out_len)");
|
|
149
|
+
|
|
150
|
+
const pomai_free = lib.func("void pomai_free(void* ptr)");
|
|
151
|
+
|
|
152
|
+
function checkStatus(st) {
|
|
153
|
+
if (st !== null && st !== undefined) {
|
|
154
|
+
const code = pomai_status_code(st);
|
|
155
|
+
const msg = pomai_status_message(st);
|
|
156
|
+
pomai_status_free(st);
|
|
157
|
+
throw new Error(`PomaiDB error (code ${code}): ${msg || "Unknown error"}`);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
export const MetricType = {
|
|
162
|
+
L2: 0,
|
|
163
|
+
InnerProduct: 1,
|
|
164
|
+
Cosine: 2
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
export const QuantType = {
|
|
168
|
+
None: 0,
|
|
169
|
+
SQ8: 1,
|
|
170
|
+
FP16: 2,
|
|
171
|
+
Bit: 3,
|
|
172
|
+
PQ8: 4
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
export class Database {
|
|
176
|
+
constructor(handle) {
|
|
177
|
+
this._handle = handle;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
static open(options) {
|
|
181
|
+
const opts = { struct_size: koffi.sizeof(PomaiOptions) };
|
|
182
|
+
pomai_options_init(opts);
|
|
183
|
+
opts.struct_size = koffi.sizeof(PomaiOptions);
|
|
184
|
+
opts.path = options.path;
|
|
185
|
+
opts.dim = options.dim;
|
|
186
|
+
opts.shards = options.shards || 1;
|
|
187
|
+
opts.metric = options.metric !== undefined ? options.metric : MetricType.L2;
|
|
188
|
+
opts.quant_type = options.quantType !== undefined ? options.quantType : QuantType.None;
|
|
189
|
+
if (options.memoryBudgetBytes) opts.memory_budget_bytes = BigInt(options.memoryBudgetBytes);
|
|
190
|
+
|
|
191
|
+
const outDb = [null];
|
|
192
|
+
checkStatus(pomai_open(opts, outDb));
|
|
193
|
+
return new Database(outDb[0]);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
close() {
|
|
197
|
+
if (this._handle) {
|
|
198
|
+
checkStatus(pomai_close(this._handle));
|
|
199
|
+
this._handle = null;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
put(id, vector, options = {}) {
|
|
204
|
+
const upsert = {
|
|
205
|
+
struct_size: koffi.sizeof(PomaiUpsert),
|
|
206
|
+
id: BigInt(id),
|
|
207
|
+
vector: vector,
|
|
208
|
+
dim: vector.length,
|
|
209
|
+
metadata: null,
|
|
210
|
+
metadata_len: 0,
|
|
211
|
+
membrane: options.membrane || null,
|
|
212
|
+
timestamp: BigInt(options.timestamp || 0),
|
|
213
|
+
payload: options.payload ? Buffer.from(options.payload) : null,
|
|
214
|
+
payload_len: options.payload ? options.payload.length : 0
|
|
215
|
+
};
|
|
216
|
+
if (options.membrane) {
|
|
217
|
+
checkStatus(pomai_put_membrane(this._handle, options.membrane, upsert));
|
|
218
|
+
} else {
|
|
219
|
+
checkStatus(pomai_put(this._handle, upsert));
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
get(id, membrane = null) {
|
|
224
|
+
const outRec = [null];
|
|
225
|
+
try {
|
|
226
|
+
if (membrane) {
|
|
227
|
+
checkStatus(pomai_get_membrane(this._handle, membrane, BigInt(id), outRec));
|
|
228
|
+
} else {
|
|
229
|
+
checkStatus(pomai_get(this._handle, BigInt(id), outRec));
|
|
230
|
+
}
|
|
231
|
+
} catch (e) {
|
|
232
|
+
return null;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
const recPtr = outRec[0];
|
|
236
|
+
if (!recPtr) return null;
|
|
237
|
+
|
|
238
|
+
try {
|
|
239
|
+
function decodeFloats(ptr, count) {
|
|
240
|
+
const arr = new Float32Array(count);
|
|
241
|
+
for (let i = 0; i < count; i++) {
|
|
242
|
+
arr[i] = koffi.decode(ptr, i * 4, "float");
|
|
243
|
+
}
|
|
244
|
+
return arr;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
function decodeBytes(ptr, len) {
|
|
248
|
+
const buf = Buffer.alloc(len);
|
|
249
|
+
for (let i = 0; i < len; i++) {
|
|
250
|
+
buf[i] = koffi.decode(ptr, i, "uint8_t");
|
|
251
|
+
}
|
|
252
|
+
return buf;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
const rec = koffi.decode(recPtr, PomaiRecord);
|
|
256
|
+
const vec = decodeFloats(rec.vector, rec.dim);
|
|
257
|
+
let payload = null;
|
|
258
|
+
if (rec.payload && rec.payload_len > 0) {
|
|
259
|
+
payload = decodeBytes(rec.payload, rec.payload_len);
|
|
260
|
+
}
|
|
261
|
+
return {
|
|
262
|
+
id: Number(rec.id),
|
|
263
|
+
vector: Array.from(vec),
|
|
264
|
+
dim: rec.dim,
|
|
265
|
+
timestamp: Number(rec.timestamp),
|
|
266
|
+
payload: payload,
|
|
267
|
+
isDeleted: rec.is_deleted
|
|
268
|
+
};
|
|
269
|
+
} finally {
|
|
270
|
+
pomai_record_free(recPtr);
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
exists(id, membrane = null) {
|
|
275
|
+
const out = [false];
|
|
276
|
+
if (membrane) {
|
|
277
|
+
checkStatus(pomai_exists_membrane(this._handle, membrane, BigInt(id), out));
|
|
278
|
+
} else {
|
|
279
|
+
checkStatus(pomai_exists(this._handle, BigInt(id), out));
|
|
280
|
+
}
|
|
281
|
+
return out[0];
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
delete(id, membrane = null) {
|
|
285
|
+
if (membrane) {
|
|
286
|
+
checkStatus(pomai_delete_membrane(this._handle, membrane, BigInt(id)));
|
|
287
|
+
} else {
|
|
288
|
+
checkStatus(pomai_delete(this._handle, BigInt(id)));
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
search(queryVector, topK = 10, options = {}) {
|
|
293
|
+
const q = {
|
|
294
|
+
struct_size: koffi.sizeof(PomaiQuery),
|
|
295
|
+
vector: queryVector,
|
|
296
|
+
dim: queryVector.length,
|
|
297
|
+
topk: topK,
|
|
298
|
+
filter_expression: options.filterExpression || null,
|
|
299
|
+
partition_device_id: null,
|
|
300
|
+
partition_location_id: null,
|
|
301
|
+
deadline_ms: 0,
|
|
302
|
+
flags: 0,
|
|
303
|
+
membrane: options.membrane || null,
|
|
304
|
+
as_of_ts: BigInt(options.asOfTs || 0),
|
|
305
|
+
as_of_lsn: BigInt(options.asOfLsn || 0)
|
|
306
|
+
};
|
|
307
|
+
|
|
308
|
+
const outResults = [null];
|
|
309
|
+
if (options.membrane) {
|
|
310
|
+
checkStatus(pomai_search_membrane(this._handle, options.membrane, q, outResults));
|
|
311
|
+
} else {
|
|
312
|
+
checkStatus(pomai_search(this._handle, q, outResults));
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
const resPtr = outResults[0];
|
|
316
|
+
if (!resPtr) return [];
|
|
317
|
+
|
|
318
|
+
try {
|
|
319
|
+
const res = koffi.decode(resPtr, PomaiSearchResults);
|
|
320
|
+
const hits = [];
|
|
321
|
+
const count = Number(res.count);
|
|
322
|
+
if (count > 0 && res.ids && res.scores) {
|
|
323
|
+
for (let i = 0; i < count; ++i) {
|
|
324
|
+
const id = koffi.decode(res.ids, i * 8, "uint64_t");
|
|
325
|
+
const score = koffi.decode(res.scores, i * 4, "float");
|
|
326
|
+
hits.push({ id: Number(id), score: score });
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
return hits;
|
|
330
|
+
} finally {
|
|
331
|
+
pomai_search_results_free(resPtr);
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
flush() {
|
|
336
|
+
checkStatus(pomai_flush(this._handle));
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
freeze(membrane = null) {
|
|
340
|
+
if (membrane) {
|
|
341
|
+
checkStatus(pomai_freeze_membrane(this._handle, membrane));
|
|
342
|
+
} else {
|
|
343
|
+
checkStatus(pomai_freeze(this._handle));
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
compact(membrane = null) {
|
|
348
|
+
if (membrane) {
|
|
349
|
+
checkStatus(pomai_compact_membrane(this._handle, membrane));
|
|
350
|
+
} else {
|
|
351
|
+
checkStatus(pomai_compact(this._handle));
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
createMembrane(name, dim, shardCount = 1) {
|
|
356
|
+
checkStatus(pomai_create_membrane_kind(this._handle, name, dim, shardCount, 0));
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
dropMembrane(name) {
|
|
360
|
+
checkStatus(pomai_drop_membrane(this._handle, name));
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
openMembrane(name) {
|
|
364
|
+
checkStatus(pomai_open_membrane(this._handle, name));
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
closeMembrane(name) {
|
|
368
|
+
checkStatus(pomai_close_membrane(this._handle, name));
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
listMembranes() {
|
|
372
|
+
const outJson = [null];
|
|
373
|
+
const outLen = [0];
|
|
374
|
+
checkStatus(pomai_list_membranes_json(this._handle, outJson, outLen));
|
|
375
|
+
if (!outJson[0]) return [];
|
|
376
|
+
try {
|
|
377
|
+
const len = Number(outLen[0]);
|
|
378
|
+
const jsonStr = koffi.decode(outJson[0], "char", len);
|
|
379
|
+
return JSON.parse(jsonStr);
|
|
380
|
+
} finally {
|
|
381
|
+
pomai_free(outJson[0]);
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
getStats() {
|
|
386
|
+
const outJson = [null];
|
|
387
|
+
const outLen = [0];
|
|
388
|
+
checkStatus(pomai_get_stats_json(this._handle, outJson, outLen));
|
|
389
|
+
if (!outJson[0]) return {};
|
|
390
|
+
try {
|
|
391
|
+
const len = Number(outLen[0]);
|
|
392
|
+
const jsonStr = koffi.decode(outJson[0], "char", len);
|
|
393
|
+
return JSON.parse(jsonStr);
|
|
394
|
+
} finally {
|
|
395
|
+
pomai_free(outJson[0]);
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
export default Database;
|
|
Binary file
|
package/package.json
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "pomaidb",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Embedded vector database for Edge AI - official Node.js bindings",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"types": "index.d.ts",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"scripts": {
|
|
9
|
+
"test": "node test/test.js"
|
|
10
|
+
},
|
|
11
|
+
"keywords": [
|
|
12
|
+
"vector",
|
|
13
|
+
"embeddings",
|
|
14
|
+
"database",
|
|
15
|
+
"hnsw",
|
|
16
|
+
"embedded",
|
|
17
|
+
"edge-ai"
|
|
18
|
+
],
|
|
19
|
+
"author": "PomaiDB Team <info@pomaidb.org>",
|
|
20
|
+
"license": "Apache-2.0",
|
|
21
|
+
"repository": {
|
|
22
|
+
"type": "git",
|
|
23
|
+
"url": "git+https://github.com/pomagrenate/pomaidb.git"
|
|
24
|
+
},
|
|
25
|
+
"dependencies": {
|
|
26
|
+
"koffi": "^2.9.0"
|
|
27
|
+
},
|
|
28
|
+
"files": [
|
|
29
|
+
"index.js",
|
|
30
|
+
"index.d.ts",
|
|
31
|
+
"README.md",
|
|
32
|
+
"lib/"
|
|
33
|
+
]
|
|
34
|
+
}
|