mm_sqlite 1.1.2 → 1.1.4
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/LICENSE +21 -201
- package/README.md +52 -21
- package/db.js +37 -0
- package/index.js +72 -67
- package/package.json +2 -2
- package/config.json +0 -8
- package/db/db/test_db_methods.db.db +0 -0
- package/db/mm.db +0 -0
- package/test.js +0 -81
- package/test_all_methods.js +0 -115
- package/test_db_methods.js +0 -262
package/LICENSE
CHANGED
|
@@ -1,201 +1,21 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
"You" (or "Your") shall mean an individual or Legal Entity
|
|
24
|
-
exercising permissions granted by this License.
|
|
25
|
-
|
|
26
|
-
"Source" form shall mean the preferred form for making modifications,
|
|
27
|
-
including but not limited to software source code, documentation
|
|
28
|
-
source, and configuration files.
|
|
29
|
-
|
|
30
|
-
"Object" form shall mean any form resulting from mechanical
|
|
31
|
-
transformation or translation of a Source form, including but
|
|
32
|
-
not limited to compiled object code, generated documentation,
|
|
33
|
-
and conversions to other media types.
|
|
34
|
-
|
|
35
|
-
"Work" shall mean the work of authorship, whether in Source or
|
|
36
|
-
Object form, made available under the License, as indicated by a
|
|
37
|
-
copyright notice that is included in or attached to the work
|
|
38
|
-
(an example is provided in the Appendix below).
|
|
39
|
-
|
|
40
|
-
"Derivative Works" shall mean any work, whether in Source or Object
|
|
41
|
-
form, that is based on (or derived from) the Work and for which the
|
|
42
|
-
editorial revisions, annotations, elaborations, or other modifications
|
|
43
|
-
represent, as a whole, an original work of authorship. For the purposes
|
|
44
|
-
of this License, Derivative Works shall not include works that remain
|
|
45
|
-
separable from, or merely link (or bind by name) to the interfaces of,
|
|
46
|
-
the Work and Derivative Works thereof.
|
|
47
|
-
|
|
48
|
-
"Contribution" shall mean any work of authorship, including
|
|
49
|
-
the original version of the Work and any modifications or additions
|
|
50
|
-
to that Work or Derivative Works thereof, that is intentionally
|
|
51
|
-
submitted to Licensor for inclusion in the Work by the copyright owner
|
|
52
|
-
or by an individual or Legal Entity authorized to submit on behalf of
|
|
53
|
-
the copyright owner. For the purposes of this definition, "submitted"
|
|
54
|
-
means any form of electronic, verbal, or written communication sent
|
|
55
|
-
to the Licensor or its representatives, including but not limited to
|
|
56
|
-
communication on electronic mailing lists, source code control systems,
|
|
57
|
-
and issue tracking systems that are managed by, or on behalf of, the
|
|
58
|
-
Licensor for the purpose of discussing and improving the Work, but
|
|
59
|
-
excluding communication that is conspicuously marked or otherwise
|
|
60
|
-
designated in writing by the copyright owner as "Not a Contribution."
|
|
61
|
-
|
|
62
|
-
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
63
|
-
on behalf of whom a Contribution has been received by Licensor and
|
|
64
|
-
subsequently incorporated within the Work.
|
|
65
|
-
|
|
66
|
-
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
67
|
-
this License, each Contributor hereby grants to You a perpetual,
|
|
68
|
-
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
69
|
-
copyright license to reproduce, prepare Derivative Works of,
|
|
70
|
-
publicly display, publicly perform, sublicense, and distribute the
|
|
71
|
-
Work and such Derivative Works in Source or Object form.
|
|
72
|
-
|
|
73
|
-
3. Grant of Patent License. Subject to the terms and conditions of
|
|
74
|
-
this License, each Contributor hereby grants to You a perpetual,
|
|
75
|
-
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
76
|
-
(except as stated in this section) patent license to make, have made,
|
|
77
|
-
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
78
|
-
where such license applies only to those patent claims licensable
|
|
79
|
-
by such Contributor that are necessarily infringed by their
|
|
80
|
-
Contribution(s) alone or by combination of their Contribution(s)
|
|
81
|
-
with the Work to which such Contribution(s) was submitted. If You
|
|
82
|
-
institute patent litigation against any entity (including a
|
|
83
|
-
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
84
|
-
or a Contribution incorporated within the Work constitutes direct
|
|
85
|
-
or contributory patent infringement, then any patent licenses
|
|
86
|
-
granted to You under this License for that Work shall terminate
|
|
87
|
-
as of the date such litigation is filed.
|
|
88
|
-
|
|
89
|
-
4. Redistribution. You may reproduce and distribute copies of the
|
|
90
|
-
Work or Derivative Works thereof in any medium, with or without
|
|
91
|
-
modifications, and in Source or Object form, provided that You
|
|
92
|
-
meet the following conditions:
|
|
93
|
-
|
|
94
|
-
(a) You must give any other recipients of the Work or
|
|
95
|
-
Derivative Works a copy of this License; and
|
|
96
|
-
|
|
97
|
-
(b) You must cause any modified files to carry prominent notices
|
|
98
|
-
stating that You changed the files; and
|
|
99
|
-
|
|
100
|
-
(c) You must retain, in the Source form of any Derivative Works
|
|
101
|
-
that You distribute, all copyright, patent, trademark, and
|
|
102
|
-
attribution notices from the Source form of the Work,
|
|
103
|
-
excluding those notices that do not pertain to any part of
|
|
104
|
-
the Derivative Works; and
|
|
105
|
-
|
|
106
|
-
(d) If the Work includes a "NOTICE" text file as part of its
|
|
107
|
-
distribution, then any Derivative Works that You distribute must
|
|
108
|
-
include a readable copy of the attribution notices contained
|
|
109
|
-
within such NOTICE file, excluding those notices that do not
|
|
110
|
-
pertain to any part of the Derivative Works, in at least one
|
|
111
|
-
of the following places: within a NOTICE text file distributed
|
|
112
|
-
as part of the Derivative Works; within the Source form or
|
|
113
|
-
documentation, if provided along with the Derivative Works; or,
|
|
114
|
-
within a display generated by the Derivative Works, if and
|
|
115
|
-
wherever such third-party notices normally appear. The contents
|
|
116
|
-
of the NOTICE file are for informational purposes only and
|
|
117
|
-
do not modify the License. You may add Your own attribution
|
|
118
|
-
notices within Derivative Works that You distribute, alongside
|
|
119
|
-
or as an addendum to the NOTICE text from the Work, provided
|
|
120
|
-
that such additional attribution notices cannot be construed
|
|
121
|
-
as modifying the License.
|
|
122
|
-
|
|
123
|
-
You may add Your own copyright statement to Your modifications and
|
|
124
|
-
may provide additional or different license terms and conditions
|
|
125
|
-
for use, reproduction, or distribution of Your modifications, or
|
|
126
|
-
for any such Derivative Works as a whole, provided Your use,
|
|
127
|
-
reproduction, and distribution of the Work otherwise complies with
|
|
128
|
-
the conditions stated in this License.
|
|
129
|
-
|
|
130
|
-
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
131
|
-
any Contribution intentionally submitted for inclusion in the Work
|
|
132
|
-
by You to the Licensor shall be under the terms and conditions of
|
|
133
|
-
this License, without any additional terms or conditions.
|
|
134
|
-
Notwithstanding the above, nothing herein shall supersede or modify
|
|
135
|
-
the terms of any separate license agreement you may have executed
|
|
136
|
-
with Licensor regarding such Contributions.
|
|
137
|
-
|
|
138
|
-
6. Trademarks. This License does not grant permission to use the trade
|
|
139
|
-
names, trademarks, service marks, or product names of the Licensor,
|
|
140
|
-
except as required for reasonable and customary use in describing the
|
|
141
|
-
origin of the Work and reproducing the content of the NOTICE file.
|
|
142
|
-
|
|
143
|
-
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
144
|
-
agreed to in writing, Licensor provides the Work (and each
|
|
145
|
-
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
146
|
-
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
147
|
-
implied, including, without limitation, any warranties or conditions
|
|
148
|
-
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
149
|
-
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
150
|
-
appropriateness of using or redistributing the Work and assume any
|
|
151
|
-
risks associated with Your exercise of permissions under this License.
|
|
152
|
-
|
|
153
|
-
8. Limitation of Liability. In no event and under no legal theory,
|
|
154
|
-
whether in tort (including negligence), contract, or otherwise,
|
|
155
|
-
unless required by applicable law (such as deliberate and grossly
|
|
156
|
-
negligent acts) or agreed to in writing, shall any Contributor be
|
|
157
|
-
liable to You for damages, including any direct, indirect, special,
|
|
158
|
-
incidental, or consequential damages of any character arising as a
|
|
159
|
-
result of this License or out of the use or inability to use the
|
|
160
|
-
Work (including but not limited to damages for loss of goodwill,
|
|
161
|
-
work stoppage, computer failure or malfunction, or any and all
|
|
162
|
-
other commercial damages or losses), even if such Contributor
|
|
163
|
-
has been advised of the possibility of such damages.
|
|
164
|
-
|
|
165
|
-
9. Accepting Warranty or Additional Liability. While redistributing
|
|
166
|
-
the Work or Derivative Works thereof, You may choose to offer,
|
|
167
|
-
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
168
|
-
or other liability obligations and/or rights consistent with this
|
|
169
|
-
License. However, in accepting such obligations, You may act only
|
|
170
|
-
on Your own behalf and on Your sole responsibility, not on behalf
|
|
171
|
-
of any other Contributor, and only if You agree to indemnify,
|
|
172
|
-
defend, and hold each Contributor harmless for any liability
|
|
173
|
-
incurred by, or claims asserted against, such Contributor by reason
|
|
174
|
-
of your accepting any such warranty or additional liability.
|
|
175
|
-
|
|
176
|
-
END OF TERMS AND CONDITIONS
|
|
177
|
-
|
|
178
|
-
APPENDIX: How to apply the Apache License to your work.
|
|
179
|
-
|
|
180
|
-
To apply the Apache License to your work, attach the following
|
|
181
|
-
boilerplate notice, with the fields enclosed by brackets "[]"
|
|
182
|
-
replaced with your own identifying information. (Don't include
|
|
183
|
-
the brackets!) The text should be enclosed in the appropriate
|
|
184
|
-
comment syntax for the file format. We also recommend that a
|
|
185
|
-
file or class name and description of purpose be included on the
|
|
186
|
-
same "printed page" as the copyright notice for easier
|
|
187
|
-
identification within third-party archives.
|
|
188
|
-
|
|
189
|
-
Copyright [yyyy] [name of copyright owner]
|
|
190
|
-
|
|
191
|
-
Licensed under the Apache License, Version 2.0 (the "License");
|
|
192
|
-
you may not use this file except in compliance with the License.
|
|
193
|
-
You may obtain a copy of the License at
|
|
194
|
-
|
|
195
|
-
http://www.apache.org/licenses/LICENSE-2.0
|
|
196
|
-
|
|
197
|
-
Unless required by applicable law or agreed to in writing, software
|
|
198
|
-
distributed under the License is distributed on an "AS IS" BASIS,
|
|
199
|
-
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
200
|
-
See the License for the specific language governing permissions and
|
|
201
|
-
limitations under the License.
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 邱文武
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -2,6 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
高性能SQLite数据库操作模块,提供与mm_mysql完全兼容的API接口。适用于Node.js应用的轻量级数据存储解决方案。
|
|
4
4
|
|
|
5
|
+
[](https://www.npmjs.com/package/mm_sqlite)
|
|
6
|
+
[](https://www.npmjs.com/package/mm_sqlite)
|
|
7
|
+
[](https://nodejs.org/en/)
|
|
8
|
+
[](LICENSE)
|
|
9
|
+
|
|
5
10
|
## 特性
|
|
6
11
|
|
|
7
12
|
- 🚀 **高性能优化**:经过深度优化的SQL构建器和连接管理
|
|
@@ -13,18 +18,21 @@
|
|
|
13
18
|
|
|
14
19
|
## 安装
|
|
15
20
|
|
|
16
|
-
|
|
17
|
-
|
|
21
|
+
### 使用 npm
|
|
18
22
|
```bash
|
|
19
23
|
npm install mm_sqlite --save
|
|
20
24
|
```
|
|
21
25
|
|
|
22
|
-
|
|
23
|
-
|
|
26
|
+
### 使用 yarn
|
|
24
27
|
```bash
|
|
25
28
|
yarn add mm_sqlite
|
|
26
29
|
```
|
|
27
30
|
|
|
31
|
+
### 使用 pnpm
|
|
32
|
+
```bash
|
|
33
|
+
pnpm add mm_sqlite
|
|
34
|
+
```
|
|
35
|
+
|
|
28
36
|
## 依赖要求
|
|
29
37
|
|
|
30
38
|
- Node.js 14.0+
|
|
@@ -41,11 +49,12 @@ const { Sqlite } = require('mm_sqlite');
|
|
|
41
49
|
|
|
42
50
|
// 创建数据库实例
|
|
43
51
|
const sqlite = new Sqlite({
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
52
|
+
dir: './db/', // 数据库文件存储目录
|
|
53
|
+
database: 'test', // 数据库文件名(不包含扩展名)
|
|
54
|
+
timeout: 30000, // 查询超时时间(毫秒)
|
|
55
|
+
retry_count: 3, // 失败重试次数
|
|
56
|
+
conn_timeout: 30000, // 连接超时时间(毫秒)
|
|
57
|
+
enablePerformanceLog: false // 是否启用性能日志
|
|
49
58
|
});
|
|
50
59
|
|
|
51
60
|
// 打开数据库连接
|
|
@@ -165,14 +174,14 @@ await sqlite.beginTransaction();
|
|
|
165
174
|
|
|
166
175
|
try {
|
|
167
176
|
// 插入数据
|
|
168
|
-
await sqlite.table('users').
|
|
177
|
+
await sqlite.table('users').add({
|
|
169
178
|
name: '张三',
|
|
170
179
|
email: 'zhangsan@example.com',
|
|
171
180
|
status: 'active'
|
|
172
181
|
});
|
|
173
182
|
|
|
174
|
-
//
|
|
175
|
-
await sqlite.table('profiles').
|
|
183
|
+
// 插入关联数据
|
|
184
|
+
await sqlite.table('profiles').add({
|
|
176
185
|
user_id: 1,
|
|
177
186
|
bio: '这是一个测试用户'
|
|
178
187
|
});
|
|
@@ -242,21 +251,27 @@ const users = await sqlite
|
|
|
242
251
|
new Sqlite(config)
|
|
243
252
|
```
|
|
244
253
|
|
|
245
|
-
|
|
246
|
-
- `config.
|
|
254
|
+
**配置参数:**
|
|
255
|
+
- `config.dir` - 数据库文件存储目录,默认为`'./db/'`
|
|
256
|
+
- `config.database` - 数据库文件名,默认为`'mm'`
|
|
247
257
|
- `config.timeout` - 查询超时时间,默认`30000ms`
|
|
248
258
|
- `config.retry_count` - 失败重试次数,默认`3`
|
|
249
259
|
- `config.conn_timeout` - 连接超时时间,默认`30000ms`
|
|
250
|
-
- `config.enablePerformanceLog` -
|
|
260
|
+
- `config.enablePerformanceLog` - 是否启用性能日志,默认`false`
|
|
261
|
+
- `config.debug` - 是否启用调试模式,默认`false`
|
|
251
262
|
|
|
252
263
|
#### 主要方法
|
|
253
264
|
|
|
254
|
-
- `
|
|
255
|
-
- `
|
|
256
|
-
- `
|
|
257
|
-
- `
|
|
258
|
-
- `
|
|
259
|
-
- `
|
|
265
|
+
- `open(timeout)` - 打开数据库连接,返回`Promise<Boolean>`
|
|
266
|
+
- `close()` - 关闭数据库连接,返回`Promise<Boolean>`
|
|
267
|
+
- `getConn(timeout)` - 获取数据库连接,返回`Promise<Connection>`
|
|
268
|
+
- `run(sql, params, timeout)` - 执行SQL语句(非查询操作),返回`Promise<Object>`
|
|
269
|
+
- `exec(sql, params, timeout)` - 执行SQL查询,返回`Promise<Array>`
|
|
270
|
+
- `beginTransaction()` - 开始事务,返回`Promise<void>`
|
|
271
|
+
- `commit()` - 提交事务,返回`Promise<void>`
|
|
272
|
+
- `rollback()` - 回滚事务,返回`Promise<void>`
|
|
273
|
+
- `transaction(fn)` - 执行事务,返回`Promise<any>`
|
|
274
|
+
- `table(tableName)` - 设置表名,返回`Sql`实例
|
|
260
275
|
|
|
261
276
|
### Sql类
|
|
262
277
|
|
|
@@ -339,6 +354,12 @@ A: 可以使用相对路径或绝对路径。建议使用绝对路径以避免
|
|
|
339
354
|
**Q: 事务处理是否支持嵌套?**
|
|
340
355
|
A: 目前不支持嵌套事务,但可以在一个事务中执行多个操作。
|
|
341
356
|
|
|
357
|
+
**Q: 如何启用调试模式?**
|
|
358
|
+
A: 在创建Sqlite实例时,设置`debug: true`配置项即可启用调试模式。
|
|
359
|
+
|
|
360
|
+
**Q: 如何处理SQLite的锁问题?**
|
|
361
|
+
A: 避免长时间运行的事务,使用适当的事务隔离级别,并确保在操作完成后及时提交或回滚事务。
|
|
362
|
+
|
|
342
363
|
## 许可证
|
|
343
364
|
|
|
344
365
|
MIT License
|
|
@@ -350,3 +371,13 @@ MIT License
|
|
|
350
371
|
1. 运行测试确保功能正常
|
|
351
372
|
2. 添加适当的注释和文档
|
|
352
373
|
3. 遵循项目的代码风格
|
|
374
|
+
4. 确保代码符合ES6+标准
|
|
375
|
+
5. 提交前请先拉取最新代码,解决冲突
|
|
376
|
+
|
|
377
|
+
### 开发流程
|
|
378
|
+
|
|
379
|
+
1. Fork 仓库
|
|
380
|
+
2. 创建特性分支 (`git checkout -b feature/AmazingFeature`)
|
|
381
|
+
3. 提交更改 (`git commit -m 'Add some AmazingFeature'`)
|
|
382
|
+
4. 推送到分支 (`git push origin feature/AmazingFeature`)
|
|
383
|
+
5. 打开 Pull Request
|
package/db.js
CHANGED
|
@@ -896,4 +896,41 @@ DB.prototype.backup = function(table, backup, timeout = 60000) {
|
|
|
896
896
|
}
|
|
897
897
|
};
|
|
898
898
|
|
|
899
|
+
/**
|
|
900
|
+
* @description 创建表
|
|
901
|
+
* @param {String} table 表名
|
|
902
|
+
* @param {Object} model 表模型,键值对,根据值类型创建字段类型,根据键名创建字段名
|
|
903
|
+
* @param {String} key 主键
|
|
904
|
+
* @return {Promise|Number} 操作结果
|
|
905
|
+
*/
|
|
906
|
+
DB.prototype.createTable = function(table, model, key = 'id', timeout = 15000){
|
|
907
|
+
if (!table || !model || !model.fields) {
|
|
908
|
+
$.log.error("[DB] [createTable] 参数不完整");
|
|
909
|
+
return 0;
|
|
910
|
+
}
|
|
911
|
+
var fields = '';
|
|
912
|
+
for (const field in model.fields) {
|
|
913
|
+
const value = model.fields[field];
|
|
914
|
+
let type = '';
|
|
915
|
+
if (field === key) {
|
|
916
|
+
type = 'INTEGER PRIMARY KEY AUTOINCREMENT';
|
|
917
|
+
} else if (typeof value === 'number') {
|
|
918
|
+
if (value % 1 === 0) {
|
|
919
|
+
type = 'INTEGER';
|
|
920
|
+
} else {
|
|
921
|
+
type = 'REAL';
|
|
922
|
+
}
|
|
923
|
+
} else if (typeof value === 'string') {
|
|
924
|
+
type = 'TEXT';
|
|
925
|
+
}
|
|
926
|
+
else {
|
|
927
|
+
type = 'BLOB';
|
|
928
|
+
}
|
|
929
|
+
fields += `\`${field}\` ${type}, `;
|
|
930
|
+
}
|
|
931
|
+
fields = fields.slice(0, -2);
|
|
932
|
+
var sql = `CREATE TABLE IF NOT EXISTS \`${table}\` (${fields});`;
|
|
933
|
+
return this.exec(sql, [], timeout);
|
|
934
|
+
}
|
|
935
|
+
|
|
899
936
|
module.exports = DB;
|
package/index.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
const sqlite3 = require('sqlite3').verbose();
|
|
2
2
|
const DB = require('./db');
|
|
3
3
|
const { BaseService } = require('mm_base_service');
|
|
4
|
-
|
|
5
4
|
/**
|
|
6
5
|
* SQLite数据库操作类
|
|
7
6
|
* @class Sqlite
|
|
@@ -12,8 +11,7 @@ class Sqlite extends BaseService {
|
|
|
12
11
|
* 默认配置
|
|
13
12
|
*/
|
|
14
13
|
static default_config = {
|
|
15
|
-
|
|
16
|
-
port: 3306,
|
|
14
|
+
dir: "./db/".fullname(),
|
|
17
15
|
user: "root",
|
|
18
16
|
password: "",
|
|
19
17
|
database: "mm",
|
|
@@ -39,7 +37,7 @@ class Sqlite extends BaseService {
|
|
|
39
37
|
constructor(config) {
|
|
40
38
|
const merged_config = Object.assign({}, Sqlite.default_config, config || {});
|
|
41
39
|
super(merged_config);
|
|
42
|
-
|
|
40
|
+
|
|
43
41
|
this.config = merged_config;
|
|
44
42
|
this._connection = null;
|
|
45
43
|
this._pool = null;
|
|
@@ -58,7 +56,7 @@ class Sqlite extends BaseService {
|
|
|
58
56
|
* 初始化服务
|
|
59
57
|
* @returns {Promise<void>}
|
|
60
58
|
*/
|
|
61
|
-
Sqlite.prototype._initService = async function() {
|
|
59
|
+
Sqlite.prototype._initService = async function () {
|
|
62
60
|
if (this._is_inited) {
|
|
63
61
|
$.log.warn('SQLite服务已初始化');
|
|
64
62
|
return;
|
|
@@ -79,7 +77,7 @@ Sqlite.prototype._initService = async function() {
|
|
|
79
77
|
* @param {Number} timeout - 超时时间(毫秒)
|
|
80
78
|
* @returns {Promise<boolean>}
|
|
81
79
|
*/
|
|
82
|
-
Sqlite.prototype.open = async function(timeout) {
|
|
80
|
+
Sqlite.prototype.open = async function (timeout) {
|
|
83
81
|
if (this._status === 'connected' || this._status === 'connecting') {
|
|
84
82
|
$.log.warn('数据库连接已存在或正在连接中');
|
|
85
83
|
return true;
|
|
@@ -89,14 +87,6 @@ Sqlite.prototype.open = async function(timeout) {
|
|
|
89
87
|
this._status = 'connecting';
|
|
90
88
|
|
|
91
89
|
try {
|
|
92
|
-
// $.log.debug(`[${this.constructor.name}] [open]`, '开始创建数据库连接', {
|
|
93
|
-
// host: this.config.host,
|
|
94
|
-
// port: this.config.port,
|
|
95
|
-
// database: this.config.database,
|
|
96
|
-
// user: this.config.user,
|
|
97
|
-
// timeout: timeout
|
|
98
|
-
// });
|
|
99
|
-
|
|
100
90
|
// 创建连接
|
|
101
91
|
const connection_promise = this._openInternal();
|
|
102
92
|
const timeout_promise = new Promise((_, reject) => {
|
|
@@ -111,8 +101,7 @@ Sqlite.prototype.open = async function(timeout) {
|
|
|
111
101
|
this._last_connect_time = Date.now();
|
|
112
102
|
this._status = 'connected';
|
|
113
103
|
$.log.info(`[${this.constructor.name}] [open]`, '数据库连接成功', {
|
|
114
|
-
|
|
115
|
-
port: this.config.port,
|
|
104
|
+
dir: this.config.dir,
|
|
116
105
|
database: this.config.database
|
|
117
106
|
});
|
|
118
107
|
return true;
|
|
@@ -122,7 +111,7 @@ Sqlite.prototype.open = async function(timeout) {
|
|
|
122
111
|
code: connection_err.code,
|
|
123
112
|
syscall: connection_err.syscall,
|
|
124
113
|
address: connection_err.address,
|
|
125
|
-
|
|
114
|
+
dir: connection_err.dir,
|
|
126
115
|
stack: connection_err.stack
|
|
127
116
|
});
|
|
128
117
|
throw connection_err;
|
|
@@ -131,8 +120,7 @@ Sqlite.prototype.open = async function(timeout) {
|
|
|
131
120
|
this._status = 'closed';
|
|
132
121
|
$.log.error(`[${this.constructor.name}] [open]`, '数据库连接失败', {
|
|
133
122
|
error: err.message,
|
|
134
|
-
|
|
135
|
-
port: this.config.port,
|
|
123
|
+
dir: this.config.dir,
|
|
136
124
|
database: this.config.database
|
|
137
125
|
});
|
|
138
126
|
throw err;
|
|
@@ -144,32 +132,29 @@ Sqlite.prototype.open = async function(timeout) {
|
|
|
144
132
|
* @private
|
|
145
133
|
* @returns {Promise<void>}
|
|
146
134
|
*/
|
|
147
|
-
Sqlite.prototype._openInternal = function() {
|
|
135
|
+
Sqlite.prototype._openInternal = function () {
|
|
148
136
|
return new Promise((resolve, reject) => {
|
|
149
137
|
try {
|
|
150
|
-
|
|
151
|
-
const path = require('path');
|
|
152
|
-
|
|
138
|
+
|
|
153
139
|
// 确保数据库目录存在
|
|
154
|
-
const
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
fs.mkdirSync(dir, { recursive: true });
|
|
140
|
+
const file = this._getDatabasePath();
|
|
141
|
+
|
|
142
|
+
if (!file.hasDir()) {
|
|
143
|
+
file.addDir();
|
|
159
144
|
}
|
|
160
|
-
|
|
145
|
+
|
|
161
146
|
// 创建数据库连接
|
|
162
|
-
this._db = new sqlite3.Database(
|
|
147
|
+
this._db = new sqlite3.Database(file);
|
|
163
148
|
this._open = true;
|
|
164
149
|
this._conn_retry_count = 0;
|
|
165
|
-
|
|
150
|
+
|
|
166
151
|
// 设置连接错误处理
|
|
167
152
|
this._db.on('error', (err) => {
|
|
168
153
|
$.log.error('SQLite数据库连接错误:', err);
|
|
169
154
|
this._handleConnectionError(err);
|
|
170
155
|
});
|
|
171
|
-
|
|
172
|
-
$.log.debug(`SQLite数据库已打开: ${
|
|
156
|
+
|
|
157
|
+
$.log.debug(`SQLite数据库已打开: ${file}`);
|
|
173
158
|
resolve();
|
|
174
159
|
} catch (error) {
|
|
175
160
|
reject(error);
|
|
@@ -182,17 +167,20 @@ Sqlite.prototype._openInternal = function() {
|
|
|
182
167
|
* @private
|
|
183
168
|
* @returns {String}
|
|
184
169
|
*/
|
|
185
|
-
Sqlite.prototype._getDatabasePath = function() {
|
|
170
|
+
Sqlite.prototype._getDatabasePath = function () {
|
|
186
171
|
const db_name = this.config.database || 'mm';
|
|
187
|
-
|
|
188
|
-
|
|
172
|
+
if (db_name.endsWith('.db')) {
|
|
173
|
+
db_name = db_name.replace('.db', '');
|
|
174
|
+
}
|
|
175
|
+
const db_dir = this.config.dir || '/db/'.fullname();
|
|
176
|
+
return `./${db_name}.db`.fullname(db_dir);
|
|
189
177
|
};
|
|
190
178
|
|
|
191
179
|
/**
|
|
192
180
|
* 关闭数据库连接
|
|
193
181
|
* @returns {Promise<boolean>}
|
|
194
182
|
*/
|
|
195
|
-
Sqlite.prototype.close = function() {
|
|
183
|
+
Sqlite.prototype.close = function () {
|
|
196
184
|
if (this._status !== 'connected') {
|
|
197
185
|
$.log.warn('数据库连接未建立');
|
|
198
186
|
return Promise.resolve(false);
|
|
@@ -230,7 +218,7 @@ Sqlite.prototype.close = function() {
|
|
|
230
218
|
* @param {Number} timeout - 超时时间(毫秒)
|
|
231
219
|
* @returns {Promise<Object>}
|
|
232
220
|
*/
|
|
233
|
-
Sqlite.prototype.getConn = async function(timeout) {
|
|
221
|
+
Sqlite.prototype.getConn = async function (timeout) {
|
|
234
222
|
timeout = timeout || this.config.acquire_timeout || this.config.connect_timeout || 20000;
|
|
235
223
|
|
|
236
224
|
// $.log.debug(`[${this.constructor.name}] [getConn] 使用超时时间: ${timeout}ms`);
|
|
@@ -279,7 +267,7 @@ Sqlite.prototype.getConn = async function(timeout) {
|
|
|
279
267
|
* @private
|
|
280
268
|
* @param {Error} err - 错误对象
|
|
281
269
|
*/
|
|
282
|
-
Sqlite.prototype._handleConnectionError = function(err) {
|
|
270
|
+
Sqlite.prototype._handleConnectionError = function (err) {
|
|
283
271
|
if (this._reconnecting) {
|
|
284
272
|
$.log.debug('重连已在进行中');
|
|
285
273
|
return;
|
|
@@ -304,7 +292,7 @@ Sqlite.prototype._handleConnectionError = function(err) {
|
|
|
304
292
|
* @param {Number} max_retries - 最大重试次数
|
|
305
293
|
* @returns {Promise<boolean>}
|
|
306
294
|
*/
|
|
307
|
-
Sqlite.prototype._reconnect = async function(max_retries) {
|
|
295
|
+
Sqlite.prototype._reconnect = async function (max_retries) {
|
|
308
296
|
if (this._reconnecting) {
|
|
309
297
|
$.log.warn('重连已在进行中');
|
|
310
298
|
return false;
|
|
@@ -353,7 +341,7 @@ Sqlite.prototype._reconnect = async function(max_retries) {
|
|
|
353
341
|
* @param {Number} ms - 休眠时间(毫秒)
|
|
354
342
|
* @returns {Promise<void>}
|
|
355
343
|
*/
|
|
356
|
-
Sqlite.prototype._sleep = function(ms) {
|
|
344
|
+
Sqlite.prototype._sleep = function (ms) {
|
|
357
345
|
return new Promise(resolve => setTimeout(resolve, ms));
|
|
358
346
|
};
|
|
359
347
|
|
|
@@ -364,7 +352,7 @@ Sqlite.prototype._sleep = function(ms) {
|
|
|
364
352
|
* @param {Number} timeout - 超时时间(毫秒)
|
|
365
353
|
* @returns {Promise<Object>}
|
|
366
354
|
*/
|
|
367
|
-
Sqlite.prototype.run = async function(sql, params, timeout) {
|
|
355
|
+
Sqlite.prototype.run = async function (sql, params, timeout) {
|
|
368
356
|
let conn = null;
|
|
369
357
|
timeout = timeout || this.config.query_timeout || 30000;
|
|
370
358
|
|
|
@@ -383,7 +371,7 @@ Sqlite.prototype.run = async function(sql, params, timeout) {
|
|
|
383
371
|
}
|
|
384
372
|
});
|
|
385
373
|
});
|
|
386
|
-
|
|
374
|
+
|
|
387
375
|
const timeout_promise = new Promise((_, reject) => {
|
|
388
376
|
setTimeout(() => {
|
|
389
377
|
reject(new Error(`SQL查询超时: ${timeout}ms`));
|
|
@@ -416,7 +404,7 @@ Sqlite.prototype.run = async function(sql, params, timeout) {
|
|
|
416
404
|
* @param {Number} timeout - 超时时间(毫秒)
|
|
417
405
|
* @returns {Promise<Object>}
|
|
418
406
|
*/
|
|
419
|
-
Sqlite.prototype.exec = async function(sql, params, timeout) {
|
|
407
|
+
Sqlite.prototype.exec = async function (sql, params, timeout) {
|
|
420
408
|
let conn = null;
|
|
421
409
|
timeout = timeout || this.config.query_timeout || 30000;
|
|
422
410
|
|
|
@@ -426,7 +414,7 @@ Sqlite.prototype.exec = async function(sql, params, timeout) {
|
|
|
426
414
|
|
|
427
415
|
// 直接在方法内部实现超时控制
|
|
428
416
|
const query_promise = new Promise((resolve, reject) => {
|
|
429
|
-
conn.run(sql, params || [], function(error) {
|
|
417
|
+
conn.run(sql, params || [], function (error) {
|
|
430
418
|
if (error) {
|
|
431
419
|
reject(error);
|
|
432
420
|
} else {
|
|
@@ -439,7 +427,7 @@ Sqlite.prototype.exec = async function(sql, params, timeout) {
|
|
|
439
427
|
}
|
|
440
428
|
});
|
|
441
429
|
});
|
|
442
|
-
|
|
430
|
+
|
|
443
431
|
const timeout_promise = new Promise((_, reject) => {
|
|
444
432
|
setTimeout(() => {
|
|
445
433
|
reject(new Error(`SQL执行超时: ${timeout}ms`));
|
|
@@ -472,7 +460,7 @@ Sqlite.prototype.exec = async function(sql, params, timeout) {
|
|
|
472
460
|
* @param {Object} options - 选项(order_by, limit, offset等)
|
|
473
461
|
* @returns {Promise<Array>}
|
|
474
462
|
*/
|
|
475
|
-
Sqlite.prototype.read = async function(table, condition, options) {
|
|
463
|
+
Sqlite.prototype.read = async function (table, condition, options) {
|
|
476
464
|
try {
|
|
477
465
|
// 检查连接状态
|
|
478
466
|
if (this._status !== 'connected') {
|
|
@@ -539,24 +527,24 @@ Sqlite.prototype.read = async function(table, condition, options) {
|
|
|
539
527
|
* @param {String} database - 数据库名称
|
|
540
528
|
* @returns {Object} 数据库操作实例
|
|
541
529
|
*/
|
|
542
|
-
Sqlite.prototype.db = function(database) {
|
|
530
|
+
Sqlite.prototype.db = function (database) {
|
|
543
531
|
if (this._status !== 'connected') {
|
|
544
532
|
throw new Error('数据库连接未建立');
|
|
545
533
|
}
|
|
546
|
-
|
|
534
|
+
|
|
547
535
|
// 优化:缓存DB实例,避免重复创建
|
|
548
536
|
if (!this._db_instance) {
|
|
549
537
|
this._db_instance = new DB(this);
|
|
550
|
-
|
|
538
|
+
|
|
551
539
|
// 为DB实例添加必要的方法,确保与MySQL接口兼容
|
|
552
540
|
this._db_instance.run = this.run.bind(this);
|
|
553
541
|
this._db_instance.exec = this.exec.bind(this);
|
|
554
542
|
}
|
|
555
|
-
|
|
543
|
+
|
|
556
544
|
if (database) {
|
|
557
545
|
this._db_instance.database = database;
|
|
558
546
|
}
|
|
559
|
-
|
|
547
|
+
|
|
560
548
|
return this._db_instance;
|
|
561
549
|
};
|
|
562
550
|
|
|
@@ -564,7 +552,7 @@ Sqlite.prototype.db = function(database) {
|
|
|
564
552
|
* 获取数据库管理器模型
|
|
565
553
|
* @returns {Object} 数据库管理器模型
|
|
566
554
|
*/
|
|
567
|
-
Sqlite.prototype.dbs = function() {
|
|
555
|
+
Sqlite.prototype.dbs = function () {
|
|
568
556
|
return this.db();
|
|
569
557
|
};
|
|
570
558
|
|
|
@@ -572,7 +560,7 @@ Sqlite.prototype.dbs = function() {
|
|
|
572
560
|
* 开始事务
|
|
573
561
|
* @returns {Promise<Object>} 事务连接对象
|
|
574
562
|
*/
|
|
575
|
-
Sqlite.prototype.beginTransaction = async function() {
|
|
563
|
+
Sqlite.prototype.beginTransaction = async function () {
|
|
576
564
|
try {
|
|
577
565
|
// 检查连接状态
|
|
578
566
|
if (this._status !== 'connected') {
|
|
@@ -631,7 +619,7 @@ Sqlite.prototype.beginTransaction = async function() {
|
|
|
631
619
|
exec: async (sql, params) => {
|
|
632
620
|
// 在事务中执行SQL
|
|
633
621
|
return new Promise((resolve, reject) => {
|
|
634
|
-
connection.run(sql, params || [], function(error) {
|
|
622
|
+
connection.run(sql, params || [], function (error) {
|
|
635
623
|
if (error) {
|
|
636
624
|
reject(error);
|
|
637
625
|
} else {
|
|
@@ -658,7 +646,7 @@ Sqlite.prototype.beginTransaction = async function() {
|
|
|
658
646
|
* @param {Function} callback - 包含事务操作的回调函数
|
|
659
647
|
* @returns {Promise<*>} 回调函数的返回值
|
|
660
648
|
*/
|
|
661
|
-
Sqlite.prototype.transaction = async function(callback) {
|
|
649
|
+
Sqlite.prototype.transaction = async function (callback) {
|
|
662
650
|
let transaction = null;
|
|
663
651
|
|
|
664
652
|
try {
|
|
@@ -685,14 +673,31 @@ Sqlite.prototype.transaction = async function(callback) {
|
|
|
685
673
|
}
|
|
686
674
|
};
|
|
687
675
|
|
|
676
|
+
/**
|
|
677
|
+
* 设置当前操作的表名
|
|
678
|
+
* @param {String} name - 表名
|
|
679
|
+
* @param {String} key - 主键
|
|
680
|
+
* @returns {Object} 数据库操作实例
|
|
681
|
+
*/
|
|
682
|
+
Sqlite.prototype.table = function (name, key) {
|
|
683
|
+
var db = this.db();
|
|
684
|
+
db.table = name;
|
|
685
|
+
if (key) {
|
|
686
|
+
db.key = key;
|
|
687
|
+
}
|
|
688
|
+
return db;
|
|
689
|
+
};
|
|
690
|
+
|
|
691
|
+
// close 方法已在文件前面部分实现,这里不再重复
|
|
692
|
+
|
|
688
693
|
/**
|
|
689
694
|
* 确保连接池对象存在
|
|
690
695
|
*/
|
|
691
696
|
if (!$.pool) {
|
|
692
|
-
|
|
697
|
+
$.pool = {};
|
|
693
698
|
}
|
|
694
699
|
if (!$.pool.sqlite) {
|
|
695
|
-
|
|
700
|
+
$.pool.sqlite = {};
|
|
696
701
|
}
|
|
697
702
|
|
|
698
703
|
/**
|
|
@@ -702,15 +707,15 @@ if (!$.pool.sqlite) {
|
|
|
702
707
|
* @return {Object} 返回一个Sqlite类实例
|
|
703
708
|
*/
|
|
704
709
|
function sqliteAdmin(scope, config) {
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
710
|
+
if (!scope) {
|
|
711
|
+
scope = 'sys';
|
|
712
|
+
}
|
|
713
|
+
var obj = $.pool.sqlite[scope];
|
|
714
|
+
if (!obj) {
|
|
715
|
+
$.pool.sqlite[scope] = new Sqlite(config);
|
|
716
|
+
obj = $.pool.sqlite[scope];
|
|
717
|
+
}
|
|
718
|
+
return obj;
|
|
714
719
|
}
|
|
715
720
|
|
|
716
721
|
// 模块导出
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mm_sqlite",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.4",
|
|
4
4
|
"description": "高性能SQLite数据库操作模块,提供与mm_mysql完全兼容的API接口,支持异步操作、事务处理和批量操作",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
"node": ">=14.0.0"
|
|
37
37
|
},
|
|
38
38
|
"dependencies": {
|
|
39
|
-
"
|
|
39
|
+
"mm_base_service": "^1.0.2",
|
|
40
40
|
"sqlite3": "^5.1.7",
|
|
41
41
|
"sqlstring": "^2.3.3"
|
|
42
42
|
}
|
package/config.json
DELETED
|
Binary file
|
package/db/mm.db
DELETED
|
Binary file
|
package/test.js
DELETED
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
const Sqlite = require('./index.js').Sqlite;
|
|
2
|
-
|
|
3
|
-
// 全面测试函数
|
|
4
|
-
async function runAllTests() {
|
|
5
|
-
$.log.info('开始全面测试mm_sqlite模块...');
|
|
6
|
-
var sql = new Sqlite();
|
|
7
|
-
await sql.open();
|
|
8
|
-
|
|
9
|
-
var test_table = 'test_mm_sqlite';
|
|
10
|
-
|
|
11
|
-
try {
|
|
12
|
-
// 1. 测试表创建
|
|
13
|
-
$.log.info('1. 测试表创建...');
|
|
14
|
-
let create_sql = `CREATE TABLE IF NOT EXISTS ${test_table} (
|
|
15
|
-
uid INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
16
|
-
username VARCHAR(50) NOT NULL,
|
|
17
|
-
age INTEGER DEFAULT 0,
|
|
18
|
-
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
19
|
-
)`;
|
|
20
|
-
let create_result = await sql.run(create_sql);
|
|
21
|
-
$.log.info('表创建结果:', create_result);
|
|
22
|
-
|
|
23
|
-
// 2. 测试数据插入
|
|
24
|
-
$.log.info('2. 测试数据插入...');
|
|
25
|
-
let insert_sql = `INSERT INTO ${test_table} (username, age) VALUES (?, ?)`;
|
|
26
|
-
let insert_result = await sql.run(insert_sql, ['test_user_1', 25]);
|
|
27
|
-
$.log.info('插入结果:', insert_result);
|
|
28
|
-
|
|
29
|
-
// 3. 测试查询 - 使用exec方法并安全处理返回结果
|
|
30
|
-
$.log.info('3. 测试查询...');
|
|
31
|
-
let query_sql = `SELECT * FROM ${test_table}`;
|
|
32
|
-
let query_result = await sql.exec(query_sql);
|
|
33
|
-
$.log.info('查询结果类型:', typeof query_result);
|
|
34
|
-
$.log.info('查询结果:', query_result);
|
|
35
|
-
|
|
36
|
-
// 4. 测试更新
|
|
37
|
-
$.log.info('4. 测试更新...');
|
|
38
|
-
let update_sql = `UPDATE ${test_table} SET age = ? WHERE username = ?`;
|
|
39
|
-
let update_result = await sql.run(update_sql, [26, 'test_user_1']);
|
|
40
|
-
$.log.info('更新结果:', update_result);
|
|
41
|
-
|
|
42
|
-
// 5. 测试删除
|
|
43
|
-
$.log.info('5. 测试删除...');
|
|
44
|
-
let delete_sql = `DELETE FROM ${test_table} WHERE username = ?`;
|
|
45
|
-
let delete_result = await sql.run(delete_sql, ['test_user_1']);
|
|
46
|
-
$.log.info('删除结果:', delete_result);
|
|
47
|
-
|
|
48
|
-
// 6. 测试事务
|
|
49
|
-
$.log.info('6. 测试事务...');
|
|
50
|
-
let transaction_result = await sql.transaction(async () => {
|
|
51
|
-
await sql.run(`INSERT INTO ${test_table} (username, age) VALUES (?, ?)`, ['transaction_user', 40]);
|
|
52
|
-
return await sql.run(`DELETE FROM ${test_table} WHERE username = ?`, ['transaction_user']);
|
|
53
|
-
});
|
|
54
|
-
$.log.info('事务结果:', transaction_result);
|
|
55
|
-
|
|
56
|
-
// 7. 测试表列表 - 安全处理exec返回结果
|
|
57
|
-
$.log.info('7. 测试表列表...');
|
|
58
|
-
let tables_sql = `SELECT name FROM sqlite_master WHERE type='table'`;
|
|
59
|
-
let tables_result = await sql.exec(tables_sql);
|
|
60
|
-
$.log.info('表列表类型:', typeof tables_result);
|
|
61
|
-
$.log.info('表列表:', tables_result);
|
|
62
|
-
|
|
63
|
-
// 8. 清理测试表
|
|
64
|
-
$.log.info('8. 清理测试表...');
|
|
65
|
-
let drop_result = await sql.run(`DROP TABLE IF EXISTS ${test_table}`);
|
|
66
|
-
$.log.info('删除表结果:', drop_result);
|
|
67
|
-
|
|
68
|
-
$.log.info('所有测试完成!mm_sqlite模块功能正常。');
|
|
69
|
-
return true;
|
|
70
|
-
} catch (error) {
|
|
71
|
-
$.log.error('测试过程中发生错误:', error);
|
|
72
|
-
return false;
|
|
73
|
-
} finally {
|
|
74
|
-
await sql.close();
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
// 运行测试
|
|
79
|
-
(async function() {
|
|
80
|
-
await runAllTests();
|
|
81
|
-
})();
|
package/test_all_methods.js
DELETED
|
@@ -1,115 +0,0 @@
|
|
|
1
|
-
// 核心方法测试脚本 - 专注测试del、delList等关键方法
|
|
2
|
-
const { Sqlite } = require('./index');
|
|
3
|
-
|
|
4
|
-
async function testAllMethods() {
|
|
5
|
-
try {
|
|
6
|
-
console.log('=== 开始测试 SQLite 模块核心方法 ===');
|
|
7
|
-
|
|
8
|
-
// 初始化SQLite实例
|
|
9
|
-
const sql = new Sqlite({
|
|
10
|
-
database: './db/test_core_methods.db'
|
|
11
|
-
});
|
|
12
|
-
|
|
13
|
-
await sql.open();
|
|
14
|
-
console.log('数据库连接成功');
|
|
15
|
-
|
|
16
|
-
// 获取数据库操作实例
|
|
17
|
-
const db = sql.db();
|
|
18
|
-
const test_table = 'test_core_methods';
|
|
19
|
-
|
|
20
|
-
// 准备测试表
|
|
21
|
-
console.log('\n=== 1. 准备测试环境 ===');
|
|
22
|
-
await db.exec(`DROP TABLE IF EXISTS ${test_table};`);
|
|
23
|
-
await db.exec(`CREATE TABLE IF NOT EXISTS ${test_table} (
|
|
24
|
-
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
25
|
-
username VARCHAR(50) NOT NULL,
|
|
26
|
-
email VARCHAR(100),
|
|
27
|
-
age INTEGER DEFAULT 0 NOT NULL
|
|
28
|
-
);`);
|
|
29
|
-
console.log('测试表创建完成');
|
|
30
|
-
|
|
31
|
-
db.table = test_table;
|
|
32
|
-
|
|
33
|
-
// 2. 单条数据操作测试
|
|
34
|
-
console.log('\n=== 2. 单条数据操作测试 ===');
|
|
35
|
-
// 添加单条数据
|
|
36
|
-
const addResult = await db.add({
|
|
37
|
-
username: 'test_user1',
|
|
38
|
-
email: 'test1@example.com',
|
|
39
|
-
age: 25
|
|
40
|
-
});
|
|
41
|
-
console.log('✓ add方法测试通过:', addResult);
|
|
42
|
-
|
|
43
|
-
// 查询单条数据
|
|
44
|
-
const getResult = await db.get({ username: 'test_user1' });
|
|
45
|
-
console.log('✓ get方法测试通过,数据:', getResult[0]?.username);
|
|
46
|
-
|
|
47
|
-
// 修改数据
|
|
48
|
-
const setResult = await db.set(
|
|
49
|
-
{ username: 'test_user1' },
|
|
50
|
-
{ age: 26 }
|
|
51
|
-
);
|
|
52
|
-
console.log('✓ set方法测试通过:', setResult);
|
|
53
|
-
|
|
54
|
-
// 3. 批量操作测试 - 重点测试addList
|
|
55
|
-
console.log('\n=== 3. 批量添加测试 ===');
|
|
56
|
-
const batchData = [
|
|
57
|
-
{ username: 'batch_user1', email: 'batch1@example.com', age: 30 },
|
|
58
|
-
{ username: 'batch_user2', email: 'batch2@example.com', age: 31 },
|
|
59
|
-
{ username: 'batch_user3', email: 'batch3@example.com', age: 32 }
|
|
60
|
-
];
|
|
61
|
-
|
|
62
|
-
const addListResult = await db.addList(batchData);
|
|
63
|
-
console.log('✓ addList方法测试通过:', addListResult);
|
|
64
|
-
|
|
65
|
-
// 4. 单条删除测试 - 重点测试del
|
|
66
|
-
console.log('\n=== 4. 单条删除测试 ===');
|
|
67
|
-
const delResult = await db.del({ username: 'test_user1' });
|
|
68
|
-
console.log('✓ del方法测试通过:', delResult);
|
|
69
|
-
|
|
70
|
-
// 验证删除结果
|
|
71
|
-
const delCheck = await db.get({ username: 'test_user1' });
|
|
72
|
-
console.log(' del方法验证结果: 删除成功', delCheck.length === 0);
|
|
73
|
-
|
|
74
|
-
// 5. 批量删除测试 - 重点测试delList
|
|
75
|
-
console.log('\n=== 5. 批量删除测试 ===');
|
|
76
|
-
const deleteList = [
|
|
77
|
-
{ query: { username: 'batch_user1' } },
|
|
78
|
-
{ query: { username: 'batch_user2' } }
|
|
79
|
-
];
|
|
80
|
-
|
|
81
|
-
const delListResult = await db.delList(deleteList);
|
|
82
|
-
console.log('✓ delList方法测试通过:', delListResult);
|
|
83
|
-
|
|
84
|
-
// 验证批量删除结果
|
|
85
|
-
const batch1Check = await db.get({ username: 'batch_user1' });
|
|
86
|
-
const batch2Check = await db.get({ username: 'batch_user2' });
|
|
87
|
-
console.log(' delList方法验证结果: 批量删除成功',
|
|
88
|
-
batch1Check.length === 0 && batch2Check.length === 0);
|
|
89
|
-
|
|
90
|
-
// 验证剩余数据
|
|
91
|
-
const remainingData = await db.get({});
|
|
92
|
-
console.log(' 剩余数据数量:', remainingData.length);
|
|
93
|
-
|
|
94
|
-
// 6. 清理测试数据
|
|
95
|
-
console.log('\n=== 6. 清理测试环境 ===');
|
|
96
|
-
await db.exec(`DROP TABLE IF EXISTS ${test_table};`);
|
|
97
|
-
console.log('测试表清理完成');
|
|
98
|
-
|
|
99
|
-
// 关闭数据库连接
|
|
100
|
-
await sql.close();
|
|
101
|
-
console.log('\n=== 核心方法测试完成!===');
|
|
102
|
-
console.log('✓ del方法工作正常');
|
|
103
|
-
console.log('✓ delList方法工作正常');
|
|
104
|
-
console.log('✓ 其他核心方法(add, get, set, addList)工作正常');
|
|
105
|
-
|
|
106
|
-
} catch (error) {
|
|
107
|
-
console.error('测试过程中出现错误:', error.message);
|
|
108
|
-
console.error('错误堆栈:', error.stack);
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
// 执行测试
|
|
113
|
-
(async () => {
|
|
114
|
-
await testAllMethods();
|
|
115
|
-
})();
|
package/test_db_methods.js
DELETED
|
@@ -1,262 +0,0 @@
|
|
|
1
|
-
// 测试db.js中的所有方法
|
|
2
|
-
const { Sqlite } = require('./index');
|
|
3
|
-
const path = require('path');
|
|
4
|
-
|
|
5
|
-
async function testDbMethods() {
|
|
6
|
-
let sql;
|
|
7
|
-
try {
|
|
8
|
-
console.log('=== 开始测试 mm_sqlite/db.js 中的方法 ===\n');
|
|
9
|
-
|
|
10
|
-
// 初始化SQLite实例
|
|
11
|
-
sql = new Sqlite({
|
|
12
|
-
database: './db/test_db_methods.db'
|
|
13
|
-
});
|
|
14
|
-
|
|
15
|
-
await sql.open();
|
|
16
|
-
console.log('✓ 数据库连接成功');
|
|
17
|
-
|
|
18
|
-
// 获取数据库操作实例
|
|
19
|
-
const db = sql.db();
|
|
20
|
-
const test_table = 'test_db_methods';
|
|
21
|
-
const backup_table = 'test_db_methods_backup';
|
|
22
|
-
|
|
23
|
-
// 清理测试环境
|
|
24
|
-
console.log('\n=== 1. 清理测试环境 ===');
|
|
25
|
-
await db.dropTable(test_table);
|
|
26
|
-
await db.dropTable(backup_table);
|
|
27
|
-
console.log('✓ 测试环境清理完成');
|
|
28
|
-
|
|
29
|
-
// 2. 测试表操作方法
|
|
30
|
-
console.log('\n=== 2. 测试表操作方法 ===');
|
|
31
|
-
|
|
32
|
-
// 测试addTable
|
|
33
|
-
console.log('测试addTable()方法...');
|
|
34
|
-
const createResult = await db.addTable(test_table, 'id', 'int', true, '测试表');
|
|
35
|
-
console.log('✓ 表创建结果:', createResult);
|
|
36
|
-
|
|
37
|
-
// 测试hasTable
|
|
38
|
-
console.log('测试hasTable()方法...');
|
|
39
|
-
const hasTableResult = await db.hasTable(test_table);
|
|
40
|
-
console.log('✓ 表是否存在:', hasTableResult);
|
|
41
|
-
|
|
42
|
-
// 测试tables
|
|
43
|
-
console.log('测试tables()方法...');
|
|
44
|
-
const tablesResult = await db.tables();
|
|
45
|
-
console.log('✓ 表列表:', tablesResult);
|
|
46
|
-
|
|
47
|
-
// 3. 测试字段操作方法
|
|
48
|
-
console.log('\n=== 3. 测试字段操作方法 ===');
|
|
49
|
-
|
|
50
|
-
// 设置表名
|
|
51
|
-
db.table = test_table;
|
|
52
|
-
|
|
53
|
-
// 测试addField
|
|
54
|
-
console.log('测试addField()方法...');
|
|
55
|
-
const addFieldResult1 = await db.addField('username', 'varchar', '', true, false, '用户名');
|
|
56
|
-
console.log('✓ 添加username字段结果:', addFieldResult1);
|
|
57
|
-
|
|
58
|
-
// 测试addField(添加email字段)
|
|
59
|
-
console.log('测试addField()方法(添加email字段)...');
|
|
60
|
-
const addFieldResult2 = await db.addField('email', 'varchar', '', true, false, '邮箱');
|
|
61
|
-
console.log('✓ 添加email字段结果:', addFieldResult2);
|
|
62
|
-
|
|
63
|
-
// 测试addField(添加age字段)
|
|
64
|
-
console.log('测试addField()方法(添加age字段)...');
|
|
65
|
-
const addFieldResult3 = await db.addField('age', 'int', 0, true, false, '年龄');
|
|
66
|
-
console.log('✓ 添加age字段结果:', addFieldResult3);
|
|
67
|
-
|
|
68
|
-
// 测试setField
|
|
69
|
-
console.log('测试setField()方法...');
|
|
70
|
-
const setFieldResult = await db.setField('email', 'varchar', '', true, false, '电子邮箱');
|
|
71
|
-
console.log('✓ 修改email字段结果:', setFieldResult);
|
|
72
|
-
|
|
73
|
-
// 测试addField(添加temp字段用于后续delField测试)
|
|
74
|
-
console.log('测试addField()方法(添加temp字段)...');
|
|
75
|
-
await db.addField('temp', 'int', 0, false, false, '临时字段');
|
|
76
|
-
console.log('✓ 添加temp字段结果: 成功');
|
|
77
|
-
|
|
78
|
-
// 测试fields
|
|
79
|
-
console.log('测试fields()方法...');
|
|
80
|
-
const fieldsResult = await db.fields();
|
|
81
|
-
console.log('✓ 字段信息:', fieldsResult.map(f => f.name));
|
|
82
|
-
|
|
83
|
-
// 测试hasField
|
|
84
|
-
console.log('测试hasField()方法...');
|
|
85
|
-
const hasFieldResult = await db.hasField(test_table, 'username');
|
|
86
|
-
console.log('✓ username字段是否存在:', hasFieldResult);
|
|
87
|
-
|
|
88
|
-
// 测试delField
|
|
89
|
-
console.log('测试delField()方法...');
|
|
90
|
-
const delFieldResult = await db.delField(test_table, 'temp');
|
|
91
|
-
console.log('✓ 删除temp字段结果:', delFieldResult);
|
|
92
|
-
|
|
93
|
-
// 测试renameField
|
|
94
|
-
console.log('测试renameField()方法...');
|
|
95
|
-
try {
|
|
96
|
-
// 先检查当前字段
|
|
97
|
-
const fieldsBefore = await db.fields();
|
|
98
|
-
console.log(' - 重命名前字段:', fieldsBefore.map(f => f.name));
|
|
99
|
-
|
|
100
|
-
const renameFieldResult = await db.renameField(test_table, 'age', 'user_age');
|
|
101
|
-
console.log(' - 重命名age字段结果:', renameFieldResult);
|
|
102
|
-
|
|
103
|
-
// 检查重命名后字段
|
|
104
|
-
const fieldsAfter = await db.fields();
|
|
105
|
-
console.log(' - 重命名后字段:', fieldsAfter.map(f => f.name));
|
|
106
|
-
|
|
107
|
-
// 只有当user_age字段存在时,才尝试重命名回age字段
|
|
108
|
-
const hasUserAgeField = fieldsAfter.some(f => f.name === 'user_age');
|
|
109
|
-
if (hasUserAgeField) {
|
|
110
|
-
// 重命名回age字段,保持后续测试一致
|
|
111
|
-
await db.renameField(test_table, 'user_age', 'age');
|
|
112
|
-
console.log(' - 重命名user_age字段回age结果: 成功');
|
|
113
|
-
|
|
114
|
-
// 再次检查字段
|
|
115
|
-
const fieldsFinal = await db.fields();
|
|
116
|
-
console.log(' - 最终字段:', fieldsFinal.map(f => f.name));
|
|
117
|
-
} else {
|
|
118
|
-
console.warn(' - user_age字段不存在,跳过重命名回age字段');
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
console.log('✓ renameField方法测试完成');
|
|
122
|
-
} catch (error) {
|
|
123
|
-
console.warn('⚠️ renameField()方法测试失败:', error.message);
|
|
124
|
-
console.log('⚠️ renameField()方法测试跳过');
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
// 4. 测试数据操作方法
|
|
128
|
-
console.log('\n=== 4. 测试数据操作方法 ===');
|
|
129
|
-
|
|
130
|
-
// 测试add(插入数据)
|
|
131
|
-
console.log('测试add()方法...');
|
|
132
|
-
const addResult = await db.add({
|
|
133
|
-
username: 'test_user',
|
|
134
|
-
email: 'test@example.com',
|
|
135
|
-
age: 25
|
|
136
|
-
});
|
|
137
|
-
console.log('✓ 插入数据结果:', addResult);
|
|
138
|
-
|
|
139
|
-
// 测试get(查询单条数据)
|
|
140
|
-
console.log('测试get()方法...');
|
|
141
|
-
const getResult = await db.get({ id: 1 });
|
|
142
|
-
console.log('✓ 查询单条数据结果:', getResult[0]);
|
|
143
|
-
|
|
144
|
-
// 测试get(查询多条数据)
|
|
145
|
-
console.log('测试get()方法(查询多条数据)...');
|
|
146
|
-
const listResult = await db.get();
|
|
147
|
-
console.log('✓ 查询多条数据结果:', listResult.length);
|
|
148
|
-
|
|
149
|
-
// 测试set(更新数据)
|
|
150
|
-
console.log('测试set()方法...');
|
|
151
|
-
const setResult = await db.set({ id: 1 }, { age: 26 });
|
|
152
|
-
console.log('✓ 更新数据结果:', setResult);
|
|
153
|
-
|
|
154
|
-
// 测试set(另一种查询条件更新方式)
|
|
155
|
-
console.log('测试set()方法(使用where属性)...');
|
|
156
|
-
db.where = { id: 1 };
|
|
157
|
-
const setResult2 = await db.set(db.where, { age: 27 });
|
|
158
|
-
console.log('✓ set方法(使用where属性)更新结果:', setResult2);
|
|
159
|
-
|
|
160
|
-
// 测试del(删除数据)
|
|
161
|
-
console.log('测试del()方法...');
|
|
162
|
-
const delResult = await db.del({ id: 1 });
|
|
163
|
-
console.log('✓ 删除数据结果:', delResult);
|
|
164
|
-
|
|
165
|
-
// 5. 测试事务操作方法
|
|
166
|
-
console.log('\n=== 5. 测试事务操作方法 ===');
|
|
167
|
-
|
|
168
|
-
// 重新插入一条数据用于事务测试
|
|
169
|
-
await db.add({
|
|
170
|
-
username: 'transaction_test',
|
|
171
|
-
email: 'transaction@example.com',
|
|
172
|
-
age: 30
|
|
173
|
-
});
|
|
174
|
-
|
|
175
|
-
try {
|
|
176
|
-
// 测试start(开始事务)
|
|
177
|
-
console.log(' - 事务开始');
|
|
178
|
-
await db.start();
|
|
179
|
-
|
|
180
|
-
// 在事务中插入数据
|
|
181
|
-
await db.add({
|
|
182
|
-
username: 'transaction_user',
|
|
183
|
-
email: 'user@example.com',
|
|
184
|
-
age: 35
|
|
185
|
-
});
|
|
186
|
-
console.log(' - 事务中插入数据成功');
|
|
187
|
-
|
|
188
|
-
// 测试commit(提交事务)
|
|
189
|
-
await db.commit();
|
|
190
|
-
console.log(' - 事务提交成功');
|
|
191
|
-
|
|
192
|
-
// 验证事务提交结果
|
|
193
|
-
const transactionResult = await db.get();
|
|
194
|
-
console.log(' - 事务后数据总数:', transactionResult.length);
|
|
195
|
-
|
|
196
|
-
} catch (error) {
|
|
197
|
-
// 测试back(回滚事务)
|
|
198
|
-
await db.back();
|
|
199
|
-
console.log(' - 事务回滚');
|
|
200
|
-
throw error;
|
|
201
|
-
} finally {
|
|
202
|
-
// 测试end(结束事务)
|
|
203
|
-
db.end();
|
|
204
|
-
}
|
|
205
|
-
console.log('✓ 事务操作完成');
|
|
206
|
-
|
|
207
|
-
// 6. 测试其他方法
|
|
208
|
-
console.log('\n=== 6. 测试其他方法 ===');
|
|
209
|
-
|
|
210
|
-
// 测试getCreateTable
|
|
211
|
-
console.log('测试getCreateTable()方法...');
|
|
212
|
-
const createTableResult = await db.getCreateTable(test_table);
|
|
213
|
-
console.log('✓ 表创建语句:', createTableResult);
|
|
214
|
-
|
|
215
|
-
// 测试backupTable
|
|
216
|
-
console.log('测试backupTable()方法...');
|
|
217
|
-
const backupResult = await db.backupTable(test_table, backup_table);
|
|
218
|
-
console.log('✓ 表备份结果:', backupResult);
|
|
219
|
-
|
|
220
|
-
// 测试hasTable(备份表)
|
|
221
|
-
console.log('测试hasTable()方法(备份表)...');
|
|
222
|
-
const hasBackupTableResult = await db.hasTable(backup_table);
|
|
223
|
-
console.log('✓ 备份表是否存在:', hasBackupTableResult);
|
|
224
|
-
|
|
225
|
-
// 测试emptyTable
|
|
226
|
-
console.log('测试emptyTable()方法...');
|
|
227
|
-
const emptyResult = await db.emptyTable(test_table);
|
|
228
|
-
console.log('✓ 清空表结果:', emptyResult);
|
|
229
|
-
|
|
230
|
-
// 7. 清理测试环境
|
|
231
|
-
console.log('\n=== 7. 清理测试环境 ===');
|
|
232
|
-
await db.dropTable(test_table);
|
|
233
|
-
await db.dropTable(backup_table);
|
|
234
|
-
console.log('✓ 测试环境清理完成');
|
|
235
|
-
|
|
236
|
-
// 关闭数据库连接
|
|
237
|
-
console.log('\n=== 8. 关闭数据库连接 ===');
|
|
238
|
-
await sql.close();
|
|
239
|
-
console.log('✓ 数据库连接关闭成功');
|
|
240
|
-
|
|
241
|
-
console.log('\n' + '='.repeat(50));
|
|
242
|
-
console.log('所有测试完成!db.js方法测试通过');
|
|
243
|
-
console.log('='.repeat(50));
|
|
244
|
-
|
|
245
|
-
} catch (error) {
|
|
246
|
-
console.error('\n测试失败:', error.message);
|
|
247
|
-
// 关闭数据库连接
|
|
248
|
-
try {
|
|
249
|
-
if (sql) await sql.close();
|
|
250
|
-
} catch (closeError) {
|
|
251
|
-
console.error('关闭数据库连接失败:', closeError.message);
|
|
252
|
-
}
|
|
253
|
-
process.exit(1);
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
// 运行测试
|
|
258
|
-
testDbMethods();
|
|
259
|
-
|
|
260
|
-
setTimeout(() => {
|
|
261
|
-
process.exit(0);
|
|
262
|
-
}, 5000);
|