befly 3.9.38 → 3.9.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 (155) hide show
  1. package/README.md +37 -38
  2. package/befly.config.ts +62 -40
  3. package/checks/checkApi.ts +16 -16
  4. package/checks/checkApp.ts +19 -25
  5. package/checks/checkTable.ts +42 -42
  6. package/docs/README.md +42 -35
  7. package/docs/{api.md → api/api.md} +223 -231
  8. package/docs/cipher.md +71 -69
  9. package/docs/database.md +143 -141
  10. package/docs/{examples.md → guide/examples.md} +181 -181
  11. package/docs/guide/quickstart.md +331 -0
  12. package/docs/hooks/auth.md +38 -0
  13. package/docs/hooks/cors.md +28 -0
  14. package/docs/{hook.md → hooks/hook.md} +140 -57
  15. package/docs/hooks/parser.md +19 -0
  16. package/docs/hooks/rateLimit.md +47 -0
  17. package/docs/{redis.md → infra/redis.md} +84 -93
  18. package/docs/plugins/cipher.md +61 -0
  19. package/docs/plugins/database.md +128 -0
  20. package/docs/{plugin.md → plugins/plugin.md} +83 -81
  21. package/docs/quickstart.md +26 -26
  22. package/docs/{addon.md → reference/addon.md} +46 -46
  23. package/docs/{config.md → reference/config.md} +32 -80
  24. package/docs/{logger.md → reference/logger.md} +52 -52
  25. package/docs/{sync.md → reference/sync.md} +32 -35
  26. package/docs/{table.md → reference/table.md} +1 -1
  27. package/docs/{validator.md → reference/validator.md} +57 -57
  28. package/hooks/auth.ts +8 -4
  29. package/hooks/cors.ts +13 -13
  30. package/hooks/parser.ts +37 -17
  31. package/hooks/permission.ts +26 -14
  32. package/hooks/rateLimit.ts +276 -0
  33. package/hooks/validator.ts +8 -8
  34. package/lib/asyncContext.ts +43 -0
  35. package/lib/cacheHelper.ts +212 -77
  36. package/lib/cacheKeys.ts +38 -0
  37. package/lib/cipher.ts +30 -30
  38. package/lib/connect.ts +28 -28
  39. package/lib/dbHelper.ts +183 -102
  40. package/lib/jwt.ts +16 -16
  41. package/lib/logger.ts +610 -19
  42. package/lib/redisHelper.ts +185 -44
  43. package/lib/sqlBuilder.ts +90 -91
  44. package/lib/validator.ts +59 -39
  45. package/loader/loadApis.ts +48 -44
  46. package/loader/loadHooks.ts +40 -14
  47. package/loader/loadPlugins.ts +16 -17
  48. package/main.ts +57 -47
  49. package/package.json +47 -45
  50. package/paths.ts +15 -14
  51. package/plugins/cache.ts +5 -4
  52. package/plugins/cipher.ts +3 -3
  53. package/plugins/config.ts +2 -2
  54. package/plugins/db.ts +9 -9
  55. package/plugins/jwt.ts +3 -3
  56. package/plugins/logger.ts +8 -12
  57. package/plugins/redis.ts +8 -8
  58. package/plugins/tool.ts +6 -6
  59. package/router/api.ts +85 -56
  60. package/router/static.ts +12 -12
  61. package/sync/syncAll.ts +12 -12
  62. package/sync/syncApi.ts +55 -52
  63. package/sync/syncDb/apply.ts +20 -19
  64. package/sync/syncDb/constants.ts +25 -23
  65. package/sync/syncDb/ddl.ts +35 -36
  66. package/sync/syncDb/helpers.ts +6 -9
  67. package/sync/syncDb/schema.ts +10 -9
  68. package/sync/syncDb/sqlite.ts +7 -8
  69. package/sync/syncDb/table.ts +37 -35
  70. package/sync/syncDb/tableCreate.ts +21 -20
  71. package/sync/syncDb/types.ts +23 -20
  72. package/sync/syncDb/version.ts +10 -10
  73. package/sync/syncDb.ts +43 -36
  74. package/sync/syncDev.ts +74 -65
  75. package/sync/syncMenu.ts +190 -55
  76. package/tests/api-integration-array-number.test.ts +282 -0
  77. package/tests/befly-config-env.test.ts +78 -0
  78. package/tests/cacheHelper.test.ts +135 -104
  79. package/tests/cacheKeys.test.ts +41 -0
  80. package/tests/cipher.test.ts +90 -89
  81. package/tests/dbHelper-advanced.test.ts +140 -134
  82. package/tests/dbHelper-all-array-types.test.ts +316 -0
  83. package/tests/dbHelper-array-serialization.test.ts +258 -0
  84. package/tests/dbHelper-columns.test.ts +56 -55
  85. package/tests/dbHelper-execute.test.ts +45 -44
  86. package/tests/dbHelper-joins.test.ts +124 -119
  87. package/tests/fields-redis-cache.test.ts +29 -27
  88. package/tests/fields-validate.test.ts +38 -38
  89. package/tests/getClientIp.test.ts +54 -0
  90. package/tests/integration.test.ts +69 -67
  91. package/tests/jwt.test.ts +27 -26
  92. package/tests/logger.test.ts +267 -34
  93. package/tests/rateLimit-hook.test.ts +477 -0
  94. package/tests/redisHelper.test.ts +187 -188
  95. package/tests/redisKeys.test.ts +6 -73
  96. package/tests/scanConfig.test.ts +144 -0
  97. package/tests/sqlBuilder-advanced.test.ts +217 -215
  98. package/tests/sqlBuilder.test.ts +92 -91
  99. package/tests/sync-connection.test.ts +29 -29
  100. package/tests/syncDb-apply.test.ts +97 -96
  101. package/tests/syncDb-array-number.test.ts +160 -0
  102. package/tests/syncDb-constants.test.ts +48 -47
  103. package/tests/syncDb-ddl.test.ts +99 -98
  104. package/tests/syncDb-helpers.test.ts +29 -28
  105. package/tests/syncDb-schema.test.ts +61 -60
  106. package/tests/syncDb-types.test.ts +60 -59
  107. package/tests/syncMenu-paths.test.ts +68 -0
  108. package/tests/util.test.ts +42 -41
  109. package/tests/validator-array-number.test.ts +310 -0
  110. package/tests/validator-default.test.ts +373 -0
  111. package/tests/validator.test.ts +271 -266
  112. package/tsconfig.json +4 -5
  113. package/types/api.d.ts +7 -12
  114. package/types/befly.d.ts +60 -13
  115. package/types/cache.d.ts +8 -4
  116. package/types/common.d.ts +17 -9
  117. package/types/context.d.ts +2 -2
  118. package/types/crypto.d.ts +23 -0
  119. package/types/database.d.ts +19 -19
  120. package/types/hook.d.ts +2 -2
  121. package/types/jwt.d.ts +118 -0
  122. package/types/logger.d.ts +30 -0
  123. package/types/plugin.d.ts +4 -4
  124. package/types/redis.d.ts +7 -3
  125. package/types/roleApisCache.ts +23 -0
  126. package/types/sync.d.ts +10 -10
  127. package/types/table.d.ts +50 -9
  128. package/types/validate.d.ts +69 -0
  129. package/utils/addonHelper.ts +90 -0
  130. package/utils/arrayKeysToCamel.ts +18 -0
  131. package/utils/calcPerfTime.ts +13 -0
  132. package/utils/configTypes.ts +3 -0
  133. package/utils/cors.ts +19 -0
  134. package/utils/fieldClear.ts +75 -0
  135. package/utils/genShortId.ts +12 -0
  136. package/utils/getClientIp.ts +45 -0
  137. package/utils/keysToCamel.ts +22 -0
  138. package/utils/keysToSnake.ts +22 -0
  139. package/utils/modules.ts +98 -0
  140. package/utils/pickFields.ts +19 -0
  141. package/utils/process.ts +56 -0
  142. package/utils/regex.ts +225 -0
  143. package/utils/response.ts +115 -0
  144. package/utils/route.ts +23 -0
  145. package/utils/scanConfig.ts +142 -0
  146. package/utils/scanFiles.ts +48 -0
  147. package/.prettierignore +0 -2
  148. package/.prettierrc +0 -12
  149. package/docs/1-/345/237/272/346/234/254/344/273/213/347/273/215.md +0 -35
  150. package/docs/2-/345/210/235/346/255/245/344/275/223/351/252/214.md +0 -64
  151. package/docs/3-/347/254/254/344/270/200/344/270/252/346/216/245/345/217/243.md +0 -46
  152. package/docs/4-/346/223/215/344/275/234/346/225/260/346/215/256/345/272/223.md +0 -172
  153. package/hooks/requestLogger.ts +0 -84
  154. package/types/index.ts +0 -24
  155. package/util.ts +0 -283
