@lobehub/lobehub 2.0.0-next.40 → 2.0.0-next.42
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/CHANGELOG.md +50 -0
- package/changelog/v1.json +18 -0
- package/locales/ar/chat.json +1 -0
- package/locales/bg-BG/chat.json +1 -0
- package/locales/de-DE/chat.json +1 -0
- package/locales/en-US/chat.json +1 -0
- package/locales/es-ES/chat.json +1 -0
- package/locales/fa-IR/chat.json +1 -0
- package/locales/fr-FR/chat.json +1 -0
- package/locales/it-IT/chat.json +1 -0
- package/locales/ja-JP/chat.json +1 -0
- package/locales/ko-KR/chat.json +1 -0
- package/locales/nl-NL/chat.json +1 -0
- package/locales/pl-PL/chat.json +1 -0
- package/locales/pt-BR/chat.json +1 -0
- package/locales/ru-RU/chat.json +1 -0
- package/locales/tr-TR/chat.json +1 -0
- package/locales/vi-VN/chat.json +1 -0
- package/locales/zh-CN/chat.json +1 -0
- package/locales/zh-TW/chat.json +1 -0
- package/package.json +1 -1
- package/packages/database/src/models/__tests__/messages/message.create.test.ts +549 -0
- package/packages/database/src/models/__tests__/messages/message.delete.test.ts +481 -0
- package/packages/database/src/models/__tests__/messages/message.query.test.ts +1187 -0
- package/packages/database/src/models/__tests__/messages/message.stats.test.ts +633 -0
- package/packages/database/src/models/__tests__/messages/message.update.test.ts +757 -0
- package/packages/database/src/models/message.ts +5 -55
- package/packages/utils/src/clientIP.ts +6 -6
- package/packages/utils/src/compressImage.ts +3 -3
- package/packages/utils/src/fetch/fetchSSE.ts +15 -15
- package/packages/utils/src/format.ts +2 -2
- package/packages/utils/src/merge.ts +3 -3
- package/packages/utils/src/parseModels.ts +3 -3
- package/packages/utils/src/sanitizeUTF8.ts +4 -4
- package/packages/utils/src/toolManifest.ts +4 -4
- package/packages/utils/src/trace.test.ts +359 -0
- package/packages/utils/src/uriParser.ts +4 -4
- package/src/features/ChatItem/components/Title.tsx +20 -16
- package/src/features/Conversation/Messages/Assistant/index.tsx +3 -2
- package/src/features/Conversation/Messages/Group/index.tsx +10 -3
- package/src/server/services/message/index.ts +14 -4
- package/src/store/chat/slices/aiChat/actions/conversationLifecycle.ts +8 -2
- package/src/store/chat/slices/aiChat/actions/streamingExecutor.ts +1 -4
- package/src/store/chat/slices/message/actions/optimisticUpdate.ts +1 -1
- package/packages/database/src/models/__tests__/message.test.ts +0 -2632
|
@@ -0,0 +1,481 @@
|
|
|
1
|
+
import { eq } from 'drizzle-orm';
|
|
2
|
+
import { afterEach, beforeEach, describe, expect, it } from 'vitest';
|
|
3
|
+
|
|
4
|
+
import { uuid } from '@/utils/uuid';
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
chatGroups,
|
|
8
|
+
messagePlugins,
|
|
9
|
+
messageQueries,
|
|
10
|
+
messageTTS,
|
|
11
|
+
messageTranslates,
|
|
12
|
+
messages,
|
|
13
|
+
sessions,
|
|
14
|
+
topics,
|
|
15
|
+
users,
|
|
16
|
+
} from '../../../schemas';
|
|
17
|
+
import { LobeChatDatabase } from '../../../type';
|
|
18
|
+
import { MessageModel } from '../../message';
|
|
19
|
+
import { getTestDB } from '../_util';
|
|
20
|
+
import { codeEmbedding } from '../fixtures/embedding';
|
|
21
|
+
|
|
22
|
+
const serverDB: LobeChatDatabase = await getTestDB();
|
|
23
|
+
|
|
24
|
+
const userId = 'message-delete-test';
|
|
25
|
+
const otherUserId = 'message-delete-test-other';
|
|
26
|
+
const messageModel = new MessageModel(serverDB, userId);
|
|
27
|
+
const embeddingsId = uuid();
|
|
28
|
+
|
|
29
|
+
beforeEach(async () => {
|
|
30
|
+
// Clear tables before each test case
|
|
31
|
+
await serverDB.transaction(async (trx) => {
|
|
32
|
+
await trx.delete(users).where(eq(users.id, userId));
|
|
33
|
+
await trx.delete(users).where(eq(users.id, otherUserId));
|
|
34
|
+
await trx.insert(users).values([{ id: userId }, { id: otherUserId }]);
|
|
35
|
+
|
|
36
|
+
await trx.insert(sessions).values([{ id: '1', userId }]);
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
afterEach(async () => {
|
|
41
|
+
// Clear tables after each test case
|
|
42
|
+
await serverDB.delete(users).where(eq(users.id, userId));
|
|
43
|
+
await serverDB.delete(users).where(eq(users.id, otherUserId));
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
describe('MessageModel Delete Tests', () => {
|
|
47
|
+
describe('deleteMessage', () => {
|
|
48
|
+
it('should delete a message', async () => {
|
|
49
|
+
// Create test data
|
|
50
|
+
await serverDB
|
|
51
|
+
.insert(messages)
|
|
52
|
+
.values([{ id: '1', userId, role: 'user', content: 'message 1' }]);
|
|
53
|
+
|
|
54
|
+
// 调用 deleteMessage 方法
|
|
55
|
+
await messageModel.deleteMessage('1');
|
|
56
|
+
|
|
57
|
+
// Assert result
|
|
58
|
+
const result = await serverDB.select().from(messages).where(eq(messages.id, '1'));
|
|
59
|
+
expect(result).toHaveLength(0);
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it('should delete a message with tool calls', async () => {
|
|
63
|
+
// Create test data
|
|
64
|
+
await serverDB.transaction(async (trx) => {
|
|
65
|
+
await trx.insert(messages).values([
|
|
66
|
+
{ id: '1', userId, role: 'user', content: 'message 1', tools: [{ id: 'tool1' }] },
|
|
67
|
+
{ id: '2', userId, role: 'tool', content: 'message 1' },
|
|
68
|
+
]);
|
|
69
|
+
await trx
|
|
70
|
+
.insert(messagePlugins)
|
|
71
|
+
.values([{ id: '2', toolCallId: 'tool1', identifier: 'plugin-1', userId }]);
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
// 调用 deleteMessage 方法
|
|
75
|
+
await messageModel.deleteMessage('1');
|
|
76
|
+
|
|
77
|
+
// Assert result
|
|
78
|
+
const result = await serverDB.select().from(messages).where(eq(messages.id, '1'));
|
|
79
|
+
expect(result).toHaveLength(0);
|
|
80
|
+
|
|
81
|
+
const result2 = await serverDB
|
|
82
|
+
.select()
|
|
83
|
+
.from(messagePlugins)
|
|
84
|
+
.where(eq(messagePlugins.id, '2'));
|
|
85
|
+
|
|
86
|
+
expect(result2).toHaveLength(0);
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it('should only delete messages belonging to the user', async () => {
|
|
90
|
+
// Create test data
|
|
91
|
+
await serverDB
|
|
92
|
+
.insert(messages)
|
|
93
|
+
.values([{ id: '1', userId: otherUserId, role: 'user', content: 'message 1' }]);
|
|
94
|
+
|
|
95
|
+
// 调用 deleteMessage 方法
|
|
96
|
+
await messageModel.deleteMessage('1');
|
|
97
|
+
|
|
98
|
+
// Assert result
|
|
99
|
+
const result = await serverDB.select().from(messages).where(eq(messages.id, '1'));
|
|
100
|
+
expect(result).toHaveLength(1);
|
|
101
|
+
});
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
describe('deleteMessages', () => {
|
|
105
|
+
it('should delete 2 messages', async () => {
|
|
106
|
+
// Create test data
|
|
107
|
+
await serverDB.insert(messages).values([
|
|
108
|
+
{ id: '1', userId, role: 'user', content: 'message 1' },
|
|
109
|
+
{ id: '2', userId, role: 'user', content: 'message 2' },
|
|
110
|
+
]);
|
|
111
|
+
|
|
112
|
+
// 调用 deleteMessage 方法
|
|
113
|
+
await messageModel.deleteMessages(['1', '2']);
|
|
114
|
+
|
|
115
|
+
// Assert result
|
|
116
|
+
const result = await serverDB.select().from(messages).where(eq(messages.id, '1'));
|
|
117
|
+
expect(result).toHaveLength(0);
|
|
118
|
+
const result2 = await serverDB.select().from(messages).where(eq(messages.id, '2'));
|
|
119
|
+
expect(result2).toHaveLength(0);
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
it('should only delete messages belonging to the user', async () => {
|
|
123
|
+
// Create test data
|
|
124
|
+
await serverDB.insert(messages).values([
|
|
125
|
+
{ id: '1', userId: otherUserId, role: 'user', content: 'message 1' },
|
|
126
|
+
{ id: '2', userId: otherUserId, role: 'user', content: 'message 1' },
|
|
127
|
+
]);
|
|
128
|
+
|
|
129
|
+
// 调用 deleteMessage 方法
|
|
130
|
+
await messageModel.deleteMessages(['1', '2']);
|
|
131
|
+
|
|
132
|
+
// Assert result
|
|
133
|
+
const result = await serverDB.select().from(messages).where(eq(messages.id, '1'));
|
|
134
|
+
expect(result).toHaveLength(1);
|
|
135
|
+
});
|
|
136
|
+
});
|
|
137
|
+
describe('deleteMessageTranslate', () => {
|
|
138
|
+
it('should delete the message translate record', async () => {
|
|
139
|
+
// Create test data
|
|
140
|
+
await serverDB.insert(messages).values([{ id: '1', role: 'abc', userId }]);
|
|
141
|
+
await serverDB.insert(messageTranslates).values([{ id: '1', userId }]);
|
|
142
|
+
|
|
143
|
+
// 调用 deleteMessageTranslate 方法
|
|
144
|
+
await messageModel.deleteMessageTranslate('1');
|
|
145
|
+
|
|
146
|
+
// Assert result
|
|
147
|
+
const result = await serverDB
|
|
148
|
+
.select()
|
|
149
|
+
.from(messageTranslates)
|
|
150
|
+
.where(eq(messageTranslates.id, '1'));
|
|
151
|
+
|
|
152
|
+
expect(result).toHaveLength(0);
|
|
153
|
+
});
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
describe('deleteMessageTTS', () => {
|
|
157
|
+
it('should delete the message TTS record', async () => {
|
|
158
|
+
// Create test data
|
|
159
|
+
await serverDB.insert(messages).values([{ id: '1', role: 'abc', userId }]);
|
|
160
|
+
await serverDB.insert(messageTTS).values([{ userId, id: '1' }]);
|
|
161
|
+
|
|
162
|
+
// 调用 deleteMessageTTS 方法
|
|
163
|
+
await messageModel.deleteMessageTTS('1');
|
|
164
|
+
|
|
165
|
+
// Assert result
|
|
166
|
+
const result = await serverDB.select().from(messageTTS).where(eq(messageTTS.id, '1'));
|
|
167
|
+
expect(result).toHaveLength(0);
|
|
168
|
+
});
|
|
169
|
+
});
|
|
170
|
+
describe('deleteMessagesBySession', () => {
|
|
171
|
+
it('should delete messages by session ID', async () => {
|
|
172
|
+
await serverDB.insert(sessions).values([
|
|
173
|
+
{ id: 'session1', userId },
|
|
174
|
+
{ id: 'session2', userId },
|
|
175
|
+
]);
|
|
176
|
+
|
|
177
|
+
await serverDB.insert(messages).values([
|
|
178
|
+
{
|
|
179
|
+
id: '1',
|
|
180
|
+
userId,
|
|
181
|
+
sessionId: 'session1',
|
|
182
|
+
role: 'user',
|
|
183
|
+
content: 'message 1',
|
|
184
|
+
},
|
|
185
|
+
{
|
|
186
|
+
id: '2',
|
|
187
|
+
userId,
|
|
188
|
+
sessionId: 'session1',
|
|
189
|
+
role: 'assistant',
|
|
190
|
+
content: 'message 2',
|
|
191
|
+
},
|
|
192
|
+
{
|
|
193
|
+
id: '3',
|
|
194
|
+
userId,
|
|
195
|
+
sessionId: 'session2',
|
|
196
|
+
role: 'user',
|
|
197
|
+
content: 'message 3',
|
|
198
|
+
},
|
|
199
|
+
]);
|
|
200
|
+
|
|
201
|
+
await messageModel.deleteMessagesBySession('session1');
|
|
202
|
+
|
|
203
|
+
const remainingMessages = await serverDB
|
|
204
|
+
.select()
|
|
205
|
+
.from(messages)
|
|
206
|
+
.where(eq(messages.userId, userId));
|
|
207
|
+
|
|
208
|
+
expect(remainingMessages).toHaveLength(1);
|
|
209
|
+
expect(remainingMessages[0].id).toBe('3');
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
it('should delete messages by session ID and topic ID', async () => {
|
|
213
|
+
await serverDB.insert(sessions).values([{ id: 'session1', userId }]);
|
|
214
|
+
await serverDB.insert(topics).values([
|
|
215
|
+
{ id: 'topic1', sessionId: 'session1', userId },
|
|
216
|
+
{ id: 'topic2', sessionId: 'session1', userId },
|
|
217
|
+
]);
|
|
218
|
+
|
|
219
|
+
await serverDB.insert(messages).values([
|
|
220
|
+
{
|
|
221
|
+
id: '1',
|
|
222
|
+
userId,
|
|
223
|
+
sessionId: 'session1',
|
|
224
|
+
topicId: 'topic1',
|
|
225
|
+
role: 'user',
|
|
226
|
+
content: 'message 1',
|
|
227
|
+
},
|
|
228
|
+
{
|
|
229
|
+
id: '2',
|
|
230
|
+
userId,
|
|
231
|
+
sessionId: 'session1',
|
|
232
|
+
topicId: 'topic2',
|
|
233
|
+
role: 'assistant',
|
|
234
|
+
content: 'message 2',
|
|
235
|
+
},
|
|
236
|
+
]);
|
|
237
|
+
|
|
238
|
+
await messageModel.deleteMessagesBySession('session1', 'topic1');
|
|
239
|
+
|
|
240
|
+
const remainingMessages = await serverDB
|
|
241
|
+
.select()
|
|
242
|
+
.from(messages)
|
|
243
|
+
.where(eq(messages.userId, userId));
|
|
244
|
+
|
|
245
|
+
expect(remainingMessages).toHaveLength(1);
|
|
246
|
+
expect(remainingMessages[0].id).toBe('2');
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
it('should delete only non-topic messages when topicId is null', async () => {
|
|
250
|
+
await serverDB.insert(sessions).values([{ id: 'session1', userId }]);
|
|
251
|
+
await serverDB.insert(topics).values([
|
|
252
|
+
{ id: 'topic1', sessionId: 'session1', userId },
|
|
253
|
+
{ id: 'topic2', sessionId: 'session1', userId },
|
|
254
|
+
]);
|
|
255
|
+
|
|
256
|
+
await serverDB.insert(messages).values([
|
|
257
|
+
{
|
|
258
|
+
id: '1',
|
|
259
|
+
userId,
|
|
260
|
+
sessionId: 'session1',
|
|
261
|
+
topicId: null,
|
|
262
|
+
role: 'user',
|
|
263
|
+
content: 'message without topic 1',
|
|
264
|
+
},
|
|
265
|
+
{
|
|
266
|
+
id: '2',
|
|
267
|
+
userId,
|
|
268
|
+
sessionId: 'session1',
|
|
269
|
+
topicId: null,
|
|
270
|
+
role: 'assistant',
|
|
271
|
+
content: 'message without topic 2',
|
|
272
|
+
},
|
|
273
|
+
{
|
|
274
|
+
id: '3',
|
|
275
|
+
userId,
|
|
276
|
+
sessionId: 'session1',
|
|
277
|
+
topicId: 'topic1',
|
|
278
|
+
role: 'user',
|
|
279
|
+
content: 'message in topic1',
|
|
280
|
+
},
|
|
281
|
+
{
|
|
282
|
+
id: '4',
|
|
283
|
+
userId,
|
|
284
|
+
sessionId: 'session1',
|
|
285
|
+
topicId: 'topic2',
|
|
286
|
+
role: 'assistant',
|
|
287
|
+
content: 'message in topic2',
|
|
288
|
+
},
|
|
289
|
+
]);
|
|
290
|
+
|
|
291
|
+
// Delete messages in session1 with null topicId
|
|
292
|
+
await messageModel.deleteMessagesBySession('session1', null);
|
|
293
|
+
|
|
294
|
+
const remainingMessages = await serverDB
|
|
295
|
+
.select()
|
|
296
|
+
.from(messages)
|
|
297
|
+
.where(eq(messages.userId, userId))
|
|
298
|
+
.orderBy(messages.id);
|
|
299
|
+
|
|
300
|
+
// Should only keep messages with topics
|
|
301
|
+
expect(remainingMessages).toHaveLength(2);
|
|
302
|
+
expect(remainingMessages[0].id).toBe('3');
|
|
303
|
+
expect(remainingMessages[1].id).toBe('4');
|
|
304
|
+
});
|
|
305
|
+
|
|
306
|
+
it('should delete messages with specific groupId in session', async () => {
|
|
307
|
+
await serverDB.insert(sessions).values([{ id: 'session1', userId }]);
|
|
308
|
+
await serverDB.insert(chatGroups).values([
|
|
309
|
+
{ id: 'group1', userId, title: 'Group 1' },
|
|
310
|
+
{ id: 'group2', userId, title: 'Group 2' },
|
|
311
|
+
]);
|
|
312
|
+
|
|
313
|
+
await serverDB.insert(messages).values([
|
|
314
|
+
{
|
|
315
|
+
id: 'msg-group1',
|
|
316
|
+
userId,
|
|
317
|
+
sessionId: 'session1',
|
|
318
|
+
groupId: 'group1',
|
|
319
|
+
role: 'user',
|
|
320
|
+
content: 'message in group1',
|
|
321
|
+
},
|
|
322
|
+
{
|
|
323
|
+
id: 'msg-group2',
|
|
324
|
+
userId,
|
|
325
|
+
sessionId: 'session1',
|
|
326
|
+
groupId: 'group2',
|
|
327
|
+
role: 'assistant',
|
|
328
|
+
content: 'message in group2',
|
|
329
|
+
},
|
|
330
|
+
{
|
|
331
|
+
id: 'msg-no-group',
|
|
332
|
+
userId,
|
|
333
|
+
sessionId: 'session1',
|
|
334
|
+
groupId: null,
|
|
335
|
+
role: 'user',
|
|
336
|
+
content: 'message without group',
|
|
337
|
+
},
|
|
338
|
+
]);
|
|
339
|
+
|
|
340
|
+
// Delete messages with specific groupId
|
|
341
|
+
await messageModel.deleteMessagesBySession('session1', null, 'group1');
|
|
342
|
+
|
|
343
|
+
const remainingMessages = await serverDB
|
|
344
|
+
.select()
|
|
345
|
+
.from(messages)
|
|
346
|
+
.where(eq(messages.userId, userId))
|
|
347
|
+
.orderBy(messages.id);
|
|
348
|
+
|
|
349
|
+
expect(remainingMessages).toHaveLength(2);
|
|
350
|
+
expect(remainingMessages[0].id).toBe('msg-group2');
|
|
351
|
+
expect(remainingMessages[1].id).toBe('msg-no-group');
|
|
352
|
+
});
|
|
353
|
+
|
|
354
|
+
it('should delete messages with combined topicId and groupId filters', async () => {
|
|
355
|
+
await serverDB.insert(sessions).values([{ id: 'session1', userId }]);
|
|
356
|
+
await serverDB.insert(topics).values([{ id: 'topic1', sessionId: 'session1', userId }]);
|
|
357
|
+
await serverDB.insert(chatGroups).values([{ id: 'group1', userId, title: 'Group 1' }]);
|
|
358
|
+
|
|
359
|
+
await serverDB.insert(messages).values([
|
|
360
|
+
{
|
|
361
|
+
id: 'msg-t1-g1',
|
|
362
|
+
userId,
|
|
363
|
+
sessionId: 'session1',
|
|
364
|
+
topicId: 'topic1',
|
|
365
|
+
groupId: 'group1',
|
|
366
|
+
role: 'user',
|
|
367
|
+
content: 'topic1 group1',
|
|
368
|
+
},
|
|
369
|
+
{
|
|
370
|
+
id: 'msg-t1-no-group',
|
|
371
|
+
userId,
|
|
372
|
+
sessionId: 'session1',
|
|
373
|
+
topicId: 'topic1',
|
|
374
|
+
groupId: null,
|
|
375
|
+
role: 'user',
|
|
376
|
+
content: 'topic1 no group',
|
|
377
|
+
},
|
|
378
|
+
{
|
|
379
|
+
id: 'msg-no-topic-g1',
|
|
380
|
+
userId,
|
|
381
|
+
sessionId: 'session1',
|
|
382
|
+
topicId: null,
|
|
383
|
+
groupId: 'group1',
|
|
384
|
+
role: 'user',
|
|
385
|
+
content: 'no topic group1',
|
|
386
|
+
},
|
|
387
|
+
]);
|
|
388
|
+
|
|
389
|
+
// Delete messages with specific topic and group combination
|
|
390
|
+
await messageModel.deleteMessagesBySession('session1', 'topic1', 'group1');
|
|
391
|
+
|
|
392
|
+
const remainingMessages = await serverDB
|
|
393
|
+
.select()
|
|
394
|
+
.from(messages)
|
|
395
|
+
.where(eq(messages.userId, userId))
|
|
396
|
+
.orderBy(messages.id);
|
|
397
|
+
|
|
398
|
+
expect(remainingMessages).toHaveLength(2);
|
|
399
|
+
expect(remainingMessages[0].id).toBe('msg-no-topic-g1');
|
|
400
|
+
expect(remainingMessages[1].id).toBe('msg-t1-no-group');
|
|
401
|
+
});
|
|
402
|
+
});
|
|
403
|
+
describe('deleteMessageQuery', () => {
|
|
404
|
+
it('should delete a message query by ID', async () => {
|
|
405
|
+
// Create test data
|
|
406
|
+
const queryId = uuid();
|
|
407
|
+
await serverDB.insert(messages).values({
|
|
408
|
+
id: 'msg4',
|
|
409
|
+
userId,
|
|
410
|
+
role: 'user',
|
|
411
|
+
content: 'test message',
|
|
412
|
+
});
|
|
413
|
+
|
|
414
|
+
await serverDB.insert(messageQueries).values({
|
|
415
|
+
id: queryId,
|
|
416
|
+
messageId: 'msg4',
|
|
417
|
+
userQuery: 'test query',
|
|
418
|
+
rewriteQuery: 'rewritten query',
|
|
419
|
+
userId,
|
|
420
|
+
});
|
|
421
|
+
|
|
422
|
+
// 验证查询已创建
|
|
423
|
+
const beforeDelete = await serverDB
|
|
424
|
+
.select()
|
|
425
|
+
.from(messageQueries)
|
|
426
|
+
.where(eq(messageQueries.id, queryId));
|
|
427
|
+
|
|
428
|
+
expect(beforeDelete).toHaveLength(1);
|
|
429
|
+
|
|
430
|
+
// 调用 deleteMessageQuery 方法
|
|
431
|
+
await messageModel.deleteMessageQuery(queryId);
|
|
432
|
+
|
|
433
|
+
// 验证查询已删除
|
|
434
|
+
const afterDelete = await serverDB
|
|
435
|
+
.select()
|
|
436
|
+
.from(messageQueries)
|
|
437
|
+
.where(eq(messageQueries.id, queryId));
|
|
438
|
+
|
|
439
|
+
expect(afterDelete).toHaveLength(0);
|
|
440
|
+
});
|
|
441
|
+
|
|
442
|
+
it('should only delete message queries belonging to the user', async () => {
|
|
443
|
+
// Create test data - 其他用户的查询
|
|
444
|
+
const queryId = uuid();
|
|
445
|
+
await serverDB.insert(messages).values({
|
|
446
|
+
id: 'msg5',
|
|
447
|
+
userId: otherUserId,
|
|
448
|
+
role: 'user',
|
|
449
|
+
content: 'test message',
|
|
450
|
+
});
|
|
451
|
+
|
|
452
|
+
await serverDB.insert(messageQueries).values({
|
|
453
|
+
id: queryId,
|
|
454
|
+
messageId: 'msg5',
|
|
455
|
+
userQuery: 'test query',
|
|
456
|
+
rewriteQuery: 'rewritten query',
|
|
457
|
+
userId: otherUserId, // 其他用户
|
|
458
|
+
});
|
|
459
|
+
|
|
460
|
+
// 调用 deleteMessageQuery 方法
|
|
461
|
+
await messageModel.deleteMessageQuery(queryId);
|
|
462
|
+
|
|
463
|
+
// 验证查询未被删除
|
|
464
|
+
const afterDelete = await serverDB
|
|
465
|
+
.select()
|
|
466
|
+
.from(messageQueries)
|
|
467
|
+
.where(eq(messageQueries.id, queryId));
|
|
468
|
+
|
|
469
|
+
expect(afterDelete).toHaveLength(1);
|
|
470
|
+
});
|
|
471
|
+
|
|
472
|
+
it('should throw error when deleting non-existent message query', async () => {
|
|
473
|
+
// 调用 deleteMessageQuery 方法删除不存在的查询
|
|
474
|
+
try {
|
|
475
|
+
await messageModel.deleteMessageQuery('non-existent-id');
|
|
476
|
+
} catch (e) {
|
|
477
|
+
expect(e).toBeInstanceOf(Error);
|
|
478
|
+
}
|
|
479
|
+
});
|
|
480
|
+
});
|
|
481
|
+
});
|