@mastra/clickhouse 0.11.1-alpha.0 → 0.11.1-alpha.2

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.
@@ -4,6 +4,7 @@ import {
4
4
  createSampleThread,
5
5
  createSampleWorkflowSnapshot,
6
6
  checkWorkflowSnapshot,
7
+ createSampleMessageV2,
7
8
  } from '@internal/storage-test-utils';
8
9
  import type { MastraMessageV1, StorageColumn, WorkflowRunState } from '@mastra/core';
9
10
  import type { TABLE_NAMES } from '@mastra/core/storage';
@@ -236,6 +237,83 @@ describe('ClickhouseStore', () => {
236
237
  });
237
238
  }, 10e3);
238
239
 
240
+ it('should upsert messages: duplicate id+threadId results in update, not duplicate row', async () => {
241
+ const thread = await createSampleThread({ resourceId: 'clickhouse-test' });
242
+ await store.saveThread({ thread });
243
+ const baseMessage = createSampleMessageV2({
244
+ threadId: thread.id,
245
+ createdAt: new Date(),
246
+ content: { content: 'Original' },
247
+ resourceId: 'clickhouse-test',
248
+ });
249
+
250
+ // Insert the message for the first time
251
+ await store.saveMessages({ messages: [baseMessage], format: 'v2' });
252
+
253
+ // Insert again with the same id and threadId but different content
254
+ const updatedMessage = {
255
+ ...createSampleMessageV2({
256
+ threadId: thread.id,
257
+ createdAt: new Date(),
258
+ content: { content: 'Updated' },
259
+ resourceId: 'clickhouse-test',
260
+ }),
261
+ id: baseMessage.id,
262
+ };
263
+ await store.saveMessages({ messages: [updatedMessage], format: 'v2' });
264
+ await new Promise(resolve => setTimeout(resolve, 500));
265
+
266
+ // Retrieve messages for the thread
267
+ const retrievedMessages = await store.getMessages({ threadId: thread.id, format: 'v2' });
268
+
269
+ // Only one message should exist for that id+threadId
270
+ expect(retrievedMessages.filter(m => m.id === baseMessage.id)).toHaveLength(1);
271
+
272
+ // The content should be the updated one
273
+ expect(retrievedMessages.find(m => m.id === baseMessage.id)?.content.content).toBe('Updated');
274
+ }, 10e3);
275
+
276
+ it('should upsert messages: duplicate id and different threadid', async () => {
277
+ const thread1 = await createSampleThread();
278
+ const thread2 = await createSampleThread();
279
+ await store.saveThread({ thread: thread1 });
280
+ await store.saveThread({ thread: thread2 });
281
+
282
+ const message = createSampleMessageV2({
283
+ threadId: thread1.id,
284
+ createdAt: new Date(),
285
+ content: { content: 'Thread1 Content' },
286
+ resourceId: thread1.resourceId,
287
+ });
288
+
289
+ // Insert message into thread1
290
+ await store.saveMessages({ messages: [message], format: 'v2' });
291
+
292
+ // Attempt to insert a message with the same id but different threadId
293
+ const conflictingMessage = {
294
+ ...createSampleMessageV2({
295
+ threadId: thread2.id,
296
+ createdAt: new Date(),
297
+ content: { content: 'Thread2 Content' },
298
+ resourceId: thread2.resourceId,
299
+ }),
300
+ id: message.id,
301
+ };
302
+
303
+ // Save should also save the message to the new thread
304
+ await store.saveMessages({ messages: [conflictingMessage], format: 'v2' });
305
+
306
+ // Retrieve messages for both threads
307
+ const thread1Messages = await store.getMessages({ threadId: thread1.id, format: 'v2' });
308
+ const thread2Messages = await store.getMessages({ threadId: thread2.id, format: 'v2' });
309
+
310
+ // Thread 1 should have the message with that id
311
+ expect(thread1Messages.find(m => m.id === message.id)?.content.content).toBe('Thread1 Content');
312
+
313
+ // Thread 2 should have the message with that id
314
+ expect(thread2Messages.find(m => m.id === message.id)?.content.content).toBe('Thread2 Content');
315
+ }, 10e3);
316
+
239
317
  // it('should retrieve messages w/ next/prev messages by message id + resource id', async () => {
240
318
  // const messages: MastraMessageV2[] = [
241
319
  // createSampleMessageV2({ threadId: 'thread-one', content: 'First', resourceId: 'cross-thread-resource' }),