@mastra/upstash 0.10.3-alpha.1 → 0.10.3-alpha.3
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 +10 -10
- package/CHANGELOG.md +17 -0
- package/dist/_tsup-dts-rollup.d.cts +25 -51
- package/dist/_tsup-dts-rollup.d.ts +25 -51
- package/dist/index.cjs +384 -384
- package/dist/index.js +384 -384
- package/package.json +3 -3
- package/src/storage/index.ts +313 -365
- package/src/storage/upstash.test.ts +190 -102
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import { randomUUID } from 'crypto';
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
checkWorkflowSnapshot,
|
|
4
|
+
createSampleMessageV2,
|
|
5
|
+
createSampleThread,
|
|
6
|
+
createSampleWorkflowSnapshot,
|
|
7
|
+
} from '@internal/storage-test-utils';
|
|
3
8
|
import type { MastraMessageV2 } from '@mastra/core';
|
|
4
9
|
import type { TABLE_NAMES } from '@mastra/core/storage';
|
|
5
10
|
import {
|
|
@@ -17,7 +22,12 @@ import { UpstashStore } from './index';
|
|
|
17
22
|
// Increase timeout for all tests in this file to 30 seconds
|
|
18
23
|
vi.setConfig({ testTimeout: 200_000, hookTimeout: 200_000 });
|
|
19
24
|
|
|
20
|
-
const createSampleTrace = (
|
|
25
|
+
const createSampleTrace = (
|
|
26
|
+
name: string,
|
|
27
|
+
scope?: string,
|
|
28
|
+
attributes?: Record<string, string>,
|
|
29
|
+
createdAt: Date = new Date(),
|
|
30
|
+
) => ({
|
|
21
31
|
id: `trace-${randomUUID()}`,
|
|
22
32
|
parentSpanId: `span-${randomUUID()}`,
|
|
23
33
|
traceId: `trace-${randomUUID()}`,
|
|
@@ -25,16 +35,16 @@ const createSampleTrace = (name: string, scope?: string, attributes?: Record<str
|
|
|
25
35
|
scope,
|
|
26
36
|
kind: 'internal',
|
|
27
37
|
status: JSON.stringify({ code: 'success' }),
|
|
28
|
-
events: JSON.stringify([{ name: 'start', timestamp:
|
|
38
|
+
events: JSON.stringify([{ name: 'start', timestamp: createdAt.getTime() }]),
|
|
29
39
|
links: JSON.stringify([]),
|
|
30
40
|
attributes: attributes ? JSON.stringify(attributes) : undefined,
|
|
31
|
-
startTime:
|
|
32
|
-
endTime: new Date().toISOString(),
|
|
41
|
+
startTime: createdAt.toISOString(),
|
|
42
|
+
endTime: new Date(createdAt.getTime() + 1000).toISOString(),
|
|
33
43
|
other: JSON.stringify({ custom: 'data' }),
|
|
34
|
-
createdAt:
|
|
44
|
+
createdAt: createdAt.toISOString(),
|
|
35
45
|
});
|
|
36
46
|
|
|
37
|
-
const createSampleEval = (agentName: string, isTest = false) => {
|
|
47
|
+
const createSampleEval = (agentName: string, isTest = false, createdAt: Date = new Date()) => {
|
|
38
48
|
const testInfo = isTest ? { testPath: 'test/path.ts', testName: 'Test Name' } : undefined;
|
|
39
49
|
|
|
40
50
|
return {
|
|
@@ -47,17 +57,10 @@ const createSampleEval = (agentName: string, isTest = false) => {
|
|
|
47
57
|
test_info: testInfo ? JSON.stringify(testInfo) : undefined,
|
|
48
58
|
global_run_id: `global-${randomUUID()}`,
|
|
49
59
|
run_id: `run-${randomUUID()}`,
|
|
50
|
-
created_at:
|
|
60
|
+
created_at: createdAt.toISOString(),
|
|
51
61
|
};
|
|
52
62
|
};
|
|
53
63
|
|
|
54
|
-
const checkWorkflowSnapshot = (snapshot: WorkflowRunState | string, stepId: string, status: string) => {
|
|
55
|
-
if (typeof snapshot === 'string') {
|
|
56
|
-
throw new Error('Expected WorkflowRunState, got string');
|
|
57
|
-
}
|
|
58
|
-
expect(snapshot.context?.[stepId]?.status).toBe(status);
|
|
59
|
-
};
|
|
60
|
-
|
|
61
64
|
describe('UpstashStore', () => {
|
|
62
65
|
let store: UpstashStore;
|
|
63
66
|
const testTableName = 'test_table';
|
|
@@ -154,7 +157,7 @@ describe('UpstashStore', () => {
|
|
|
154
157
|
|
|
155
158
|
it('should get threads by resource ID', async () => {
|
|
156
159
|
const thread1 = createSampleThread();
|
|
157
|
-
const thread2 =
|
|
160
|
+
const thread2 = createSampleThread({ resourceId: thread1.resourceId });
|
|
158
161
|
const threads = [thread1, thread2];
|
|
159
162
|
|
|
160
163
|
const resourceId = threads[0].resourceId;
|
|
@@ -187,7 +190,7 @@ describe('UpstashStore', () => {
|
|
|
187
190
|
it('should fetch >100000 threads by resource ID', async () => {
|
|
188
191
|
const resourceId = `resource-${randomUUID()}`;
|
|
189
192
|
const total = 100_000;
|
|
190
|
-
const threads = Array.from({ length: total }, () => ({
|
|
193
|
+
const threads = Array.from({ length: total }, () => createSampleThread({ resourceId }));
|
|
191
194
|
|
|
192
195
|
await store.batchInsert({ tableName: TABLE_THREADS, records: threads });
|
|
193
196
|
|
|
@@ -300,13 +303,117 @@ describe('UpstashStore', () => {
|
|
|
300
303
|
createSampleMessageV2({ threadId, content: 'Third' }),
|
|
301
304
|
];
|
|
302
305
|
|
|
303
|
-
await store.saveMessages({ messages
|
|
306
|
+
await store.saveMessages({ messages, format: 'v2' });
|
|
304
307
|
|
|
305
308
|
const retrievedMessages = await store.getMessages({ threadId, format: 'v2' });
|
|
306
309
|
expect(retrievedMessages).toHaveLength(3);
|
|
307
310
|
expect(retrievedMessages.map((m: any) => m.content.parts[0].text)).toEqual(['First', 'Second', 'Third']);
|
|
308
311
|
});
|
|
309
312
|
|
|
313
|
+
it('should retrieve messages w/ next/prev messages by message id + resource id', async () => {
|
|
314
|
+
const thread = createSampleThread({ id: 'thread-one' });
|
|
315
|
+
await store.saveThread({ thread });
|
|
316
|
+
|
|
317
|
+
const thread2 = createSampleThread({ id: 'thread-two' });
|
|
318
|
+
await store.saveThread({ thread: thread2 });
|
|
319
|
+
|
|
320
|
+
const thread3 = createSampleThread({ id: 'thread-three' });
|
|
321
|
+
await store.saveThread({ thread: thread3 });
|
|
322
|
+
|
|
323
|
+
const messages: MastraMessageV2[] = [
|
|
324
|
+
createSampleMessageV2({ threadId: 'thread-one', content: 'First', resourceId: 'cross-thread-resource' }),
|
|
325
|
+
createSampleMessageV2({ threadId: 'thread-one', content: 'Second', resourceId: 'cross-thread-resource' }),
|
|
326
|
+
createSampleMessageV2({ threadId: 'thread-one', content: 'Third', resourceId: 'cross-thread-resource' }),
|
|
327
|
+
|
|
328
|
+
createSampleMessageV2({ threadId: 'thread-two', content: 'Fourth', resourceId: 'cross-thread-resource' }),
|
|
329
|
+
createSampleMessageV2({ threadId: 'thread-two', content: 'Fifth', resourceId: 'cross-thread-resource' }),
|
|
330
|
+
createSampleMessageV2({ threadId: 'thread-two', content: 'Sixth', resourceId: 'cross-thread-resource' }),
|
|
331
|
+
|
|
332
|
+
createSampleMessageV2({ threadId: 'thread-three', content: 'Seventh', resourceId: 'other-resource' }),
|
|
333
|
+
createSampleMessageV2({ threadId: 'thread-three', content: 'Eighth', resourceId: 'other-resource' }),
|
|
334
|
+
];
|
|
335
|
+
|
|
336
|
+
await store.saveMessages({ messages: messages, format: 'v2' });
|
|
337
|
+
|
|
338
|
+
const retrievedMessages = await store.getMessages({ threadId: 'thread-one', format: 'v2' });
|
|
339
|
+
expect(retrievedMessages).toHaveLength(3);
|
|
340
|
+
expect(retrievedMessages.map((m: any) => m.content.parts[0].text)).toEqual(['First', 'Second', 'Third']);
|
|
341
|
+
|
|
342
|
+
const retrievedMessages2 = await store.getMessages({ threadId: 'thread-two', format: 'v2' });
|
|
343
|
+
expect(retrievedMessages2).toHaveLength(3);
|
|
344
|
+
expect(retrievedMessages2.map((m: any) => m.content.parts[0].text)).toEqual(['Fourth', 'Fifth', 'Sixth']);
|
|
345
|
+
|
|
346
|
+
const retrievedMessages3 = await store.getMessages({ threadId: 'thread-three', format: 'v2' });
|
|
347
|
+
expect(retrievedMessages3).toHaveLength(2);
|
|
348
|
+
expect(retrievedMessages3.map((m: any) => m.content.parts[0].text)).toEqual(['Seventh', 'Eighth']);
|
|
349
|
+
|
|
350
|
+
const crossThreadMessages = await store.getMessages({
|
|
351
|
+
threadId: 'thread-doesnt-exist',
|
|
352
|
+
format: 'v2',
|
|
353
|
+
selectBy: {
|
|
354
|
+
last: 0,
|
|
355
|
+
include: [
|
|
356
|
+
{
|
|
357
|
+
id: messages[1].id,
|
|
358
|
+
threadId: 'thread-one',
|
|
359
|
+
withNextMessages: 2,
|
|
360
|
+
withPreviousMessages: 2,
|
|
361
|
+
},
|
|
362
|
+
{
|
|
363
|
+
id: messages[4].id,
|
|
364
|
+
threadId: 'thread-two',
|
|
365
|
+
withPreviousMessages: 2,
|
|
366
|
+
withNextMessages: 2,
|
|
367
|
+
},
|
|
368
|
+
],
|
|
369
|
+
},
|
|
370
|
+
});
|
|
371
|
+
|
|
372
|
+
expect(crossThreadMessages).toHaveLength(6);
|
|
373
|
+
expect(crossThreadMessages.filter(m => m.threadId === `thread-one`)).toHaveLength(3);
|
|
374
|
+
expect(crossThreadMessages.filter(m => m.threadId === `thread-two`)).toHaveLength(3);
|
|
375
|
+
|
|
376
|
+
const crossThreadMessages2 = await store.getMessages({
|
|
377
|
+
threadId: 'thread-one',
|
|
378
|
+
format: 'v2',
|
|
379
|
+
selectBy: {
|
|
380
|
+
last: 0,
|
|
381
|
+
include: [
|
|
382
|
+
{
|
|
383
|
+
id: messages[4].id,
|
|
384
|
+
threadId: 'thread-two',
|
|
385
|
+
withPreviousMessages: 1,
|
|
386
|
+
withNextMessages: 1,
|
|
387
|
+
},
|
|
388
|
+
],
|
|
389
|
+
},
|
|
390
|
+
});
|
|
391
|
+
|
|
392
|
+
expect(crossThreadMessages2).toHaveLength(3);
|
|
393
|
+
expect(crossThreadMessages2.filter(m => m.threadId === `thread-one`)).toHaveLength(0);
|
|
394
|
+
expect(crossThreadMessages2.filter(m => m.threadId === `thread-two`)).toHaveLength(3);
|
|
395
|
+
|
|
396
|
+
const crossThreadMessages3 = await store.getMessages({
|
|
397
|
+
threadId: 'thread-two',
|
|
398
|
+
format: 'v2',
|
|
399
|
+
selectBy: {
|
|
400
|
+
last: 0,
|
|
401
|
+
include: [
|
|
402
|
+
{
|
|
403
|
+
id: messages[1].id,
|
|
404
|
+
threadId: 'thread-one',
|
|
405
|
+
withNextMessages: 1,
|
|
406
|
+
withPreviousMessages: 1,
|
|
407
|
+
},
|
|
408
|
+
],
|
|
409
|
+
},
|
|
410
|
+
});
|
|
411
|
+
|
|
412
|
+
expect(crossThreadMessages3).toHaveLength(3);
|
|
413
|
+
expect(crossThreadMessages3.filter(m => m.threadId === `thread-one`)).toHaveLength(3);
|
|
414
|
+
expect(crossThreadMessages3.filter(m => m.threadId === `thread-two`)).toHaveLength(0);
|
|
415
|
+
});
|
|
416
|
+
|
|
310
417
|
it('should handle empty message array', async () => {
|
|
311
418
|
const result = await store.saveMessages({ messages: [] });
|
|
312
419
|
expect(result).toEqual([]);
|
|
@@ -336,7 +443,7 @@ describe('UpstashStore', () => {
|
|
|
336
443
|
expect(retrievedMessages[0].content).toEqual(messages[0].content);
|
|
337
444
|
});
|
|
338
445
|
|
|
339
|
-
describe('
|
|
446
|
+
describe('getMessagesPaginated', () => {
|
|
340
447
|
it('should return paginated messages with total count', async () => {
|
|
341
448
|
const thread = createSampleThread();
|
|
342
449
|
await store.saveThread({ thread });
|
|
@@ -347,10 +454,9 @@ describe('UpstashStore', () => {
|
|
|
347
454
|
|
|
348
455
|
await store.saveMessages({ messages, format: 'v2' });
|
|
349
456
|
|
|
350
|
-
const page1 = await store.
|
|
457
|
+
const page1 = await store.getMessagesPaginated({
|
|
351
458
|
threadId: thread.id,
|
|
352
|
-
page: 0,
|
|
353
|
-
perPage: 5,
|
|
459
|
+
selectBy: { pagination: { page: 0, perPage: 5 } },
|
|
354
460
|
format: 'v2',
|
|
355
461
|
});
|
|
356
462
|
expect(page1.messages).toHaveLength(5);
|
|
@@ -359,20 +465,18 @@ describe('UpstashStore', () => {
|
|
|
359
465
|
expect(page1.perPage).toBe(5);
|
|
360
466
|
expect(page1.hasMore).toBe(true);
|
|
361
467
|
|
|
362
|
-
const page3 = await store.
|
|
468
|
+
const page3 = await store.getMessagesPaginated({
|
|
363
469
|
threadId: thread.id,
|
|
364
|
-
page: 2,
|
|
365
|
-
perPage: 5,
|
|
470
|
+
selectBy: { pagination: { page: 2, perPage: 5 } },
|
|
366
471
|
format: 'v2',
|
|
367
472
|
});
|
|
368
473
|
expect(page3.messages).toHaveLength(5);
|
|
369
474
|
expect(page3.total).toBe(15);
|
|
370
475
|
expect(page3.hasMore).toBe(false);
|
|
371
476
|
|
|
372
|
-
const page4 = await store.
|
|
477
|
+
const page4 = await store.getMessagesPaginated({
|
|
373
478
|
threadId: thread.id,
|
|
374
|
-
page: 3,
|
|
375
|
-
perPage: 5,
|
|
479
|
+
selectBy: { pagination: { page: 3, perPage: 5 } },
|
|
376
480
|
format: 'v2',
|
|
377
481
|
});
|
|
378
482
|
expect(page4.messages).toHaveLength(0);
|
|
@@ -393,10 +497,9 @@ describe('UpstashStore', () => {
|
|
|
393
497
|
|
|
394
498
|
await store.saveMessages({ messages, format: 'v2' });
|
|
395
499
|
|
|
396
|
-
const page1 = await store.
|
|
500
|
+
const page1 = await store.getMessagesPaginated({
|
|
397
501
|
threadId: thread.id,
|
|
398
|
-
page: 0,
|
|
399
|
-
perPage: 3,
|
|
502
|
+
selectBy: { pagination: { page: 0, perPage: 3 } },
|
|
400
503
|
format: 'v2',
|
|
401
504
|
});
|
|
402
505
|
|
|
@@ -410,32 +513,6 @@ describe('UpstashStore', () => {
|
|
|
410
513
|
}
|
|
411
514
|
});
|
|
412
515
|
|
|
413
|
-
it('should maintain backward compatibility when no pagination params provided', async () => {
|
|
414
|
-
const thread = createSampleThread();
|
|
415
|
-
await store.saveThread({ thread });
|
|
416
|
-
|
|
417
|
-
const messages = Array.from({ length: 5 }, (_, i) =>
|
|
418
|
-
createSampleMessageV2({ threadId: thread.id, content: `Message ${i + 1}` }),
|
|
419
|
-
);
|
|
420
|
-
|
|
421
|
-
await store.saveMessages({ messages, format: 'v2' });
|
|
422
|
-
|
|
423
|
-
// Test original format without pagination - should return array
|
|
424
|
-
const messagesV1 = await store.getMessages({
|
|
425
|
-
threadId: thread.id,
|
|
426
|
-
format: 'v1',
|
|
427
|
-
});
|
|
428
|
-
expect(Array.isArray(messagesV1)).toBe(true);
|
|
429
|
-
expect(messagesV1).toHaveLength(5);
|
|
430
|
-
|
|
431
|
-
const messagesV2 = await store.getMessages({
|
|
432
|
-
threadId: thread.id,
|
|
433
|
-
format: 'v2',
|
|
434
|
-
});
|
|
435
|
-
expect(Array.isArray(messagesV2)).toBe(true);
|
|
436
|
-
expect(messagesV2).toHaveLength(5);
|
|
437
|
-
});
|
|
438
|
-
|
|
439
516
|
it('should support date filtering with pagination', async () => {
|
|
440
517
|
const thread = createSampleThread();
|
|
441
518
|
await store.saveThread({ thread });
|
|
@@ -458,11 +535,15 @@ describe('UpstashStore', () => {
|
|
|
458
535
|
|
|
459
536
|
await store.saveMessages({ messages: [...oldMessages, ...newMessages], format: 'v2' });
|
|
460
537
|
|
|
461
|
-
const recentMessages = await store.
|
|
538
|
+
const recentMessages = await store.getMessagesPaginated({
|
|
462
539
|
threadId: thread.id,
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
540
|
+
selectBy: {
|
|
541
|
+
pagination: {
|
|
542
|
+
page: 0,
|
|
543
|
+
perPage: 10,
|
|
544
|
+
dateRange: { start: now },
|
|
545
|
+
},
|
|
546
|
+
},
|
|
466
547
|
format: 'v2',
|
|
467
548
|
});
|
|
468
549
|
expect(recentMessages.messages).toHaveLength(4);
|
|
@@ -1098,7 +1179,7 @@ describe('UpstashStore', () => {
|
|
|
1098
1179
|
expect(page3.hasMore).toBe(false);
|
|
1099
1180
|
});
|
|
1100
1181
|
|
|
1101
|
-
it('should support
|
|
1182
|
+
it('should support page/perPage pagination', async () => {
|
|
1102
1183
|
const agentName = 'test-agent-2';
|
|
1103
1184
|
const evals = Array.from({ length: 15 }, () => createSampleEval(agentName));
|
|
1104
1185
|
|
|
@@ -1110,12 +1191,12 @@ describe('UpstashStore', () => {
|
|
|
1110
1191
|
}
|
|
1111
1192
|
|
|
1112
1193
|
// Test offset-based pagination
|
|
1113
|
-
const result1 = await store.getEvals({ agentName,
|
|
1194
|
+
const result1 = await store.getEvals({ agentName, page: 0, perPage: 5 });
|
|
1114
1195
|
expect(result1.evals).toHaveLength(5);
|
|
1115
1196
|
expect(result1.total).toBe(15);
|
|
1116
1197
|
expect(result1.hasMore).toBe(true);
|
|
1117
1198
|
|
|
1118
|
-
const result2 = await store.getEvals({ agentName,
|
|
1199
|
+
const result2 = await store.getEvals({ agentName, page: 2, perPage: 5 });
|
|
1119
1200
|
expect(result2.evals).toHaveLength(5);
|
|
1120
1201
|
expect(result2.total).toBe(15);
|
|
1121
1202
|
expect(result2.hasMore).toBe(false);
|
|
@@ -1141,9 +1222,30 @@ describe('UpstashStore', () => {
|
|
|
1141
1222
|
expect(liveResults.evals).toHaveLength(5);
|
|
1142
1223
|
expect(liveResults.total).toBe(8);
|
|
1143
1224
|
});
|
|
1225
|
+
|
|
1226
|
+
it('should filter by date with pagination', async () => {
|
|
1227
|
+
const agentName = 'test-agent-date';
|
|
1228
|
+
const now = new Date();
|
|
1229
|
+
const yesterday = new Date(now.getTime() - 24 * 60 * 60 * 1000);
|
|
1230
|
+
const evals = [createSampleEval(agentName, false, now), createSampleEval(agentName, false, yesterday)];
|
|
1231
|
+
for (const evalRecord of evals) {
|
|
1232
|
+
await store.insert({
|
|
1233
|
+
tableName: TABLE_EVALS,
|
|
1234
|
+
record: evalRecord,
|
|
1235
|
+
});
|
|
1236
|
+
}
|
|
1237
|
+
const result = await store.getEvals({
|
|
1238
|
+
agentName,
|
|
1239
|
+
page: 0,
|
|
1240
|
+
perPage: 10,
|
|
1241
|
+
dateRange: { start: now },
|
|
1242
|
+
});
|
|
1243
|
+
expect(result.evals).toHaveLength(1);
|
|
1244
|
+
expect(result.total).toBe(1);
|
|
1245
|
+
});
|
|
1144
1246
|
});
|
|
1145
1247
|
|
|
1146
|
-
describe('
|
|
1248
|
+
describe('getTraces with pagination', () => {
|
|
1147
1249
|
it('should return paginated traces with total count', async () => {
|
|
1148
1250
|
const traces = Array.from({ length: 18 }, (_, i) => createSampleTrace(`test-trace-${i}`, 'test-scope'));
|
|
1149
1251
|
|
|
@@ -1154,11 +1256,10 @@ describe('UpstashStore', () => {
|
|
|
1154
1256
|
});
|
|
1155
1257
|
}
|
|
1156
1258
|
|
|
1157
|
-
const page1 = await store.
|
|
1259
|
+
const page1 = await store.getTracesPaginated({
|
|
1158
1260
|
scope: 'test-scope',
|
|
1159
1261
|
page: 0,
|
|
1160
1262
|
perPage: 8,
|
|
1161
|
-
returnPaginationResults: true,
|
|
1162
1263
|
});
|
|
1163
1264
|
expect(page1.traces).toHaveLength(8);
|
|
1164
1265
|
expect(page1.total).toBe(18);
|
|
@@ -1166,75 +1267,62 @@ describe('UpstashStore', () => {
|
|
|
1166
1267
|
expect(page1.perPage).toBe(8);
|
|
1167
1268
|
expect(page1.hasMore).toBe(true);
|
|
1168
1269
|
|
|
1169
|
-
const page3 = await store.
|
|
1270
|
+
const page3 = await store.getTracesPaginated({
|
|
1170
1271
|
scope: 'test-scope',
|
|
1171
1272
|
page: 2,
|
|
1172
1273
|
perPage: 8,
|
|
1173
|
-
returnPaginationResults: true,
|
|
1174
1274
|
});
|
|
1175
1275
|
expect(page3.traces).toHaveLength(2);
|
|
1176
1276
|
expect(page3.total).toBe(18);
|
|
1177
1277
|
expect(page3.hasMore).toBe(false);
|
|
1178
1278
|
});
|
|
1179
1279
|
|
|
1180
|
-
it('should filter by
|
|
1181
|
-
const
|
|
1182
|
-
|
|
1183
|
-
);
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1280
|
+
it('should filter by date with pagination', async () => {
|
|
1281
|
+
const scope = 'test-scope-date';
|
|
1282
|
+
const now = new Date();
|
|
1283
|
+
const yesterday = new Date(now.getTime() - 24 * 60 * 60 * 1000);
|
|
1284
|
+
|
|
1285
|
+
const traces = [
|
|
1286
|
+
createSampleTrace(`test-trace-now`, scope, undefined, now),
|
|
1287
|
+
createSampleTrace(`test-trace-yesterday`, scope, undefined, yesterday),
|
|
1288
|
+
];
|
|
1187
1289
|
|
|
1188
|
-
for (const trace of
|
|
1290
|
+
for (const trace of traces) {
|
|
1189
1291
|
await store.insert({
|
|
1190
1292
|
tableName: TABLE_TRACES,
|
|
1191
1293
|
record: trace,
|
|
1192
1294
|
});
|
|
1193
1295
|
}
|
|
1194
1296
|
|
|
1195
|
-
const
|
|
1196
|
-
scope
|
|
1197
|
-
attributes: { environment: 'prod' },
|
|
1198
|
-
page: 0,
|
|
1199
|
-
perPage: 5,
|
|
1200
|
-
returnPaginationResults: true,
|
|
1201
|
-
});
|
|
1202
|
-
expect(prodTraces.traces).toHaveLength(5);
|
|
1203
|
-
expect(prodTraces.total).toBe(8);
|
|
1204
|
-
expect(prodTraces.hasMore).toBe(true);
|
|
1205
|
-
|
|
1206
|
-
const devTraces = await store.getTraces({
|
|
1207
|
-
scope: 'test-scope',
|
|
1208
|
-
attributes: { environment: 'dev' },
|
|
1297
|
+
const result = await store.getTracesPaginated({
|
|
1298
|
+
scope,
|
|
1209
1299
|
page: 0,
|
|
1210
1300
|
perPage: 10,
|
|
1211
|
-
|
|
1301
|
+
dateRange: { start: now },
|
|
1212
1302
|
});
|
|
1213
|
-
|
|
1214
|
-
expect(
|
|
1215
|
-
expect(
|
|
1303
|
+
|
|
1304
|
+
expect(result.traces).toHaveLength(1);
|
|
1305
|
+
expect(result.traces[0].name).toBe('test-trace-now');
|
|
1306
|
+
expect(result.total).toBe(1);
|
|
1216
1307
|
});
|
|
1217
1308
|
});
|
|
1218
1309
|
|
|
1219
1310
|
describe('Enhanced existing methods with pagination', () => {
|
|
1220
1311
|
it('should support pagination in getThreadsByResourceId', async () => {
|
|
1221
1312
|
const resourceId = 'enhanced-resource';
|
|
1222
|
-
const threads = Array.from({ length: 17 }, () => ({
|
|
1223
|
-
...createSampleThread(),
|
|
1224
|
-
resourceId,
|
|
1225
|
-
}));
|
|
1313
|
+
const threads = Array.from({ length: 17 }, () => createSampleThread({ resourceId }));
|
|
1226
1314
|
|
|
1227
1315
|
for (const thread of threads) {
|
|
1228
1316
|
await store.saveThread({ thread });
|
|
1229
1317
|
}
|
|
1230
1318
|
|
|
1231
|
-
const page1 = await store.
|
|
1319
|
+
const page1 = await store.getThreadsByResourceIdPaginated({ resourceId, page: 0, perPage: 7 });
|
|
1232
1320
|
expect(page1.threads).toHaveLength(7);
|
|
1233
1321
|
|
|
1234
|
-
const page3 = await store.
|
|
1322
|
+
const page3 = await store.getThreadsByResourceIdPaginated({ resourceId, page: 2, perPage: 7 });
|
|
1235
1323
|
expect(page3.threads).toHaveLength(3);
|
|
1236
1324
|
|
|
1237
|
-
const limited = await store.
|
|
1325
|
+
const limited = await store.getThreadsByResourceIdPaginated({ resourceId, page: 1, perPage: 5 });
|
|
1238
1326
|
expect(limited.threads).toHaveLength(5);
|
|
1239
1327
|
});
|
|
1240
1328
|
});
|