@mastra/pg 0.12.0 → 0.12.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 +44 -2
- package/dist/_tsup-dts-rollup.d.cts +4 -3
- package/dist/_tsup-dts-rollup.d.ts +4 -3
- package/dist/index.cjs +22 -2
- package/dist/index.js +22 -2
- package/package.json +5 -5
- package/src/storage/index.test.ts +55 -0
- package/src/storage/index.ts +30 -4
- package/src/vector/index.test.ts +133 -0
- package/src/vector/index.ts +1 -1
package/.turbo/turbo-build.log
CHANGED
|
@@ -1,23 +1,23 @@
|
|
|
1
1
|
|
|
2
|
-
> @mastra/pg@0.12.
|
|
2
|
+
> @mastra/pg@0.12.1-alpha.0 build /home/runner/work/mastra/mastra/stores/pg
|
|
3
3
|
> tsup src/index.ts --format esm,cjs --experimental-dts --clean --treeshake=smallest --splitting
|
|
4
4
|
|
|
5
5
|
[34mCLI[39m Building entry: src/index.ts
|
|
6
6
|
[34mCLI[39m Using tsconfig: tsconfig.json
|
|
7
7
|
[34mCLI[39m tsup v8.5.0
|
|
8
8
|
[34mTSC[39m Build start
|
|
9
|
-
[32mTSC[39m ⚡️ Build success in
|
|
9
|
+
[32mTSC[39m ⚡️ Build success in 11911ms
|
|
10
10
|
[34mDTS[39m Build start
|
|
11
11
|
[34mCLI[39m Target: es2022
|
|
12
12
|
Analysis will use the bundled TypeScript version 5.8.3
|
|
13
13
|
[36mWriting package typings: /home/runner/work/mastra/mastra/stores/pg/dist/_tsup-dts-rollup.d.ts[39m
|
|
14
14
|
Analysis will use the bundled TypeScript version 5.8.3
|
|
15
15
|
[36mWriting package typings: /home/runner/work/mastra/mastra/stores/pg/dist/_tsup-dts-rollup.d.cts[39m
|
|
16
|
-
[32mDTS[39m ⚡️ Build success in
|
|
16
|
+
[32mDTS[39m ⚡️ Build success in 12897ms
|
|
17
17
|
[34mCLI[39m Cleaning output folder
|
|
18
18
|
[34mESM[39m Build start
|
|
19
19
|
[34mCJS[39m Build start
|
|
20
|
-
[32mCJS[39m [1mdist/index.cjs [22m[
|
|
21
|
-
[32mCJS[39m ⚡️ Build success in
|
|
22
|
-
[32mESM[39m [1mdist/index.js [22m[32m86.
|
|
23
|
-
[32mESM[39m ⚡️ Build success in
|
|
20
|
+
[32mCJS[39m [1mdist/index.cjs [22m[32m88.25 KB[39m
|
|
21
|
+
[32mCJS[39m ⚡️ Build success in 1549ms
|
|
22
|
+
[32mESM[39m [1mdist/index.js [22m[32m86.87 KB[39m
|
|
23
|
+
[32mESM[39m ⚡️ Build success in 1554ms
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,49 @@
|
|
|
1
1
|
# @mastra/pg
|
|
2
2
|
|
|
3
|
+
## 0.12.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- e0ad8e3: Exposes database connection objects as public fields in PostgresStore and PgVector classes to enable direct database operations and connection monitoring.
|
|
8
|
+
- Updated dependencies [9dda1ac]
|
|
9
|
+
- Updated dependencies [c984582]
|
|
10
|
+
- Updated dependencies [7e801dd]
|
|
11
|
+
- Updated dependencies [a606c75]
|
|
12
|
+
- Updated dependencies [7aa70a4]
|
|
13
|
+
- Updated dependencies [764f86a]
|
|
14
|
+
- Updated dependencies [1760a1c]
|
|
15
|
+
- Updated dependencies [038e5ae]
|
|
16
|
+
- Updated dependencies [7dda16a]
|
|
17
|
+
- Updated dependencies [5ebfcdd]
|
|
18
|
+
- Updated dependencies [b2d0c91]
|
|
19
|
+
- Updated dependencies [4e809ad]
|
|
20
|
+
- Updated dependencies [57929df]
|
|
21
|
+
- Updated dependencies [b7852ed]
|
|
22
|
+
- Updated dependencies [6320a61]
|
|
23
|
+
- @mastra/core@0.10.9
|
|
24
|
+
|
|
25
|
+
## 0.12.1-alpha.0
|
|
26
|
+
|
|
27
|
+
### Patch Changes
|
|
28
|
+
|
|
29
|
+
- e0ad8e3: Exposes database connection objects as public fields in PostgresStore and PgVector classes to enable direct database operations and connection monitoring.
|
|
30
|
+
- Updated dependencies [9dda1ac]
|
|
31
|
+
- Updated dependencies [c984582]
|
|
32
|
+
- Updated dependencies [7e801dd]
|
|
33
|
+
- Updated dependencies [a606c75]
|
|
34
|
+
- Updated dependencies [7aa70a4]
|
|
35
|
+
- Updated dependencies [764f86a]
|
|
36
|
+
- Updated dependencies [1760a1c]
|
|
37
|
+
- Updated dependencies [038e5ae]
|
|
38
|
+
- Updated dependencies [7dda16a]
|
|
39
|
+
- Updated dependencies [5ebfcdd]
|
|
40
|
+
- Updated dependencies [b2d0c91]
|
|
41
|
+
- Updated dependencies [4e809ad]
|
|
42
|
+
- Updated dependencies [57929df]
|
|
43
|
+
- Updated dependencies [b7852ed]
|
|
44
|
+
- Updated dependencies [6320a61]
|
|
45
|
+
- @mastra/core@0.10.9-alpha.0
|
|
46
|
+
|
|
3
47
|
## 0.12.0
|
|
4
48
|
|
|
5
49
|
### Minor Changes
|
|
@@ -1577,7 +1621,6 @@
|
|
|
1577
1621
|
### Minor Changes
|
|
1578
1622
|
|
|
1579
1623
|
- c87eb4e: Combine PostgreSQL packages into `@mastra/pg`.
|
|
1580
|
-
|
|
1581
1624
|
- Move and combine packages to `stores/pg`
|
|
1582
1625
|
- Reorganize source files into `src/vector` and `src/store`
|
|
1583
1626
|
- Add deprecation notices to old packages
|
|
@@ -1911,7 +1954,6 @@
|
|
|
1911
1954
|
### Minor Changes
|
|
1912
1955
|
|
|
1913
1956
|
- c87eb4e: Combine PostgreSQL packages into `@mastra/pg`.
|
|
1914
|
-
|
|
1915
1957
|
- Move and combine packages to `stores/pg`
|
|
1916
1958
|
- Reorganize source files into `src/vector` and `src/store`
|
|
1917
1959
|
- Add deprecation notices to old packages
|
|
@@ -18,6 +18,7 @@ import type { OperatorValueMap } from '@mastra/core/vector/filter';
|
|
|
18
18
|
import type { PaginationArgs } from '@mastra/core/storage';
|
|
19
19
|
import type { PaginationInfo } from '@mastra/core/storage';
|
|
20
20
|
import pg from 'pg';
|
|
21
|
+
import pgPromise from 'pg-promise';
|
|
21
22
|
import type { QueryResult } from '@mastra/core/vector';
|
|
22
23
|
import type { QueryVectorParams } from '@mastra/core/vector';
|
|
23
24
|
import type { StorageColumn } from '@mastra/core/storage';
|
|
@@ -200,7 +201,7 @@ declare interface PgQueryVectorParams extends QueryVectorParams<PGVectorFilter>
|
|
|
200
201
|
}
|
|
201
202
|
|
|
202
203
|
declare class PgVector extends MastraVector<PGVectorFilter> {
|
|
203
|
-
|
|
204
|
+
pool: pg.Pool;
|
|
204
205
|
private describeIndexCache;
|
|
205
206
|
private createdIndexes;
|
|
206
207
|
private mutexesByName;
|
|
@@ -289,8 +290,8 @@ export { PostgresConfig }
|
|
|
289
290
|
export { PostgresConfig as PostgresConfig_alias_1 }
|
|
290
291
|
|
|
291
292
|
declare class PostgresStore extends MastraStorage {
|
|
292
|
-
|
|
293
|
-
|
|
293
|
+
db: pgPromise.IDatabase<{}>;
|
|
294
|
+
pgp: pgPromise.IMain;
|
|
294
295
|
private schema?;
|
|
295
296
|
private setupSchemaPromise;
|
|
296
297
|
private schemaSetupComplete;
|
|
@@ -18,6 +18,7 @@ import type { OperatorValueMap } from '@mastra/core/vector/filter';
|
|
|
18
18
|
import type { PaginationArgs } from '@mastra/core/storage';
|
|
19
19
|
import type { PaginationInfo } from '@mastra/core/storage';
|
|
20
20
|
import pg from 'pg';
|
|
21
|
+
import pgPromise from 'pg-promise';
|
|
21
22
|
import type { QueryResult } from '@mastra/core/vector';
|
|
22
23
|
import type { QueryVectorParams } from '@mastra/core/vector';
|
|
23
24
|
import type { StorageColumn } from '@mastra/core/storage';
|
|
@@ -200,7 +201,7 @@ declare interface PgQueryVectorParams extends QueryVectorParams<PGVectorFilter>
|
|
|
200
201
|
}
|
|
201
202
|
|
|
202
203
|
declare class PgVector extends MastraVector<PGVectorFilter> {
|
|
203
|
-
|
|
204
|
+
pool: pg.Pool;
|
|
204
205
|
private describeIndexCache;
|
|
205
206
|
private createdIndexes;
|
|
206
207
|
private mutexesByName;
|
|
@@ -289,8 +290,8 @@ export { PostgresConfig }
|
|
|
289
290
|
export { PostgresConfig as PostgresConfig_alias_1 }
|
|
290
291
|
|
|
291
292
|
declare class PostgresStore extends MastraStorage {
|
|
292
|
-
|
|
293
|
-
|
|
293
|
+
db: pgPromise.IDatabase<{}>;
|
|
294
|
+
pgp: pgPromise.IMain;
|
|
294
295
|
private schema?;
|
|
295
296
|
private setupSchemaPromise;
|
|
296
297
|
private schemaSetupComplete;
|
package/dist/index.cjs
CHANGED
|
@@ -1954,7 +1954,17 @@ var PostgresStore = class extends storage.MastraStorage {
|
|
|
1954
1954
|
)} ${whereClause} ${excludeIds.length ? `AND id NOT IN (${excludeIdsParam})` : ""}${orderByStatement} LIMIT $${paramIndex++} OFFSET $${paramIndex++}`;
|
|
1955
1955
|
const rows = await this.db.manyOrNone(dataQuery, [...queryParams, ...excludeIds, perPage, currentOffset]);
|
|
1956
1956
|
messages.push(...rows || []);
|
|
1957
|
-
const
|
|
1957
|
+
const messagesWithParsedContent = messages.map((message) => {
|
|
1958
|
+
if (typeof message.content === "string") {
|
|
1959
|
+
try {
|
|
1960
|
+
return { ...message, content: JSON.parse(message.content) };
|
|
1961
|
+
} catch {
|
|
1962
|
+
return message;
|
|
1963
|
+
}
|
|
1964
|
+
}
|
|
1965
|
+
return message;
|
|
1966
|
+
});
|
|
1967
|
+
const list = new agent.MessageList().add(messagesWithParsedContent, "memory");
|
|
1958
1968
|
const messagesToReturn = format === `v2` ? list.get.all.v2() : list.get.all.v1();
|
|
1959
1969
|
return {
|
|
1960
1970
|
messages: messagesToReturn,
|
|
@@ -2048,7 +2058,17 @@ var PostgresStore = class extends storage.MastraStorage {
|
|
|
2048
2058
|
);
|
|
2049
2059
|
await Promise.all([...messageInserts, threadUpdate]);
|
|
2050
2060
|
});
|
|
2051
|
-
const
|
|
2061
|
+
const messagesWithParsedContent = messages.map((message) => {
|
|
2062
|
+
if (typeof message.content === "string") {
|
|
2063
|
+
try {
|
|
2064
|
+
return { ...message, content: JSON.parse(message.content) };
|
|
2065
|
+
} catch {
|
|
2066
|
+
return message;
|
|
2067
|
+
}
|
|
2068
|
+
}
|
|
2069
|
+
return message;
|
|
2070
|
+
});
|
|
2071
|
+
const list = new agent.MessageList().add(messagesWithParsedContent, "memory");
|
|
2052
2072
|
if (format === `v2`) return list.get.all.v2();
|
|
2053
2073
|
return list.get.all.v1();
|
|
2054
2074
|
} catch (error$1) {
|
package/dist/index.js
CHANGED
|
@@ -1946,7 +1946,17 @@ var PostgresStore = class extends MastraStorage {
|
|
|
1946
1946
|
)} ${whereClause} ${excludeIds.length ? `AND id NOT IN (${excludeIdsParam})` : ""}${orderByStatement} LIMIT $${paramIndex++} OFFSET $${paramIndex++}`;
|
|
1947
1947
|
const rows = await this.db.manyOrNone(dataQuery, [...queryParams, ...excludeIds, perPage, currentOffset]);
|
|
1948
1948
|
messages.push(...rows || []);
|
|
1949
|
-
const
|
|
1949
|
+
const messagesWithParsedContent = messages.map((message) => {
|
|
1950
|
+
if (typeof message.content === "string") {
|
|
1951
|
+
try {
|
|
1952
|
+
return { ...message, content: JSON.parse(message.content) };
|
|
1953
|
+
} catch {
|
|
1954
|
+
return message;
|
|
1955
|
+
}
|
|
1956
|
+
}
|
|
1957
|
+
return message;
|
|
1958
|
+
});
|
|
1959
|
+
const list = new MessageList().add(messagesWithParsedContent, "memory");
|
|
1950
1960
|
const messagesToReturn = format === `v2` ? list.get.all.v2() : list.get.all.v1();
|
|
1951
1961
|
return {
|
|
1952
1962
|
messages: messagesToReturn,
|
|
@@ -2040,7 +2050,17 @@ var PostgresStore = class extends MastraStorage {
|
|
|
2040
2050
|
);
|
|
2041
2051
|
await Promise.all([...messageInserts, threadUpdate]);
|
|
2042
2052
|
});
|
|
2043
|
-
const
|
|
2053
|
+
const messagesWithParsedContent = messages.map((message) => {
|
|
2054
|
+
if (typeof message.content === "string") {
|
|
2055
|
+
try {
|
|
2056
|
+
return { ...message, content: JSON.parse(message.content) };
|
|
2057
|
+
} catch {
|
|
2058
|
+
return message;
|
|
2059
|
+
}
|
|
2060
|
+
}
|
|
2061
|
+
return message;
|
|
2062
|
+
});
|
|
2063
|
+
const list = new MessageList().add(messagesWithParsedContent, "memory");
|
|
2044
2064
|
if (format === `v2`) return list.get.all.v2();
|
|
2045
2065
|
return list.get.all.v1();
|
|
2046
2066
|
} catch (error) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mastra/pg",
|
|
3
|
-
"version": "0.12.
|
|
3
|
+
"version": "0.12.1",
|
|
4
4
|
"description": "Postgres provider for Mastra - includes both vector and db storage capabilities",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -32,10 +32,10 @@
|
|
|
32
32
|
"eslint": "^9.29.0",
|
|
33
33
|
"tsup": "^8.5.0",
|
|
34
34
|
"typescript": "^5.8.3",
|
|
35
|
-
"vitest": "^3.2.
|
|
36
|
-
"@internal/lint": "0.0.
|
|
37
|
-
"@
|
|
38
|
-
"@
|
|
35
|
+
"vitest": "^3.2.4",
|
|
36
|
+
"@internal/lint": "0.0.16",
|
|
37
|
+
"@internal/storage-test-utils": "0.0.12",
|
|
38
|
+
"@mastra/core": "0.10.9"
|
|
39
39
|
},
|
|
40
40
|
"peerDependencies": {
|
|
41
41
|
"@mastra/core": ">=0.10.7-0 <0.11.0-0"
|
|
@@ -46,6 +46,61 @@ describe('PostgresStore', () => {
|
|
|
46
46
|
await store.init();
|
|
47
47
|
});
|
|
48
48
|
|
|
49
|
+
describe('Public Fields Access', () => {
|
|
50
|
+
let testDB: PostgresStore;
|
|
51
|
+
beforeAll(async () => {
|
|
52
|
+
testDB = new PostgresStore(TEST_CONFIG);
|
|
53
|
+
});
|
|
54
|
+
afterAll(async () => {
|
|
55
|
+
try {
|
|
56
|
+
await testDB.close();
|
|
57
|
+
} catch {}
|
|
58
|
+
store = new PostgresStore(TEST_CONFIG);
|
|
59
|
+
await store.init();
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it('should expose db field as public', () => {
|
|
63
|
+
expect(testDB.db).toBeDefined();
|
|
64
|
+
expect(typeof testDB.db).toBe('object');
|
|
65
|
+
expect(testDB.db.query).toBeDefined();
|
|
66
|
+
expect(typeof testDB.db.query).toBe('function');
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
it('should expose pgp field as public', () => {
|
|
70
|
+
expect(testDB.pgp).toBeDefined();
|
|
71
|
+
expect(typeof testDB.pgp).toBe('function');
|
|
72
|
+
expect(testDB.pgp.end).toBeDefined();
|
|
73
|
+
expect(typeof testDB.pgp.end).toBe('function');
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it('should allow direct database queries via public db field', async () => {
|
|
77
|
+
const result = await testDB.db.one('SELECT 1 as test');
|
|
78
|
+
expect(result.test).toBe(1);
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
it('should allow access to pgp utilities via public pgp field', () => {
|
|
82
|
+
const helpers = testDB.pgp.helpers;
|
|
83
|
+
expect(helpers).toBeDefined();
|
|
84
|
+
expect(helpers.insert).toBeDefined();
|
|
85
|
+
expect(helpers.update).toBeDefined();
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
it('should maintain connection state through public db field', async () => {
|
|
89
|
+
// Test multiple queries to ensure connection state
|
|
90
|
+
const result1 = await testDB.db.one('SELECT NOW() as timestamp1');
|
|
91
|
+
const result2 = await testDB.db.one('SELECT NOW() as timestamp2');
|
|
92
|
+
|
|
93
|
+
expect(result1.timestamp1).toBeDefined();
|
|
94
|
+
expect(result2.timestamp2).toBeDefined();
|
|
95
|
+
expect(new Date(result2.timestamp2).getTime()).toBeGreaterThanOrEqual(new Date(result1.timestamp1).getTime());
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
it('should throw error when pool is used after disconnect', async () => {
|
|
99
|
+
await testDB.close();
|
|
100
|
+
expect(testDB.db.connect()).rejects.toThrow();
|
|
101
|
+
});
|
|
102
|
+
});
|
|
103
|
+
|
|
49
104
|
beforeEach(async () => {
|
|
50
105
|
// Only clear tables if store is initialized
|
|
51
106
|
try {
|
package/src/storage/index.ts
CHANGED
|
@@ -45,8 +45,8 @@ export type PostgresConfig = {
|
|
|
45
45
|
);
|
|
46
46
|
|
|
47
47
|
export class PostgresStore extends MastraStorage {
|
|
48
|
-
|
|
49
|
-
|
|
48
|
+
public db: pgPromise.IDatabase<{}>;
|
|
49
|
+
public pgp: pgPromise.IMain;
|
|
50
50
|
private schema?: string;
|
|
51
51
|
private setupSchemaPromise: Promise<void> | null = null;
|
|
52
52
|
private schemaSetupComplete: boolean | undefined = undefined;
|
|
@@ -1072,7 +1072,20 @@ export class PostgresStore extends MastraStorage {
|
|
|
1072
1072
|
const rows = await this.db.manyOrNone(dataQuery, [...queryParams, ...excludeIds, perPage, currentOffset]);
|
|
1073
1073
|
messages.push(...(rows || []));
|
|
1074
1074
|
|
|
1075
|
-
|
|
1075
|
+
// Parse content back to objects if they were stringified during storage
|
|
1076
|
+
const messagesWithParsedContent = messages.map(message => {
|
|
1077
|
+
if (typeof message.content === 'string') {
|
|
1078
|
+
try {
|
|
1079
|
+
return { ...message, content: JSON.parse(message.content) };
|
|
1080
|
+
} catch {
|
|
1081
|
+
// If parsing fails, leave as string (V1 message)
|
|
1082
|
+
return message;
|
|
1083
|
+
}
|
|
1084
|
+
}
|
|
1085
|
+
return message;
|
|
1086
|
+
});
|
|
1087
|
+
|
|
1088
|
+
const list = new MessageList().add(messagesWithParsedContent, 'memory');
|
|
1076
1089
|
const messagesToReturn = format === `v2` ? list.get.all.v2() : list.get.all.v1();
|
|
1077
1090
|
|
|
1078
1091
|
return {
|
|
@@ -1180,7 +1193,20 @@ export class PostgresStore extends MastraStorage {
|
|
|
1180
1193
|
await Promise.all([...messageInserts, threadUpdate]);
|
|
1181
1194
|
});
|
|
1182
1195
|
|
|
1183
|
-
|
|
1196
|
+
// Parse content back to objects if they were stringified during storage
|
|
1197
|
+
const messagesWithParsedContent = messages.map(message => {
|
|
1198
|
+
if (typeof message.content === 'string') {
|
|
1199
|
+
try {
|
|
1200
|
+
return { ...message, content: JSON.parse(message.content) };
|
|
1201
|
+
} catch {
|
|
1202
|
+
// If parsing fails, leave as string (V1 message)
|
|
1203
|
+
return message;
|
|
1204
|
+
}
|
|
1205
|
+
}
|
|
1206
|
+
return message;
|
|
1207
|
+
});
|
|
1208
|
+
|
|
1209
|
+
const list = new MessageList().add(messagesWithParsedContent, 'memory');
|
|
1184
1210
|
if (format === `v2`) return list.get.all.v2();
|
|
1185
1211
|
return list.get.all.v1();
|
|
1186
1212
|
} catch (error) {
|
package/src/vector/index.test.ts
CHANGED
|
@@ -15,6 +15,139 @@ describe('PgVector', () => {
|
|
|
15
15
|
vectorDB = new PgVector({ connectionString });
|
|
16
16
|
});
|
|
17
17
|
|
|
18
|
+
describe('Public Fields Access', () => {
|
|
19
|
+
let testDB: PgVector;
|
|
20
|
+
beforeAll(async () => {
|
|
21
|
+
testDB = new PgVector({ connectionString });
|
|
22
|
+
});
|
|
23
|
+
afterAll(async () => {
|
|
24
|
+
try {
|
|
25
|
+
await testDB.disconnect();
|
|
26
|
+
} catch {}
|
|
27
|
+
});
|
|
28
|
+
it('should expose pool field as public', () => {
|
|
29
|
+
expect(testDB.pool).toBeDefined();
|
|
30
|
+
expect(typeof testDB.pool).toBe('object');
|
|
31
|
+
expect(testDB.pool.connect).toBeDefined();
|
|
32
|
+
expect(typeof testDB.pool.connect).toBe('function');
|
|
33
|
+
expect(testDB.pool).toBeInstanceOf(pg.Pool);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it('pool provides a working client connection', async () => {
|
|
37
|
+
const pool = testDB.pool;
|
|
38
|
+
const client = await pool.connect();
|
|
39
|
+
expect(typeof client.query).toBe('function');
|
|
40
|
+
expect(typeof client.release).toBe('function');
|
|
41
|
+
client.release();
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it('should allow direct database connections via public pool field', async () => {
|
|
45
|
+
const client = await testDB.pool.connect();
|
|
46
|
+
try {
|
|
47
|
+
const result = await client.query('SELECT 1 as test');
|
|
48
|
+
expect(result.rows[0].test).toBe(1);
|
|
49
|
+
} finally {
|
|
50
|
+
client.release();
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it('should provide access to pool configuration via public pool field', () => {
|
|
55
|
+
expect(testDB.pool.options).toBeDefined();
|
|
56
|
+
expect(testDB.pool.options.connectionString).toBe(connectionString);
|
|
57
|
+
expect(testDB.pool.options.max).toBeDefined();
|
|
58
|
+
expect(testDB.pool.options.idleTimeoutMillis).toBeDefined();
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it('should allow pool monitoring via public pool field', () => {
|
|
62
|
+
expect(testDB.pool.totalCount).toBeDefined();
|
|
63
|
+
expect(testDB.pool.idleCount).toBeDefined();
|
|
64
|
+
expect(testDB.pool.waitingCount).toBeDefined();
|
|
65
|
+
expect(typeof testDB.pool.totalCount).toBe('number');
|
|
66
|
+
expect(typeof testDB.pool.idleCount).toBe('number');
|
|
67
|
+
expect(typeof testDB.pool.waitingCount).toBe('number');
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it('should allow executing raw SQL via public pool field', async () => {
|
|
71
|
+
const client = await testDB.pool.connect();
|
|
72
|
+
try {
|
|
73
|
+
// Test a simple vector-related query
|
|
74
|
+
const result = await client.query('SELECT version()');
|
|
75
|
+
expect(result.rows[0].version).toBeDefined();
|
|
76
|
+
expect(typeof result.rows[0].version).toBe('string');
|
|
77
|
+
} finally {
|
|
78
|
+
client.release();
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
it('should maintain proper connection lifecycle via public pool field', async () => {
|
|
83
|
+
const initialIdleCount = testDB.pool.idleCount;
|
|
84
|
+
const initialTotalCount = testDB.pool.totalCount;
|
|
85
|
+
|
|
86
|
+
const client = await testDB.pool.connect();
|
|
87
|
+
|
|
88
|
+
// After connecting, total count should be >= initial, idle count should be less
|
|
89
|
+
expect(testDB.pool.totalCount).toBeGreaterThanOrEqual(initialTotalCount);
|
|
90
|
+
expect(testDB.pool.idleCount).toBeLessThanOrEqual(initialIdleCount);
|
|
91
|
+
|
|
92
|
+
client.release();
|
|
93
|
+
|
|
94
|
+
// After releasing, idle count should return to at least initial value
|
|
95
|
+
expect(testDB.pool.idleCount).toBeGreaterThanOrEqual(initialIdleCount);
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
it('allows performing a transaction', async () => {
|
|
99
|
+
const client = await testDB.pool.connect();
|
|
100
|
+
try {
|
|
101
|
+
await client.query('BEGIN');
|
|
102
|
+
const { rows } = await client.query('SELECT 2 as value');
|
|
103
|
+
expect(rows[0].value).toBe(2);
|
|
104
|
+
await client.query('COMMIT');
|
|
105
|
+
} finally {
|
|
106
|
+
client.release();
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
it('releases client on query error', async () => {
|
|
110
|
+
const client = await testDB.pool.connect();
|
|
111
|
+
try {
|
|
112
|
+
await expect(client.query('SELECT * FROM not_a_real_table')).rejects.toThrow();
|
|
113
|
+
} finally {
|
|
114
|
+
client.release();
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
it('can use getPool() to query metadata for filter options (user scenario)', async () => {
|
|
119
|
+
// Insert vectors with metadata
|
|
120
|
+
await testDB.createIndex({ indexName: 'filter_test', dimension: 2 });
|
|
121
|
+
await testDB.upsert({
|
|
122
|
+
indexName: 'filter_test',
|
|
123
|
+
vectors: [
|
|
124
|
+
[0.1, 0.2],
|
|
125
|
+
[0.3, 0.4],
|
|
126
|
+
[0.5, 0.6],
|
|
127
|
+
],
|
|
128
|
+
metadata: [
|
|
129
|
+
{ category: 'A', color: 'red' },
|
|
130
|
+
{ category: 'B', color: 'blue' },
|
|
131
|
+
{ category: 'A', color: 'green' },
|
|
132
|
+
],
|
|
133
|
+
ids: ['id1', 'id2', 'id3'],
|
|
134
|
+
});
|
|
135
|
+
// Use the pool to query unique categories
|
|
136
|
+
const { tableName } = testDB['getTableName']('filter_test');
|
|
137
|
+
const res = await testDB.pool.query(
|
|
138
|
+
`SELECT DISTINCT metadata->>'category' AS category FROM ${tableName} ORDER BY category`,
|
|
139
|
+
);
|
|
140
|
+
expect(res.rows.map(r => r.category).sort()).toEqual(['A', 'B']);
|
|
141
|
+
// Clean up
|
|
142
|
+
await testDB.deleteIndex({ indexName: 'filter_test' });
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
it('should throw error when pool is used after disconnect', async () => {
|
|
146
|
+
await testDB.disconnect();
|
|
147
|
+
expect(testDB.pool.connect()).rejects.toThrow();
|
|
148
|
+
});
|
|
149
|
+
});
|
|
150
|
+
|
|
18
151
|
afterAll(async () => {
|
|
19
152
|
// Clean up test tables
|
|
20
153
|
await vectorDB.deleteIndex({ indexName: testIndexName });
|
package/src/vector/index.ts
CHANGED
|
@@ -57,7 +57,7 @@ interface PgDefineIndexParams {
|
|
|
57
57
|
}
|
|
58
58
|
|
|
59
59
|
export class PgVector extends MastraVector<PGVectorFilter> {
|
|
60
|
-
|
|
60
|
+
public pool: pg.Pool;
|
|
61
61
|
private describeIndexCache: Map<string, PGIndexStats> = new Map();
|
|
62
62
|
private createdIndexes = new Map<string, number>();
|
|
63
63
|
private mutexesByName = new Map<string, Mutex>();
|