mm_mysql 2.1.0 → 2.2.0
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.
- package/README.md +224 -81
- package/db.js +129 -54
- package/index.js +3 -2
- package/package.json +1 -1
- package/sql.js +12 -13
- package/test.js +150 -49
- package/test_create_table.js +193 -0
package/test.js
CHANGED
|
@@ -48,7 +48,7 @@ TestMysql.prototype._init = async function() {
|
|
|
48
48
|
await this._mysql.open();
|
|
49
49
|
|
|
50
50
|
// 创建测试数据库
|
|
51
|
-
await this.
|
|
51
|
+
await this._createTestDatabase();
|
|
52
52
|
|
|
53
53
|
// 重新连接指定数据库
|
|
54
54
|
await this._mysql.close();
|
|
@@ -57,7 +57,7 @@ TestMysql.prototype._init = async function() {
|
|
|
57
57
|
await this._mysql.open();
|
|
58
58
|
|
|
59
59
|
// 创建测试表
|
|
60
|
-
await this.
|
|
60
|
+
await this._createTestTable();
|
|
61
61
|
|
|
62
62
|
console.log('测试环境初始化完成');
|
|
63
63
|
return true;
|
|
@@ -71,7 +71,7 @@ TestMysql.prototype._init = async function() {
|
|
|
71
71
|
* 创建测试数据库
|
|
72
72
|
* @returns {Promise<boolean>}
|
|
73
73
|
*/
|
|
74
|
-
TestMysql.prototype.
|
|
74
|
+
TestMysql.prototype._createTestDatabase = async function() {
|
|
75
75
|
try {
|
|
76
76
|
const create_db_sql = `CREATE DATABASE IF NOT EXISTS test_db`;
|
|
77
77
|
await this._mysql.exec(create_db_sql);
|
|
@@ -87,7 +87,7 @@ TestMysql.prototype._create_test_database = async function() {
|
|
|
87
87
|
* 创建测试表
|
|
88
88
|
* @returns {Promise<boolean>}
|
|
89
89
|
*/
|
|
90
|
-
TestMysql.prototype.
|
|
90
|
+
TestMysql.prototype._createTestTable = async function() {
|
|
91
91
|
try {
|
|
92
92
|
const sql = `
|
|
93
93
|
CREATE TABLE IF NOT EXISTS ${this._test_table_name} (
|
|
@@ -131,7 +131,7 @@ TestMysql.prototype._cleanup = async function() {
|
|
|
131
131
|
* @param {Boolean} success - 是否成功
|
|
132
132
|
* @param {String} message - 测试信息
|
|
133
133
|
*/
|
|
134
|
-
TestMysql.prototype.
|
|
134
|
+
TestMysql.prototype._recordResult = function(test_name, success, message) {
|
|
135
135
|
this._test_results.push({
|
|
136
136
|
test_name,
|
|
137
137
|
success,
|
|
@@ -147,7 +147,7 @@ TestMysql.prototype._record_result = function(test_name, success, message) {
|
|
|
147
147
|
* 测试连接功能
|
|
148
148
|
* @returns {Promise<boolean>}
|
|
149
149
|
*/
|
|
150
|
-
TestMysql.prototype.
|
|
150
|
+
TestMysql.prototype.testConnection = async function() {
|
|
151
151
|
try {
|
|
152
152
|
// 测试获取连接
|
|
153
153
|
const conn = await this._mysql.getConn();
|
|
@@ -166,10 +166,10 @@ TestMysql.prototype.test_connection = async function() {
|
|
|
166
166
|
conn.release();
|
|
167
167
|
}
|
|
168
168
|
|
|
169
|
-
this.
|
|
169
|
+
this._recordResult('连接测试', true, '数据库连接正常');
|
|
170
170
|
return true;
|
|
171
171
|
} catch (error) {
|
|
172
|
-
this.
|
|
172
|
+
this._recordResult('连接测试', false, error.message);
|
|
173
173
|
return false;
|
|
174
174
|
}
|
|
175
175
|
};
|
|
@@ -178,7 +178,7 @@ TestMysql.prototype.test_connection = async function() {
|
|
|
178
178
|
* 测试插入功能
|
|
179
179
|
* @returns {Promise<boolean>}
|
|
180
180
|
*/
|
|
181
|
-
TestMysql.prototype.
|
|
181
|
+
TestMysql.prototype.testInsert = async function() {
|
|
182
182
|
try {
|
|
183
183
|
const test_data = {
|
|
184
184
|
name: '测试用户',
|
|
@@ -193,10 +193,10 @@ TestMysql.prototype.test_insert = async function() {
|
|
|
193
193
|
throw new Error('插入数据失败');
|
|
194
194
|
}
|
|
195
195
|
|
|
196
|
-
this.
|
|
196
|
+
this._recordResult('插入测试', true, `插入成功,ID: ${result.insertId}`);
|
|
197
197
|
return true;
|
|
198
198
|
} catch (error) {
|
|
199
|
-
this.
|
|
199
|
+
this._recordResult('插入测试', false, error.message);
|
|
200
200
|
return false;
|
|
201
201
|
}
|
|
202
202
|
};
|
|
@@ -205,7 +205,7 @@ TestMysql.prototype.test_insert = async function() {
|
|
|
205
205
|
* 测试查询功能
|
|
206
206
|
* @returns {Promise<boolean>}
|
|
207
207
|
*/
|
|
208
|
-
TestMysql.prototype.
|
|
208
|
+
TestMysql.prototype.testQuery = async function() {
|
|
209
209
|
try {
|
|
210
210
|
// 查询所有数据
|
|
211
211
|
const sql = `SELECT * FROM ${this._test_table_name}`;
|
|
@@ -215,10 +215,10 @@ TestMysql.prototype.test_query = async function() {
|
|
|
215
215
|
throw new Error('查询结果格式异常');
|
|
216
216
|
}
|
|
217
217
|
|
|
218
|
-
this.
|
|
218
|
+
this._recordResult('查询测试', true, `查询到 ${results.length} 条记录`);
|
|
219
219
|
return true;
|
|
220
220
|
} catch (error) {
|
|
221
|
-
this.
|
|
221
|
+
this._recordResult('查询测试', false, error.message);
|
|
222
222
|
return false;
|
|
223
223
|
}
|
|
224
224
|
};
|
|
@@ -227,7 +227,7 @@ TestMysql.prototype.test_query = async function() {
|
|
|
227
227
|
* 测试条件查询
|
|
228
228
|
* @returns {Promise<boolean>}
|
|
229
229
|
*/
|
|
230
|
-
TestMysql.prototype.
|
|
230
|
+
TestMysql.prototype.testConditionalQuery = async function() {
|
|
231
231
|
try {
|
|
232
232
|
const sql = `SELECT * FROM ${this._test_table_name} WHERE name = ?`;
|
|
233
233
|
const results = await this._mysql.run(sql, ['测试用户']);
|
|
@@ -236,10 +236,10 @@ TestMysql.prototype.test_conditional_query = async function() {
|
|
|
236
236
|
throw new Error('条件查询结果格式异常');
|
|
237
237
|
}
|
|
238
238
|
|
|
239
|
-
this.
|
|
239
|
+
this._recordResult('条件查询测试', true, `查询到 ${results.length} 条匹配记录`);
|
|
240
240
|
return true;
|
|
241
241
|
} catch (error) {
|
|
242
|
-
this.
|
|
242
|
+
this._recordResult('条件查询测试', false, error.message);
|
|
243
243
|
return false;
|
|
244
244
|
}
|
|
245
245
|
};
|
|
@@ -248,7 +248,7 @@ TestMysql.prototype.test_conditional_query = async function() {
|
|
|
248
248
|
* 测试更新功能
|
|
249
249
|
* @returns {Promise<boolean>}
|
|
250
250
|
*/
|
|
251
|
-
TestMysql.prototype.
|
|
251
|
+
TestMysql.prototype.testUpdate = async function() {
|
|
252
252
|
try {
|
|
253
253
|
const sql = `UPDATE ${this._test_table_name} SET age = ? WHERE name = ?`;
|
|
254
254
|
const result = await this._mysql.exec(sql, [30, '测试用户']);
|
|
@@ -257,10 +257,10 @@ TestMysql.prototype.test_update = async function() {
|
|
|
257
257
|
throw new Error('更新数据失败');
|
|
258
258
|
}
|
|
259
259
|
|
|
260
|
-
this.
|
|
260
|
+
this._recordResult('更新测试', true, `更新了 ${result.affectedRows} 条记录`);
|
|
261
261
|
return true;
|
|
262
262
|
} catch (error) {
|
|
263
|
-
this.
|
|
263
|
+
this._recordResult('更新测试', false, error.message);
|
|
264
264
|
return false;
|
|
265
265
|
}
|
|
266
266
|
};
|
|
@@ -269,7 +269,7 @@ TestMysql.prototype.test_update = async function() {
|
|
|
269
269
|
* 测试删除功能
|
|
270
270
|
* @returns {Promise<boolean>}
|
|
271
271
|
*/
|
|
272
|
-
TestMysql.prototype.
|
|
272
|
+
TestMysql.prototype.testDelete = async function() {
|
|
273
273
|
try {
|
|
274
274
|
const sql = `DELETE FROM ${this._test_table_name} WHERE name = ?`;
|
|
275
275
|
const result = await this._mysql.exec(sql, ['测试用户']);
|
|
@@ -278,10 +278,109 @@ TestMysql.prototype.test_delete = async function() {
|
|
|
278
278
|
throw new Error('删除数据失败');
|
|
279
279
|
}
|
|
280
280
|
|
|
281
|
-
this.
|
|
281
|
+
this._recordResult('删除测试', true, `删除了 ${result.affectedRows} 条记录`);
|
|
282
282
|
return true;
|
|
283
283
|
} catch (error) {
|
|
284
|
-
this.
|
|
284
|
+
this._recordResult('删除测试', false, error.message);
|
|
285
|
+
return false;
|
|
286
|
+
}
|
|
287
|
+
};
|
|
288
|
+
|
|
289
|
+
/**
|
|
290
|
+
* 测试DB类功能
|
|
291
|
+
* @returns {Promise<boolean>}
|
|
292
|
+
*/
|
|
293
|
+
TestMysql.prototype.testDbClass = async function() {
|
|
294
|
+
try {
|
|
295
|
+
// 获取DB实例
|
|
296
|
+
const db = this._mysql.db().new(this._test_table_name, 'id');
|
|
297
|
+
|
|
298
|
+
if (!db) {
|
|
299
|
+
throw new Error('获取DB实例失败');
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
// 测试DB类的add方法
|
|
303
|
+
const add_result = await db.add({
|
|
304
|
+
name: 'DB测试用户',
|
|
305
|
+
email: 'db_test@example.com',
|
|
306
|
+
age: 30
|
|
307
|
+
});
|
|
308
|
+
|
|
309
|
+
if (!add_result || add_result.insertId <= 0) {
|
|
310
|
+
throw new Error('DB.add()方法测试失败');
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
// 测试DB类的get方法
|
|
314
|
+
const get_result = await db.get({ name: 'DB测试用户' });
|
|
315
|
+
|
|
316
|
+
if (!get_result || get_result.length !== 1) {
|
|
317
|
+
throw new Error('DB.get()方法测试失败');
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
// 测试DB类的set方法
|
|
321
|
+
const set_result = await db.set({ id: add_result.insertId }, { age: 31 });
|
|
322
|
+
|
|
323
|
+
if (!set_result || set_result.affectedRows !== 1) {
|
|
324
|
+
throw new Error('DB.set()方法测试失败');
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
// 测试DB类的del方法
|
|
328
|
+
const del_result = await db.del({ id: add_result.insertId });
|
|
329
|
+
|
|
330
|
+
if (!del_result || del_result.affectedRows !== 1) {
|
|
331
|
+
throw new Error('DB.del()方法测试失败');
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
this._recordResult('DB类测试', true, 'DB类方法测试通过');
|
|
335
|
+
return true;
|
|
336
|
+
} catch (error) {
|
|
337
|
+
this._recordResult('DB类测试', false, error.message);
|
|
338
|
+
return false;
|
|
339
|
+
}
|
|
340
|
+
};
|
|
341
|
+
|
|
342
|
+
/**
|
|
343
|
+
* 测试Sql类功能
|
|
344
|
+
* @returns {Promise<boolean>}
|
|
345
|
+
*/
|
|
346
|
+
TestMysql.prototype.testSqlClass = async function() {
|
|
347
|
+
try {
|
|
348
|
+
// 获取DB实例(Sql类的子类)
|
|
349
|
+
const db = this._mysql.db().new(this._test_table_name, 'id');
|
|
350
|
+
|
|
351
|
+
if (!db) {
|
|
352
|
+
throw new Error('获取Sql实例失败');
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
// 测试Sql类的addSql方法
|
|
356
|
+
const add_sql = db.toAddSql({
|
|
357
|
+
name: 'Sql测试用户',
|
|
358
|
+
email: 'sql_test@example.com',
|
|
359
|
+
age: 28
|
|
360
|
+
});
|
|
361
|
+
|
|
362
|
+
if (!add_sql || typeof add_sql !== 'string') {
|
|
363
|
+
throw new Error('Sql.toAddSql()方法测试失败');
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
// 测试Sql类的getSql方法
|
|
367
|
+
const get_sql = db.toGetSql({ name: 'Sql测试用户' });
|
|
368
|
+
|
|
369
|
+
if (!get_sql || typeof get_sql !== 'string') {
|
|
370
|
+
throw new Error('Sql.toGetSql()方法测试失败');
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
// 测试Sql类的escape方法
|
|
374
|
+
const escaped_value = db.escape("test' OR '1'='1");
|
|
375
|
+
|
|
376
|
+
if (!escaped_value || escaped_value === "test' OR '1'='1") {
|
|
377
|
+
throw new Error('Sql.escape()方法测试失败');
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
this._recordResult('Sql类测试', true, 'Sql类方法测试通过');
|
|
381
|
+
return true;
|
|
382
|
+
} catch (error) {
|
|
383
|
+
this._recordResult('Sql类测试', false, error.message);
|
|
285
384
|
return false;
|
|
286
385
|
}
|
|
287
386
|
};
|
|
@@ -290,7 +389,7 @@ TestMysql.prototype.test_delete = async function() {
|
|
|
290
389
|
* 测试事务功能
|
|
291
390
|
* @returns {Promise<boolean>}
|
|
292
391
|
*/
|
|
293
|
-
TestMysql.prototype.
|
|
392
|
+
TestMysql.prototype.testTransaction = async function() {
|
|
294
393
|
try {
|
|
295
394
|
const result = await this._mysql.transaction(async (tx) => {
|
|
296
395
|
// 在事务中插入数据 - 使用Mysql类的exec方法
|
|
@@ -304,10 +403,10 @@ TestMysql.prototype.test_transaction = async function() {
|
|
|
304
403
|
return results;
|
|
305
404
|
});
|
|
306
405
|
|
|
307
|
-
this.
|
|
406
|
+
this._recordResult('事务测试', true, '事务执行成功');
|
|
308
407
|
return true;
|
|
309
408
|
} catch (error) {
|
|
310
|
-
this.
|
|
409
|
+
this._recordResult('事务测试', false, error.message);
|
|
311
410
|
return false;
|
|
312
411
|
}
|
|
313
412
|
};
|
|
@@ -316,10 +415,10 @@ TestMysql.prototype.test_transaction = async function() {
|
|
|
316
415
|
* 测试连接池功能
|
|
317
416
|
* @returns {Promise<boolean>}
|
|
318
417
|
*/
|
|
319
|
-
TestMysql.prototype.
|
|
418
|
+
TestMysql.prototype.testConnectionPool = async function() {
|
|
320
419
|
try {
|
|
321
420
|
if (!this._mysql._pool) {
|
|
322
|
-
this.
|
|
421
|
+
this._recordResult('连接池测试', true, '连接池未启用(单连接模式)');
|
|
323
422
|
return true;
|
|
324
423
|
}
|
|
325
424
|
|
|
@@ -338,10 +437,10 @@ TestMysql.prototype.test_connection_pool = async function() {
|
|
|
338
437
|
}
|
|
339
438
|
});
|
|
340
439
|
|
|
341
|
-
this.
|
|
440
|
+
this._recordResult('连接池测试', true, `并发获取 ${connections.length} 个连接成功`);
|
|
342
441
|
return true;
|
|
343
442
|
} catch (error) {
|
|
344
|
-
this.
|
|
443
|
+
this._recordResult('连接池测试', false, error.message);
|
|
345
444
|
return false;
|
|
346
445
|
}
|
|
347
446
|
};
|
|
@@ -350,20 +449,20 @@ TestMysql.prototype.test_connection_pool = async function() {
|
|
|
350
449
|
* 测试错误处理
|
|
351
450
|
* @returns {Promise<boolean>}
|
|
352
451
|
*/
|
|
353
|
-
TestMysql.prototype.
|
|
452
|
+
TestMysql.prototype.testErrorHandling = async function() {
|
|
354
453
|
try {
|
|
355
454
|
// 测试无效SQL
|
|
356
455
|
const invalid_sql = 'SELECT * FROM non_existent_table';
|
|
357
456
|
await this._mysql.run(invalid_sql);
|
|
358
457
|
|
|
359
|
-
this.
|
|
458
|
+
this._recordResult('错误处理测试', false, '应该抛出错误但未抛出');
|
|
360
459
|
return false;
|
|
361
460
|
} catch (error) {
|
|
362
461
|
if (error.code && error.code.startsWith('ER_')) {
|
|
363
|
-
this.
|
|
462
|
+
this._recordResult('错误处理测试', true, `正确捕获SQL错误: ${error.message}`);
|
|
364
463
|
return true;
|
|
365
464
|
} else {
|
|
366
|
-
this.
|
|
465
|
+
this._recordResult('错误处理测试', false, `捕获到非预期错误: ${error.message}`);
|
|
367
466
|
return false;
|
|
368
467
|
}
|
|
369
468
|
}
|
|
@@ -373,27 +472,29 @@ TestMysql.prototype.test_error_handling = async function() {
|
|
|
373
472
|
* 运行所有测试
|
|
374
473
|
* @returns {Promise<Object>}
|
|
375
474
|
*/
|
|
376
|
-
TestMysql.prototype.
|
|
475
|
+
TestMysql.prototype.runAllTests = async function() {
|
|
377
476
|
console.log('\n=== 开始运行MySQL功能测试 ===\n');
|
|
378
477
|
|
|
379
478
|
// 初始化测试环境
|
|
380
479
|
const init_success = await this._init();
|
|
381
480
|
if (!init_success) {
|
|
382
481
|
console.log('测试环境初始化失败,跳过所有测试');
|
|
383
|
-
return this.
|
|
482
|
+
return this._getTestSummary();
|
|
384
483
|
}
|
|
385
484
|
|
|
386
485
|
// 定义测试用例
|
|
387
486
|
const test_cases = [
|
|
388
|
-
{ name: '连接测试', method: '
|
|
389
|
-
{ name: '插入测试', method: '
|
|
390
|
-
{ name: '查询测试', method: '
|
|
391
|
-
{ name: '条件查询测试', method: '
|
|
392
|
-
{ name: '更新测试', method: '
|
|
393
|
-
{ name: '删除测试', method: '
|
|
394
|
-
{ name: '
|
|
395
|
-
{ name: '
|
|
396
|
-
{ name: '
|
|
487
|
+
{ name: '连接测试', method: 'testConnection' },
|
|
488
|
+
{ name: '插入测试', method: 'testInsert' },
|
|
489
|
+
{ name: '查询测试', method: 'testQuery' },
|
|
490
|
+
{ name: '条件查询测试', method: 'testConditionalQuery' },
|
|
491
|
+
{ name: '更新测试', method: 'testUpdate' },
|
|
492
|
+
{ name: '删除测试', method: 'testDelete' },
|
|
493
|
+
{ name: 'DB类测试', method: 'testDbClass' },
|
|
494
|
+
{ name: 'Sql类测试', method: 'testSqlClass' },
|
|
495
|
+
{ name: '事务测试', method: 'testTransaction' },
|
|
496
|
+
{ name: '连接池测试', method: 'testConnectionPool' },
|
|
497
|
+
{ name: '错误处理测试', method: 'testErrorHandling' }
|
|
397
498
|
];
|
|
398
499
|
|
|
399
500
|
// 顺序执行测试用例
|
|
@@ -401,7 +502,7 @@ TestMysql.prototype.run_all_tests = async function() {
|
|
|
401
502
|
try {
|
|
402
503
|
await this[test_case.method]();
|
|
403
504
|
} catch (error) {
|
|
404
|
-
this.
|
|
505
|
+
this._recordResult(test_case.name, false, `测试执行异常: ${error.message}`);
|
|
405
506
|
}
|
|
406
507
|
|
|
407
508
|
// 添加短暂延迟,避免数据库压力
|
|
@@ -417,14 +518,14 @@ TestMysql.prototype.run_all_tests = async function() {
|
|
|
417
518
|
}
|
|
418
519
|
|
|
419
520
|
console.log('\n=== 测试完成 ===\n');
|
|
420
|
-
return this.
|
|
521
|
+
return this._getTestSummary();
|
|
421
522
|
};
|
|
422
523
|
|
|
423
524
|
/**
|
|
424
525
|
* 获取测试摘要
|
|
425
526
|
* @returns {Object}
|
|
426
527
|
*/
|
|
427
|
-
TestMysql.prototype.
|
|
528
|
+
TestMysql.prototype._getTestSummary = function() {
|
|
428
529
|
const total = this._test_results.length;
|
|
429
530
|
const passed = this._test_results.filter(r => r.success).length;
|
|
430
531
|
const failed = total - passed;
|
|
@@ -466,7 +567,7 @@ TestMysql.prototype._sleep = function(ms) {
|
|
|
466
567
|
*/
|
|
467
568
|
TestMysql.prototype.main = async function() {
|
|
468
569
|
try {
|
|
469
|
-
const summary = await this.
|
|
570
|
+
const summary = await this.runAllTests();
|
|
470
571
|
|
|
471
572
|
if (summary.failed > 0) {
|
|
472
573
|
console.log('\n❌ 部分测试失败,请检查数据库配置和连接');
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
const { Mysql } = require('./index');
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* 测试 createTable 方法功能
|
|
5
|
+
*/
|
|
6
|
+
async function testCreateTable() {
|
|
7
|
+
console.log('开始测试 createTable 方法...');
|
|
8
|
+
|
|
9
|
+
let mysql = null;
|
|
10
|
+
const testDatabase = 'test_mm_mysql';
|
|
11
|
+
const testTable = 'test_users';
|
|
12
|
+
|
|
13
|
+
try {
|
|
14
|
+
// 初始化 MySQL 连接
|
|
15
|
+
mysql = new Mysql({
|
|
16
|
+
host: '127.0.0.1',
|
|
17
|
+
port: 3306,
|
|
18
|
+
user: 'root',
|
|
19
|
+
password: 'Asd159357',
|
|
20
|
+
database: testDatabase,
|
|
21
|
+
connectionLimit: 1
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
// 打开连接
|
|
25
|
+
await mysql.open();
|
|
26
|
+
console.log('✅ 数据库连接成功');
|
|
27
|
+
|
|
28
|
+
// 获取 DB 实例
|
|
29
|
+
const db = mysql.db();
|
|
30
|
+
|
|
31
|
+
// 定义测试表模型
|
|
32
|
+
const userModel = {
|
|
33
|
+
fields: {
|
|
34
|
+
id: 0, // 主键,会被自动设置为 INT AUTO_INCREMENT PRIMARY KEY
|
|
35
|
+
username: 'admin', // 字符串,长度 <= 255,会被设置为 VARCHAR(255)
|
|
36
|
+
email: 'test@example.com', // 字符串,会被设置为 VARCHAR(255)
|
|
37
|
+
age: 25, // 整数,会被设置为 INT
|
|
38
|
+
salary: 5000.50, // 浮点数,会被设置为 FLOAT
|
|
39
|
+
active: true, // boolean 类型,会被设置为 INT
|
|
40
|
+
birth_date: '1990-01-01', // date 类型,会被设置为 DATE
|
|
41
|
+
bio: 'This is a very long bio about the user that exceeds 255 characters in length. ' +
|
|
42
|
+
'This is necessary to test the text type functionality in the createTable method. ' +
|
|
43
|
+
'By making this string longer than 255 characters, we can ensure that the field ' +
|
|
44
|
+
'is created as a TEXT type instead of a VARCHAR(255).', // 字符串,长度 > 255,会被设置为 TEXT
|
|
45
|
+
created_at: '2023-10-25 10:30:00', // 日期时间字符串,会被设置为 DATETIME
|
|
46
|
+
login_time: new Date(), // Date 对象,会被设置为 DATETIME
|
|
47
|
+
last_active: Date.now() // 时间戳,会被设置为 DATETIME
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
// 创建表
|
|
52
|
+
console.log('开始创建测试表...');
|
|
53
|
+
const createResult = await db.createTable(testTable, userModel, 'id', 15000);
|
|
54
|
+
|
|
55
|
+
if (createResult && createResult.affectedRows !== undefined) {
|
|
56
|
+
console.log('✅ 测试表创建成功');
|
|
57
|
+
console.log(' 影响行数:', createResult.affectedRows);
|
|
58
|
+
} else {
|
|
59
|
+
console.log('⚠️ 表可能已存在(CREATE TABLE IF NOT EXISTS)');
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// 验证表是否存在
|
|
63
|
+
console.log('\n验证表结构...');
|
|
64
|
+
const tableExistsSql = `SHOW TABLES LIKE '${testTable}'`;
|
|
65
|
+
const tables = await mysql.run(tableExistsSql);
|
|
66
|
+
|
|
67
|
+
if (tables.length > 0) {
|
|
68
|
+
console.log('✅ 测试表确实存在');
|
|
69
|
+
} else {
|
|
70
|
+
throw new Error('测试表不存在');
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// 查看表结构
|
|
74
|
+
const describeSql = `DESCRIBE ${testTable}`;
|
|
75
|
+
const tableStructure = await mysql.run(describeSql);
|
|
76
|
+
|
|
77
|
+
console.log('\n表结构:');
|
|
78
|
+
tableStructure.forEach(row => {
|
|
79
|
+
console.log(` ${row.Field}: ${row.Type} ${row.Null} ${row.Key} ${row.Default} ${row.Extra}`);
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
// 验证字段类型是否正确
|
|
83
|
+
const fieldTypes = {
|
|
84
|
+
id: 'int',
|
|
85
|
+
username: 'varchar(255)',
|
|
86
|
+
email: 'varchar(255)',
|
|
87
|
+
age: 'int',
|
|
88
|
+
salary: 'float',
|
|
89
|
+
active: 'int', // MySQL 中 boolean 会被转换为 tinyint 或 int
|
|
90
|
+
birth_date: 'date',
|
|
91
|
+
bio: 'text',
|
|
92
|
+
created_at: 'datetime',
|
|
93
|
+
login_time: 'datetime', // Date 对象会被设置为 DATETIME
|
|
94
|
+
last_active: 'datetime' // 时间戳会被设置为 DATETIME
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
let allFieldsCorrect = true;
|
|
98
|
+
tableStructure.forEach(row => {
|
|
99
|
+
const expectedType = fieldTypes[row.Field];
|
|
100
|
+
if (expectedType && !row.Type.toLowerCase().includes(expectedType)) {
|
|
101
|
+
console.log(`❌ 字段 ${row.Field} 类型不正确,预期: ${expectedType},实际: ${row.Type}`);
|
|
102
|
+
allFieldsCorrect = false;
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
if (allFieldsCorrect) {
|
|
107
|
+
console.log('✅ 所有字段类型符合预期');
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// 测试插入数据
|
|
111
|
+
console.log('\n测试插入数据...');
|
|
112
|
+
const currentTime = new Date();
|
|
113
|
+
const insertSql = `INSERT INTO ${testTable} (username, email, age, salary, active, birth_date, bio, created_at, login_time, last_active) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`;
|
|
114
|
+
const insertResult = await mysql.exec(insertSql, ['testuser', 'testuser@example.com', 30, 6000.75, true, '1995-05-15', 'Test user bio', '2023-10-25 11:00:00', currentTime, currentTime]);
|
|
115
|
+
|
|
116
|
+
if (insertResult.insertId) {
|
|
117
|
+
console.log('✅ 数据插入成功,插入ID:', insertResult.insertId);
|
|
118
|
+
} else {
|
|
119
|
+
throw new Error('数据插入失败');
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// 测试查询数据
|
|
123
|
+
console.log('\n测试查询数据...');
|
|
124
|
+
const selectSql = `SELECT * FROM ${testTable} WHERE id = ?`;
|
|
125
|
+
const user = await mysql.run(selectSql, [insertResult.insertId]);
|
|
126
|
+
|
|
127
|
+
if (user && user.length > 0) {
|
|
128
|
+
console.log('✅ 数据查询成功');
|
|
129
|
+
console.log(' 查询结果:', user[0]);
|
|
130
|
+
} else {
|
|
131
|
+
throw new Error('数据查询失败');
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// 测试使用自定义主键
|
|
135
|
+
console.log('\n测试使用自定义主键...');
|
|
136
|
+
const customKeyTable = 'test_custom_key';
|
|
137
|
+
const customModel = {
|
|
138
|
+
fields: {
|
|
139
|
+
user_id: 'u001', // 自定义主键,会被设置为 INT AUTO_INCREMENT PRIMARY KEY
|
|
140
|
+
name: 'test', // 字符串
|
|
141
|
+
value: 100, // 整数
|
|
142
|
+
is_active: true, // boolean 类型
|
|
143
|
+
join_date: '2023-01-01' // date 类型
|
|
144
|
+
}
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
const customCreateResult = await db.createTable(customKeyTable, customModel, 'user_id', 15000);
|
|
148
|
+
if (customCreateResult || customCreateResult === 0) {
|
|
149
|
+
console.log('✅ 使用自定义主键创建表成功');
|
|
150
|
+
|
|
151
|
+
// 验证自定义主键表结构
|
|
152
|
+
const customDescribeSql = `DESCRIBE ${customKeyTable}`;
|
|
153
|
+
const customStructure = await mysql.run(customDescribeSql);
|
|
154
|
+
const customKeyField = customStructure.find(field => field.Field === 'user_id');
|
|
155
|
+
|
|
156
|
+
if (customKeyField && customKeyField.Key === 'PRI') {
|
|
157
|
+
console.log('✅ 自定义主键设置正确');
|
|
158
|
+
} else {
|
|
159
|
+
console.log('⚠️ 自定义主键可能未设置为 PRIMARY KEY');
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// 清理测试表
|
|
164
|
+
console.log('\n清理测试环境...');
|
|
165
|
+
await mysql.exec(`DROP TABLE IF EXISTS ${testTable}`);
|
|
166
|
+
await mysql.exec(`DROP TABLE IF EXISTS ${customKeyTable}`);
|
|
167
|
+
console.log('✅ 测试表已删除');
|
|
168
|
+
|
|
169
|
+
console.log('\n🎉 所有测试通过!createTable 方法功能正常');
|
|
170
|
+
|
|
171
|
+
} catch (error) {
|
|
172
|
+
console.error('❌ 测试失败:', error.message);
|
|
173
|
+
console.error('错误详情:', error);
|
|
174
|
+
return false;
|
|
175
|
+
} finally {
|
|
176
|
+
// 关闭连接
|
|
177
|
+
if (mysql) {
|
|
178
|
+
try {
|
|
179
|
+
await mysql.close();
|
|
180
|
+
console.log('✅ 数据库连接已关闭');
|
|
181
|
+
} catch (closeError) {
|
|
182
|
+
console.error('⚠️ 关闭数据库连接失败:', closeError.message);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
return true;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// 运行测试
|
|
191
|
+
testCreateTable().then(success => {
|
|
192
|
+
process.exit(success ? 0 : 1);
|
|
193
|
+
});
|