fdb2 1.0.39 → 1.0.40

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 (63) hide show
  1. package/README.md +2 -1
  2. package/dist/public/explorer.css +403 -380
  3. package/dist/public/explorer.js +1294 -737
  4. package/dist/public/index.js +242 -16
  5. package/dist/public/layout.js +1 -1
  6. package/dist/scripts/verify-db-support.cjs +239 -0
  7. package/dist/server/core/dialect.d.ts +9 -0
  8. package/dist/server/core/dialect.d.ts.map +1 -1
  9. package/dist/server/core/dialect.js +24 -9
  10. package/dist/server/core/dialect.js.map +1 -1
  11. package/dist/server/core/dialect.ts +29 -9
  12. package/dist/server/core/schema/__tests__/ddl-emitter.test.ts +7 -3
  13. package/dist/server/core/schema/ddl-emitter.d.ts.map +1 -1
  14. package/dist/server/core/schema/ddl-emitter.js +32 -12
  15. package/dist/server/core/schema/ddl-emitter.js.map +1 -1
  16. package/dist/server/core/schema/ddl-emitter.ts +34 -11
  17. package/dist/server/index.d.ts.map +1 -1
  18. package/dist/server/index.js +83 -6
  19. package/dist/server/index.js.map +1 -1
  20. package/dist/server/index.ts +87 -6
  21. package/dist/server/model/ddl-spec.d.ts +9 -0
  22. package/dist/server/model/ddl-spec.d.ts.map +1 -1
  23. package/dist/server/model/ddl-spec.ts +9 -0
  24. package/dist/server/service/connection.service.d.ts +8 -0
  25. package/dist/server/service/connection.service.d.ts.map +1 -1
  26. package/dist/server/service/connection.service.js +75 -17
  27. package/dist/server/service/connection.service.js.map +1 -1
  28. package/dist/server/service/connection.service.ts +74 -17
  29. package/dist/server/service/database/base.service.d.ts +45 -0
  30. package/dist/server/service/database/base.service.d.ts.map +1 -1
  31. package/dist/server/service/database/base.service.js +120 -7
  32. package/dist/server/service/database/base.service.js.map +1 -1
  33. package/dist/server/service/database/base.service.ts +143 -8
  34. package/dist/server/service/database/cockroachdb.service.d.ts +9 -0
  35. package/dist/server/service/database/cockroachdb.service.d.ts.map +1 -1
  36. package/dist/server/service/database/cockroachdb.service.js +67 -56
  37. package/dist/server/service/database/cockroachdb.service.js.map +1 -1
  38. package/dist/server/service/database/cockroachdb.service.ts +66 -57
  39. package/dist/server/service/database/database.service.d.ts +3 -221
  40. package/dist/server/service/database/database.service.d.ts.map +1 -1
  41. package/dist/server/service/database/database.service.js +66 -24
  42. package/dist/server/service/database/database.service.js.map +1 -1
  43. package/dist/server/service/database/database.service.ts +69 -23
  44. package/dist/server/service/database/mongodb.service.d.ts +58 -3
  45. package/dist/server/service/database/mongodb.service.d.ts.map +1 -1
  46. package/dist/server/service/database/mongodb.service.js +251 -54
  47. package/dist/server/service/database/mongodb.service.js.map +1 -1
  48. package/dist/server/service/database/mongodb.service.ts +275 -60
  49. package/dist/server/service/database/mssql.service.d.ts +8 -0
  50. package/dist/server/service/database/mssql.service.d.ts.map +1 -1
  51. package/dist/server/service/database/mssql.service.js +41 -36
  52. package/dist/server/service/database/mssql.service.js.map +1 -1
  53. package/dist/server/service/database/mssql.service.ts +45 -40
  54. package/dist/server/service/database/oracle.service.d.ts +24 -0
  55. package/dist/server/service/database/oracle.service.d.ts.map +1 -1
  56. package/dist/server/service/database/oracle.service.js +146 -106
  57. package/dist/server/service/database/oracle.service.js.map +1 -1
  58. package/dist/server/service/database/oracle.service.ts +145 -105
  59. package/dist/server/service/database/sqlite.service.js +1 -1
  60. package/dist/server/service/database/sqlite.service.js.map +1 -1
  61. package/dist/server/service/database/sqlite.service.ts +1 -1
  62. package/package.json +8 -8
  63. package/scripts/verify-db-support.cjs +239 -0
