@mastra/pg 0.12.4 → 0.12.6-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.
@@ -1,23 +1,23 @@
1
1
 
2
- > @mastra/pg@0.12.4-alpha.0 build /home/runner/work/mastra/mastra/stores/pg
2
+ > @mastra/pg@0.12.6-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 16748ms
9
+ TSC ⚡️ Build success in 17910ms
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 14394ms
16
+ DTS ⚡️ Build success in 13382ms
17
17
  CLI Cleaning output folder
18
18
  ESM Build start
19
19
  CJS Build start
20
- ESM dist/index.js 102.98 KB
21
- ESM ⚡️ Build success in 2355ms
22
- CJS dist/index.cjs 104.50 KB
23
- CJS ⚡️ Build success in 2355ms
20
+ ESM dist/index.js 104.78 KB
21
+ ESM ⚡️ Build success in 2545ms
22
+ CJS dist/index.cjs 106.34 KB
23
+ CJS ⚡️ Build success in 2546ms
package/CHANGELOG.md CHANGED
@@ -1,5 +1,40 @@
1
1
  # @mastra/pg
2
2
 
3
+ ## 0.12.6-alpha.0
4
+
5
+ ### Patch Changes
6
+
7
+ - ff9c125: enhance thread retrieval with sorting options in libsql and pg
8
+ - b8efbb9: feat: add flexible deleteMessages method to memory API
9
+ - Added `memory.deleteMessages(input)` method that accepts multiple input types:
10
+ - Single message ID as string: `deleteMessages('msg-123')`
11
+ - Array of message IDs: `deleteMessages(['msg-1', 'msg-2'])`
12
+ - Message object with id property: `deleteMessages({ id: 'msg-123' })`
13
+ - Array of message objects: `deleteMessages([{ id: 'msg-1' }, { id: 'msg-2' }])`
14
+ - Implemented in all storage adapters (LibSQL, PostgreSQL, Upstash, InMemory)
15
+ - Added REST API endpoint: `POST /api/memory/messages/delete`
16
+ - Updated client SDK: `thread.deleteMessages()` accepts all input types
17
+ - Updates thread timestamps when messages are deleted
18
+ - Added comprehensive test coverage and documentation
19
+
20
+ - Updated dependencies [27cc97a]
21
+ - Updated dependencies [41daa63]
22
+ - Updated dependencies [254a36b]
23
+ - Updated dependencies [0b89602]
24
+ - Updated dependencies [4d37822]
25
+ - Updated dependencies [ff9c125]
26
+ - Updated dependencies [b8efbb9]
27
+ - Updated dependencies [71466e7]
28
+ - Updated dependencies [0c99fbe]
29
+ - @mastra/core@0.12.0-alpha.2
30
+
31
+ ## 0.12.5
32
+
33
+ ### Patch Changes
34
+
35
+ - ce088f5: Update all peerdeps to latest core
36
+ - @mastra/core@0.11.1
37
+
3
38
  ## 0.12.4
4
39
 
5
40
  ### Patch Changes
@@ -39,6 +39,7 @@ import type { StorageResourceType } from '@mastra/core/storage';
39
39
  import type { StorageThreadType } from '@mastra/core/memory';
40
40
  import { StoreOperations } from '@mastra/core/storage';
41
41
  import type { TABLE_NAMES } from '@mastra/core/storage';
42
+ import type { ThreadSortOptions } from '@mastra/core/storage';
42
43
  import type { Trace } from '@mastra/core/telemetry';
43
44
  import { TracesStorage } from '@mastra/core/storage';
44
45
  import type { UpdateVectorParams } from '@mastra/core/vector';
@@ -194,12 +195,12 @@ export declare class MemoryPG extends MemoryStorage {
194
195
  */
195
196
  getThreadsByResourceId(args: {
196
197
  resourceId: string;
197
- }): Promise<StorageThreadType[]>;
198
+ } & ThreadSortOptions): Promise<StorageThreadType[]>;
198
199
  getThreadsByResourceIdPaginated(args: {
199
200
  resourceId: string;
200
201
  page: number;
201
202
  perPage: number;
202
- }): Promise<PaginationInfo & {
203
+ } & ThreadSortOptions): Promise<PaginationInfo & {
203
204
  threads: StorageThreadType[];
204
205
  }>;
