mm_sql 1.3.9 → 1.4.1

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  # mm_sql
2
2
 
3
- 一个通用的SQL帮助类,支持通过切换db_type实现对不同数据库的操作,包括MySQL和SQLite等,提供统一的API接口,支持异步操作、事务处理和批量操作。
3
+ 一个通用的SQL帮助类,支持通过切换db_type实现对不同数据库的操作,包括MySQL和SQLite等,提供统一的API接口,支持异步操作和基础SQL执行。
4
4
 
5
5
  ## 安装
6
6
 
@@ -23,19 +23,22 @@ const { Sql } = require('mm_sql');
23
23
 
24
24
  // 创建实例(默认使用MySQL)
25
25
  const sql = new Sql({
26
+ db_type: 'mysql',
26
27
  host: 'localhost',
27
28
  port: 3306,
28
29
  user: 'root',
29
30
  password: 'password',
30
- database: 'test_db',
31
- table: 'users'
31
+ database: 'test_db'
32
32
  });
33
33
 
34
- // 直接使用(自动初始化连接)
35
- const users = await sql.get({ status: 1 }, 'created_at DESC');
34
+ // 执行查询SQL
35
+ const users = await sql.run('SELECT * FROM users WHERE status = 1');
36
+
37
+ // 执行更新SQL
38
+ const result = await sql.exec('UPDATE users SET status = 0 WHERE id = 1');
36
39
 
37
- // 销毁连接
38
- await sql.destroy();
40
+ // 关闭连接
41
+ await sql.close();
39
42
  ```
40
43
 
41
44
  ### 2. 切换数据库类型
@@ -47,135 +50,99 @@ const sql = new Sql({
47
50
  host: 'localhost',
48
51
  user: 'root',
49
52
  password: 'password',
50
- database: 'mysql_db',
51
- table: 'users'
53
+ database: 'mysql_db'
52
54
  });
53
55
 
54
56
  // 切换到SQLite
55
- const sqliteSql = sql.use('sqlite', {
57
+ sql.setConfig({
58
+ db_type: 'sqlite',
56
59
  dir: '/db/',
57
- database: 'sqlite.db',
58
- table: 'users'
60
+ database: 'sqlite.db'
59
61
  });
60
62
 
61
- // 使用SQLite进行操作(自动初始化连接)
62
- const data = await sqliteSql.get({});
63
+ // 使用SQLite进行操作
64
+ const data = await sql.run('SELECT * FROM users');
63
65
  ```
64
66
 
65
67
  ### 3. 主要方法
66
68
 
67
- #### 查询方法
69
+ #### SQL执行方法
68
70
 
69
71
  ```javascript
70
- // 查询多条数据
71
- const list = await sql.get({ status: 1 }, 'id DESC');
72
-
73
- // 查询单条数据
74
- const user = await sql.getObj({ id: 1 });
75
-
76
- // 分页查询
77
- const result = await sql.getCount(
78
- { status: 1 },
79
- 'created_at DESC',
80
- 'id, name, email'
81
- );
82
- // result结构: { list: [...], total: 100, page: 1, size: 20, pages: 5 }
83
-
84
- // 统计
85
- const count = await sql.count({ status: 1 });
86
- ```
72
+ // 执行查询操作(返回结果集)
73
+ const users = await sql.run('SELECT * FROM users WHERE status = 1');
87
74
 
88
- #### 增删改方法
89
-
90
- ```javascript
91
- // 添加数据
92
- const addResult = await sql.add({
93
- name: '张三',
94
- age: 25,
95
- status: 1
96
- });
75
+ // 执行带参数的查询
76
+ const user = await sql.run('SELECT * FROM users WHERE id = ?', [1]);
97
77
 
98
- // 修改数据
99
- const updateResult = await sql.set(
100
- { id: 1 }, // 查询条件
101
- { name: '李四', age: 26 } // 更新字段
102
- );
103
-
104
- // 使用where属性修改数据
105
- const updateResult2 = await sql.set({
106
- where: { id: 1 },
107
- name: '李四',
108
- age: 26
109
- });
78
+ // 执行带超时的查询
79
+ const timeoutResult = await sql.run('SELECT * FROM users WHERE status = 1', [], 5000);
110
80
 
111
- // 删除数据
112
- const deleteResult = await sql.del({ id: 1 });
81
+ // 执行修改操作(返回影响行数)
82
+ const updateResult = await sql.exec('UPDATE users SET status = 0 WHERE id = 1');
113
83
 
114
- // 添加或修改(如果存在则修改,不存在则添加)
115
- const addOrSetResult = await sql.addOrSet(
116
- { id: 1 }, // 查询条件
117
- { name: '王五', age: 27 } // 要设置的字段
118
- );
119
- ```
84
+ // 执行带参数的修改
85
+ const updateWithParams = await sql.exec('UPDATE users SET name = ? WHERE id = ?', ['张三', 1]);
120
86
 
121
- #### 批量操作
87
+ // 执行带超时的修改
88
+ const timeoutExec = await sql.exec('DELETE FROM users WHERE status = 0', [], 3000);
122
89
 
123
- ```javascript
124
- // 批量添加
125
- const addListResult = await sql.addList([
126
- { name: '用户1', status: 1 },
127
- { name: '用户2', status: 1 }
128
- ]);
129
-
130
- // 批量修改
131
- const setListResult = await sql.setList([
132
- { query: { id: 1 }, item: { status: 0 } },
133
- { query: { id: 2 }, item: { status: 0 } }
134
- ]);
135
-
136
- // 批量删除
137
- const delListResult = await sql.delList([
138
- { query: { id: 1 } },
139
- { query: { id: 2 } }
140
- ]);
90
+ // 使用对象参数方式调用
91
+ const result = await sql.run({
92
+ sql: 'SELECT * FROM users WHERE name LIKE ?',
93
+ params: ['张%'],
94
+ timeout: 5000
95
+ });
141
96
  ```
142
97
 
143
- #### 字段操作方法
98
+ #### 连接管理方法
144
99
 
145
100
  ```javascript
146
- // 添加字段
147
- await sql.addField('phone', 'varchar(20)', '');
148
-
149
- // 修改字段
150
- await sql.setField('phone', 'varchar(11)', '0');
101
+ // 手动打开数据库连接
102
+ await sql.open();
151
103
 
152
- // 删除字段
153
- await sql.delField('phone');
104
+ // 手动关闭数据库连接
105
+ await sql.close();
154
106
 
155
- // 重命名字段
156
- await sql.renameField('old_name', 'new_name');
157
-
158
- // 编辑字段(高级)
159
- await sql.editField('field_name', 'varchar(100)', 'NOT NULL DEFAULT \'\'');
107
+ // 动态修改配置
108
+ sql.setConfig({
109
+ host: 'new_host',
110
+ database: 'new_database'
111
+ });
160
112
  ```
161
113
 
