fdb2 1.0.27 → 1.0.31

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 (75) hide show
  1. package/bin/fdb2.js +18 -2
  2. package/dist/public/.vite/manifest.json +4 -4
  3. package/dist/public/bootstrap.js +6 -5
  4. package/dist/public/explorer.js +318 -193
  5. package/dist/public/index.css +59 -0
  6. package/dist/public/index.js +486 -259
  7. package/dist/public/layout.js +2 -2
  8. package/dist/public/rolldown-runtime.js +8 -1
  9. package/dist/public/vconsole.min.js +0 -26
  10. package/dist/public/vue.js +5238 -5192
  11. package/dist/server/cli/format.d.ts +6 -0
  12. package/dist/server/cli/format.d.ts.map +1 -0
  13. package/dist/server/cli/format.js +116 -0
  14. package/dist/server/cli/format.js.map +1 -0
  15. package/dist/server/cli/format.ts +104 -0
  16. package/dist/server/cli/main.d.ts +3 -0
  17. package/dist/server/cli/main.d.ts.map +1 -0
  18. package/dist/server/cli/main.js +710 -0
  19. package/dist/server/cli/main.js.map +1 -0
  20. package/dist/server/cli/main.ts +746 -0
  21. package/dist/server/cli/parse.d.ts +18 -0
  22. package/dist/server/cli/parse.d.ts.map +1 -0
  23. package/dist/server/cli/parse.js +150 -0
  24. package/dist/server/cli/parse.js.map +1 -0
  25. package/dist/server/cli/parse.ts +148 -0
  26. package/dist/server/core/column-spec.d.ts +29 -0
  27. package/dist/server/core/column-spec.d.ts.map +1 -0
  28. package/dist/server/core/column-spec.js +148 -0
  29. package/dist/server/core/column-spec.js.map +1 -0
  30. package/dist/server/core/column-spec.ts +147 -0
  31. package/dist/server/core/config.d.ts +34 -0
  32. package/dist/server/core/config.d.ts.map +1 -0
  33. package/dist/server/core/config.js +187 -0
  34. package/dist/server/core/config.js.map +1 -0
  35. package/dist/server/core/config.ts +165 -0
  36. package/dist/server/core/db-api.d.ts +169 -0
  37. package/dist/server/core/db-api.d.ts.map +1 -0
  38. package/dist/server/core/db-api.js +1078 -0
  39. package/dist/server/core/db-api.js.map +1 -0
  40. package/dist/server/core/db-api.ts +1181 -0
  41. package/dist/server/core/dialect.d.ts +44 -0
  42. package/dist/server/core/dialect.d.ts.map +1 -0
  43. package/dist/server/core/dialect.js +260 -0
  44. package/dist/server/core/dialect.js.map +1 -0
  45. package/dist/server/core/dialect.ts +293 -0
  46. package/dist/server/core/errors.d.ts +22 -0
  47. package/dist/server/core/errors.d.ts.map +1 -0
  48. package/dist/server/core/errors.js +61 -0
  49. package/dist/server/core/errors.js.map +1 -0
  50. package/dist/server/core/errors.ts +58 -0
  51. package/dist/server/core/filter-dsl.d.ts +39 -0
  52. package/dist/server/core/filter-dsl.d.ts.map +1 -0
  53. package/dist/server/core/filter-dsl.js +167 -0
  54. package/dist/server/core/filter-dsl.js.map +1 -0
  55. package/dist/server/core/filter-dsl.ts +180 -0
  56. package/dist/server/core/guard.d.ts +54 -0
  57. package/dist/server/core/guard.d.ts.map +1 -0
  58. package/dist/server/core/guard.js +207 -0
  59. package/dist/server/core/guard.js.map +1 -0
  60. package/dist/server/core/guard.ts +205 -0
  61. package/dist/server/core/query-builder.d.ts +72 -0
  62. package/dist/server/core/query-builder.d.ts.map +1 -0
  63. package/dist/server/core/query-builder.js +478 -0
  64. package/dist/server/core/query-builder.js.map +1 -0
  65. package/dist/server/core/query-builder.ts +502 -0
  66. package/dist/server/service/connection.service.d.ts.map +1 -1
  67. package/dist/server/service/connection.service.js +7 -3
  68. package/dist/server/service/connection.service.js.map +1 -1
  69. package/dist/server/service/connection.service.ts +5 -3
  70. package/dist/server/utils/data-dir.d.ts.map +1 -1
  71. package/dist/server/utils/data-dir.js +2 -0
  72. package/dist/server/utils/data-dir.js.map +1 -1
  73. package/dist/server/utils/data-dir.ts +2 -0
  74. package/electron/updater.js +12 -66
  75. package/package.json +22 -22
