utilitas 1989.8.52
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 -0
- package/README.md +3 -0
- package/index.js +40 -0
- package/lib/cache.js +281 -0
- package/lib/dbio.js +291 -0
- package/lib/email.js +120 -0
- package/lib/encryption.js +62 -0
- package/lib/event.js +118 -0
- package/lib/network.js +105 -0
- package/lib/sentinel.js +28 -0
- package/lib/shell.js +44 -0
- package/lib/shot.js +77 -0
- package/lib/sms.js +68 -0
- package/lib/storage.js +115 -0
- package/lib/tape.js +97 -0
- package/lib/uoid.js +38 -0
- package/lib/utilitas.js +660 -0
- package/package.json +45 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2020 Leask Wong
|
|
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
ADDED
package/index.js
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
module.exports = {
|
|
4
|
+
// dependencies
|
|
5
|
+
base64url: require('base64url'),
|
|
6
|
+
colors: require('colors/safe'),
|
|
7
|
+
fetch: require('node-fetch').default,
|
|
8
|
+
fileType: require('file-type'),
|
|
9
|
+
geoIp: require('fast-geoip'),
|
|
10
|
+
jwt: require('jsonwebtoken'),
|
|
11
|
+
mailgun: require('mailgun-js'),
|
|
12
|
+
mailjet: require('node-mailjet'),
|
|
13
|
+
math: require('mathjs'),
|
|
14
|
+
mysql: require('mysql2/promise'),
|
|
15
|
+
ping: require('ping'),
|
|
16
|
+
publicIp: require('public-ip'),
|
|
17
|
+
qs: require('qs'),
|
|
18
|
+
redis: require('ioredis'),
|
|
19
|
+
sentry: require('@sentry/node'),
|
|
20
|
+
telesign: require('telesignsdk'),
|
|
21
|
+
twilio: require('twilio'),
|
|
22
|
+
uuid: require('uuid'),
|
|
23
|
+
winston: require('winston'),
|
|
24
|
+
winstonPapertrail: require('winston-papertrail-mproved'),
|
|
25
|
+
// features
|
|
26
|
+
cache: require('./lib/cache'),
|
|
27
|
+
dbio: require('./lib/dbio'),
|
|
28
|
+
email: require('./lib/email'),
|
|
29
|
+
encryption: require('./lib/encryption'),
|
|
30
|
+
event: require('./lib/event'),
|
|
31
|
+
network: require('./lib/network'),
|
|
32
|
+
sentinel: require('./lib/sentinel'),
|
|
33
|
+
shell: require('./lib/shell'),
|
|
34
|
+
shot: require('./lib/shot'),
|
|
35
|
+
sms: require('./lib/sms'),
|
|
36
|
+
storage: require('./lib/storage'),
|
|
37
|
+
tape: require('./lib/tape'),
|
|
38
|
+
uoid: require('./lib/uoid'),
|
|
39
|
+
utilitas: require('./lib/utilitas'),
|
|
40
|
+
};
|
package/lib/cache.js
ADDED
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const defaultOptions = {
|
|
4
|
+
port: 6379, host: '127.0.0.1', family: 4, db: 0, connectTimeout: 1000 * 3,
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
let ioredis, redis;
|
|
8
|
+
|
|
9
|
+
const log = (content) => { return utilitas.modLog(content, 'cache'); };
|
|
10
|
+
|
|
11
|
+
const init = async (options) => {
|
|
12
|
+
if ((options = options === '@' ? defaultOptions : options)) {
|
|
13
|
+
ioredis = require('ioredis');
|
|
14
|
+
redis = new ioredis(options);
|
|
15
|
+
if (!options.silent) {
|
|
16
|
+
log(`Initialized: redis://${redis.options.host}`
|
|
17
|
+
+ `:${redis.options.port}/${redis.options.db} .`);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
utilitas.assert(redis, 'Redis has not been initialized.', 501);
|
|
21
|
+
return redis;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
module.exports = {
|
|
25
|
+
init,
|
|
26
|
+
// set,
|
|
27
|
+
// get,
|
|
28
|
+
// mGet,
|
|
29
|
+
// lPush,
|
|
30
|
+
// rPush,
|
|
31
|
+
// lRange,
|
|
32
|
+
// getList,
|
|
33
|
+
// del,
|
|
34
|
+
// lrem,
|
|
35
|
+
// smartDel,
|
|
36
|
+
// setWithExpired,
|
|
37
|
+
// tryLock,
|
|
38
|
+
// lock,
|
|
39
|
+
// unLock,
|
|
40
|
+
// init,
|
|
41
|
+
// pTryLock,
|
|
42
|
+
// pUnLock
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
const utilitas = require('./utilitas');
|
|
46
|
+
|
|
47
|
+
// https://github.com/luin/ioredis
|
|
48
|
+
|
|
49
|
+
// var getKey = function(type, id, callback) {
|
|
50
|
+
// if (!type || !id) {
|
|
51
|
+
// return callback ? callback('Error cache type or id.') : null;
|
|
52
|
+
// }
|
|
53
|
+
// var key = 'PRSCACHE_' + type.toUpperCase() + '_' + String(id);
|
|
54
|
+
// return callback ? callback(null, key) : key;
|
|
55
|
+
// };
|
|
56
|
+
|
|
57
|
+
// var getKeys = function(type, ids, callback) {
|
|
58
|
+
// if (!type || !ids || !ids.length) {
|
|
59
|
+
// return callback ? callback('Error cache type or ids.') : null;
|
|
60
|
+
// }
|
|
61
|
+
// var result = [];
|
|
62
|
+
// for (var i in ids) {
|
|
63
|
+
// var id = getKey(type, ids[i]);
|
|
64
|
+
// if (id) {
|
|
65
|
+
// result.push(id);
|
|
66
|
+
// }
|
|
67
|
+
// }
|
|
68
|
+
// return callback ? callback(null, result) : result;
|
|
69
|
+
// };
|
|
70
|
+
|
|
71
|
+
// var rawSet = function(type, id, data, options, callback) {
|
|
72
|
+
// options = options || {};
|
|
73
|
+
// getKey(type, id, function(err, key) {
|
|
74
|
+
// if (err) {
|
|
75
|
+
// return callback(err);
|
|
76
|
+
// }
|
|
77
|
+
// var value = JSON.stringify(data);
|
|
78
|
+
// if (verbose && global.config.debug) {
|
|
79
|
+
// console.log('Set cache: ' + key + ' = ' + value);
|
|
80
|
+
// }
|
|
81
|
+
// var args = [key, value];
|
|
82
|
+
// for (var i in options) {
|
|
83
|
+
// if (['EX', 'PX'].indexOf(i) !== -1 && options[i]) {
|
|
84
|
+
// args.push(i, options[i]);
|
|
85
|
+
// }
|
|
86
|
+
// options['NX'] && args.push('NX');
|
|
87
|
+
// options['XX'] && args.push('XX');
|
|
88
|
+
// }
|
|
89
|
+
// global.redis.set(args, callback || function() { });
|
|
90
|
+
// });
|
|
91
|
+
// };
|
|
92
|
+
|
|
93
|
+
// var set = function(type, id, data, callback) {
|
|
94
|
+
// rawSet(type, id, data, {}, callback);
|
|
95
|
+
// };
|
|
96
|
+
|
|
97
|
+
// var setWithExpired = function(type, id, data, ex, nx, callback) {
|
|
98
|
+
// rawSet(type, id, data, { EX: ex, NX: nx }, callback);
|
|
99
|
+
// };
|
|
100
|
+
|
|
101
|
+
// var del = function(type, id, callback) {
|
|
102
|
+
// getKey(type, id, function(err, key) {
|
|
103
|
+
// if (err) {
|
|
104
|
+
// return callback(err);
|
|
105
|
+
// }
|
|
106
|
+
// if (verbose && global.config.debug) {
|
|
107
|
+
// console.log('Del cache: ' + key);
|
|
108
|
+
// }
|
|
109
|
+
// global.redis.del(key, callback || function() { });
|
|
110
|
+
// });
|
|
111
|
+
// };
|
|
112
|
+
|
|
113
|
+
// let lrem = function(type, id, data, callback) {
|
|
114
|
+
// getKey(type, id, function(err, key) {
|
|
115
|
+
// if (err) {
|
|
116
|
+
// return callback(err);
|
|
117
|
+
// }
|
|
118
|
+
// if (global.config.debug) {
|
|
119
|
+
// console.log('Del cache by value: ' + data);
|
|
120
|
+
// }
|
|
121
|
+
// global.redis.lrem(key, 0, data, callback || function() { });
|
|
122
|
+
// });
|
|
123
|
+
// };
|
|
124
|
+
|
|
125
|
+
// var findKeys = function(type, preStr, callback) {
|
|
126
|
+
// getKey(type, preStr, function(err, key) {
|
|
127
|
+
// if (err) {
|
|
128
|
+
// return callback(err);
|
|
129
|
+
// }
|
|
130
|
+
// redis.keys(key, callback);
|
|
131
|
+
// });
|
|
132
|
+
// };
|
|
133
|
+
|
|
134
|
+
// var findAndDel = function(type, preStr, callback) {
|
|
135
|
+
// findKeys(type, preStr, function(err, data) {
|
|
136
|
+
// if (err) {
|
|
137
|
+
// return callback(err);
|
|
138
|
+
// }
|
|
139
|
+
// async.eachSeries(data, function(item, cbf) {
|
|
140
|
+
// // console.log('Clean ' + item);
|
|
141
|
+
// redis.del(item, function(err, result) {
|
|
142
|
+
// if (err) {
|
|
143
|
+
// console.log(err);
|
|
144
|
+
// }
|
|
145
|
+
// cbf();
|
|
146
|
+
// });
|
|
147
|
+
// }, function(result) {
|
|
148
|
+
// callback(null, data.length);
|
|
149
|
+
// });
|
|
150
|
+
// });
|
|
151
|
+
// };
|
|
152
|
+
|
|
153
|
+
// var smartDel = function(type, id, callback) {
|
|
154
|
+
// return /^.*\*$/.test(id)
|
|
155
|
+
// ? findAndDel(type, id, callback) : del(type, id, callback);
|
|
156
|
+
// };
|
|
157
|
+
|
|
158
|
+
// var get = function(type, id, callback) {
|
|
159
|
+
// getKey(type, id, function(err, key) {
|
|
160
|
+
// if (err) {
|
|
161
|
+
// return callback(err);
|
|
162
|
+
// }
|
|
163
|
+
// if (global.argv.ignore_cache) {
|
|
164
|
+
// return callback(null, null);
|
|
165
|
+
// }
|
|
166
|
+
// global.redis.get(key, function(err, reply) {
|
|
167
|
+
// if (err) {
|
|
168
|
+
// return callback(err);
|
|
169
|
+
// }
|
|
170
|
+
// var value = null;
|
|
171
|
+
// try {
|
|
172
|
+
// value = JSON.parse(reply);
|
|
173
|
+
// } catch (err) {
|
|
174
|
+
// console.log(err);
|
|
175
|
+
// return callback(err);
|
|
176
|
+
// }
|
|
177
|
+
// if (verbose && global.config.debug) {
|
|
178
|
+
// console.log('Get cache: ' + key + ' = ' + reply);
|
|
179
|
+
// }
|
|
180
|
+
// callback(null, value);
|
|
181
|
+
// });
|
|
182
|
+
// });
|
|
183
|
+
// };
|
|
184
|
+
|
|
185
|
+
// var mGet = function(type, ids, callback) {
|
|
186
|
+
// getKeys(type, ids, function(err, keys) {
|
|
187
|
+
// if (err) {
|
|
188
|
+
// return callback(err);
|
|
189
|
+
// }
|
|
190
|
+
// if (global.argv.ignore_cache) {
|
|
191
|
+
// return callback(null, null);
|
|
192
|
+
// }
|
|
193
|
+
// global.redis.mget(keys, function(err, reply) {
|
|
194
|
+
// if (err) {
|
|
195
|
+
// return callback(err);
|
|
196
|
+
// }
|
|
197
|
+
// var values = [];
|
|
198
|
+
// for (var i in reply) {
|
|
199
|
+
// var value = null;
|
|
200
|
+
// try {
|
|
201
|
+
// value = JSON.parse(reply[i]);
|
|
202
|
+
// } catch (err) {
|
|
203
|
+
// return callback(err);
|
|
204
|
+
// }
|
|
205
|
+
// if (value) {
|
|
206
|
+
// values.push(value);
|
|
207
|
+
// }
|
|
208
|
+
// }
|
|
209
|
+
// if (verbose && global.config.debug) {
|
|
210
|
+
// console.log('Get cache: ' + keys + ' = ' + reply);
|
|
211
|
+
// }
|
|
212
|
+
// callback(null, values);
|
|
213
|
+
// });
|
|
214
|
+
// });
|
|
215
|
+
// };
|
|
216
|
+
|
|
217
|
+
// let rawPush = (type, id, left, values, callback) => {
|
|
218
|
+
// getKey(type, id, (err, key) => {
|
|
219
|
+
// if (err) {
|
|
220
|
+
// return callback(err);
|
|
221
|
+
// }
|
|
222
|
+
// if (verbose && global.config.debug) {
|
|
223
|
+
// console.log(`RPUSH ${value} to ${key}`);
|
|
224
|
+
// }
|
|
225
|
+
// callback = callback || function() { };
|
|
226
|
+
// left ? global.redis.lpush(key, values, callback)
|
|
227
|
+
// : global.redis.rpush(key, values, callback);
|
|
228
|
+
// });
|
|
229
|
+
// };
|
|
230
|
+
|
|
231
|
+
// let lPush = (type, id, values, callback) => {
|
|
232
|
+
// rawPush(type, id, true, values, callback);
|
|
233
|
+
// };
|
|
234
|
+
|
|
235
|
+
// let rPush = (type, id, values, callback) => {
|
|
236
|
+
// rawPush(type, id, false, values, callback);
|
|
237
|
+
// };
|
|
238
|
+
|
|
239
|
+
// let lRange = (type, id, start, stop, callback) => {
|
|
240
|
+
// getKey(type, id, (err, key) => {
|
|
241
|
+
// if (err) {
|
|
242
|
+
// return callback(err);
|
|
243
|
+
// }
|
|
244
|
+
// if (global.argv.ignore_cache) {
|
|
245
|
+
// return callback(null, null);
|
|
246
|
+
// }
|
|
247
|
+
// global.redis.lrange(key, start, stop, (err, reply) => {
|
|
248
|
+
// if (verbose && global.config.debug) {
|
|
249
|
+
// console.log('Get list: ' + key + ' = ' + reply);
|
|
250
|
+
// }
|
|
251
|
+
// callback(err, reply);
|
|
252
|
+
// });
|
|
253
|
+
// });
|
|
254
|
+
// };
|
|
255
|
+
|
|
256
|
+
// let getList = (type, id, callback) => {
|
|
257
|
+
// lRange(type, id, 0, -1, callback);
|
|
258
|
+
// };
|
|
259
|
+
|
|
260
|
+
// let tryLock = (key, timeout, callback) => { // 有返回值表示已经被锁,需要等待。
|
|
261
|
+
// get('lock', key, (err, data) => {
|
|
262
|
+
// if (err || data) {
|
|
263
|
+
// return callback(err, true);
|
|
264
|
+
// }
|
|
265
|
+
// lock(key, timeout, (err, data) => {
|
|
266
|
+
// if (err || !data) {
|
|
267
|
+
// callback(err, true);
|
|
268
|
+
// }
|
|
269
|
+
// callback(err, false);
|
|
270
|
+
// });
|
|
271
|
+
// });
|
|
272
|
+
// };
|
|
273
|
+
|
|
274
|
+
// let lock = (key, timeout, callback) => {
|
|
275
|
+
// timeout = ~~timeout;
|
|
276
|
+
// setWithExpired('lock', key, new Date(), timeout || 30, true, callback);
|
|
277
|
+
// };
|
|
278
|
+
|
|
279
|
+
// let unLock = (key, callback) => {
|
|
280
|
+
// del('lock', key, callback);
|
|
281
|
+
// };
|
package/lib/dbio.js
ADDED
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const defaultPort = 3306;
|
|
4
|
+
const orders = { '+': 'ASC', '-': 'DESC' };
|
|
5
|
+
const fieldId = 'id';
|
|
6
|
+
const fieldAny = '*';
|
|
7
|
+
const fieldCount = `COUNT(${fieldAny})`;
|
|
8
|
+
const comparison = ['=', '>', '<', '<>', '!='];
|
|
9
|
+
const fieldNoQuote = [fieldAny, fieldCount];
|
|
10
|
+
const log = (content) => { return utilitas.modLog(content, 'dbio'); };
|
|
11
|
+
|
|
12
|
+
let mysql, pool;
|
|
13
|
+
|
|
14
|
+
const init = async (options) => {
|
|
15
|
+
if (options) {
|
|
16
|
+
mysql = require('mysql2/promise');
|
|
17
|
+
pool = mysql.createPool(options);
|
|
18
|
+
if (!options.silent) {
|
|
19
|
+
log(`Initialized: mysql://${options.user}@${options.host}`
|
|
20
|
+
+ `:${options.port || defaultPort}/${options.database} .`);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
utilitas.assert(pool, 'Database has not been initialized.', 501);
|
|
24
|
+
return pool;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
const end = async (options) => {
|
|
28
|
+
pool && pool.end();
|
|
29
|
+
log('Terminated.');
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const logCommand = (args) => {
|
|
33
|
+
if (~~global.debug > 0 && args && args[0]) { log(`SQL: ${args[0]}`); }
|
|
34
|
+
if (~~global.debug > 1 && args && args[1]) { console.log(args[1]); };
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
const getComparison = (val) => {
|
|
38
|
+
return utilitas.isObject(val) && comparison.includes(Object.keys(val)[0])
|
|
39
|
+
? Object.keys(val)[0] : null;
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
const getOrder = (ord) => {
|
|
43
|
+
utilitas.assert(orders[ord], `Invalid order expression: '${ord}'.`, 400);
|
|
44
|
+
return orders[ord];
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
const distillArguments = (args) => {
|
|
48
|
+
Array.isArray(args?.['1']) && args['1'].map((v, k) => {
|
|
49
|
+
const cps = getComparison(v); cps && (args['1'][k] = v[cps]);
|
|
50
|
+
});
|
|
51
|
+
return args;
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
const rawQuery = async function() {
|
|
55
|
+
const conn = await init();
|
|
56
|
+
logCommand(arguments);
|
|
57
|
+
return await conn.query.apply(conn, [...arguments]);
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
const rawExecute = async function() {
|
|
61
|
+
const conn = await init();
|
|
62
|
+
logCommand(arguments);
|
|
63
|
+
return await conn.execute.apply(conn, [...arguments]);
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
const query = async function() {
|
|
67
|
+
return (await rawQuery.apply(null, [...distillArguments(arguments)]))[0];
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
const execute = async function() {
|
|
71
|
+
return (await rawExecute.apply(null, [...distillArguments(arguments)]))[0];
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
const defaultKey = (options) => {
|
|
75
|
+
return options && options.key ? options.key : fieldId;
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
const assertTable = (table, message = 'Table is required.', status = 500) => {
|
|
79
|
+
utilitas.assert(table, message, status);
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
const assertKeyValue = (key, value) => {
|
|
83
|
+
utilitas.assert(key, 'Key is required.', 500);
|
|
84
|
+
utilitas.assertSet(value, 'Value is required.', 500);
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
// const assertTableKeyValue = (table, key, value) => {
|
|
88
|
+
// assertTable(table);
|
|
89
|
+
// assertKeyValue(key, value);
|
|
90
|
+
// };
|
|
91
|
+
|
|
92
|
+
const assembleQuery = (table, options) => {
|
|
93
|
+
options = options || {};
|
|
94
|
+
assertTable(table);
|
|
95
|
+
const fields = [];
|
|
96
|
+
utilitas.ensureArray(options.fields).map((field) => {
|
|
97
|
+
fields.push(fieldNoQuote.includes(field) || options.noQuote
|
|
98
|
+
? field : `\`${field}\``);
|
|
99
|
+
});
|
|
100
|
+
if (!fields.length) { fields.push(fieldAny); }
|
|
101
|
+
return `SELECT ${fields.join(', ')} FROM \`${table}\``;
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
const rawAssembleKeyValue = (key, value, options) => {
|
|
105
|
+
options = options || {};
|
|
106
|
+
assertKeyValue(key, value);
|
|
107
|
+
let express = `${getComparison(value) || '='} ?`;
|
|
108
|
+
if (Array.isArray(value)) { express = 'IN (?)'; }
|
|
109
|
+
else if (value === null) { express = 'IS ?'; }
|
|
110
|
+
return `${options.prefix || ''}\`${key}\` ${express}`;
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
const assembleKeyValue = (key, value, options) => {
|
|
114
|
+
options = options || {};
|
|
115
|
+
options.prefix = ' WHERE ';
|
|
116
|
+
return rawAssembleKeyValue(key, value, options);
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
const assembleSet = (data, options) => {
|
|
120
|
+
options = options || {};
|
|
121
|
+
const [isArray, result] = [options.asArray || Array.isArray(data), []];
|
|
122
|
+
utilitas.ensureArray(data).map((item) => {
|
|
123
|
+
utilitas.assert(Object.keys(item).length, 'Fields are required.', 500);
|
|
124
|
+
let [sql, values, dupSql] = [[], [], []];
|
|
125
|
+
for (let k in item) { sql.push(`\`${k}\` = ?`); values.push(item[k]); }
|
|
126
|
+
if (options.upsert) {
|
|
127
|
+
for (let k in item) {
|
|
128
|
+
dupSql.push(`\`${k}\` = ?`); values.push(item[k]);
|
|
129
|
+
}
|
|
130
|
+
dupSql = ` ON DUPLICATE KEY UPDATE ${dupSql.join(', ')}`;
|
|
131
|
+
} else { dupSql = ''; }
|
|
132
|
+
result.push({
|
|
133
|
+
sql: `${options.prefix || ''}SET ${sql.join(', ')}${dupSql}`,
|
|
134
|
+
values, object: item,
|
|
135
|
+
});
|
|
136
|
+
});
|
|
137
|
+
return isArray ? result : result[0];
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
const assembleInsert = (table, data, options) => {
|
|
141
|
+
options = options || {};
|
|
142
|
+
assertTable(table);
|
|
143
|
+
options.prefix = `INSERT INTO \`${table}\` `;
|
|
144
|
+
return assembleSet(data, options);
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
const assembleUpdate = (table, data, options) => {
|
|
148
|
+
options = options || {};
|
|
149
|
+
assertTable(table);
|
|
150
|
+
options.prefix = `UPDATE \`${table}\` `;
|
|
151
|
+
return assembleSet(data, options);
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
const assembleDelete = (table) => {
|
|
155
|
+
assertTable(table);
|
|
156
|
+
return `DELETE FROM \`${table}\``;
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
const assembleTail = (options) => {
|
|
160
|
+
let sort = [];
|
|
161
|
+
utilitas.ensureArray(options?.order || []).map?.(x => {
|
|
162
|
+
const ord = utilitas.isObject(x) ? x : { [x]: '+' };
|
|
163
|
+
const key = Object.keys(ord)[0];
|
|
164
|
+
sort.push(`\`${key}\` ${getOrder(ord[key])}`);
|
|
165
|
+
});
|
|
166
|
+
return (sort.length ? ` ORDER BY ${sort.join(', ')}` : '')
|
|
167
|
+
+ (~~options?.limit ? ` LIMIT ${~~options.limit}` : '');
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
const queryAll = async (table, opts) => {
|
|
171
|
+
return await query(`${assembleQuery(table, opts)}${assembleTail(opts)}`);
|
|
172
|
+
};
|
|
173
|
+
|
|
174
|
+
const queryByKeyValue = async (table, key, value, options) => {
|
|
175
|
+
options = options || {};
|
|
176
|
+
const sql = assembleQuery(table, options)
|
|
177
|
+
+ assembleKeyValue(key, value)
|
|
178
|
+
+ assembleTail(options);
|
|
179
|
+
const resp = await query(sql, [value]);
|
|
180
|
+
return options.unique ? (resp && resp.length ? resp[0] : null) : resp;
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
const queryById = async (table, id, options) => {
|
|
184
|
+
options = options || {};
|
|
185
|
+
options.unique = !Array.isArray(id);
|
|
186
|
+
return await queryByKeyValue(table, defaultKey(options), id, options);
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
const insert = async (table, fields, options) => {
|
|
190
|
+
options = options || {};
|
|
191
|
+
let [isArray, key, ids, error, result]
|
|
192
|
+
= [Array.isArray(fields), defaultKey(options), [], [], []];
|
|
193
|
+
for (let item of assembleInsert(
|
|
194
|
+
table, fields, { ...options, asArray: true }
|
|
195
|
+
)) {
|
|
196
|
+
try {
|
|
197
|
+
const resp = await execute(item.sql, item.values);
|
|
198
|
+
resp.key = key;
|
|
199
|
+
resp.insertId = !resp.insertId && item.object[key]
|
|
200
|
+
? item.object[key] : resp.insertId;
|
|
201
|
+
result.push(resp);
|
|
202
|
+
ids.push(resp.insertId);
|
|
203
|
+
} catch (err) { error.push(err); }
|
|
204
|
+
}
|
|
205
|
+
if (!options.skipEcho && ids.length) {
|
|
206
|
+
result = await queryById(table, ids, options);
|
|
207
|
+
}
|
|
208
|
+
if (!isArray) {
|
|
209
|
+
if (error.length) { throw error[0]; }
|
|
210
|
+
return result.length ? result[0] : null;
|
|
211
|
+
}
|
|
212
|
+
return { error, result };
|
|
213
|
+
};
|
|
214
|
+
|
|
215
|
+
const upsert = async (table, fields, options) => {
|
|
216
|
+
return await insert(table, fields, { ...options || {}, upsert: true });
|
|
217
|
+
};
|
|
218
|
+
|
|
219
|
+
const countAll = async (table) => {
|
|
220
|
+
const sql = assembleQuery(table, { fields: fieldCount });
|
|
221
|
+
return (await query(sql))[0][fieldCount];
|
|
222
|
+
};
|
|
223
|
+
|
|
224
|
+
const countByKeyValue = async (table, key, value) => {
|
|
225
|
+
const sql = assembleQuery(table, { fields: fieldCount })
|
|
226
|
+
+ assembleKeyValue(key, value);
|
|
227
|
+
return (await query(sql, [value]))[0][fieldCount];
|
|
228
|
+
};
|
|
229
|
+
|
|
230
|
+
const updateByKeyValue = async (table, key, value, fields, options) => {
|
|
231
|
+
options = options || {};
|
|
232
|
+
assertTable(table);
|
|
233
|
+
let { sql, values } = assembleUpdate(table, fields);
|
|
234
|
+
sql += assembleKeyValue(key, value) + assembleTail(options);
|
|
235
|
+
const resp = await query(sql, [...values, value]);
|
|
236
|
+
return options.skipEcho
|
|
237
|
+
? resp : await queryByKeyValue(table, key, value, options);
|
|
238
|
+
};
|
|
239
|
+
|
|
240
|
+
const updateById = async (table, id, fields, options) => {
|
|
241
|
+
const resp = await updateByKeyValue(
|
|
242
|
+
table, defaultKey(options), id, fields, options
|
|
243
|
+
);
|
|
244
|
+
return Array.isArray(id) ? resp : (resp && resp.length ? resp[0] : null);
|
|
245
|
+
};
|
|
246
|
+
|
|
247
|
+
const deleteByKeyValue = async (table, key, value, options) => {
|
|
248
|
+
const sql = assembleDelete(table)
|
|
249
|
+
+ assembleKeyValue(key, value)
|
|
250
|
+
+ assembleTail(options);
|
|
251
|
+
return await query(sql, [value]);
|
|
252
|
+
};
|
|
253
|
+
|
|
254
|
+
const deleteById = async (table, id, options) => {
|
|
255
|
+
return await deleteByKeyValue(table, defaultKey(options), id);
|
|
256
|
+
};
|
|
257
|
+
|
|
258
|
+
const deleteAll = async (table, options) => {
|
|
259
|
+
utilitas.assert(options && options.force,
|
|
260
|
+
"Option 'force' is required.", 500);
|
|
261
|
+
return await execute(assembleDelete(table));
|
|
262
|
+
};
|
|
263
|
+
|
|
264
|
+
module.exports = {
|
|
265
|
+
assembleInsert,
|
|
266
|
+
assembleQuery,
|
|
267
|
+
assembleSet,
|
|
268
|
+
assembleTail,
|
|
269
|
+
assembleUpdate,
|
|
270
|
+
countAll,
|
|
271
|
+
countByKeyValue,
|
|
272
|
+
deleteAll,
|
|
273
|
+
deleteById,
|
|
274
|
+
deleteByKeyValue,
|
|
275
|
+
end,
|
|
276
|
+
execute,
|
|
277
|
+
init,
|
|
278
|
+
insert,
|
|
279
|
+
query,
|
|
280
|
+
queryAll,
|
|
281
|
+
queryById,
|
|
282
|
+
queryByKeyValue,
|
|
283
|
+
rawAssembleKeyValue,
|
|
284
|
+
rawExecute,
|
|
285
|
+
rawQuery,
|
|
286
|
+
updateById,
|
|
287
|
+
updateByKeyValue,
|
|
288
|
+
upsert,
|
|
289
|
+
};
|
|
290
|
+
|
|
291
|
+
const utilitas = require('./utilitas');
|