@lobehub/chat 1.71.5 → 1.72.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.
- package/CHANGELOG.md +25 -0
- package/changelog/v1.json +9 -0
- package/docs/developer/database-schema.dbml +16 -0
- package/package.json +3 -3
- package/src/database/client/db.ts +14 -8
- package/src/database/client/migrations.json +62 -0
- package/src/database/migrations/0017_add_user_id_to_tables.sql +225 -0
- package/src/database/migrations/meta/0017_snapshot.json +3858 -0
- package/src/database/migrations/meta/_journal.json +7 -0
- package/src/database/{server/models → models}/__tests__/_test_template.ts +2 -2
- package/src/database/models/__tests__/_util.ts +12 -0
- package/src/database/{server/models → models}/__tests__/agent.test.ts +6 -5
- package/src/database/{server/models → models}/__tests__/aiModel.test.ts +5 -4
- package/src/database/{server/models → models}/__tests__/aiProvider.test.ts +5 -4
- package/src/database/{server/models → models}/__tests__/asyncTask.test.ts +5 -4
- package/src/database/{server/models → models}/__tests__/chunk.test.ts +25 -21
- package/src/database/{server/models → models}/__tests__/file.test.ts +19 -5
- package/src/database/{server/models → models}/__tests__/knowledgeBase.test.ts +9 -4
- package/src/database/{server/models → models}/__tests__/message.test.ts +625 -29
- package/src/database/{server/models → models}/__tests__/plugin.test.ts +5 -4
- package/src/database/{server/models → models}/__tests__/session.test.ts +23 -20
- package/src/database/{server/models → models}/__tests__/sessionGroup.test.ts +5 -4
- package/src/database/{server/models → models}/__tests__/topic.test.ts +5 -4
- package/src/database/repositories/dataImporter/index.ts +3 -0
- package/src/database/schemas/file.ts +38 -32
- package/src/database/schemas/message.ts +21 -0
- package/src/database/schemas/relations.ts +10 -0
- package/src/database/server/models/__tests__/nextauth.test.ts +2 -0
- package/src/database/server/models/__tests__/user.test.ts +13 -1
- package/src/database/server/models/chunk.ts +5 -1
- package/src/database/server/models/file.ts +6 -3
- package/src/database/server/models/message.ts +29 -12
- package/src/database/server/models/session.ts +1 -0
- package/src/services/file/client.test.ts +2 -1
- package/src/services/message/client.test.ts +3 -3
- package/src/services/session/client.test.ts +5 -3
- package/src/types/message/base.ts +7 -0
- package/vitest.server.config.ts +1 -1
- package/src/database/server/models/user.test.ts +0 -58
- /package/src/database/{server/models → models}/__tests__/fixtures/embedding.ts +0 -0
@@ -119,6 +119,13 @@
|
|
119
119
|
"when": 1741844738677,
|
120
120
|
"tag": "0016_add_message_index",
|
121
121
|
"breakpoints": true
|
122
|
+
},
|
123
|
+
{
|
124
|
+
"idx": 17,
|
125
|
+
"version": "7",
|
126
|
+
"when": 1742269437903,
|
127
|
+
"tag": "0017_add_user_id_to_tables",
|
128
|
+
"breakpoints": true
|
122
129
|
}
|
123
130
|
],
|
124
131
|
"version": "6"
|
@@ -4,8 +4,8 @@ import { afterEach, beforeEach, describe, expect, it } from 'vitest';
|
|
4
4
|
|
5
5
|
import { getTestDBInstance } from '@/database/server/core/dbForTest';
|
6
6
|
|
7
|
-
import { sessionGroups, users } from '
|
8
|
-
import { SessionGroupModel } from '
|
7
|
+
import { sessionGroups, users } from '../../schemas';
|
8
|
+
import { SessionGroupModel } from '../../server/models/sessionGroup';
|
9
9
|
|
10
10
|
let serverDB = await getTestDBInstance();
|
11
11
|
|
@@ -0,0 +1,12 @@
|
|
1
|
+
import { clientDB, initializeDB } from '@/database/client/db';
|
2
|
+
import { getTestDBInstance } from '@/database/server/core/dbForTest';
|
3
|
+
import { LobeChatDatabase } from '@/database/type';
|
4
|
+
|
5
|
+
export const isServerDBMode = process.env.TEST_SERVER_DB === '1';
|
6
|
+
|
7
|
+
export const getTestDB = async () => {
|
8
|
+
if (isServerDBMode) return await getTestDBInstance();
|
9
|
+
|
10
|
+
await initializeDB();
|
11
|
+
return clientDB as LobeChatDatabase;
|
12
|
+
};
|
@@ -2,7 +2,7 @@
|
|
2
2
|
import { eq } from 'drizzle-orm/expressions';
|
3
3
|
import { afterEach, beforeEach, describe, expect, it } from 'vitest';
|
4
4
|
|
5
|
-
import {
|
5
|
+
import { LobeChatDatabase } from '@/database/type';
|
6
6
|
|
7
7
|
import {
|
8
8
|
agents,
|
@@ -13,10 +13,11 @@ import {
|
|
13
13
|
knowledgeBases,
|
14
14
|
sessions,
|
15
15
|
users,
|
16
|
-
} from '
|
17
|
-
import { AgentModel } from '
|
16
|
+
} from '../../schemas';
|
17
|
+
import { AgentModel } from '../../server/models/agent';
|
18
|
+
import { getTestDB } from './_util';
|
18
19
|
|
19
|
-
|
20
|
+
const serverDB: LobeChatDatabase = await getTestDB();
|
20
21
|
|
21
22
|
const userId = 'agent-model-test-user-id';
|
22
23
|
const agentModel = new AgentModel(serverDB, userId);
|
@@ -77,7 +78,7 @@ describe('AgentModel', () => {
|
|
77
78
|
const sessionId = 'test-session-id';
|
78
79
|
await serverDB.insert(agents).values({ id: agentId, userId });
|
79
80
|
await serverDB.insert(sessions).values({ id: sessionId, userId });
|
80
|
-
await serverDB.insert(agentsToSessions).values({ agentId, sessionId });
|
81
|
+
await serverDB.insert(agentsToSessions).values({ agentId, sessionId, userId });
|
81
82
|
|
82
83
|
const result = await agentModel.findBySessionId(sessionId);
|
83
84
|
|
@@ -2,13 +2,14 @@
|
|
2
2
|
import { eq } from 'drizzle-orm/expressions';
|
3
3
|
import { afterEach, beforeEach, describe, expect, it } from 'vitest';
|
4
4
|
|
5
|
-
import {
|
5
|
+
import { LobeChatDatabase } from '@/database/type';
|
6
6
|
import { AiProviderModelListItem } from '@/types/aiModel';
|
7
7
|
|
8
|
-
import { AiModelSelectItem, NewAiModelItem, aiModels, users } from '
|
9
|
-
import { AiModelModel } from '
|
8
|
+
import { AiModelSelectItem, NewAiModelItem, aiModels, users } from '../../schemas';
|
9
|
+
import { AiModelModel } from '../../server/models/aiModel';
|
10
|
+
import { getTestDB } from './_util';
|
10
11
|
|
11
|
-
|
12
|
+
const serverDB: LobeChatDatabase = await getTestDB();
|
12
13
|
|
13
14
|
const userId = 'ai-model-test-user-id';
|
14
15
|
const aiProviderModel = new AiModelModel(serverDB, userId);
|
@@ -2,13 +2,14 @@
|
|
2
2
|
import { eq } from 'drizzle-orm/expressions';
|
3
3
|
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
4
4
|
|
5
|
-
import {
|
5
|
+
import { LobeChatDatabase } from '@/database/type';
|
6
6
|
import { ModelProvider } from '@/libs/agent-runtime';
|
7
7
|
|
8
|
-
import { aiProviders, users } from '
|
9
|
-
import { AiProviderModel } from '
|
8
|
+
import { aiProviders, users } from '../../schemas';
|
9
|
+
import { AiProviderModel } from '../../server/models/aiProvider';
|
10
|
+
import { getTestDB } from './_util';
|
10
11
|
|
11
|
-
|
12
|
+
const serverDB: LobeChatDatabase = await getTestDB();
|
12
13
|
|
13
14
|
const userId = 'session-group-model-test-user-id';
|
14
15
|
const aiProviderModel = new AiProviderModel(serverDB, userId);
|
@@ -2,13 +2,14 @@
|
|
2
2
|
import { eq } from 'drizzle-orm/expressions';
|
3
3
|
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
4
4
|
|
5
|
-
import {
|
5
|
+
import { LobeChatDatabase } from '@/database/type';
|
6
6
|
import { AsyncTaskStatus, AsyncTaskType } from '@/types/asyncTask';
|
7
7
|
|
8
|
-
import { asyncTasks, users } from '
|
9
|
-
import { ASYNC_TASK_TIMEOUT, AsyncTaskModel } from '
|
8
|
+
import { asyncTasks, users } from '../../schemas';
|
9
|
+
import { ASYNC_TASK_TIMEOUT, AsyncTaskModel } from '../../server/models/asyncTask';
|
10
|
+
import { getTestDB } from './_util';
|
10
11
|
|
11
|
-
|
12
|
+
const serverDB: LobeChatDatabase = await getTestDB();
|
12
13
|
|
13
14
|
const userId = 'async-task-model-test-user-id';
|
14
15
|
const asyncTaskModel = new AsyncTaskModel(serverDB, userId);
|
@@ -2,14 +2,15 @@
|
|
2
2
|
import { eq } from 'drizzle-orm/expressions';
|
3
3
|
import { afterEach, beforeEach, describe, expect, it } from 'vitest';
|
4
4
|
|
5
|
-
import {
|
5
|
+
import { LobeChatDatabase } from '@/database/type';
|
6
6
|
import { uuid } from '@/utils/uuid';
|
7
7
|
|
8
|
-
import { chunks, embeddings, fileChunks, files, unstructuredChunks, users } from '
|
9
|
-
import { ChunkModel } from '
|
8
|
+
import { chunks, embeddings, fileChunks, files, unstructuredChunks, users } from '../../schemas';
|
9
|
+
import { ChunkModel } from '../../server/models/chunk';
|
10
|
+
import { getTestDB } from './_util';
|
10
11
|
import { codeEmbedding, designThinkingQuery, designThinkingQuery2 } from './fixtures/embedding';
|
11
12
|
|
12
|
-
|
13
|
+
const serverDB: LobeChatDatabase = await getTestDB();
|
13
14
|
|
14
15
|
const userId = 'chunk-model-test-user-id';
|
15
16
|
const chunkModel = new ChunkModel(serverDB, userId);
|
@@ -124,7 +125,9 @@ describe('ChunkModel', () => {
|
|
124
125
|
.values([{ text: 'Non-Orphan Chunk', userId }])
|
125
126
|
.returning();
|
126
127
|
|
127
|
-
await serverDB
|
128
|
+
await serverDB
|
129
|
+
.insert(fileChunks)
|
130
|
+
.values([{ fileId: '1', chunkId: nonOrphanChunk.id, userId }]);
|
128
131
|
|
129
132
|
// Execute the method
|
130
133
|
await chunkModel.deleteOrphanChunks();
|
@@ -146,8 +149,8 @@ describe('ChunkModel', () => {
|
|
146
149
|
.returning();
|
147
150
|
|
148
151
|
await serverDB.insert(fileChunks).values([
|
149
|
-
{ fileId: '1', chunkId: chunk1.id },
|
150
|
-
{ fileId: '2', chunkId: chunk2.id },
|
152
|
+
{ fileId: '1', chunkId: chunk1.id, userId },
|
153
|
+
{ fileId: '2', chunkId: chunk2.id, userId },
|
151
154
|
]);
|
152
155
|
|
153
156
|
// Execute the method
|
@@ -180,8 +183,8 @@ describe('ChunkModel', () => {
|
|
180
183
|
.returning();
|
181
184
|
|
182
185
|
await serverDB.insert(fileChunks).values([
|
183
|
-
{ fileId, chunkId: chunk1.id },
|
184
|
-
{ fileId, chunkId: chunk2.id },
|
186
|
+
{ fileId, chunkId: chunk1.id, userId },
|
187
|
+
{ fileId, chunkId: chunk2.id, userId },
|
185
188
|
]);
|
186
189
|
|
187
190
|
await serverDB.insert(embeddings).values([
|
@@ -273,9 +276,9 @@ describe('ChunkModel', () => {
|
|
273
276
|
.returning();
|
274
277
|
|
275
278
|
await serverDB.insert(fileChunks).values([
|
276
|
-
{ fileId, chunkId: chunk1.id },
|
277
|
-
{ fileId, chunkId: chunk2.id },
|
278
|
-
{ fileId, chunkId: chunk3.id },
|
279
|
+
{ fileId, chunkId: chunk1.id, userId },
|
280
|
+
{ fileId, chunkId: chunk2.id, userId },
|
281
|
+
{ fileId, chunkId: chunk3.id, userId },
|
279
282
|
]);
|
280
283
|
|
281
284
|
const result = await chunkModel.findByFileId(fileId, 0);
|
@@ -299,8 +302,8 @@ describe('ChunkModel', () => {
|
|
299
302
|
.returning();
|
300
303
|
|
301
304
|
await serverDB.insert(fileChunks).values([
|
302
|
-
{ fileId, chunkId: chunk1.id },
|
303
|
-
{ fileId, chunkId: chunk2.id },
|
305
|
+
{ fileId, chunkId: chunk1.id, userId },
|
306
|
+
{ fileId, chunkId: chunk2.id, userId },
|
304
307
|
]);
|
305
308
|
|
306
309
|
const result = await chunkModel.getChunksTextByFileId(fileId);
|
@@ -324,9 +327,9 @@ describe('ChunkModel', () => {
|
|
324
327
|
.returning();
|
325
328
|
|
326
329
|
await serverDB.insert(fileChunks).values([
|
327
|
-
{ fileId: '1', chunkId: chunk1.id },
|
328
|
-
{ fileId: '1', chunkId: chunk2.id },
|
329
|
-
{ fileId: '2', chunkId: chunk3.id },
|
330
|
+
{ fileId: '1', chunkId: chunk1.id, userId },
|
331
|
+
{ fileId: '1', chunkId: chunk2.id, userId },
|
332
|
+
{ fileId: '2', chunkId: chunk3.id, userId },
|
330
333
|
]);
|
331
334
|
|
332
335
|
const result = await chunkModel.countByFileIds(fileIds);
|
@@ -355,8 +358,8 @@ describe('ChunkModel', () => {
|
|
355
358
|
.returning();
|
356
359
|
|
357
360
|
await serverDB.insert(fileChunks).values([
|
358
|
-
{ fileId, chunkId: chunk1.id },
|
359
|
-
{ fileId, chunkId: chunk2.id },
|
361
|
+
{ fileId, chunkId: chunk1.id, userId },
|
362
|
+
{ fileId, chunkId: chunk2.id, userId },
|
360
363
|
]);
|
361
364
|
|
362
365
|
const result = await chunkModel.countByFileId(fileId);
|
@@ -383,8 +386,8 @@ describe('ChunkModel', () => {
|
|
383
386
|
.returning();
|
384
387
|
|
385
388
|
await serverDB.insert(fileChunks).values([
|
386
|
-
{ fileId, chunkId: chunk1.id },
|
387
|
-
{ fileId, chunkId: chunk2.id },
|
389
|
+
{ fileId, chunkId: chunk1.id, userId },
|
390
|
+
{ fileId, chunkId: chunk2.id, userId },
|
388
391
|
]);
|
389
392
|
|
390
393
|
await serverDB.insert(embeddings).values([
|
@@ -511,6 +514,7 @@ content in Table html is below:
|
|
511
514
|
chunkResult.map((chunk) => ({
|
512
515
|
fileId,
|
513
516
|
chunkId: chunk.id,
|
517
|
+
userId,
|
514
518
|
})),
|
515
519
|
);
|
516
520
|
|
@@ -2,13 +2,14 @@
|
|
2
2
|
import { eq, inArray } from 'drizzle-orm/expressions';
|
3
3
|
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
4
4
|
|
5
|
-
import {
|
5
|
+
import { LobeChatDatabase } from '@/database/type';
|
6
6
|
import { FilesTabs, SortType } from '@/types/files';
|
7
7
|
|
8
|
-
import { files, globalFiles, knowledgeBaseFiles, knowledgeBases, users } from '
|
9
|
-
import { FileModel } from '
|
8
|
+
import { files, globalFiles, knowledgeBaseFiles, knowledgeBases, users } from '../../schemas';
|
9
|
+
import { FileModel } from '../../server/models/file';
|
10
|
+
import { getTestDB } from './_util';
|
10
11
|
|
11
|
-
const serverDB = await
|
12
|
+
const serverDB: LobeChatDatabase = await getTestDB();
|
12
13
|
|
13
14
|
const userId = 'file-model-test-user-id';
|
14
15
|
const fileModel = new FileModel(serverDB, userId);
|
@@ -95,6 +96,7 @@ describe('FileModel', () => {
|
|
95
96
|
size: 100,
|
96
97
|
url: 'https://example.com/global-file.txt',
|
97
98
|
metadata: { key: 'value' },
|
99
|
+
creator: userId,
|
98
100
|
};
|
99
101
|
|
100
102
|
const result = await fileModel.createGlobalFile(globalFile);
|
@@ -115,6 +117,7 @@ describe('FileModel', () => {
|
|
115
117
|
size: 100,
|
116
118
|
url: 'https://example.com/existing-file.txt',
|
117
119
|
metadata: { key: 'value' },
|
120
|
+
creator: userId,
|
118
121
|
};
|
119
122
|
|
120
123
|
await serverDB.insert(globalFiles).values(globalFile);
|
@@ -137,6 +140,7 @@ describe('FileModel', () => {
|
|
137
140
|
url: 'https://example.com/file1.txt',
|
138
141
|
size: 100,
|
139
142
|
fileType: 'text/plain',
|
143
|
+
creator: userId,
|
140
144
|
});
|
141
145
|
|
142
146
|
const { id } = await fileModel.create({
|
@@ -163,6 +167,7 @@ describe('FileModel', () => {
|
|
163
167
|
url: 'https://example.com/file1.txt',
|
164
168
|
size: 100,
|
165
169
|
fileType: 'text/plain',
|
170
|
+
creator: userId,
|
166
171
|
});
|
167
172
|
|
168
173
|
const { id } = await fileModel.create({
|
@@ -192,12 +197,14 @@ describe('FileModel', () => {
|
|
192
197
|
url: 'https://example.com/file1.txt',
|
193
198
|
size: 100,
|
194
199
|
fileType: 'text/plain',
|
200
|
+
creator: userId,
|
195
201
|
});
|
196
202
|
await fileModel.createGlobalFile({
|
197
203
|
hashId: '2',
|
198
204
|
url: 'https://example.com/file2.txt',
|
199
205
|
size: 200,
|
200
206
|
fileType: 'text/plain',
|
207
|
+
creator: userId,
|
201
208
|
});
|
202
209
|
|
203
210
|
const file1 = await fileModel.create({
|
@@ -240,12 +247,14 @@ describe('FileModel', () => {
|
|
240
247
|
url: 'https://example.com/file1.txt',
|
241
248
|
size: 100,
|
242
249
|
fileType: 'text/plain',
|
250
|
+
creator: userId,
|
243
251
|
});
|
244
252
|
await fileModel.createGlobalFile({
|
245
253
|
hashId: '2',
|
246
254
|
url: 'https://example.com/file2.txt',
|
247
255
|
size: 200,
|
248
256
|
fileType: 'text/plain',
|
257
|
+
creator: userId,
|
249
258
|
});
|
250
259
|
|
251
260
|
const file1 = await fileModel.create({
|
@@ -450,7 +459,7 @@ describe('FileModel', () => {
|
|
450
459
|
]);
|
451
460
|
await serverDB
|
452
461
|
.insert(knowledgeBaseFiles)
|
453
|
-
.values([{ fileId: 'file1', knowledgeBaseId: 'kb1' }]);
|
462
|
+
.values([{ fileId: 'file1', knowledgeBaseId: 'kb1', userId }]);
|
454
463
|
});
|
455
464
|
|
456
465
|
it('should query files in a specific knowledge base', async () => {
|
@@ -551,12 +560,14 @@ describe('FileModel', () => {
|
|
551
560
|
url: 'https://example.com/document.pdf',
|
552
561
|
size: 1000,
|
553
562
|
fileType: 'application/pdf',
|
563
|
+
creator: userId,
|
554
564
|
},
|
555
565
|
{
|
556
566
|
hashId: 'hash2',
|
557
567
|
url: 'https://example.com/image.jpg',
|
558
568
|
size: 500,
|
559
569
|
fileType: 'image/jpeg',
|
570
|
+
creator: userId,
|
560
571
|
},
|
561
572
|
]);
|
562
573
|
|
@@ -674,6 +685,7 @@ describe('FileModel', () => {
|
|
674
685
|
size: 100,
|
675
686
|
url: 'https://example.com/global-file.txt',
|
676
687
|
metadata: { key: 'value' },
|
688
|
+
creator: userId,
|
677
689
|
};
|
678
690
|
|
679
691
|
await serverDB.insert(globalFiles).values(globalFile);
|
@@ -700,12 +712,14 @@ describe('FileModel', () => {
|
|
700
712
|
fileType: 'text/plain',
|
701
713
|
size: 100,
|
702
714
|
url: 'https://example.com/file1.txt',
|
715
|
+
creator: userId,
|
703
716
|
};
|
704
717
|
const globalFiles2 = {
|
705
718
|
hashId: 'hash2',
|
706
719
|
fileType: 'text/plain',
|
707
720
|
size: 200,
|
708
721
|
url: 'https://example.com/file2.txt',
|
722
|
+
creator: userId,
|
709
723
|
};
|
710
724
|
|
711
725
|
await serverDB.insert(globalFiles).values([globalFiles1, globalFiles2]);
|
@@ -2,7 +2,7 @@
|
|
2
2
|
import { and, eq } from 'drizzle-orm/expressions';
|
3
3
|
import { afterEach, beforeEach, describe, expect, it } from 'vitest';
|
4
4
|
|
5
|
-
import {
|
5
|
+
import { LobeChatDatabase } from '@/database/type';
|
6
6
|
|
7
7
|
import {
|
8
8
|
NewKnowledgeBase,
|
@@ -11,10 +11,11 @@ import {
|
|
11
11
|
knowledgeBaseFiles,
|
12
12
|
knowledgeBases,
|
13
13
|
users,
|
14
|
-
} from '
|
15
|
-
import { KnowledgeBaseModel } from '
|
14
|
+
} from '../../schemas';
|
15
|
+
import { KnowledgeBaseModel } from '../../server/models/knowledgeBase';
|
16
|
+
import { getTestDB } from './_util';
|
16
17
|
|
17
|
-
|
18
|
+
const serverDB: LobeChatDatabase = await getTestDB();
|
18
19
|
|
19
20
|
const userId = 'session-group-model-test-user-id';
|
20
21
|
const knowledgeBaseModel = new KnowledgeBaseModel(serverDB, userId);
|
@@ -160,12 +161,14 @@ describe('KnowledgeBaseModel', () => {
|
|
160
161
|
url: 'https://example.com/document.pdf',
|
161
162
|
size: 1000,
|
162
163
|
fileType: 'application/pdf',
|
164
|
+
creator: userId,
|
163
165
|
},
|
164
166
|
{
|
165
167
|
hashId: 'hash2',
|
166
168
|
url: 'https://example.com/image.jpg',
|
167
169
|
size: 500,
|
168
170
|
fileType: 'image/jpeg',
|
171
|
+
creator: userId,
|
169
172
|
},
|
170
173
|
]);
|
171
174
|
|
@@ -198,12 +201,14 @@ describe('KnowledgeBaseModel', () => {
|
|
198
201
|
url: 'https://example.com/document.pdf',
|
199
202
|
size: 1000,
|
200
203
|
fileType: 'application/pdf',
|
204
|
+
creator: userId,
|
201
205
|
},
|
202
206
|
{
|
203
207
|
hashId: 'hash2',
|
204
208
|
url: 'https://example.com/image.jpg',
|
205
209
|
size: 500,
|
206
210
|
fileType: 'image/jpeg',
|
211
|
+
creator: userId,
|
207
212
|
},
|
208
213
|
]);
|
209
214
|
|