@@ -24,39 +24,45 @@ export class CockroachDBService extends BaseDatabaseService {
24
24
 
25
25
  /**
26
26
  * 获取CockroachDB数据库列表
27
+ * 注意:CockroachDB 兼容 PostgreSQL 协议,但没有 information_schema.databases,
28
+ * 数据库列表须查 pg_database。
27
29
  */
28
30
  async getDatabases(dataSource: DataSource): Promise<string[]> {
29
31
  const result = await dataSource.query(`
30
- SELECT
31
- database_name as name
32
- FROM
33
- information_schema.databases
34
- WHERE
35
- database_name NOT IN ('system', 'pg_catalog', 'information_schema', 'crdb_internal')
36
- ORDER BY
37
- database_name
32
+ SELECT
33
+ datname as name
34
+ FROM
35
+ pg_database
36
+ WHERE
37
+ datname NOT IN ('system', 'postgres')
38
+ ORDER BY
39
+ datname
38
40
  `);
39
41
  return result.map((row: any) => row.name);
40
42
  }
41
43
 
42
44
  /**
43
45
  * 获取CockroachDB表列表
46
+ * 注意:CockroachDB 的 information_schema.tables 没有 oid 列(与 PG 不同),
47
+ * 且 table_schema 是 'public' 而非数据库名。改为直接查 pg_class(relkind='r' 为普通表),
48
+ * 连接已定位到目标数据库,无需再按库名过滤。
44
49
  */
45
50
  async getTables(dataSource: DataSource, database: string): Promise<TableEntity[]> {
46
51
  const result = await dataSource.query(`
47
- SELECT
48
- t.table_name as name,
52
+ SELECT
53
+ c.relname as name,
49
54
  'table' as type,
50
- obj_description(t.oid) as comment
51
- FROM
52
- information_schema.tables t
53
- WHERE
54
- t.table_schema = $1
55
- AND t.table_type = 'BASE TABLE'
56
- ORDER BY
57
- t.table_name
58
- `, [database]);
59
-
55
+ obj_description(c.oid) as comment
56
+ FROM
57
+ pg_class c
58
+ JOIN pg_namespace n ON n.oid = c.relnamespace
59
+ WHERE
60
+ c.relkind = 'r'
61
+ AND n.nspname NOT IN ('information_schema', 'pg_catalog', 'system')
62
+ ORDER BY
63
+ c.relname
64
+ `);
65
+
60
66
  return result.map((row: any) => ({
61
67
  name: row.name,
62
68
  type: row.type,
@@ -81,33 +87,31 @@ export class CockroachDBService extends BaseDatabaseService {
81
87
  WHEN column_name IN (
82
88
  SELECT column_name
83
89
  FROM information_schema.key_column_usage
84
- WHERE table_schema = $1
85
- AND table_name = $2
90
+ WHERE table_name = $1
86
91
  AND constraint_name LIKE '%_pkey'
87
92
  ) THEN true
88
93
  ELSE false
89
- END as isPrimary,
94
+ END as "isPrimary",
90
95
  CASE
91
- WHEN data_type LIKE '%serial%' OR data_type LIKE '%identity%'
96
+ WHEN column_default LIKE '%nextval%' OR is_identity = 'YES'
92
97
  THEN true
93
98
  ELSE false
94
- END as isAutoIncrement
99
+ END as "isAutoIncrement"
95
100
  FROM
96
101
  information_schema.columns
97
102
  WHERE
98
- table_schema = $1
99
- AND table_name = $2
103
+ table_name = $1
100
104
  ORDER BY
101
105
  ordinal_position
102
- `, [database, table]);
106
+ `, [table]);
103
107
 
104
108
  return result.map((row: any) => ({
105
109
  name: row.name,
106
110
  type: row.type,
107
111
  nullable: row.nullable === 'YES',
108
112
  defaultValue: row.defaultValue,
109
- isPrimary: row.isPrimary,
110
- isAutoIncrement: row.isAutoIncrement
113
+ isPrimary: row.isPrimary === true,
114
+ isAutoIncrement: row.isAutoIncrement === true
111
115
  }));
112
116
  }
113
117
 
@@ -119,34 +123,43 @@ export class CockroachDBService extends BaseDatabaseService {
119
123
  SELECT
120
124
  i.relname as name,
121
125
  CASE
122
- WHEN i.indisunique THEN 'UNIQUE'
126
+ WHEN ix.indisunique THEN 'UNIQUE'
123
127
  ELSE 'INDEX'
124
128
  END as type,
125
- array_agg(a.attname ORDER BY k.n) as columns,
126
- i.indisunique as unique
129
+ array_agg(a.attname ORDER BY array_position(ix.indkey, a.attnum)) as columns,
130
+ ix.indisunique as unique
127
131
  FROM
128
- pg_index i
129
- JOIN pg_class t ON t.oid = i.indrelid
130
- JOIN pg_namespace n ON n.oid = t.relnamespace
131
- JOIN pg_attribute a ON a.attrelid = t.oid AND a.attnum = ANY(i.indkey)
132
- CROSS JOIN LATERAL unnest(i.indkey) WITH ORDINALITY AS k(n, ord) ON true
132
+ pg_index ix
133
+ JOIN pg_class t ON t.oid = ix.indrelid
134
+ JOIN pg_class i ON i.oid = ix.indexrelid
135
+ JOIN pg_attribute a ON a.attrelid = t.oid AND a.attnum = ANY(ix.indkey)
133
136
  WHERE
134
- n.nspname = $1
135
- AND t.relname = $2
137
+ t.relname = $1
136
138
  GROUP BY
137
- i.relname, i.indisunique
139
+ i.relname, ix.indisunique
138
140
  ORDER BY
139
141
  i.relname
140
- `, [database, table]);
142
+ `, [table]);
141
143
 
142
144
  return result.map((row: any) => ({
143
145
  name: row.name,
144
146
  type: row.type,
145
- columns: row.columns || [],
147
+ columns: this.parsePgArray(row.columns),
146
148
  unique: row.unique
147
149
  }));
148
150
  }
149
151
 
152
+ /**
153
+ * 解析 pg 驱动返回的数组字符串(形如 "{a,b}" 或 "{a}")为 JS 数组
154
+ */
155
+ private parsePgArray(value: any): string[] {
156
+ if (Array.isArray(value)) return value;
157
+ if (typeof value !== 'string') return [];
158
+ const s = value.trim();
159
+ if (!s || s === '{}') return [];
160
+ return s.replace(/^\{|\}$/g, '').split(',').map((x) => x.trim().replace(/^"|"$/g, ''));
161
+ }
162
+
150
163
  /**
151
164
  * 获取CockroachDB外键信息
152
165
  */
@@ -171,11 +184,10 @@ export class CockroachDBService extends BaseDatabaseService {
171
184
  ON rc.constraint_name = tc.constraint_name
172
185
  WHERE
173
186
  tc.constraint_type = 'FOREIGN KEY'
174
- AND tc.table_schema = $1
175
- AND tc.table_name = $2
187
+ AND tc.table_name = $1
176
188
  ORDER BY
177
189
  tc.constraint_name
178
- `, [database, table]);
190
+ `, [table]);
179
191
 
180
192
  return result.map((row: any) => ({
181
193
  name: row.name,
@@ -216,11 +228,9 @@ export class CockroachDBService extends BaseDatabaseService {
216
228
  view_definition as definition
217
229
  FROM
218
230
  information_schema.views
219
- WHERE
220
- table_schema = $1
221
231
  ORDER BY
222
232
  table_name
223
- `, [database]);
233
+ `);
224
234
 
225
235
  return result.map((row: any) => ({
226
236
  name: row.name,
@@ -240,9 +250,8 @@ export class CockroachDBService extends BaseDatabaseService {
240
250
  FROM
241
251
  information_schema.views
242
252
  WHERE
243
- table_schema = $1
244
- AND table_name = $2
245
- `, [database, viewName]);
253
+ table_name = $1
254
+ `, [viewName]);
246
255
  return result[0]?.definition || '';
247
256
  }
248
257
 
@@ -259,11 +268,11 @@ export class CockroachDBService extends BaseDatabaseService {
259
268
  pg_proc p
260
269
  JOIN pg_namespace n ON n.oid = p.pronamespace
261
270
  WHERE
262
- n.nspname = $1
271
+ n.nspname NOT IN ('information_schema', 'pg_catalog', 'system')
263
272
  AND p.prokind = 'f'
264
273
  ORDER BY
265
274
  p.proname
266
- `, [database]);
275
+ `);
267
276
 
268
277
  return result.map((row: any) => ({
269
278
  name: row.name,
@@ -283,9 +292,9 @@ export class CockroachDBService extends BaseDatabaseService {
283
292
  pg_proc p
284
293
  JOIN pg_namespace n ON n.oid = p.pronamespace
285
294
  WHERE
286
- n.nspname = $1
287
- AND p.proname = $2
288
- `, [database, procedureName]);
295
+ n.nspname NOT IN ('information_schema', 'pg_catalog', 'system')
296
+ AND p.proname = $1
297
+ `, [procedureName]);
289
298
  return result[0]?.definition || '';
290
299
  }
291
300
 
@@ -1,7 +1,7 @@
1
1
  import { ConnectionService } from '../connection.service';
2
2
  import { BaseDatabaseService } from './base.service';
3
3
  import { DatabaseEntity, TableEntity } from '../../model/database.entity';
4
- import type { DdlCapability, DdlPreview, TableSpec } from '../../model/ddl-spec';
4
+ import type { DdlCapability, DdlExecuteResult, DdlPreview, TableSpec } from '../../model/ddl-spec';
5
5
  /**
6
6
  * 数据库服务管理类
7
7
  * 负责根据数据库类型选择相应的服务实现
@@ -82,9 +82,7 @@ export declare class DatabaseService {
82
82
  /**
83
83
  * 执行建表:与预览同一出口生成语句后执行(事务包裹)。
84
84
  */
85
- executeCreateTable(connectionId: string, databaseName: string, spec: TableSpec): Promise<{
86
- statements: string[];
87
- }>;
85
+ executeCreateTable(connectionId: string, databaseName: string, spec: TableSpec): Promise<DdlExecuteResult>;
88
86
  /**
89
87
  * 表结构变更计划(preview/execute 的单一出口)。
90
88
  *
@@ -132,223 +130,7 @@ export declare class DatabaseService {
132
130
  /**
133
131
  * 获取支持的数据库类型
134
132
  */
135
- getSupportedDatabaseTypes(): ({
136
- value: string;
137
- label: string;
138
- icon: string;
139
- defaultPort: number;
140
- description: string;
141
- features: {
142
- supportSchemas: boolean;
143
- supportProcedures: boolean;
144
- supportTriggers: boolean;
145
- supportViews: boolean;
146
- supportFullTextSearch: boolean;
147
- supportJson: boolean;
148
- supportArrays?: undefined;
149
- supportEnum?: undefined;
150
- supportSequences?: undefined;
151
- supportSynonyms?: undefined;
152
- supportStoredProcedures?: undefined;
153
- supportDistributed?: undefined;
154
- supportDocuments?: undefined;
155
- supportNoSQL?: undefined;
156
- supportInMemory?: undefined;
157
- supportHighPerformance?: undefined;
158
- };
159
- } | {
160
- value: string;
161
- label: string;
162
- icon: string;
163
- defaultPort: number;
164
- description: string;
165
- features: {
166
- supportSchemas: boolean;
167
- supportProcedures: boolean;
168
- supportTriggers: boolean;
169
- supportViews: boolean;
170
- supportFullTextSearch: boolean;
171
- supportJson: boolean;
172
- supportArrays: boolean;
173
- supportEnum: boolean;
174
- supportSequences?: undefined;
175
- supportSynonyms?: undefined;
176
- supportStoredProcedures?: undefined;
177
- supportDistributed?: undefined;
178
- supportDocuments?: undefined;
179
- supportNoSQL?: undefined;
180
- supportInMemory?: undefined;
181
- supportHighPerformance?: undefined;
182
- };
183
- } | {
184
- value: string;
185
- label: string;
186
- icon: string;
187
- defaultPort: any;
188
- description: string;
189
- features: {
190
- supportSchemas: boolean;
191
- supportProcedures: boolean;
192
- supportTriggers: boolean;
193
- supportViews: boolean;
194
- supportFullTextSearch: boolean;
195
- supportJson: boolean;
196
- supportArrays: boolean;
197
- supportEnum?: undefined;
198
- supportSequences?: undefined;
199
- supportSynonyms?: undefined;
200
- supportStoredProcedures?: undefined;
201
- supportDistributed?: undefined;
202
- supportDocuments?: undefined;
203
- supportNoSQL?: undefined;
204
- supportInMemory?: undefined;
205
- supportHighPerformance?: undefined;
206
- };
207
- } | {
208
- value: string;
209
- label: string;
210
- icon: string;
211
- defaultPort: number;
212
- description: string;
213
- features: {
214
- supportSchemas: boolean;
215
- supportProcedures: boolean;
216
- supportTriggers: boolean;
217
- supportViews: boolean;
218
- supportFullTextSearch: boolean;
219
- supportJson: boolean;
220
- supportArrays: boolean;
221
- supportSequences: boolean;
222
- supportSynonyms: boolean;
223
- supportEnum?: undefined;
224
- supportStoredProcedures?: undefined;
225
- supportDistributed?: undefined;
226
- supportDocuments?: undefined;
227
- supportNoSQL?: undefined;
228
- supportInMemory?: undefined;
229
- supportHighPerformance?: undefined;
230
- };
231
- } | {
232
- value: string;
233
- label: string;
234
- icon: string;
235
- defaultPort: number;
236
- description: string;
237
- features: {
238
- supportSchemas: boolean;
239
- supportProcedures: boolean;
240
- supportTriggers: boolean;
241
- supportViews: boolean;
242
- supportFullTextSearch: boolean;
243
- supportJson: boolean;
244
- supportArrays: boolean;
245
- supportStoredProcedures: boolean;
246
- supportEnum?: undefined;
247
- supportSequences?: undefined;
248
- supportSynonyms?: undefined;
249
- supportDistributed?: undefined;
250
- supportDocuments?: undefined;
251
- supportNoSQL?: undefined;
252
- supportInMemory?: undefined;
253
- supportHighPerformance?: undefined;
254
- };
255
- } | {
256
- value: string;
257
- label: string;
258
- icon: string;
259
- defaultPort: number;
260
- description: string;
261
- features: {
262
- supportSchemas: boolean;
263
- supportProcedures: boolean;
264
- supportTriggers: boolean;
265
- supportViews: boolean;
266
- supportFullTextSearch: boolean;
267
- supportJson: boolean;
268
- supportArrays: boolean;
269
- supportEnum: boolean;
270
- supportDistributed: boolean;
271
- supportSequences?: undefined;
272
- supportSynonyms?: undefined;
273
- supportStoredProcedures?: undefined;
274
- supportDocuments?: undefined;
275
- supportNoSQL?: undefined;
276
- supportInMemory?: undefined;
277
- supportHighPerformance?: undefined;
278
- };
279
- } | {
280
- value: string;
281
- label: string;
282
- icon: string;
283
- defaultPort: number;
284
- description: string;
285
- features: {
286
- supportSchemas: boolean;
287
- supportProcedures: boolean;
288
- supportTriggers: boolean;
289
- supportViews: boolean;
290
- supportFullTextSearch: boolean;
291
- supportJson: boolean;
292
- supportArrays: boolean;
293
- supportDocuments: boolean;
294
- supportNoSQL: boolean;
295
- supportEnum?: undefined;
296
- supportSequences?: undefined;
297
- supportSynonyms?: undefined;
298
- supportStoredProcedures?: undefined;
299
- supportDistributed?: undefined;
300
- supportInMemory?: undefined;
301
- supportHighPerformance?: undefined;
302
- };
303
- } | {
304
- value: string;
305
- label: string;
306
- icon: string;
307
- defaultPort: number;
308
- description: string;
309
- features: {
310
- supportSchemas: boolean;
311
- supportProcedures: boolean;
312
- supportTriggers: boolean;
313
- supportViews: boolean;
314
- supportFullTextSearch: boolean;
315
- supportJson: boolean;
316
- supportArrays: boolean;
317
- supportInMemory: boolean;
318
- supportHighPerformance: boolean;
319
- supportEnum?: undefined;
320
- supportSequences?: undefined;
321
- supportSynonyms?: undefined;
322
- supportStoredProcedures?: undefined;
323
- supportDistributed?: undefined;
324
- supportDocuments?: undefined;
325
- supportNoSQL?: undefined;
326
- };
327
- } | {
328
- value: string;
329
- label: string;
330
- icon: string;
331
- defaultPort: number;
332
- description: string;
333
- features: {
334
- supportSchemas: boolean;
335
- supportProcedures: boolean;
336
- supportTriggers: boolean;
337
- supportViews: boolean;
338
- supportFullTextSearch: boolean;
339
- supportJson: boolean;
340
- supportArrays: boolean;
341
- supportDistributed: boolean;
342
- supportHighPerformance: boolean;
343
- supportEnum?: undefined;
344
- supportSequences?: undefined;
345
- supportSynonyms?: undefined;
346
- supportStoredProcedures?: undefined;
347
- supportDocuments?: undefined;
348
- supportNoSQL?: undefined;
349
- supportInMemory?: undefined;
350
- };
351
- })[];
133
+ getSupportedDatabaseTypes(): any[];
352
134
  /**
353
135
  * 创建数据库
354
136
  */
@@ -1 +1 @@
1
- {"version":3,"file":"database.service.d.ts","sourceRoot":"","sources":["../../../../server/service/database/database.service.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"database.service.d.ts","sourceRoot":"","sources":["../../../../server/service/database/database.service.ts"],"names":[],"mappings":"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"}
@@ -165,20 +165,23 @@ class DatabaseService {
165
165
  /**
166
166
  * 目标态 TableSpec 的静态校验(建表/改表共用)
167
167
  */
168
- validateTableSpec(spec) {
168
+ validateTableSpec(spec, requireColumns = true) {
169
169
  if (!spec || typeof spec.name !== 'string' || !spec.name.trim()) {
170
170
  throw new Error('目标表名不能为空');
171
171
  }
172
- if (!Array.isArray(spec.columns) || spec.columns.length === 0) {
172
+ // 无模式方言(MongoDB 建集合)没有列定义,不强制要求至少一列
173
+ if (requireColumns && (!Array.isArray(spec.columns) || spec.columns.length === 0)) {
173
174
  throw new Error('目标结构至少需要一列');
174
175
  }
175
- const names = new Set(spec.columns.map((c) => c.name));
176
- if (names.size !== spec.columns.length) {
177
- throw new Error('目标结构存在重名列');
178
- }
179
- for (const pk of spec.primaryKey || []) {
180
- if (!names.has(pk))
181
- throw new Error(`主键列 "${pk}" 不在目标结构中`);
176
+ if (Array.isArray(spec.columns) && spec.columns.length > 0) {
177
+ const names = new Set(spec.columns.map((c) => c.name));
178
+ if (names.size !== spec.columns.length) {
179
+ throw new Error('目标结构存在重名列');
180
+ }
181
+ for (const pk of spec.primaryKey || []) {
182
+ if (!names.has(pk))
183
+ throw new Error(`主键列 "${pk}" 不在目标结构中`);
184
+ }
182
185
  }
183
186
  return spec.name.trim();
184
187
  }
@@ -188,25 +191,31 @@ class DatabaseService {
188
191
  * 前端建表全部走同一渲染出口,CREATE TABLE 不再有第二份方言实现。
189
192
  */
190
193
  async buildCreatePlan(connectionId, databaseName, spec, forceRefresh = false) {
191
- const tableName = this.validateTableSpec(spec);
192
194
  const dataSource = await this.connectionService.getActiveConnection(connectionId, databaseName);
193
195
  const type = dataSource.options.type;
194
196
  const kind = (0, dialect_1.getDialectInfo)(type).kind;
195
197
  const dbService = this.getDatabaseService(type);
196
198
  const caps = (0, ddl_emitter_1.ddlCapabilities)(kind);
199
+ // 无模式方言(MongoDB):走驱动原生建集合——不生成 CREATE TABLE SQL,也不需要列定义
200
+ const driverCreate = caps.createStrategy === 'driver';
201
+ const tableName = this.validateTableSpec(spec, !driverCreate);
197
202
  // 方言不支持建表:作为计划内错误返回(而非抛出)——capabilities 仍要带回前端用于禁用 UI
198
203
  if (!caps.createTable) {
199
- return { dataSource, kind, caps, dbService, statements: [], error: `该数据库类型(${kind})不支持通过 SQL 建表` };
204
+ return { dataSource, kind, caps, dbService, tableName, statements: [], error: `该数据库类型(${kind})不支持通过 SQL 建表` };
200
205
  }
201
206
  // 重名检测:目标态与实时结构冲突(等价 409 语义)。
202
207
  // 预览走缓存避免每次输入都全量拉表;执行前必须 force 刷新,否则缓存会让重名检测失效。
203
208
  const tables = await this.getTableList(connectionId, databaseName, forceRefresh);
204
209
  if (tables.some((t) => (0, ddl_emitter_1.tableNameEquals)(kind, String(t?.name ?? ''), tableName))) {
205
- return { dataSource, kind, caps, dbService, statements: [], error: `表 "${tableName}" 已存在` };
210
+ return { dataSource, kind, caps, dbService, tableName, statements: [], error: `表 "${tableName}" 已存在` };
211
+ }
212
+ // 驱动路径:无列定义、无 SQL 语句,执行阶段直接调 dbService.createTable
213
+ if (driverCreate) {
214
+ return { dataSource, kind, caps, dbService, tableName, statements: [], error: '' };
206
215
  }
207
216
  const desired = (0, canonical_1.canonicalizeTableSpec)(spec);
208
217
  const statements = (0, ddl_emitter_1.emitCreateDdl)(kind, desired, { mssqlDatabase: databaseName });
209
- return { dataSource, kind, caps, dbService, statements, error: '' };
218
+ return { dataSource, kind, caps, dbService, tableName, statements, error: '' };
210
219
  }
211
220
  /**
212
221
  * 预览建表:纯计算不执行。与执行同一出口生成语句,所见即所得。
@@ -216,14 +225,21 @@ class DatabaseService {
216
225
  */
217
226
  async previewCreateTable(connectionId, databaseName, spec) {
218
227
  const plan = await this.buildCreatePlan(connectionId, databaseName, spec);
219
- if (plan.error)
220
- throw new Error(plan.error);
221
- const previewText = plan.statements.length > 0 ? plan.statements.join(';\n') + ';' : '';
228
+ // 注意:计划级非致命错误(方言不支持建表、表已存在)不能抛——否则 capabilities 不会返回,
229
+ // 前端无法据此禁用提交按钮。错误以注释形式写入预览,并由前端 submitDisabledHint 展示。
230
+ const previewText = plan.statements.length > 0
231
+ ? plan.statements.join(';\n') + ';'
232
+ : plan.error
233
+ ? `-- ${plan.error}`
234
+ : (plan.caps.createStrategy === 'driver'
235
+ ? `-- 创建集合 "${plan.tableName}"(无模式集合,不生成建表 SQL)`
236
+ : '');
222
237
  return {
223
238
  statements: plan.statements,
224
239
  preview: previewText,
225
240
  changeSet: null,
226
- capabilities: plan.caps
241
+ capabilities: plan.caps,
242
+ error: plan.error || null
227
243
  };
228
244
  }
229
245
  /**
@@ -234,6 +250,19 @@ class DatabaseService {
234
250
  const plan = await this.buildCreatePlan(connectionId, databaseName, spec, true);
235
251
  if (plan.error)
236
252
  throw new Error(plan.error);
253
+ // 无模式方言(MongoDB):没有建表 SQL,直接走驱动原生建集合
254
+ if (plan.caps.createStrategy === 'driver') {
255
+ try {
256
+ await plan.dbService.createTable(plan.dataSource, databaseName, { name: plan.tableName });
257
+ }
258
+ catch (error) {
259
+ console.error('执行创建集合失败:', error);
260
+ throw new Error(`创建集合失败: ${error instanceof Error ? error.message : String(error)}`);
261
+ }
262
+ this.invalidateTableList(connectionId, databaseName); // 集合列表已变化
263
+ // native: 无 SQL 语句但集合已实际创建——前端据此与"无修改"区分
264
+ return { statements: plan.statements, native: true };
265
+ }
237
266
  if (plan.statements.length === 0)
238
267
  throw new Error('未能生成建表语句');
239
268
  try {
@@ -315,14 +344,16 @@ class DatabaseService {
315
344
  */
316
345
  async previewAlterTable(connectionId, databaseName, tableName, spec) {
317
346
  const plan = await this.buildAlterPlan(connectionId, databaseName, tableName, spec);
318
- if (plan.error)
319
- throw new Error(plan.error);
320
- const previewText = plan.statements.length > 0 ? plan.statements.join(';\n') + ';' : '';
347
+ // 与 previewCreateTable 同理:计划级非致命错误不抛,确保 capabilities 返回以驱动 UI 禁用。
348
+ const previewText = plan.statements.length > 0
349
+ ? plan.statements.join(';\n') + ';'
350
+ : (plan.error ? `-- ${plan.error}` : '');
321
351
  return {
322
352
  statements: plan.statements,
323
353
  preview: previewText,
324
354
  changeSet: plan.changeSet,
325
- capabilities: plan.caps
355
+ capabilities: plan.caps,
356
+ error: plan.error || null
326
357
  };
327
358
  }
328
359
  /**
@@ -646,7 +677,10 @@ class DatabaseService {
646
677
  supportJson: true,
647
678
  supportArrays: true,
648
679
  supportDocuments: true,
649
- supportNoSQL: true
680
+ supportNoSQL: true,
681
+ // 数据层能力:文档型、无 SQL 编辑器(前端据此切文档模式 UI)
682
+ dataModel: 'document',
683
+ supportSqlEditor: false
650
684
  }
651
685
  },
652
686
  {
@@ -654,7 +688,11 @@ class DatabaseService {
654
688
  label: 'SAP HANA',
655
689
  icon: 'bi-database',
656
690
  defaultPort: 39013,
657
- description: 'SAP HANA内存数据库',
691
+ description: 'SAP HANA内存数据库(实验性)',
692
+ // 实验性:依赖未随默认依赖安装的 @sap/hana-client 驱动,且官方无免费 Docker 镜像,
693
+ // 本仓库尚未做端到端运行验证。驱动缺失时会给出明确的安装提示。
694
+ experimental: true,
695
+ driverPackage: '@sap/hana-client',
658
696
  features: {
659
697
  supportSchemas: true,
660
698
  supportProcedures: true,
@@ -700,7 +738,11 @@ class DatabaseService {
700
738
  supportJson: false
701
739
  }
702
740
  }
703
- ];
741
+ ].map((t) => ({
742
+ ...t,
743
+ // 数据层能力默认值:关系型 + 支持 SQL;文档型(MongoDB)在自身 features 中覆盖
744
+ features: { dataModel: 'relational', supportSqlEditor: true, ...(t.features || {}) }
745
+ }));
704
746
  }
705
747
  /**
706
748
  * 创建数据库