205
206
  saveThread({ thread }: {
@@ -245,6 +246,7 @@ export declare class MemoryPG extends MemoryStorage {
245
246
  };
246
247
  })[];
247
248
  }): Promise<MastraMessageV2_2[]>;
249
+ deleteMessages(messageIds: string[]): Promise<void>;
248
250
  getResourceById({ resourceId }: {
249
251
  resourceId: string;
250
252
  }): Promise<StorageResourceType | null>;
@@ -429,6 +431,7 @@ declare class PostgresStore extends MastraStorage {
429
431
  resourceWorkingMemory: boolean;
430
432
  hasColumn: boolean;
431
433
  createTable: boolean;
434
+ deleteMessages: boolean;
432
435
  };
433
436
  /** @deprecated use getEvals instead */
434
437
  getEvalsByAgentName(agentName: string, type?: 'test' | 'live'): Promise<EvalRow[]>;
@@ -486,12 +489,12 @@ declare class PostgresStore extends MastraStorage {
486
489
  */
487
490
  getThreadsByResourceId(args: {
488
491
  resourceId: string;
489
- }): Promise<StorageThreadType[]>;
492
+ } & ThreadSortOptions): Promise<StorageThreadType[]>;
490
493
  getThreadsByResourceIdPaginated(args: {
491
494
  resourceId: string;
492
495
  page: number;
493
496
  perPage: number;
494
- }): Promise<PaginationInfo & {
497
+ } & ThreadSortOptions): Promise<PaginationInfo & {
495
498
  threads: StorageThreadType[];
496
499
  }>;
497
500
  saveThread({ thread }: {
@@ -536,6 +539,7 @@ declare class PostgresStore extends MastraStorage {
536
539
  };
537
540
  })[];
538
541
  }): Promise<MastraMessageV2[]>;
542
+ deleteMessages(messageIds: string[]): Promise<void>;
539
543
  getResourceById({ resourceId }: {
540
544
  resourceId: string;
541
545
  }): Promise<StorageResourceType | null>;
@@ -39,6 +39,7 @@ import type { StorageResourceType } from '@mastra/core/storage';
39
39
  import type { StorageThreadType } from '@mastra/core/memory';
40
40
  import { StoreOperations } from '@mastra/core/storage';
41
41
  import type { TABLE_NAMES } from '@mastra/core/storage';
42
+ import type { ThreadSortOptions } from '@mastra/core/storage';
42
43
  import type { Trace } from '@mastra/core/telemetry';
43
44
  import { TracesStorage } from '@mastra/core/storage';
44
45
  import type { UpdateVectorParams } from '@mastra/core/vector';
@@ -194,12 +195,12 @@ export declare class MemoryPG extends MemoryStorage {
194
195
  */
195
196
  getThreadsByResourceId(args: {
196
197
  resourceId: string;
197
- }): Promise<StorageThreadType[]>;
198
+ } & ThreadSortOptions): Promise<StorageThreadType[]>;
198
199
  getThreadsByResourceIdPaginated(args: {
199
200
  resourceId: string;
200
201
  page: number;
201
202
  perPage: number;
202
- }): Promise<PaginationInfo & {
203
+ } & ThreadSortOptions): Promise<PaginationInfo & {
203
204
  threads: StorageThreadType[];
204
205
  }>;
205
206
  saveThread({ thread }: {
@@ -245,6 +246,7 @@ export declare class MemoryPG extends MemoryStorage {
245
246
  };
246
247
  })[];
247
248
  }): Promise<MastraMessageV2_2[]>;
249
+ deleteMessages(messageIds: string[]): Promise<void>;
248
250
  getResourceById({ resourceId }: {
249
251
  resourceId: string;
250
252
  }): Promise<StorageResourceType | null>;
