@mastra/pg 1.23.0-alpha.6 → 1.23.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/dist/docs/SKILL.md +1 -1
- package/dist/docs/assets/SOURCE_MAP.json +1 -1
- package/dist/index.cjs +136 -44
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +136 -44
- package/dist/index.js.map +1 -1
- package/dist/vector/index.d.ts +9 -8
- package/dist/vector/index.d.ts.map +1 -1
- package/dist/vector/namespace-test-utils.d.ts +9 -0
- package/dist/vector/namespace-test-utils.d.ts.map +1 -0
- package/package.json +5 -5
package/dist/docs/SKILL.md
CHANGED
package/dist/index.cjs
CHANGED
|
@@ -584,6 +584,8 @@ var PgVector = class extends _mastra_core_vector.MastraVector {
|
|
|
584
584
|
indexMetadataCache = /* @__PURE__ */ new Map();
|
|
585
585
|
createdIndexes = /* @__PURE__ */ new Map();
|
|
586
586
|
namespaceReadyIndexes = /* @__PURE__ */ new Set();
|
|
587
|
+
/** In-flight lazy namespace migrations, keyed by index name (see {@link ensureNamespaceReady}). */
|
|
588
|
+
namespaceReadyCache = /* @__PURE__ */ new Map();
|
|
587
589
|
indexVectorTypes = /* @__PURE__ */ new Map();
|
|
588
590
|
mutexesByName = /* @__PURE__ */ new Map();
|
|
589
591
|
schema;
|
|
@@ -828,8 +830,10 @@ var PgVector = class extends _mastra_core_vector.MastraVector {
|
|
|
828
830
|
AND attnum > 0
|
|
829
831
|
AND NOT attisdropped`, [tableName])).rowCount === 0) return;
|
|
830
832
|
await client.query(`ALTER TABLE ${tableName} ADD COLUMN IF NOT EXISTS namespace VARCHAR(255) NOT NULL DEFAULT '${DEFAULT_NAMESPACE}'`);
|
|
831
|
-
|
|
832
|
-
|
|
833
|
+
if (!(await this.getNamespaceSchemaState(tableName, client)).composite_index) {
|
|
834
|
+
const namespaceIndexName = this.getNamespaceIndexName(parsedIndexName);
|
|
835
|
+
await client.query(`CREATE UNIQUE INDEX IF NOT EXISTS "${namespaceIndexName}" ON ${tableName} (namespace, vector_id)`);
|
|
836
|
+
}
|
|
833
837
|
const legacyConstraints = await client.query(`SELECT c.conname
|
|
834
838
|
FROM pg_constraint c
|
|
835
839
|
WHERE c.conrelid = to_regclass($1)
|
|
@@ -840,21 +844,84 @@ var PgVector = class extends _mastra_core_vector.MastraVector {
|
|
|
840
844
|
await client.query(`ALTER TABLE ${tableName} DROP CONSTRAINT "${parsedConstraintName}"`);
|
|
841
845
|
}
|
|
842
846
|
}
|
|
843
|
-
/**
|
|
844
|
-
* Name of the unique (namespace, vector_id) index for a table.
|
|
845
|
-
*
|
|
846
|
-
* The full `<index>_namespace_vector_id_idx` name is kept whenever it fits so tables that
|
|
847
|
-
* were already migrated keep matching `IF NOT EXISTS`. Longer index names would exceed
|
|
848
|
-
* Postgres' 63-char identifier limit, so those fall back to a truncated prefix plus a hash
|
|
849
|
-
* of the index name to distinguish tables that
|
|
850
|
-
* share a long prefix.
|
|
851
|
-
*/
|
|
852
847
|
getNamespaceIndexName(parsedIndexName) {
|
|
853
848
|
const fullName = `${parsedIndexName}_namespace_vector_id_idx`;
|
|
854
849
|
if (fullName.length <= 63) return fullName;
|
|
855
850
|
const suffix = `_ns_${(0, crypto$1.createHash)("sha256").update(parsedIndexName).digest("hex").slice(0, 32)}_idx`;
|
|
856
851
|
return `${parsedIndexName.slice(0, 63 - suffix.length)}${suffix}`;
|
|
857
852
|
}
|
|
853
|
+
async getNamespaceSchemaState(tableName, client) {
|
|
854
|
+
return (await client.query(`SELECT
|
|
855
|
+
EXISTS (SELECT 1 FROM pg_attribute WHERE attrelid = to_regclass($1)
|
|
856
|
+
AND attname = 'vector_id' AND attnum > 0 AND NOT attisdropped) AS vector_id,
|
|
857
|
+
EXISTS (SELECT 1 FROM pg_attribute WHERE attrelid = to_regclass($1)
|
|
858
|
+
AND attname = 'namespace' AND attnum > 0 AND NOT attisdropped) AS namespace,
|
|
859
|
+
EXISTS (
|
|
860
|
+
SELECT 1 FROM pg_index i
|
|
861
|
+
WHERE i.indrelid = to_regclass($1)
|
|
862
|
+
AND i.indisunique AND i.indisvalid AND i.indisready AND i.indimmediate
|
|
863
|
+
AND i.indpred IS NULL AND i.indexprs IS NULL AND i.indnkeyatts = 2
|
|
864
|
+
AND (SELECT array_agg(a.attname::text ORDER BY a.attname)
|
|
865
|
+
FROM unnest(i.indkey) WITH ORDINALITY AS k(attnum, position)
|
|
866
|
+
JOIN pg_attribute a ON a.attrelid = i.indrelid AND a.attnum = k.attnum
|
|
867
|
+
WHERE k.position <= i.indnkeyatts) = ARRAY['namespace', 'vector_id']
|
|
868
|
+
) AS composite_index,
|
|
869
|
+
EXISTS (SELECT 1 FROM pg_constraint WHERE conrelid = to_regclass($1)
|
|
870
|
+
AND contype = 'u' AND pg_get_constraintdef(oid) = 'UNIQUE (vector_id)') AS legacy_constraint`, [tableName])).rows[0];
|
|
871
|
+
}
|
|
872
|
+
async reconcileNamespace(indexName, client) {
|
|
873
|
+
const { tableName } = this.getTableName(indexName);
|
|
874
|
+
await client.query("BEGIN");
|
|
875
|
+
try {
|
|
876
|
+
await client.query("SELECT pg_advisory_xact_lock((1936876916::bigint << 32) | to_regclass($1)::oid::bigint)", [tableName]);
|
|
877
|
+
const state = await this.getNamespaceSchemaState(tableName, client);
|
|
878
|
+
if (!state.vector_id) {
|
|
879
|
+
await client.query("ROLLBACK");
|
|
880
|
+
return false;
|
|
881
|
+
}
|
|
882
|
+
if (!state.namespace || !state.composite_index || state.legacy_constraint) {
|
|
883
|
+
if (this.disableInit || process.env.MASTRA_DISABLE_STORAGE_INIT === "true") throw new _mastra_core_error.MastraError({
|
|
884
|
+
id: (0, _mastra_core_storage.createVectorErrorId)("PG", "ENSURE_NAMESPACE", "MIGRATION_REQUIRED"),
|
|
885
|
+
domain: _mastra_core_error.ErrorDomain.MASTRA_VECTOR,
|
|
886
|
+
category: _mastra_core_error.ErrorCategory.USER,
|
|
887
|
+
text: `Vector index "${indexName}" requires namespace migration and schema changes are disabled. Call createIndex({ indexName: "${indexName}", dimension }) with init enabled, or apply the namespace migration SQL from the @mastra/pg changelog.`,
|
|
888
|
+
details: { indexName }
|
|
889
|
+
});
|
|
890
|
+
await this.ensureNamespaceSchema(indexName, client);
|
|
891
|
+
const migrated = await this.getNamespaceSchemaState(tableName, client);
|
|
892
|
+
if (!migrated.namespace || !migrated.composite_index || migrated.legacy_constraint) throw new _mastra_core_error.MastraError({
|
|
893
|
+
id: (0, _mastra_core_storage.createVectorErrorId)("PG", "ENSURE_NAMESPACE", "MIGRATION_REQUIRED"),
|
|
894
|
+
domain: _mastra_core_error.ErrorDomain.MASTRA_VECTOR,
|
|
895
|
+
category: _mastra_core_error.ErrorCategory.USER,
|
|
896
|
+
text: `Vector index "${indexName}" requires a valid unique (namespace, vector_id) index. Resolve conflicting index names and retry the namespace migration.`,
|
|
897
|
+
details: { indexName }
|
|
898
|
+
});
|
|
899
|
+
}
|
|
900
|
+
await client.query("COMMIT");
|
|
901
|
+
return true;
|
|
902
|
+
} catch (error) {
|
|
903
|
+
await client.query("ROLLBACK");
|
|
904
|
+
throw error;
|
|
905
|
+
}
|
|
906
|
+
}
|
|
907
|
+
/**
|
|
908
|
+
* Every data path filters on `namespace`, but tables created before that column existed are
|
|
909
|
+
* only migrated by `createIndex()`, which callers are not required to invoke before reading.
|
|
910
|
+
* Run the migration lazily instead, once per index per process.
|
|
911
|
+
*/
|
|
912
|
+
ensureNamespaceReady(indexName) {
|
|
913
|
+
if (this.namespaceReadyIndexes.has(indexName)) return Promise.resolve();
|
|
914
|
+
return this.memoize(this.namespaceReadyCache, indexName, () => this.getMutexByName(`create-${indexName}`).runExclusive(async () => {
|
|
915
|
+
if (this.namespaceReadyIndexes.has(indexName)) return;
|
|
916
|
+
const client = await this.pool.connect();
|
|
917
|
+
try {
|
|
918
|
+
if (await this.reconcileNamespace(indexName, client)) this.namespaceReadyIndexes.add(indexName);
|
|
919
|
+
else this.namespaceReadyCache.delete(indexName);
|
|
920
|
+
} finally {
|
|
921
|
+
client.release();
|
|
922
|
+
}
|
|
923
|
+
}));
|
|
924
|
+
}
|
|
858
925
|
transformFilter(filter) {
|
|
859
926
|
return new PGFilterTranslator().translate(filter);
|
|
860
927
|
}
|
|
@@ -912,8 +979,10 @@ var PgVector = class extends _mastra_core_vector.MastraVector {
|
|
|
912
979
|
throw mastraError;
|
|
913
980
|
}
|
|
914
981
|
if (queryVector === void 0) {
|
|
915
|
-
|
|
982
|
+
let client;
|
|
916
983
|
try {
|
|
984
|
+
await this.ensureNamespaceReady(indexName);
|
|
985
|
+
client = await this.pool.connect();
|
|
917
986
|
const { sql: filterQuery, values: filterValues } = buildDeleteFilterQuery(this.transformFilter(filter));
|
|
918
987
|
const { tableName } = this.getTableName(indexName);
|
|
919
988
|
const filterClause = filterQuery.trim().replace(/^WHERE\s+/i, "");
|
|
@@ -939,6 +1008,10 @@ var PgVector = class extends _mastra_core_vector.MastraVector {
|
|
|
939
1008
|
...includeVector && embedding && { vector: JSON.parse(embedding) }
|
|
940
1009
|
}));
|
|
941
1010
|
} catch (error) {
|
|
1011
|
+
if (error instanceof _mastra_core_error.MastraError) {
|
|
1012
|
+
this.logger?.trackException(error);
|
|
1013
|
+
throw error;
|
|
1014
|
+
}
|
|
942
1015
|
const mastraError = new _mastra_core_error.MastraError({
|
|
943
1016
|
id: (0, _mastra_core_storage.createVectorErrorId)("PG", "QUERY", "FAILED"),
|
|
944
1017
|
domain: _mastra_core_error.ErrorDomain.MASTRA_VECTOR,
|
|
@@ -948,12 +1021,14 @@ var PgVector = class extends _mastra_core_vector.MastraVector {
|
|
|
948
1021
|
this.logger?.trackException(mastraError);
|
|
949
1022
|
throw mastraError;
|
|
950
1023
|
} finally {
|
|
951
|
-
client
|
|
1024
|
+
client?.release();
|
|
952
1025
|
}
|
|
953
1026
|
}
|
|
954
|
-
|
|
955
|
-
const client = await this.pool.connect();
|
|
1027
|
+
let client;
|
|
956
1028
|
try {
|
|
1029
|
+
await this.ensureNamespaceReady(indexName);
|
|
1030
|
+
const indexInfo = await this.getIndexMetadata({ indexName });
|
|
1031
|
+
client = await this.pool.connect();
|
|
957
1032
|
await this.ensureSearchPath(client);
|
|
958
1033
|
await client.query("BEGIN");
|
|
959
1034
|
const { sql: filterQuery, values: filterValues } = buildFilterQuery(this.transformFilter(filter), minScore, topK);
|
|
@@ -1015,7 +1090,11 @@ var PgVector = class extends _mastra_core_vector.MastraVector {
|
|
|
1015
1090
|
...includeVector && embedding && { vector: ops.parseEmbedding(embedding) }
|
|
1016
1091
|
}));
|
|
1017
1092
|
} catch (error) {
|
|
1018
|
-
await client
|
|
1093
|
+
await client?.query("ROLLBACK");
|
|
1094
|
+
if (error instanceof _mastra_core_error.MastraError) {
|
|
1095
|
+
this.logger?.trackException(error);
|
|
1096
|
+
throw error;
|
|
1097
|
+
}
|
|
1019
1098
|
const mastraError = new _mastra_core_error.MastraError({
|
|
1020
1099
|
id: (0, _mastra_core_storage.createVectorErrorId)("PG", "QUERY", "FAILED"),
|
|
1021
1100
|
domain: _mastra_core_error.ErrorDomain.MASTRA_VECTOR,
|
|
@@ -1025,15 +1104,17 @@ var PgVector = class extends _mastra_core_vector.MastraVector {
|
|
|
1025
1104
|
this.logger?.trackException(mastraError);
|
|
1026
1105
|
throw mastraError;
|
|
1027
1106
|
} finally {
|
|
1028
|
-
client
|
|
1107
|
+
client?.release();
|
|
1029
1108
|
}
|
|
1030
1109
|
}
|
|
1031
1110
|
async upsert({ indexName, vectors, metadata, ids, deleteFilter, namespace = DEFAULT_NAMESPACE }) {
|
|
1032
1111
|
(0, _mastra_core_vector.validateUpsertInput)("PG", vectors, metadata, ids);
|
|
1033
1112
|
const { tableName } = this.getTableName(indexName);
|
|
1034
|
-
|
|
1035
|
-
const client = await this.pool.connect();
|
|
1113
|
+
let client;
|
|
1036
1114
|
try {
|
|
1115
|
+
const indexInfo = await this.getIndexMetadata({ indexName });
|
|
1116
|
+
await this.ensureNamespaceReady(indexName);
|
|
1117
|
+
client = await this.pool.connect();
|
|
1037
1118
|
await this.ensureSearchPath(client);
|
|
1038
1119
|
await client.query("BEGIN");
|
|
1039
1120
|
if (deleteFilter) {
|
|
@@ -1099,7 +1180,11 @@ var PgVector = class extends _mastra_core_vector.MastraVector {
|
|
|
1099
1180
|
});
|
|
1100
1181
|
return vectorIds;
|
|
1101
1182
|
} catch (error) {
|
|
1102
|
-
await client
|
|
1183
|
+
await client?.query("ROLLBACK");
|
|
1184
|
+
if (error instanceof _mastra_core_error.MastraError) {
|
|
1185
|
+
this.logger?.trackException(error);
|
|
1186
|
+
throw error;
|
|
1187
|
+
}
|
|
1103
1188
|
if (error instanceof Error && error.message?.includes("expected") && error.message?.includes("dimensions")) {
|
|
1104
1189
|
const match = error.message.match(/expected (\d+) dimensions, not (\d+)/);
|
|
1105
1190
|
if (match) {
|
|
@@ -1128,7 +1213,7 @@ var PgVector = class extends _mastra_core_vector.MastraVector {
|
|
|
1128
1213
|
this.logger?.trackException(mastraError);
|
|
1129
1214
|
throw mastraError;
|
|
1130
1215
|
} finally {
|
|
1131
|
-
client
|
|
1216
|
+
client?.release();
|
|
1132
1217
|
}
|
|
1133
1218
|
}
|
|
1134
1219
|
hasher = (0, xxhash_wasm.default)();
|
|
@@ -1256,9 +1341,8 @@ var PgVector = class extends _mastra_core_vector.MastraVector {
|
|
|
1256
1341
|
namespace VARCHAR(255) NOT NULL DEFAULT '${DEFAULT_NAMESPACE}'
|
|
1257
1342
|
);
|
|
1258
1343
|
`);
|
|
1259
|
-
await this.
|
|
1344
|
+
if (await this.reconcileNamespace(indexName, client)) this.namespaceReadyIndexes.add(indexName);
|
|
1260
1345
|
this.createdIndexes.set(indexName, indexCacheKey);
|
|
1261
|
-
this.namespaceReadyIndexes.add(indexName);
|
|
1262
1346
|
this.indexVectorTypes.set(indexName, vectorType);
|
|
1263
1347
|
if (buildIndex) await this.setupIndex({
|
|
1264
1348
|
indexName,
|
|
@@ -1270,6 +1354,7 @@ var PgVector = class extends _mastra_core_vector.MastraVector {
|
|
|
1270
1354
|
} catch (error) {
|
|
1271
1355
|
this.createdIndexes.delete(indexName);
|
|
1272
1356
|
this.namespaceReadyIndexes.delete(indexName);
|
|
1357
|
+
this.namespaceReadyCache.delete(indexName);
|
|
1273
1358
|
this.indexVectorTypes.delete(indexName);
|
|
1274
1359
|
throw error;
|
|
1275
1360
|
} finally {
|
|
@@ -1644,27 +1729,30 @@ var PgVector = class extends _mastra_core_vector.MastraVector {
|
|
|
1644
1729
|
}
|
|
1645
1730
|
}
|
|
1646
1731
|
async deleteIndex({ indexName }) {
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1732
|
+
await this.getMutexByName(`create-${indexName}`).runExclusive(async () => {
|
|
1733
|
+
const client = await this.pool.connect();
|
|
1734
|
+
try {
|
|
1735
|
+
const { tableName } = this.getTableName(indexName);
|
|
1736
|
+
await client.query(`DROP TABLE IF EXISTS ${tableName} CASCADE`);
|
|
1737
|
+
this.createdIndexes.delete(indexName);
|
|
1738
|
+
this.namespaceReadyIndexes.delete(indexName);
|
|
1739
|
+
this.namespaceReadyCache.delete(indexName);
|
|
1740
|
+
this.indexVectorTypes.delete(indexName);
|
|
1741
|
+
this.invalidateIndexCaches(indexName);
|
|
1742
|
+
} catch (error) {
|
|
1743
|
+
await client.query("ROLLBACK");
|
|
1744
|
+
const mastraError = new _mastra_core_error.MastraError({
|
|
1745
|
+
id: (0, _mastra_core_storage.createVectorErrorId)("PG", "DELETE_INDEX", "FAILED"),
|
|
1746
|
+
domain: _mastra_core_error.ErrorDomain.MASTRA_VECTOR,
|
|
1747
|
+
category: _mastra_core_error.ErrorCategory.THIRD_PARTY,
|
|
1748
|
+
details: { indexName }
|
|
1749
|
+
}, error);
|
|
1750
|
+
this.logger?.trackException(mastraError);
|
|
1751
|
+
throw mastraError;
|
|
1752
|
+
} finally {
|
|
1753
|
+
client.release();
|
|
1754
|
+
}
|
|
1755
|
+
});
|
|
1668
1756
|
}
|
|
1669
1757
|
async truncateIndex({ indexName }) {
|
|
1670
1758
|
const client = await this.pool.connect();
|
|
@@ -1720,6 +1808,7 @@ var PgVector = class extends _mastra_core_vector.MastraVector {
|
|
|
1720
1808
|
details: { indexName }
|
|
1721
1809
|
});
|
|
1722
1810
|
const indexInfo = await this.getIndexMetadata({ indexName });
|
|
1811
|
+
await this.ensureNamespaceReady(indexName);
|
|
1723
1812
|
client = await this.pool.connect();
|
|
1724
1813
|
await this.ensureSearchPath(client);
|
|
1725
1814
|
const { tableName } = this.getTableName(indexName);
|
|
@@ -1813,6 +1902,7 @@ var PgVector = class extends _mastra_core_vector.MastraVector {
|
|
|
1813
1902
|
async deleteVector({ indexName, id, namespace = DEFAULT_NAMESPACE }) {
|
|
1814
1903
|
let client;
|
|
1815
1904
|
try {
|
|
1905
|
+
await this.ensureNamespaceReady(indexName);
|
|
1816
1906
|
client = await this.pool.connect();
|
|
1817
1907
|
const { tableName } = this.getTableName(indexName);
|
|
1818
1908
|
const query = `
|
|
@@ -1821,6 +1911,7 @@ var PgVector = class extends _mastra_core_vector.MastraVector {
|
|
|
1821
1911
|
`;
|
|
1822
1912
|
await client.query(query, [id, namespace]);
|
|
1823
1913
|
} catch (error) {
|
|
1914
|
+
if (error instanceof _mastra_core_error.MastraError) throw error;
|
|
1824
1915
|
const mastraError = new _mastra_core_error.MastraError({
|
|
1825
1916
|
id: (0, _mastra_core_storage.createVectorErrorId)("PG", "DELETE_VECTOR", "FAILED"),
|
|
1826
1917
|
domain: _mastra_core_error.ErrorDomain.MASTRA_VECTOR,
|
|
@@ -1847,6 +1938,7 @@ var PgVector = class extends _mastra_core_vector.MastraVector {
|
|
|
1847
1938
|
let client;
|
|
1848
1939
|
const effectiveNamespace = namespace ?? DEFAULT_NAMESPACE;
|
|
1849
1940
|
try {
|
|
1941
|
+
await this.ensureNamespaceReady(indexName);
|
|
1850
1942
|
client = await this.pool.connect();
|
|
1851
1943
|
const { tableName } = this.getTableName(indexName);
|
|
1852
1944
|
if (!filter && !ids && namespace === void 0) throw new _mastra_core_error.MastraError({
|