befly 3.8.25 → 3.8.27

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 (61) hide show
  1. package/config.ts +8 -9
  2. package/hooks/{rateLimit.ts → _rateLimit.ts} +7 -13
  3. package/hooks/auth.ts +3 -11
  4. package/hooks/cors.ts +1 -4
  5. package/hooks/parser.ts +6 -8
  6. package/hooks/permission.ts +9 -12
  7. package/hooks/validator.ts +6 -9
  8. package/lib/cacheHelper.ts +0 -4
  9. package/lib/{database.ts → connect.ts} +65 -18
  10. package/lib/logger.ts +1 -17
  11. package/lib/redisHelper.ts +6 -5
  12. package/loader/loadApis.ts +3 -3
  13. package/loader/loadHooks.ts +15 -41
  14. package/loader/loadPlugins.ts +10 -16
  15. package/main.ts +25 -28
  16. package/package.json +3 -3
  17. package/plugins/cache.ts +2 -2
  18. package/plugins/cipher.ts +15 -0
  19. package/plugins/config.ts +16 -0
  20. package/plugins/db.ts +7 -17
  21. package/plugins/jwt.ts +15 -0
  22. package/plugins/logger.ts +1 -1
  23. package/plugins/redis.ts +4 -4
  24. package/plugins/tool.ts +50 -0
  25. package/router/api.ts +56 -42
  26. package/router/static.ts +12 -12
  27. package/sync/syncAll.ts +2 -20
  28. package/sync/syncApi.ts +7 -7
  29. package/sync/syncDb/apply.ts +1 -4
  30. package/sync/syncDb/constants.ts +3 -0
  31. package/sync/syncDb/ddl.ts +2 -1
  32. package/sync/syncDb/helpers.ts +5 -117
  33. package/sync/syncDb/sqlite.ts +1 -3
  34. package/sync/syncDb/table.ts +8 -142
  35. package/sync/syncDb/tableCreate.ts +25 -9
  36. package/sync/syncDb/types.ts +125 -0
  37. package/sync/syncDb/version.ts +0 -3
  38. package/sync/syncDb.ts +146 -6
  39. package/sync/syncDev.ts +19 -15
  40. package/sync/syncMenu.ts +87 -75
  41. package/tests/redisHelper.test.ts +15 -16
  42. package/tests/sync-connection.test.ts +189 -0
  43. package/tests/syncDb-apply.test.ts +287 -0
  44. package/tests/syncDb-constants.test.ts +150 -0
  45. package/tests/syncDb-ddl.test.ts +205 -0
  46. package/tests/syncDb-helpers.test.ts +112 -0
  47. package/tests/syncDb-schema.test.ts +178 -0
  48. package/tests/syncDb-types.test.ts +129 -0
  49. package/tsconfig.json +2 -2
  50. package/types/api.d.ts +1 -1
  51. package/types/befly.d.ts +23 -21
  52. package/types/common.d.ts +0 -29
  53. package/types/context.d.ts +8 -6
  54. package/types/hook.d.ts +3 -4
  55. package/types/plugin.d.ts +3 -0
  56. package/hooks/errorHandler.ts +0 -23
  57. package/hooks/requestId.ts +0 -24
  58. package/hooks/requestLogger.ts +0 -25
  59. package/hooks/responseFormatter.ts +0 -64
  60. package/router/root.ts +0 -56
  61. package/sync/syncDb/index.ts +0 -164