@@ -429,6 +431,7 @@ declare class PostgresStore extends MastraStorage {
429
431
  resourceWorkingMemory: boolean;
430
432
  hasColumn: boolean;
431
433
  createTable: boolean;
434
+ deleteMessages: boolean;
432
435
  };
433
436
  /** @deprecated use getEvals instead */
434
437
  getEvalsByAgentName(agentName: string, type?: 'test' | 'live'): Promise<EvalRow[]>;
@@ -486,12 +489,12 @@ declare class PostgresStore extends MastraStorage {
486
489
  */
487
490
  getThreadsByResourceId(args: {
488
491
  resourceId: string;
489
- }): Promise<StorageThreadType[]>;
492
+ } & ThreadSortOptions): Promise<StorageThreadType[]>;
490
493
  getThreadsByResourceIdPaginated(args: {
491
494
  resourceId: string;
492
495
  page: number;
493
496
  perPage: number;
494
- }): Promise<PaginationInfo & {
497
+ } & ThreadSortOptions): Promise<PaginationInfo & {
495
498
  threads: StorageThreadType[];
496
499
  }>;
497
500
  saveThread({ thread }: {
@@ -536,6 +539,7 @@ declare class PostgresStore extends MastraStorage {
536
539
  };
537
540
  })[];
538
541
  }): Promise<MastraMessageV2[]>;
542
+ deleteMessages(messageIds: string[]): Promise<void>;
539
543
  getResourceById({ resourceId }: {
540
544
  resourceId: string;
541
545
  }): Promise<StorageResourceType | null>;
