@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.
@@ -1,23 +1,23 @@
1
1
 
2
- > @mastra/pg@0.12.0-alpha.3 build /home/runner/work/mastra/mastra/stores/pg
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
  CLI Building entry: src/index.ts
6
6
  CLI Using tsconfig: tsconfig.json
7
7
  CLI tsup v8.5.0
8
8
  TSC Build start
9
- TSC ⚡️ Build success in 10128ms
9
+ TSC ⚡️ Build success in 11911ms
10
10
  DTS Build start
11
11
  CLI Target: es2022
12
12
  Analysis will use the bundled TypeScript version 5.8.3
13
13
  Writing package typings: /home/runner/work/mastra/mastra/stores/pg/dist/_tsup-dts-rollup.d.ts
14
14
  Analysis will use the bundled TypeScript version 5.8.3
15
15
  Writing package typings: /home/runner/work/mastra/mastra/stores/pg/dist/_tsup-dts-rollup.d.cts
16
- DTS ⚡️ Build success in 11992ms
16
+ DTS ⚡️ Build success in 12897ms
17
17
  CLI Cleaning output folder
18
18
  ESM Build start
19
19
  CJS Build start
20
- CJS dist/index.cjs 87.61 KB
21
- CJS ⚡️ Build success in 1941ms
22
- ESM dist/index.js 86.23 KB
23
- ESM ⚡️ Build success in 1945ms
20
+ CJS dist/index.cjs 88.25 KB
21
+ CJS ⚡️ Build success in 1549ms
22
+ ESM dist/index.js 86.87 KB
23
+ ESM ⚡️ 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
- private pool;
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
- private db;
293
- private pgp;
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
- private pool;
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
- private db;
293
- private pgp;
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 list = new agent.MessageList().add(messages, "memory");
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 list = new agent.MessageList().add(messages, "memory");
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 list = new MessageList().add(messages, "memory");
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 list = new MessageList().add(messages, "memory");
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.0",
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.3",
36
- "@internal/lint": "0.0.14",
37
- "@mastra/core": "0.10.7",
38
- "@internal/storage-test-utils": "0.0.10"
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 {
@@ -45,8 +45,8 @@ export type PostgresConfig = {
45
45
  );
46
46
 
47
47
  export class PostgresStore extends MastraStorage {
48
- private db: pgPromise.IDatabase<{}>;
49
- private pgp: pgPromise.IMain;
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
- const list = new MessageList().add(messages, 'memory');
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
- const list = new MessageList().add(messages, 'memory');
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) {
@@ -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 });
@@ -57,7 +57,7 @@ interface PgDefineIndexParams {
57
57
  }
58
58
 
59
59
  export class PgVector extends MastraVector<PGVectorFilter> {
60
- private pool: pg.Pool;
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>();