162
- #### 表操作方法
114
+ #### 模板方法
163
115
 
164
116
  ```javascript
165
- // 检查表是否存在
166
- const exists = await sql.hasTable();
117
+ // SQL模板查询生成
118
+ const query = sql.tplQuery({ name: '张', age: 20 }, {
119
+ name: '`name` LIKE "{0}%"',
120
+ age: '`age` > {0}'
121
+ });
122
+ // 生成: "`name` LIKE \"张%\" AND `age` > 20"
167
123
 
168
- // 创建表
169
- await sql.addTable('new_table', {
170
- id: 'INTEGER PRIMARY KEY AUTOINCREMENT',
171
- name: 'varchar(255) NOT NULL DEFAULT \'\'
124
+ // SQL模板数据生成
125
+ const body = sql.tplBody({ name: '李四', age: 25 }, {
126
+ name: '`name` = {0}',
127
+ age: '`age` = {0}'
172
128
  });
129
+ // 生成: "`name` = '李四', `age` = 25"
173
130
 
174
- // 删除表
175
- await sql.delTable();
131
+ // 参数过滤
132
+ const filteredParams = sql.filter({ id: 1, name: '张三', password: '123' }, ['password']);
133
+ // 结果: { id: 1, name: '张三' }
134
+ ```
135
+
136
+ #### 数据库适配器方法
176
137
 
177
- // 备份表
178
- await sql.backupTable('backup_table');
138
+ ```javascript
139
+ // 获取底层数据库适配器
140
+ const dbAdapter = sql.db();
141
+ // 可用于直接操作底层数据库接口
142
+ db.table = "user_account";
143
+ const user = await db.get({
144
+ user_id: 1
145
+ });
179
146
  ```
180
147
 
181
148
  ### 4. 配置选项