package/dist/index.cjs CHANGED
@@ -1284,12 +1284,14 @@ var MemoryPG = class extends storage.MemoryStorage {
1284
1284
  * @deprecated use getThreadsByResourceIdPaginated instead
1285
1285
  */
1286
1286
  async getThreadsByResourceId(args) {
1287
- const { resourceId } = args;
1287
+ const resourceId = args.resourceId;
1288
+ const orderBy = this.castThreadOrderBy(args.orderBy);
1289
+ const sortDirection = this.castThreadSortDirection(args.sortDirection);
1288
1290
  try {
1289
1291
  const tableName = getTableName({ indexName: storage.TABLE_THREADS, schemaName: getSchemaName(this.schema) });
1290
1292
  const baseQuery = `FROM ${tableName} WHERE "resourceId" = $1`;
1291
1293
  const queryParams = [resourceId];
1292
- const dataQuery = `SELECT id, "resourceId", title, metadata, "createdAt", "updatedAt" ${baseQuery} ORDER BY "createdAt" DESC`;
1294
+ const dataQuery = `SELECT id, "resourceId", title, metadata, "createdAt", "updatedAt" ${baseQuery} ORDER BY "${orderBy}" ${sortDirection}`;
1293
1295
  const rows = await this.client.manyOrNone(dataQuery, queryParams);
1294
1296
  return (rows || []).map((thread) => ({
1295
1297
  ...thread,
@@ -1304,6 +1306,8 @@ var MemoryPG = class extends storage.MemoryStorage {
1304
1306
  }
1305
1307
  async getThreadsByResourceIdPaginated(args) {
1306
1308
  const { resourceId, page = 0, perPage: perPageInput } = args;
1309
+ const orderBy = this.castThreadOrderBy(args.orderBy);
1310
+ const sortDirection = this.castThreadSortDirection(args.sortDirection);
1307
1311
  try {
1308
1312
  const tableName = getTableName({ indexName: storage.TABLE_THREADS, schemaName: getSchemaName(this.schema) });
1309
1313
  const baseQuery = `FROM ${tableName} WHERE "resourceId" = $1`;
@@ -1322,7 +1326,7 @@ var MemoryPG = class extends storage.MemoryStorage {
1322
1326
  hasMore: false
1323
1327
  };
1324
1328
  }
1325
- const dataQuery = `SELECT id, "resourceId", title, metadata, "createdAt", "updatedAt" ${baseQuery} ORDER BY "createdAt" DESC LIMIT $2 OFFSET $3`;
1329
+ const dataQuery = `SELECT id, "resourceId", title, metadata, "createdAt", "updatedAt" ${baseQuery} ORDER BY "${orderBy}" ${sortDirection} LIMIT $2 OFFSET $3`;
1326
1330
  const rows = await this.client.manyOrNone(dataQuery, [...queryParams, perPage, currentOffset]);
1327
1331
  const threads = (rows || []).map((thread) => ({
1328
1332
  ...thread,
@@ -1882,6 +1886,40 @@ var MemoryPG = class extends storage.MemoryStorage {
1882
1886
  return message;
1883
1887
  });
1884
1888
  }
1889
+ async deleteMessages(messageIds) {
1890
+ if (!messageIds || messageIds.length === 0) {
1891
+ return;
1892
+ }
1893
+ try {
1894
+ const messageTableName = getTableName({ indexName: storage.TABLE_MESSAGES, schemaName: getSchemaName(this.schema) });
1895
+ const threadTableName = getTableName({ indexName: storage.TABLE_THREADS, schemaName: getSchemaName(this.schema) });
1896
+ await this.client.tx(async (t) => {
1897
+ const placeholders = messageIds.map((_, idx) => `$${idx + 1}`).join(",");
1898
+ const messages = await t.manyOrNone(
1899
+ `SELECT DISTINCT thread_id FROM ${messageTableName} WHERE id IN (${placeholders})`,
1900
+ messageIds
1901
+ );
1902
+ const threadIds = messages?.map((msg) => msg.thread_id).filter(Boolean) || [];
1903
+ await t.none(`DELETE FROM ${messageTableName} WHERE id IN (${placeholders})`, messageIds);
1904
+ if (threadIds.length > 0) {
1905
+ const updatePromises = threadIds.map(
1906
+ (threadId) => t.none(`UPDATE ${threadTableName} SET "updatedAt" = NOW(), "updatedAtZ" = NOW() WHERE id = $1`, [threadId])
1907
+ );
1908
+ await Promise.all(updatePromises);
1909
+ }
1910
+ });
1911
+ } catch (error$1) {
1912
+ throw new error.MastraError(
1913
+ {
1914
+ id: "PG_STORE_DELETE_MESSAGES_FAILED",
1915
+ domain: error.ErrorDomain.STORAGE,
1916
+ category: error.ErrorCategory.THIRD_PARTY,
1917
+ details: { messageIds: messageIds.join(", ") }
1918
+ },
1919
+ error$1
1920
+ );
1921
+ }
1922
+ }
1885
1923
  async getResourceById({ resourceId }) {
1886
1924
  const tableName = getTableName({ indexName: storage.TABLE_RESOURCES, schemaName: getSchemaName(this.schema) });
1887
1925
  const result = await this.client.oneOrNone(
@@ -2858,7 +2896,8 @@ var PostgresStore = class extends storage.MastraStorage {
2858
2896
  selectByIncludeResourceScope: true,
2859
2897
  resourceWorkingMemory: true,
2860
2898
  hasColumn: true,
2861
- createTable: true
2899
+ createTable: true,
2900
+ deleteMessages: true
2862
2901
  };
2863
2902
  }
2864
2903
  /** @deprecated use getEvals instead */
@@ -2950,6 +2989,9 @@ var PostgresStore = class extends storage.MastraStorage {
2950
2989
  }) {
2951
2990
  return this.stores.memory.updateMessages({ messages });
2952
2991
  }
2992
+ async deleteMessages(messageIds) {
2993
+ return this.stores.memory.deleteMessages(messageIds);
2994
+ }
2953
2995
  async getResourceById({ resourceId }) {
2954
2996
  return this.stores.memory.getResourceById({ resourceId });
2955
2997
  }
package/dist/index.js CHANGED
@@ -1276,12 +1276,14 @@ var MemoryPG = class extends MemoryStorage {
1276
1276
  * @deprecated use getThreadsByResourceIdPaginated instead
1277
1277
  */
1278
1278
  async getThreadsByResourceId(args) {
1279
- const { resourceId } = args;
1279
+ const resourceId = args.resourceId;
1280
+ const orderBy = this.castThreadOrderBy(args.orderBy);
1281
+ const sortDirection = this.castThreadSortDirection(args.sortDirection);
1280
1282
  try {
1281
1283
  const tableName = getTableName({ indexName: TABLE_THREADS, schemaName: getSchemaName(this.schema) });
1282
1284
  const baseQuery = `FROM ${tableName} WHERE "resourceId" = $1`;
1283
1285
  const queryParams = [resourceId];
1284
- const dataQuery = `SELECT id, "resourceId", title, metadata, "createdAt", "updatedAt" ${baseQuery} ORDER BY "createdAt" DESC`;
1286
+ const dataQuery = `SELECT id, "resourceId", title, metadata, "createdAt", "updatedAt" ${baseQuery} ORDER BY "${orderBy}" ${sortDirection}`;
1285
1287
  const rows = await this.client.manyOrNone(dataQuery, queryParams);
1286
1288
  return (rows || []).map((thread) => ({
1287
1289
  ...thread,
@@ -1296,6 +1298,8 @@ var MemoryPG = class extends MemoryStorage {
1296
1298
  }
1297
1299
  async getThreadsByResourceIdPaginated(args) {
1298
1300
  const { resourceId, page = 0, perPage: perPageInput } = args;
1301
+ const orderBy = this.castThreadOrderBy(args.orderBy);
1302
+ const sortDirection = this.castThreadSortDirection(args.sortDirection);
1299
1303
  try {
1300
1304
  const tableName = getTableName({ indexName: TABLE_THREADS, schemaName: getSchemaName(this.schema) });
1301
1305
  const baseQuery = `FROM ${tableName} WHERE "resourceId" = $1`;
@@ -1314,7 +1318,7 @@ var MemoryPG = class extends MemoryStorage {
1314
1318
  hasMore: false
1315
1319
  };
1316
1320
  }
1317
- const dataQuery = `SELECT id, "resourceId", title, metadata, "createdAt", "updatedAt" ${baseQuery} ORDER BY "createdAt" DESC LIMIT $2 OFFSET $3`;
1321
+ const dataQuery = `SELECT id, "resourceId", title, metadata, "createdAt", "updatedAt" ${baseQuery} ORDER BY "${orderBy}" ${sortDirection} LIMIT $2 OFFSET $3`;
1318
1322
  const rows = await this.client.manyOrNone(dataQuery, [...queryParams, perPage, currentOffset]);
1319
1323
  const threads = (rows || []).map((thread) => ({
1320
1324
  ...thread,
@@ -1874,6 +1878,40 @@ var MemoryPG = class extends MemoryStorage {
1874
1878
  return message;
1875
1879
  });
1876
1880
  }
1881
+ async deleteMessages(messageIds) {
1882
+ if (!messageIds || messageIds.length === 0) {
1883
+ return;
1884
+ }
1885
+ try {
1886
+ const messageTableName = getTableName({ indexName: TABLE_MESSAGES, schemaName: getSchemaName(this.schema) });
1887
+ const threadTableName = getTableName({ indexName: TABLE_THREADS, schemaName: getSchemaName(this.schema) });
1888
+ await this.client.tx(async (t) => {
1889
+ const placeholders = messageIds.map((_, idx) => `$${idx + 1}`).join(",");
1890
+ const messages = await t.manyOrNone(
1891
+ `SELECT DISTINCT thread_id FROM ${messageTableName} WHERE id IN (${placeholders})`,
1892
+ messageIds
1893
+ );
1894
+ const threadIds = messages?.map((msg) => msg.thread_id).filter(Boolean) || [];
1895
+ await t.none(`DELETE FROM ${messageTableName} WHERE id IN (${placeholders})`, messageIds);
1896
+ if (threadIds.length > 0) {
1897
+ const updatePromises = threadIds.map(
1898
+ (threadId) => t.none(`UPDATE ${threadTableName} SET "updatedAt" = NOW(), "updatedAtZ" = NOW() WHERE id = $1`, [threadId])
1899
+ );
1900
+ await Promise.all(updatePromises);
1901
+ }
1902
+ });
1903
+ } catch (error) {
1904
+ throw new MastraError(
1905
+ {
1906
+ id: "PG_STORE_DELETE_MESSAGES_FAILED",
1907
+ domain: ErrorDomain.STORAGE,
1908
+ category: ErrorCategory.THIRD_PARTY,
1909
+ details: { messageIds: messageIds.join(", ") }
1910
+ },
1911
+ error
1912
+ );
1913
+ }
1914
+ }
1877
1915
  async getResourceById({ resourceId }) {
1878
1916
  const tableName = getTableName({ indexName: TABLE_RESOURCES, schemaName: getSchemaName(this.schema) });
1879
1917
  const result = await this.client.oneOrNone(
@@ -2850,7 +2888,8 @@ var PostgresStore = class extends MastraStorage {
2850
2888
  selectByIncludeResourceScope: true,
2851
2889
  resourceWorkingMemory: true,
2852
2890
  hasColumn: true,
2853
- createTable: true
2891
+ createTable: true,
2892
+ deleteMessages: true
2854
2893
  };
2855
2894
  }
2856
2895
  /** @deprecated use getEvals instead */
@@ -2942,6 +2981,9 @@ var PostgresStore = class extends MastraStorage {
2942
2981
  }) {
2943
2982
  return this.stores.memory.updateMessages({ messages });
2944
2983
  }
2984
+ async deleteMessages(messageIds) {
2985
+ return this.stores.memory.deleteMessages(messageIds);
2986
+ }
2945
2987
  async getResourceById({ resourceId }) {
2946
2988
  return this.stores.memory.getResourceById({ resourceId });
2947
2989
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mastra/pg",
3
- "version": "0.12.4",
3
+ "version": "0.12.6-alpha.0",
4
4
  "description": "Postgres provider for Mastra - includes both vector and db storage capabilities",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -33,12 +33,12 @@
33
33
  "tsup": "^8.5.0",
34
34
  "typescript": "^5.8.3",
35
35
  "vitest": "^3.2.4",
36
- "@internal/lint": "0.0.21",
37
- "@internal/storage-test-utils": "0.0.17",
38
- "@mastra/core": "0.11.0"
36
+ "@internal/lint": "0.0.23",
37
+ "@internal/storage-test-utils": "0.0.19",
38
+ "@mastra/core": "0.12.0-alpha.2"
39
39
  },
40
40
  "peerDependencies": {
41
- "@mastra/core": ">=0.10.7-0 <0.11.0-0"
41
+ "@mastra/core": ">=0.10.7-0 <0.12.0-0"
42
42
  },
43
43
  "scripts": {
44
44
  "build": "tsup src/index.ts --format esm,cjs --experimental-dts --clean --treeshake=smallest --splitting",
@@ -9,7 +9,12 @@ import {
9
9
  TABLE_RESOURCES,
10
10
  TABLE_THREADS,
11
11
  } from '@mastra/core/storage';
12
- import type { StorageGetMessagesArg, PaginationInfo, StorageResourceType } from '@mastra/core/storage';
12
+ import type {
13
+ StorageGetMessagesArg,
14
+ PaginationInfo,
15
+ StorageResourceType,
16
+ ThreadSortOptions,
17
+ } from '@mastra/core/storage';
13
18
  import type { IDatabase } from 'pg-promise';
14
19
  import type { StoreOperationsPG } from '../operations';
15
20
  import { getTableName, getSchemaName } from '../utils';
@@ -73,15 +78,17 @@ export class MemoryPG extends MemoryStorage {
73
78
  /**
74
79
  * @deprecated use getThreadsByResourceIdPaginated instead
75
80
  */
76
- public async getThreadsByResourceId(args: { resourceId: string }): Promise<StorageThreadType[]> {
77
- const { resourceId } = args;
81
+ public async getThreadsByResourceId(args: { resourceId: string } & ThreadSortOptions): Promise<StorageThreadType[]> {
82
+ const resourceId = args.resourceId;
83
+ const orderBy = this.castThreadOrderBy(args.orderBy);
84
+ const sortDirection = this.castThreadSortDirection(args.sortDirection);
78
85
 
79
86
  try {
80
87
  const tableName = getTableName({ indexName: TABLE_THREADS, schemaName: getSchemaName(this.schema) });
81
88
  const baseQuery = `FROM ${tableName} WHERE "resourceId" = $1`;
82
89
  const queryParams: any[] = [resourceId];
83
90
 
84
- const dataQuery = `SELECT id, "resourceId", title, metadata, "createdAt", "updatedAt" ${baseQuery} ORDER BY "createdAt" DESC`;
91
+ const dataQuery = `SELECT id, "resourceId", title, metadata, "createdAt", "updatedAt" ${baseQuery} ORDER BY "${orderBy}" ${sortDirection}`;
85
92
  const rows = await this.client.manyOrNone(dataQuery, queryParams);
86
93
  return (rows || []).map(thread => ({
87
94
  ...thread,
@@ -95,12 +102,16 @@ export class MemoryPG extends MemoryStorage {
95
102
  }
96
103
  }
97
104
 
98
- public async getThreadsByResourceIdPaginated(args: {
99
- resourceId: string;
100
- page: number;
101
- perPage: number;
102
- }): Promise<PaginationInfo & { threads: StorageThreadType[] }> {
105
+ public async getThreadsByResourceIdPaginated(
106
+ args: {
107
+ resourceId: string;
108
+ page: number;
109
+ perPage: number;
110
+ } & ThreadSortOptions,
111
+ ): Promise<PaginationInfo & { threads: StorageThreadType[] }> {
103
112
  const { resourceId, page = 0, perPage: perPageInput } = args;
113
+ const orderBy = this.castThreadOrderBy(args.orderBy);
114
+ const sortDirection = this.castThreadSortDirection(args.sortDirection);
104
115
  try {
105
116
  const tableName = getTableName({ indexName: TABLE_THREADS, schemaName: getSchemaName(this.schema) });
106
117
  const baseQuery = `FROM ${tableName} WHERE "resourceId" = $1`;
@@ -122,7 +133,7 @@ export class MemoryPG extends MemoryStorage {
122
133
  };
123
134
  }
124
135
 
125
- const dataQuery = `SELECT id, "resourceId", title, metadata, "createdAt", "updatedAt" ${baseQuery} ORDER BY "createdAt" DESC LIMIT $2 OFFSET $3`;
136
+ const dataQuery = `SELECT id, "resourceId", title, metadata, "createdAt", "updatedAt" ${baseQuery} ORDER BY "${orderBy}" ${sortDirection} LIMIT $2 OFFSET $3`;
126
137
  const rows = await this.client.manyOrNone(dataQuery, [...queryParams, perPage, currentOffset]);
127
138
 
128
139
  const threads = (rows || []).map(thread => ({
@@ -801,6 +812,51 @@ export class MemoryPG extends MemoryStorage {
801
812
  });
802
813
  }
803
814
 
815
+ async deleteMessages(messageIds: string[]): Promise<void> {
816
+ if (!messageIds || messageIds.length === 0) {
817
+ return;
818
+ }
819
+
820
+ try {
821
+ const messageTableName = getTableName({ indexName: TABLE_MESSAGES, schemaName: getSchemaName(this.schema) });
822
+ const threadTableName = getTableName({ indexName: TABLE_THREADS, schemaName: getSchemaName(this.schema) });
823
+
824
+ await this.client.tx(async t => {
825
+ // Get thread IDs for all messages
826
+ const placeholders = messageIds.map((_, idx) => `$${idx + 1}`).join(',');
827
+ const messages = await t.manyOrNone(
828
+ `SELECT DISTINCT thread_id FROM ${messageTableName} WHERE id IN (${placeholders})`,
829
+ messageIds,
830
+ );
831
+
832
+ const threadIds = messages?.map(msg => msg.thread_id).filter(Boolean) || [];
833
+
834
+ // Delete all messages
835
+ await t.none(`DELETE FROM ${messageTableName} WHERE id IN (${placeholders})`, messageIds);
836
+
837
+ // Update thread timestamps
838
+ if (threadIds.length > 0) {
839
+ const updatePromises = threadIds.map(threadId =>
840
+ t.none(`UPDATE ${threadTableName} SET "updatedAt" = NOW(), "updatedAtZ" = NOW() WHERE id = $1`, [threadId]),
841
+ );
842
+ await Promise.all(updatePromises);
843
+ }
844
+ });
845
+
846
+ // TODO: Delete from vector store if semantic recall is enabled
847
+ } catch (error) {
848
+ throw new MastraError(
849
+ {
850
+ id: 'PG_STORE_DELETE_MESSAGES_FAILED',
851
+ domain: ErrorDomain.STORAGE,
852
+ category: ErrorCategory.THIRD_PARTY,
853
+ details: { messageIds: messageIds.join(', ') },
854
+ },
855
+ error,
856
+ );
857
+ }
858
+ }
859
+
804
860
  async getResourceById({ resourceId }: { resourceId: string }): Promise<StorageResourceType | null> {
805
861
  const tableName = getTableName({ indexName: TABLE_RESOURCES, schemaName: getSchemaName(this.schema) });
806
862
  const result = await this.client.oneOrNone<StorageResourceType & { createdAtZ: Date; updatedAtZ: Date }>(
@@ -17,6 +17,7 @@ import type {
17
17
  PaginationArgs,
18
18
  StoragePagination,
19
19
  StorageDomains,
20
+ ThreadSortOptions,
20
21
  } from '@mastra/core/storage';
21
22
  import type { Trace } from '@mastra/core/telemetry';
22
23
  import type { WorkflowRunState } from '@mastra/core/workflows';
@@ -127,6 +128,7 @@ export class PostgresStore extends MastraStorage {
127
128
  resourceWorkingMemory: true,
128
129
  hasColumn: true,
129
130
  createTable: true,
131
+ deleteMessages: true,
130
132
  };
131
133
  }
132
134
 
@@ -212,15 +214,17 @@ export class PostgresStore extends MastraStorage {
212
214
  /**
213
215
  * @deprecated use getThreadsByResourceIdPaginated instead
214
216
  */
215
- public async getThreadsByResourceId(args: { resourceId: string }): Promise<StorageThreadType[]> {
217
+ public async getThreadsByResourceId(args: { resourceId: string } & ThreadSortOptions): Promise<StorageThreadType[]> {
216
218
  return this.stores.memory.getThreadsByResourceId(args);
217
219
  }
218
220
 
219
- public async getThreadsByResourceIdPaginated(args: {
220
- resourceId: string;
221
- page: number;
222
- perPage: number;
223
- }): Promise<PaginationInfo & { threads: StorageThreadType[] }> {
221
+ public async getThreadsByResourceIdPaginated(
222
+ args: {
223
+ resourceId: string;
224
+ page: number;
225
+ perPage: number;
226
+ } & ThreadSortOptions,
227
+ ): Promise<PaginationInfo & { threads: StorageThreadType[] }> {
224
228
  return this.stores.memory.getThreadsByResourceIdPaginated(args);
225
229
  }
226
230
 
@@ -287,6 +291,10 @@ export class PostgresStore extends MastraStorage {
287
291
  return this.stores.memory.updateMessages({ messages });
288
292
  }
289
293
 
294
+ async deleteMessages(messageIds: string[]): Promise<void> {
295
+ return this.stores.memory.deleteMessages(messageIds);
296
+ }
297
+
290
298
  async getResourceById({ resourceId }: { resourceId: string }): Promise<StorageResourceType | null> {
291
299
  return this.stores.memory.getResourceById({ resourceId });
292
300
  }