@lobehub/chat 1.71.4 → 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.
Files changed (43) hide show
  1. package/CHANGELOG.md +50 -0
  2. package/changelog/v1.json +18 -0
  3. package/docs/developer/database-schema.dbml +16 -0
  4. package/package.json +3 -3
  5. package/src/database/client/db.ts +14 -8
  6. package/src/database/client/migrations.json +62 -0
  7. package/src/database/migrations/0017_add_user_id_to_tables.sql +225 -0
  8. package/src/database/migrations/meta/0017_snapshot.json +3858 -0
  9. package/src/database/migrations/meta/_journal.json +7 -0
  10. package/src/database/{server/models → models}/__tests__/_test_template.ts +2 -2
  11. package/src/database/models/__tests__/_util.ts +12 -0
  12. package/src/database/{server/models → models}/__tests__/agent.test.ts +6 -5
  13. package/src/database/{server/models → models}/__tests__/aiModel.test.ts +5 -4
  14. package/src/database/{server/models → models}/__tests__/aiProvider.test.ts +5 -4
  15. package/src/database/{server/models → models}/__tests__/asyncTask.test.ts +5 -4
  16. package/src/database/{server/models → models}/__tests__/chunk.test.ts +25 -21
  17. package/src/database/{server/models → models}/__tests__/file.test.ts +19 -5
  18. package/src/database/{server/models → models}/__tests__/knowledgeBase.test.ts +9 -4
  19. package/src/database/{server/models → models}/__tests__/message.test.ts +625 -29
  20. package/src/database/{server/models → models}/__tests__/plugin.test.ts +5 -4
  21. package/src/database/{server/models → models}/__tests__/session.test.ts +23 -20
  22. package/src/database/{server/models → models}/__tests__/sessionGroup.test.ts +5 -4
  23. package/src/database/{server/models → models}/__tests__/topic.test.ts +5 -4
  24. package/src/database/repositories/dataImporter/index.ts +3 -0
  25. package/src/database/schemas/file.ts +38 -32
  26. package/src/database/schemas/message.ts +21 -0
  27. package/src/database/schemas/relations.ts +10 -0
  28. package/src/database/server/models/__tests__/nextauth.test.ts +2 -0
  29. package/src/database/server/models/__tests__/user.test.ts +13 -1
  30. package/src/database/server/models/chunk.ts +5 -1
  31. package/src/database/server/models/file.ts +6 -3
  32. package/src/database/server/models/message.ts +29 -12
  33. package/src/database/server/models/session.ts +1 -0
  34. package/src/features/ShareModal/ShareImage/index.tsx +27 -11
  35. package/src/hooks/useImgToClipboard.ts +29 -0
  36. package/src/hooks/useScreenshot.ts +53 -40
  37. package/src/services/file/client.test.ts +2 -1
  38. package/src/services/message/client.test.ts +3 -3
  39. package/src/services/session/client.test.ts +5 -3
  40. package/src/types/message/base.ts +7 -0
  41. package/vitest.server.config.ts +1 -1
  42. package/src/database/server/models/user.test.ts +0 -58
  43. /package/src/database/{server/models → models}/__tests__/fixtures/embedding.ts +0 -0
package/CHANGELOG.md CHANGED
@@ -2,6 +2,56 @@
2
2
 
3
3
  # Changelog
4
4
 