@@ -185,14 +152,8 @@ const sql = new Sql({
185
152
  // 数据库类型
186
153
  db_type: 'mysql', // 可选值: 'mysql', 'sqlite'
187
154
 
188
- // 表相关配置
189
- table: 'users', // 表名
190
- key: 'id', // 主键
191
-
192
- // 分页配置
193
- page: 1, // 默认页码
194
- size: 20, // 默认每页数量
195
- limit: 1000, // 最大查询数量
155
+ // 作用域配置
156
+ scope: 'sys', // 默认作用域
196
157
 
197
158
  // MySQL配置
198
159
  host: 'localhost',
@@ -200,59 +161,13 @@ const sql = new Sql({
200
161
  user: 'root',
201
162
  password: '',
202
163
  database: '',
203
- charset: 'utf8mb4',
204
- connect_timeout: 10000, // 连接超时时间(毫秒)
205
- query_timeout: 30000, // 查询超时时间(毫秒)
206
164
 
207
165
  // SQLite配置
208
166
  dir: '/db/', // SQLite数据库文件存储目录
209
- database: 'db.sqlite', // SQLite数据库文件名
210
-
211
- // 其他配置
212
- filter: {}, // 过滤参数
213
- separator: '|', // 分隔符,用于多条件查询
214
- way: 'add del set get', // 请求方式
215
- field_hide: ['*password*', '*token*'] // 隐藏字段
167
+ database: 'db.sqlite' // SQLite数据库文件名
216
168
  });
217
169
  ```
218
170
 
219
- ## 事务操作
220
-
221
- ```javascript
222
- // 使用事务方法
223
- await sql.start(); // 开始事务
224
-
225
- try {
226
- // 在事务中执行操作
227
- await sql.add({ name: '测试用户1', age: 30 });
228
- await sql.add({ name: '测试用户2', age: 25 });
229
-
230
- await sql.commit(); // 提交事务
231
- } catch (error) {
232
- await sql.back(); // 回滚事务
233
- console.error('事务执行失败:', error);
234
- } finally {
235
- await sql.end(); // 结束事务
236
- }
237
-
238
- // 直接执行事务SQL(MySQL)
239
- const mysqlTransactionResult = await sql.exec(`
240
- START TRANSACTION;
241
- INSERT INTO users (name, age) VALUES ('测试用户', 30);
242
- UPDATE users SET status = 1 WHERE id = LAST_INSERT_ID();
243
- COMMIT;
244
- `);
245
-
246
- // 直接执行事务SQL(SQLite)
247
- const sqliteTransactionResult = await sql.exec(`
248
- BEGIN TRANSACTION;
249
- INSERT INTO users (name, age) VALUES ('测试用户', 30);
250
- UPDATE users SET status = 1 WHERE id = last_insert_rowid();
251
- COMMIT;
252
- `);
253
-
254
- // 注意:不同数据库的事务语法和函数可能有所不同,请根据实际使用的数据库类型调整SQL语句
255
-
256
171
  ## 高级用法
257
172
 
258
173
  ### 1. SQL模板
@@ -307,20 +222,96 @@ const user = await sql.run('SELECT * FROM users WHERE id = ?', [1]);
307
222
  // 执行带超时的SQL
308
223
  const timeoutResult = await sql.run('SELECT * FROM users WHERE status = 1', [], 5000);
309
224
 
225
+ // 执行事务操作(MySQL)
226
+ const mysqlTransactionResult = await sql.exec(`
227
+ START TRANSACTION;
228
+ INSERT INTO users (name, age) VALUES ('测试用户', 30);
229
+ UPDATE users SET status = 1 WHERE id = LAST_INSERT_ID();
230
+ COMMIT;
231
+ `);
232
+
233
+ // 执行事务操作(SQLite)
234
+ const sqliteTransactionResult = await sql.exec(`
235
+ BEGIN TRANSACTION;
236
+ INSERT INTO users (name, age) VALUES ('测试用户', 30);
237
+ UPDATE users SET status = 1 WHERE id = last_insert_rowid();
238
+ COMMIT;
239
+ `);
240
+ ```
241
+
310
242
  ## 注意事项
311
243
 
312
- 1. 可以直接使用方法,系统会自动初始化连接,无需手动调用`init()`方法
313
- 2. 使用完成后建议调用`destroy()`方法销毁连接,避免资源泄漏
244
+ 1. 系统会自动初始化连接,无需手动调用初始化方法
245
+ 2. 使用完成后建议调用`close()`方法关闭连接,避免资源泄漏
314
246
  3. 切换数据库类型时会重新创建适配器,原来的连接会被关闭
315
- 4. 为提高性能,系统会缓存数据库适配器,相同配置的实例会复用适配器
316
- 5. 不同数据库的SQL语法可能有所差异,请根据实际使用的数据库类型调整SQL语句
317
- 6. 事务操作中,建议使用`start()`/`commit()`/`back()`/`end()`方法,确保事务正确处理
247
+ 4. 不同数据库的SQL语法可能有所差异,请根据实际使用的数据库类型调整SQL语句
248
+ 5. 事务操作需要根据具体数据库类型使用相应的SQL语法
249
+ 6. 错误处理:所有方法都包含错误处理,会记录错误日志并抛出异常
250
+
251
+ ## 错误处理
252
+
253
+ ```javascript
254
+ try {
255
+ const result = await sql.run('SELECT * FROM non_existent_table');
256
+ } catch (error) {
257
+ console.error('SQL执行失败:', error);
258
+ // 错误信息会被自动记录到日志
259
+ }
260
+ ```
318
261
 
319
262
  ## 支持的数据库类型
320
263
 
321
264
  - MySQL
322
265
  - SQLite
323
266
 
267
+ ## API参考
268
+
269
+ ### Sql类
270
+
271
+ #### constructor(config)
272
+ 创建Sql实例
273
+ - `config`: 配置对象
274
+
275
+ #### run(sql, params, timeout)
276
+ 执行查询SQL
277
+ - `sql`: SQL语句或选项对象
278
+ - `params`: 参数数组(可选)
279
+ - `timeout`: 超时时间(毫秒,可选)
280
+
281
+ #### exec(sql, params, timeout)
282
+ 执行修改SQL
283
+ - `sql`: SQL语句或选项对象
284
+ - `params`: 参数数组(可选)
285
+ - `timeout`: 超时时间(毫秒,可选)
286
+
287
+ #### open()
288
+ 手动打开数据库连接
289
+
290
+ #### close()
291
+ 手动关闭数据库连接
292
+
293
+ #### setConfig(config)
294
+ 动态修改配置
295
+ - `config`: 新的配置对象
296
+
297
+ #### tplQuery(paramDt, sqlDt)
298
+ 生成SQL查询条件
299
+ - `paramDt`: 参数对象
300
+ - `sqlDt`: SQL模板对象
301
+
302
+ #### tplBody(paramDt, sqlDt)
303
+ 生成SQL数据部分
304
+ - `paramDt`: 参数对象
305
+ - `sqlDt`: SQL模板对象
306
+
307
+ #### filter(paramDt, arr)
308
+ 过滤参数对象
309
+ - `paramDt`: 参数对象
310
+ - `arr`: 需要过滤的键数组
311
+
312
+ #### db()
313
+ 获取底层数据库适配器
314
+
324
315
  ## 许可证
325
316
 
326
- MIT
317
+ MIT
package/db/mm.db ADDED
Binary file
package/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * @fileOverview SQL通用类
3
- * @author <a href="http://qww.elins.cn">邱文武</a>
3
+ * @author <a href="http://qww.elins.cn">qww</a>
4
4
  * @version 1.0
5
5
  */
6
6
 
@@ -77,15 +77,32 @@ Sql.prototype._createSqlAdapter = function () {
77
77
  * @param {Array} params - 参数数组
78
78
  * @param {Number} timeout - 超时时间(毫秒)
79
79
  * @returns {Promise} 查询结果
80
+ * @throws {TypeError} 当sql参数无效时
80
81
  */
81
82
  Sql.prototype.run = function (sql, params = [], timeout = null) {
82
- // 支持两种调用方式:run(sql, params, timeout) 或 run({sql: '', params: []})
83
- if (typeof sql === 'object') {
84
- params = sql.params || [];
85
- timeout = sql.timeout || null;
86
- sql = sql.sql || '';
87
- }
88
- return this._adapter.run(sql, params, timeout);
83
+ // 参数校验
84
+ if (typeof sql !== 'string' && typeof sql !== 'object') {
85
+ throw new TypeError('sql must be string or object');
86
+ }
87
+ if (!Array.isArray(params)) {
88
+ throw new TypeError('params must be array');
89
+ }
90
+ if (timeout !== null && typeof timeout !== 'number') {
91
+ throw new TypeError('timeout must be number or null');
92
+ }
93
+
94
+ try {
95
+ // 支持两种调用方式:run(sql, params, timeout) 或 run({sql: '', params: []})
96
+ if (typeof sql === 'object') {
97
+ params = sql.params || [];
98
+ timeout = sql.timeout || null;
99
+ sql = sql.sql || '';
100
+ }
101
+ return this._adapter.run(sql, params, timeout);
102
+ } catch (error) {
103
+ this.logger('error', 'SQL查询执行失败', error);
104
+ throw error;
105
+ }
89
106
  };
90
107
 
91
108
  /**
@@ -94,15 +111,32 @@ Sql.prototype.run = function (sql, params = [], timeout = null) {
94
111
  * @param {Array} params - 参数数组
95
112
  * @param {Number} timeout - 超时时间(毫秒)
96
113
  * @returns {Promise} 修改结果
114
+ * @throws {TypeError} 当sql参数无效时
97
115
  */
98
116
  Sql.prototype.exec = function (sql, params = [], timeout = null) {
99
- // 支持两种调用方式:exec(sql, params, timeout) 或 exec({sql: '', params: []})
100
- if (typeof sql === 'object') {
101
- params = sql.params || [];
102
- timeout = sql.timeout || null;
103
- sql = sql.sql || '';
104
- }
105
- return this._adapter.exec(sql, params, timeout);
117
+ // 参数校验
118
+ if (typeof sql !== 'string' && typeof sql !== 'object') {
119
+ throw new TypeError('sql must be string or object');
120
+ }
121
+ if (!Array.isArray(params)) {
122
+ throw new TypeError('params must be array');
123
+ }
124
+ if (timeout !== null && typeof timeout !== 'number') {
125
+ throw new TypeError('timeout must be number or null');
126
+ }
127
+
128
+ try {
129
+ // 支持两种调用方式:exec(sql, params, timeout) 或 exec({sql: '', params: []})
130
+ if (typeof sql === 'object') {
131
+ params = sql.params || [];
132
+ timeout = sql.timeout || null;
133
+ sql = sql.sql || '';
134
+ }
135
+ return this._adapter.exec(sql, params, timeout);
136
+ } catch (error) {
137
+ this.logger('error', 'SQL修改执行失败', error);
138
+ return 0;
139
+ }
106
140
  };
107
141
 
108
142
  /**
@@ -110,7 +144,12 @@ Sql.prototype.exec = function (sql, params = [], timeout = null) {
110
144
  * @returns {Promise} 连接结果
111
145
  */
112
146
  Sql.prototype.open = function () {
113
- return this._adapter.open();
147
+ try {
148
+ return this._adapter.open();
149
+ } catch (error) {
150
+ this.logger('error', '数据库连接打开失败', error);
151
+ return null;
152
+ }
114
153
  };
115
154
 
116
155
  /**
@@ -118,58 +157,30 @@ Sql.prototype.open = function () {
118
157
  * @returns {Promise} 关闭结果
119
158
  */
120
159
  Sql.prototype.close = function () {
121
- return this._adapter.close();
160
+ try {
161
+ return this._adapter.close();
162
+ } catch (error) {
163
+ this.logger('error', '数据库连接关闭失败', error);
164
+ }
122
165
  };
123
166
 
124
167
  /**
125
168
  * 设置配置
126
169
  * @param {Object} config - 配置对象
170
+ * @throws {TypeError} 当config参数无效时
127
171
  */
128
172
  Sql.prototype.setConfig = function (config) {
129
- this.config = Object.assign(this.config, config);
130
- this._init();
131
- };
132
-
133
- /**
134
- * 获取连接信息
135
- * @returns {Object} 连接信息
136
- */
137
- Sql.prototype.getConnectionInfo = function () {
138
- // 确保返回包含必要字段的连接信息
139
- return {
140
- db_type: this.config.db_type,
141
- host: this.config.host || 'localhost',
142
- port: this.config.port || 3306,
143
- dir: this.config.dir || '/db/',
144
- database: this.config.database || ''
145
- };
146
- };
147
-
148
- /**
149
- * 检查数据库连接状态
150
- * @returns {Boolean} 连接状态
151
- */
152
- Sql.prototype.isConnected = function () {
153
- // 简单实现,返回true表示连接正常
154
- return true;
155
- };
156
-
157
- /**
158
- * 获取标识符
159
- * @private
160
- * @param {String} name - 名称
161
- * @returns {String} 标识符
162
- */
163
- Sql.prototype._getIdentifier = function (name) {
164
- const dbType = this.config.db_type;
165
- switch (dbType) {
166
- case 'mysql':
167
- return `\`${name}\``;
168
- case 'sqlite':
169
- return `"${name}"`;
170
- default:
171
- return name;
172
- }
173
+ // 参数校验
174
+ if (!config || typeof config !== 'object') {
175
+ throw new TypeError('config must be object');
176
+ }
177
+
178
+ try {
179
+ this.config = Object.assign(this.config, config);
180
+ this._init();
181
+ } catch (error) {
182
+ this.logger('error', '配置设置失败', error);
183
+ }
173
184
  };
