gaojintao01 commited on
Commit
e99cbb0
·
1 Parent(s): c8317fa
server/prisma/check-migration-dependencies.js ADDED
@@ -0,0 +1,175 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+
4
+ /**
5
+ * 检查迁移文件的外键依赖关系
6
+ */
7
+
8
+ // 存储表创建和引用信息的映射
9
+ const tableCreationOrder = {};
10
+ const foreignKeyReferences = {};
11
+
12
+ /**
13
+ * 解析迁移文件中的表创建和外键引用
14
+ */
15
+ function parseMigrationFile(filePath) {
16
+ try {
17
+ const sqlContent = fs.readFileSync(filePath, 'utf8');
18
+ const lines = sqlContent.split('\n');
19
+
20
+ let currentTable = null;
21
+ let inCreateTable = false;
22
+
23
+ lines.forEach((line, index) => {
24
+ const trimmedLine = line.trim();
25
+
26
+ // 检测 CREATE TABLE 语句
27
+ if (trimmedLine.startsWith('CREATE TABLE')) {
28
+ const tableMatch = trimmedLine.match(/CREATE TABLE "([^"]+)"/);
29
+ if (tableMatch) {
30
+ currentTable = tableMatch[1];
31
+ inCreateTable = true;
32
+ tableCreationOrder[currentTable] = path.basename(path.dirname(filePath));
33
+ }
34
+ }
35
+
36
+ // 检测外键约束
37
+ if (trimmedLine.includes('FOREIGN KEY') && trimmedLine.includes('REFERENCES')) {
38
+ const fkMatch = trimmedLine.match(/FOREIGN KEY \("[^"]+"\)\s+REFERENCES\s+"([^"]+)"/);
39
+ if (fkMatch && currentTable) {
40
+ const referencedTable = fkMatch[1];
41
+ if (!foreignKeyReferences[currentTable]) {
42
+ foreignKeyReferences[currentTable] = [];
43
+ }
44
+ foreignKeyReferences[currentTable].push({
45
+ referencedTable,
46
+ line: index + 1
47
+ });
48
+ }
49
+ }
50
+
51
+ // 检测表创建结束
52
+ if (inCreateTable && trimmedLine === ');') {
53
+ inCreateTable = false;
54
+ currentTable = null;
55
+ }
56
+ });
57
+
58
+ return true;
59
+ } catch (error) {
60
+ console.error(`解析文件失败: ${filePath}`, error.message);
61
+ return false;
62
+ }
63
+ }
64
+
65
+ /**
66
+ * 递归处理目录中的所有迁移文件
67
+ */
68
+ function processMigrationsDirectory(migrationsDir) {
69
+ const items = fs.readdirSync(migrationsDir);
70
+
71
+ items.forEach(item => {
72
+ const itemPath = path.join(migrationsDir, item);
73
+ const stat = fs.statSync(itemPath);
74
+
75
+ if (stat.isDirectory() && item !== 'migration_lock.toml') {
76
+ // 递归处理子目录
77
+ processMigrationsDirectory(itemPath);
78
+ } else if (item === 'migration.sql') {
79
+ // 处理迁移文件
80
+ parseMigrationFile(itemPath);
81
+ }
82
+ });
83
+ }
84
+
85
+ /**
86
+ * 检查依赖关系
87
+ */
88
+ function checkDependencies() {
89
+ console.log('=== 迁移文件外键依赖关系检查 ===\n');
90
+
91
+ const issues = [];
92
+
93
+ // 检查每个表的外键引用
94
+ Object.entries(foreignKeyReferences).forEach(([table, references]) => {
95
+ references.forEach(({ referencedTable, line }) => {
96
+ // 检查被引用的表是否在当前迁移或更早的迁移中创建
97
+ if (tableCreationOrder[referencedTable]) {
98
+ const currentMigration = tableCreationOrder[table];
99
+ const referencedMigration = tableCreationOrder[referencedTable];
100
+
101
+ // 如果被引用的表在更新的迁移中创建,这可能有问题
102
+ if (currentMigration < referencedMigration) {
103
+ issues.push({
104
+ table,
105
+ referencedTable,
106
+ issue: `表 ${table} 引用了在更晚迁移中创建的表 ${referencedTable}`,
107
+ migration: currentMigration
108
+ });
109
+ }
110
+ } else {
111
+ issues.push({
112
+ table,
113
+ referencedTable,
114
+ issue: `表 ${table} 引用了不存在的表 ${referencedTable}`,
115
+ migration: tableCreationOrder[table]
116
+ });
117
+ }
118
+ });
119
+ });
120
+
121
+ if (issues.length === 0) {
122
+ console.log('✅ 没有发现外键依赖关系问题');
123
+ } else {
124
+ console.log('❌ 发现以下外键依赖关系问题:');
125
+ issues.forEach(issue => {
126
+ console.log(` 表: ${issue.table}`);
127
+ console.log(` 引用表: ${issue.referencedTable}`);
128
+ console.log(` 问题: ${issue.issue}`);
129
+ console.log(` 迁移: ${issue.migration}`);
130
+ console.log('');
131
+ });
132
+ }
133
+
134
+ return issues;
135
+ }
136
+
137
+ /**
138
+ * 显示表创建顺序
139
+ */
140
+ function showTableCreationOrder() {
141
+ console.log('\n=== 表创建顺序 ===');
142
+
143
+ const sortedTables = Object.entries(tableCreationOrder)
144
+ .sort(([,a], [,b]) => a.localeCompare(b))
145
+ .map(([table, migration]) => ` ${table} (${migration})`);
146
+
147
+ sortedTables.forEach(table => console.log(table));
148
+ }
149
+
150
+ /**
151
+ * 主函数
152
+ */
153
+ function main() {
154
+ const migrationsDir = path.join(__dirname, 'migrations');
155
+
156
+ console.log('开始检查迁移文件外键依赖关系...\n');
157
+
158
+ processMigrationsDirectory(migrationsDir);
159
+
160
+ showTableCreationOrder();
161
+ const issues = checkDependencies();
162
+
163
+ return {
164
+ tableCreationOrder,
165
+ foreignKeyReferences,
166
+ issues: issues.length
167
+ };
168
+ }
169
+
170
+ // 运行检查
171
+ if (require.main === module) {
172
+ main();
173
+ }
174
+
175
+ module.exports = { parseMigrationFile, processMigrationsDirectory, checkDependencies };
server/prisma/migrations/20230921191814_init/migration.sql CHANGED
@@ -1,4 +1,4 @@
1
- -- CreateTable
2
  CREATE TABLE "api_keys" (
3
  "id" SERIAL PRIMARY KEY,
4
  "secret" TEXT,
@@ -7,30 +7,6 @@ CREATE TABLE "api_keys" (
7
  "lastUpdatedAt" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
8
  );
9
 
10
- -- CreateTable
11
- CREATE TABLE "workspace_documents" (
12
- "id" SERIAL PRIMARY KEY,
13
- "docId" TEXT NOT NULL,
14
- "filename" TEXT NOT NULL,
15
- "docpath" TEXT NOT NULL,
16
- "workspaceId" INTEGER NOT NULL,
17
- "metadata" TEXT,
18
- "createdAt" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
19
- "lastUpdatedAt" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
20
- CONSTRAINT "workspace_documents_workspaceId_fkey" FOREIGN KEY ("workspaceId") REFERENCES "workspaces" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
21
- );
22
-
23
- -- CreateTable
24
- CREATE TABLE "invites" (
25
- "id" SERIAL PRIMARY KEY,
26
- "code" TEXT NOT NULL,
27
- "status" TEXT NOT NULL DEFAULT 'pending',
28
- "claimedBy" INTEGER,
29
- "createdAt" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
30
- "createdBy" INTEGER NOT NULL,
31
- "lastUpdatedAt" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
32
- );
33
-
34
  -- CreateTable
35
  CREATE TABLE "system_settings" (
36
  "id" SERIAL PRIMARY KEY,
@@ -52,11 +28,26 @@ CREATE TABLE "users" (
52
  );
53
 
54
  -- CreateTable
55
- CREATE TABLE "document_vectors" (
56
  "id" SERIAL PRIMARY KEY,
57
- "docId" TEXT NOT NULL,
58
- "vectorId" TEXT NOT NULL,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
59
  "createdAt" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
 
60
  "lastUpdatedAt" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
61
  );
62
 
@@ -70,19 +61,28 @@ CREATE TABLE "welcome_messages" (
70
  );
71
 
72
  -- CreateTable
73
- CREATE TABLE "workspaces" (
74
  "id" SERIAL PRIMARY KEY,
75
- "name" TEXT NOT NULL,
76
- "slug" TEXT NOT NULL,
77
- "vectorTag" TEXT,
 
 
 
 
 
 
 
 
 
 
 
78
  "createdAt" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
79
- "openAiTemp" REAL,
80
- "openAiHistory" INTEGER NOT NULL DEFAULT 20,
81
  "lastUpdatedAt" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
82
- "openAiPrompt" TEXT
83
  );
84
 
85
- -- CreateTable
86
  CREATE TABLE "workspace_chats" (
87
  "id" SERIAL PRIMARY KEY,
88
  "workspaceId" INTEGER NOT NULL,
@@ -95,7 +95,7 @@ CREATE TABLE "workspace_chats" (
95
  CONSTRAINT "workspace_chats_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "users" ("id") ON DELETE CASCADE ON UPDATE CASCADE
96
  );
97
 
98
- -- CreateTable
99
  CREATE TABLE "workspace_users" (
100
  "id" SERIAL PRIMARY KEY,
101
  "user_id" INTEGER NOT NULL,
@@ -109,9 +109,6 @@ CREATE TABLE "workspace_users" (
109
  -- CreateIndex
110
  CREATE UNIQUE INDEX "api_keys_secret_key" ON "api_keys"("secret");
111
 
112
- -- CreateIndex
113
- CREATE UNIQUE INDEX "workspace_documents_docId_key" ON "workspace_documents"("docId");
114
-
115
  -- CreateIndex
116
  CREATE UNIQUE INDEX "invites_code_key" ON "invites"("code");
117
 
@@ -123,3 +120,6 @@ CREATE UNIQUE INDEX "users_username_key" ON "users"("username");
123
 
124
  -- CreateIndex
125
  CREATE UNIQUE INDEX "workspaces_slug_key" ON "workspaces"("slug");
 
 
 
 
1
+ -- CreateTable (基础表 - 无外键依赖)
2
  CREATE TABLE "api_keys" (
3
  "id" SERIAL PRIMARY KEY,
4
  "secret" TEXT,
 
7
  "lastUpdatedAt" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
8
  );
9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
10
  -- CreateTable
11
  CREATE TABLE "system_settings" (
12
  "id" SERIAL PRIMARY KEY,
 
28
  );
29
 
30
  -- CreateTable
31
+ CREATE TABLE "workspaces" (
32
  "id" SERIAL PRIMARY KEY,
33
+ "name" TEXT NOT NULL,
34
+ "slug" TEXT NOT NULL,
35
+ "vectorTag" TEXT,
36
+ "createdAt" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
37
+ "openAiTemp" REAL,
38
+ "openAiHistory" INTEGER NOT NULL DEFAULT 20,
39
+ "lastUpdatedAt" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
40
+ "openAiPrompt" TEXT
41
+ );
42
+
43
+ -- CreateTable
44
+ CREATE TABLE "invites" (
45
+ "id" SERIAL PRIMARY KEY,
46
+ "code" TEXT NOT NULL,
47
+ "status" TEXT NOT NULL DEFAULT 'pending',
48
+ "claimedBy" INTEGER,
49
  "createdAt" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
50
+ "createdBy" INTEGER NOT NULL,
51
  "lastUpdatedAt" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
52
  );
53
 
 
61
  );
62
 
63
  -- CreateTable
64
+ CREATE TABLE "document_vectors" (
65
  "id" SERIAL PRIMARY KEY,
66
+ "docId" TEXT NOT NULL,
67
+ "vectorId" TEXT NOT NULL,
68
+ "createdAt" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
69
+ "lastUpdatedAt" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
70
+ );
71
+
72
+ -- CreateTable (有外键依赖的表 - 依赖 workspaces)
73
+ CREATE TABLE "workspace_documents" (
74
+ "id" SERIAL PRIMARY KEY,
75
+ "docId" TEXT NOT NULL,
76
+ "filename" TEXT NOT NULL,
77
+ "docpath" TEXT NOT NULL,
78
+ "workspaceId" INTEGER NOT NULL,
79
+ "metadata" TEXT,
80
  "createdAt" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
 
 
81
  "lastUpdatedAt" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
82
+ CONSTRAINT "workspace_documents_workspaceId_fkey" FOREIGN KEY ("workspaceId") REFERENCES "workspaces" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
83
  );
84
 
85
+ -- CreateTable (有外键依赖的表 - 依赖 workspaces 和 users)
86
  CREATE TABLE "workspace_chats" (
87
  "id" SERIAL PRIMARY KEY,
88
  "workspaceId" INTEGER NOT NULL,
 
95
  CONSTRAINT "workspace_chats_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "users" ("id") ON DELETE CASCADE ON UPDATE CASCADE
96
  );
97
 
98
+ -- CreateTable (有外键依赖的表 - 依赖 workspaces 和 users)
99
  CREATE TABLE "workspace_users" (
100
  "id" SERIAL PRIMARY KEY,
101
  "user_id" INTEGER NOT NULL,
 
109
  -- CreateIndex
110
  CREATE UNIQUE INDEX "api_keys_secret_key" ON "api_keys"("secret");
111
 
 
 
 
112
  -- CreateIndex
113
  CREATE UNIQUE INDEX "invites_code_key" ON "invites"("code");
114
 
 
120
 
121
  -- CreateIndex
122
  CREATE UNIQUE INDEX "workspaces_slug_key" ON "workspaces"("slug");
123
+
124
+ -- CreateIndex
125
+ CREATE UNIQUE INDEX "workspace_documents_docId_key" ON "workspace_documents"("docId");