@@ -0,0 +1,189 @@
1
+ /**
2
+ * sync 模块连接管理集成测试
3
+ * 验证数据库连接的正确关闭
4
+ */
5
+ import { describe, test, expect, afterEach } from 'bun:test';
6
+
7
+ import { Connect } from '../lib/connect.js';
8
+
9
+ describe('sync 模块连接管理', () => {
10
+ afterEach(() => {
11
+ // 每个测试后重置连接状态
12
+ Connect.__reset();
13
+ });
14
+
15
+ describe('Connect.isConnected', () => {
16
+ test('初始状态应该都是未连接', () => {
17
+ const status = Connect.isConnected();
18
+ expect(status.sql).toBe(false);
19
+ expect(status.redis).toBe(false);
20
+ });
21
+ });
22
+
23
+ describe('Connect.disconnect', () => {
24
+ test('disconnect 应该能安全地关闭未连接的状态', async () => {
25
+ // 即使没有连接,disconnect 也不应该抛出错误
26
+ await expect(Connect.disconnect()).resolves.toBeUndefined();
27
+ });
28
+
29
+ test('disconnectSql 应该能安全地关闭未连接的状态', async () => {
30
+ await expect(Connect.disconnectSql()).resolves.toBeUndefined();
31
+ });
32
+
33
+ test('disconnectRedis 应该能安全地关闭未连接的状态', async () => {
34
+ await expect(Connect.disconnectRedis()).resolves.toBeUndefined();
35
+ });
36
+ });
37
+
38
+ describe('Connect.getSql', () => {
39
+ test('未连接时应该抛出错误', () => {
40
+ expect(() => Connect.getSql()).toThrow('SQL 客户端未连接');
41
+ });
42
+ });
43
+
44
+ describe('Connect.getRedis', () => {
45
+ test('未连接时应该抛出错误', () => {
46
+ expect(() => Connect.getRedis()).toThrow('Redis 客户端未连接');
47
+ });
48
+ });
49
+
50
+ describe('Connect.getDbHelper', () => {
51
+ test('未连接时应该抛出错误', () => {
52
+ expect(() => Connect.getDbHelper()).toThrow('SQL 客户端未连接');
53
+ });
54
+ });
55
+
56
+ describe('Mock 连接测试', () => {
57
+ test('__setMockSql 应该设置 mock SQL 客户端', () => {
58
+ const mockSql = { close: async () => {} } as any;
59
+ Connect.__setMockSql(mockSql);
60
+
61
+ const status = Connect.isConnected();
62
+ expect(status.sql).toBe(true);
63
+ expect(status.redis).toBe(false);
64
+ });
65
+
66
+ test('__setMockRedis 应该设置 mock Redis 客户端', () => {
67
+ const mockRedis = { close: () => {} } as any;
68
+ Connect.__setMockRedis(mockRedis);
69
+
70
+ const status = Connect.isConnected();
71
+ expect(status.sql).toBe(false);
72
+ expect(status.redis).toBe(true);
73
+ });
74
+
75
+ test('__reset 应该重置所有连接', () => {
76
+ const mockSql = { close: async () => {} } as any;
77
+ const mockRedis = { close: () => {} } as any;
78
+ Connect.__setMockSql(mockSql);
79
+ Connect.__setMockRedis(mockRedis);
80
+
81
+ expect(Connect.isConnected().sql).toBe(true);
82
+ expect(Connect.isConnected().redis).toBe(true);
83
+
84
+ Connect.__reset();
85
+
86
+ expect(Connect.isConnected().sql).toBe(false);
87
+ expect(Connect.isConnected().redis).toBe(false);
88
+ });
89
+
90
+ test('disconnect 应该正确关闭 mock 连接', async () => {
91
+ let sqlClosed = false;
92
+ let redisClosed = false;
93
+
94
+ const mockSql = {
95
+ close: async () => {
96
+ sqlClosed = true;
97
+ }
98
+ } as any;
99
+ const mockRedis = {
100
+ close: () => {
101
+ redisClosed = true;
102
+ }
103
+ } as any;
104
+
105
+ Connect.__setMockSql(mockSql);
106
+ Connect.__setMockRedis(mockRedis);
107
+
108
+ await Connect.disconnect();
109
+
110
+ expect(sqlClosed).toBe(true);
111
+ expect(redisClosed).toBe(true);
112
+ expect(Connect.isConnected().sql).toBe(false);
113
+ expect(Connect.isConnected().redis).toBe(false);
114
+ });
115
+ });
116
+
117
+ describe('连接异常处理', () => {
118
+ test('disconnectSql 应该处理关闭时的错误', async () => {
119
+ const mockSql = {
120
+ close: async () => {
121
+ throw new Error('Close error');
122
+ }
123
+ } as any;
124
+
125
+ Connect.__setMockSql(mockSql);
126
+
127
+ // 不应该抛出错误,只是记录日志
128
+ await expect(Connect.disconnectSql()).resolves.toBeUndefined();
129
+ expect(Connect.isConnected().sql).toBe(false);
130
+ });
131
+
132
+ test('disconnectRedis 应该处理关闭时的错误', async () => {
133
+ const mockRedis = {
134
+ close: () => {
135
+ throw new Error('Close error');
136
+ }
137
+ } as any;
138
+
139
+ Connect.__setMockRedis(mockRedis);
140
+
141
+ // 不应该抛出错误,只是记录日志
142
+ await expect(Connect.disconnectRedis()).resolves.toBeUndefined();
143
+ expect(Connect.isConnected().redis).toBe(false);
144
+ });
145
+ });
146
+
147
+ describe('Connect.getStatus', () => {
148
+ test('未连接时返回正确的状态', () => {
149
+ const status = Connect.getStatus();
150
+
151
+ expect(status.sql.connected).toBe(false);
152
+ expect(status.sql.connectedAt).toBeNull();
153
+ expect(status.sql.uptime).toBeNull();
154
+ expect(status.sql.poolMax).toBe(1);
155
+
156
+ expect(status.redis.connected).toBe(false);
157
+ expect(status.redis.connectedAt).toBeNull();
158
+ expect(status.redis.uptime).toBeNull();
159
+ });
160
+
161
+ test('Mock 连接后返回正确的状态', () => {
162
+ const mockSql = { close: async () => {} } as any;
163
+ const mockRedis = { close: () => {} } as any;
164
+
165
+ Connect.__setMockSql(mockSql);
166
+ Connect.__setMockRedis(mockRedis);
167
+
168
+ const status = Connect.getStatus();
169
+
170
+ // Mock 不会设置连接时间,但连接状态应该为 true
171
+ expect(status.sql.connected).toBe(true);
172
+ expect(status.redis.connected).toBe(true);
173
+ });
174
+
175
+ test('__reset 应该重置所有状态包括连接时间', () => {
176
+ const mockSql = { close: async () => {} } as any;
177
+ Connect.__setMockSql(mockSql);
178
+
179
+ expect(Connect.getStatus().sql.connected).toBe(true);
180
+
181
+ Connect.__reset();
182
+
183
+ const status = Connect.getStatus();
184
+ expect(status.sql.connected).toBe(false);
185
+ expect(status.sql.connectedAt).toBeNull();
186
+ expect(status.sql.poolMax).toBe(1);
187
+ });
188
+ });
189
+ });
@@ -0,0 +1,287 @@
1
+ /**
2
+ * syncDb 变更应用模块测试
3
+ *
4
+ * 测试 apply.ts 中的函数:
5
+ * - compareFieldDefinition
6
+ */
7
+
8
+ import { describe, test, expect, beforeAll } from 'bun:test';
9
+
10
+ // 设置环境变量模拟 MySQL 环境
11
+ process.env.DB_TYPE = 'mysql';
12
+
13
+ let compareFieldDefinition: any;
14
+
15
+ beforeAll(async () => {
16
+ const apply = await import('../sync/syncDb/apply.js');
17
+ compareFieldDefinition = apply.compareFieldDefinition;
18
+ });
19
+
20
+ describe('compareFieldDefinition', () => {
21
+ describe('长度变化检测', () => {
22
+ test('string 类型长度变化被检测到', () => {
23
+ const existingColumn = {
24
+ type: 'varchar',
25
+ max: 50,
26
+ nullable: false,
27
+ defaultValue: '',
28
+ comment: '用户名'
29
+ };
30
+ const fieldDef = {
31
+ name: '用户名',
32
+ type: 'string',
33
+ max: 100,
34
+ nullable: false,
35
+ default: null
36
+ };
37
+
38
+ const changes = compareFieldDefinition(existingColumn, fieldDef);
39
+ const lengthChange = changes.find((c: any) => c.type === 'length');
40
+
41
+ expect(lengthChange).toBeDefined();
42
+ expect(lengthChange.current).toBe(50);
43
+ expect(lengthChange.expected).toBe(100);
44
+ });
45
+
46
+ test('长度相同无变化', () => {
47
+ const existingColumn = {
48
+ type: 'varchar',
49
+ max: 100,
50
+ nullable: false,
51
+ defaultValue: '',
52
+ comment: '用户名'
53
+ };
54
+ const fieldDef = {
55
+ name: '用户名',
56
+ type: 'string',
57
+ max: 100,
58
+ nullable: false,
59
+ default: null
60
+ };
61
+
62
+ const changes = compareFieldDefinition(existingColumn, fieldDef);
63
+ const lengthChange = changes.find((c: any) => c.type === 'length');
64
+
65
+ expect(lengthChange).toBeUndefined();
66
+ });
67
+ });
68
+
69
+ describe('注释变化检测', () => {
70
+ test('注释变化被检测到', () => {
71
+ const existingColumn = {
72
+ type: 'varchar',
73
+ max: 100,
74
+ nullable: false,
75
+ defaultValue: '',
76
+ comment: '旧注释'
77
+ };
78
+ const fieldDef = {
79
+ name: '新注释',
80
+ type: 'string',
81
+ max: 100,
82
+ nullable: false,
83
+ default: null
84
+ };
85
+
86
+ const changes = compareFieldDefinition(existingColumn, fieldDef);
87
+ const commentChange = changes.find((c: any) => c.type === 'comment');
88
+
89
+ expect(commentChange).toBeDefined();
90
+ expect(commentChange.current).toBe('旧注释');
91
+ expect(commentChange.expected).toBe('新注释');
92
+ });
93
+
94
+ test('注释相同无变化', () => {
95
+ const existingColumn = {
96
+ type: 'varchar',
97
+ max: 100,
98
+ nullable: false,
99
+ defaultValue: '',
100
+ comment: '用户名'
101
+ };
102
+ const fieldDef = {
103
+ name: '用户名',
104
+ type: 'string',
105
+ max: 100,
106
+ nullable: false,
107
+ default: null
108
+ };
109
+
110
+ const changes = compareFieldDefinition(existingColumn, fieldDef);
111
+ const commentChange = changes.find((c: any) => c.type === 'comment');
112
+
113
+ expect(commentChange).toBeUndefined();
114
+ });
115
+ });
116
+
117
+ describe('数据类型变化检测', () => {
118
+ test('类型变化被检测到', () => {
119
+ const existingColumn = {
120
+ type: 'bigint',
121
+ max: null,
122
+ nullable: false,
123
+ defaultValue: 0,
124
+ comment: '数量'
125
+ };
126
+ const fieldDef = {
127
+ name: '数量',
128
+ type: 'string',
129
+ max: 100,
130
+ nullable: false,
131
+ default: null
132
+ };
133
+
134
+ const changes = compareFieldDefinition(existingColumn, fieldDef);
135
+ const typeChange = changes.find((c: any) => c.type === 'datatype');
136
+
137
+ expect(typeChange).toBeDefined();
138
+ expect(typeChange.current).toBe('bigint');
139
+ expect(typeChange.expected).toBe('varchar');
140
+ });
141
+
142
+ test('类型相同无变化', () => {
143
+ const existingColumn = {
144
+ type: 'bigint',
145
+ max: null,
146
+ nullable: false,
147
+ defaultValue: 0,
148
+ comment: '数量'
149
+ };
150
+ const fieldDef = {
151
+ name: '数量',
152
+ type: 'number',
153
+ max: null,
154
+ nullable: false,
155
+ default: 0
156
+ };
157
+
158
+ const changes = compareFieldDefinition(existingColumn, fieldDef);
159
+ const typeChange = changes.find((c: any) => c.type === 'datatype');
160
+
161
+ expect(typeChange).toBeUndefined();
162
+ });
163
+ });
164
+
165
+ describe('可空性变化检测', () => {
166
+ test('nullable 变化被检测到', () => {
167
+ const existingColumn = {
168
+ type: 'varchar',
169
+ max: 100,
170
+ nullable: false,
171
+ defaultValue: '',
172
+ comment: '用户名'
173
+ };
174
+ const fieldDef = {
175
+ name: '用户名',
176
+ type: 'string',
177
+ max: 100,
178
+ nullable: true,
179
+ default: null
180
+ };
181
+
182
+ const changes = compareFieldDefinition(existingColumn, fieldDef);
183
+ const nullableChange = changes.find((c: any) => c.type === 'nullable');
184
+
185
+ expect(nullableChange).toBeDefined();
186
+ expect(nullableChange.current).toBe(false);
187
+ expect(nullableChange.expected).toBe(true);
188
+ });
189
+ });
190
+
191
+ describe('默认值变化检测', () => {
192
+ test('默认值变化被检测到', () => {
193
+ const existingColumn = {
194
+ type: 'varchar',
195
+ max: 100,
196
+ nullable: false,
197
+ defaultValue: 'old',
198
+ comment: '用户名'
199
+ };
200
+ const fieldDef = {
201
+ name: '用户名',
202
+ type: 'string',
203
+ max: 100,
204
+ nullable: false,
205
+ default: 'new'
206
+ };
207
+
208
+ const changes = compareFieldDefinition(existingColumn, fieldDef);
209
+ const defaultChange = changes.find((c: any) => c.type === 'default');
210
+
211
+ expect(defaultChange).toBeDefined();
212
+ expect(defaultChange.current).toBe('old');
213
+ expect(defaultChange.expected).toBe('new');
214
+ });
215
+
216
+ test('null 默认值被正确处理', () => {
217
+ const existingColumn = {
218
+ type: 'varchar',
219
+ max: 100,
220
+ nullable: false,
221
+ defaultValue: '',
222
+ comment: '用户名'
223
+ };
224
+ const fieldDef = {
225
+ name: '用户名',
226
+ type: 'string',
227
+ max: 100,
228
+ nullable: false,
229
+ default: null // null 会被解析为空字符串
230
+ };
231
+
232
+ const changes = compareFieldDefinition(existingColumn, fieldDef);
233
+ const defaultChange = changes.find((c: any) => c.type === 'default');
234
+
235
+ // null -> '' (空字符串),与现有值相同,无变化
236
+ expect(defaultChange).toBeUndefined();
237
+ });
238
+ });
239
+
240
+ describe('多变化组合', () => {
241
+ test('多个变化同时被检测', () => {
242
+ const existingColumn = {
243
+ type: 'varchar',
244
+ max: 50,
245
+ nullable: false,
246
+ defaultValue: 'old',
247
+ comment: '旧注释'
248
+ };
249
+ const fieldDef = {
250
+ name: '新注释',
251
+ type: 'string',
252
+ max: 100,
253
+ nullable: true,
254
+ default: 'new'
255
+ };
256
+
257
+ const changes = compareFieldDefinition(existingColumn, fieldDef);
258
+
259
+ expect(changes.length).toBe(4); // length, comment, nullable, default
260
+ expect(changes.some((c: any) => c.type === 'length')).toBe(true);
261
+ expect(changes.some((c: any) => c.type === 'comment')).toBe(true);
262
+ expect(changes.some((c: any) => c.type === 'nullable')).toBe(true);
263
+ expect(changes.some((c: any) => c.type === 'default')).toBe(true);
264
+ });
265
+
266
+ test('无变化返回空数组', () => {
267
+ const existingColumn = {
268
+ type: 'varchar',
269
+ max: 100,
270
+ nullable: false,
271
+ defaultValue: '',
272
+ comment: '用户名'
273
+ };
274
+ const fieldDef = {
275
+ name: '用户名',
276
+ type: 'string',
277
+ max: 100,
278
+ nullable: false,
279
+ default: null
280
+ };
281
+
282
+ const changes = compareFieldDefinition(existingColumn, fieldDef);
283
+
284
+ expect(changes.length).toBe(0);
285
+ });
286
+ });
287
+ });
@@ -0,0 +1,150 @@
1
+ /**
2
+ * syncDb 常量模块测试
3
+ *
4
+ * 测试 constants.ts 中的常量:
5
+ * - DB_VERSION_REQUIREMENTS
6
+ * - SYSTEM_FIELDS
7
+ * - SYSTEM_INDEX_FIELDS
8
+ * - CHANGE_TYPE_LABELS
9
+ * - MYSQL_TABLE_CONFIG
10
+ * - typeMapping
11
+ */
12
+
13
+ import { describe, test, expect, beforeAll } from 'bun:test';
14
+
15
+ // 设置环境变量模拟 MySQL 环境
16
+ process.env.DB_TYPE = 'mysql';
17
+
18
+ let constants: any;
19
+
20
+ beforeAll(async () => {
21
+ constants = await import('../sync/syncDb/constants.js');
22
+ });
23
+
24
+ describe('DB_VERSION_REQUIREMENTS', () => {
25
+ test('MySQL 最低版本为 8', () => {
26
+ expect(constants.DB_VERSION_REQUIREMENTS.MYSQL_MIN_MAJOR).toBe(8);
27
+ });
28
+
29
+ test('PostgreSQL 最低版本为 17', () => {
30
+ expect(constants.DB_VERSION_REQUIREMENTS.POSTGRES_MIN_MAJOR).toBe(17);
31
+ });
32
+
33
+ test('SQLite 最低版本为 3.50.0', () => {
34
+ expect(constants.DB_VERSION_REQUIREMENTS.SQLITE_MIN_VERSION).toBe('3.50.0');
35
+ });
36
+ });
37
+
38
+ describe('SYSTEM_FIELDS', () => {
39
+ test('包含 id 字段', () => {
40
+ expect(constants.SYSTEM_FIELDS.ID.name).toBe('id');
41
+ });
42
+
43
+ test('包含 created_at 字段', () => {
44
+ expect(constants.SYSTEM_FIELDS.CREATED_AT.name).toBe('created_at');
45
+ });
46
+
47
+ test('包含 updated_at 字段', () => {
48
+ expect(constants.SYSTEM_FIELDS.UPDATED_AT.name).toBe('updated_at');
49
+ });
50
+
51
+ test('包含 deleted_at 字段', () => {
52
+ expect(constants.SYSTEM_FIELDS.DELETED_AT.name).toBe('deleted_at');
53
+ });
54
+
55
+ test('包含 state 字段', () => {
56
+ expect(constants.SYSTEM_FIELDS.STATE.name).toBe('state');
57
+ });
58
+ });
59
+
60
+ describe('SYSTEM_INDEX_FIELDS', () => {
61
+ test('包含 created_at', () => {
62
+ expect(constants.SYSTEM_INDEX_FIELDS).toContain('created_at');
63
+ });
64
+
65
+ test('包含 updated_at', () => {
66
+ expect(constants.SYSTEM_INDEX_FIELDS).toContain('updated_at');
67
+ });
68
+
69
+ test('包含 state', () => {
70
+ expect(constants.SYSTEM_INDEX_FIELDS).toContain('state');
71
+ });
72
+
73
+ test('共 3 个系统索引字段', () => {
74
+ expect(constants.SYSTEM_INDEX_FIELDS.length).toBe(3);
75
+ });
76
+ });
77
+
78
+ describe('CHANGE_TYPE_LABELS', () => {
79
+ test('length 对应 "长度"', () => {
80
+ expect(constants.CHANGE_TYPE_LABELS.length).toBe('长度');
81
+ });
82
+
83
+ test('datatype 对应 "类型"', () => {
84
+ expect(constants.CHANGE_TYPE_LABELS.datatype).toBe('类型');
85
+ });
86
+
87
+ test('comment 对应 "注释"', () => {
88
+ expect(constants.CHANGE_TYPE_LABELS.comment).toBe('注释');
89
+ });
90
+
91
+ test('default 对应 "默认值"', () => {
92
+ expect(constants.CHANGE_TYPE_LABELS.default).toBe('默认值');
93
+ });
94
+ });
95
+
96
+ describe('MYSQL_TABLE_CONFIG', () => {
97
+ test('ENGINE 为 InnoDB', () => {
98
+ expect(constants.MYSQL_TABLE_CONFIG.ENGINE).toBe('InnoDB');
99
+ });
100
+
101
+ test('CHARSET 为 utf8mb4', () => {
102
+ expect(constants.MYSQL_TABLE_CONFIG.CHARSET).toBe('utf8mb4');
103
+ });
104
+
105
+ test('COLLATE 为 utf8mb4_0900_ai_ci', () => {
106
+ expect(constants.MYSQL_TABLE_CONFIG.COLLATE).toBe('utf8mb4_0900_ai_ci');
107
+ });
108
+ });
109
+
110
+ describe('typeMapping (MySQL)', () => {
111
+ test('number 映射为 BIGINT', () => {
112
+ expect(constants.typeMapping.number).toBe('BIGINT');
113
+ });
114
+
115
+ test('string 映射为 VARCHAR', () => {
116
+ expect(constants.typeMapping.string).toBe('VARCHAR');
117
+ });
118
+
119
+ test('text 映射为 MEDIUMTEXT', () => {
120
+ expect(constants.typeMapping.text).toBe('MEDIUMTEXT');
121
+ });
122
+
123
+ test('array_string 映射为 VARCHAR', () => {
124
+ expect(constants.typeMapping.array_string).toBe('VARCHAR');
125
+ });
126
+
127
+ test('array_text 映射为 MEDIUMTEXT', () => {
128
+ expect(constants.typeMapping.array_text).toBe('MEDIUMTEXT');
129
+ });
130
+ });
131
+
132
+ describe('IS_PLAN', () => {
133
+ test('IS_PLAN 为 boolean 类型', () => {
134
+ expect(typeof constants.IS_PLAN).toBe('boolean');
135
+ });
136
+ });
137
+
138
+ describe('数据库类型判断 (MySQL)', () => {
139
+ test('IS_MYSQL 为 true', () => {
140
+ expect(constants.IS_MYSQL).toBe(true);
141
+ });
142
+
143
+ test('IS_PG 为 false', () => {
144
+ expect(constants.IS_PG).toBe(false);
145
+ });
146
+
147
+ test('IS_SQLITE 为 false', () => {
148
+ expect(constants.IS_SQLITE).toBe(false);
149
+ });
150
+ });