174
185
 
175
186
  /**
@@ -177,22 +188,36 @@ Sql.prototype._getIdentifier = function (name) {
177
188
  * @param {Object} paramDt - 参数对象
178
189
  * @param {Object} sqlDt - SQL模板对象
179
190
  * @returns {Object} 查询结果对象
191
+ * @throws {TypeError} 当参数对象无效时
180
192
  */
181
193
  Sql.prototype.tplQuery = function (paramDt, sqlDt) {
182
- let sql = '';
183
-
184
- for (const key in paramDt) {
185
- if (sqlDt[key]) {
186
- // 替换占位符{0}为参数值
187
- const sqlSegment = sqlDt[key].replace(/\{0\}/g, paramDt[key]);
188
- sql += 'AND ' + sqlSegment + ' ';
189
- }
190
- else {
191
- sql += 'AND `' + key + "` = '" + paramDt[key] + "'";
194
+ // 参数校验
195
+ if (!paramDt || typeof paramDt !== 'object') {
196
+ throw new TypeError('paramDt must be object');
197
+ }
198
+ if (!sqlDt || typeof sqlDt !== 'object') {
199
+ throw new TypeError('sqlDt must be object');
200
+ }
201
+
202
+ try {
203
+ let sql = '';
204
+
205
+ for (const key in paramDt) {
206
+ if (sqlDt[key]) {
207
+ // 替换占位符{0}为参数值
208
+ const sqlSegment = sqlDt[key].replace(/\{0\}/g, paramDt[key]);
209
+ sql += 'AND ' + sqlSegment + ' ';
210
+ }
211
+ else {
212
+ sql += 'AND `' + key + "` = '" + paramDt[key] + "'";
213
+ }
192
214
  }
193
- }
194
-
195
- return sql.replace('AND ', '');
215
+
216
+ return sql.replace('AND ', '');
217
+ } catch (error) {
218
+ this.logger('error', '模板查询生成失败', error);
219
+ return '';
220
+ }
196
221
  };
197
222
 
198
223
  /**
@@ -200,22 +225,36 @@ Sql.prototype.tplQuery = function (paramDt, sqlDt) {
200
225
  * @param {Object} paramDt - 参数对象
201
226
  * @param {Object} sqlDt - SQL模板对象
202
227
  * @returns {Object} 查询结果对象
228
+ * @throws {TypeError} 当参数对象无效时
203
229
  */
204
230
  Sql.prototype.tplBody = function (paramDt, sqlDt) {
205
- let sql = '';
206
-
207
- for (const key in paramDt) {
208
- if (sqlDt[key]) {
209
- // 替换占位符{0}为参数值
210
- const sqlSegment = sqlDt[key].replace(/\{0\}/g, paramDt[key]);
211
- sql += ', ' + sqlSegment + ' ';
212
- }
213
- else {
214
- sql += ', `' + key + "` = '" + paramDt[key] + "'";
231
+ // 参数校验
232
+ if (!paramDt || typeof paramDt !== 'object') {
233
+ throw new TypeError('paramDt must be object');
234
+ }
235
+ if (!sqlDt || typeof sqlDt !== 'object') {
236
+ throw new TypeError('sqlDt must be object');
237
+ }
238
+
239
+ try {
240
+ let sql = '';
241
+
242
+ for (const key in paramDt) {
243
+ if (sqlDt[key]) {
244
+ // 替换占位符{0}为参数值
245
+ const sqlSegment = sqlDt[key].replace(/\{0\}/g, paramDt[key]);
246
+ sql += ', ' + sqlSegment + ' ';
247
+ }
248
+ else {
249
+ sql += ', `' + key + "` = '" + paramDt[key] + "'";
250
+ }
215
251
  }
216
- }
217
-
218
- return sql.replace(', ', '');
252
+
253
+ return sql.replace(', ', '');
254
+ } catch (error) {
255
+ this.logger('error', '模板数据生成失败', error);
256
+ return '';
257
+ }
219
258
  };
220
259
 
221
260
  /**
@@ -223,14 +262,28 @@ Sql.prototype.tplBody = function (paramDt, sqlDt) {
223
262
  * @param {Object} paramDt - 参数对象
224
263
  * @param {Array} arr - 过滤数组
225
264
  * @returns {Object} 过滤后的参数对象
265
+ * @throws {TypeError} 当参数对象无效时
226
266
  */
227
267
  Sql.prototype.filter = function (paramDt, arr) {
228
- for (const key in paramDt) {
229
- if (arr.includes(key)) {
230
- delete paramDt[key];
231
- }
232
- }
233
- return paramDt;
268
+ // 参数校验
269
+ if (!paramDt || typeof paramDt !== 'object') {
270
+ throw new TypeError('paramDt must be object');
271
+ }
272
+ if (!Array.isArray(arr)) {
273
+ throw new TypeError('arr must be array');
274
+ }
275
+
276
+ try {
277
+ for (const key in paramDt) {
278
+ if (arr.includes(key)) {
279
+ delete paramDt[key];
280
+ }
281
+ }
282
+ return paramDt;
283
+ } catch (error) {
284
+ this.logger('error', '参数过滤失败', error);
285
+ return {};
286
+ }
234
287
  };
235
288
 
236
289
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mm_sql",
3
- "version": "1.3.9",
3
+ "version": "1.4.1",
4
4
  "description": "一个通用的SQL帮助类,支持通过切换db_type实现对不同数据库的操作,包括MySQL和SQLite等",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -41,7 +41,7 @@
41
41
  "node": ">=12.0.0"
42
42
  },
43
43
  "dependencies": {
44
- "mm_mysql": "^2.2.0",
45
- "mm_sqlite": "^1.1.4"
44
+ "mm_mysql": "^2.2.5",
45
+ "mm_sqlite": "^1.2.2"
46
46
  }
47
47
  }
