n8n-nodes-minimemory 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 +204 -0
- package/dist/credentials/MinimemoryConfig.credentials.d.ts +8 -0
- package/dist/credentials/MinimemoryConfig.credentials.d.ts.map +1 -0
- package/dist/credentials/MinimemoryConfig.credentials.js +40 -0
- package/dist/credentials/MinimemoryConfig.credentials.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -0
- package/dist/nodes/Minimemory/Minimemory.node.d.ts +6 -0
- package/dist/nodes/Minimemory/Minimemory.node.d.ts.map +1 -0
- package/dist/nodes/Minimemory/Minimemory.node.js +672 -0
- package/dist/nodes/Minimemory/Minimemory.node.js.map +1 -0
- package/dist/nodes/Minimemory/VectorDB.d.ts +129 -0
- package/dist/nodes/Minimemory/VectorDB.d.ts.map +1 -0
- package/dist/nodes/Minimemory/VectorDB.js +386 -0
- package/dist/nodes/Minimemory/VectorDB.js.map +1 -0
- package/dist/nodes/Minimemory/minimemory.svg +23 -0
- package/package.json +61 -0
|
@@ -0,0 +1,672 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Minimemory = void 0;
|
|
4
|
+
const n8n_workflow_1 = require("n8n-workflow");
|
|
5
|
+
const VectorDB_1 = require("./VectorDB");
|
|
6
|
+
class Minimemory {
|
|
7
|
+
constructor() {
|
|
8
|
+
this.description = {
|
|
9
|
+
displayName: 'Minimemory',
|
|
10
|
+
name: 'minimemory',
|
|
11
|
+
icon: 'file:minimemory.svg',
|
|
12
|
+
group: ['transform'],
|
|
13
|
+
version: 1,
|
|
14
|
+
subtitle: '={{$parameter["operation"]}}',
|
|
15
|
+
description: 'Embedded vector database for similarity search - no server required',
|
|
16
|
+
defaults: {
|
|
17
|
+
name: 'Minimemory',
|
|
18
|
+
},
|
|
19
|
+
inputs: ['main'],
|
|
20
|
+
outputs: ['main'],
|
|
21
|
+
properties: [
|
|
22
|
+
// Operation selector
|
|
23
|
+
{
|
|
24
|
+
displayName: 'Operation',
|
|
25
|
+
name: 'operation',
|
|
26
|
+
type: 'options',
|
|
27
|
+
noDataExpression: true,
|
|
28
|
+
options: [
|
|
29
|
+
{
|
|
30
|
+
name: 'Clear Database',
|
|
31
|
+
value: 'clear',
|
|
32
|
+
description: 'Remove all vectors from the database',
|
|
33
|
+
action: 'Clear database',
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
name: 'Create Database',
|
|
37
|
+
value: 'create',
|
|
38
|
+
description: 'Create a new vector database in memory',
|
|
39
|
+
action: 'Create a new vector database',
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
name: 'Create or Update',
|
|
43
|
+
value: 'upsert',
|
|
44
|
+
description: 'Create a new record, or update the current one if it already exists (upsert)',
|
|
45
|
+
action: 'Upsert a vector',
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
name: 'Delete Database',
|
|
49
|
+
value: 'deleteDb',
|
|
50
|
+
description: 'Remove database from memory',
|
|
51
|
+
action: 'Delete database',
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
name: 'Delete Vector',
|
|
55
|
+
value: 'delete',
|
|
56
|
+
description: 'Delete a vector by its ID',
|
|
57
|
+
action: 'Delete a vector',
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
name: 'Get',
|
|
61
|
+
value: 'get',
|
|
62
|
+
description: 'Get a vector by its ID',
|
|
63
|
+
action: 'Get a vector by ID',
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
name: 'Get Info',
|
|
67
|
+
value: 'info',
|
|
68
|
+
description: 'Get database information and statistics',
|
|
69
|
+
action: 'Get database info',
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
name: 'Insert Many',
|
|
73
|
+
value: 'insertMany',
|
|
74
|
+
description: 'Insert multiple vectors from input data',
|
|
75
|
+
action: 'Insert multiple vectors',
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
name: 'Insert Vector',
|
|
79
|
+
value: 'insert',
|
|
80
|
+
description: 'Insert a vector with ID and optional metadata',
|
|
81
|
+
action: 'Insert a vector',
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
name: 'List Databases',
|
|
85
|
+
value: 'list',
|
|
86
|
+
description: 'List all databases in memory',
|
|
87
|
+
action: 'List all databases',
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
name: 'Load From File',
|
|
91
|
+
value: 'load',
|
|
92
|
+
description: 'Load database from a JSON file',
|
|
93
|
+
action: 'Load database from file',
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
name: 'Save to File',
|
|
97
|
+
value: 'save',
|
|
98
|
+
description: 'Save database to a JSON file',
|
|
99
|
+
action: 'Save database to file',
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
name: 'Search',
|
|
103
|
+
value: 'search',
|
|
104
|
+
description: 'Search for k nearest neighbors',
|
|
105
|
+
action: 'Search for similar vectors',
|
|
106
|
+
},
|
|
107
|
+
],
|
|
108
|
+
default: 'search',
|
|
109
|
+
},
|
|
110
|
+
// Database Name (used by most operations)
|
|
111
|
+
{
|
|
112
|
+
displayName: 'Database Name',
|
|
113
|
+
name: 'databaseName',
|
|
114
|
+
type: 'string',
|
|
115
|
+
default: 'default',
|
|
116
|
+
required: true,
|
|
117
|
+
description: 'Name to identify this database instance in memory',
|
|
118
|
+
displayOptions: {
|
|
119
|
+
hide: {
|
|
120
|
+
operation: ['list'],
|
|
121
|
+
},
|
|
122
|
+
},
|
|
123
|
+
},
|
|
124
|
+
// === CREATE operation fields ===
|
|
125
|
+
{
|
|
126
|
+
displayName: 'Dimensions',
|
|
127
|
+
name: 'dimensions',
|
|
128
|
+
type: 'number',
|
|
129
|
+
default: 384,
|
|
130
|
+
required: true,
|
|
131
|
+
description: 'Number of dimensions for vectors. Common: 384 (MiniLM), 768 (MPNet), 1536 (OpenAI).',
|
|
132
|
+
displayOptions: {
|
|
133
|
+
show: {
|
|
134
|
+
operation: ['create'],
|
|
135
|
+
},
|
|
136
|
+
},
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
displayName: 'Distance Metric',
|
|
140
|
+
name: 'distance',
|
|
141
|
+
type: 'options',
|
|
142
|
+
options: [
|
|
143
|
+
{
|
|
144
|
+
name: 'Cosine (Best for Text)',
|
|
145
|
+
value: 'cosine',
|
|
146
|
+
description: 'Cosine similarity - ideal for text embeddings',
|
|
147
|
+
},
|
|
148
|
+
{
|
|
149
|
+
name: 'Euclidean (L2)',
|
|
150
|
+
value: 'euclidean',
|
|
151
|
+
description: 'Euclidean distance - good for normalized vectors',
|
|
152
|
+
},
|
|
153
|
+
{
|
|
154
|
+
name: 'Dot Product',
|
|
155
|
+
value: 'dot',
|
|
156
|
+
description: 'Dot product - when magnitude matters',
|
|
157
|
+
},
|
|
158
|
+
],
|
|
159
|
+
default: 'cosine',
|
|
160
|
+
description: 'Distance metric for similarity calculation',
|
|
161
|
+
displayOptions: {
|
|
162
|
+
show: {
|
|
163
|
+
operation: ['create'],
|
|
164
|
+
},
|
|
165
|
+
},
|
|
166
|
+
},
|
|
167
|
+
{
|
|
168
|
+
displayName: 'Index Type',
|
|
169
|
+
name: 'indexType',
|
|
170
|
+
type: 'options',
|
|
171
|
+
options: [
|
|
172
|
+
{
|
|
173
|
+
name: 'Flat (Exact Search)',
|
|
174
|
+
value: 'flat',
|
|
175
|
+
description: '100% accurate, best for < 10,000 vectors',
|
|
176
|
+
},
|
|
177
|
+
{
|
|
178
|
+
name: 'HNSW (Fast Approximate)',
|
|
179
|
+
value: 'hnsw',
|
|
180
|
+
description: 'Very fast, slight accuracy trade-off for large datasets',
|
|
181
|
+
},
|
|
182
|
+
],
|
|
183
|
+
default: 'flat',
|
|
184
|
+
description: 'Index type - affects speed vs accuracy',
|
|
185
|
+
displayOptions: {
|
|
186
|
+
show: {
|
|
187
|
+
operation: ['create'],
|
|
188
|
+
},
|
|
189
|
+
},
|
|
190
|
+
},
|
|
191
|
+
// === INSERT/GET/DELETE operation fields ===
|
|
192
|
+
{
|
|
193
|
+
displayName: 'Vector ID',
|
|
194
|
+
name: 'vectorId',
|
|
195
|
+
type: 'string',
|
|
196
|
+
default: '',
|
|
197
|
+
required: true,
|
|
198
|
+
description: 'Unique identifier for the vector',
|
|
199
|
+
displayOptions: {
|
|
200
|
+
show: {
|
|
201
|
+
operation: ['insert', 'upsert', 'get', 'delete'],
|
|
202
|
+
},
|
|
203
|
+
},
|
|
204
|
+
},
|
|
205
|
+
{
|
|
206
|
+
displayName: 'Vector',
|
|
207
|
+
name: 'vector',
|
|
208
|
+
type: 'json',
|
|
209
|
+
default: '[]',
|
|
210
|
+
required: true,
|
|
211
|
+
description: 'Vector as JSON array of numbers, e.g., [0.1, 0.2, 0.3, ...]. Can also use expression to get from previous node.',
|
|
212
|
+
displayOptions: {
|
|
213
|
+
show: {
|
|
214
|
+
operation: ['insert', 'upsert'],
|
|
215
|
+
},
|
|
216
|
+
},
|
|
217
|
+
},
|
|
218
|
+
{
|
|
219
|
+
displayName: 'Metadata',
|
|
220
|
+
name: 'metadata',
|
|
221
|
+
type: 'json',
|
|
222
|
+
default: '{}',
|
|
223
|
+
description: 'Optional metadata as JSON object, e.g., {"title": "Document 1", "category": "tech"}',
|
|
224
|
+
displayOptions: {
|
|
225
|
+
show: {
|
|
226
|
+
operation: ['insert', 'upsert'],
|
|
227
|
+
},
|
|
228
|
+
},
|
|
229
|
+
},
|
|
230
|
+
// === INSERT MANY operation fields ===
|
|
231
|
+
{
|
|
232
|
+
displayName: 'ID Field',
|
|
233
|
+
name: 'idField',
|
|
234
|
+
type: 'string',
|
|
235
|
+
default: 'id',
|
|
236
|
+
required: true,
|
|
237
|
+
description: 'Field name containing the vector ID in input items',
|
|
238
|
+
displayOptions: {
|
|
239
|
+
show: {
|
|
240
|
+
operation: ['insertMany'],
|
|
241
|
+
},
|
|
242
|
+
},
|
|
243
|
+
},
|
|
244
|
+
{
|
|
245
|
+
displayName: 'Vector Field',
|
|
246
|
+
name: 'vectorField',
|
|
247
|
+
type: 'string',
|
|
248
|
+
default: 'embedding',
|
|
249
|
+
required: true,
|
|
250
|
+
description: 'Field name containing the vector array in input items',
|
|
251
|
+
displayOptions: {
|
|
252
|
+
show: {
|
|
253
|
+
operation: ['insertMany'],
|
|
254
|
+
},
|
|
255
|
+
},
|
|
256
|
+
},
|
|
257
|
+
{
|
|
258
|
+
displayName: 'Metadata Fields',
|
|
259
|
+
name: 'metadataFields',
|
|
260
|
+
type: 'string',
|
|
261
|
+
default: '',
|
|
262
|
+
description: 'Comma-separated field names to include as metadata (leave empty for all other fields)',
|
|
263
|
+
displayOptions: {
|
|
264
|
+
show: {
|
|
265
|
+
operation: ['insertMany'],
|
|
266
|
+
},
|
|
267
|
+
},
|
|
268
|
+
},
|
|
269
|
+
// === SEARCH operation fields ===
|
|
270
|
+
{
|
|
271
|
+
displayName: 'Query Vector',
|
|
272
|
+
name: 'queryVector',
|
|
273
|
+
type: 'json',
|
|
274
|
+
default: '[]',
|
|
275
|
+
required: true,
|
|
276
|
+
description: 'Query vector as JSON array. Use expression like {{ $JSON.embedding }} to get from previous node.',
|
|
277
|
+
displayOptions: {
|
|
278
|
+
show: {
|
|
279
|
+
operation: ['search'],
|
|
280
|
+
},
|
|
281
|
+
},
|
|
282
|
+
},
|
|
283
|
+
{
|
|
284
|
+
displayName: 'Number of Results (K)',
|
|
285
|
+
name: 'topK',
|
|
286
|
+
type: 'number',
|
|
287
|
+
default: 10,
|
|
288
|
+
description: 'Number of nearest neighbors to return',
|
|
289
|
+
displayOptions: {
|
|
290
|
+
show: {
|
|
291
|
+
operation: ['search'],
|
|
292
|
+
},
|
|
293
|
+
},
|
|
294
|
+
},
|
|
295
|
+
{
|
|
296
|
+
displayName: 'Include Vectors',
|
|
297
|
+
name: 'includeVectors',
|
|
298
|
+
type: 'boolean',
|
|
299
|
+
default: false,
|
|
300
|
+
description: 'Whether to include the actual vectors in the results (increases output size)',
|
|
301
|
+
displayOptions: {
|
|
302
|
+
show: {
|
|
303
|
+
operation: ['search'],
|
|
304
|
+
},
|
|
305
|
+
},
|
|
306
|
+
},
|
|
307
|
+
{
|
|
308
|
+
displayName: 'Minimum Similarity',
|
|
309
|
+
name: 'minSimilarity',
|
|
310
|
+
type: 'number',
|
|
311
|
+
default: 0,
|
|
312
|
+
description: 'Filter results below this similarity threshold (0-1 for cosine)',
|
|
313
|
+
displayOptions: {
|
|
314
|
+
show: {
|
|
315
|
+
operation: ['search'],
|
|
316
|
+
},
|
|
317
|
+
},
|
|
318
|
+
},
|
|
319
|
+
// === SAVE/LOAD operation fields ===
|
|
320
|
+
{
|
|
321
|
+
displayName: 'File Path',
|
|
322
|
+
name: 'filePath',
|
|
323
|
+
type: 'string',
|
|
324
|
+
default: '',
|
|
325
|
+
required: true,
|
|
326
|
+
description: 'Full path to the database file (JSON format)',
|
|
327
|
+
placeholder: '/data/vectors/my_database.json',
|
|
328
|
+
displayOptions: {
|
|
329
|
+
show: {
|
|
330
|
+
operation: ['save', 'load'],
|
|
331
|
+
},
|
|
332
|
+
},
|
|
333
|
+
},
|
|
334
|
+
],
|
|
335
|
+
};
|
|
336
|
+
}
|
|
337
|
+
async execute() {
|
|
338
|
+
const items = this.getInputData();
|
|
339
|
+
const returnData = [];
|
|
340
|
+
// Handle insertMany specially - it processes all items at once
|
|
341
|
+
const operation = this.getNodeParameter('operation', 0);
|
|
342
|
+
if (operation === 'insertMany') {
|
|
343
|
+
return executeInsertMany(this, items);
|
|
344
|
+
}
|
|
345
|
+
if (operation === 'list') {
|
|
346
|
+
const databases = (0, VectorDB_1.listDBs)();
|
|
347
|
+
returnData.push({
|
|
348
|
+
json: {
|
|
349
|
+
success: true,
|
|
350
|
+
databases,
|
|
351
|
+
count: databases.length,
|
|
352
|
+
},
|
|
353
|
+
});
|
|
354
|
+
return [returnData];
|
|
355
|
+
}
|
|
356
|
+
// Process each item for other operations
|
|
357
|
+
for (let i = 0; i < items.length; i++) {
|
|
358
|
+
try {
|
|
359
|
+
const databaseName = this.getNodeParameter('databaseName', i);
|
|
360
|
+
let result = {};
|
|
361
|
+
switch (operation) {
|
|
362
|
+
case 'create': {
|
|
363
|
+
const dimensions = this.getNodeParameter('dimensions', i);
|
|
364
|
+
const distance = this.getNodeParameter('distance', i);
|
|
365
|
+
const indexType = this.getNodeParameter('indexType', i);
|
|
366
|
+
try {
|
|
367
|
+
const db = (0, VectorDB_1.createDB)(databaseName, { dimensions, distance, indexType });
|
|
368
|
+
result = {
|
|
369
|
+
success: true,
|
|
370
|
+
message: `Database "${databaseName}" created successfully`,
|
|
371
|
+
name: databaseName,
|
|
372
|
+
dimensions,
|
|
373
|
+
distance,
|
|
374
|
+
indexType,
|
|
375
|
+
vectorCount: 0,
|
|
376
|
+
};
|
|
377
|
+
}
|
|
378
|
+
catch (error) {
|
|
379
|
+
result = {
|
|
380
|
+
success: false,
|
|
381
|
+
message: error instanceof Error ? error.message : String(error),
|
|
382
|
+
name: databaseName,
|
|
383
|
+
};
|
|
384
|
+
}
|
|
385
|
+
break;
|
|
386
|
+
}
|
|
387
|
+
case 'insert':
|
|
388
|
+
case 'upsert': {
|
|
389
|
+
const db = (0, VectorDB_1.getDB)(databaseName);
|
|
390
|
+
const vectorId = this.getNodeParameter('vectorId', i);
|
|
391
|
+
const vectorJson = this.getNodeParameter('vector', i);
|
|
392
|
+
const metadataJson = this.getNodeParameter('metadata', i);
|
|
393
|
+
const vector = typeof vectorJson === 'string' ? JSON.parse(vectorJson) : vectorJson;
|
|
394
|
+
const metadata = typeof metadataJson === 'string'
|
|
395
|
+
? JSON.parse(metadataJson)
|
|
396
|
+
: metadataJson;
|
|
397
|
+
const hasMetadata = metadata && Object.keys(metadata).length > 0;
|
|
398
|
+
if (operation === 'upsert') {
|
|
399
|
+
db.upsert(vectorId, vector, hasMetadata ? metadata : undefined);
|
|
400
|
+
}
|
|
401
|
+
else {
|
|
402
|
+
db.insert(vectorId, vector, hasMetadata ? metadata : undefined);
|
|
403
|
+
}
|
|
404
|
+
result = {
|
|
405
|
+
success: true,
|
|
406
|
+
operation,
|
|
407
|
+
id: vectorId,
|
|
408
|
+
dimensions: vector.length,
|
|
409
|
+
hasMetadata,
|
|
410
|
+
totalVectors: db.length,
|
|
411
|
+
};
|
|
412
|
+
break;
|
|
413
|
+
}
|
|
414
|
+
case 'search': {
|
|
415
|
+
const db = (0, VectorDB_1.getDB)(databaseName);
|
|
416
|
+
const queryJson = this.getNodeParameter('queryVector', i);
|
|
417
|
+
const topK = this.getNodeParameter('topK', i);
|
|
418
|
+
const includeVectors = this.getNodeParameter('includeVectors', i);
|
|
419
|
+
const minSimilarity = this.getNodeParameter('minSimilarity', i);
|
|
420
|
+
const queryVector = typeof queryJson === 'string'
|
|
421
|
+
? JSON.parse(queryJson)
|
|
422
|
+
: queryJson;
|
|
423
|
+
let results = db.search(queryVector, topK);
|
|
424
|
+
// Filter by minimum similarity if specified
|
|
425
|
+
if (minSimilarity > 0) {
|
|
426
|
+
results = results.filter(r => r.similarity >= minSimilarity);
|
|
427
|
+
}
|
|
428
|
+
// Optionally include vectors
|
|
429
|
+
const formattedResults = results.map(r => {
|
|
430
|
+
const item = {
|
|
431
|
+
id: r.id,
|
|
432
|
+
distance: r.distance,
|
|
433
|
+
similarity: r.similarity,
|
|
434
|
+
};
|
|
435
|
+
if (r.metadata) {
|
|
436
|
+
item.metadata = r.metadata;
|
|
437
|
+
}
|
|
438
|
+
if (includeVectors) {
|
|
439
|
+
const stored = db.get(r.id);
|
|
440
|
+
if (stored) {
|
|
441
|
+
item.vector = stored.vector;
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
return item;
|
|
445
|
+
});
|
|
446
|
+
result = {
|
|
447
|
+
success: true,
|
|
448
|
+
query: 'vector',
|
|
449
|
+
k: topK,
|
|
450
|
+
resultsCount: formattedResults.length,
|
|
451
|
+
results: formattedResults,
|
|
452
|
+
};
|
|
453
|
+
break;
|
|
454
|
+
}
|
|
455
|
+
case 'get': {
|
|
456
|
+
const db = (0, VectorDB_1.getDB)(databaseName);
|
|
457
|
+
const vectorId = this.getNodeParameter('vectorId', i);
|
|
458
|
+
const data = db.get(vectorId);
|
|
459
|
+
if (data) {
|
|
460
|
+
result = {
|
|
461
|
+
success: true,
|
|
462
|
+
found: true,
|
|
463
|
+
id: vectorId,
|
|
464
|
+
vector: data.vector,
|
|
465
|
+
metadata: data.metadata,
|
|
466
|
+
dimensions: data.vector.length,
|
|
467
|
+
};
|
|
468
|
+
}
|
|
469
|
+
else {
|
|
470
|
+
result = {
|
|
471
|
+
success: true,
|
|
472
|
+
found: false,
|
|
473
|
+
id: vectorId,
|
|
474
|
+
message: 'Vector not found',
|
|
475
|
+
};
|
|
476
|
+
}
|
|
477
|
+
break;
|
|
478
|
+
}
|
|
479
|
+
case 'delete': {
|
|
480
|
+
const db = (0, VectorDB_1.getDB)(databaseName);
|
|
481
|
+
const vectorId = this.getNodeParameter('vectorId', i);
|
|
482
|
+
const deleted = db.delete(vectorId);
|
|
483
|
+
result = {
|
|
484
|
+
success: true,
|
|
485
|
+
deleted,
|
|
486
|
+
id: vectorId,
|
|
487
|
+
message: deleted ? 'Vector deleted' : 'Vector not found',
|
|
488
|
+
totalVectors: db.length,
|
|
489
|
+
};
|
|
490
|
+
break;
|
|
491
|
+
}
|
|
492
|
+
case 'save': {
|
|
493
|
+
const db = (0, VectorDB_1.getDB)(databaseName);
|
|
494
|
+
const filePath = this.getNodeParameter('filePath', i);
|
|
495
|
+
db.save(filePath);
|
|
496
|
+
result = {
|
|
497
|
+
success: true,
|
|
498
|
+
message: `Database saved to ${filePath}`,
|
|
499
|
+
path: filePath,
|
|
500
|
+
totalVectors: db.length,
|
|
501
|
+
dimensions: db.dimensions,
|
|
502
|
+
};
|
|
503
|
+
break;
|
|
504
|
+
}
|
|
505
|
+
case 'load': {
|
|
506
|
+
const filePath = this.getNodeParameter('filePath', i);
|
|
507
|
+
const db = (0, VectorDB_1.loadDB)(databaseName, filePath);
|
|
508
|
+
result = {
|
|
509
|
+
success: true,
|
|
510
|
+
message: `Database loaded from ${filePath}`,
|
|
511
|
+
name: databaseName,
|
|
512
|
+
path: filePath,
|
|
513
|
+
totalVectors: db.length,
|
|
514
|
+
dimensions: db.dimensions,
|
|
515
|
+
distance: db.distance,
|
|
516
|
+
};
|
|
517
|
+
break;
|
|
518
|
+
}
|
|
519
|
+
case 'info': {
|
|
520
|
+
try {
|
|
521
|
+
const db = (0, VectorDB_1.getDB)(databaseName);
|
|
522
|
+
const stats = db.stats();
|
|
523
|
+
result = {
|
|
524
|
+
success: true,
|
|
525
|
+
name: databaseName,
|
|
526
|
+
...stats,
|
|
527
|
+
allDatabases: (0, VectorDB_1.listDBs)(),
|
|
528
|
+
};
|
|
529
|
+
}
|
|
530
|
+
catch {
|
|
531
|
+
result = {
|
|
532
|
+
success: false,
|
|
533
|
+
name: databaseName,
|
|
534
|
+
message: `Database "${databaseName}" not found`,
|
|
535
|
+
allDatabases: (0, VectorDB_1.listDBs)(),
|
|
536
|
+
};
|
|
537
|
+
}
|
|
538
|
+
break;
|
|
539
|
+
}
|
|
540
|
+
case 'clear': {
|
|
541
|
+
const db = (0, VectorDB_1.getDB)(databaseName);
|
|
542
|
+
const previousCount = db.length;
|
|
543
|
+
db.clear();
|
|
544
|
+
result = {
|
|
545
|
+
success: true,
|
|
546
|
+
message: `Cleared ${previousCount} vectors`,
|
|
547
|
+
previousCount,
|
|
548
|
+
totalVectors: 0,
|
|
549
|
+
};
|
|
550
|
+
break;
|
|
551
|
+
}
|
|
552
|
+
case 'deleteDb': {
|
|
553
|
+
const deleted = (0, VectorDB_1.deleteDB)(databaseName);
|
|
554
|
+
result = {
|
|
555
|
+
success: deleted,
|
|
556
|
+
name: databaseName,
|
|
557
|
+
message: deleted
|
|
558
|
+
? `Database "${databaseName}" deleted from memory`
|
|
559
|
+
: `Database "${databaseName}" not found`,
|
|
560
|
+
remainingDatabases: (0, VectorDB_1.listDBs)(),
|
|
561
|
+
};
|
|
562
|
+
break;
|
|
563
|
+
}
|
|
564
|
+
default:
|
|
565
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Unknown operation: ${operation}`);
|
|
566
|
+
}
|
|
567
|
+
returnData.push({
|
|
568
|
+
json: result,
|
|
569
|
+
pairedItem: { item: i },
|
|
570
|
+
});
|
|
571
|
+
}
|
|
572
|
+
catch (error) {
|
|
573
|
+
if (this.continueOnFail()) {
|
|
574
|
+
returnData.push({
|
|
575
|
+
json: {
|
|
576
|
+
success: false,
|
|
577
|
+
error: error instanceof Error ? error.message : String(error),
|
|
578
|
+
},
|
|
579
|
+
pairedItem: { item: i },
|
|
580
|
+
});
|
|
581
|
+
}
|
|
582
|
+
else {
|
|
583
|
+
throw error;
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
return [returnData];
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
exports.Minimemory = Minimemory;
|
|
591
|
+
/**
|
|
592
|
+
* Handles insertMany operation - processes all input items at once
|
|
593
|
+
*/
|
|
594
|
+
async function executeInsertMany(context, items) {
|
|
595
|
+
const databaseName = context.getNodeParameter('databaseName', 0);
|
|
596
|
+
const idField = context.getNodeParameter('idField', 0);
|
|
597
|
+
const vectorField = context.getNodeParameter('vectorField', 0);
|
|
598
|
+
const metadataFieldsStr = context.getNodeParameter('metadataFields', 0);
|
|
599
|
+
const metadataFields = metadataFieldsStr
|
|
600
|
+
? metadataFieldsStr.split(',').map(f => f.trim()).filter(f => f)
|
|
601
|
+
: null;
|
|
602
|
+
try {
|
|
603
|
+
const db = (0, VectorDB_1.getDB)(databaseName);
|
|
604
|
+
let insertedCount = 0;
|
|
605
|
+
const errors = [];
|
|
606
|
+
for (let i = 0; i < items.length; i++) {
|
|
607
|
+
const item = items[i].json;
|
|
608
|
+
try {
|
|
609
|
+
const id = item[idField];
|
|
610
|
+
const vector = item[vectorField];
|
|
611
|
+
if (!id) {
|
|
612
|
+
errors.push(`Item ${i}: Missing ID field "${idField}"`);
|
|
613
|
+
continue;
|
|
614
|
+
}
|
|
615
|
+
if (!vector || !Array.isArray(vector)) {
|
|
616
|
+
errors.push(`Item ${i}: Missing or invalid vector field "${vectorField}"`);
|
|
617
|
+
continue;
|
|
618
|
+
}
|
|
619
|
+
// Extract metadata
|
|
620
|
+
let metadata;
|
|
621
|
+
if (metadataFields) {
|
|
622
|
+
// Use specified fields
|
|
623
|
+
metadata = {};
|
|
624
|
+
for (const field of metadataFields) {
|
|
625
|
+
if (field in item) {
|
|
626
|
+
metadata[field] = item[field];
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
else {
|
|
631
|
+
// Use all fields except id and vector
|
|
632
|
+
metadata = {};
|
|
633
|
+
for (const [key, value] of Object.entries(item)) {
|
|
634
|
+
if (key !== idField && key !== vectorField) {
|
|
635
|
+
metadata[key] = value;
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
const hasMetadata = metadata && Object.keys(metadata).length > 0;
|
|
640
|
+
db.upsert(id, vector, hasMetadata ? metadata : undefined);
|
|
641
|
+
insertedCount++;
|
|
642
|
+
}
|
|
643
|
+
catch (error) {
|
|
644
|
+
errors.push(`Item ${i}: ${error instanceof Error ? error.message : String(error)}`);
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
return [[{
|
|
648
|
+
json: {
|
|
649
|
+
success: true,
|
|
650
|
+
operation: 'insertMany',
|
|
651
|
+
database: databaseName,
|
|
652
|
+
processed: items.length,
|
|
653
|
+
inserted: insertedCount,
|
|
654
|
+
errors: errors.length,
|
|
655
|
+
errorDetails: errors.length > 0 ? errors : undefined,
|
|
656
|
+
totalVectors: db.length,
|
|
657
|
+
},
|
|
658
|
+
}]];
|
|
659
|
+
}
|
|
660
|
+
catch (error) {
|
|
661
|
+
if (context.continueOnFail()) {
|
|
662
|
+
return [[{
|
|
663
|
+
json: {
|
|
664
|
+
success: false,
|
|
665
|
+
error: error instanceof Error ? error.message : String(error),
|
|
666
|
+
},
|
|
667
|
+
}]];
|
|
668
|
+
}
|
|
669
|
+
throw error;
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
//# sourceMappingURL=Minimemory.node.js.map
|