5
+ ## [Version 1.72.0](https://github.com/lobehub/lobe-chat/compare/v1.71.5...v1.72.0)
6
+
7
+ <sup>Released on **2025-03-18**</sup>
8
+
9
+ #### ✨ Features
10
+
11
+ - **misc**: Update db schema to add `user_id` for data export.
12
+
13
+ <br/>
14
+
15
+ <details>
16
+ <summary><kbd>Improvements and Fixes</kbd></summary>
17
+
18
+ #### What's improved
19
+
20
+ - **misc**: Update db schema to add `user_id` for data export, closes [#7022](https://github.com/lobehub/lobe-chat/issues/7022) ([c35471a](https://github.com/lobehub/lobe-chat/commit/c35471a))
21
+
22
+ </details>
23
+
24
+ <div align="right">
25
+
26
+ [![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)
27
+
28
+ </div>
29
+
30
+ ### [Version 1.71.5](https://github.com/lobehub/lobe-chat/compare/v1.71.4...v1.71.5)
31
+
32
+ <sup>Released on **2025-03-17**</sup>
33
+
34
+ #### 💄 Styles
35
+
36
+ - **misc**: Support screenshot to clipboard when sharing.
37
+
38
+ <br/>
39
+
40
+ <details>
41
+ <summary><kbd>Improvements and Fixes</kbd></summary>
42
+
43
+ #### Styles
44
+
45
+ - **misc**: Support screenshot to clipboard when sharing, closes [#6275](https://github.com/lobehub/lobe-chat/issues/6275) ([45663c3](https://github.com/lobehub/lobe-chat/commit/45663c3))
46
+
47
+ </details>
48
+
49
+ <div align="right">
50
+
51
+ [![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)
52
+
53
+ </div>
54
+
5
55
  ### [Version 1.71.4](https://github.com/lobehub/lobe-chat/compare/v1.71.3...v1.71.4)
6
56
 
7
57
  <sup>Released on **2025-03-17**</sup>
package/changelog/v1.json CHANGED
@@ -1,4 +1,22 @@
1
1
  [
2
+ {
3
+ "children": {
4
+ "features": [
5
+ "Update db schema to add user_id for data export."
6
+ ]
7
+ },
8
+ "date": "2025-03-18",
9
+ "version": "1.72.0"
10
+ },
11
+ {
12
+ "children": {
13
+ "improvements": [
14
+ "Support screenshot to clipboard when sharing."
15
+ ]
16
+ },
17
+ "date": "2025-03-17",
18
+ "version": "1.71.5"
19
+ },
2
20
  {
3
21
  "children": {
4
22
  "improvements": [
@@ -122,6 +122,10 @@ table files {
122
122
  accessed_at "timestamp with time zone" [not null, default: `now()`]
123
123
  created_at "timestamp with time zone" [not null, default: `now()`]
124
124
  updated_at "timestamp with time zone" [not null, default: `now()`]
125
+
126
+ indexes {
127
+ file_hash [name: 'file_hash_idx']
128
+ }
125
129
  }
126
130
 
127
131
  table global_files {
@@ -130,6 +134,7 @@ table global_files {
130
134
  size integer [not null]
131
135
  url text [not null]
132
136
  metadata jsonb
137
+ creator text [not null]
133
138
  created_at "timestamp with time zone" [not null, default: `now()`]
134
139
  accessed_at "timestamp with time zone" [not null, default: `now()`]
135
140
  }
@@ -137,6 +142,7 @@ table global_files {
137
142
  table knowledge_base_files {
138
143
  knowledge_base_id text [not null]
139
144
  file_id text [not null]
145
+ user_id text [not null]
140
146
  created_at "timestamp with time zone" [not null, default: `now()`]
141
147
 
142
148
  indexes {
@@ -161,6 +167,7 @@ table knowledge_bases {
161
167
  table message_chunks {
162
168
  message_id text
163
169
  chunk_id uuid
170
+ user_id text [not null]
164
171
 
165
172
  indexes {
166
173
  (chunk_id, message_id) [pk]
@@ -176,6 +183,7 @@ table message_plugins {
176
183
  identifier text
177
184
  state jsonb
178
185
  error jsonb
186
+ user_id text [not null]
179
187
  }
180
188
 
181
189
  table message_queries {
@@ -183,6 +191,7 @@ table message_queries {
183
191
  message_id text [not null]
184
192
  rewrite_query text
185
193
  user_query text
194
+ user_id text [not null]
186
195
  embeddings_id uuid
187
196
  }
188
197
 
@@ -191,6 +200,7 @@ table message_query_chunks {
191
200
  query_id uuid
192
201
  chunk_id uuid
193
202
  similarity "numeric(6, 5)"
203
+ user_id text [not null]
194
204
 
195
205
  indexes {
196
206
  (chunk_id, id, query_id) [pk]
@@ -202,6 +212,7 @@ table message_tts {
202
212
  content_md5 text
203
213
  file_id text
204
214
  voice text
215
+ user_id text [not null]
205
216
  }
206
217
 
207
218
  table message_translates {
@@ -209,6 +220,7 @@ table message_translates {
209
220
  content text
210
221
  from text
211
222
  to text
223
+ user_id text [not null]
212
224
  }
213
225
 
214
226
  table messages {
@@ -249,6 +261,7 @@ table messages {
249
261
  table messages_files {
250
262
  file_id text [not null]
251
263
  message_id text [not null]
264
+ user_id text [not null]
252
265
 
253
266
  indexes {
254
267
  (file_id, message_id) [pk]
@@ -404,6 +417,7 @@ table rag_eval_evaluation_records {
404
417
  table agents_to_sessions {
405
418
  agent_id text [not null]
406
419
  session_id text [not null]
420
+ user_id text [not null]
407
421
 
408
422
  indexes {
409
423
  (agent_id, session_id) [pk]
@@ -414,6 +428,7 @@ table file_chunks {
414
428
  file_id varchar
415
429
  chunk_id uuid
416
430
  created_at "timestamp with time zone" [not null, default: `now()`]
431
+ user_id text [not null]
417
432
 
418
433
  indexes {
419
434
  (file_id, chunk_id) [pk]
@@ -423,6 +438,7 @@ table file_chunks {
423
438
  table files_to_sessions {
424
439
  file_id text [not null]
425
440
  session_id text [not null]
441
+ user_id text [not null]
426
442
 
427
443
  indexes {
428
444
  (file_id, session_id) [pk]
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lobehub/chat",
3
- "version": "1.71.4",
3
+ "version": "1.72.0",
4
4
  "description": "Lobe Chat - an open-source, high-performance chatbot framework that supports speech synthesis, multimodal, and extensible Function Call plugin system. Supports one-click free deployment of your private ChatGPT/LLM web application.",
5
5
  "keywords": [
6
6
  "framework",
@@ -65,8 +65,8 @@
65
65
  "test": "npm run test-app && npm run test-server",
66
66
  "test-app": "vitest run --config vitest.config.ts",
67
67
  "test-app:coverage": "vitest run --config vitest.config.ts --coverage",
68
- "test-server": "vitest run --config vitest.server.config.ts",
69
- "test-server:coverage": "vitest run --config vitest.server.config.ts --coverage",
68
+ "test-server": "TEST_SERVER_DB=1 vitest run --config vitest.server.config.ts",
69
+ "test-server:coverage": "TEST_SERVER_DB=1 vitest run --config vitest.server.config.ts --coverage",
70
70
  "test:update": "vitest -u",
71
71
  "type-check": "tsc --noEmit",
72
72
  "webhook:ngrok": "ngrok http http://localhost:3011",
@@ -146,13 +146,15 @@ export class DatabaseManager {
146
146
  private async migrate(skipMultiRun = false): Promise<DrizzleInstance> {
147
147
  if (this.isLocalDBSchemaSynced && skipMultiRun) return this.db;
148
148
 
149
- const cacheHash = localStorage.getItem(pgliteSchemaHashCache);
150
- const hash = Md5.hashStr(JSON.stringify(migrations));
151
-
152
- // if hash is the same, no need to migrate
153
- if (hash === cacheHash) {
154
- this.isLocalDBSchemaSynced = true;
155
- return this.db;
149
+ let hash: string | undefined;
150
+ if (typeof localStorage !== 'undefined') {
151
+ const cacheHash = localStorage.getItem(pgliteSchemaHashCache);
152
+ hash = Md5.hashStr(JSON.stringify(migrations));
153
+ // if hash is the same, no need to migrate
154
+ if (hash === cacheHash) {
155
+ this.isLocalDBSchemaSynced = true;
156
+ return this.db;
157
+ }
156
158
  }
157
159
 
158
160
  const start = Date.now();
@@ -162,7 +164,11 @@ export class DatabaseManager {
162
164
  // refs: https://github.com/drizzle-team/drizzle-orm/discussions/2532
163
165
  // @ts-expect-error
164
166
  await this.db.dialect.migrate(migrations, this.db.session, {});
165
- localStorage.setItem(pgliteSchemaHashCache, hash);
167
+
168
+ if (typeof localStorage !== 'undefined' && hash) {
169
+ localStorage.setItem(pgliteSchemaHashCache, hash);
170
+ }
171
+
166
172
  this.isLocalDBSchemaSynced = true;
167
173
 
168
174
  console.info(`🗂 Migration success, take ${Date.now() - start}ms`);
@@ -323,5 +323,67 @@
323
323
  "bps": true,
324
324
  "folderMillis": 1741844738677,
325
325
  "hash": "2a7a98be2e49361391444d6fabf3fb5db0bcb6a65e5540e9c3d426ceeb1f7f3a"
326
+ },
327
+ {
328
+ "sql": [
329
+ "-- Complete User ID Migration Script\n-- Includes adding columns to all tables, populating data, and setting constraints\n\nBEGIN;",
330
+ "\n\nCREATE INDEX \"file_hash_idx\" ON \"files\" USING btree (\"file_hash\");",
331
+ "\n\n-- Step 1: Add nullable user_id columns to all required tables\nALTER TABLE \"global_files\" ADD COLUMN IF NOT EXISTS \"creator\" text;",
332
+ "\nALTER TABLE \"knowledge_base_files\" ADD COLUMN IF NOT EXISTS \"user_id\" text;",
333
+ "\nALTER TABLE \"message_chunks\" ADD COLUMN IF NOT EXISTS \"user_id\" text;",
334
+ "\nALTER TABLE \"message_plugins\" ADD COLUMN IF NOT EXISTS \"user_id\" text;",
335
+ "\nALTER TABLE \"message_queries\" ADD COLUMN IF NOT EXISTS \"user_id\" text;",
336
+ "\nALTER TABLE \"message_query_chunks\" ADD COLUMN IF NOT EXISTS \"user_id\" text;",
337
+ "\nALTER TABLE \"message_tts\" ADD COLUMN IF NOT EXISTS \"user_id\" text;",
338
+ "\nALTER TABLE \"message_translates\" ADD COLUMN IF NOT EXISTS \"user_id\" text;",
339
+ "\nALTER TABLE \"messages_files\" ADD COLUMN IF NOT EXISTS \"user_id\" text;",
340
+ "\nALTER TABLE \"agents_to_sessions\" ADD COLUMN IF NOT EXISTS \"user_id\" text;",
341
+ "\nALTER TABLE \"file_chunks\" ADD COLUMN IF NOT EXISTS \"user_id\" text;",
342
+ "\nALTER TABLE \"files_to_sessions\" ADD COLUMN IF NOT EXISTS \"user_id\" text;",
343
+ "\n\n-- Step 2: Populate user_id fields\n-- Retrieve user_id from associated tables\n\n-- Populate user_id for knowledge_base_files\nUPDATE \"knowledge_base_files\" AS kbf\nSET \"user_id\" = kb.\"user_id\"\n FROM \"knowledge_bases\" AS kb\nWHERE kbf.\"knowledge_base_id\" = kb.\"id\";",
344
+ "\n\n-- Populate user_id for message_chunks\nUPDATE \"message_chunks\" AS mc\nSET \"user_id\" = m.\"user_id\"\n FROM \"messages\" AS m\nWHERE mc.\"message_id\" = m.\"id\";",
345
+ "\n\n-- Populate user_id for message_plugins (directly from messages table)\nUPDATE \"message_plugins\" AS mp\nSET \"user_id\" = m.\"user_id\"\n FROM \"messages\" AS m\nWHERE mp.\"id\" = m.\"id\";",
346
+ "\n\n-- Populate user_id for message_queries\nUPDATE \"message_queries\" AS mq\nSET \"user_id\" = m.\"user_id\"\n FROM \"messages\" AS m\nWHERE mq.\"message_id\" = m.\"id\";",
347
+ "\n\n-- Populate user_id for message_query_chunks\nUPDATE \"message_query_chunks\" AS mqc\nSET \"user_id\" = mq.\"user_id\"\n FROM \"message_queries\" AS mq\nWHERE mqc.\"query_id\" = mq.\"id\";",
348
+ "\n\n-- Populate user_id for message_tts\nUPDATE \"message_tts\" AS mt\nSET \"user_id\" = m.\"user_id\"\n FROM \"messages\" AS m\nWHERE mt.\"id\" = m.\"id\";",
349
+ "\n\n-- Populate user_id for message_translates\nUPDATE \"message_translates\" AS mt\nSET \"user_id\" = m.\"user_id\"\n FROM \"messages\" AS m\nWHERE mt.\"id\" = m.\"id\";",
350
+ "\n\n-- Populate user_id for messages_files\nUPDATE \"messages_files\" AS mf\nSET \"user_id\" = m.\"user_id\"\n FROM \"messages\" AS m\nWHERE mf.\"message_id\" = m.\"id\";",
351
+ "\n\n-- Populate creator for global_files (get the first user who created the file from files table)\nUPDATE \"global_files\" AS gf\nSET \"creator\" = (\n SELECT f.\"user_id\"\n FROM \"files\" AS f\n WHERE f.\"file_hash\" = gf.\"hash_id\"\n ORDER BY f.\"created_at\" ASC\n LIMIT 1\n );",
352
+ "\n\n-- Delete global_files records where no user has used the file in the files table\nDELETE FROM \"global_files\"\nWHERE \"creator\" IS NULL;",
353
+ "\n\n-- Populate user_id for agents_to_sessions\nUPDATE \"agents_to_sessions\" AS ats\nSET \"user_id\" = a.\"user_id\"\n FROM \"agents\" AS a\nWHERE ats.\"agent_id\" = a.\"id\";",
354
+ "\n\n-- Populate user_id for file_chunks\nUPDATE \"file_chunks\" AS fc\nSET \"user_id\" = f.\"user_id\"\n FROM \"files\" AS f\nWHERE fc.\"file_id\" = f.\"id\";",
355
+ "\n\n-- Populate user_id for files_to_sessions\nUPDATE \"files_to_sessions\" AS fts\nSET \"user_id\" = f.\"user_id\"\n FROM \"files\" AS f\nWHERE fts.\"file_id\" = f.\"id\";",
356
+ "\n\n-- Get user_id from sessions table (handle potential NULL values)\nUPDATE \"files_to_sessions\" AS fts\nSET \"user_id\" = s.\"user_id\"\n FROM \"sessions\" AS s\nWHERE fts.\"session_id\" = s.\"id\" AND fts.\"user_id\" IS NULL;",
357
+ "\n\nUPDATE \"agents_to_sessions\" AS ats\nSET \"user_id\" = s.\"user_id\"\n FROM \"sessions\" AS s\nWHERE ats.\"session_id\" = s.\"id\" AND ats.\"user_id\" IS NULL;",
358
+ "\n\n-- Step 3: Check for any unpopulated records\nDO $$\nDECLARE\nkb_files_count INTEGER;\n msg_chunks_count INTEGER;\n msg_plugins_count INTEGER;\n msg_queries_count INTEGER;\n msg_query_chunks_count INTEGER;\n msg_tts_count INTEGER;\n msg_translates_count INTEGER;\n msgs_files_count INTEGER;\n agents_sessions_count INTEGER;\n file_chunks_count INTEGER;\n files_sessions_count INTEGER;\nBEGIN\nSELECT COUNT(*) INTO kb_files_count FROM \"knowledge_base_files\" WHERE \"user_id\" IS NULL;\nSELECT COUNT(*) INTO msg_chunks_count FROM \"message_chunks\" WHERE \"user_id\" IS NULL;\nSELECT COUNT(*) INTO msg_plugins_count FROM \"message_plugins\" WHERE \"user_id\" IS NULL;\nSELECT COUNT(*) INTO msg_queries_count FROM \"message_queries\" WHERE \"user_id\" IS NULL;\nSELECT COUNT(*) INTO msg_query_chunks_count FROM \"message_query_chunks\" WHERE \"user_id\" IS NULL;\nSELECT COUNT(*) INTO msg_tts_count FROM \"message_tts\" WHERE \"user_id\" IS NULL;\nSELECT COUNT(*) INTO msg_translates_count FROM \"message_translates\" WHERE \"user_id\" IS NULL;\nSELECT COUNT(*) INTO msgs_files_count FROM \"messages_files\" WHERE \"user_id\" IS NULL;\nSELECT COUNT(*) INTO agents_sessions_count FROM \"agents_to_sessions\" WHERE \"user_id\" IS NULL;\nSELECT COUNT(*) INTO file_chunks_count FROM \"file_chunks\" WHERE \"user_id\" IS NULL;\nSELECT COUNT(*) INTO files_sessions_count FROM \"files_to_sessions\" WHERE \"user_id\" IS NULL;\n\nIF kb_files_count > 0 OR msg_chunks_count > 0 OR msg_plugins_count > 0 OR\n msg_queries_count > 0 OR msg_query_chunks_count > 0 OR msg_tts_count > 0 OR\n msg_translates_count > 0 OR msgs_files_count > 0 OR agents_sessions_count > 0 OR\n file_chunks_count > 0 OR files_sessions_count > 0 THEN\n RAISE EXCEPTION 'There are records with NULL user_id values that could not be populated';\nEND IF;\nEND $$;",
359
+ "\n\n-- Step 4: Add NOT NULL constraints and foreign keys\nALTER TABLE \"knowledge_base_files\" ALTER COLUMN \"user_id\" SET NOT NULL;",
360
+ "\nALTER TABLE \"message_chunks\" ALTER COLUMN \"user_id\" SET NOT NULL;",
361
+ "\nALTER TABLE \"message_plugins\" ALTER COLUMN \"user_id\" SET NOT NULL;",
362
+ "\nALTER TABLE \"message_queries\" ALTER COLUMN \"user_id\" SET NOT NULL;",
363
+ "\nALTER TABLE \"message_query_chunks\" ALTER COLUMN \"user_id\" SET NOT NULL;",
364
+ "\nALTER TABLE \"message_tts\" ALTER COLUMN \"user_id\" SET NOT NULL;",
365
+ "\nALTER TABLE \"message_translates\" ALTER COLUMN \"user_id\" SET NOT NULL;",
366
+ "\nALTER TABLE \"messages_files\" ALTER COLUMN \"user_id\" SET NOT NULL;",
367
+ "\nALTER TABLE \"agents_to_sessions\" ALTER COLUMN \"user_id\" SET NOT NULL;",
368
+ "\nALTER TABLE \"file_chunks\" ALTER COLUMN \"user_id\" SET NOT NULL;",
369
+ "\nALTER TABLE \"files_to_sessions\" ALTER COLUMN \"user_id\" SET NOT NULL;",
370
+ "\n\n-- Add foreign key constraints\nALTER TABLE \"global_files\"\n ADD CONSTRAINT \"global_files_creator_users_id_fk\"\n FOREIGN KEY (\"creator\") REFERENCES \"public\".\"users\"(\"id\")\n ON DELETE SET NULL ON UPDATE NO ACTION;",
371
+ "\n\nALTER TABLE \"knowledge_base_files\"\n ADD CONSTRAINT \"knowledge_base_files_user_id_users_id_fk\"\n FOREIGN KEY (\"user_id\") REFERENCES \"public\".\"users\"(\"id\")\n ON DELETE CASCADE ON UPDATE NO ACTION;",
372
+ "\n\nALTER TABLE \"message_chunks\"\n ADD CONSTRAINT \"message_chunks_user_id_users_id_fk\"\n FOREIGN KEY (\"user_id\") REFERENCES \"public\".\"users\"(\"id\")\n ON DELETE CASCADE ON UPDATE NO ACTION;",
373
+ "\n\nALTER TABLE \"message_plugins\"\n ADD CONSTRAINT \"message_plugins_user_id_users_id_fk\"\n FOREIGN KEY (\"user_id\") REFERENCES \"public\".\"users\"(\"id\")\n ON DELETE CASCADE ON UPDATE NO ACTION;",
374
+ "\n\nALTER TABLE \"message_queries\"\n ADD CONSTRAINT \"message_queries_user_id_users_id_fk\"\n FOREIGN KEY (\"user_id\") REFERENCES \"public\".\"users\"(\"id\")\n ON DELETE CASCADE ON UPDATE NO ACTION;",
375
+ "\n\nALTER TABLE \"message_query_chunks\"\n ADD CONSTRAINT \"message_query_chunks_user_id_users_id_fk\"\n FOREIGN KEY (\"user_id\") REFERENCES \"public\".\"users\"(\"id\")\n ON DELETE CASCADE ON UPDATE NO ACTION;",
376
+ "\n\nALTER TABLE \"message_tts\"\n ADD CONSTRAINT \"message_tts_user_id_users_id_fk\"\n FOREIGN KEY (\"user_id\") REFERENCES \"public\".\"users\"(\"id\")\n ON DELETE CASCADE ON UPDATE NO ACTION;",
377
+ "\n\nALTER TABLE \"message_translates\"\n ADD CONSTRAINT \"message_translates_user_id_users_id_fk\"\n FOREIGN KEY (\"user_id\") REFERENCES \"public\".\"users\"(\"id\")\n ON DELETE CASCADE ON UPDATE NO ACTION;",
378
+ "\n\nALTER TABLE \"messages_files\"\n ADD CONSTRAINT \"messages_files_user_id_users_id_fk\"\n FOREIGN KEY (\"user_id\") REFERENCES \"public\".\"users\"(\"id\")\n ON DELETE CASCADE ON UPDATE NO ACTION;",
379
+ "\n\nALTER TABLE \"agents_to_sessions\"\n ADD CONSTRAINT \"agents_to_sessions_user_id_users_id_fk\"\n FOREIGN KEY (\"user_id\") REFERENCES \"public\".\"users\"(\"id\")\n ON DELETE CASCADE ON UPDATE NO ACTION;",
380
+ "\n\nALTER TABLE \"file_chunks\"\n ADD CONSTRAINT \"file_chunks_user_id_users_id_fk\"\n FOREIGN KEY (\"user_id\") REFERENCES \"public\".\"users\"(\"id\")\n ON DELETE CASCADE ON UPDATE NO ACTION;",
381
+ "\n\nALTER TABLE \"files_to_sessions\"\n ADD CONSTRAINT \"files_to_sessions_user_id_users_id_fk\"\n FOREIGN KEY (\"user_id\") REFERENCES \"public\".\"users\"(\"id\")\n ON DELETE CASCADE ON UPDATE NO ACTION;",
382
+ "\n\nCOMMIT;",
383
+ "\n"
384
+ ],
385
+ "bps": true,
386
+ "folderMillis": 1742269437903,
387
+ "hash": "89e91285be422d5f44511c7405f57b57f8dfda4f0304126ae9b0f266e5fd60f1"
326
388
  }
327
389
  ]
@@ -0,0 +1,225 @@
1
+ -- Complete User ID Migration Script
2
+ -- Includes adding columns to all tables, populating data, and setting constraints
3
+
4
+ BEGIN;--> statement-breakpoint
5
+
6
+ CREATE INDEX "file_hash_idx" ON "files" USING btree ("file_hash");--> statement-breakpoint
7
+
8
+ -- Step 1: Add nullable user_id columns to all required tables
9
+ ALTER TABLE "global_files" ADD COLUMN IF NOT EXISTS "creator" text;--> statement-breakpoint
10
+ ALTER TABLE "knowledge_base_files" ADD COLUMN IF NOT EXISTS "user_id" text;--> statement-breakpoint
11
+ ALTER TABLE "message_chunks" ADD COLUMN IF NOT EXISTS "user_id" text;--> statement-breakpoint
12
+ ALTER TABLE "message_plugins" ADD COLUMN IF NOT EXISTS "user_id" text;--> statement-breakpoint
13
+ ALTER TABLE "message_queries" ADD COLUMN IF NOT EXISTS "user_id" text;--> statement-breakpoint
14
+ ALTER TABLE "message_query_chunks" ADD COLUMN IF NOT EXISTS "user_id" text;--> statement-breakpoint
15
+ ALTER TABLE "message_tts" ADD COLUMN IF NOT EXISTS "user_id" text;--> statement-breakpoint
16
+ ALTER TABLE "message_translates" ADD COLUMN IF NOT EXISTS "user_id" text;--> statement-breakpoint
17
+ ALTER TABLE "messages_files" ADD COLUMN IF NOT EXISTS "user_id" text;--> statement-breakpoint
18
+ ALTER TABLE "agents_to_sessions" ADD COLUMN IF NOT EXISTS "user_id" text;--> statement-breakpoint
19
+ ALTER TABLE "file_chunks" ADD COLUMN IF NOT EXISTS "user_id" text;--> statement-breakpoint
20
+ ALTER TABLE "files_to_sessions" ADD COLUMN IF NOT EXISTS "user_id" text;--> statement-breakpoint
21
+
22
+ -- Step 2: Populate user_id fields
23
+ -- Retrieve user_id from associated tables
24
+
25
+ -- Populate user_id for knowledge_base_files
26
+ UPDATE "knowledge_base_files" AS kbf
27
+ SET "user_id" = kb."user_id"
28
+ FROM "knowledge_bases" AS kb
29
+ WHERE kbf."knowledge_base_id" = kb."id";--> statement-breakpoint
30
+
31
+ -- Populate user_id for message_chunks
32
+ UPDATE "message_chunks" AS mc
33
+ SET "user_id" = m."user_id"
34
+ FROM "messages" AS m
35
+ WHERE mc."message_id" = m."id";--> statement-breakpoint
36
+
37
+ -- Populate user_id for message_plugins (directly from messages table)
38
+ UPDATE "message_plugins" AS mp
39
+ SET "user_id" = m."user_id"
40
+ FROM "messages" AS m
41
+ WHERE mp."id" = m."id";--> statement-breakpoint
42
+
43
+ -- Populate user_id for message_queries
44
+ UPDATE "message_queries" AS mq
45
+ SET "user_id" = m."user_id"
46
+ FROM "messages" AS m
47
+ WHERE mq."message_id" = m."id";--> statement-breakpoint
48
+
49
+ -- Populate user_id for message_query_chunks
50
+ UPDATE "message_query_chunks" AS mqc
51
+ SET "user_id" = mq."user_id"
52
+ FROM "message_queries" AS mq
53
+ WHERE mqc."query_id" = mq."id";--> statement-breakpoint
54
+
55
+ -- Populate user_id for message_tts
56
+ UPDATE "message_tts" AS mt
57
+ SET "user_id" = m."user_id"
58
+ FROM "messages" AS m
59
+ WHERE mt."id" = m."id";--> statement-breakpoint
60
+
61
+ -- Populate user_id for message_translates
62
+ UPDATE "message_translates" AS mt
63
+ SET "user_id" = m."user_id"
64
+ FROM "messages" AS m
65
+ WHERE mt."id" = m."id";--> statement-breakpoint
66
+
67
+ -- Populate user_id for messages_files
68
+ UPDATE "messages_files" AS mf
69
+ SET "user_id" = m."user_id"
70
+ FROM "messages" AS m
71
+ WHERE mf."message_id" = m."id";--> statement-breakpoint
72
+
73
+ -- Populate creator for global_files (get the first user who created the file from files table)
74
+ UPDATE "global_files" AS gf
75
+ SET "creator" = (
76
+ SELECT f."user_id"
77
+ FROM "files" AS f
78
+ WHERE f."file_hash" = gf."hash_id"
79
+ ORDER BY f."created_at" ASC
80
+ LIMIT 1
81
+ );--> statement-breakpoint
82
+
83
+ -- Delete global_files records where no user has used the file in the files table
84
+ DELETE FROM "global_files"
85
+ WHERE "creator" IS NULL;--> statement-breakpoint
86
+
87
+ -- Populate user_id for agents_to_sessions
88
+ UPDATE "agents_to_sessions" AS ats
89
+ SET "user_id" = a."user_id"
90
+ FROM "agents" AS a
91
+ WHERE ats."agent_id" = a."id";--> statement-breakpoint
92
+
93
+ -- Populate user_id for file_chunks
94
+ UPDATE "file_chunks" AS fc
95
+ SET "user_id" = f."user_id"
96
+ FROM "files" AS f
97
+ WHERE fc."file_id" = f."id";--> statement-breakpoint
98
+
99
+ -- Populate user_id for files_to_sessions
100
+ UPDATE "files_to_sessions" AS fts
101
+ SET "user_id" = f."user_id"
102
+ FROM "files" AS f
103
+ WHERE fts."file_id" = f."id";--> statement-breakpoint
104
+
105
+ -- Get user_id from sessions table (handle potential NULL values)
106
+ UPDATE "files_to_sessions" AS fts
107
+ SET "user_id" = s."user_id"
108
+ FROM "sessions" AS s
109
+ WHERE fts."session_id" = s."id" AND fts."user_id" IS NULL;--> statement-breakpoint
110
+
111
+ UPDATE "agents_to_sessions" AS ats
112
+ SET "user_id" = s."user_id"
113
+ FROM "sessions" AS s
114
+ WHERE ats."session_id" = s."id" AND ats."user_id" IS NULL;--> statement-breakpoint
115
+
116
+ -- Step 3: Check for any unpopulated records
117
+ DO $$
118
+ DECLARE
119
+ kb_files_count INTEGER;
120
+ msg_chunks_count INTEGER;
121
+ msg_plugins_count INTEGER;
122
+ msg_queries_count INTEGER;
123
+ msg_query_chunks_count INTEGER;
124
+ msg_tts_count INTEGER;
125
+ msg_translates_count INTEGER;
126
+ msgs_files_count INTEGER;
127
+ agents_sessions_count INTEGER;
128
+ file_chunks_count INTEGER;
129
+ files_sessions_count INTEGER;
130
+ BEGIN
131
+ SELECT COUNT(*) INTO kb_files_count FROM "knowledge_base_files" WHERE "user_id" IS NULL;
132
+ SELECT COUNT(*) INTO msg_chunks_count FROM "message_chunks" WHERE "user_id" IS NULL;
133
+ SELECT COUNT(*) INTO msg_plugins_count FROM "message_plugins" WHERE "user_id" IS NULL;
134
+ SELECT COUNT(*) INTO msg_queries_count FROM "message_queries" WHERE "user_id" IS NULL;
135
+ SELECT COUNT(*) INTO msg_query_chunks_count FROM "message_query_chunks" WHERE "user_id" IS NULL;
136
+ SELECT COUNT(*) INTO msg_tts_count FROM "message_tts" WHERE "user_id" IS NULL;
137
+ SELECT COUNT(*) INTO msg_translates_count FROM "message_translates" WHERE "user_id" IS NULL;
138
+ SELECT COUNT(*) INTO msgs_files_count FROM "messages_files" WHERE "user_id" IS NULL;
139
+ SELECT COUNT(*) INTO agents_sessions_count FROM "agents_to_sessions" WHERE "user_id" IS NULL;
140
+ SELECT COUNT(*) INTO file_chunks_count FROM "file_chunks" WHERE "user_id" IS NULL;
141
+ SELECT COUNT(*) INTO files_sessions_count FROM "files_to_sessions" WHERE "user_id" IS NULL;
142
+
143
+ IF kb_files_count > 0 OR msg_chunks_count > 0 OR msg_plugins_count > 0 OR
144
+ msg_queries_count > 0 OR msg_query_chunks_count > 0 OR msg_tts_count > 0 OR
145
+ msg_translates_count > 0 OR msgs_files_count > 0 OR agents_sessions_count > 0 OR
146
+ file_chunks_count > 0 OR files_sessions_count > 0 THEN
147
+ RAISE EXCEPTION 'There are records with NULL user_id values that could not be populated';
148
+ END IF;
149
+ END $$;--> statement-breakpoint
150
+
151
+ -- Step 4: Add NOT NULL constraints and foreign keys
152
+ ALTER TABLE "knowledge_base_files" ALTER COLUMN "user_id" SET NOT NULL;--> statement-breakpoint
153
+ ALTER TABLE "message_chunks" ALTER COLUMN "user_id" SET NOT NULL;--> statement-breakpoint
154
+ ALTER TABLE "message_plugins" ALTER COLUMN "user_id" SET NOT NULL;--> statement-breakpoint
155
+ ALTER TABLE "message_queries" ALTER COLUMN "user_id" SET NOT NULL;--> statement-breakpoint
156
+ ALTER TABLE "message_query_chunks" ALTER COLUMN "user_id" SET NOT NULL;--> statement-breakpoint
157
+ ALTER TABLE "message_tts" ALTER COLUMN "user_id" SET NOT NULL;--> statement-breakpoint
158
+ ALTER TABLE "message_translates" ALTER COLUMN "user_id" SET NOT NULL;--> statement-breakpoint
159
+ ALTER TABLE "messages_files" ALTER COLUMN "user_id" SET NOT NULL;--> statement-breakpoint
160
+ ALTER TABLE "agents_to_sessions" ALTER COLUMN "user_id" SET NOT NULL;--> statement-breakpoint
161
+ ALTER TABLE "file_chunks" ALTER COLUMN "user_id" SET NOT NULL;--> statement-breakpoint
162
+ ALTER TABLE "files_to_sessions" ALTER COLUMN "user_id" SET NOT NULL;--> statement-breakpoint
163
+
164
+ -- Add foreign key constraints
165
+ ALTER TABLE "global_files"
166
+ ADD CONSTRAINT "global_files_creator_users_id_fk"
167
+ FOREIGN KEY ("creator") REFERENCES "public"."users"("id")
168
+ ON DELETE SET NULL ON UPDATE NO ACTION;--> statement-breakpoint
169
+
170
+ ALTER TABLE "knowledge_base_files"
171
+ ADD CONSTRAINT "knowledge_base_files_user_id_users_id_fk"
172
+ FOREIGN KEY ("user_id") REFERENCES "public"."users"("id")
173
+ ON DELETE CASCADE ON UPDATE NO ACTION;--> statement-breakpoint
174
+
175
+ ALTER TABLE "message_chunks"
176
+ ADD CONSTRAINT "message_chunks_user_id_users_id_fk"
177
+ FOREIGN KEY ("user_id") REFERENCES "public"."users"("id")
178
+ ON DELETE CASCADE ON UPDATE NO ACTION;--> statement-breakpoint
179
+
180
+ ALTER TABLE "message_plugins"
181
+ ADD CONSTRAINT "message_plugins_user_id_users_id_fk"
182
+ FOREIGN KEY ("user_id") REFERENCES "public"."users"("id")
183
+ ON DELETE CASCADE ON UPDATE NO ACTION;--> statement-breakpoint
184
+
185
+ ALTER TABLE "message_queries"
186
+ ADD CONSTRAINT "message_queries_user_id_users_id_fk"
187
+ FOREIGN KEY ("user_id") REFERENCES "public"."users"("id")
188
+ ON DELETE CASCADE ON UPDATE NO ACTION;--> statement-breakpoint
189
+
190
+ ALTER TABLE "message_query_chunks"
191
+ ADD CONSTRAINT "message_query_chunks_user_id_users_id_fk"
192
+ FOREIGN KEY ("user_id") REFERENCES "public"."users"("id")
193
+ ON DELETE CASCADE ON UPDATE NO ACTION;--> statement-breakpoint
194
+
195
+ ALTER TABLE "message_tts"
196
+ ADD CONSTRAINT "message_tts_user_id_users_id_fk"
197
+ FOREIGN KEY ("user_id") REFERENCES "public"."users"("id")
198
+ ON DELETE CASCADE ON UPDATE NO ACTION;--> statement-breakpoint
199
+
200
+ ALTER TABLE "message_translates"
201
+ ADD CONSTRAINT "message_translates_user_id_users_id_fk"
202
+ FOREIGN KEY ("user_id") REFERENCES "public"."users"("id")
203
+ ON DELETE CASCADE ON UPDATE NO ACTION;--> statement-breakpoint
204
+
205
+ ALTER TABLE "messages_files"
206
+ ADD CONSTRAINT "messages_files_user_id_users_id_fk"
207
+ FOREIGN KEY ("user_id") REFERENCES "public"."users"("id")
208
+ ON DELETE CASCADE ON UPDATE NO ACTION;--> statement-breakpoint
209
+
210
+ ALTER TABLE "agents_to_sessions"
211
+ ADD CONSTRAINT "agents_to_sessions_user_id_users_id_fk"
212
+ FOREIGN KEY ("user_id") REFERENCES "public"."users"("id")
213
+ ON DELETE CASCADE ON UPDATE NO ACTION;--> statement-breakpoint
214
+
215
+ ALTER TABLE "file_chunks"
216
+ ADD CONSTRAINT "file_chunks_user_id_users_id_fk"
217
+ FOREIGN KEY ("user_id") REFERENCES "public"."users"("id")
218
+ ON DELETE CASCADE ON UPDATE NO ACTION;--> statement-breakpoint
219
+
220
+ ALTER TABLE "files_to_sessions"
221
+ ADD CONSTRAINT "files_to_sessions_user_id_users_id_fk"
222
+ FOREIGN KEY ("user_id") REFERENCES "public"."users"("id")
223
+ ON DELETE CASCADE ON UPDATE NO ACTION;--> statement-breakpoint
224
+
225
+ COMMIT;--> statement-breakpoint