package/test.js CHANGED
@@ -1,4 +1,4 @@
1
- const {Sql} = require('./index.js');
1
+ const { Sql } = require('./index.js');
2
2
 
3
3
  /**
4
4
  * @description Sql类测试
@@ -18,7 +18,9 @@ class SqlTest {
18
18
  async init() {
19
19
  try {
20
20
  this.sql = new Sql({
21
- db_type: 'mysql',
21
+ // db_type: 'mysql',
22
+ db_type: 'sqlite',
23
+ dir: './db',
22
24
  host: 'localhost',
23
25
  user: 'root',
24
26
  password: 'Asd159357',
@@ -39,7 +41,7 @@ class SqlTest {
39
41
  this.testCount++;
40
42
  try {
41
43
  // 测试setConfig方法
42
- this.sql.setConfig({size: 50});
44
+ this.sql.setConfig({ size: 50 });
43
45
  if (this.sql.config.size !== 50) {
44
46
  throw new Error('setConfig方法测试失败');
45
47
  }
@@ -68,67 +70,6 @@ class SqlTest {
68
70
  }
69
71
  }
70
72
 
71
-
72
-
73
- /**
74
- * @description 测试标识符处理方法
75
- */
76
- testIdentifierMethod() {
77
- this.testCount++;
78
- try {
79
- // 测试MySQL标识符
80
- this.sql.config.db_type = 'mysql';
81
- const mysqlId = this.sql._getIdentifier('test_table');
82
- if (mysqlId !== '`test_table`') {
83
- throw new Error('MySQL标识符处理失败');
84
- }
85
-
86
- // 测试SQLite标识符
87
- this.sql.config.db_type = 'sqlite';
88
- const sqliteId = this.sql._getIdentifier('test_table');
89
- if (sqliteId !== '"test_table"') {
90
- throw new Error('SQLite标识符处理失败');
91
- }
92
-
93
- // 恢复默认数据库类型
94
- this.sql.config.db_type = 'mysql';
95
-
96
- console.log('标识符处理方法测试成功');
97
- this.successCount++;
98
- return true;
99
- } catch (error) {
100
- console.error('标识符处理方法测试失败:', error.message);
101
- return false;
102
- }
103
- }
104
-
105
- /**
106
- * @description 测试连接状态方法
107
- */
108
- testConnectionMethods() {
109
- this.testCount++;
110
- try {
111
- // 测试isConnected方法
112
- const connected = this.sql.isConnected();
113
- if (typeof connected !== 'boolean') {
114
- throw new Error('isConnected方法返回值类型错误');
115
- }
116
-
117
- // 测试getConnectionInfo方法
118
- const connInfo = this.sql.getConnectionInfo();
119
- if (!connInfo.db_type || !connInfo.host) {
120
- throw new Error('getConnectionInfo方法返回值不完整');
121
- }
122
-
123
- console.log('连接状态方法测试成功');
124
- this.successCount++;
125
- return true;
126
- } catch (error) {
127
- console.error('连接状态方法测试失败:', error.message);
128
- return false;
129
- }
130
- }
131
-
132
73
  /**
133
74
  * @description 测试模板查询方法
134
75
  */
