befly 0.1.26
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 +201 -0
- package/README.md +3 -0
- package/apis/health/info.js +33 -0
- package/checks/schema.js +132 -0
- package/config/env.js +56 -0
- package/libs/xml/DocTypeReader.js +362 -0
- package/libs/xml/OptionsBuilder.js +45 -0
- package/libs/xml/OrderedObjParser.js +597 -0
- package/libs/xml/XMLParser.js +69 -0
- package/libs/xml/ignoreAttributes.js +18 -0
- package/libs/xml/node2json.js +114 -0
- package/libs/xml/strnum.js +134 -0
- package/libs/xml/util.js +68 -0
- package/libs/xml/validator.js +425 -0
- package/libs/xml/xmlNode.js +40 -0
- package/main.js +410 -0
- package/package.json +53 -0
- package/plugins/cors.js +15 -0
- package/plugins/db.js +56 -0
- package/plugins/logger.js +13 -0
- package/plugins/redis.js +116 -0
- package/schema/common.json +17 -0
- package/schema/debug.json +1 -0
- package/schema/health.json +1 -0
- package/schema/tool.json +6 -0
- package/utils/api.js +49 -0
- package/utils/colors.js +83 -0
- package/utils/crypto.js +260 -0
- package/utils/curd.js +183 -0
- package/utils/jwt.js +154 -0
- package/utils/logger.js +143 -0
- package/utils/util.js +171 -0
- package/utils/validate.js +244 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{}
|
package/schema/tool.json
ADDED
package/utils/api.js
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { Logger } from '../utils/logger.js';
|
|
2
|
+
import { RYes, RNo } from '../utils/util.js';
|
|
3
|
+
export class Api {
|
|
4
|
+
// GET 方法
|
|
5
|
+
static GET(name, auth = false, fields = {}, required = [], handler) {
|
|
6
|
+
return {
|
|
7
|
+
method: 'GET',
|
|
8
|
+
name: name,
|
|
9
|
+
auth: auth,
|
|
10
|
+
fields: fields,
|
|
11
|
+
required: required,
|
|
12
|
+
handler: this.wrapHandler(handler)
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// POST 方法
|
|
17
|
+
static POST(name, auth = false, fields = {}, required = [], handler) {
|
|
18
|
+
return {
|
|
19
|
+
method: 'POST',
|
|
20
|
+
name: name,
|
|
21
|
+
auth: auth,
|
|
22
|
+
fields: fields,
|
|
23
|
+
required: required,
|
|
24
|
+
handler: this.wrapHandler(handler)
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// 包装处理器,自动处理异常和响应格式
|
|
29
|
+
static wrapHandler(handler) {
|
|
30
|
+
return async (bp, ctx, req) => {
|
|
31
|
+
try {
|
|
32
|
+
const result = await handler(bp, ctx, req);
|
|
33
|
+
|
|
34
|
+
return result;
|
|
35
|
+
} catch (error) {
|
|
36
|
+
Logger.error({
|
|
37
|
+
msg: '内部服务器错误',
|
|
38
|
+
error: error.message,
|
|
39
|
+
stack: error.stack,
|
|
40
|
+
url: req?.url || '',
|
|
41
|
+
user: ctx?.user || {}
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
// 返回错误响应
|
|
45
|
+
return RNo('内部服务器错误');
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
}
|
package/utils/colors.js
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
const p = process || {},
|
|
2
|
+
argv = p.argv || [],
|
|
3
|
+
env = p.env || {};
|
|
4
|
+
const isColorSupported = !(!!env.NO_COLOR || argv.includes('--no-color')) && (!!env.FORCE_COLOR || argv.includes('--color') || p.platform === 'win32' || ((p.stdout || {}).isTTY && env.TERM !== 'dumb') || !!env.CI);
|
|
5
|
+
|
|
6
|
+
const formatter =
|
|
7
|
+
(open, close, replace = open) =>
|
|
8
|
+
(input) => {
|
|
9
|
+
let string = '' + input,
|
|
10
|
+
index = string.indexOf(close, open.length);
|
|
11
|
+
return ~index ? open + replaceClose(string, close, replace, index) + close : open + string + close;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
const replaceClose = (string, close, replace, index) => {
|
|
15
|
+
let result = '',
|
|
16
|
+
cursor = 0;
|
|
17
|
+
do {
|
|
18
|
+
result += string.substring(cursor, index) + replace;
|
|
19
|
+
cursor = index + close.length;
|
|
20
|
+
index = string.indexOf(close, cursor);
|
|
21
|
+
} while (~index);
|
|
22
|
+
return result + string.substring(cursor);
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const createColors = (enabled = isColorSupported) => {
|
|
26
|
+
let f = enabled ? formatter : () => String;
|
|
27
|
+
return {
|
|
28
|
+
isColorSupported: enabled,
|
|
29
|
+
reset: f('\x1b[0m', '\x1b[0m'),
|
|
30
|
+
bold: f('\x1b[1m', '\x1b[22m', '\x1b[22m\x1b[1m'),
|
|
31
|
+
dim: f('\x1b[2m', '\x1b[22m', '\x1b[22m\x1b[2m'),
|
|
32
|
+
italic: f('\x1b[3m', '\x1b[23m'),
|
|
33
|
+
underline: f('\x1b[4m', '\x1b[24m'),
|
|
34
|
+
inverse: f('\x1b[7m', '\x1b[27m'),
|
|
35
|
+
hidden: f('\x1b[8m', '\x1b[28m'),
|
|
36
|
+
strikethrough: f('\x1b[9m', '\x1b[29m'),
|
|
37
|
+
|
|
38
|
+
black: f('\x1b[30m', '\x1b[39m'),
|
|
39
|
+
red: f('\x1b[31m', '\x1b[39m'),
|
|
40
|
+
green: f('\x1b[32m', '\x1b[39m'),
|
|
41
|
+
yellow: f('\x1b[33m', '\x1b[39m'),
|
|
42
|
+
blue: f('\x1b[34m', '\x1b[39m'),
|
|
43
|
+
magenta: f('\x1b[35m', '\x1b[39m'),
|
|
44
|
+
cyan: f('\x1b[36m', '\x1b[39m'),
|
|
45
|
+
white: f('\x1b[37m', '\x1b[39m'),
|
|
46
|
+
gray: f('\x1b[90m', '\x1b[39m'),
|
|
47
|
+
|
|
48
|
+
bgBlack: f('\x1b[40m', '\x1b[49m'),
|
|
49
|
+
bgRed: f('\x1b[41m', '\x1b[49m'),
|
|
50
|
+
bgGreen: f('\x1b[42m', '\x1b[49m'),
|
|
51
|
+
bgYellow: f('\x1b[43m', '\x1b[49m'),
|
|
52
|
+
bgBlue: f('\x1b[44m', '\x1b[49m'),
|
|
53
|
+
bgMagenta: f('\x1b[45m', '\x1b[49m'),
|
|
54
|
+
bgCyan: f('\x1b[46m', '\x1b[49m'),
|
|
55
|
+
bgWhite: f('\x1b[47m', '\x1b[49m'),
|
|
56
|
+
|
|
57
|
+
blackBright: f('\x1b[90m', '\x1b[39m'),
|
|
58
|
+
redBright: f('\x1b[91m', '\x1b[39m'),
|
|
59
|
+
greenBright: f('\x1b[92m', '\x1b[39m'),
|
|
60
|
+
yellowBright: f('\x1b[93m', '\x1b[39m'),
|
|
61
|
+
blueBright: f('\x1b[94m', '\x1b[39m'),
|
|
62
|
+
magentaBright: f('\x1b[95m', '\x1b[39m'),
|
|
63
|
+
cyanBright: f('\x1b[96m', '\x1b[39m'),
|
|
64
|
+
whiteBright: f('\x1b[97m', '\x1b[39m'),
|
|
65
|
+
|
|
66
|
+
bgBlackBright: f('\x1b[100m', '\x1b[49m'),
|
|
67
|
+
bgRedBright: f('\x1b[101m', '\x1b[49m'),
|
|
68
|
+
bgGreenBright: f('\x1b[102m', '\x1b[49m'),
|
|
69
|
+
bgYellowBright: f('\x1b[103m', '\x1b[49m'),
|
|
70
|
+
bgBlueBright: f('\x1b[104m', '\x1b[49m'),
|
|
71
|
+
bgMagentaBright: f('\x1b[105m', '\x1b[49m'),
|
|
72
|
+
bgCyanBright: f('\x1b[106m', '\x1b[49m'),
|
|
73
|
+
bgWhiteBright: f('\x1b[107m', '\x1b[49m')
|
|
74
|
+
};
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
const colors = createColors();
|
|
78
|
+
colors.info = colors.blue('i');
|
|
79
|
+
colors.success = colors.green('√');
|
|
80
|
+
colors.warn = colors.yellow('‼');
|
|
81
|
+
colors.error = colors.red('x');
|
|
82
|
+
|
|
83
|
+
export { colors };
|
package/utils/crypto.js
ADDED
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
import { createSign } from 'node:crypto';
|
|
2
|
+
|
|
3
|
+
export class Crypto2 {
|
|
4
|
+
/**
|
|
5
|
+
* MD5 哈希
|
|
6
|
+
* @param {string|Uint8Array} data - 要哈希的数据
|
|
7
|
+
* @param {string} encoding - 输出编码 ('hex', 'base64')
|
|
8
|
+
* @returns {string} MD5 哈希值
|
|
9
|
+
*/
|
|
10
|
+
static md5(data, encoding = 'hex') {
|
|
11
|
+
const hasher = new Bun.CryptoHasher('md5');
|
|
12
|
+
hasher.update(data);
|
|
13
|
+
return hasher.digest(encoding);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* HMAC-MD5 签名
|
|
18
|
+
* @param {string|Uint8Array} key - 密钥
|
|
19
|
+
* @param {string|Uint8Array} data - 要签名的数据
|
|
20
|
+
* @param {string} encoding - 输出编码 ('hex', 'base64')
|
|
21
|
+
* @returns {string} HMAC-MD5 签名
|
|
22
|
+
*/
|
|
23
|
+
static hmacMd5(key, data, encoding = 'hex') {
|
|
24
|
+
const hasher = new Bun.CryptoHasher('md5', key);
|
|
25
|
+
hasher.update(data);
|
|
26
|
+
return hasher.digest(encoding);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* SHA-1 哈希
|
|
31
|
+
* @param {string|Uint8Array} data - 要哈希的数据
|
|
32
|
+
* @param {string} encoding - 输出编码 ('hex', 'base64')
|
|
33
|
+
* @returns {string} SHA-1 哈希值
|
|
34
|
+
*/
|
|
35
|
+
static sha1(data, encoding = 'hex') {
|
|
36
|
+
const hasher = new Bun.CryptoHasher('sha1');
|
|
37
|
+
hasher.update(data);
|
|
38
|
+
return hasher.digest(encoding);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* HMAC-SHA1 签名
|
|
43
|
+
* @param {string|Uint8Array} key - 密钥
|
|
44
|
+
* @param {string|Uint8Array} data - 要签名的数据
|
|
45
|
+
* @param {string} encoding - 输出编码 ('hex', 'base64')
|
|
46
|
+
* @returns {string} HMAC-SHA1 签名
|
|
47
|
+
*/
|
|
48
|
+
static hmacSha1(key, data, encoding = 'hex') {
|
|
49
|
+
const hasher = new Bun.CryptoHasher('sha1', key);
|
|
50
|
+
hasher.update(data);
|
|
51
|
+
return hasher.digest(encoding);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* SHA-256 哈希
|
|
56
|
+
* @param {string|Uint8Array} data - 要哈希的数据
|
|
57
|
+
* @param {string} encoding - 输出编码 ('hex', 'base64')
|
|
58
|
+
* @returns {string} SHA-256 哈希值
|
|
59
|
+
*/
|
|
60
|
+
static sha256(data, encoding = 'hex') {
|
|
61
|
+
const hasher = new Bun.CryptoHasher('sha256');
|
|
62
|
+
hasher.update(data);
|
|
63
|
+
return hasher.digest(encoding);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
static rsaSha256(data, privateKey, encoding = 'hex') {
|
|
67
|
+
const sign = createSign('RSA-SHA256');
|
|
68
|
+
sign.update(data);
|
|
69
|
+
const signature = sign.sign(privateKey, encoding);
|
|
70
|
+
return signature;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* HMAC-SHA256 签名
|
|
75
|
+
* @param {string|Uint8Array} key - 密钥
|
|
76
|
+
* @param {string|Uint8Array} data - 要签名的数据
|
|
77
|
+
* @param {string} encoding - 输出编码 ('hex', 'base64')
|
|
78
|
+
* @returns {string} HMAC-SHA256 签名
|
|
79
|
+
*/
|
|
80
|
+
static hmacSha256(key, data, encoding = 'hex') {
|
|
81
|
+
const hasher = new Bun.CryptoHasher('sha256', key);
|
|
82
|
+
hasher.update(data);
|
|
83
|
+
return hasher.digest(encoding);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* SHA-512 哈希
|
|
88
|
+
* @param {string|Uint8Array} data - 要哈希的数据
|
|
89
|
+
* @param {string} encoding - 输出编码 ('hex', 'base64')
|
|
90
|
+
* @returns {string} SHA-512 哈希值
|
|
91
|
+
*/
|
|
92
|
+
static sha512(data, encoding = 'hex') {
|
|
93
|
+
const hasher = new Bun.CryptoHasher('sha512');
|
|
94
|
+
hasher.update(data);
|
|
95
|
+
return hasher.digest(encoding);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* HMAC-SHA512 签名
|
|
100
|
+
* @param {string|Uint8Array} key - 密钥
|
|
101
|
+
* @param {string|Uint8Array} data - 要签名的数据
|
|
102
|
+
* @param {string} encoding - 输出编码 ('hex', 'base64')
|
|
103
|
+
* @returns {string} HMAC-SHA512 签名
|
|
104
|
+
*/
|
|
105
|
+
static hmacSha512(key, data, encoding = 'hex') {
|
|
106
|
+
const hasher = new Bun.CryptoHasher('sha512', key);
|
|
107
|
+
hasher.update(data);
|
|
108
|
+
return hasher.digest(encoding);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* 通用哈希方法
|
|
113
|
+
* @param {string} algorithm - 算法名称 ('md5', 'sha1', 'sha256', 'sha512')
|
|
114
|
+
* @param {string|Uint8Array} data - 要哈希的数据
|
|
115
|
+
* @param {string} encoding - 输出编码 ('hex', 'base64')
|
|
116
|
+
* @returns {string} 哈希值
|
|
117
|
+
*/
|
|
118
|
+
static hash(algorithm, data, encoding = 'hex') {
|
|
119
|
+
const hasher = new Bun.CryptoHasher(algorithm);
|
|
120
|
+
hasher.update(data);
|
|
121
|
+
return hasher.digest(encoding);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* 通用 HMAC 方法
|
|
126
|
+
* @param {string} algorithm - 算法名称 ('md5', 'sha1', 'sha256', 'sha512')
|
|
127
|
+
* @param {string|Uint8Array} key - 密钥
|
|
128
|
+
* @param {string|Uint8Array} data - 要签名的数据
|
|
129
|
+
* @param {string} encoding - 输出编码 ('hex', 'base64')
|
|
130
|
+
* @returns {string} HMAC 签名
|
|
131
|
+
*/
|
|
132
|
+
static hmac(algorithm, key, data, encoding = 'hex') {
|
|
133
|
+
const hasher = new Bun.CryptoHasher(algorithm, key);
|
|
134
|
+
hasher.update(data);
|
|
135
|
+
return hasher.digest(encoding);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* 文件哈希
|
|
140
|
+
* @param {string} filePath - 文件路径
|
|
141
|
+
* @param {string} algorithm - 算法名称 (默认 'sha256')
|
|
142
|
+
* @param {string} encoding - 输出编码 ('hex', 'base64')
|
|
143
|
+
* @returns {Promise<string>} 文件哈希值
|
|
144
|
+
*/
|
|
145
|
+
static async hashFile(filePath, algorithm = 'sha256', encoding = 'hex') {
|
|
146
|
+
const file = Bun.file(filePath);
|
|
147
|
+
const hasher = new Bun.CryptoHasher(algorithm);
|
|
148
|
+
|
|
149
|
+
const stream = file.stream();
|
|
150
|
+
const reader = stream.getReader();
|
|
151
|
+
|
|
152
|
+
try {
|
|
153
|
+
while (true) {
|
|
154
|
+
const { done, value } = await reader.read();
|
|
155
|
+
if (done) break;
|
|
156
|
+
hasher.update(value);
|
|
157
|
+
}
|
|
158
|
+
return hasher.digest(encoding);
|
|
159
|
+
} finally {
|
|
160
|
+
reader.releaseLock();
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* 创建流式哈希器
|
|
166
|
+
* @param {string} algorithm - 算法名称
|
|
167
|
+
* @param {string|Uint8Array} key - 可选的 HMAC 密钥
|
|
168
|
+
* @returns {StreamHasher} 流式哈希器实例
|
|
169
|
+
*/
|
|
170
|
+
static createHasher(algorithm, key = null) {
|
|
171
|
+
return new StreamHasher(algorithm, key);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* 密码哈希 (使用 Argon2)
|
|
176
|
+
* @param {string} password - 密码
|
|
177
|
+
* @param {object} options - 选项
|
|
178
|
+
* @returns {Promise<string>} 哈希后的密码
|
|
179
|
+
*/
|
|
180
|
+
static async hashPassword(password, options = {}) {
|
|
181
|
+
return await Bun.password.hash(password, options);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* 验证密码
|
|
186
|
+
* @param {string} password - 原始密码
|
|
187
|
+
* @param {string} hash - 哈希值
|
|
188
|
+
* @returns {Promise<boolean>} 验证结果
|
|
189
|
+
*/
|
|
190
|
+
static async verifyPassword(password, hash) {
|
|
191
|
+
return await Bun.password.verify(password, hash);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* 快速哈希 (非密码学)
|
|
196
|
+
* @param {string|Uint8Array} data - 数据
|
|
197
|
+
* @param {number} seed - 种子值
|
|
198
|
+
* @returns {number} 64位哈希值
|
|
199
|
+
*/
|
|
200
|
+
static fastHash(data, seed = 0) {
|
|
201
|
+
return Bun.hash(data, seed);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* 流式哈希器类
|
|
207
|
+
*/
|
|
208
|
+
class StreamHasher {
|
|
209
|
+
constructor(algorithm, key = null) {
|
|
210
|
+
this.hasher = new Bun.CryptoHasher(algorithm, key);
|
|
211
|
+
this.finalized = false;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* 更新数据
|
|
216
|
+
* @param {string|Uint8Array} data - 数据
|
|
217
|
+
* @returns {StreamHasher} 支持链式调用
|
|
218
|
+
*/
|
|
219
|
+
update(data) {
|
|
220
|
+
if (this.finalized) {
|
|
221
|
+
throw new Error('哈希器已经完成,不能再更新数据');
|
|
222
|
+
}
|
|
223
|
+
this.hasher.update(data);
|
|
224
|
+
return this;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* 生成最终哈希值
|
|
229
|
+
* @param {string} encoding - 输出编码
|
|
230
|
+
* @returns {string} 哈希值
|
|
231
|
+
*/
|
|
232
|
+
digest(encoding = 'hex') {
|
|
233
|
+
if (this.finalized) {
|
|
234
|
+
throw new Error('哈希器已经完成');
|
|
235
|
+
}
|
|
236
|
+
this.finalized = true;
|
|
237
|
+
return this.hasher.digest(encoding);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* 复制哈希器
|
|
242
|
+
* @returns {StreamHasher} 新的哈希器实例
|
|
243
|
+
*/
|
|
244
|
+
copy() {
|
|
245
|
+
if (this.finalized) {
|
|
246
|
+
throw new Error('不能复制已完成的哈希器');
|
|
247
|
+
}
|
|
248
|
+
const newHasher = new StreamHasher();
|
|
249
|
+
newHasher.hasher = this.hasher.copy();
|
|
250
|
+
return newHasher;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
// 使用示例:
|
|
255
|
+
// const md5Hash = Crypto.md5('hello world');
|
|
256
|
+
// const hmacMd5 = Crypto.hmacMd5('secret-key', 'hello world');
|
|
257
|
+
// const sha256Hash = Crypto.sha256('hello world');
|
|
258
|
+
// const fileHash = await Crypto.hashFile('./file.txt', 'md5');
|
|
259
|
+
// const hasher = Crypto.createHasher('md5').update('hello').update(' world');
|
|
260
|
+
// const result = hasher.digest('hex');
|
package/utils/curd.js
ADDED
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import { omitFields } from './util.js';
|
|
2
|
+
|
|
3
|
+
export class Crud {
|
|
4
|
+
constructor(db, redis, sql) {
|
|
5
|
+
this.db = db;
|
|
6
|
+
this.redis = redis;
|
|
7
|
+
this.sql = sql;
|
|
8
|
+
this.initMethods();
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
initMethods() {
|
|
12
|
+
// 将所有 CRUD 方法直接挂载到 db 实例上
|
|
13
|
+
this.db.insData = this.insData.bind(this);
|
|
14
|
+
this.db.updData = this.updData.bind(this);
|
|
15
|
+
this.db.delData = this.delData.bind(this);
|
|
16
|
+
this.db.getOne = this.getOne.bind(this);
|
|
17
|
+
this.db.getList = this.getList.bind(this);
|
|
18
|
+
this.db.getAll = this.getAll.bind(this);
|
|
19
|
+
this.db.getCount = this.getCount.bind(this);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// 事务方法
|
|
23
|
+
async trans(callback) {
|
|
24
|
+
return await this.db.transaction().execute(async (trx) => {
|
|
25
|
+
// 创建一个临时的 Crud 实例,使用事务连接
|
|
26
|
+
const transactionCrud = new Crud(trx, this.redis, this.sql);
|
|
27
|
+
return await callback(transactionCrud);
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// 增强的插入方法 - 自动添加 ID 和时间戳,支持链式调用
|
|
32
|
+
insData(tableName, data) {
|
|
33
|
+
const insertQuery = this.db.insertInto(tableName);
|
|
34
|
+
const redis = this.redis;
|
|
35
|
+
|
|
36
|
+
insertQuery.exec = async function () {
|
|
37
|
+
const now = Date.now();
|
|
38
|
+
let processedData = data;
|
|
39
|
+
|
|
40
|
+
if (Array.isArray(data)) {
|
|
41
|
+
processedData = await Promise.all(
|
|
42
|
+
data.map(async (item) => ({
|
|
43
|
+
...item,
|
|
44
|
+
id: await redis.genTimeID(),
|
|
45
|
+
created_at: now,
|
|
46
|
+
updated_at: now
|
|
47
|
+
}))
|
|
48
|
+
);
|
|
49
|
+
} else {
|
|
50
|
+
processedData = {
|
|
51
|
+
...data,
|
|
52
|
+
id: await redis.genTimeID(),
|
|
53
|
+
created_at: now,
|
|
54
|
+
updated_at: now
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const result = await this.values(processedData).execute();
|
|
59
|
+
return { data: result }; // 返回统一格式
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
return insertQuery;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// 增强的更新方法 - 自动添加 updated_at,支持链式调用
|
|
66
|
+
updData(tableName, data) {
|
|
67
|
+
const updateData = {
|
|
68
|
+
...omitFields(data, ['id', 'created_at', 'deleted_at']),
|
|
69
|
+
updated_at: Date.now()
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
const updateQuery = this.db.updateTable(tableName).set(updateData);
|
|
73
|
+
|
|
74
|
+
updateQuery.exec = async function () {
|
|
75
|
+
const result = await this.execute();
|
|
76
|
+
return { data: result }; // 返回统一格式
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
return updateQuery;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// 增强的删除方法 - 支持链式调用
|
|
83
|
+
delData(tableName) {
|
|
84
|
+
const deleteQuery = this.db.deleteFrom(tableName);
|
|
85
|
+
|
|
86
|
+
deleteQuery.exec = async function () {
|
|
87
|
+
const result = await this.execute();
|
|
88
|
+
return { data: result }; // 返回统一格式
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
return deleteQuery;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// 查询单条记录 - 支持链式调用
|
|
95
|
+
getOne(tableName, fields) {
|
|
96
|
+
let selectQuery;
|
|
97
|
+
|
|
98
|
+
if (fields) {
|
|
99
|
+
selectQuery = Array.isArray(fields) ? this.db.selectFrom(tableName).select(fields) : this.db.selectFrom(tableName).select([fields]);
|
|
100
|
+
} else {
|
|
101
|
+
selectQuery = this.db.selectFrom(tableName).selectAll();
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// 默认过滤软删除的数据
|
|
105
|
+
selectQuery = selectQuery.where('state', '<>', 2);
|
|
106
|
+
|
|
107
|
+
// 添加 exec 方法,自动返回单条记录
|
|
108
|
+
selectQuery.exec = async function () {
|
|
109
|
+
const result = await this.executeTakeFirst();
|
|
110
|
+
return { data: result }; // 返回统一格式
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
return selectQuery;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// 查询列表 - 支持链式调用和分页
|
|
117
|
+
getList(tableName, fields, page = 1, pageSize = 20) {
|
|
118
|
+
let selectQuery;
|
|
119
|
+
|
|
120
|
+
if (fields) {
|
|
121
|
+
selectQuery = Array.isArray(fields) ? this.db.selectFrom(tableName).select(fields) : this.db.selectFrom(tableName).select([fields]);
|
|
122
|
+
} else {
|
|
123
|
+
selectQuery = this.db.selectFrom(tableName).selectAll();
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// 默认过滤软删除的数据
|
|
127
|
+
selectQuery = selectQuery.where('state', '<>', 2);
|
|
128
|
+
|
|
129
|
+
// 添加 exec 方法 - 支持分页,只返回数据列表
|
|
130
|
+
selectQuery.exec = async function () {
|
|
131
|
+
const offset = (page - 1) * pageSize;
|
|
132
|
+
const result = await this.limit(pageSize).offset(offset).execute();
|
|
133
|
+
return { data: result };
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
return selectQuery;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// 查询所有记录 - 支持链式调用
|
|
140
|
+
getAll(tableName, fields) {
|
|
141
|
+
let selectQuery;
|
|
142
|
+
|
|
143
|
+
if (fields) {
|
|
144
|
+
selectQuery = Array.isArray(fields) ? this.db.selectFrom(tableName).select(fields) : this.db.selectFrom(tableName).select([fields]);
|
|
145
|
+
} else {
|
|
146
|
+
selectQuery = this.db.selectFrom(tableName).selectAll();
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// 默认过滤软删除的数据
|
|
150
|
+
selectQuery = selectQuery.where('state', '<>', 2);
|
|
151
|
+
|
|
152
|
+
// 添加 exec 方法,执行查询所有记录
|
|
153
|
+
selectQuery.exec = async function () {
|
|
154
|
+
const result = await this.execute();
|
|
155
|
+
return { data: result }; // 返回统一格式
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
return selectQuery;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// 便捷的计数方法 - 支持链式调用
|
|
162
|
+
getCount(tableName) {
|
|
163
|
+
const sql = this.sql;
|
|
164
|
+
const countQuery = this.db
|
|
165
|
+
.selectFrom(tableName)
|
|
166
|
+
.select(sql`count(*)`.as('total'))
|
|
167
|
+
.where('state', '<>', 2);
|
|
168
|
+
|
|
169
|
+
// 添加便捷的 exec 方法
|
|
170
|
+
countQuery.exec = async function () {
|
|
171
|
+
const result = await this.executeTakeFirst();
|
|
172
|
+
const count = Number(result?.total || 0);
|
|
173
|
+
return { data: count }; // 返回统一格式
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
return countQuery;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// 获取原始数据库实例
|
|
180
|
+
getDb() {
|
|
181
|
+
return this.db;
|
|
182
|
+
}
|
|
183
|
+
}
|