@mastra/pg 0.3.4 → 0.3.5-alpha.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/.turbo/turbo-build.log +7 -7
- package/CHANGELOG.md +15 -0
- package/dist/_tsup-dts-rollup.d.cts +19 -31
- package/dist/_tsup-dts-rollup.d.ts +19 -31
- package/dist/index.cjs +151 -90
- package/dist/index.js +151 -90
- package/docker-compose.perf.yaml +9 -9
- package/package.json +2 -2
- package/src/storage/index.ts +12 -6
- package/src/vector/index.test.ts +53 -51
- package/src/vector/index.ts +47 -21
- package/src/vector/sql-builder.ts +110 -77
- package/src/vector/vector.performance.test.ts +2 -2
package/src/vector/index.test.ts
CHANGED
|
@@ -12,12 +12,12 @@ describe('PgVector', () => {
|
|
|
12
12
|
|
|
13
13
|
beforeAll(async () => {
|
|
14
14
|
// Initialize PgVector
|
|
15
|
-
vectorDB = new PgVector(connectionString);
|
|
15
|
+
vectorDB = new PgVector({ connectionString });
|
|
16
16
|
});
|
|
17
17
|
|
|
18
18
|
afterAll(async () => {
|
|
19
19
|
// Clean up test tables
|
|
20
|
-
await vectorDB.deleteIndex(testIndexName);
|
|
20
|
+
await vectorDB.deleteIndex({ indexName: testIndexName });
|
|
21
21
|
await vectorDB.disconnect();
|
|
22
22
|
});
|
|
23
23
|
|
|
@@ -43,19 +43,19 @@ describe('PgVector', () => {
|
|
|
43
43
|
describe('Index Management', () => {
|
|
44
44
|
describe('createIndex', () => {
|
|
45
45
|
afterAll(async () => {
|
|
46
|
-
await vectorDB.deleteIndex(testIndexName2);
|
|
46
|
+
await vectorDB.deleteIndex({ indexName: testIndexName2 });
|
|
47
47
|
});
|
|
48
48
|
|
|
49
49
|
it('should create a new vector table with specified dimensions', async () => {
|
|
50
50
|
await vectorDB.createIndex({ indexName: testIndexName, dimension: 3 });
|
|
51
|
-
const stats = await vectorDB.describeIndex(testIndexName);
|
|
51
|
+
const stats = await vectorDB.describeIndex({ indexName: testIndexName });
|
|
52
52
|
expect(stats?.dimension).toBe(3);
|
|
53
53
|
expect(stats?.count).toBe(0);
|
|
54
54
|
});
|
|
55
55
|
|
|
56
56
|
it('should create index with specified metric', async () => {
|
|
57
57
|
await vectorDB.createIndex({ indexName: testIndexName2, dimension: 3, metric: 'euclidean' });
|
|
58
|
-
const stats = await vectorDB.describeIndex(testIndexName2);
|
|
58
|
+
const stats = await vectorDB.describeIndex({ indexName: testIndexName2 });
|
|
59
59
|
expect(stats.metric).toBe('euclidean');
|
|
60
60
|
});
|
|
61
61
|
|
|
@@ -70,7 +70,7 @@ describe('PgVector', () => {
|
|
|
70
70
|
metric: 'cosine',
|
|
71
71
|
indexConfig: { type: 'flat' },
|
|
72
72
|
});
|
|
73
|
-
const stats = await vectorDB.describeIndex(testIndexName2);
|
|
73
|
+
const stats = await vectorDB.describeIndex({ indexName: testIndexName2 });
|
|
74
74
|
expect(stats.type).toBe('flat');
|
|
75
75
|
});
|
|
76
76
|
|
|
@@ -81,7 +81,7 @@ describe('PgVector', () => {
|
|
|
81
81
|
metric: 'cosine',
|
|
82
82
|
indexConfig: { type: 'hnsw', hnsw: { m: 16, efConstruction: 64 } }, // Any reasonable values work
|
|
83
83
|
});
|
|
84
|
-
const stats = await vectorDB.describeIndex(testIndexName2);
|
|
84
|
+
const stats = await vectorDB.describeIndex({ indexName: testIndexName2 });
|
|
85
85
|
expect(stats.type).toBe('hnsw');
|
|
86
86
|
expect(stats.config.m).toBe(16);
|
|
87
87
|
});
|
|
@@ -93,7 +93,7 @@ describe('PgVector', () => {
|
|
|
93
93
|
metric: 'cosine',
|
|
94
94
|
indexConfig: { type: 'ivfflat', ivf: { lists: 100 } },
|
|
95
95
|
});
|
|
96
|
-
const stats = await vectorDB.describeIndex(testIndexName2);
|
|
96
|
+
const stats = await vectorDB.describeIndex({ indexName: testIndexName2 });
|
|
97
97
|
expect(stats.type).toBe('ivfflat');
|
|
98
98
|
expect(stats.config.lists).toBe(100);
|
|
99
99
|
});
|
|
@@ -106,7 +106,7 @@ describe('PgVector', () => {
|
|
|
106
106
|
});
|
|
107
107
|
|
|
108
108
|
afterAll(async () => {
|
|
109
|
-
await vectorDB.deleteIndex(indexName);
|
|
109
|
+
await vectorDB.deleteIndex({ indexName });
|
|
110
110
|
});
|
|
111
111
|
|
|
112
112
|
it('should list all vector tables', async () => {
|
|
@@ -115,7 +115,7 @@ describe('PgVector', () => {
|
|
|
115
115
|
});
|
|
116
116
|
|
|
117
117
|
it('should not return created index in list if it is deleted', async () => {
|
|
118
|
-
await vectorDB.deleteIndex(indexName);
|
|
118
|
+
await vectorDB.deleteIndex({ indexName });
|
|
119
119
|
const indexes = await vectorDB.listIndexes();
|
|
120
120
|
expect(indexes).not.toContain(indexName);
|
|
121
121
|
});
|
|
@@ -128,7 +128,7 @@ describe('PgVector', () => {
|
|
|
128
128
|
});
|
|
129
129
|
|
|
130
130
|
afterAll(async () => {
|
|
131
|
-
await vectorDB.deleteIndex(indexName);
|
|
131
|
+
await vectorDB.deleteIndex({ indexName });
|
|
132
132
|
});
|
|
133
133
|
|
|
134
134
|
it('should return correct index stats', async () => {
|
|
@@ -139,7 +139,7 @@ describe('PgVector', () => {
|
|
|
139
139
|
];
|
|
140
140
|
await vectorDB.upsert({ indexName, vectors });
|
|
141
141
|
|
|
142
|
-
const stats = await vectorDB.describeIndex(indexName);
|
|
142
|
+
const stats = await vectorDB.describeIndex({ indexName });
|
|
143
143
|
expect(stats).toEqual({
|
|
144
144
|
type: 'ivfflat',
|
|
145
145
|
config: {
|
|
@@ -163,7 +163,7 @@ describe('PgVector', () => {
|
|
|
163
163
|
});
|
|
164
164
|
|
|
165
165
|
afterAll(async () => {
|
|
166
|
-
await vectorDB.deleteIndex(indexName);
|
|
166
|
+
await vectorDB.deleteIndex({ indexName });
|
|
167
167
|
});
|
|
168
168
|
|
|
169
169
|
it('should build index with specified metric and config', async () => {
|
|
@@ -173,7 +173,7 @@ describe('PgVector', () => {
|
|
|
173
173
|
indexConfig: { type: 'hnsw', hnsw: { m: 16, efConstruction: 64 } },
|
|
174
174
|
});
|
|
175
175
|
|
|
176
|
-
const stats = await vectorDB.describeIndex(indexName);
|
|
176
|
+
const stats = await vectorDB.describeIndex({ indexName });
|
|
177
177
|
expect(stats.type).toBe('hnsw');
|
|
178
178
|
expect(stats.metric).toBe('cosine');
|
|
179
179
|
expect(stats.config.m).toBe(16);
|
|
@@ -186,7 +186,7 @@ describe('PgVector', () => {
|
|
|
186
186
|
indexConfig: { type: 'ivfflat', ivf: { lists: 100 } },
|
|
187
187
|
});
|
|
188
188
|
|
|
189
|
-
const stats = await vectorDB.describeIndex(indexName);
|
|
189
|
+
const stats = await vectorDB.describeIndex({ indexName });
|
|
190
190
|
expect(stats.type).toBe('ivfflat');
|
|
191
191
|
expect(stats.metric).toBe('euclidean');
|
|
192
192
|
expect(stats.config.lists).toBe(100);
|
|
@@ -202,7 +202,7 @@ describe('PgVector', () => {
|
|
|
202
202
|
});
|
|
203
203
|
|
|
204
204
|
afterEach(async () => {
|
|
205
|
-
await vectorDB.deleteIndex(testIndexName);
|
|
205
|
+
await vectorDB.deleteIndex({ indexName: testIndexName });
|
|
206
206
|
});
|
|
207
207
|
|
|
208
208
|
it('should insert new vectors', async () => {
|
|
@@ -213,7 +213,7 @@ describe('PgVector', () => {
|
|
|
213
213
|
const ids = await vectorDB.upsert({ indexName: testIndexName, vectors });
|
|
214
214
|
|
|
215
215
|
expect(ids).toHaveLength(2);
|
|
216
|
-
const stats = await vectorDB.describeIndex(testIndexName);
|
|
216
|
+
const stats = await vectorDB.describeIndex({ indexName: testIndexName });
|
|
217
217
|
expect(stats.count).toBe(2);
|
|
218
218
|
});
|
|
219
219
|
|
|
@@ -267,7 +267,7 @@ describe('PgVector', () => {
|
|
|
267
267
|
});
|
|
268
268
|
|
|
269
269
|
afterEach(async () => {
|
|
270
|
-
await vectorDB.deleteIndex(testIndexName);
|
|
270
|
+
await vectorDB.deleteIndex({ indexName: testIndexName });
|
|
271
271
|
});
|
|
272
272
|
|
|
273
273
|
it('should update the vector by id', async () => {
|
|
@@ -285,7 +285,7 @@ describe('PgVector', () => {
|
|
|
285
285
|
metadata: newMetaData,
|
|
286
286
|
};
|
|
287
287
|
|
|
288
|
-
await vectorDB.updateVector(testIndexName, idToBeUpdated, update);
|
|
288
|
+
await vectorDB.updateVector({ indexName: testIndexName, id: idToBeUpdated, update });
|
|
289
289
|
|
|
290
290
|
const results: QueryResult[] = await vectorDB.query({
|
|
291
291
|
indexName: testIndexName,
|
|
@@ -311,7 +311,7 @@ describe('PgVector', () => {
|
|
|
311
311
|
metadata: newMetaData,
|
|
312
312
|
};
|
|
313
313
|
|
|
314
|
-
await vectorDB.updateVector(testIndexName, idToBeUpdated, update);
|
|
314
|
+
await vectorDB.updateVector({ indexName: testIndexName, id: idToBeUpdated, update });
|
|
315
315
|
|
|
316
316
|
const results: QueryResult[] = await vectorDB.query({
|
|
317
317
|
indexName: testIndexName,
|
|
@@ -335,7 +335,7 @@ describe('PgVector', () => {
|
|
|
335
335
|
vector: newVector,
|
|
336
336
|
};
|
|
337
337
|
|
|
338
|
-
await vectorDB.updateVector(testIndexName, idToBeUpdated, update);
|
|
338
|
+
await vectorDB.updateVector({ indexName: testIndexName, id: idToBeUpdated, update });
|
|
339
339
|
|
|
340
340
|
const results: QueryResult[] = await vectorDB.query({
|
|
341
341
|
indexName: testIndexName,
|
|
@@ -348,7 +348,9 @@ describe('PgVector', () => {
|
|
|
348
348
|
});
|
|
349
349
|
|
|
350
350
|
it('should throw exception when no updates are given', async () => {
|
|
351
|
-
await expect(vectorDB.updateVector(testIndexName, 'id', {})).rejects.toThrow(
|
|
351
|
+
await expect(vectorDB.updateVector({ indexName: testIndexName, id: 'id', update: {} })).rejects.toThrow(
|
|
352
|
+
'No updates provided',
|
|
353
|
+
);
|
|
352
354
|
});
|
|
353
355
|
});
|
|
354
356
|
|
|
@@ -364,7 +366,7 @@ describe('PgVector', () => {
|
|
|
364
366
|
});
|
|
365
367
|
|
|
366
368
|
afterEach(async () => {
|
|
367
|
-
await vectorDB.deleteIndex(testIndexName);
|
|
369
|
+
await vectorDB.deleteIndex({ indexName: testIndexName });
|
|
368
370
|
});
|
|
369
371
|
|
|
370
372
|
it('should delete the vector by id', async () => {
|
|
@@ -372,7 +374,7 @@ describe('PgVector', () => {
|
|
|
372
374
|
expect(ids).toHaveLength(3);
|
|
373
375
|
const idToBeDeleted = ids[0];
|
|
374
376
|
|
|
375
|
-
await vectorDB.deleteVector(testIndexName, idToBeDeleted);
|
|
377
|
+
await vectorDB.deleteVector({ indexName: testIndexName, id: idToBeDeleted });
|
|
376
378
|
|
|
377
379
|
const results: QueryResult[] = await vectorDB.query({
|
|
378
380
|
indexName: testIndexName,
|
|
@@ -390,7 +392,7 @@ describe('PgVector', () => {
|
|
|
390
392
|
const indexName = `test_query_2_${indexType}`;
|
|
391
393
|
beforeAll(async () => {
|
|
392
394
|
try {
|
|
393
|
-
await vectorDB.deleteIndex(indexName);
|
|
395
|
+
await vectorDB.deleteIndex({ indexName });
|
|
394
396
|
} catch {
|
|
395
397
|
// Ignore if doesn't exist
|
|
396
398
|
}
|
|
@@ -398,7 +400,7 @@ describe('PgVector', () => {
|
|
|
398
400
|
});
|
|
399
401
|
|
|
400
402
|
beforeEach(async () => {
|
|
401
|
-
await vectorDB.truncateIndex(indexName);
|
|
403
|
+
await vectorDB.truncateIndex({ indexName });
|
|
402
404
|
const vectors = [
|
|
403
405
|
[1, 0, 0],
|
|
404
406
|
[0.8, 0.2, 0],
|
|
@@ -413,7 +415,7 @@ describe('PgVector', () => {
|
|
|
413
415
|
});
|
|
414
416
|
|
|
415
417
|
afterAll(async () => {
|
|
416
|
-
await vectorDB.deleteIndex(indexName);
|
|
418
|
+
await vectorDB.deleteIndex({ indexName });
|
|
417
419
|
});
|
|
418
420
|
|
|
419
421
|
it('should return closest vectors', async () => {
|
|
@@ -451,7 +453,7 @@ describe('PgVector', () => {
|
|
|
451
453
|
const indexName = 'test_query_filters';
|
|
452
454
|
beforeAll(async () => {
|
|
453
455
|
try {
|
|
454
|
-
await vectorDB.deleteIndex(indexName);
|
|
456
|
+
await vectorDB.deleteIndex({ indexName });
|
|
455
457
|
} catch {
|
|
456
458
|
// Ignore if doesn't exist
|
|
457
459
|
}
|
|
@@ -459,7 +461,7 @@ describe('PgVector', () => {
|
|
|
459
461
|
});
|
|
460
462
|
|
|
461
463
|
beforeEach(async () => {
|
|
462
|
-
await vectorDB.truncateIndex(indexName);
|
|
464
|
+
await vectorDB.truncateIndex({ indexName });
|
|
463
465
|
const vectors = [
|
|
464
466
|
[1, 0.1, 0],
|
|
465
467
|
[0.9, 0.2, 0],
|
|
@@ -509,7 +511,7 @@ describe('PgVector', () => {
|
|
|
509
511
|
});
|
|
510
512
|
|
|
511
513
|
afterAll(async () => {
|
|
512
|
-
await vectorDB.deleteIndex(indexName);
|
|
514
|
+
await vectorDB.deleteIndex({ indexName });
|
|
513
515
|
});
|
|
514
516
|
|
|
515
517
|
// Numeric Comparison Tests
|
|
@@ -1346,7 +1348,7 @@ describe('PgVector', () => {
|
|
|
1346
1348
|
});
|
|
1347
1349
|
|
|
1348
1350
|
afterAll(async () => {
|
|
1349
|
-
await vectorDB.deleteIndex(testIndexName);
|
|
1351
|
+
await vectorDB.deleteIndex({ indexName: testIndexName });
|
|
1350
1352
|
});
|
|
1351
1353
|
|
|
1352
1354
|
it('should handle non-existent index queries', async () => {
|
|
@@ -1379,7 +1381,7 @@ describe('PgVector', () => {
|
|
|
1379
1381
|
).resolves.not.toThrow();
|
|
1380
1382
|
|
|
1381
1383
|
// Cleanup
|
|
1382
|
-
await vectorDB.deleteIndex(duplicateIndexName);
|
|
1384
|
+
await vectorDB.deleteIndex({ indexName: duplicateIndexName });
|
|
1383
1385
|
});
|
|
1384
1386
|
});
|
|
1385
1387
|
|
|
@@ -1765,7 +1767,7 @@ describe('PgVector', () => {
|
|
|
1765
1767
|
});
|
|
1766
1768
|
|
|
1767
1769
|
afterAll(async () => {
|
|
1768
|
-
await vectorDB.deleteIndex(indexName);
|
|
1770
|
+
await vectorDB.deleteIndex({ indexName });
|
|
1769
1771
|
});
|
|
1770
1772
|
|
|
1771
1773
|
it('should use default ef value', async () => {
|
|
@@ -1810,7 +1812,7 @@ describe('PgVector', () => {
|
|
|
1810
1812
|
});
|
|
1811
1813
|
|
|
1812
1814
|
afterAll(async () => {
|
|
1813
|
-
await vectorDB.deleteIndex(indexName);
|
|
1815
|
+
await vectorDB.deleteIndex({ indexName });
|
|
1814
1816
|
});
|
|
1815
1817
|
|
|
1816
1818
|
it('should use default probe value', async () => {
|
|
@@ -1845,12 +1847,12 @@ describe('PgVector', () => {
|
|
|
1845
1847
|
let warnSpy;
|
|
1846
1848
|
|
|
1847
1849
|
beforeAll(async () => {
|
|
1848
|
-
await vectorDB.createIndex({ indexName
|
|
1850
|
+
await vectorDB.createIndex({ indexName, dimension: 3 });
|
|
1849
1851
|
});
|
|
1850
1852
|
|
|
1851
1853
|
afterAll(async () => {
|
|
1852
|
-
await vectorDB.deleteIndex(indexName);
|
|
1853
|
-
await vectorDB.deleteIndex(indexName2);
|
|
1854
|
+
await vectorDB.deleteIndex({ indexName });
|
|
1855
|
+
await vectorDB.deleteIndex({ indexName: indexName2 });
|
|
1854
1856
|
});
|
|
1855
1857
|
|
|
1856
1858
|
beforeEach(async () => {
|
|
@@ -1859,7 +1861,7 @@ describe('PgVector', () => {
|
|
|
1859
1861
|
|
|
1860
1862
|
afterEach(async () => {
|
|
1861
1863
|
warnSpy.mockRestore();
|
|
1862
|
-
await vectorDB.deleteIndex(indexName2);
|
|
1864
|
+
await vectorDB.deleteIndex({ indexName: indexName2 });
|
|
1863
1865
|
});
|
|
1864
1866
|
|
|
1865
1867
|
it('should show deprecation warning when using individual args for createIndex', async () => {
|
|
@@ -1970,10 +1972,10 @@ describe('PgVector', () => {
|
|
|
1970
1972
|
await expect(Promise.all(promises)).resolves.not.toThrow();
|
|
1971
1973
|
|
|
1972
1974
|
// Verify only one index was actually created
|
|
1973
|
-
const stats = await vectorDB.describeIndex(indexName);
|
|
1975
|
+
const stats = await vectorDB.describeIndex({ indexName });
|
|
1974
1976
|
expect(stats.dimension).toBe(dimension);
|
|
1975
1977
|
|
|
1976
|
-
await vectorDB.deleteIndex(indexName);
|
|
1978
|
+
await vectorDB.deleteIndex({ indexName });
|
|
1977
1979
|
});
|
|
1978
1980
|
|
|
1979
1981
|
it('should handle concurrent buildIndex attempts', async () => {
|
|
@@ -1992,10 +1994,10 @@ describe('PgVector', () => {
|
|
|
1992
1994
|
|
|
1993
1995
|
await expect(Promise.all(promises)).resolves.not.toThrow();
|
|
1994
1996
|
|
|
1995
|
-
const stats = await vectorDB.describeIndex(indexName);
|
|
1997
|
+
const stats = await vectorDB.describeIndex({ indexName });
|
|
1996
1998
|
expect(stats.type).toBe('ivfflat');
|
|
1997
1999
|
|
|
1998
|
-
await vectorDB.deleteIndex(indexName);
|
|
2000
|
+
await vectorDB.deleteIndex({ indexName });
|
|
1999
2001
|
});
|
|
2000
2002
|
});
|
|
2001
2003
|
|
|
@@ -2006,7 +2008,7 @@ describe('PgVector', () => {
|
|
|
2006
2008
|
|
|
2007
2009
|
beforeAll(async () => {
|
|
2008
2010
|
// Initialize default vectorDB first
|
|
2009
|
-
vectorDB = new PgVector(connectionString);
|
|
2011
|
+
vectorDB = new PgVector({ connectionString });
|
|
2010
2012
|
|
|
2011
2013
|
// Create schema using the default vectorDB connection
|
|
2012
2014
|
const client = await vectorDB['pool'].connect();
|
|
@@ -2030,7 +2032,7 @@ describe('PgVector', () => {
|
|
|
2030
2032
|
afterAll(async () => {
|
|
2031
2033
|
// Clean up test tables and schema
|
|
2032
2034
|
try {
|
|
2033
|
-
await customSchemaVectorDB.deleteIndex('schema_test_vectors');
|
|
2035
|
+
await customSchemaVectorDB.deleteIndex({ indexName: 'schema_test_vectors' });
|
|
2034
2036
|
} catch {
|
|
2035
2037
|
// Ignore errors if index doesn't exist
|
|
2036
2038
|
}
|
|
@@ -2075,12 +2077,12 @@ describe('PgVector', () => {
|
|
|
2075
2077
|
beforeEach(async () => {
|
|
2076
2078
|
// Clean up any existing indexes
|
|
2077
2079
|
try {
|
|
2078
|
-
await customSchemaVectorDB.deleteIndex(testIndexName);
|
|
2080
|
+
await customSchemaVectorDB.deleteIndex({ indexName: testIndexName });
|
|
2079
2081
|
} catch {
|
|
2080
2082
|
// Ignore if doesn't exist
|
|
2081
2083
|
}
|
|
2082
2084
|
try {
|
|
2083
|
-
await vectorDB.deleteIndex(testIndexName);
|
|
2085
|
+
await vectorDB.deleteIndex({ indexName: testIndexName });
|
|
2084
2086
|
} catch {
|
|
2085
2087
|
// Ignore if doesn't exist
|
|
2086
2088
|
}
|
|
@@ -2089,12 +2091,12 @@ describe('PgVector', () => {
|
|
|
2089
2091
|
afterEach(async () => {
|
|
2090
2092
|
// Clean up indexes after each test
|
|
2091
2093
|
try {
|
|
2092
|
-
await customSchemaVectorDB.deleteIndex(testIndexName);
|
|
2094
|
+
await customSchemaVectorDB.deleteIndex({ indexName: testIndexName });
|
|
2093
2095
|
} catch {
|
|
2094
2096
|
// Ignore if doesn't exist
|
|
2095
2097
|
}
|
|
2096
2098
|
try {
|
|
2097
|
-
await vectorDB.deleteIndex(testIndexName);
|
|
2099
|
+
await vectorDB.deleteIndex({ indexName: testIndexName });
|
|
2098
2100
|
} catch {
|
|
2099
2101
|
// Ignore if doesn't exist
|
|
2100
2102
|
}
|
|
@@ -2150,7 +2152,7 @@ describe('PgVector', () => {
|
|
|
2150
2152
|
// Insert a vector
|
|
2151
2153
|
await customSchemaVectorDB.upsert({ indexName: testIndexName, vectors: [[1, 2, 3]] });
|
|
2152
2154
|
// Describe the index
|
|
2153
|
-
const stats = await customSchemaVectorDB.describeIndex(testIndexName);
|
|
2155
|
+
const stats = await customSchemaVectorDB.describeIndex({ indexName: testIndexName });
|
|
2154
2156
|
expect(stats).toMatchObject({
|
|
2155
2157
|
dimension: 3,
|
|
2156
2158
|
metric: 'dotproduct',
|
|
@@ -2198,7 +2200,7 @@ describe('PgVector', () => {
|
|
|
2198
2200
|
await customSchemaVectorDB.createIndex({ indexName: testIndexName, dimension: 3 });
|
|
2199
2201
|
|
|
2200
2202
|
// Test index operations
|
|
2201
|
-
const stats = await customSchemaVectorDB.describeIndex(testIndexName);
|
|
2203
|
+
const stats = await customSchemaVectorDB.describeIndex({ indexName: testIndexName });
|
|
2202
2204
|
expect(stats.dimension).toBe(3);
|
|
2203
2205
|
|
|
2204
2206
|
// Test list operation
|
|
@@ -2215,7 +2217,7 @@ describe('PgVector', () => {
|
|
|
2215
2217
|
});
|
|
2216
2218
|
|
|
2217
2219
|
// Test delete operation
|
|
2218
|
-
await customSchemaVectorDB.deleteVector(testIndexName, id!);
|
|
2220
|
+
await customSchemaVectorDB.deleteVector({ indexName: testIndexName, id: id! });
|
|
2219
2221
|
|
|
2220
2222
|
// Verify deletion
|
|
2221
2223
|
const results = await customSchemaVectorDB.query({
|
package/src/vector/index.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { parseSqlIdentifier } from '@mastra/core/utils';
|
|
1
2
|
import { MastraVector } from '@mastra/core/vector';
|
|
2
3
|
import type {
|
|
3
4
|
IndexStats,
|
|
@@ -8,6 +9,10 @@ import type {
|
|
|
8
9
|
ParamsToArgs,
|
|
9
10
|
QueryVectorArgs,
|
|
10
11
|
CreateIndexArgs,
|
|
12
|
+
DescribeIndexParams,
|
|
13
|
+
DeleteIndexParams,
|
|
14
|
+
DeleteVectorParams,
|
|
15
|
+
UpdateVectorParams,
|
|
11
16
|
} from '@mastra/core/vector';
|
|
12
17
|
import type { VectorFilter } from '@mastra/core/vector/filter';
|
|
13
18
|
import { Mutex } from 'async-mutex';
|
|
@@ -143,7 +148,7 @@ export class PgVector extends MastraVector {
|
|
|
143
148
|
// warm the created indexes cache so we don't need to check if indexes exist every time
|
|
144
149
|
const existingIndexes = await this.listIndexes();
|
|
145
150
|
void existingIndexes.map(async indexName => {
|
|
146
|
-
const info = await this.getIndexInfo(indexName);
|
|
151
|
+
const info = await this.getIndexInfo({ indexName });
|
|
147
152
|
const key = await this.getIndexCacheKey({
|
|
148
153
|
indexName,
|
|
149
154
|
metric: info.metric,
|
|
@@ -161,7 +166,9 @@ export class PgVector extends MastraVector {
|
|
|
161
166
|
}
|
|
162
167
|
|
|
163
168
|
private getTableName(indexName: string) {
|
|
164
|
-
|
|
169
|
+
const parsedIndexName = parseSqlIdentifier(indexName, 'index name');
|
|
170
|
+
const parsedSchemaName = this.schema ? parseSqlIdentifier(this.schema, 'schema name') : undefined;
|
|
171
|
+
return parsedSchemaName ? `${parsedSchemaName}.${parsedIndexName}` : parsedIndexName;
|
|
165
172
|
}
|
|
166
173
|
|
|
167
174
|
transformFilter(filter?: VectorFilter) {
|
|
@@ -169,9 +176,11 @@ export class PgVector extends MastraVector {
|
|
|
169
176
|
return translator.translate(filter);
|
|
170
177
|
}
|
|
171
178
|
|
|
172
|
-
async getIndexInfo(
|
|
179
|
+
async getIndexInfo(...args: ParamsToArgs<DescribeIndexParams>): Promise<PGIndexStats> {
|
|
180
|
+
const params = this.normalizeArgs<DescribeIndexParams>('getIndexInfo', args);
|
|
181
|
+
const { indexName } = params;
|
|
173
182
|
if (!this.describeIndexCache.has(indexName)) {
|
|
174
|
-
this.describeIndexCache.set(indexName, await this.describeIndex(indexName));
|
|
183
|
+
this.describeIndexCache.set(indexName, await this.describeIndex({ indexName }));
|
|
175
184
|
}
|
|
176
185
|
return this.describeIndexCache.get(indexName)!;
|
|
177
186
|
}
|
|
@@ -184,14 +193,21 @@ export class PgVector extends MastraVector {
|
|
|
184
193
|
]);
|
|
185
194
|
const { indexName, queryVector, topK = 10, filter, includeVector = false, minScore = 0, ef, probes } = params;
|
|
186
195
|
|
|
196
|
+
if (!Number.isInteger(topK) || topK <= 0) {
|
|
197
|
+
throw new Error('topK must be a positive integer');
|
|
198
|
+
}
|
|
199
|
+
if (!Array.isArray(queryVector) || !queryVector.every(x => typeof x === 'number' && Number.isFinite(x))) {
|
|
200
|
+
throw new Error('queryVector must be an array of finite numbers');
|
|
201
|
+
}
|
|
202
|
+
|
|
187
203
|
const client = await this.pool.connect();
|
|
188
204
|
try {
|
|
189
205
|
const vectorStr = `[${queryVector.join(',')}]`;
|
|
190
206
|
const translatedFilter = this.transformFilter(filter);
|
|
191
|
-
const { sql: filterQuery, values: filterValues } = buildFilterQuery(translatedFilter, minScore);
|
|
207
|
+
const { sql: filterQuery, values: filterValues } = buildFilterQuery(translatedFilter, minScore, topK);
|
|
192
208
|
|
|
193
209
|
// Get index type and configuration
|
|
194
|
-
const indexInfo = await this.getIndexInfo(indexName);
|
|
210
|
+
const indexInfo = await this.getIndexInfo({ indexName });
|
|
195
211
|
|
|
196
212
|
// Set HNSW search parameter if applicable
|
|
197
213
|
if (indexInfo.type === 'hnsw') {
|
|
@@ -221,7 +237,7 @@ export class PgVector extends MastraVector {
|
|
|
221
237
|
FROM vector_scores
|
|
222
238
|
WHERE score > $1
|
|
223
239
|
ORDER BY score DESC
|
|
224
|
-
LIMIT $
|
|
240
|
+
LIMIT $2`;
|
|
225
241
|
const result = await client.query(query, filterValues);
|
|
226
242
|
|
|
227
243
|
return result.rows.map(({ id, score, metadata, embedding }) => ({
|
|
@@ -552,7 +568,16 @@ export class PgVector extends MastraVector {
|
|
|
552
568
|
}
|
|
553
569
|
}
|
|
554
570
|
|
|
555
|
-
|
|
571
|
+
/**
|
|
572
|
+
* Retrieves statistics about a vector index.
|
|
573
|
+
*
|
|
574
|
+
* @param params - The parameters for describing an index
|
|
575
|
+
* @param params.indexName - The name of the index to describe
|
|
576
|
+
* @returns A promise that resolves to the index statistics including dimension, count and metric
|
|
577
|
+
*/
|
|
578
|
+
async describeIndex(...args: ParamsToArgs<DescribeIndexParams>): Promise<PGIndexStats> {
|
|
579
|
+
const params = this.normalizeArgs<DescribeIndexParams>('describeIndex', args);
|
|
580
|
+
const { indexName } = params;
|
|
556
581
|
const client = await this.pool.connect();
|
|
557
582
|
try {
|
|
558
583
|
const tableName = this.getTableName(indexName);
|
|
@@ -648,7 +673,9 @@ export class PgVector extends MastraVector {
|
|
|
648
673
|
}
|
|
649
674
|
}
|
|
650
675
|
|
|
651
|
-
async deleteIndex(
|
|
676
|
+
async deleteIndex(...args: ParamsToArgs<DeleteIndexParams>): Promise<void> {
|
|
677
|
+
const params = this.normalizeArgs<DeleteIndexParams>('deleteIndex', args);
|
|
678
|
+
const { indexName } = params;
|
|
652
679
|
const client = await this.pool.connect();
|
|
653
680
|
try {
|
|
654
681
|
const tableName = this.getTableName(indexName);
|
|
@@ -663,7 +690,9 @@ export class PgVector extends MastraVector {
|
|
|
663
690
|
}
|
|
664
691
|
}
|
|
665
692
|
|
|
666
|
-
async truncateIndex(
|
|
693
|
+
async truncateIndex(...args: ParamsToArgs<DeleteIndexParams>): Promise<void> {
|
|
694
|
+
const params = this.normalizeArgs<DeleteIndexParams>('truncateIndex', args);
|
|
695
|
+
const { indexName } = params;
|
|
667
696
|
const client = await this.pool.connect();
|
|
668
697
|
try {
|
|
669
698
|
const tableName = this.getTableName(indexName);
|
|
@@ -702,7 +731,7 @@ export class PgVector extends MastraVector {
|
|
|
702
731
|
Please use updateVector() instead.
|
|
703
732
|
updateIndexById() will be removed on May 20th, 2025.`,
|
|
704
733
|
);
|
|
705
|
-
await this.updateVector(indexName, id, update);
|
|
734
|
+
await this.updateVector({ indexName, id, update });
|
|
706
735
|
}
|
|
707
736
|
|
|
708
737
|
/**
|
|
@@ -715,14 +744,9 @@ export class PgVector extends MastraVector {
|
|
|
715
744
|
* @returns A promise that resolves when the update is complete.
|
|
716
745
|
* @throws Will throw an error if no updates are provided or if the update operation fails.
|
|
717
746
|
*/
|
|
718
|
-
async updateVector(
|
|
719
|
-
|
|
720
|
-
id
|
|
721
|
-
update: {
|
|
722
|
-
vector?: number[];
|
|
723
|
-
metadata?: Record<string, any>;
|
|
724
|
-
},
|
|
725
|
-
): Promise<void> {
|
|
747
|
+
async updateVector(...args: ParamsToArgs<UpdateVectorParams>): Promise<void> {
|
|
748
|
+
const params = this.normalizeArgs<UpdateVectorParams>('updateVector', args);
|
|
749
|
+
const { indexName, id, update } = params;
|
|
726
750
|
if (!update.vector && !update.metadata) {
|
|
727
751
|
throw new Error('No updates provided');
|
|
728
752
|
}
|
|
@@ -781,7 +805,7 @@ export class PgVector extends MastraVector {
|
|
|
781
805
|
Please use deleteVector() instead.
|
|
782
806
|
deleteIndexById() will be removed on May 20th, 2025.`,
|
|
783
807
|
);
|
|
784
|
-
await this.deleteVector(indexName, id);
|
|
808
|
+
await this.deleteVector({ indexName, id });
|
|
785
809
|
}
|
|
786
810
|
|
|
787
811
|
/**
|
|
@@ -791,7 +815,9 @@ export class PgVector extends MastraVector {
|
|
|
791
815
|
* @returns A promise that resolves when the deletion is complete.
|
|
792
816
|
* @throws Will throw an error if the deletion operation fails.
|
|
793
817
|
*/
|
|
794
|
-
async deleteVector(
|
|
818
|
+
async deleteVector(...args: ParamsToArgs<DeleteVectorParams>): Promise<void> {
|
|
819
|
+
const params = this.normalizeArgs<DeleteVectorParams>('deleteVector', args);
|
|
820
|
+
const { indexName, id } = params;
|
|
795
821
|
const client = await this.pool.connect();
|
|
796
822
|
try {
|
|
797
823
|
const tableName = this.getTableName(indexName);
|