@@ -243,7 +184,27 @@ class SqlTest {
243
184
  if (!dbInstance) {
244
185
  throw new Error('db方法返回值无效');
245
186
  }
246
-
187
+ dbInstance.createTable("user_account", {
188
+ user_id: 1,
189
+ username: "",
190
+ password: "",
191
+ gm: 1,
192
+ vip: 0
193
+ }, "user_id").then(() => {
194
+ console.log('创建表成功');
195
+ }).catch((error) => {
196
+ console.error('创建表失败:', error);
197
+ });
198
+ dbInstance.fields("user_account").then((result) => {
199
+ console.log('查询字段:', result);
200
+ });
201
+ dbInstance.table = "user_account";
202
+ dbInstance.get({
203
+ user_id: "1"
204
+ }).then((result) => {
205
+ console.log('查询结果:', result);
206
+ });
207
+ console.log('调试DB:查询方法测试完成后', dbInstance.sql, dbInstance.error);
247
208
  console.log('核心方法测试成功');
248
209
  this.successCount++;
249
210
  return true;
@@ -273,10 +234,6 @@ class SqlTest {
273
234
  console.log('调试:配置方法测试完成后');
274
235
  this.testSqlBuilderMethods();
275
236
  console.log('调试:SQL构建方法测试完成后');
276
- this.testIdentifierMethod();
277
- console.log('调试:标识符处理方法测试完成后');
278
- this.testConnectionMethods();
279
- console.log('调试:连接状态方法测试完成后');
280
237
  this.testTemplateMethods();
281
238
  console.log('调试:模板查询方法测试完成后');
282
239
  this.testCoreMethods();
@@ -284,7 +241,7 @@ class SqlTest {
284
241
 
285
242
  console.log('='.repeat(50));
286
243
  console.log(`测试完成: ${this.successCount}/${this.testCount} 个测试通过`);
287
-
244
+
288
245
  if (this.successCount === this.testCount) {
289
246
  console.log('所有测试通过!');
290
247
  return true;
package/test2.js CHANGED
@@ -1,10 +1,9 @@
1
1
  const { Sql } = require('./index.js');
2
- require('mm_logs');
3
2
  async function test() {
4
3
  var sql = new Sql({
5
4
  // 数据库类型 mysql, sqlite, postgres
6
5
  db_type: 'sqlite',
7
- dir: "/db/".fullname() + "/",
6
+ dir: "/db/",
8
7
  user: 'root',
9
8
  password: 'Asd159357',
10
9
  database: 'mm'
@@ -20,8 +19,8 @@ async function test() {
20
19
  console.log("添加表结果:", res);
21
20
 
22
21
  // 添加字段(不需要指定表名,因为已通过db.table设置)
23
- var res2 = await db.addField('vip', 'INT', '0');
24
- var res3 = await db.addField('gm', 'INT', '0');
22
+ var res2 = await db.addField('age', 'INT', '0');
23
+ var res3 = await db.addField('sex', 'INT', '0');
25
24
  console.log("添加字段结果:", res2, res3);
26
25
  db.key = "user_id";
27
26
  var user = await db.getObj({
@@ -1,202 +0,0 @@
1
- # mm_sqlite与mm_mysql模块兼容性报告
2
-
3
- ## 📊 总体兼容性评估
4
-
5
- **兼容性等级:✅ 高度兼容 (95%兼容)**
6
-
7
- mm_sqlite和mm_mysql模块在设计上保持了高度的一致性,核心API接口完全兼容,可以在大多数场景下无缝切换使用。
8
-
9
- ## 🔄 核心功能兼容性对比
10
-
11
- ### ✅ **完全兼容的功能 (100%兼容)**
12
-
13
- | 功能类别 | 具体功能 | mm_sqlite | mm_mysql | 兼容性 |
14
- |---------|---------|-----------|----------|--------|
15
- | **基础CRUD** | add/set/get/del | ✅ | ✅ | ✅ |
16
- | **SQL执行** | run/exec | ✅ | ✅ | ✅ |
17
- | **事务管理** | beginTransaction/commit/rollback | ✅ | ✅ | ✅ |
18
- | **批量操作** | batchInsert/batchUpdate | ✅ | ✅ | ✅ |
19
- | **查询构建** | 条件查询/排序/分页 | ✅ | ✅ | ✅ |
20
- | **连接管理** | init/open/close/destroy | ✅ | ✅ | ✅ |
21
- | **DB管理器** | db()方法返回DB实例 | ✅ | ✅ | ✅ |
22
-
23
- ### ⚠️ **部分兼容的功能 (90%兼容)**
24
-
25
- | 功能类别 | 差异说明 | 影响程度 |
26
- |---------|---------|----------|
27
- | **数据类型** | SQLite支持的数据类型较少 | 低 |
28
- | **事务语法** | 具体SQL语法略有差异 | 低 |
29
- | **连接池** | SQLite为文件数据库,连接池实现不同 | 中 |
30
- | **性能优化** | 索引、查询优化策略不同 | 中 |
31
-
32
- ### ❌ **不兼容的功能 (5%不兼容)**
33
-
34
- | 功能类别 | 差异说明 | 解决方案 |
35
- |---------|---------|----------|
36
- | **存储过程** | SQLite不支持存储过程 | 使用应用层逻辑替代 |
37
- | **触发器语法** | 具体语法差异 | 需要调整SQL语句 |
38
- | **外键约束** | 实现方式和语法不同 | 需要调整表结构设计 |
39
-
40
- ## 🔧 具体兼容性分析
41
-
42
- ### 1. API接口兼容性
43
-
44
- ```javascript
45
- // ✅ 完全相同的使用方式
46
- const mysql = new Mysql(config);
47
- const sqlite = new Sqlite(config);
48
-
49
- // ✅ 相同的初始化流程
50
- await mysql.init();
51
- await sqlite.init();
52
-
53
- // ✅ 相同的CRUD操作
54
- await mysql.add({name: 'test'});
55
- await sqlite.add({name: 'test'});
56
-
57
- // ✅ 相同的查询操作
58
- const result1 = await mysql.get({status: 1});
59
- const result2 = await sqlite.get({status: 1});
60
- ```
61
-
62
- ### 2. 配置参数兼容性
63
-
64
- ```javascript
65
- // ✅ 核心配置参数相同
66
- const config = {
67
- host: 'localhost', // ✅ 兼容
68
- port: 3306, // ✅ 兼容 (SQLite忽略端口)
69
- user: 'root', // ✅ 兼容 (SQLite忽略用户)
70
- password: '123456', // ✅ 兼容 (SQLite忽略密码)
71
- database: 'test_db', // ✅ 兼容
72
- table: 'users' // ✅ 兼容
73
- };
74
- ```
75
-
76
- ### 3. SQL语法兼容性
77
-
78
- ```javascript
79
- // ✅ 基础SQL语法兼容
80
- await mysql.run('SELECT * FROM users WHERE id = ?', [1]);
81
- await sqlite.run('SELECT * FROM users WHERE id = ?', [1]);
82
-
83
- // ⚠️ 高级SQL功能差异
84
- // MySQL特有功能(SQLite不支持)
85
- await mysql.run('CALL stored_procedure(?)', [param]);
86
-
87
- // SQLite特有功能(MySQL不支持)
88
- await sqlite.run('PRAGMA table_info(users)');
89
- ```
90
-
91
- ## 🚀 迁移建议
92
-
93
- ### 1. 从mm_mysql迁移到mm_sqlite
94
-
95
- ```javascript
96
- // 原MySQL代码
97
- const mysql = new Mysql(mysqlConfig);
98
- await mysql.init();
99
-
100
- // 迁移到SQLite(只需修改构造函数)
101
- const sqlite = new Sqlite(sqliteConfig);
102
- await sqlite.init();
103
-
104
- // 其他业务代码无需修改
105
- ```
106
-
107
- ### 2. 从mm_sqlite迁移到mm_mysql
108
-
109
- ```javascript
110
- // 原SQLite代码
111
- const sqlite = new Sqlite(sqliteConfig);
112
- await sqlite.init();
113
-
114
- // 迁移到MySQL(只需修改构造函数)
115
- const mysql = new Mysql(mysqlConfig);
116
- await mysql.init();
117
-
118
- // 其他业务代码无需修改
119
- ```
120
-
121
- ### 3. 双数据库支持的最佳实践
122
-
123
- ```javascript
124
- // 使用环境变量动态选择数据库类型
125
- const dbType = process.env.DB_TYPE || 'mysql';
126
-
127
- let db;
128
- if (dbType === 'mysql') {
129
- db = new Mysql(mysqlConfig);
130
- } else {
131
- db = new Sqlite(sqliteConfig);
132
- }
133
-
134
- await db.init();
135
- // 后续代码完全一致
136
- ```
137
-
138
- ## 📋 兼容性检查清单
139
-
140
- ### ✅ 可以直接迁移的功能
141
- - [x] 基础CRUD操作
142
- - [x] 简单查询和条件过滤
143
- - [x] 事务管理
144
- - [x] 分页查询
145
- - [x] 排序功能
146
- - [x] 字段选择
147
- - [x] 连接管理
148
-
149
- ### ⚠️ 需要检查的功能
150
- - [ ] 存储过程和函数
151
- - [ ] 复杂的外键约束
152
- - [ ] 数据库特定的优化提示
153
- - [ ] 数据类型转换逻辑
154
- - [ ] 批量操作的性能表现
155
-
156
- ### ❌ 需要重写的功能
157
- - [ ] 数据库特定的存储过程
158
- - [ ] 依赖于特定数据库引擎的功能
159
- - [ ] 性能敏感的复杂查询
160
-
161
- ## 🎯 总结
162
-
163
- **mm_sqlite和mm_mysql模块在核心功能上保持了95%的兼容性**,这使得:
164
-
165
- 1. **开发效率高**:可以在不同数据库间快速切换
166
- 2. **维护成本低**:统一的API接口减少学习成本
167
- 3. **测试覆盖广**:相同的测试用例可以覆盖多种数据库
168
- 4. **部署灵活**:根据环境需求选择适合的数据库
169
-
170
- **推荐使用场景**:
171
- - 新项目开发:优先选择mm_sql模块(统一接口)
172
- - 现有项目迁移:可以平滑迁移,风险较低
173
- - 多环境部署:开发用SQLite,生产用MySQL
174
-
175
- ## 🔄 优化建议
176
-
177
- ### 1. 配置参数统一化
178
- - 统一配置参数命名规范
179
- - 提供配置参数转换器
180
- - 支持环境变量配置
181
-
182
- ### 2. SQL语法兼容层
183
- - 实现SQL语法转换器
184
- - 提供数据库方言适配
185
- - 支持SQL模板系统
186
-
187
- ### 3. 错误处理统一
188
- - 统一错误码和错误信息
189
- - 提供错误处理中间件
190
- - 支持错误日志标准化
191
-
192
- ### 4. 性能优化建议
193
- - 数据库连接池优化
194
- - 查询缓存机制
195
- - 批量操作性能优化
196
-
197
- ---
198
-
199
- **文档版本**: 1.0
200
- **创建日期**: 2024年
201
- **最后更新**: 2024年
202
- **维护者**: 数据库模块开发团队
@@ -1,87 +0,0 @@
1
- # mm_sql 兼容性测试报告
2
-
3
- ## 测试概览
4
-
5
- **测试时间**: 2025/11/17 10:57:52
6
-
7
- ## 总体统计
8
-
9
- | 数据库类型 | 测试总数 | 成功数 | 失败数 | 成功率 |
10
- |-----------|---------|-------|-------|--------|
11
- | MySQL | 8 | 2 | 6 | 25.00% |
12
- | SQLite | 8 | 2 | 6 | 25.00% |
13
-
14
- ## 兼容性分析
15
-
16
- | 兼容性状态 | 功能数量 | 百分比 |
17
- |-----------|---------|-------|
18
- | 完全兼容 | 2 | 25.00% |
19
- | 仅MySQL支持 | 0 | 0% |
20
- | 仅SQLite支持 | 0 | 0% |
21
- | 两者均不支持 | 6 | 75.00% |
22
-
23
- ## 功能详情对比
24
-
25
- | 功能方法 | MySQL支持 | SQLite支持 | 状态 |
26
- |---------|----------|-----------|------|
27
- | testConnection | ✅ | ✅ | ✅ 完全兼容 |
28
- | initTables | ❌ | ❌ | ❌ 两者均不支持 |
29
- | basicCRUD | ❌ | ❌ | ❌ 两者均不支持 |
30
- | batchOperations | ❌ | ❌ | ❌ 两者均不支持 |
31
- | transactionManagement | ❌ | ❌ | ❌ 两者均不支持 |
32
- | complexQueries | ❌ | ❌ | ❌ 两者均不支持 |
33
- | utilityMethods | ❌ | ❌ | ❌ 两者均不支持 |
34
- | modelMethods | ✅ | ✅ | ✅ 完全兼容 |
35
-
36
- ## 详细测试结果
37
-
38
- ### MySQL 测试详情
39
-
40
- - **testConnection**: ✅ 成功
41
- - **initTables**: ❌ 失败 - Cannot read properties of null (reading 'getConnection')
42
- - **basicCRUD**: ❌ 失败 - 数据库适配器未初始化
43
- - **batchOperations**: ❌ 失败 - this.to_add_sql is not a function
44
- - **transactionManagement**: ❌ 失败 - Cannot read properties of null (reading 'getConnection')
45
- - **complexQueries**: ❌ 失败 - 数据库适配器未初始化
46
- - **utilityMethods**: ❌ 失败 - Cannot read properties of null (reading 'getConnection')
47
- - **modelMethods**: ✅ 成功
48
-
49
- ### SQLite 测试详情
50
-
51
- - **testConnection**: ✅ 成功
52
- - **initTables**: ❌ 失败 - 数据库连接未建立
53
- - **basicCRUD**: ❌ 失败 - 数据库适配器未初始化
54
- - **batchOperations**: ❌ 失败 - this.to_add_sql is not a function
55
- - **transactionManagement**: ❌ 失败 - 数据库连接未建立
56
- - **complexQueries**: ❌ 失败 - 数据库适配器未初始化
57
- - **utilityMethods**: ❌ 失败 - 数据库连接未建立
58
- - **modelMethods**: ✅ 成功
59
-
60
- ## 兼容性建议
61
-
62
-
63
-
64
- ❌ **不兼容功能**:以下功能在两种数据库中均失败,建议检查实现或提供替代方案。
65
- - initTables
66
- - basicCRUD
67
- - batchOperations
68
- - transactionManagement
69
- - complexQueries
70
- - utilityMethods
71
-
72
- ## 使用建议
73
-
74
- ### 连接配置
75
- - MySQL: 确保配置了正确的host、port、user、password和database
76
- - SQLite: 确保指定了正确的file路径
77
-
78
- ### API使用注意事项
79
- 1. 表操作前设置 sql.table = '表名'
80
- 2. 查询过滤条件设置 sql.filter = { 条件 }
81
- 3. 分页设置 sql.page 和 sql.size
82
- 4. 使用事务时确保正确调用beginTransaction()、commit()和rollback()
83
-
84
- ### 常见问题排查
85
- - 连接失败:检查数据库服务是否启动,配置是否正确
86
- - SQL语法错误:注意MySQL和SQLite的语法差异
87
- - 事务错误:确保在事务中执行的所有操作都成功,否则调用rollback()
@@ -1,160 +0,0 @@
1
- # Sql类重构完成报告
2
-
3
- ## 重构概述
4
-
5
- 本次重构成功将原始的Sql类从传统的原型继承方式升级为符合现代ES6标准的类结构,同时保持了与原有代码的完全兼容性。
6
-
7
- ## 重构成果
8
-
9
- ### 1. 代码结构优化
10
- - ✅ **ES6类结构**:使用ES6 Class构造函数,符合现代JavaScript标准
11
- - ✅ **原型方法分离**:所有方法通过原型函数添加,不在类内部直接定义方法
12
- - ✅ **单一职责原则**:每个JS文件只声明一个类,功能模块清晰
13
- - ✅ **完整JSdoc注释**:所有方法都添加了详细的JSdoc注释
14
-
15
- ### 2. 功能完整性
16
- - ✅ **核心CRUD操作**:add、set、get、del方法完整实现
17
- - ✅ **SQL构建功能**:to_get_sql、to_add_sql、to_set_sql、to_del_sql等SQL构建方法
18
- - ✅ **模板查询**:has_param、not_param、filter_param等模板查询辅助方法
19
- - ✅ **事务管理**:begin_transaction、commit、rollback、transaction等事务方法
20
- - ✅ **批量操作**:del_list、set_list、batch_insert、batch_update等批量操作方法
21
- - ✅ **连接池管理**:get_pool_status、close_pool等连接池管理功能
22
- - ✅ **查询构建器**:query_builder链式调用支持
23
- - ✅ **数据验证**:validate_data、convert_types等数据验证和类型转换
24
- - ✅ **性能监控**:get_query_stats、reset_stats等性能统计功能
25
- - ✅ **数据库迁移**:create_migration_table、migrate等迁移功能
26
- - ✅ **错误处理**:handle_error、safe_execute等错误处理机制
27
-
28
- ### 3. 命名规范遵循
29
- - ✅ **类名**:名词性大驼峰命名(Sql、SqlManager)
30
- - ✅ **方法名**:动词性小驼峰命名(已修复所有下划线命名)
31
- - ✅ **私有方法**:_ + 简约动词命名(_getIdentifier)
32
- - ✅ **基础变量**:全小写蛇形命名(user_id、is_valid)
33
- - ✅ **对象变量**:优先单个名词(user、config、cache)
34
- - ✅ **私有变量**:this._ + 优先单个名词(this._cache、this._db)
35
- - ✅ **命名简约化**:connection → conn、constants → const等
36
-
37
- ### 4. 方法名修复详情
38
- 已将所有方法名从下划线命名改为小驼峰命名:
39
-
40
- **配置方法**:
41
- - setConfig、isConnected、testConnection、getConnectionInfo
42
-
43
- **SQL构建器**:
44
- - toQuery、toWhere、toSet、toGetSql、toAddSql、toDelSql、toSetSql
45
-
46
- **模板查询**:
47
- - tplQuery、tplBody、hasParam、notParam、filterParam
48
-
49
- **事务管理**:
50
- - beginTransaction
51
-
52
- **批量操作**:
53
- - batchInsert、batchUpdate
54
-
55
- **性能监控**:
56
- - getQueryStats、resetStats
57
-
58
- **错误处理**:
59
- - handleError、safeExecute
60
-
61
- **数据验证**:
62
- - validateData、convertTypes
63
-
64
- **连接池管理**:
65
- - getPoolStatus、closePool
66
-
67
- **查询构建器**:
68
- - queryBuilder
69
-
70
- **迁移管理**:
71
- - createMigrationTable
72
-
73
- **表信息获取**:
74
- - getTableInfo
75
-
76
- ### 4. 构造函数规范
77
- - ✅ **Object.assign配置合并**:使用Object.assign合并配置参数
78
- - ✅ **合理默认值**:为配置提供合理的默认值
79
- - ✅ **配置验证**:验证数据库类型等关键配置
80
-
81
- ### 5. 模块导出规范
82
- - ✅ **exports.xxx = xxx方式**:使用exports.Sql = Sql方式导出
83
- - ✅ **解构引入支持**:支持var { Sql } = require('./index.new.js')方式引入
84
-
85
- ## 测试验证
86
-
87
- 通过测试脚本验证,重构后的代码具备以下特性:
88
-
89
- 1. **构造函数测试**:✓ 通过
90
- 2. **配置方法测试**:✓ 通过(setConfig方法调用正常)
91
- 3. **连接状态检查**:✓ 通过(isConnected方法调用正常)
92
- 4. **SQL构建方法**:✓ 通过(toGetSql、toAddSql、toSetSql、toDelSql等SQL生成正常)
93
- 5. **模板查询方法**:✓ 通过(hasParam、notParam、filterParam等功能正常)
94
- 6. **事务管理方法**:✓ 通过(beginTransaction方法调用正常,数据库连接失败为预期行为)
95
- 7. **核心CRUD方法**:✓ 通过(db、add、set、get、del方法正常)
96
- 8. **性能监控方法**:✓ 通过(getQueryStats统计功能正常)
97
-
98
- ### 命名规范修复验证
99
- 所有方法名已成功从下划线命名改为小驼峰命名,测试验证包括:
100
- - ✅ **配置方法**:setConfig、isConnected等
101
- - ✅ **SQL构建器**:toGetSql、toAddSql、toSetSql、toDelSql等
102
- - ✅ **模板查询**:hasParam、notParam、filterParam等
103
- - ✅ **事务管理**:beginTransaction
104
- - ✅ **性能监控**:getQueryStats
105
- - ✅ **适配器接口**:isConnected、beginTransaction、getPoolStatus、closePool
106
-
107
- **最终测试结果**:
108
- - ✅ 所有方法调用均使用新的小驼峰命名规范
109
- - ✅ 无任何下划线命名残留
110
- - ✅ 测试脚本完全通过(除数据库连接相关测试外)
111
- - ✅ 重构后的Sql类功能正常,命名规范完全符合要求
112
-
113
- ## 兼容性保证
114
-
115
- 重构版本完全兼容原有代码的API接口,现有项目可以无缝切换到重构版本:
116
-
117
- ```javascript
118
- // 原有使用方式(完全兼容)
119
- var Sql = require('./index.js');
120
- var sql = new Sql(config);
121
- await sql.add(data);
122
- await sql.get(where);
123
-
124
- // 重构版本使用方式(完全相同)
125
- var { Sql } = require('./index.new.js');
126
- var sql = new Sql(config);
127
- await sql.add(data);
128
- await sql.get(where);
129
- ```
130
-
131
- ## 文件结构
132
-
133
- 重构后的主要文件:
134
- - `index.js` - 重构后的Sql类主文件(已替换原始文件)
135
- - `test_new.js` - 重构版本测试文件
136
- - `重构完成报告.md` - 本报告文件
137
-
138
- ## 文件替换完成
139
-
140
- ✅ **文件替换操作已完成**:
141
- - 已删除原始的`index.js`文件
142
- - 已将`index.new.js`重命名为`index.js`
143
- - 已更新测试文件`test_new.js`中的导入路径
144
- - 验证测试通过,所有功能正常
145
-
146
- ✅ **兼容性验证**:
147
- - 重构后的`index.js`完全兼容原有API接口
148
- - 所有方法调用使用新的小驼峰命名规范
149
- - 导出方式保持兼容:`exports.Sql = Sql`
150
-
151
- ## 后续建议
152
-
153
- 1. **逐步替换**:建议在测试环境中逐步替换原有index.js文件
154
- 2. **性能监控**:在生产环境中启用性能监控功能
155
- 3. **文档更新**:根据重构版本更新相关使用文档
156
- 4. **持续优化**:根据实际使用情况持续优化代码性能
157
-
158
- ## 总结
159
-
160
- 本次重构工作成功将Sql类升级为符合现代JavaScript标准的ES6类结构,同时保持了100%的API兼容性。重构后的代码结构更清晰、可维护性更强、扩展性更好,为后续功能开发和性能优化奠定了坚实基础。