@@ -0,0 +1,18 @@
1
+ export type OptType = 'bool' | 'string' | 'int' | 'list' | 'json';
2
+ export interface OptDef {
3
+ name: string;
4
+ alias?: string;
5
+ type: OptType;
6
+ }
7
+ export interface Parsed {
8
+ pos: string[];
9
+ values: Record<string, any>;
10
+ }
11
+ /** 全局通用选项(每个命令都可用) */
12
+ export declare const GLOBAL_DEFS: OptDef[];
13
+ export declare function parseArgs(argv: string[], extraDefs?: OptDef[]): Parsed;
14
+ /** k=v 列表解析 */
15
+ export declare function parseKvList(list: string[]): Record<string, any>;
16
+ /** csv 拆分(--select a,b) */
17
+ export declare function splitCsv(s?: string): string[];
18
+ //# sourceMappingURL=parse.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse.d.ts","sourceRoot":"","sources":["../../../server/cli/parse.ts"],"names":[],"mappings":"AAMA,MAAM,MAAM,OAAO,GAAG,MAAM,GAAG,QAAQ,GAAG,KAAK,GAAG,MAAM,GAAG,MAAM,CAAC;AAElE,MAAM,WAAW,MAAM;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,OAAO,CAAC;CACf;AAED,MAAM,WAAW,MAAM;IACrB,GAAG,EAAE,MAAM,EAAE,CAAC;IACd,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;CAC7B;AAED,sBAAsB;AACtB,eAAO,MAAM,WAAW,EAAE,MAAM,EA0B/B,CAAC;AAEF,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,SAAS,GAAE,MAAM,EAAO,GAAG,MAAM,CAqE1E;AAED,eAAe;AACf,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAU/D;AAED,2BAA2B;AAC3B,wBAAgB,QAAQ,CAAC,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAM7C"}
@@ -0,0 +1,150 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.GLOBAL_DEFS = void 0;
4
+ exports.parseArgs = parseArgs;
5
+ exports.parseKvList = parseKvList;
6
+ exports.splitCsv = splitCsv;
7
+ /**
8
+ * 轻量参数解析器(零依赖)
9
+ * 支持:--k v、--k=v、-a v;可重复 list 参数(--filter a --filter b)
10
+ */
11
+ const errors_1 = require("../core/errors");
12
+ /** 全局通用选项(每个命令都可用) */
13
+ exports.GLOBAL_DEFS = [
14
+ { name: 'json', type: 'bool' },
15
+ { name: 'quiet', type: 'bool' },
16
+ { name: 'yes', type: 'bool' },
17
+ { name: 'write', type: 'bool' },
18
+ { name: 'dry-run', alias: 'dry', type: 'bool' },
19
+ { name: 'confirm', type: 'string' },
20
+ { name: 'force', type: 'bool' },
21
+ { name: 'conn', type: 'string' },
22
+ { name: 'db', type: 'string' },
23
+ { name: 'limit', type: 'int' },
24
+ { name: 'offset', type: 'int' },
25
+ { name: 'count', type: 'bool' },
26
+ { name: 'out', type: 'string' },
27
+ // 连接参数
28
+ { name: 'name', type: 'string' },
29
+ { name: 'type', type: 'string' },
30
+ { name: 'host', type: 'string' },
31
+ { name: 'port', type: 'int' },
32
+ { name: 'database', type: 'string' },
33
+ { name: 'username', type: 'string' },
34
+ { name: 'password', type: 'string' },
35
+ { name: 'password-stdin', type: 'bool' },
36
+ { name: 'ssl', type: 'bool' },
37
+ { name: 'option', type: 'list' },
38
+ { name: 'enabled', type: 'string' }
39
+ ];
40
+ function parseArgs(argv, extraDefs = []) {
41
+ const defs = extraDefs.concat(exports.GLOBAL_DEFS);
42
+ const index = {};
43
+ for (const d of defs) {
44
+ index['--' + d.name] = d;
45
+ if (d.alias)
46
+ index['-' + d.alias] = d;
47
+ }
48
+ const pos = [];
49
+ const values = {};
50
+ let i = 0;
51
+ const setVal = (def, rawVal, hasEq) => {
52
+ if (def.type === 'bool') {
53
+ values[def.name] = hasEq ? !(rawVal === 'false' || rawVal === '0') : true;
54
+ return;
55
+ }
56
+ if (rawVal === null || rawVal === undefined) {
57
+ throw new errors_1.AppError('PARAM_ERROR', `选项 --${def.name} 缺少值`);
58
+ }
59
+ if (def.type === 'int') {
60
+ const n = Math.floor(Number(rawVal));
61
+ if (!Number.isFinite(n))
62
+ throw new errors_1.AppError('PARAM_ERROR', `选项 --${def.name} 需要整数,收到: ${rawVal}`);
63
+ values[def.name] = n;
64
+ }
65
+ else if (def.type === 'list') {
66
+ if (!values[def.name])
67
+ values[def.name] = [];
68
+ values[def.name].push(rawVal);
69
+ }
70
+ else if (def.type === 'json') {
71
+ try {
72
+ values[def.name] = JSON.parse(rawVal);
73
+ }
74
+ catch (e) {
75
+ throw new errors_1.AppError('PARAM_ERROR', `选项 --${def.name} 需要合法 JSON,收到: ${rawVal}`);
76
+ }
77
+ }
78
+ else {
79
+ values[def.name] = rawVal;
80
+ }
81
+ };
82
+ while (i < argv.length) {
83
+ const token = argv[i];
84
+ if (token === '--') {
85
+ pos.push(...argv.slice(i + 1));
86
+ break;
87
+ }
88
+ if (token.startsWith('--') || (token.startsWith('-') && token.length > 1 && !/^-\d/.test(token))) {
89
+ const eq = token.indexOf('=');
90
+ const key = eq > 0 ? token.slice(0, eq) : token;
91
+ const def = index[key];
92
+ if (!def) {
93
+ throw new errors_1.AppError('PARAM_ERROR', `未知选项: ${token}`, { hint: `可用选项: ${Object.keys(index).join(' ')}` });
94
+ }
95
+ if (eq > 0) {
96
+ setVal(def, token.slice(eq + 1), true);
97
+ i++;
98
+ }
99
+ else if (def.type === 'bool') {
100
+ setVal(def, null, false);
101
+ i++;
102
+ }
103
+ else {
104
+ const next = argv[i + 1];
105
+ if (next === undefined)
106
+ throw new errors_1.AppError('PARAM_ERROR', `选项 --${def.name} 缺少值`);
107
+ setVal(def, next, false);
108
+ i += 2;
109
+ }
110
+ }
111
+ else {
112
+ pos.push(token);
113
+ i++;
114
+ }
115
+ }
116
+ return { pos, values };
117
+ }
118
+ /** k=v 列表解析 */
119
+ function parseKvList(list) {
120
+ const out = {};
121
+ for (const item of list || []) {
122
+ const eq = item.indexOf('=');
123
+ if (eq <= 0)
124
+ throw new errors_1.AppError('PARAM_ERROR', `选项格式应为 k=v,收到: ${item}`);
125
+ const k = item.slice(0, eq).trim();
126
+ const v = item.slice(eq + 1).trim();
127
+ out[k] = coerceOptValue(v);
128
+ }
129
+ return out;
130
+ }
131
+ /** csv 拆分(--select a,b) */
132
+ function splitCsv(s) {
133
+ if (!s)
134
+ return [];
135
+ return String(s)
136
+ .split(',')
137
+ .map((x) => x.trim())
138
+ .filter(Boolean);
139
+ }
140
+ function coerceOptValue(v) {
141
+ if (v === 'true')
142
+ return true;
143
+ if (v === 'false')
144
+ return false;
145
+ const n = Number(v);
146
+ if (v !== '' && !Number.isNaN(n) && String(v).trim() !== '')
147
+ return n;
148
+ return v;
149
+ }
150
+ //# sourceMappingURL=parse.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse.js","sourceRoot":"","sources":["../../../server/cli/parse.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,148 @@
1
+ /**
2
+ * 轻量参数解析器(零依赖)
3
+ * 支持:--k v、--k=v、-a v;可重复 list 参数(--filter a --filter b)
4
+ */
5
+ import { AppError } from '../core/errors';
6
+
7
+ export type OptType = 'bool' | 'string' | 'int' | 'list' | 'json';
8
+
9
+ export interface OptDef {
10
+ name: string;
11
+ alias?: string;
12
+ type: OptType;
13
+ }
14
+
15
+ export interface Parsed {
16
+ pos: string[];
17
+ values: Record<string, any>;
18
+ }
19
+
20
+ /** 全局通用选项(每个命令都可用) */
21
+ export const GLOBAL_DEFS: OptDef[] = [
22
+ { name: 'json', type: 'bool' },
23
+ { name: 'quiet', type: 'bool' },
24
+ { name: 'yes', type: 'bool' },
25
+ { name: 'write', type: 'bool' },
26
+ { name: 'dry-run', alias: 'dry', type: 'bool' },
27
+ { name: 'confirm', type: 'string' },
28
+ { name: 'force', type: 'bool' },
29
+ { name: 'conn', type: 'string' },
30
+ { name: 'db', type: 'string' },
31
+ { name: 'limit', type: 'int' },
32
+ { name: 'offset', type: 'int' },
33
+ { name: 'count', type: 'bool' },
34
+ { name: 'out', type: 'string' },
35
+ // 连接参数
36
+ { name: 'name', type: 'string' },
37
+ { name: 'type', type: 'string' },
38
+ { name: 'host', type: 'string' },
39
+ { name: 'port', type: 'int' },
40
+ { name: 'database', type: 'string' },
41
+ { name: 'username', type: 'string' },
42
+ { name: 'password', type: 'string' },
43
+ { name: 'password-stdin', type: 'bool' },
44
+ { name: 'ssl', type: 'bool' },
45
+ { name: 'option', type: 'list' },
46
+ { name: 'enabled', type: 'string' }
47
+ ];
48
+
49
+ export function parseArgs(argv: string[], extraDefs: OptDef[] = []): Parsed {
50
+ const defs = extraDefs.concat(GLOBAL_DEFS);
51
+ const index: Record<string, OptDef> = {};
52
+ for (const d of defs) {
53
+ index['--' + d.name] = d;
54
+ if (d.alias) index['-' + d.alias] = d;
55
+ }
56
+
57
+ const pos: string[] = [];
58
+ const values: Record<string, any> = {};
59
+ let i = 0;
60
+
61
+ const setVal = (def: OptDef, rawVal: string | null, hasEq: boolean) => {
62
+ if (def.type === 'bool') {
63
+ values[def.name] = hasEq ? !(rawVal === 'false' || rawVal === '0') : true;
64
+ return;
65
+ }
66
+ if (rawVal === null || rawVal === undefined) {
67
+ throw new AppError('PARAM_ERROR', `选项 --${def.name} 缺少值`);
68
+ }
69
+ if (def.type === 'int') {
70
+ const n = Math.floor(Number(rawVal));
71
+ if (!Number.isFinite(n)) throw new AppError('PARAM_ERROR', `选项 --${def.name} 需要整数,收到: ${rawVal}`);
72
+ values[def.name] = n;
73
+ } else if (def.type === 'list') {
74
+ if (!values[def.name]) values[def.name] = [];
75
+ values[def.name].push(rawVal);
76
+ } else if (def.type === 'json') {
77
+ try {
78
+ values[def.name] = JSON.parse(rawVal);
79
+ } catch (e) {
80
+ throw new AppError('PARAM_ERROR', `选项 --${def.name} 需要合法 JSON,收到: ${rawVal}`);
81
+ }
82
+ } else {
83
+ values[def.name] = rawVal;
84
+ }
85
+ };
86
+
87
+ while (i < argv.length) {
88
+ const token = argv[i];
89
+ if (token === '--') {
90
+ pos.push(...argv.slice(i + 1));
91
+ break;
92
+ }
93
+ if (token.startsWith('--') || (token.startsWith('-') && token.length > 1 && !/^-\d/.test(token))) {
94
+ const eq = token.indexOf('=');
95
+ const key = eq > 0 ? token.slice(0, eq) : token;
96
+ const def = index[key];
97
+ if (!def) {
98
+ throw new AppError('PARAM_ERROR', `未知选项: ${token}`, { hint: `可用选项: ${Object.keys(index).join(' ')}` });
99
+ }
100
+ if (eq > 0) {
101
+ setVal(def, token.slice(eq + 1), true);
102
+ i++;
103
+ } else if (def.type === 'bool') {
104
+ setVal(def, null, false);
105
+ i++;
106
+ } else {
107
+ const next = argv[i + 1];
108
+ if (next === undefined) throw new AppError('PARAM_ERROR', `选项 --${def.name} 缺少值`);
109
+ setVal(def, next, false);
110
+ i += 2;
111
+ }
112
+ } else {
113
+ pos.push(token);
114
+ i++;
115
+ }
116
+ }
117
+ return { pos, values };
118
+ }
119
+
120
+ /** k=v 列表解析 */
121
+ export function parseKvList(list: string[]): Record<string, any> {
122
+ const out: Record<string, any> = {};
123
+ for (const item of list || []) {
124
+ const eq = item.indexOf('=');
125
+ if (eq <= 0) throw new AppError('PARAM_ERROR', `选项格式应为 k=v,收到: ${item}`);
126
+ const k = item.slice(0, eq).trim();
127
+ const v = item.slice(eq + 1).trim();
128
+ out[k] = coerceOptValue(v);
129
+ }
130
+ return out;
131
+ }
132
+
133
+ /** csv 拆分(--select a,b) */
134
+ export function splitCsv(s?: string): string[] {
135
+ if (!s) return [];
136
+ return String(s)
137
+ .split(',')
138
+ .map((x) => x.trim())
139
+ .filter(Boolean);
140
+ }
141
+
142
+ function coerceOptValue(v: string): any {
143
+ if (v === 'true') return true;
144
+ if (v === 'false') return false;
145
+ const n = Number(v);
146
+ if (v !== '' && !Number.isNaN(n) && String(v).trim() !== '') return n;
147
+ return v;
148
+ }
@@ -0,0 +1,29 @@
1
+ /**
2
+ * 列定义 DSL:name:type[:约束...]
3
+ * 约束: primary | auto_increment | not_null | null | unique
4
+ * default=<v> | comment=<str> | len=<n> | precision=<p[,s]>
5
+ * 示例: id:int:primary:auto_increment
6
+ * name:varchar:len=64:not_null
7
+ * amount:decimal:precision=10,2:default=0
8
+ */
9
+ export interface ParsedColumn {
10
+ name: string;
11
+ /** 类型全名(含长度),如 varchar(64) */
12
+ type: string;
13
+ /** 基础类型,如 varchar */
14
+ baseType: string;
15
+ nullable: boolean;
16
+ isPrimary: boolean;
17
+ isAutoIncrement: boolean;
18
+ unique: boolean;
19
+ defaultValue?: any;
20
+ hasDefault: boolean;
21
+ comment?: string;
22
+ length?: number;
23
+ precision?: number;
24
+ scale?: number;
25
+ /** 原始 spec 字符串 */
26
+ raw: string;
27
+ }
28
+ export declare function parseColumnSpec(spec: string): ParsedColumn;
29
+ //# sourceMappingURL=column-spec.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"column-spec.d.ts","sourceRoot":"","sources":["../../../server/core/column-spec.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,8BAA8B;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,qBAAqB;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,OAAO,CAAC;IAClB,SAAS,EAAE,OAAO,CAAC;IACnB,eAAe,EAAE,OAAO,CAAC;IACzB,MAAM,EAAE,OAAO,CAAC;IAChB,YAAY,CAAC,EAAE,GAAG,CAAC;IACnB,UAAU,EAAE,OAAO,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,kBAAkB;IAClB,GAAG,EAAE,MAAM,CAAC;CACb;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,YAAY,CA0E1D"}
@@ -0,0 +1,148 @@
1
+ "use strict";
2
+ /**
3
+ * 列定义 DSL:name:type[:约束...]
4
+ * 约束: primary | auto_increment | not_null | null | unique
5
+ * default=<v> | comment=<str> | len=<n> | precision=<p[,s]>
6
+ * 示例: id:int:primary:auto_increment
7
+ * name:varchar:len=64:not_null
8
+ * amount:decimal:precision=10,2:default=0
9
+ */
10
+ Object.defineProperty(exports, "__esModule", { value: true });
11
+ exports.parseColumnSpec = parseColumnSpec;
12
+ function parseColumnSpec(spec) {
13
+ if (!spec || typeof spec !== 'string')
14
+ throw new Error('列定义不能为空');
15
+ const parts = splitColon(spec);
16
+ if (parts.length < 2) {
17
+ throw new Error(`列定义格式应为 "名称:类型[:约束...]",收到: ${spec}`);
18
+ }
19
+ const name = parts[0].trim();
20
+ const typeRaw = parts[1].trim();
21
+ if (!name || !typeRaw)
22
+ throw new Error(`列定义无效: ${spec}`);
23
+ const col = {
24
+ name,
25
+ type: typeRaw,
26
+ baseType: typeRaw.split('(')[0].trim().toLowerCase(),
27
+ nullable: true,
28
+ isPrimary: false,
29
+ isAutoIncrement: false,
30
+ unique: false,
31
+ hasDefault: false,
32
+ raw: spec
33
+ };
34
+ // 提取类型长度
35
+ const lenMatch = /\((\d+)(?:,\s*(\d+))?\)/.exec(typeRaw);
36
+ if (lenMatch) {
37
+ col.length = parseInt(lenMatch[1], 10);
38
+ if (lenMatch[2])
39
+ col.precision = parseInt(lenMatch[2], 10);
40
+ if (lenMatch[2])
41
+ col.scale = parseInt(lenMatch[2], 10);
42
+ col.type = typeRaw; // 保持原样
43
+ }
44
+ else {
45
+ // 无长度时按基础类型输出
46
+ col.type = col.baseType;
47
+ }
48
+ for (const rawMod of parts.slice(2)) {
49
+ const mod = rawMod.trim();
50
+ const lower = mod.toLowerCase();
51
+ if (lower === 'primary') {
52
+ col.isPrimary = true;
53
+ }
54
+ else if (lower === 'auto_increment' || lower === 'ai') {
55
+ col.isAutoIncrement = true;
56
+ col.isPrimary = true;
57
+ }
58
+ else if (lower === 'not_null' || lower === 'notnull') {
59
+ col.nullable = false;
60
+ }
61
+ else if (lower === 'null' || lower === 'nullable') {
62
+ col.nullable = true;
63
+ }
64
+ else if (lower === 'unique') {
65
+ col.unique = true;
66
+ }
67
+ else if (lower.startsWith('default=')) {
68
+ col.hasDefault = true;
69
+ col.defaultValue = parseDefault(mod.slice('default='.length));
70
+ }
71
+ else if (lower.startsWith('comment=')) {
72
+ col.comment = unquote(mod.slice('comment='.length));
73
+ }
74
+ else if (lower.startsWith('len=')) {
75
+ col.length = parseInt(mod.slice('len='.length), 10);
76
+ col.type = `${col.baseType}(${col.length})`;
77
+ }
78
+ else if (lower.startsWith('length=')) {
79
+ col.length = parseInt(mod.slice('length='.length), 10);
80
+ col.type = `${col.baseType}(${col.length})`;
81
+ }
82
+ else if (lower.startsWith('precision=')) {
83
+ const pv = mod.slice('precision='.length).split(',');
84
+ col.precision = parseInt(pv[0], 10);
85
+ if (pv[1] !== undefined) {
86
+ col.scale = parseInt(pv[1], 10);
87
+ col.type = `${col.baseType}(${col.precision},${col.scale})`;
88
+ }
89
+ else {
90
+ col.type = `${col.baseType}(${col.precision})`;
91
+ }
92
+ }
93
+ else {
94
+ throw new Error(`列 "${name}" 的约束无效: ${mod}`);
95
+ }
96
+ }
97
+ return col;
98
+ }
99
+ function splitColon(spec) {
100
+ // 用 '\' 转义冒号
101
+ const parts = [];
102
+ let current = '';
103
+ let escaped = false;
104
+ for (const ch of spec) {
105
+ if (escaped) {
106
+ current += ch;
107
+ escaped = false;
108
+ }
109
+ else if (ch === '\\') {
110
+ escaped = true;
111
+ }
112
+ else if (ch === ':') {
113
+ parts.push(current);
114
+ current = '';
115
+ }
116
+ else {
117
+ current += ch;
118
+ }
119
+ }
120
+ if (escaped)
121
+ current += '\\';
122
+ parts.push(current);
123
+ return parts;
124
+ }
125
+ function unquote(s) {
126
+ const t = s.trim();
127
+ if ((t.startsWith("'") && t.endsWith("'")) || (t.startsWith('"') && t.endsWith('"'))) {
128
+ return t.slice(1, -1);
129
+ }
130
+ return t;
131
+ }
132
+ function parseDefault(raw) {
133
+ const v = raw.trim();
134
+ const up = v.toUpperCase();
135
+ if (up === 'NULL')
136
+ return null;
137
+ if (up === 'TRUE')
138
+ return true;
139
+ if (up === 'FALSE')
140
+ return false;
141
+ if (up === 'CURRENT_TIMESTAMP' || up === 'NOW()' || up === 'CURRENT_DATE')
142
+ return up;
143
+ // 数字
144
+ if (/^-?\d+(\.\d+)?$/.test(v))
145
+ return Number(v);
146
+ return unquote(v);
147
+ }
148
+ //# sourceMappingURL=column-spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"column-spec.js","sourceRoot":"","sources":["../../../server/core/column-spec.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,147 @@
1
+ /**
2
+ * 列定义 DSL:name:type[:约束...]
3
+ * 约束: primary | auto_increment | not_null | null | unique
4
+ * default=<v> | comment=<str> | len=<n> | precision=<p[,s]>
5
+ * 示例: id:int:primary:auto_increment
6
+ * name:varchar:len=64:not_null
7
+ * amount:decimal:precision=10,2:default=0
8
+ */
9
+
10
+ export interface ParsedColumn {
11
+ name: string;
12
+ /** 类型全名(含长度),如 varchar(64) */
13
+ type: string;
14
+ /** 基础类型,如 varchar */
15
+ baseType: string;
16
+ nullable: boolean;
17
+ isPrimary: boolean;
18
+ isAutoIncrement: boolean;
19
+ unique: boolean;
20
+ defaultValue?: any;
21
+ hasDefault: boolean;
22
+ comment?: string;
23
+ length?: number;
24
+ precision?: number;
25
+ scale?: number;
26
+ /** 原始 spec 字符串 */
27
+ raw: string;
28
+ }
29
+
30
+ export function parseColumnSpec(spec: string): ParsedColumn {
31
+ if (!spec || typeof spec !== 'string') throw new Error('列定义不能为空');
32
+ const parts = splitColon(spec);
33
+ if (parts.length < 2) {
34
+ throw new Error(`列定义格式应为 "名称:类型[:约束...]",收到: ${spec}`);
35
+ }
36
+ const name = parts[0].trim();
37
+ const typeRaw = parts[1].trim();
38
+ if (!name || !typeRaw) throw new Error(`列定义无效: ${spec}`);
39
+
40
+ const col: ParsedColumn = {
41
+ name,
42
+ type: typeRaw,
43
+ baseType: typeRaw.split('(')[0].trim().toLowerCase(),
44
+ nullable: true,
45
+ isPrimary: false,
46
+ isAutoIncrement: false,
47
+ unique: false,
48
+ hasDefault: false,
49
+ raw: spec
50
+ };
51
+
52
+ // 提取类型长度
53
+ const lenMatch = /\((\d+)(?:,\s*(\d+))?\)/.exec(typeRaw);
54
+ if (lenMatch) {
55
+ col.length = parseInt(lenMatch[1], 10);
56
+ if (lenMatch[2]) col.precision = parseInt(lenMatch[2], 10);
57
+ if (lenMatch[2]) col.scale = parseInt(lenMatch[2], 10);
58
+ col.type = typeRaw; // 保持原样
59
+ } else {
60
+ // 无长度时按基础类型输出
61
+ col.type = col.baseType;
62
+ }
63
+
64
+ for (const rawMod of parts.slice(2)) {
65
+ const mod = rawMod.trim();
66
+ const lower = mod.toLowerCase();
67
+ if (lower === 'primary') {
68
+ col.isPrimary = true;
69
+ } else if (lower === 'auto_increment' || lower === 'ai') {
70
+ col.isAutoIncrement = true;
71
+ col.isPrimary = true;
72
+ } else if (lower === 'not_null' || lower === 'notnull') {
73
+ col.nullable = false;
74
+ } else if (lower === 'null' || lower === 'nullable') {
75
+ col.nullable = true;
76
+ } else if (lower === 'unique') {
77
+ col.unique = true;
78
+ } else if (lower.startsWith('default=')) {
79
+ col.hasDefault = true;
80
+ col.defaultValue = parseDefault(mod.slice('default='.length));
81
+ } else if (lower.startsWith('comment=')) {
82
+ col.comment = unquote(mod.slice('comment='.length));
83
+ } else if (lower.startsWith('len=')) {
84
+ col.length = parseInt(mod.slice('len='.length), 10);
85
+ col.type = `${col.baseType}(${col.length})`;
86
+ } else if (lower.startsWith('length=')) {
87
+ col.length = parseInt(mod.slice('length='.length), 10);
88
+ col.type = `${col.baseType}(${col.length})`;
89
+ } else if (lower.startsWith('precision=')) {
90
+ const pv = mod.slice('precision='.length).split(',');
91
+ col.precision = parseInt(pv[0], 10);
92
+ if (pv[1] !== undefined) {
93
+ col.scale = parseInt(pv[1], 10);
94
+ col.type = `${col.baseType}(${col.precision},${col.scale})`;
95
+ } else {
96
+ col.type = `${col.baseType}(${col.precision})`;
97
+ }
98
+ } else {
99
+ throw new Error(`列 "${name}" 的约束无效: ${mod}`);
100
+ }
101
+ }
102
+
103
+ return col;
104
+ }
105
+
106
+ function splitColon(spec: string): string[] {
107
+ // 用 '\' 转义冒号
108
+ const parts: string[] = [];
109
+ let current = '';
110
+ let escaped = false;
111
+ for (const ch of spec) {
112
+ if (escaped) {
113
+ current += ch;
114
+ escaped = false;
115
+ } else if (ch === '\\') {
116
+ escaped = true;
117
+ } else if (ch === ':') {
118
+ parts.push(current);
119
+ current = '';
120
+ } else {
121
+ current += ch;
122
+ }
123
+ }
124
+ if (escaped) current += '\\';
125
+ parts.push(current);
126
+ return parts;
127
+ }
128
+
129
+ function unquote(s: string): string {
130
+ const t = s.trim();
131
+ if ((t.startsWith("'") && t.endsWith("'")) || (t.startsWith('"') && t.endsWith('"'))) {
132
+ return t.slice(1, -1);
133
+ }
134
+ return t;
135
+ }
136
+
137
+ function parseDefault(raw: string): any {
138
+ const v = raw.trim();
139
+ const up = v.toUpperCase();
140
+ if (up === 'NULL') return null;
141
+ if (up === 'TRUE') return true;
142
+ if (up === 'FALSE') return false;
143
+ if (up === 'CURRENT_TIMESTAMP' || up === 'NOW()' || up === 'CURRENT_DATE') return up;
144
+ // 数字
145
+ if (/^-?\d+(\.\d+)?$/.test(v)) return Number(v);
146
+ return unquote(v);
147
+ }