@lobehub/chat 1.37.0 → 1.37.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.
- package/CHANGELOG.md +50 -0
- package/changelog/v1.json +18 -0
- package/locales/en-US/common.json +2 -2
- package/package.json +1 -1
- package/src/services/file/_deprecated.test.ts +119 -0
- package/src/services/file/{pglite.ts → _deprecated.ts} +28 -32
- package/src/services/file/client.test.ts +153 -74
- package/src/services/file/client.ts +32 -28
- package/src/services/file/index.ts +2 -2
- package/src/services/import/_deprecated.ts +74 -0
- package/src/services/import/{pglite.test.ts → client.test.ts} +1 -1
- package/src/services/import/client.ts +21 -61
- package/src/services/import/index.ts +2 -2
- package/src/services/message/_deprecated.test.ts +398 -0
- package/src/services/message/_deprecated.ts +121 -0
- package/src/services/message/client.test.ts +191 -159
- package/src/services/message/client.ts +47 -50
- package/src/services/message/index.ts +2 -2
- package/src/services/plugin/_deprecated.test.ts +162 -0
- package/src/services/plugin/_deprecated.ts +42 -0
- package/src/services/plugin/client.test.ts +68 -55
- package/src/services/plugin/client.ts +20 -11
- package/src/services/plugin/index.ts +2 -2
- package/src/services/session/_deprecated.test.ts +440 -0
- package/src/services/session/_deprecated.ts +183 -0
- package/src/services/session/client.test.ts +212 -241
- package/src/services/session/client.ts +61 -60
- package/src/services/session/index.ts +2 -2
- package/src/services/topic/{client.test.ts → _deprecated.test.ts} +1 -1
- package/src/services/topic/_deprecated.ts +70 -0
- package/src/services/topic/client.ts +40 -25
- package/src/services/topic/index.ts +2 -2
- package/src/services/topic/pglite.test.ts +1 -1
- package/src/services/user/{pglite.test.ts → _deprecated.test.ts} +32 -29
- package/src/services/user/_deprecated.ts +57 -0
- package/src/services/user/client.test.ts +28 -31
- package/src/services/user/client.ts +51 -16
- package/src/services/user/index.ts +2 -2
- package/src/store/chat/slices/builtinTool/action.test.ts +1 -1
- package/src/store/user/slices/common/action.test.ts +1 -1
- package/src/services/file/pglite.test.ts +0 -198
- package/src/services/import/pglite.ts +0 -34
- package/src/services/message/pglite.test.ts +0 -430
- package/src/services/message/pglite.ts +0 -118
- package/src/services/plugin/pglite.test.ts +0 -175
- package/src/services/plugin/pglite.ts +0 -51
- package/src/services/session/pglite.test.ts +0 -411
- package/src/services/session/pglite.ts +0 -184
- package/src/services/topic/pglite.ts +0 -85
- package/src/services/user/pglite.ts +0 -92
@@ -0,0 +1,121 @@
|
|
1
|
+
import dayjs from 'dayjs';
|
2
|
+
|
3
|
+
import { FileModel } from '@/database/_deprecated/models/file';
|
4
|
+
import { MessageModel } from '@/database/_deprecated/models/message';
|
5
|
+
import { DB_Message } from '@/database/_deprecated/schemas/message';
|
6
|
+
import {
|
7
|
+
ChatFileItem,
|
8
|
+
ChatMessage,
|
9
|
+
ChatMessageError,
|
10
|
+
ChatTTS,
|
11
|
+
ChatTranslate,
|
12
|
+
CreateMessageParams,
|
13
|
+
} from '@/types/message';
|
14
|
+
|
15
|
+
import { IMessageService } from './type';
|
16
|
+
|
17
|
+
export class ClientService implements IMessageService {
|
18
|
+
async createMessage(data: CreateMessageParams) {
|
19
|
+
const { id } = await MessageModel.create(data);
|
20
|
+
|
21
|
+
return id;
|
22
|
+
}
|
23
|
+
|
24
|
+
// @ts-ignore
|
25
|
+
async batchCreateMessages(messages: ChatMessage[]) {
|
26
|
+
return MessageModel.batchCreate(messages);
|
27
|
+
}
|
28
|
+
|
29
|
+
async getMessages(sessionId: string, topicId?: string): Promise<ChatMessage[]> {
|
30
|
+
const messages = await MessageModel.query({ sessionId, topicId });
|
31
|
+
|
32
|
+
const fileList = (await Promise.all(
|
33
|
+
messages
|
34
|
+
.flatMap((item) => item.files)
|
35
|
+
.filter(Boolean)
|
36
|
+
.map(async (id) => FileModel.findById(id!)),
|
37
|
+
)) as ChatFileItem[];
|
38
|
+
|
39
|
+
return messages.map((item) => ({
|
40
|
+
...item,
|
41
|
+
imageList: fileList
|
42
|
+
.filter((file) => item.files?.includes(file.id) && file.fileType.startsWith('image'))
|
43
|
+
.map((file) => ({
|
44
|
+
alt: file.name,
|
45
|
+
id: file.id,
|
46
|
+
url: file.url,
|
47
|
+
})),
|
48
|
+
}));
|
49
|
+
}
|
50
|
+
|
51
|
+
async getAllMessages() {
|
52
|
+
return MessageModel.queryAll();
|
53
|
+
}
|
54
|
+
|
55
|
+
async countMessages() {
|
56
|
+
return MessageModel.count();
|
57
|
+
}
|
58
|
+
|
59
|
+
async countTodayMessages() {
|
60
|
+
const topics = await MessageModel.queryAll();
|
61
|
+
return topics.filter(
|
62
|
+
(item) => dayjs(item.createdAt).format('YYYY-MM-DD') === dayjs().format('YYYY-MM-DD'),
|
63
|
+
).length;
|
64
|
+
}
|
65
|
+
|
66
|
+
async getAllMessagesInSession(sessionId: string) {
|
67
|
+
return MessageModel.queryBySessionId(sessionId);
|
68
|
+
}
|
69
|
+
|
70
|
+
async updateMessageError(id: string, error: ChatMessageError) {
|
71
|
+
return MessageModel.update(id, { error });
|
72
|
+
}
|
73
|
+
|
74
|
+
// @ts-ignore
|
75
|
+
async updateMessage(id: string, message: Partial<DB_Message>) {
|
76
|
+
return MessageModel.update(id, message);
|
77
|
+
}
|
78
|
+
|
79
|
+
async updateMessageTTS(id: string, tts: Partial<ChatTTS> | false) {
|
80
|
+
return MessageModel.update(id, { tts });
|
81
|
+
}
|
82
|
+
|
83
|
+
async updateMessageTranslate(id: string, translate: Partial<ChatTranslate> | false) {
|
84
|
+
return MessageModel.update(id, { translate });
|
85
|
+
}
|
86
|
+
|
87
|
+
async updateMessagePluginState(id: string, value: Record<string, any>) {
|
88
|
+
return MessageModel.updatePluginState(id, value);
|
89
|
+
}
|
90
|
+
|
91
|
+
async updateMessagePluginArguments(id: string, value: string | Record<string, any>) {
|
92
|
+
const args = typeof value === 'string' ? value : JSON.stringify(value);
|
93
|
+
|
94
|
+
return MessageModel.updatePlugin(id, { arguments: args });
|
95
|
+
}
|
96
|
+
|
97
|
+
async bindMessagesToTopic(topicId: string, messageIds: string[]) {
|
98
|
+
return MessageModel.batchUpdate(messageIds, { topicId });
|
99
|
+
}
|
100
|
+
|
101
|
+
async removeMessage(id: string) {
|
102
|
+
return MessageModel.delete(id);
|
103
|
+
}
|
104
|
+
|
105
|
+
async removeMessages(ids: string[]) {
|
106
|
+
return MessageModel.bulkDelete(ids);
|
107
|
+
}
|
108
|
+
|
109
|
+
async removeMessagesByAssistant(assistantId: string, topicId?: string) {
|
110
|
+
return MessageModel.batchDelete(assistantId, topicId);
|
111
|
+
}
|
112
|
+
|
113
|
+
async removeAllMessages() {
|
114
|
+
return MessageModel.clearTable();
|
115
|
+
}
|
116
|
+
|
117
|
+
async hasMessages() {
|
118
|
+
const number = await this.countMessages();
|
119
|
+
return number > 0;
|
120
|
+
}
|
121
|
+
}
|
@@ -1,133 +1,155 @@
|
|
1
1
|
import dayjs from 'dayjs';
|
2
|
-
import {
|
2
|
+
import { and, eq } from 'drizzle-orm';
|
3
|
+
import { Mock, afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
3
4
|
|
4
|
-
import {
|
5
|
+
import { MessageModel } from '@/database/_deprecated/models/message';
|
6
|
+
import { clientDB, initializeDB } from '@/database/client/db';
|
7
|
+
import {
|
8
|
+
MessageItem,
|
9
|
+
files,
|
10
|
+
messagePlugins,
|
11
|
+
messageTTS,
|
12
|
+
messageTranslates,
|
13
|
+
messages,
|
14
|
+
sessions,
|
15
|
+
topics,
|
16
|
+
users,
|
17
|
+
} from '@/database/schemas';
|
5
18
|
import {
|
6
19
|
ChatMessage,
|
7
20
|
ChatMessageError,
|
8
|
-
ChatPluginPayload,
|
9
21
|
ChatTTS,
|
10
22
|
ChatTranslate,
|
23
|
+
CreateMessageParams,
|
11
24
|
} from '@/types/message';
|
12
25
|
|
13
26
|
import { ClientService } from './client';
|
14
27
|
|
15
|
-
const
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
28
|
+
const userId = 'message-db';
|
29
|
+
const sessionId = '1';
|
30
|
+
const topicId = 'topic-id';
|
31
|
+
|
32
|
+
// Mock data
|
33
|
+
const mockMessageId = 'mock-message-id';
|
34
|
+
const mockMessage = {
|
35
|
+
id: mockMessageId,
|
36
|
+
content: 'Mock message content',
|
37
|
+
sessionId,
|
38
|
+
role: 'user',
|
39
|
+
} as ChatMessage;
|
40
|
+
|
41
|
+
const mockMessages = [mockMessage];
|
42
|
+
|
43
|
+
beforeEach(async () => {
|
44
|
+
await initializeDB();
|
45
|
+
|
46
|
+
// 在每个测试用例之前,清空表
|
47
|
+
await clientDB.transaction(async (trx) => {
|
48
|
+
await trx.delete(users);
|
49
|
+
await trx.insert(users).values([{ id: userId }, { id: '456' }]);
|
50
|
+
|
51
|
+
await trx.insert(sessions).values([{ id: sessionId, userId }]);
|
52
|
+
await trx.insert(topics).values([{ id: topicId, sessionId, userId }]);
|
53
|
+
await trx.insert(files).values({
|
54
|
+
id: 'f1',
|
55
|
+
userId: userId,
|
56
|
+
url: 'abc',
|
57
|
+
name: 'file-1',
|
58
|
+
fileType: 'image/png',
|
59
|
+
size: 1000,
|
60
|
+
});
|
61
|
+
});
|
37
62
|
});
|
38
63
|
|
39
|
-
|
40
|
-
//
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
sessionId: 'mock-session-id',
|
46
|
-
createdAt: 100,
|
47
|
-
updatedAt: 100,
|
48
|
-
role: 'user',
|
49
|
-
// ... other properties
|
50
|
-
} as ChatMessage;
|
51
|
-
const mockMessages = [mockMessage];
|
52
|
-
|
53
|
-
beforeEach(() => {
|
54
|
-
// Reset all mocks before running each test case
|
55
|
-
vi.resetAllMocks();
|
56
|
-
});
|
64
|
+
afterEach(async () => {
|
65
|
+
// 在每个测试用例之后,清空表
|
66
|
+
await clientDB.delete(users);
|
67
|
+
});
|
68
|
+
|
69
|
+
const messageService = new ClientService(userId);
|
57
70
|
|
71
|
+
describe('MessageClientService', () => {
|
58
72
|
describe('create', () => {
|
59
73
|
it('should create a message and return its id', async () => {
|
60
74
|
// Setup
|
61
|
-
const createParams = {
|
75
|
+
const createParams: CreateMessageParams = {
|
62
76
|
content: 'New message content',
|
63
|
-
sessionId
|
64
|
-
|
65
|
-
}
|
66
|
-
(MessageModel.create as Mock).mockResolvedValue({ id: mockMessageId });
|
77
|
+
sessionId,
|
78
|
+
role: 'user',
|
79
|
+
};
|
67
80
|
|
68
81
|
// Execute
|
69
82
|
const messageId = await messageService.createMessage(createParams);
|
70
83
|
|
71
84
|
// Assert
|
72
|
-
expect(
|
73
|
-
expect(messageId).toBe(mockMessageId);
|
85
|
+
expect(messageId).toMatch(/^msg_/);
|
74
86
|
});
|
75
87
|
});
|
76
88
|
|
77
89
|
describe('batchCreate', () => {
|
78
90
|
it('should batch create messages', async () => {
|
79
|
-
// Setup
|
80
|
-
(MessageModel.batchCreate as Mock).mockResolvedValue(mockMessages);
|
81
|
-
|
82
91
|
// Execute
|
83
|
-
|
92
|
+
await messageService.batchCreateMessages([
|
93
|
+
{
|
94
|
+
content: 'Mock message content',
|
95
|
+
sessionId,
|
96
|
+
role: 'user',
|
97
|
+
},
|
98
|
+
{
|
99
|
+
content: 'Mock message content',
|
100
|
+
sessionId,
|
101
|
+
role: 'user',
|
102
|
+
},
|
103
|
+
] as MessageItem[]);
|
104
|
+
const count = await clientDB.$count(messages);
|
84
105
|
|
85
106
|
// Assert
|
86
|
-
expect(
|
87
|
-
expect(result).toBe(mockMessages);
|
107
|
+
expect(count).toBe(2);
|
88
108
|
});
|
89
109
|
});
|
90
110
|
|
91
111
|
describe('removeMessage', () => {
|
92
112
|
it('should remove a message by id', async () => {
|
93
|
-
// Setup
|
94
|
-
(MessageModel.delete as Mock).mockResolvedValue(true);
|
95
|
-
|
96
113
|
// Execute
|
97
|
-
|
114
|
+
await clientDB.insert(messages).values({ id: mockMessageId, role: 'user', userId });
|
115
|
+
await messageService.removeMessage(mockMessageId);
|
98
116
|
|
99
117
|
// Assert
|
100
|
-
|
101
|
-
|
118
|
+
const count = await clientDB.$count(messages);
|
119
|
+
|
120
|
+
expect(count).toBe(0);
|
102
121
|
});
|
103
122
|
});
|
104
123
|
describe('removeMessages', () => {
|
105
124
|
it('should remove a message by id', async () => {
|
106
125
|
// Setup
|
107
|
-
(
|
126
|
+
await clientDB.insert(messages).values([
|
127
|
+
{ id: mockMessageId, role: 'user', userId },
|
128
|
+
{ role: 'assistant', userId },
|
129
|
+
]);
|
108
130
|
|
109
131
|
// Execute
|
110
|
-
|
132
|
+
await messageService.removeMessages([mockMessageId]);
|
111
133
|
|
112
134
|
// Assert
|
113
|
-
|
114
|
-
|
135
|
+
const count = await clientDB.$count(messages);
|
136
|
+
|
137
|
+
expect(count).toBe(1);
|
115
138
|
});
|
116
139
|
});
|
117
140
|
|
118
141
|
describe('getMessages', () => {
|
119
142
|
it('should retrieve messages by sessionId and topicId', async () => {
|
120
143
|
// Setup
|
121
|
-
|
122
|
-
|
123
|
-
|
144
|
+
await clientDB
|
145
|
+
.insert(messages)
|
146
|
+
.values({ id: mockMessageId, sessionId, topicId, role: 'user', userId });
|
124
147
|
|
125
148
|
// Execute
|
126
|
-
const
|
149
|
+
const data = await messageService.getMessages(sessionId, topicId);
|
127
150
|
|
128
151
|
// Assert
|
129
|
-
expect(
|
130
|
-
expect(messages).toEqual(mockMessages.map((i) => ({ ...i, imageList: [] })));
|
152
|
+
expect(data[0]).toMatchObject({ id: mockMessageId, role: 'user' });
|
131
153
|
});
|
132
154
|
});
|
133
155
|
|
@@ -135,14 +157,21 @@ describe('MessageClientService', () => {
|
|
135
157
|
it('should retrieve all messages in a session', async () => {
|
136
158
|
// Setup
|
137
159
|
const sessionId = 'session-id';
|
138
|
-
(
|
160
|
+
await clientDB.insert(sessions).values([
|
161
|
+
{ id: 'bbb', userId },
|
162
|
+
{ id: sessionId, userId },
|
163
|
+
]);
|
164
|
+
await clientDB.insert(messages).values([
|
165
|
+
{ sessionId, topicId, role: 'user', userId },
|
166
|
+
{ sessionId, topicId, role: 'assistant', userId },
|
167
|
+
{ sessionId: 'bbb', topicId, role: 'assistant', userId },
|
168
|
+
]);
|
139
169
|
|
140
170
|
// Execute
|
141
|
-
const
|
171
|
+
const data = await messageService.getAllMessagesInSession(sessionId);
|
142
172
|
|
143
173
|
// Assert
|
144
|
-
expect(
|
145
|
-
expect(messages).toBe(mockMessages);
|
174
|
+
expect(data.length).toBe(2);
|
146
175
|
});
|
147
176
|
});
|
148
177
|
|
@@ -150,77 +179,85 @@ describe('MessageClientService', () => {
|
|
150
179
|
it('should batch remove messages by assistantId and topicId', async () => {
|
151
180
|
// Setup
|
152
181
|
const assistantId = 'assistant-id';
|
153
|
-
const
|
154
|
-
(
|
182
|
+
const sessionId = 'session-id';
|
183
|
+
await clientDB.insert(sessions).values([
|
184
|
+
{ id: 'bbb', userId },
|
185
|
+
{ id: sessionId, userId },
|
186
|
+
]);
|
187
|
+
await clientDB.insert(messages).values([
|
188
|
+
{ sessionId, topicId, role: 'user', userId },
|
189
|
+
{ sessionId, topicId, role: 'assistant', userId },
|
190
|
+
{ sessionId: 'bbb', topicId, role: 'assistant', userId },
|
191
|
+
]);
|
155
192
|
|
156
193
|
// Execute
|
157
|
-
|
194
|
+
await messageService.removeMessagesByAssistant(sessionId, topicId);
|
158
195
|
|
159
196
|
// Assert
|
160
|
-
|
161
|
-
|
197
|
+
const result = await clientDB.query.messages.findMany({
|
198
|
+
where: and(eq(messages.sessionId, sessionId), eq(messages.topicId, topicId)),
|
199
|
+
});
|
200
|
+
|
201
|
+
expect(result.length).toBe(0);
|
162
202
|
});
|
163
203
|
});
|
164
204
|
|
165
205
|
describe('clearAllMessage', () => {
|
166
206
|
it('should clear all messages from the table', async () => {
|
167
207
|
// Setup
|
168
|
-
(
|
208
|
+
await clientDB.insert(users).values({ id: 'another' });
|
209
|
+
await clientDB.insert(messages).values([
|
210
|
+
{ id: mockMessageId, role: 'user', userId },
|
211
|
+
{ role: 'user', userId: 'another' },
|
212
|
+
]);
|
169
213
|
|
170
214
|
// Execute
|
171
|
-
|
215
|
+
await messageService.removeAllMessages();
|
172
216
|
|
173
217
|
// Assert
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
describe('bindMessagesToTopic', () => {
|
180
|
-
it('should batch update messages to bind them to a topic', async () => {
|
181
|
-
// Setup
|
182
|
-
const topicId = 'topic-id';
|
183
|
-
const messageIds = [mockMessageId];
|
184
|
-
(MessageModel.batchUpdate as Mock).mockResolvedValue(mockMessages);
|
185
|
-
|
186
|
-
// Execute
|
187
|
-
const result = await messageService.bindMessagesToTopic(topicId, messageIds);
|
188
|
-
|
189
|
-
// Assert
|
190
|
-
expect(MessageModel.batchUpdate).toHaveBeenCalledWith(messageIds, { topicId });
|
191
|
-
expect(result).toBe(mockMessages);
|
218
|
+
const result = await clientDB.query.messages.findMany({
|
219
|
+
where: eq(messages.userId, userId),
|
220
|
+
});
|
221
|
+
expect(result.length).toBe(0);
|
192
222
|
});
|
193
223
|
});
|
194
224
|
|
195
225
|
describe('getAllMessages', () => {
|
196
226
|
it('should retrieve all messages', async () => {
|
197
|
-
|
198
|
-
|
227
|
+
await clientDB.insert(messages).values([
|
228
|
+
{ sessionId, topicId, content: '1', role: 'user', userId },
|
229
|
+
{ sessionId, topicId, content: '2', role: 'assistant', userId },
|
230
|
+
]);
|
199
231
|
|
200
232
|
// Execute
|
201
|
-
const
|
233
|
+
const data = await messageService.getAllMessages();
|
202
234
|
|
203
235
|
// Assert
|
204
|
-
expect(
|
205
|
-
|
236
|
+
expect(data).toMatchObject([
|
237
|
+
{ sessionId, topicId, content: '1', role: 'user', userId },
|
238
|
+
{ sessionId, topicId, content: '2', role: 'assistant', userId },
|
239
|
+
]);
|
206
240
|
});
|
207
241
|
});
|
208
242
|
|
209
243
|
describe('updateMessageError', () => {
|
210
244
|
it('should update the error field of a message', async () => {
|
211
245
|
// Setup
|
246
|
+
await clientDB.insert(messages).values({ id: mockMessageId, role: 'user', userId });
|
212
247
|
const newError = {
|
213
248
|
type: 'InvalidProviderAPIKey',
|
214
249
|
message: 'Error occurred',
|
215
250
|
} as ChatMessageError;
|
216
|
-
(MessageModel.update as Mock).mockResolvedValue({ ...mockMessage, error: newError });
|
217
251
|
|
218
252
|
// Execute
|
219
|
-
|
253
|
+
await messageService.updateMessageError(mockMessageId, newError);
|
220
254
|
|
221
255
|
// Assert
|
222
|
-
|
223
|
-
|
256
|
+
const result = await clientDB.query.messages.findFirst({
|
257
|
+
where: eq(messages.id, mockMessageId),
|
258
|
+
});
|
259
|
+
|
260
|
+
expect(result!.error).toEqual(newError);
|
224
261
|
});
|
225
262
|
});
|
226
263
|
|
@@ -248,88 +285,85 @@ describe('MessageClientService', () => {
|
|
248
285
|
describe('updateMessagePluginState', () => {
|
249
286
|
it('should update the plugin state of a message', async () => {
|
250
287
|
// Setup
|
288
|
+
await clientDB.insert(messages).values({ id: mockMessageId, role: 'user', userId });
|
289
|
+
await clientDB.insert(messagePlugins).values({ id: mockMessageId });
|
251
290
|
const key = 'stateKey';
|
252
291
|
const value = 'stateValue';
|
253
292
|
const newPluginState = { [key]: value };
|
254
|
-
(MessageModel.updatePluginState as Mock).mockResolvedValue({
|
255
|
-
...mockMessage,
|
256
|
-
pluginState: newPluginState,
|
257
|
-
});
|
258
293
|
|
259
294
|
// Execute
|
260
|
-
|
295
|
+
await messageService.updateMessagePluginState(mockMessageId, { stateKey: value });
|
261
296
|
|
262
297
|
// Assert
|
263
|
-
|
264
|
-
|
298
|
+
const result = await clientDB.query.messagePlugins.findFirst({
|
299
|
+
where: eq(messagePlugins.id, mockMessageId),
|
300
|
+
});
|
301
|
+
expect(result!.state).toEqual(newPluginState);
|
265
302
|
});
|
266
303
|
});
|
267
304
|
|
268
305
|
describe('updateMessagePluginArguments', () => {
|
269
306
|
it('should update the plugin arguments object of a message', async () => {
|
270
307
|
// Setup
|
271
|
-
|
308
|
+
await clientDB.insert(messages).values({ id: mockMessageId, role: 'user', userId });
|
309
|
+
await clientDB.insert(messagePlugins).values({ id: mockMessageId });
|
272
310
|
const value = 'stateValue';
|
273
|
-
(MessageModel.updatePlugin as Mock).mockResolvedValue({});
|
274
311
|
|
275
312
|
// Execute
|
276
313
|
await messageService.updateMessagePluginArguments(mockMessageId, { key: value });
|
277
314
|
|
278
315
|
// Assert
|
279
|
-
|
280
|
-
|
316
|
+
const result = await clientDB.query.messagePlugins.findFirst({
|
317
|
+
where: eq(messageTTS.id, mockMessageId),
|
281
318
|
});
|
319
|
+
expect(result).toMatchObject({ arguments: '{"key":"stateValue"}' });
|
282
320
|
});
|
283
321
|
it('should update the plugin arguments string of a message', async () => {
|
284
322
|
// Setup
|
285
|
-
|
323
|
+
await clientDB.insert(messages).values({ id: mockMessageId, role: 'user', userId });
|
324
|
+
await clientDB.insert(messagePlugins).values({ id: mockMessageId });
|
286
325
|
const value = 'stateValue';
|
287
|
-
(MessageModel.updatePlugin as Mock).mockResolvedValue({});
|
288
|
-
|
289
326
|
// Execute
|
290
327
|
await messageService.updateMessagePluginArguments(
|
291
328
|
mockMessageId,
|
292
|
-
JSON.stringify({
|
329
|
+
JSON.stringify({ abc: value }),
|
293
330
|
);
|
294
331
|
|
295
332
|
// Assert
|
296
|
-
|
297
|
-
|
333
|
+
const result = await clientDB.query.messagePlugins.findFirst({
|
334
|
+
where: eq(messageTTS.id, mockMessageId),
|
298
335
|
});
|
336
|
+
expect(result).toMatchObject({ arguments: '{"abc":"stateValue"}' });
|
299
337
|
});
|
300
338
|
});
|
301
339
|
|
302
340
|
describe('countMessages', () => {
|
303
341
|
it('should count the total number of messages', async () => {
|
304
342
|
// Setup
|
305
|
-
|
306
|
-
(MessageModel.count as Mock).mockResolvedValue(mockCount);
|
343
|
+
await clientDB.insert(messages).values({ id: mockMessageId, role: 'user', userId });
|
307
344
|
|
308
345
|
// Execute
|
309
346
|
const count = await messageService.countMessages();
|
310
347
|
|
311
348
|
// Assert
|
312
|
-
expect(
|
313
|
-
expect(count).toBe(mockCount);
|
349
|
+
expect(count).toBe(1);
|
314
350
|
});
|
315
351
|
});
|
316
352
|
|
317
353
|
describe('countTodayMessages', () => {
|
318
354
|
it('should count the number of messages created today', async () => {
|
319
355
|
// Setup
|
320
|
-
const today = dayjs().format('YYYY-MM-DD');
|
321
356
|
const mockMessages = [
|
322
|
-
{ ...mockMessage, createdAt:
|
323
|
-
{ ...mockMessage, createdAt:
|
324
|
-
{ ...mockMessage, createdAt: '2023-01-01' },
|
357
|
+
{ ...mockMessage, id: undefined, createdAt: new Date(), userId },
|
358
|
+
{ ...mockMessage, id: undefined, createdAt: new Date(), userId },
|
359
|
+
{ ...mockMessage, id: undefined, createdAt: new Date('2023-01-01'), userId },
|
325
360
|
];
|
326
|
-
(
|
361
|
+
await clientDB.insert(messages).values(mockMessages);
|
327
362
|
|
328
363
|
// Execute
|
329
364
|
const count = await messageService.countTodayMessages();
|
330
365
|
|
331
366
|
// Assert
|
332
|
-
expect(MessageModel.queryAll).toHaveBeenCalled();
|
333
367
|
expect(count).toBe(2);
|
334
368
|
});
|
335
369
|
});
|
@@ -337,45 +371,46 @@ describe('MessageClientService', () => {
|
|
337
371
|
describe('updateMessageTTS', () => {
|
338
372
|
it('should update the TTS field of a message', async () => {
|
339
373
|
// Setup
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
};
|
344
|
-
|
345
|
-
(MessageModel.update as Mock).mockResolvedValue({ ...mockMessage, tts: newTTS });
|
374
|
+
await clientDB
|
375
|
+
.insert(files)
|
376
|
+
.values({ id: 'file-abc', fileType: 'text', name: 'abc', url: 'abc', size: 100, userId });
|
377
|
+
await clientDB.insert(messages).values({ id: mockMessageId, role: 'user', userId });
|
378
|
+
const newTTS: ChatTTS = { contentMd5: 'abc', file: 'file-abc' };
|
346
379
|
|
347
380
|
// Execute
|
348
|
-
|
381
|
+
await messageService.updateMessageTTS(mockMessageId, newTTS);
|
349
382
|
|
350
383
|
// Assert
|
351
|
-
|
352
|
-
|
384
|
+
const result = await clientDB.query.messageTTS.findFirst({
|
385
|
+
where: eq(messageTTS.id, mockMessageId),
|
386
|
+
});
|
387
|
+
|
388
|
+
expect(result).toMatchObject({ contentMd5: 'abc', fileId: 'file-abc', id: mockMessageId });
|
353
389
|
});
|
354
390
|
});
|
355
391
|
|
356
392
|
describe('updateMessageTranslate', () => {
|
357
393
|
it('should update the translate field of a message', async () => {
|
358
394
|
// Setup
|
359
|
-
|
360
|
-
|
361
|
-
to: 'es',
|
362
|
-
};
|
363
|
-
|
364
|
-
(MessageModel.update as Mock).mockResolvedValue({ ...mockMessage, translate: newTranslate });
|
395
|
+
await clientDB.insert(messages).values({ id: mockMessageId, role: 'user', userId });
|
396
|
+
const newTranslate: ChatTranslate = { content: 'Translated text', to: 'es' };
|
365
397
|
|
366
398
|
// Execute
|
367
|
-
|
399
|
+
await messageService.updateMessageTranslate(mockMessageId, newTranslate);
|
368
400
|
|
369
401
|
// Assert
|
370
|
-
|
371
|
-
|
402
|
+
const result = await clientDB.query.messageTranslates.findFirst({
|
403
|
+
where: eq(messageTranslates.id, mockMessageId),
|
404
|
+
});
|
405
|
+
|
406
|
+
expect(result).toMatchObject(newTranslate);
|
372
407
|
});
|
373
408
|
});
|
374
409
|
|
375
410
|
describe('hasMessages', () => {
|
376
411
|
it('should return true if there are messages', async () => {
|
377
412
|
// Setup
|
378
|
-
(
|
413
|
+
await clientDB.insert(messages).values({ id: mockMessageId, role: 'user', userId });
|
379
414
|
|
380
415
|
// Execute
|
381
416
|
const result = await messageService.hasMessages();
|
@@ -385,9 +420,6 @@ describe('MessageClientService', () => {
|
|
385
420
|
});
|
386
421
|
|
387
422
|
it('should return false if there are no messages', async () => {
|
388
|
-
// Setup
|
389
|
-
(MessageModel.count as Mock).mockResolvedValue(0);
|
390
|
-
|
391
423
|
// Execute
|
392
424
|
const result = await messageService.hasMessages();
|
393
425
|
|