@@ -5,183 +5,184 @@
5
5
  * - compareFieldDefinition
6
6
  */
7
7
 
8
- import { describe, test, expect, beforeAll } from 'bun:test';
9
- import { setDbType } from '../sync/syncDb/constants.js';
8
+ import { describe, test, expect, beforeAll } from "bun:test";
9
+
10
+ import { setDbType } from "../sync/syncDb/constants.js";
10
11
 
11
12
  // 设置数据库类型为 MySQL
12
- setDbType('mysql');
13
+ setDbType("mysql");
13
14
 
14
15
  let compareFieldDefinition: any;
15
16
 
16
17
  beforeAll(async () => {
17
- const apply = await import('../sync/syncDb/apply.js');
18
+ const apply = await import("../sync/syncDb/apply.js");
18
19
  compareFieldDefinition = apply.compareFieldDefinition;
19
20
  });
20
21
 
21
- describe('compareFieldDefinition', () => {
22
- describe('长度变化检测', () => {
23
- test('string 类型长度变化被检测到', () => {
22
+ describe("compareFieldDefinition", () => {
23
+ describe("长度变化检测", () => {
24
+ test("string 类型长度变化被检测到", () => {
24
25
  const existingColumn = {
25
- type: 'varchar',
26
+ type: "varchar",
26
27
  max: 50,
27
28
  nullable: false,
28
- defaultValue: '',
29
- comment: '用户名'
29
+ defaultValue: "",
30
+ comment: "用户名"
30
31
  };
31
32
  const fieldDef = {
32
- name: '用户名',
33
- type: 'string',
33
+ name: "用户名",
34
+ type: "string",
34
35
  max: 100,
35
36
  nullable: false,
36
37
  default: null
37
38
  };
38
39
 
39
40
  const changes = compareFieldDefinition(existingColumn, fieldDef);
40
- const lengthChange = changes.find((c: any) => c.type === 'length');
41
+ const lengthChange = changes.find((c: any) => c.type === "length");
41
42
 
42
43
  expect(lengthChange).toBeDefined();
43
44
  expect(lengthChange.current).toBe(50);
44
45
  expect(lengthChange.expected).toBe(100);
45
46
  });
46
47
 
47
- test('长度相同无变化', () => {
48
+ test("长度相同无变化", () => {
48
49
  const existingColumn = {
49
- type: 'varchar',
50
+ type: "varchar",
50
51
  max: 100,
51
52
  nullable: false,
52
- defaultValue: '',
53
- comment: '用户名'
53
+ defaultValue: "",
54
+ comment: "用户名"
54
55
  };
55
56
  const fieldDef = {
56
- name: '用户名',
57
- type: 'string',
57
+ name: "用户名",
58
+ type: "string",
58
59
  max: 100,
59
60
  nullable: false,
60
61
  default: null
61
62
  };
62
63
 
63
64
  const changes = compareFieldDefinition(existingColumn, fieldDef);
64
- const lengthChange = changes.find((c: any) => c.type === 'length');
65
+ const lengthChange = changes.find((c: any) => c.type === "length");
65
66
 
66
67
  expect(lengthChange).toBeUndefined();
67
68
  });
68
69
  });
69
70
 
70
- describe('注释变化检测', () => {
71
- test('注释变化被检测到', () => {
71
+ describe("注释变化检测", () => {
72
+ test("注释变化被检测到", () => {
72
73
  const existingColumn = {
73
- type: 'varchar',
74
+ type: "varchar",
74
75
  max: 100,
75
76
  nullable: false,
76
- defaultValue: '',
77
- comment: '旧注释'
77
+ defaultValue: "",
78
+ comment: "旧注释"
78
79
  };
79
80
  const fieldDef = {
80
- name: '新注释',
81
- type: 'string',
81
+ name: "新注释",
82
+ type: "string",
82
83
  max: 100,
83
84
  nullable: false,
84
85
  default: null
85
86
  };
86
87
 
87
88
  const changes = compareFieldDefinition(existingColumn, fieldDef);
88
- const commentChange = changes.find((c: any) => c.type === 'comment');
89
+ const commentChange = changes.find((c: any) => c.type === "comment");
89
90
 
90
91
  expect(commentChange).toBeDefined();
91
- expect(commentChange.current).toBe('旧注释');
92
- expect(commentChange.expected).toBe('新注释');
92
+ expect(commentChange.current).toBe("旧注释");
93
+ expect(commentChange.expected).toBe("新注释");
93
94
  });
94
95
 
95
- test('注释相同无变化', () => {
96
+ test("注释相同无变化", () => {
96
97
  const existingColumn = {
97
- type: 'varchar',
98
+ type: "varchar",
98
99
  max: 100,
99
100
  nullable: false,
100
- defaultValue: '',
101
- comment: '用户名'
101
+ defaultValue: "",
102
+ comment: "用户名"
102
103
  };
103
104
  const fieldDef = {
104
- name: '用户名',
105
- type: 'string',
105
+ name: "用户名",
106
+ type: "string",
106
107
  max: 100,
107
108
  nullable: false,
108
109
  default: null
109
110
  };
110
111
 
111
112
  const changes = compareFieldDefinition(existingColumn, fieldDef);
112
- const commentChange = changes.find((c: any) => c.type === 'comment');
113
+ const commentChange = changes.find((c: any) => c.type === "comment");
113
114
 
114
115
  expect(commentChange).toBeUndefined();
115
116
  });
116
117
  });
117
118
 
118
- describe('数据类型变化检测', () => {
119
- test('类型变化被检测到', () => {
119
+ describe("数据类型变化检测", () => {
120
+ test("类型变化被检测到", () => {
120
121
  const existingColumn = {
121
- type: 'bigint',
122
+ type: "bigint",
122
123
  max: null,
123
124
  nullable: false,
124
125
  defaultValue: 0,
125
- comment: '数量'
126
+ comment: "数量"
126
127
  };
127
128
  const fieldDef = {
128
- name: '数量',
129
- type: 'string',
129
+ name: "数量",
130
+ type: "string",
130
131
  max: 100,
131
132
  nullable: false,
132
133
  default: null
133
134
  };
134
135
 
135
136
  const changes = compareFieldDefinition(existingColumn, fieldDef);
136
- const typeChange = changes.find((c: any) => c.type === 'datatype');
137
+ const typeChange = changes.find((c: any) => c.type === "datatype");
137
138
 
138
139
  expect(typeChange).toBeDefined();
139
- expect(typeChange.current).toBe('bigint');
140
- expect(typeChange.expected).toBe('varchar');
140
+ expect(typeChange.current).toBe("bigint");
141
+ expect(typeChange.expected).toBe("varchar");
141
142
  });
142
143
 
143
- test('类型相同无变化', () => {
144
+ test("类型相同无变化", () => {
144
145
  const existingColumn = {
145
- type: 'bigint',
146
+ type: "bigint",
146
147
  max: null,
147
148
  nullable: false,
148
149
  defaultValue: 0,
149
- comment: '数量'
150
+ comment: "数量"
150
151
  };
151
152
  const fieldDef = {
152
- name: '数量',
153
- type: 'number',
153
+ name: "数量",
154
+ type: "number",
154
155
  max: null,
155
156
  nullable: false,
156
157
  default: 0
157
158
  };
158
159
 
159
160
  const changes = compareFieldDefinition(existingColumn, fieldDef);
160
- const typeChange = changes.find((c: any) => c.type === 'datatype');
161
+ const typeChange = changes.find((c: any) => c.type === "datatype");
161
162
 
162
163
  expect(typeChange).toBeUndefined();
163
164
  });
164
165
  });
165
166
 
166
- describe('可空性变化检测', () => {
167
- test('nullable 变化被检测到', () => {
167
+ describe("可空性变化检测", () => {
168
+ test("nullable 变化被检测到", () => {
168
169
  const existingColumn = {
169
- type: 'varchar',
170
+ type: "varchar",
170
171
  max: 100,
171
172
  nullable: false,
172
- defaultValue: '',
173
- comment: '用户名'
173
+ defaultValue: "",
174
+ comment: "用户名"
174
175
  };
175
176
  const fieldDef = {
176
- name: '用户名',
177
- type: 'string',
177
+ name: "用户名",
178
+ type: "string",
178
179
  max: 100,
179
180
  nullable: true,
180
181
  default: null
181
182
  };
182
183
 
183
184
  const changes = compareFieldDefinition(existingColumn, fieldDef);
184
- const nullableChange = changes.find((c: any) => c.type === 'nullable');
185
+ const nullableChange = changes.find((c: any) => c.type === "nullable");
185
186
 
186
187
  expect(nullableChange).toBeDefined();
187
188
  expect(nullableChange.current).toBe(false);
@@ -189,92 +190,92 @@ describe('compareFieldDefinition', () => {
189
190
  });
190
191
  });
191
192
 
192
- describe('默认值变化检测', () => {
193
- test('默认值变化被检测到', () => {
193
+ describe("默认值变化检测", () => {
194
+ test("默认值变化被检测到", () => {
194
195
  const existingColumn = {
195
- type: 'varchar',
196
+ type: "varchar",
196
197
  max: 100,
197
198
  nullable: false,
198
- defaultValue: 'old',
199
- comment: '用户名'
199
+ defaultValue: "old",
200
+ comment: "用户名"
200
201
  };
201
202
  const fieldDef = {
202
- name: '用户名',
203
- type: 'string',
203
+ name: "用户名",
204
+ type: "string",
204
205
  max: 100,
205
206
  nullable: false,
206
- default: 'new'
207
+ default: "new"
207
208
  };
208
209
 
209
210
  const changes = compareFieldDefinition(existingColumn, fieldDef);
210
- const defaultChange = changes.find((c: any) => c.type === 'default');
211
+ const defaultChange = changes.find((c: any) => c.type === "default");
211
212
 
212
213
  expect(defaultChange).toBeDefined();
213
- expect(defaultChange.current).toBe('old');
214
- expect(defaultChange.expected).toBe('new');
214
+ expect(defaultChange.current).toBe("old");
215
+ expect(defaultChange.expected).toBe("new");
215
216
  });
216
217
 
217
- test('null 默认值被正确处理', () => {
218
+ test("null 默认值被正确处理", () => {
218
219
  const existingColumn = {
219
- type: 'varchar',
220
+ type: "varchar",
220
221
  max: 100,
221
222
  nullable: false,
222
- defaultValue: '',
223
- comment: '用户名'
223
+ defaultValue: "",
224
+ comment: "用户名"
224
225
  };
225
226
  const fieldDef = {
226
- name: '用户名',
227
- type: 'string',
227
+ name: "用户名",
228
+ type: "string",
228
229
  max: 100,
229
230
  nullable: false,
230
231
  default: null // null 会被解析为空字符串
231
232
  };
232
233
 
233
234
  const changes = compareFieldDefinition(existingColumn, fieldDef);
234
- const defaultChange = changes.find((c: any) => c.type === 'default');
235
+ const defaultChange = changes.find((c: any) => c.type === "default");
235
236
 
236
237
  // null -> '' (空字符串),与现有值相同,无变化
237
238
  expect(defaultChange).toBeUndefined();
238
239
  });
239
240
  });
240
241
 
241
- describe('多变化组合', () => {
242
- test('多个变化同时被检测', () => {
242
+ describe("多变化组合", () => {
243
+ test("多个变化同时被检测", () => {
243
244
  const existingColumn = {
244
- type: 'varchar',
245
+ type: "varchar",
245
246
  max: 50,
246
247
  nullable: false,
247
- defaultValue: 'old',
248
- comment: '旧注释'
248
+ defaultValue: "old",
249
+ comment: "旧注释"
249
250
  };
250
251
  const fieldDef = {
251
- name: '新注释',
252
- type: 'string',
252
+ name: "新注释",
253
+ type: "string",
253
254
  max: 100,
254
255
  nullable: true,
255
- default: 'new'
256
+ default: "new"
256
257
  };
257
258
 
258
259
  const changes = compareFieldDefinition(existingColumn, fieldDef);
259
260
 
260
261
  expect(changes.length).toBe(4); // length, comment, nullable, default
261
- expect(changes.some((c: any) => c.type === 'length')).toBe(true);
262
- expect(changes.some((c: any) => c.type === 'comment')).toBe(true);
263
- expect(changes.some((c: any) => c.type === 'nullable')).toBe(true);
264
- expect(changes.some((c: any) => c.type === 'default')).toBe(true);
262
+ expect(changes.some((c: any) => c.type === "length")).toBe(true);
263
+ expect(changes.some((c: any) => c.type === "comment")).toBe(true);
264
+ expect(changes.some((c: any) => c.type === "nullable")).toBe(true);
265
+ expect(changes.some((c: any) => c.type === "default")).toBe(true);
265
266
  });
266
267
 
267
- test('无变化返回空数组', () => {
268
+ test("无变化返回空数组", () => {
268
269
  const existingColumn = {
269
- type: 'varchar',
270
+ type: "varchar",
270
271
  max: 100,
271
272
  nullable: false,
272
- defaultValue: '',
273
- comment: '用户名'
273
+ defaultValue: "",
274
+ comment: "用户名"
274
275
  };
275
276
  const fieldDef = {
276
- name: '用户名',
277
- type: 'string',
277
+ name: "用户名",
278
+ type: "string",
278
279
  max: 100,
279
280
  nullable: false,
280
281
  default: null
@@ -0,0 +1,160 @@
1
+ /**
2
+ * 测试 syncDb 对 array_number_string 和 array_number_text 类型的支持
3
+ */
4
+
5
+ import { describe, expect, test } from "bun:test";
6
+
7
+ import { getSqlType, resolveDefaultValue, generateDefaultSql, isStringOrArrayType } from "../sync/syncDb/types.js";
8
+
9
+ describe("syncDb - array_number 类型支持", () => {
10
+ // ==================== 类型判断测试 ====================
11
+
12
+ test("isStringOrArrayType: array_number_string 需要长度", () => {
13
+ expect(isStringOrArrayType("array_number_string")).toBe(true);
14
+ });
15
+
16
+ test("isStringOrArrayType: array_number_text 不需要长度", () => {
17
+ expect(isStringOrArrayType("array_number_text")).toBe(false);
18
+ });
19
+
20
+ // ==================== SQL 类型映射测试 ====================
21
+
22
+ test("getSqlType: array_number_string 生成 VARCHAR(max)", () => {
23
+ const sqlType = getSqlType("array_number_string", 500);
24
+ expect(sqlType).toMatch(/VARCHAR\(500\)/i);
25
+ });
26
+
27
+ test("getSqlType: array_number_text 生成 TEXT/MEDIUMTEXT", () => {
28
+ const sqlType = getSqlType("array_number_text", null);
29
+ expect(sqlType).toMatch(/TEXT/i);
30
+ });
31
+
32
+ test("getSqlType: array_number_string 使用 max 参数", () => {
33
+ const sqlType1 = getSqlType("array_number_string", 200);
34
+ const sqlType2 = getSqlType("array_number_string", 1000);
35
+
36
+ expect(sqlType1).toMatch(/VARCHAR\(200\)/i);
37
+ expect(sqlType2).toMatch(/VARCHAR\(1000\)/i);
38
+ });
39
+
40
+ // ==================== 默认值处理测试 ====================
41
+
42
+ test('resolveDefaultValue: array_number_string null 时返回 "[]"', () => {
43
+ const result = resolveDefaultValue(null, "array_number_string");
44
+ expect(result).toBe("[]");
45
+ });
46
+
47
+ test("resolveDefaultValue: array_number_string 有默认值时保留", () => {
48
+ const result = resolveDefaultValue("[1,2,3]", "array_number_string");
49
+ expect(result).toBe("[1,2,3]");
50
+ });
51
+
52
+ test('resolveDefaultValue: array_number_text null 时返回 "null"', () => {
53
+ const result = resolveDefaultValue(null, "array_number_text");
54
+ expect(result).toBe("null");
55
+ });
56
+
57
+ test("resolveDefaultValue: array_number_text 有默认值时保留", () => {
58
+ const result = resolveDefaultValue("[100,200]", "array_number_text");
59
+ expect(result).toBe("[100,200]");
60
+ });
61
+
62
+ test('resolveDefaultValue: 字符串 "null" 也视为 null', () => {
63
+ const result1 = resolveDefaultValue("null", "array_number_string");
64
+ const result2 = resolveDefaultValue("null", "array_number_text");
65
+
66
+ expect(result1).toBe("[]");
67
+ expect(result2).toBe("null");
68
+ });
69
+
70
+ // ==================== SQL DEFAULT 子句测试 ====================
71
+
72
+ test("generateDefaultSql: array_number_string 生成 DEFAULT 子句", () => {
73
+ const sql = generateDefaultSql("[]", "array_number_string");
74
+ expect(sql).toBe(" DEFAULT '[]'");
75
+ });
76
+
77
+ test("generateDefaultSql: array_number_string 自定义默认值", () => {
78
+ const sql = generateDefaultSql("[10,20,30]", "array_number_string");
79
+ expect(sql).toBe(" DEFAULT '[10,20,30]'");
80
+ });
81
+
82
+ test("generateDefaultSql: array_number_text 不生成 DEFAULT", () => {
83
+ const sql = generateDefaultSql("[]", "array_number_text");
84
+ expect(sql).toBe("");
85
+ });
86
+
87
+ test("generateDefaultSql: array_number_text null 时不生成 DEFAULT", () => {
88
+ const sql = generateDefaultSql("null", "array_number_text");
89
+ expect(sql).toBe("");
90
+ });
91
+
92
+ // ==================== 单引号转义测试 ====================
93
+
94
+ test("generateDefaultSql: 默认值包含单引号时正确转义", () => {
95
+ const sql = generateDefaultSql("[1,'test',2]", "array_number_string");
96
+ expect(sql).toBe(" DEFAULT '[1,''test'',2]'");
97
+ });
98
+
99
+ // ==================== 完整流程测试 ====================
100
+
101
+ test("完整流程: array_number_string 字段定义", () => {
102
+ // 模拟字段定义:"标签ID|array_number_string|0|500|[]|0"
103
+ const fieldType = "array_number_string";
104
+ const fieldMax = 500;
105
+ const fieldDefault = null;
106
+
107
+ // 1. 判断是否需要长度
108
+ expect(isStringOrArrayType(fieldType)).toBe(true);
109
+
110
+ // 2. 获取 SQL 类型
111
+ const sqlType = getSqlType(fieldType, fieldMax);
112
+ expect(sqlType).toMatch(/VARCHAR\(500\)/i);
113
+
114
+ // 3. 处理默认值
115
+ const actualDefault = resolveDefaultValue(fieldDefault, fieldType);
116
+ expect(actualDefault).toBe("[]");
117
+
118
+ // 4. 生成 DEFAULT 子句
119
+ const defaultSql = generateDefaultSql(actualDefault, fieldType);
120
+ expect(defaultSql).toBe(" DEFAULT '[]'");
121
+ });
122
+
123
+ test("完整流程: array_number_text 字段定义", () => {
124
+ // 模拟字段定义:"关联ID|array_number_text|||null|0"
125
+ const fieldType = "array_number_text";
126
+ const fieldMax = null;
127
+ const fieldDefault = null;
128
+
129
+ // 1. 判断是否需要长度
130
+ expect(isStringOrArrayType(fieldType)).toBe(false);
131
+
132
+ // 2. 获取 SQL 类型
133
+ const sqlType = getSqlType(fieldType, fieldMax);
134
+ expect(sqlType).toMatch(/TEXT/i);
135
+
136
+ // 3. 处理默认值
137
+ const actualDefault = resolveDefaultValue(fieldDefault, fieldType);
138
+ expect(actualDefault).toBe("null");
139
+
140
+ // 4. 生成 DEFAULT 子句(TEXT 类型不支持)
141
+ const defaultSql = generateDefaultSql(actualDefault, fieldType);
142
+ expect(defaultSql).toBe("");
143
+ });
144
+
145
+ test("完整流程: array_number_string 自定义默认值", () => {
146
+ // 模拟字段定义:"分数|array_number_string|2|10|[60,70,80]|0"
147
+ const fieldType = "array_number_string";
148
+ const fieldMax = 10;
149
+ const fieldDefault = "[60,70,80]";
150
+
151
+ const sqlType = getSqlType(fieldType, fieldMax);
152
+ expect(sqlType).toMatch(/VARCHAR\(10\)/i);
153
+
154
+ const actualDefault = resolveDefaultValue(fieldDefault, fieldType);
155
+ expect(actualDefault).toBe("[60,70,80]");
156
+
157
+ const defaultSql = generateDefaultSql(actualDefault, fieldType);
158
+ expect(defaultSql).toBe(" DEFAULT '[60,70,80]'");
159
+ });
160
+ });