@mastra/pg 0.3.4 → 0.4.0-alpha.1
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 +37 -0
- package/dist/_tsup-dts-rollup.d.cts +21 -83
- package/dist/_tsup-dts-rollup.d.ts +21 -83
- package/dist/index.cjs +169 -185
- package/dist/index.js +169 -185
- package/docker-compose.perf.yaml +9 -9
- package/package.json +7 -4
- package/src/storage/index.test.ts +32 -51
- package/src/storage/index.ts +13 -17
- package/src/vector/index.test.ts +52 -179
- package/src/vector/index.ts +64 -152
- package/src/vector/sql-builder.ts +110 -77
- package/src/vector/vector.performance.test.ts +2 -2
package/dist/index.cjs
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
var utils = require('@mastra/core/utils');
|
|
3
4
|
var vector = require('@mastra/core/vector');
|
|
4
5
|
var asyncMutex = require('async-mutex');
|
|
5
6
|
var pg = require('pg');
|
|
@@ -81,22 +82,26 @@ var PGFilterTranslator = class extends filter.BaseFilterTranslator {
|
|
|
81
82
|
return { $regex: flags ? `(?${flags})${pattern}` : pattern };
|
|
82
83
|
}
|
|
83
84
|
};
|
|
84
|
-
|
|
85
|
-
// src/vector/sql-builder.ts
|
|
86
85
|
var createBasicOperator = (symbol) => {
|
|
87
|
-
return (key, paramIndex) =>
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
86
|
+
return (key, paramIndex) => {
|
|
87
|
+
const jsonPathKey = parseJsonPathKey(key);
|
|
88
|
+
return {
|
|
89
|
+
sql: `CASE
|
|
90
|
+
WHEN $${paramIndex}::text IS NULL THEN metadata#>>'{${jsonPathKey}}' IS ${symbol === "=" ? "" : "NOT"} NULL
|
|
91
|
+
ELSE metadata#>>'{${jsonPathKey}}' ${symbol} $${paramIndex}::text
|
|
92
|
+
END`,
|
|
93
|
+
needsValue: true
|
|
94
|
+
};
|
|
95
|
+
};
|
|
94
96
|
};
|
|
95
97
|
var createNumericOperator = (symbol) => {
|
|
96
|
-
return (key, paramIndex) =>
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
98
|
+
return (key, paramIndex) => {
|
|
99
|
+
const jsonPathKey = parseJsonPathKey(key);
|
|
100
|
+
return {
|
|
101
|
+
sql: `(metadata#>>'{${jsonPathKey}}')::numeric ${symbol} $${paramIndex}`,
|
|
102
|
+
needsValue: true
|
|
103
|
+
};
|
|
104
|
+
};
|
|
100
105
|
};
|
|
101
106
|
function buildElemMatchConditions(value, paramIndex) {
|
|
102
107
|
if (typeof value !== "object" || Array.isArray(value)) {
|
|
@@ -147,46 +152,56 @@ var FILTER_OPERATORS = {
|
|
|
147
152
|
$lt: createNumericOperator("<"),
|
|
148
153
|
$lte: createNumericOperator("<="),
|
|
149
154
|
// Array Operators
|
|
150
|
-
$in: (key, paramIndex) =>
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
155
|
+
$in: (key, paramIndex) => {
|
|
156
|
+
const jsonPathKey = parseJsonPathKey(key);
|
|
157
|
+
return {
|
|
158
|
+
sql: `(
|
|
159
|
+
CASE
|
|
160
|
+
WHEN jsonb_typeof(metadata->'${jsonPathKey}') = 'array' THEN
|
|
161
|
+
EXISTS (
|
|
162
|
+
SELECT 1 FROM jsonb_array_elements_text(metadata->'${jsonPathKey}') as elem
|
|
163
|
+
WHERE elem = ANY($${paramIndex}::text[])
|
|
164
|
+
)
|
|
165
|
+
ELSE metadata#>>'{${jsonPathKey}}' = ANY($${paramIndex}::text[])
|
|
166
|
+
END
|
|
167
|
+
)`,
|
|
168
|
+
needsValue: true
|
|
169
|
+
};
|
|
170
|
+
},
|
|
171
|
+
$nin: (key, paramIndex) => {
|
|
172
|
+
const jsonPathKey = parseJsonPathKey(key);
|
|
173
|
+
return {
|
|
174
|
+
sql: `(
|
|
175
|
+
CASE
|
|
176
|
+
WHEN jsonb_typeof(metadata->'${jsonPathKey}') = 'array' THEN
|
|
177
|
+
NOT EXISTS (
|
|
178
|
+
SELECT 1 FROM jsonb_array_elements_text(metadata->'${jsonPathKey}') as elem
|
|
179
|
+
WHERE elem = ANY($${paramIndex}::text[])
|
|
180
|
+
)
|
|
181
|
+
ELSE metadata#>>'{${jsonPathKey}}' != ALL($${paramIndex}::text[])
|
|
182
|
+
END
|
|
183
|
+
)`,
|
|
184
|
+
needsValue: true
|
|
185
|
+
};
|
|
186
|
+
},
|
|
187
|
+
$all: (key, paramIndex) => {
|
|
188
|
+
const jsonPathKey = parseJsonPathKey(key);
|
|
189
|
+
return {
|
|
190
|
+
sql: `CASE WHEN array_length($${paramIndex}::text[], 1) IS NULL THEN false
|
|
191
|
+
ELSE (metadata#>'{${jsonPathKey}}')::jsonb ?& $${paramIndex}::text[] END`,
|
|
192
|
+
needsValue: true
|
|
193
|
+
};
|
|
194
|
+
},
|
|
181
195
|
$elemMatch: (key, paramIndex, value) => {
|
|
182
196
|
const { sql, values } = buildElemMatchConditions(value, paramIndex);
|
|
197
|
+
const jsonPathKey = parseJsonPathKey(key);
|
|
183
198
|
return {
|
|
184
199
|
sql: `(
|
|
185
200
|
CASE
|
|
186
|
-
WHEN jsonb_typeof(metadata->'${
|
|
201
|
+
WHEN jsonb_typeof(metadata->'${jsonPathKey}') = 'array' THEN
|
|
187
202
|
EXISTS (
|
|
188
203
|
SELECT 1
|
|
189
|
-
FROM jsonb_array_elements(metadata->'${
|
|
204
|
+
FROM jsonb_array_elements(metadata->'${jsonPathKey}') as elem
|
|
190
205
|
WHERE ${sql}
|
|
191
206
|
)
|
|
192
207
|
ELSE FALSE
|
|
@@ -197,33 +212,40 @@ var FILTER_OPERATORS = {
|
|
|
197
212
|
};
|
|
198
213
|
},
|
|
199
214
|
// Element Operators
|
|
200
|
-
$exists: (key) =>
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
215
|
+
$exists: (key) => {
|
|
216
|
+
const jsonPathKey = parseJsonPathKey(key);
|
|
217
|
+
return {
|
|
218
|
+
sql: `metadata ? '${jsonPathKey}'`,
|
|
219
|
+
needsValue: false
|
|
220
|
+
};
|
|
221
|
+
},
|
|
204
222
|
// Logical Operators
|
|
205
223
|
$and: (key) => ({ sql: `(${key})`, needsValue: false }),
|
|
206
224
|
$or: (key) => ({ sql: `(${key})`, needsValue: false }),
|
|
207
225
|
$not: (key) => ({ sql: `NOT (${key})`, needsValue: false }),
|
|
208
226
|
$nor: (key) => ({ sql: `NOT (${key})`, needsValue: false }),
|
|
209
227
|
// Regex Operators
|
|
210
|
-
$regex: (key, paramIndex) =>
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
228
|
+
$regex: (key, paramIndex) => {
|
|
229
|
+
const jsonPathKey = parseJsonPathKey(key);
|
|
230
|
+
return {
|
|
231
|
+
sql: `metadata#>>'{${jsonPathKey}}' ~ $${paramIndex}`,
|
|
232
|
+
needsValue: true
|
|
233
|
+
};
|
|
234
|
+
},
|
|
214
235
|
$contains: (key, paramIndex, value) => {
|
|
236
|
+
const jsonPathKey = parseJsonPathKey(key);
|
|
215
237
|
let sql;
|
|
216
238
|
if (Array.isArray(value)) {
|
|
217
|
-
sql = `(metadata->'${
|
|
239
|
+
sql = `(metadata->'${jsonPathKey}') ?& $${paramIndex}`;
|
|
218
240
|
} else if (typeof value === "string") {
|
|
219
|
-
sql = `metadata->>'${
|
|
241
|
+
sql = `metadata->>'${jsonPathKey}' ILIKE '%' || $${paramIndex} || '%' ESCAPE '\\'`;
|
|
220
242
|
} else {
|
|
221
|
-
sql = `metadata->>'${
|
|
243
|
+
sql = `metadata->>'${jsonPathKey}' = $${paramIndex}`;
|
|
222
244
|
}
|
|
223
245
|
return {
|
|
224
246
|
sql,
|
|
225
247
|
needsValue: true,
|
|
226
|
-
transformValue: () => Array.isArray(value) ? value.map(String) : value
|
|
248
|
+
transformValue: () => Array.isArray(value) ? value.map(String) : typeof value === "string" ? escapeLikePattern(value) : value
|
|
227
249
|
};
|
|
228
250
|
},
|
|
229
251
|
/**
|
|
@@ -238,29 +260,36 @@ var FILTER_OPERATORS = {
|
|
|
238
260
|
// return JSON.stringify(parts.reduceRight((value, key) => ({ [key]: value }), value));
|
|
239
261
|
// },
|
|
240
262
|
// }),
|
|
241
|
-
$size: (key, paramIndex) =>
|
|
242
|
-
|
|
263
|
+
$size: (key, paramIndex) => {
|
|
264
|
+
const jsonPathKey = parseJsonPathKey(key);
|
|
265
|
+
return {
|
|
266
|
+
sql: `(
|
|
243
267
|
CASE
|
|
244
|
-
WHEN jsonb_typeof(metadata#>'{${
|
|
245
|
-
jsonb_array_length(metadata#>'{${
|
|
268
|
+
WHEN jsonb_typeof(metadata#>'{${jsonPathKey}}') = 'array' THEN
|
|
269
|
+
jsonb_array_length(metadata#>'{${jsonPathKey}}') = $${paramIndex}
|
|
246
270
|
ELSE FALSE
|
|
247
271
|
END
|
|
248
272
|
)`,
|
|
249
|
-
|
|
250
|
-
|
|
273
|
+
needsValue: true
|
|
274
|
+
};
|
|
275
|
+
}
|
|
251
276
|
};
|
|
252
|
-
var
|
|
253
|
-
|
|
277
|
+
var parseJsonPathKey = (key) => {
|
|
278
|
+
const parsedKey = key !== "" ? utils.parseFieldKey(key) : "";
|
|
279
|
+
return parsedKey.replace(/\./g, ",");
|
|
254
280
|
};
|
|
255
|
-
function
|
|
256
|
-
|
|
281
|
+
function escapeLikePattern(str) {
|
|
282
|
+
return str.replace(/([%_\\])/g, "\\$1");
|
|
283
|
+
}
|
|
284
|
+
function buildFilterQuery(filter, minScore, topK) {
|
|
285
|
+
const values = [minScore, topK];
|
|
257
286
|
function buildCondition(key, value, parentPath) {
|
|
258
287
|
if (["$and", "$or", "$not", "$nor"].includes(key)) {
|
|
259
288
|
return handleLogicalOperator(key, value);
|
|
260
289
|
}
|
|
261
290
|
if (!value || typeof value !== "object") {
|
|
262
291
|
values.push(value);
|
|
263
|
-
return `metadata#>>'{${
|
|
292
|
+
return `metadata#>>'{${parseJsonPathKey(key)}}' = $${values.length}`;
|
|
264
293
|
}
|
|
265
294
|
const [[operator, operatorValue] = []] = Object.entries(value);
|
|
266
295
|
if (operator === "$not") {
|
|
@@ -270,7 +299,7 @@ function buildFilterQuery(filter, minScore) {
|
|
|
270
299
|
throw new Error(`Invalid operator in $not condition: ${nestedOp}`);
|
|
271
300
|
}
|
|
272
301
|
const operatorFn2 = FILTER_OPERATORS[nestedOp];
|
|
273
|
-
const operatorResult2 = operatorFn2(key, values.length + 1);
|
|
302
|
+
const operatorResult2 = operatorFn2(key, values.length + 1, nestedValue);
|
|
274
303
|
if (operatorResult2.needsValue) {
|
|
275
304
|
values.push(nestedValue);
|
|
276
305
|
}
|
|
@@ -341,27 +370,11 @@ var PgVector = class extends vector.MastraVector {
|
|
|
341
370
|
installVectorExtensionPromise = null;
|
|
342
371
|
vectorExtensionInstalled = void 0;
|
|
343
372
|
schemaSetupComplete = void 0;
|
|
344
|
-
constructor(
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
console.warn(
|
|
350
|
-
`DEPRECATION WARNING: Passing connectionString as a string to PgVector constructor is deprecated.
|
|
351
|
-
|
|
352
|
-
Please use an object parameter instead:
|
|
353
|
-
new PgVector({ connectionString })
|
|
354
|
-
|
|
355
|
-
The string signature will be removed on May 20th, 2025.`
|
|
356
|
-
);
|
|
357
|
-
connectionString = config;
|
|
358
|
-
schemaName = void 0;
|
|
359
|
-
pgPoolOptions = void 0;
|
|
360
|
-
} else {
|
|
361
|
-
connectionString = config.connectionString;
|
|
362
|
-
schemaName = config.schemaName;
|
|
363
|
-
pgPoolOptions = config.pgPoolOptions;
|
|
364
|
-
}
|
|
373
|
+
constructor({
|
|
374
|
+
connectionString,
|
|
375
|
+
schemaName,
|
|
376
|
+
pgPoolOptions
|
|
377
|
+
}) {
|
|
365
378
|
if (!connectionString || connectionString.trim() === "") {
|
|
366
379
|
throw new Error(
|
|
367
380
|
"PgVector: connectionString must be provided and cannot be empty. Passing an empty string may cause fallback to local Postgres defaults."
|
|
@@ -389,7 +402,7 @@ var PgVector = class extends vector.MastraVector {
|
|
|
389
402
|
void (async () => {
|
|
390
403
|
const existingIndexes = await this.listIndexes();
|
|
391
404
|
void existingIndexes.map(async (indexName) => {
|
|
392
|
-
const info = await this.getIndexInfo(indexName);
|
|
405
|
+
const info = await this.getIndexInfo({ indexName });
|
|
393
406
|
const key = await this.getIndexCacheKey({
|
|
394
407
|
indexName,
|
|
395
408
|
metric: info.metric,
|
|
@@ -405,31 +418,42 @@ var PgVector = class extends vector.MastraVector {
|
|
|
405
418
|
return this.mutexesByName.get(indexName);
|
|
406
419
|
}
|
|
407
420
|
getTableName(indexName) {
|
|
408
|
-
|
|
421
|
+
const parsedIndexName = utils.parseSqlIdentifier(indexName, "index name");
|
|
422
|
+
const parsedSchemaName = this.schema ? utils.parseSqlIdentifier(this.schema, "schema name") : void 0;
|
|
423
|
+
return parsedSchemaName ? `${parsedSchemaName}.${parsedIndexName}` : parsedIndexName;
|
|
409
424
|
}
|
|
410
425
|
transformFilter(filter) {
|
|
411
426
|
const translator = new PGFilterTranslator();
|
|
412
427
|
return translator.translate(filter);
|
|
413
428
|
}
|
|
414
|
-
async getIndexInfo(indexName) {
|
|
429
|
+
async getIndexInfo({ indexName }) {
|
|
415
430
|
if (!this.describeIndexCache.has(indexName)) {
|
|
416
|
-
this.describeIndexCache.set(indexName, await this.describeIndex(indexName));
|
|
431
|
+
this.describeIndexCache.set(indexName, await this.describeIndex({ indexName }));
|
|
417
432
|
}
|
|
418
433
|
return this.describeIndexCache.get(indexName);
|
|
419
434
|
}
|
|
420
|
-
async query(
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
435
|
+
async query({
|
|
436
|
+
indexName,
|
|
437
|
+
queryVector,
|
|
438
|
+
topK = 10,
|
|
439
|
+
filter,
|
|
440
|
+
includeVector = false,
|
|
441
|
+
minScore = 0,
|
|
442
|
+
ef,
|
|
443
|
+
probes
|
|
444
|
+
}) {
|
|
445
|
+
if (!Number.isInteger(topK) || topK <= 0) {
|
|
446
|
+
throw new Error("topK must be a positive integer");
|
|
447
|
+
}
|
|
448
|
+
if (!Array.isArray(queryVector) || !queryVector.every((x) => typeof x === "number" && Number.isFinite(x))) {
|
|
449
|
+
throw new Error("queryVector must be an array of finite numbers");
|
|
450
|
+
}
|
|
427
451
|
const client = await this.pool.connect();
|
|
428
452
|
try {
|
|
429
453
|
const vectorStr = `[${queryVector.join(",")}]`;
|
|
430
454
|
const translatedFilter = this.transformFilter(filter);
|
|
431
|
-
const { sql: filterQuery, values: filterValues } = buildFilterQuery(translatedFilter, minScore);
|
|
432
|
-
const indexInfo = await this.getIndexInfo(indexName);
|
|
455
|
+
const { sql: filterQuery, values: filterValues } = buildFilterQuery(translatedFilter, minScore, topK);
|
|
456
|
+
const indexInfo = await this.getIndexInfo({ indexName });
|
|
433
457
|
if (indexInfo.type === "hnsw") {
|
|
434
458
|
const calculatedEf = ef ?? Math.max(topK, (indexInfo?.config?.m ?? 16) * topK);
|
|
435
459
|
const searchEf = Math.min(1e3, Math.max(1, calculatedEf));
|
|
@@ -453,7 +477,7 @@ var PgVector = class extends vector.MastraVector {
|
|
|
453
477
|
FROM vector_scores
|
|
454
478
|
WHERE score > $1
|
|
455
479
|
ORDER BY score DESC
|
|
456
|
-
LIMIT $
|
|
480
|
+
LIMIT $2`;
|
|
457
481
|
const result = await client.query(query, filterValues);
|
|
458
482
|
return result.rows.map(({ id, score, metadata, embedding }) => ({
|
|
459
483
|
id,
|
|
@@ -465,9 +489,7 @@ var PgVector = class extends vector.MastraVector {
|
|
|
465
489
|
client.release();
|
|
466
490
|
}
|
|
467
491
|
}
|
|
468
|
-
async upsert(
|
|
469
|
-
const params = this.normalizeArgs("upsert", args);
|
|
470
|
-
const { indexName, vectors, metadata, ids } = params;
|
|
492
|
+
async upsert({ indexName, vectors, metadata, ids }) {
|
|
471
493
|
const tableName = this.getTableName(indexName);
|
|
472
494
|
const client = await this.pool.connect();
|
|
473
495
|
try {
|
|
@@ -494,7 +516,7 @@ var PgVector = class extends vector.MastraVector {
|
|
|
494
516
|
if (match) {
|
|
495
517
|
const [, expected, actual] = match;
|
|
496
518
|
throw new Error(
|
|
497
|
-
`Vector dimension mismatch: Index "${
|
|
519
|
+
`Vector dimension mismatch: Index "${indexName}" expects ${expected} dimensions but got ${actual} dimensions. Either use a matching embedding model or delete and recreate the index with the new dimension.`
|
|
498
520
|
);
|
|
499
521
|
}
|
|
500
522
|
}
|
|
@@ -504,8 +526,13 @@ var PgVector = class extends vector.MastraVector {
|
|
|
504
526
|
}
|
|
505
527
|
}
|
|
506
528
|
hasher = xxhash__default.default();
|
|
507
|
-
async getIndexCacheKey(
|
|
508
|
-
|
|
529
|
+
async getIndexCacheKey({
|
|
530
|
+
indexName,
|
|
531
|
+
dimension,
|
|
532
|
+
metric,
|
|
533
|
+
type
|
|
534
|
+
}) {
|
|
535
|
+
const input = indexName + dimension + metric + (type || "ivfflat");
|
|
509
536
|
return (await this.hasher).h32(input);
|
|
510
537
|
}
|
|
511
538
|
cachedIndexExists(indexName, newKey) {
|
|
@@ -553,12 +580,13 @@ var PgVector = class extends vector.MastraVector {
|
|
|
553
580
|
}
|
|
554
581
|
await this.setupSchemaPromise;
|
|
555
582
|
}
|
|
556
|
-
async createIndex(
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
583
|
+
async createIndex({
|
|
584
|
+
indexName,
|
|
585
|
+
dimension,
|
|
586
|
+
metric = "cosine",
|
|
587
|
+
indexConfig = {},
|
|
588
|
+
buildIndex = true
|
|
589
|
+
}) {
|
|
562
590
|
const tableName = this.getTableName(indexName);
|
|
563
591
|
if (!indexName.match(/^[a-zA-Z_][a-zA-Z0-9_]*$/)) {
|
|
564
592
|
throw new Error("Invalid index name format");
|
|
@@ -599,20 +627,7 @@ var PgVector = class extends vector.MastraVector {
|
|
|
599
627
|
}
|
|
600
628
|
});
|
|
601
629
|
}
|
|
602
|
-
|
|
603
|
-
* @deprecated This function is deprecated. Use buildIndex instead
|
|
604
|
-
* This function will be removed on May 20th, 2025
|
|
605
|
-
*/
|
|
606
|
-
async defineIndex(indexName, metric = "cosine", indexConfig) {
|
|
607
|
-
console.warn("defineIndex is deprecated. Use buildIndex instead. This function will be removed on May 20th, 2025");
|
|
608
|
-
return this.buildIndex({ indexName, metric, indexConfig });
|
|
609
|
-
}
|
|
610
|
-
async buildIndex(...args) {
|
|
611
|
-
const params = this.normalizeArgs("buildIndex", args, [
|
|
612
|
-
"metric",
|
|
613
|
-
"indexConfig"
|
|
614
|
-
]);
|
|
615
|
-
const { indexName, metric = "cosine", indexConfig } = params;
|
|
630
|
+
async buildIndex({ indexName, metric = "cosine", indexConfig }) {
|
|
616
631
|
const client = await this.pool.connect();
|
|
617
632
|
try {
|
|
618
633
|
await this.setupIndex({ indexName, metric, indexConfig }, client);
|
|
@@ -716,7 +731,13 @@ var PgVector = class extends vector.MastraVector {
|
|
|
716
731
|
client.release();
|
|
717
732
|
}
|
|
718
733
|
}
|
|
719
|
-
|
|
734
|
+
/**
|
|
735
|
+
* Retrieves statistics about a vector index.
|
|
736
|
+
*
|
|
737
|
+
* @param {string} indexName - The name of the index to describe
|
|
738
|
+
* @returns A promise that resolves to the index statistics including dimension, count and metric
|
|
739
|
+
*/
|
|
740
|
+
async describeIndex({ indexName }) {
|
|
720
741
|
const client = await this.pool.connect();
|
|
721
742
|
try {
|
|
722
743
|
const tableName = this.getTableName(indexName);
|
|
@@ -790,7 +811,7 @@ var PgVector = class extends vector.MastraVector {
|
|
|
790
811
|
client.release();
|
|
791
812
|
}
|
|
792
813
|
}
|
|
793
|
-
async deleteIndex(indexName) {
|
|
814
|
+
async deleteIndex({ indexName }) {
|
|
794
815
|
const client = await this.pool.connect();
|
|
795
816
|
try {
|
|
796
817
|
const tableName = this.getTableName(indexName);
|
|
@@ -803,7 +824,7 @@ var PgVector = class extends vector.MastraVector {
|
|
|
803
824
|
client.release();
|
|
804
825
|
}
|
|
805
826
|
}
|
|
806
|
-
async truncateIndex(indexName) {
|
|
827
|
+
async truncateIndex({ indexName }) {
|
|
807
828
|
const client = await this.pool.connect();
|
|
808
829
|
try {
|
|
809
830
|
const tableName = this.getTableName(indexName);
|
|
@@ -819,8 +840,6 @@ var PgVector = class extends vector.MastraVector {
|
|
|
819
840
|
await this.pool.end();
|
|
820
841
|
}
|
|
821
842
|
/**
|
|
822
|
-
* @deprecated Use {@link updateVector} instead. This method will be removed on May 20th, 2025.
|
|
823
|
-
*
|
|
824
843
|
* Updates a vector by its ID with the provided vector and/or metadata.
|
|
825
844
|
* @param indexName - The name of the index containing the vector.
|
|
826
845
|
* @param id - The ID of the vector to update.
|
|
@@ -830,25 +849,7 @@ var PgVector = class extends vector.MastraVector {
|
|
|
830
849
|
* @returns A promise that resolves when the update is complete.
|
|
831
850
|
* @throws Will throw an error if no updates are provided or if the update operation fails.
|
|
832
851
|
*/
|
|
833
|
-
async
|
|
834
|
-
this.logger.warn(
|
|
835
|
-
`Deprecation Warning: updateIndexById() is deprecated.
|
|
836
|
-
Please use updateVector() instead.
|
|
837
|
-
updateIndexById() will be removed on May 20th, 2025.`
|
|
838
|
-
);
|
|
839
|
-
await this.updateVector(indexName, id, update);
|
|
840
|
-
}
|
|
841
|
-
/**
|
|
842
|
-
* Updates a vector by its ID with the provided vector and/or metadata.
|
|
843
|
-
* @param indexName - The name of the index containing the vector.
|
|
844
|
-
* @param id - The ID of the vector to update.
|
|
845
|
-
* @param update - An object containing the vector and/or metadata to update.
|
|
846
|
-
* @param update.vector - An optional array of numbers representing the new vector.
|
|
847
|
-
* @param update.metadata - An optional record containing the new metadata.
|
|
848
|
-
* @returns A promise that resolves when the update is complete.
|
|
849
|
-
* @throws Will throw an error if no updates are provided or if the update operation fails.
|
|
850
|
-
*/
|
|
851
|
-
async updateVector(indexName, id, update) {
|
|
852
|
+
async updateVector({ indexName, id, update }) {
|
|
852
853
|
if (!update.vector && !update.metadata) {
|
|
853
854
|
throw new Error("No updates provided");
|
|
854
855
|
}
|
|
@@ -882,23 +883,6 @@ var PgVector = class extends vector.MastraVector {
|
|
|
882
883
|
client.release();
|
|
883
884
|
}
|
|
884
885
|
}
|
|
885
|
-
/**
|
|
886
|
-
* @deprecated Use {@link deleteVector} instead. This method will be removed on May 20th, 2025.
|
|
887
|
-
*
|
|
888
|
-
* Deletes a vector by its ID.
|
|
889
|
-
* @param indexName - The name of the index containing the vector.
|
|
890
|
-
* @param id - The ID of the vector to delete.
|
|
891
|
-
* @returns A promise that resolves when the deletion is complete.
|
|
892
|
-
* @throws Will throw an error if the deletion operation fails.
|
|
893
|
-
*/
|
|
894
|
-
async deleteIndexById(indexName, id) {
|
|
895
|
-
this.logger.warn(
|
|
896
|
-
`Deprecation Warning: deleteIndexById() is deprecated.
|
|
897
|
-
Please use deleteVector() instead.
|
|
898
|
-
deleteIndexById() will be removed on May 20th, 2025.`
|
|
899
|
-
);
|
|
900
|
-
await this.deleteVector(indexName, id);
|
|
901
|
-
}
|
|
902
886
|
/**
|
|
903
887
|
* Deletes a vector by its ID.
|
|
904
888
|
* @param indexName - The name of the index containing the vector.
|
|
@@ -906,7 +890,7 @@ var PgVector = class extends vector.MastraVector {
|
|
|
906
890
|
* @returns A promise that resolves when the deletion is complete.
|
|
907
891
|
* @throws Will throw an error if the deletion operation fails.
|
|
908
892
|
*/
|
|
909
|
-
async deleteVector(indexName, id) {
|
|
893
|
+
async deleteVector({ indexName, id }) {
|
|
910
894
|
const client = await this.pool.connect();
|
|
911
895
|
try {
|
|
912
896
|
const tableName = this.getTableName(indexName);
|
|
@@ -947,12 +931,7 @@ var PostgresStore = class extends storage.MastraStorage {
|
|
|
947
931
|
}
|
|
948
932
|
super({ name: "PostgresStore" });
|
|
949
933
|
this.pgp = pgPromise__default.default();
|
|
950
|
-
|
|
951
|
-
console.warn(
|
|
952
|
-
'[DEPRECATION NOTICE] The "schema" option in PostgresStore is deprecated. Please use "schemaName" instead. Support for "schema" will be removed on May 20th, 2025.'
|
|
953
|
-
);
|
|
954
|
-
}
|
|
955
|
-
this.schema = config.schemaName ?? config.schema;
|
|
934
|
+
this.schema = config.schemaName;
|
|
956
935
|
this.db = this.pgp(
|
|
957
936
|
`connectionString` in config ? { connectionString: config.connectionString } : {
|
|
958
937
|
host: config.host,
|
|
@@ -965,7 +944,9 @@ var PostgresStore = class extends storage.MastraStorage {
|
|
|
965
944
|
);
|
|
966
945
|
}
|
|
967
946
|
getTableName(indexName) {
|
|
968
|
-
|
|
947
|
+
const parsedIndexName = utils.parseSqlIdentifier(indexName, "table name");
|
|
948
|
+
const parsedSchemaName = this.schema ? utils.parseSqlIdentifier(this.schema, "schema name") : void 0;
|
|
949
|
+
return parsedSchemaName ? `${parsedSchemaName}."${parsedIndexName}"` : `"${parsedIndexName}"`;
|
|
969
950
|
}
|
|
970
951
|
async getEvalsByAgentName(agentName, type) {
|
|
971
952
|
try {
|
|
@@ -1040,12 +1021,14 @@ var PostgresStore = class extends storage.MastraStorage {
|
|
|
1040
1021
|
}
|
|
1041
1022
|
if (attributes) {
|
|
1042
1023
|
Object.keys(attributes).forEach((key) => {
|
|
1043
|
-
|
|
1024
|
+
const parsedKey = utils.parseSqlIdentifier(key, "attribute key");
|
|
1025
|
+
conditions.push(`attributes->>'${parsedKey}' = $${idx++}`);
|
|
1044
1026
|
});
|
|
1045
1027
|
}
|
|
1046
1028
|
if (filters) {
|
|
1047
1029
|
Object.entries(filters).forEach(([key]) => {
|
|
1048
|
-
|
|
1030
|
+
const parsedKey = utils.parseSqlIdentifier(key, "filter key");
|
|
1031
|
+
conditions.push(`${parsedKey} = $${idx++}`);
|
|
1049
1032
|
});
|
|
1050
1033
|
}
|
|
1051
1034
|
if (fromDate) {
|
|
@@ -1147,10 +1130,11 @@ var PostgresStore = class extends storage.MastraStorage {
|
|
|
1147
1130
|
}) {
|
|
1148
1131
|
try {
|
|
1149
1132
|
const columns = Object.entries(schema).map(([name, def]) => {
|
|
1133
|
+
const parsedName = utils.parseSqlIdentifier(name, "column name");
|
|
1150
1134
|
const constraints = [];
|
|
1151
1135
|
if (def.primaryKey) constraints.push("PRIMARY KEY");
|
|
1152
1136
|
if (!def.nullable) constraints.push("NOT NULL");
|
|
1153
|
-
return `"${
|
|
1137
|
+
return `"${parsedName}" ${def.type.toUpperCase()} ${constraints.join(" ")}`;
|
|
1154
1138
|
}).join(",\n");
|
|
1155
1139
|
if (this.schema) {
|
|
1156
1140
|
await this.setupSchema();
|
|
@@ -1187,7 +1171,7 @@ var PostgresStore = class extends storage.MastraStorage {
|
|
|
1187
1171
|
}
|
|
1188
1172
|
async insert({ tableName, record }) {
|
|
1189
1173
|
try {
|
|
1190
|
-
const columns = Object.keys(record);
|
|
1174
|
+
const columns = Object.keys(record).map((col) => utils.parseSqlIdentifier(col, "column name"));
|
|
1191
1175
|
const values = Object.values(record);
|
|
1192
1176
|
const placeholders = values.map((_, i) => `$${i + 1}`).join(", ");
|
|
1193
1177
|
await this.db.none(
|
|
@@ -1201,7 +1185,7 @@ var PostgresStore = class extends storage.MastraStorage {
|
|
|
1201
1185
|
}
|
|
1202
1186
|
async load({ tableName, keys }) {
|
|
1203
1187
|
try {
|
|
1204
|
-
const keyEntries = Object.entries(keys);
|
|
1188
|
+
const keyEntries = Object.entries(keys).map(([key, value]) => [utils.parseSqlIdentifier(key, "column name"), value]);
|
|
1205
1189
|
const conditions = keyEntries.map(([key], index) => `"${key}" = $${index + 1}`).join(" AND ");
|
|
1206
1190
|
const values = keyEntries.map(([_, value]) => value);
|
|
1207
1191
|
const result = await this.db.oneOrNone(
|