@maiyunnet/kebab 2.0.2 → 2.0.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.
Files changed (49) hide show
  1. package/index.js +1 -1
  2. package/lib/sql.js +1 -3
  3. package/lib/text.js +5 -1
  4. package/package.json +1 -1
  5. package/tsconfig.json +1 -1
  6. package/index.ts +0 -33
  7. package/lib/buffer.ts +0 -152
  8. package/lib/captcha.ts +0 -63
  9. package/lib/consistent.ts +0 -219
  10. package/lib/core.ts +0 -880
  11. package/lib/crypto.ts +0 -384
  12. package/lib/db.ts +0 -719
  13. package/lib/dns.ts +0 -405
  14. package/lib/fs.ts +0 -527
  15. package/lib/jwt.ts +0 -276
  16. package/lib/kv.ts +0 -1489
  17. package/lib/lan.ts +0 -87
  18. package/lib/net/formdata.ts +0 -166
  19. package/lib/net/request.ts +0 -150
  20. package/lib/net/response.ts +0 -59
  21. package/lib/net.ts +0 -662
  22. package/lib/s3.ts +0 -235
  23. package/lib/scan.ts +0 -364
  24. package/lib/session.ts +0 -230
  25. package/lib/sql.ts +0 -1151
  26. package/lib/ssh/sftp.ts +0 -508
  27. package/lib/ssh/shell.ts +0 -123
  28. package/lib/ssh.ts +0 -191
  29. package/lib/text.ts +0 -615
  30. package/lib/time.ts +0 -254
  31. package/lib/ws.ts +0 -523
  32. package/lib/zip.ts +0 -447
  33. package/lib/zlib.ts +0 -350
  34. package/main.ts +0 -27
  35. package/sys/child.ts +0 -678
  36. package/sys/cmd.ts +0 -225
  37. package/sys/ctr.ts +0 -904
  38. package/sys/master.ts +0 -355
  39. package/sys/mod.ts +0 -1871
  40. package/sys/route.ts +0 -1113
  41. package/types/index.d.ts +0 -283
  42. package/www/example/ctr/main.ts +0 -9
  43. package/www/example/ctr/middle.ts +0 -26
  44. package/www/example/ctr/test.ts +0 -3218
  45. package/www/example/mod/test.ts +0 -47
  46. package/www/example/mod/testdata.ts +0 -30
  47. package/www/example/ws/mproxy.ts +0 -16
  48. package/www/example/ws/rproxy.ts +0 -14
  49. package/www/example/ws/test.ts +0 -36
package/lib/sql.ts DELETED
@@ -1,1151 +0,0 @@
1
- /**
2
- * Project: Kebab, User: JianSuoQiYue
3
- * Date: 2019-5-27 20:18:50
4
- * Last: 2020-3-29 19:37:25, 2022-07-24 22:38:11, 2023-5-24 18:49:18, 2023-6-13 22:20:21, 2023-12-11 13:58:54, 2023-12-14 13:14:40, 2023-12-21 00:04:40, 2024-4-11 19:29:29, 2024-9-2 17:15:28
5
- */
6
-
7
- import * as lText from '~/lib/text';
8
- import * as lCore from '~/lib/core';
9
- // --- 第三方 ---
10
- import * as mysql2 from 'mysql2/promise';
11
- // --- 库和定义 ---
12
- import * as ctr from '~/sys/ctr';
13
- import * as types from '~/types';
14
-
15
- /** --- filed 用 token --- */
16
- let columnToken = '';
17
-
18
- export class Sql {
19
-
20
- /** --- 前置 --- */
21
- private readonly _pre: string = '';
22
-
23
- /** --- 预拼装 Sql 数组 --- */
24
- private _sql: string[] = [];
25
-
26
- /** --- 所有 data 数据 --- */
27
- private _data: types.DbValue[] = [];
28
-
29
- // --- 实例化 ---
30
- public constructor(pre?: string, opt: {
31
- 'data'?: types.DbValue[];
32
- 'sql'?: string[];
33
- } = {}) {
34
- this._pre = pre ?? '';
35
- if (opt.data) {
36
- this._data = opt.data;
37
- }
38
- if (opt.sql) {
39
- this._sql = opt.sql;
40
- }
41
- }
42
-
43
- // --- 前导 ---
44
-
45
- /**
46
- * --- 插入数据前导 ---
47
- * @param table 表名
48
- */
49
- public insert(table: string): this {
50
- this._data = [];
51
- const sql = 'INSERT INTO ' + this.field(table, this._pre);
52
- this._sql = [sql];
53
- return this;
54
- }
55
-
56
- /**
57
- * --- 替换已经存在的唯一索引数据,不存在则插入 ---
58
- * @param table 表名
59
- */
60
- public replace(table: string): this {
61
- this._data = [];
62
- const sql = 'REPLACE INTO ' + this.field(table, this._pre);
63
- this._sql = [sql];
64
- return this;
65
- }
66
-
67
- /**
68
- * --- 实际插入数据的数据 ---
69
- * @param cs [] 数据列或字段列
70
- * @param vs [] | [][] 数据
71
- */
72
- public values(
73
- cs: string[] | Record<string, types.DbValue>,
74
- vs: types.DbValue[] | types.DbValue[][] = []
75
- ): this {
76
- let sql = ' (';
77
- if (Array.isArray(cs)) {
78
- // --- ['id', 'name'], [['1', 'wow'], ['2', 'oh']] ---
79
- // --- ['id', 'name'], ['1', 'wow'] ---
80
- for (const i of cs) {
81
- sql += this.field(i) + ', ';
82
- }
83
- sql = sql.slice(0, -2) + ') VALUES ';
84
- if (!Array.isArray(vs[0])) {
85
- vs = [vs];
86
- }
87
- // --- INSERT INTO xx (id, name) VALUES (?, ?) ---
88
- // --- INSERT INTO xx (id, name) VALUES (?, ?), (?, ?) ---
89
- for (const v of vs as types.DbValue[][]) {
90
- sql += '(';
91
- for (const v1 of v) {
92
- // --- v1 是项目值,如 {'x': 1, 'y': 2}, 'string', 0 ---
93
- if (v1 === undefined || Number.isNaN(v1)) {
94
- // --- 异常情况 ---
95
- lCore.log({
96
- 'path': '',
97
- 'urlFull': '',
98
- 'hostname': '',
99
- 'req': null,
100
- 'get': {},
101
- 'cookie': {},
102
- 'headers': {}
103
- }, '(sql.values) value error', '-error').catch(() => {
104
- //
105
- });
106
- sql += `'', `;
107
- }
108
- else if (v1 === null) {
109
- sql += 'NULL, ';
110
- }
111
- else if (typeof v1 === 'string' || typeof v1 === 'number') {
112
- sql += '?, ';
113
- this._data.push(v1);
114
- }
115
- else if (Array.isArray(v1)) {
116
- if (
117
- v1[0]?.[0]?.x === undefined && typeof v1[0] === 'string' &&
118
- v1[0].includes('(') && v1[0].includes(')')
119
- ) {
120
- // --- v1: ['POINT(?)', ['20']] ---
121
- sql += this.field(v1[0]) + ', ';
122
- if (v1[1]) {
123
- this._data.push(...v1[1]);
124
- }
125
- }
126
- else if (v1[0]?.[0]?.y !== undefined) {
127
- // --- v1: [[{'x': 1, 'y': 2}, { ... }], [{ ... }, { ... }]] ---
128
- sql += 'ST_POLYGONFROMTEXT(?), ';
129
- this._data.push(`POLYGON(${v1.map((item) => {
130
- return `(${item.map((it: Record<string, string | number>) => {
131
- return `${it.x} ${it.y}`;
132
- }).join(', ')})`;
133
- }).join(', ')})`);
134
- }
135
- else {
136
- // --- v1: json ---
137
- sql += '?, ';
138
- this._data.push(lText.stringifyJson(v1));
139
- }
140
- }
141
- else if (v1.x !== undefined) {
142
- if (v1.y !== undefined) {
143
- // --- v1: {'x': 1, 'y': 2} ---
144
- sql += 'ST_POINTFROMTEXT(?), ';
145
- this._data.push(`POINT(${v1.x} ${v1.y})`);
146
- }
147
- else {
148
- // --- v1: json ---
149
- sql += '?, ';
150
- this._data.push(lText.stringifyJson(v1));
151
- }
152
- }
153
- else if (v1 instanceof Buffer) {
154
- // --- Buffer ---
155
- sql += '?, ';
156
- this._data.push(v);
157
- }
158
- else if (this._isField(v1)) {
159
- // --- 3 ---
160
- sql += this.field(v1.value) + ', ';
161
- }
162
- else {
163
- // --- json ---
164
- sql += '?, ';
165
- this._data.push(lText.stringifyJson(v1));
166
- }
167
- }
168
- sql = sql.slice(0, -2) + '), ';
169
- }
170
- sql = sql.slice(0, -2);
171
- }
172
- else {
173
- // --- {'id': '1', 'name': 'wow'} ---
174
- // --- INSERT INTO xx (id, name) VALUES (?, ?) ---
175
- let values = '';
176
- for (const k in cs) {
177
- const v = cs[k];
178
- sql += this.field(k) + ', ';
179
- if (v === undefined || Number.isNaN(v)) {
180
- // --- 异常情况 ---
181
- lCore.log({
182
- 'path': '',
183
- 'urlFull': '',
184
- 'hostname': '',
185
- 'req': null,
186
- 'get': {},
187
- 'cookie': {},
188
- 'headers': {}
189
- }, '(sql.values) value error', '-error').catch(() => {
190
- //
191
- });
192
- values += `'', `;
193
- }
194
- else if (v === null) {
195
- values += 'NULL, ';
196
- }
197
- else if (typeof v === 'string' || typeof v === 'number') {
198
- values += '?, ';
199
- this._data.push(v);
200
- }
201
- else if (Array.isArray(v)) {
202
- if (
203
- v[0]?.[0]?.x === undefined && typeof v[0] === 'string' &&
204
- v[0].includes('(') && v[0].includes(')')
205
- ) {
206
- // --- v: ['POINT(?)', ['20']] ---
207
- values += this.field(v[0]) + ', ';
208
- if (v[1] !== undefined) {
209
- this._data.push(...v[1]);
210
- }
211
- }
212
- else if (v[0]?.[0]?.y !== undefined) {
213
- // --- v: [[{'x': 1, 'y': 2}, { ... }], [{ ... }, { ... }]] ---
214
- values += 'ST_POLYGONFROMTEXT(?), ';
215
- this._data.push(`POLYGON(${v.map((item) => {
216
- return `(${item.map((it: Record<string, string | number>) => {
217
- return `${it.x} ${it.y}`;
218
- }).join(', ')})`;
219
- }).join(', ')})`);
220
- }
221
- else {
222
- // --- v: json ---
223
- values += '?, ';
224
- this._data.push(lText.stringifyJson(v));
225
- }
226
- }
227
- else if (v.x !== undefined) {
228
- if (v.y !== undefined) {
229
- // --- v: {'x': 1, 'y': 2} ---
230
- values += 'ST_POINTFROMTEXT(?), ';
231
- this._data.push(`POINT(${v.x} ${v.y})`);
232
- }
233
- else {
234
- // --- v: json ---
235
- values += '?, ';
236
- this._data.push(lText.stringifyJson(v));
237
- }
238
- }
239
- else if (v instanceof Buffer) {
240
- // --- Buffer ---
241
- values += '?, ';
242
- this._data.push(v);
243
- }
244
- else if (this._isField(v)) {
245
- // --- 3 ---
246
- values += this.field(v.value) + ', ';
247
- }
248
- else {
249
- // --- json ---
250
- values += '?, ';
251
- this._data.push(lText.stringifyJson(v));
252
- }
253
- }
254
- sql = sql.slice(0, -2) + ') VALUES (' + values.slice(0, -2) + ')';
255
- }
256
- this._sql.push(sql);
257
- return this;
258
- }
259
-
260
- /**
261
- * --- 不存在则插入,衔接在 insert 之后 ---
262
- * @param table 表名
263
- * @param insert {'xx': 'xx', 'xx': 'xx'}
264
- * @param where [{'xx': 'xx', 'xx': 'xx'}], {'xx': 'xx'}
265
- */
266
- public notExists(
267
- table: string, insert: Record<string, types.DbValue>,
268
- where: string | types.Json
269
- ): this {
270
- let sql = '(';
271
- const values = [];
272
- for (const field in insert) {
273
- const val = insert[field];
274
- sql += this.field(field) + ', ';
275
- values.push(val);
276
- }
277
- sql = sql.slice(0, -2) + ') SELECT ';
278
- for (const value of values) {
279
- if (Array.isArray(value)) {
280
- sql += value[0] + ', ';
281
- this._data.push(...value[1]);
282
- }
283
- else {
284
- sql += '?, ';
285
- this._data.push(value);
286
- }
287
- }
288
- sql = sql.slice(0, -2) + ' FROM DUAL WHERE NOT EXISTS (SELECT `id` FROM ' + this.field(table, this._pre) + ' WHERE ' + this._whereSub(where) + ')';
289
- this._sql.push(sql);
290
- return this;
291
- }
292
-
293
- /**
294
- * --- 当不能 insert 时,update(仅能配合 insert 方法用) ---
295
- * @param s 更新数据
296
- */
297
- public duplicate(s: types.Json): this {
298
- if (Array.isArray(s) ? s.length : Object.keys(s).length) {
299
- const sql = ' ON DUPLICATE KEY UPDATE ' + this._updateSub(s);
300
- this._sql.push(sql);
301
- }
302
- return this;
303
- }
304
-
305
- /**
306
- * --- '*', 'xx' ---
307
- * @param c 字段字符串或字段数组
308
- * @param f 表,允许多张表
309
- */
310
- public select(c: string | Array<string | Array<string | string[]>>, f: string | string[]): this {
311
- this._data = [];
312
- let sql = 'SELECT ';
313
- if (typeof c === 'string') {
314
- sql += this.field(c);
315
- }
316
- else {
317
- // --- c: ['id', 'name'] ---
318
- for (const i of c) {
319
- if (Array.isArray(i)) {
320
- // --- i: ['xx', ['x']] ---
321
- sql += this.field(i[0]) + ', ';
322
- this._data.push(...i[1]);
323
- }
324
- else {
325
- sql += this.field(i) + ', ';
326
- }
327
- }
328
- sql = sql.slice(0, -2);
329
- }
330
- sql += ' FROM ';
331
- if (typeof f === 'string') {
332
- sql += this.field(f, this._pre);
333
- }
334
- else {
335
- // --- f: ['user', 'order'] ---
336
- for (const i of f) {
337
- sql += this.field(i, this._pre) + ', ';
338
- }
339
- sql = sql.slice(0, -2);
340
- }
341
- this._sql = [sql];
342
- return this;
343
- }
344
-
345
- /**
346
- * --- UPDATE SQL 方法 ---
347
- * @param f 表名
348
- * @param s 设定 update 的值
349
- */
350
- public update(f: string, s: types.Json): this {
351
- this._data = [];
352
- const sql = `UPDATE ${this.field(f, this._pre)} SET ${this._updateSub(s)}`;
353
- this._sql = [sql];
354
- return this;
355
- }
356
-
357
- private _updateSub(s: types.Json): string {
358
- /*
359
- [
360
- ['total', '+', '1'], // 1, '1' 可能也是 1 数字类型
361
- {
362
- 'type': '6', // 2
363
- 'type': column('type2'), // 3
364
- // 'type': ['type3'], // 4 - 此写法已被禁止,请用 (3) 代替
365
- 'type': ['(CASE `id` WHEN 1 THEN ? WHEN 2 THEN ? END)', ['val1', 'val2']], // 5
366
- 'point': { 'x': 0, 'y': 0 }, // 6
367
- 'polygon': [ [ { 'x': 0, 'y': 0 }, { ... } ], [ ... ] ], // 7
368
- 'json': { 'a': 1, 'b': { 'c': 2 }, 'c': [ { 'c': 2 } ] }, // 8 - 对象类 json,可能为空对象
369
- 'json2': ['abc'] // 9 - 数组类 json,可能为空数组
370
- }
371
- ]
372
- */
373
- s = aoMix(s);
374
- let sql = '';
375
- for (const k in s) {
376
- const v = s[k];
377
- if (/^[0-9]+$/.test(k)) {
378
- // --- 1 ---
379
- const nv = v[2];
380
- const isf = this._isField(nv);
381
- if (isf) {
382
- if (v[1] === '=') {
383
- sql += this.field(v[0]) + ' = ' + this.field(nv.value) + ', ';
384
- }
385
- else {
386
- sql += this.field(v[0]) + ' = ' + this.field(v[0]) + ' ' + v[1] + ' ' + this.field(nv.value) + ', ';
387
- }
388
- }
389
- else {
390
- if (v[1] === '=') {
391
- sql += this.field(v[0]) + ' = ?, ';
392
- }
393
- else {
394
- sql += this.field(v[0]) + ' = ' + this.field(v[0]) + ' ' + v[1] + ' ?, ';
395
- }
396
- this._data.push(nv);
397
- }
398
- }
399
- else {
400
- // --- 2, 3, 4, 5, 6, 7, 8 ---
401
- sql += this.field(k) + ' = ';
402
- if (v === undefined || Number.isNaN(v)) {
403
- // --- 异常情况 ---
404
- lCore.log({
405
- 'path': '',
406
- 'urlFull': '',
407
- 'hostname': '',
408
- 'req': null,
409
- 'get': {},
410
- 'cookie': {},
411
- 'headers': {}
412
- }, '(sql._updateSub) value error, key: ' + k, '-error').catch(() => {
413
- //
414
- });
415
- sql += '"", ';
416
- }
417
- else if (v === null) {
418
- sql += 'NULL, ';
419
- }
420
- else if (typeof v === 'string' || typeof v === 'number') {
421
- // --- 2 ---
422
- sql += '?, ';
423
- this._data.push(v);
424
- }
425
- else if (Array.isArray(v)) {
426
- if (
427
- v[0]?.[0]?.x === undefined && typeof v[0] === 'string' &&
428
- v[0].includes('(') && v[0].includes(')')
429
- ) {
430
- // --- 4, 5: ['(CASE `id` WHEN 1 THEN ? WHEN 2 THEN ? END)', ['val1', 'val2']] ---
431
- sql += this.field(v[0]) + ', ';
432
- if (v[1] !== undefined) {
433
- this._data.push(...v[1]);
434
- }
435
- }
436
- else if (v[0]?.[0]?.y !== undefined) {
437
- // --- 7 ---
438
- sql += 'ST_POLYGONFROMTEXT(?), ';
439
- this._data.push(`POLYGON(${v.map((item) => {
440
- return `(${item.map((it: Record<string, string | number>) => {
441
- return `${it.x} ${it.y}`;
442
- }).join(', ')})`;
443
- }).join(', ')})`);
444
- }
445
- else {
446
- // --- v: json ---
447
- sql += '?, ';
448
- this._data.push(lText.stringifyJson(v));
449
- }
450
- }
451
- else if (v.x !== undefined) {
452
- if (v.y !== undefined) {
453
- // --- 6: v: {'x': 1, 'y': 2} ---
454
- sql += 'ST_POINTFROMTEXT(?), ';
455
- this._data.push(`POINT(${v.x} ${v.y})`);
456
- }
457
- else {
458
- // --- v: json ---
459
- if (this._isField(v)) {
460
- // --- 3 ---
461
- sql += this.field(v.value) + ', ';
462
- }
463
- else {
464
- // --- 8 ---
465
- sql += '?, ';
466
- this._data.push(lText.stringifyJson(v));
467
- }
468
- }
469
- }
470
- else if (v instanceof Buffer) {
471
- // --- Buffer ---
472
- sql += '?, ';
473
- this._data.push(v);
474
- }
475
- else if (this._isField(v)) {
476
- // --- 3 ---
477
- sql += this.field(v.value) + ', ';
478
- }
479
- else {
480
- // --- json ---
481
- sql += '?, ';
482
- this._data.push(lText.stringifyJson(v));
483
- }
484
- }
485
- }
486
- sql = sql.slice(0, -2);
487
- return sql;
488
- }
489
-
490
- /**
491
- * --- 'xx' ---
492
- * @param f 表名
493
- */
494
- public delete(f: string): this {
495
- this._data = [];
496
- this._sql = ['DELETE FROM ' + this.field(f, this._pre)];
497
- return this;
498
- }
499
-
500
- /**
501
- * --- 联查另一个 sql 对象 ---
502
- * @param sql sql 对象
503
- * @param type 类型
504
- */
505
- public union(lsql: Sql, type: string = ''): this {
506
- this._data = this._data.concat(lsql.getData());
507
- this._sql.push(' UNION ' + (type ? type + ' ' : ''));
508
- this._sql.push(lsql.getSql());
509
- return this;
510
- }
511
-
512
- /**
513
- * --- 所有联查另一个 sql 对象 ---
514
- * @param sql sql 对象
515
- */
516
- public unionAll(lsql: Sql): this {
517
- return this.union(lsql, 'ALL');
518
- }
519
-
520
- /**
521
- * --- join 方法 ---
522
- * @param f 表名
523
- * @param s ON 信息
524
- * @param type 类型
525
- * @param suf 表后缀
526
- * @param pre 表前缀,仅在 join 非默认表前缀时填写
527
- */
528
- public join(f: string, s: types.Json = [], type: string = 'INNER', suf: string = '', pre: string = ''): this {
529
- let field = this.field(f, pre || this._pre, suf ? ('#' + suf) : '');
530
- if (pre) {
531
- // --- 处理不同 pre 的 as 前缀问题 ---
532
- field = field.replace(new RegExp(`AS \`${pre}(.+?)\``), `AS \`${this._pre}$1\``);
533
- }
534
- let sql = ' ' + type + ' JOIN ' + field;
535
- if (Array.isArray(s) ? s.length : Object.keys(s).length) {
536
- sql += ' ON ' + this._whereSub(s);
537
- }
538
- this._sql.push(sql);
539
- return this;
540
- }
541
-
542
- /**
543
- * --- left join 方法 ---
544
- * @param f 表名
545
- * @param s ON 信息
546
- * @param suf 表后缀
547
- * @param pre 表前缀,仅在 join 非默认表前缀时填写
548
- */
549
- public leftJoin(f: string, s: types.Json = [], suf: string = '', pre: string = ''): this {
550
- return this.join(f, s, 'LEFT', suf, pre);
551
- }
552
-
553
- /**
554
- * --- right join 方法 ---
555
- * @param f 表名
556
- * @param s ON 信息
557
- * @param suf 表后缀
558
- * @param pre 表前缀,仅在 join 非默认表前缀时填写
559
- */
560
- public rightJoin(f: string, s: types.Json = [], suf: string = '', pre: string = ''): this {
561
- return this.join(f, s, 'RIGHT', suf, pre);
562
- }
563
-
564
- /**
565
- * --- inner join 方法 ---
566
- * @param f 表名
567
- * @param s ON 信息
568
- * @param suf 表后缀
569
- * @param pre 表前缀,仅在 join 非默认表前缀时填写
570
- */
571
- public innerJoin(f: string, s: types.Json = [], suf: string = '', pre: string = ''): this {
572
- return this.join(f, s, 'INNER', suf, pre);
573
- }
574
-
575
- /**
576
- * --- full join 方法 ---
577
- * @param f 表名
578
- * @param s ON 信息
579
- * @param suf 表后缀
580
- * @param pre 表前缀,仅在 join 非默认表前缀时填写
581
- */
582
- public fullJoin(f: string, s: types.Json = [], suf: string = '', pre: string = ''): this {
583
- return this.join(f, s, 'FULL', suf, pre);
584
- }
585
-
586
- /**
587
- * --- cross join 方法 ---
588
- * @param f 表名
589
- * @param s ON 信息
590
- * @param suf 表后缀
591
- * @param pre 表前缀,仅在 join 非默认表前缀时填写
592
- */
593
- public crossJoin(f: string, s: types.Json = [], suf: string = '', pre: string = ''): this {
594
- return this.join(f, s, 'CROSS', suf, pre);
595
- }
596
-
597
- /**
598
- * --- having 后置筛选器,用法类似 where ---
599
- */
600
- public having(s: string | types.Json = ''): this {
601
- if (typeof s === 'string') {
602
- // --- string ---
603
- if (s !== '') {
604
- this._sql.push(' HAVING ' + s);
605
- }
606
- }
607
- else {
608
- // --- array ---
609
- if (s.length) {
610
- const whereSub = this._whereSub(s);
611
- if (whereSub !== '') {
612
- this._sql.push(' HAVING ' + whereSub);
613
- }
614
- }
615
- }
616
- return this;
617
- }
618
-
619
- /** --- where 的 data 的开始处和结束处 --- */
620
- private _whereDataPosition = [0, 0];
621
-
622
- /**
623
- * --- 筛选器 ---
624
- * --- 1. 'city': 'bj', 'type': '2' ---
625
- * --- 2. ['type', '>', '1'] ---
626
- * --- 3. ['type', 'in', ['1', '2']] ---
627
- * --- 4. 'type': ['1', '2'] ---
628
- * --- 5. '$or': [{'city': 'bj'}, {'city': 'sh'}, [['age', '>', '10']]], 'type': '2' ---
629
- * --- 6. 'city_in': column('city_out') ---
630
- * --- 7. ['JSON_CONTAINS(`uid`, ?)', ['hello']] ---
631
- * @param s 筛选数据
632
- */
633
- public where(s: string | types.Json): this {
634
- this._whereDataPosition[0] = this._data.length;
635
- if (typeof s === 'string') {
636
- // --- string ---
637
- if (s !== '') {
638
- this._sql.push(' WHERE ' + s);
639
- this._whereDataPosition[1] = this._data.length;
640
- }
641
- }
642
- else {
643
- // --- array ---
644
- let go: boolean = false;
645
- if (Array.isArray(s)) {
646
- if (s.length) {
647
- go = true;
648
- }
649
- }
650
- else {
651
- if (Object.keys(s).length) {
652
- go = true;
653
- }
654
- }
655
- if (go) {
656
- const whereSub = this._whereSub(s);
657
- if (whereSub !== '') {
658
- this._sql.push(' WHERE ' + whereSub);
659
- }
660
- }
661
- this._whereDataPosition[1] = this._data.length;
662
- }
663
- return this;
664
- }
665
-
666
- private _whereSub(s: types.Json, data?: any[]): string {
667
- if (!data) {
668
- data = this._data;
669
- }
670
- s = aoMix(s);
671
- let sql = '';
672
- for (const k in s) {
673
- const v = s[k];
674
- if (/^[0-9]+$/.test(k)) {
675
- // --- 2, 3, 7 ---
676
- if (v[2] === undefined) {
677
- // --- 7 ---
678
- sql += this.field(v[0]) + ' AND ';
679
- if (v[1] !== undefined) {
680
- data.push(...v[1]);
681
- }
682
- }
683
- else if (v[2] === null) {
684
- // --- 3: null ---
685
- let opera = v[1];
686
- if (opera === '!=' || opera === '!==' || opera === '<>') {
687
- opera = 'IS NOT';
688
- }
689
- else if (opera === '=' || opera === '==' || opera === '===') {
690
- opera = 'IS';
691
- }
692
- else {
693
- opera = opera.toUpperCase();
694
- }
695
- sql += this.field(v[0]) + ' ' + opera + ' NULL AND ';
696
- }
697
- else if (Array.isArray(v[2])) {
698
- // --- 3 ---
699
- sql += this.field(v[0]) + ' ' + v[1].toUpperCase() + ' (';
700
- for (const v1 of v[2]) {
701
- sql += '?, ';
702
- data.push(v1);
703
- }
704
- sql = sql.slice(0, -2) + ') AND ';
705
- }
706
- else {
707
- // --- 2, 6 ---
708
- const nv = v[2];
709
- const isf = this._isField(nv);
710
- if (isf) {
711
- // --- 6. field ---
712
- sql += this.field(v[0]) + ' ' + v[1] + ' ' + this.field(nv.value) + ' AND ';
713
- }
714
- else {
715
- sql += this.field(v[0]) + ' ' + v[1] + ' ? AND ';
716
- data.push(nv);
717
- }
718
- }
719
- }
720
- else {
721
- // --- 1, 4, 5, 6 ---
722
- if (k.startsWith('$')) {
723
- // --- 5 - '$or': [{'city': 'bj'}, {'city': 'sh'}] ---
724
- const sp = ' ' + k.slice(1).split('-')[0].toUpperCase() + ' ';
725
- sql += '(';
726
- for (let v1 of v) {
727
- // --- v1 是 {'city': 'bj'} ---
728
- v1 = aoMix(v1);
729
- if (Object.keys(v1).length > 1) {
730
- sql += '(' + this._whereSub(v1, data) + ')' + sp;
731
- }
732
- else {
733
- sql += this._whereSub(v1, data) + sp;
734
- }
735
- }
736
- sql = sql.slice(0, -sp.length) + ') AND ';
737
- }
738
- else {
739
- // --- 1, 4, 6 ---
740
- if (v === null) {
741
- sql += this.field(k) + ' IS NULL AND ';
742
- }
743
- else if (typeof v === 'string' || typeof v === 'number') {
744
- // --- 1 ---
745
- sql += this.field(k) + ' = ? AND ';
746
- data.push(v);
747
- }
748
- else if (this._isField(v)) {
749
- // --- 6 ---
750
- sql += this.field(k) + ' = ' + this.field(v.value) + ' AND ';
751
- }
752
- else {
753
- // --- 4 - 'type': ['1', '2'] ---
754
- if (v.length > 0) {
755
- sql += this.field(k) + ' IN (';
756
- for (const v1 of v) {
757
- sql += '?, ';
758
- data.push(v1);
759
- }
760
- sql = sql.slice(0, -2) + ') AND ';
761
- }
762
- else {
763
- sql += this.field(k) + ' IN (NULL) AND ';
764
- }
765
- }
766
- }
767
- }
768
- }
769
- if (sql === '') {
770
- return '';
771
- }
772
- return sql.slice(0, -5);
773
- }
774
-
775
- /**
776
- * --- ORDER BY ---
777
- * @param c 字段字符串或数组
778
- * @param d 排序规则
779
- */
780
- public by(c: string | Array<string | string[]>, d: 'DESC' | 'ASC' = 'DESC'): this {
781
- let sql: string = ' ORDER BY ';
782
- if (typeof c === 'string') {
783
- sql += this.field(c) + ' ' + d;
784
- }
785
- else {
786
- for (const v of c) {
787
- if (typeof v === 'string' || typeof v === 'number') {
788
- sql += this.field(v) + ' ' + d + ', ';
789
- }
790
- else {
791
- sql += this.field(v[0]) + ' ' + v[1] + ', ';
792
- }
793
- }
794
- sql = sql.slice(0, -2);
795
- }
796
- this._sql.push(sql);
797
- return this;
798
- }
799
-
800
- /**
801
- * --- GROUP BY ---
802
- * @param c 字段字符串或数组
803
- */
804
- public group(c: string | string[]): this {
805
- let sql = ' GROUP BY ';
806
- if (typeof c === 'string') {
807
- sql += this.field(c);
808
- }
809
- else {
810
- for (const v of c) {
811
- sql += this.field(v) + ', ';
812
- }
813
- sql = sql.slice(0, -2);
814
- }
815
- this._sql.push(sql);
816
- return this;
817
- }
818
-
819
- /**
820
- * --- LIMIT ---
821
- * @param a 起始
822
- * @param b 长度
823
- */
824
- public limit(a: number, b: number = 0): this {
825
- this._sql.push(' LIMIT ' + a.toString() + (b > 0 ? ', ' + b.toString() : ''));
826
- return this;
827
- }
828
-
829
- /**
830
- * --- 追加消极锁,通常不建议使用 ---
831
- */
832
- public lock(): this {
833
- this._sql.push(' FOR UPDATE');
834
- return this;
835
- }
836
-
837
- /**
838
- * --- 创建一个本对象的一个新的 sql 对象拷贝 ---
839
- * @param f 可为空,可设置新对象的 table 名变化
840
- */
841
- public copy(f?: string | string[], opt: {
842
- 'where'?: string | types.Json;
843
- } = {}): Sql {
844
- const sql: string[] = lCore.clone(this._sql);
845
- const data: any[] = lCore.clone(this._data);
846
- if (opt.where !== undefined) {
847
- if (typeof opt.where === 'string') {
848
- // --- string ---
849
- for (let i = 0; i < sql.length; ++i) {
850
- if (!sql[i].startsWith(' WHERE ')) {
851
- continue;
852
- }
853
- sql[i] = opt.where ? (' WHERE ' + opt.where) : '';
854
- data.splice(
855
- this._whereDataPosition[0],
856
- this._whereDataPosition[1] - this._whereDataPosition[0]
857
- );
858
- break;
859
- }
860
- }
861
- else {
862
- // --- array ---
863
- let go: boolean = false;
864
- if (Array.isArray(opt.where)) {
865
- if (opt.where.length) {
866
- go = true;
867
- }
868
- }
869
- else {
870
- if (Object.keys(opt.where).length) {
871
- go = true;
872
- }
873
- }
874
- // --- 找到原来的 where ---
875
- for (let i = 0; i < sql.length; ++i) {
876
- if (!sql[i].startsWith(' WHERE ')) {
877
- continue;
878
- }
879
- if (go) {
880
- // --- 修改 where ---
881
- const d: any[] = [];
882
- sql[i] = ' WHERE ' + this._whereSub(opt.where, d);
883
- data.splice(
884
- this._whereDataPosition[0],
885
- this._whereDataPosition[1] - this._whereDataPosition[0],
886
- ...d
887
- );
888
- }
889
- else {
890
- // --- 清除 where ---
891
- sql.splice(i, 1);
892
- data.splice(
893
- this._whereDataPosition[0],
894
- this._whereDataPosition[1] - this._whereDataPosition[0]
895
- );
896
- }
897
- break;
898
- }
899
- }
900
- }
901
- // --- 替换表名 ---
902
- if (f && sql[0]) {
903
- let table = '';
904
- if (typeof f === 'string') {
905
- table = this.field(f, this._pre);
906
- }
907
- else {
908
- // --- f: ['user', 'order'] ---
909
- for (const i of f) {
910
- table += this.field(i, this._pre) + ', ';
911
- }
912
- table = table.slice(0, -2);
913
- }
914
- sql[0] = sql[0].replace(/FROM [`\w, ]+/, 'FROM ' + table);
915
- }
916
- return get(this.getPre(), {
917
- 'data': data,
918
- 'sql': sql
919
- });
920
- }
921
-
922
- // --- 操作 ---
923
-
924
- /**
925
- * --- 获取 sql 语句 ---
926
- */
927
- public getSql(): string {
928
- return this._sql.join('');
929
- }
930
-
931
- /**
932
- * --- 获取全部 data ---
933
- */
934
- public getData(): types.DbValue[] {
935
- return this._data;
936
- }
937
-
938
- /**
939
- * --- 获取定义的 pre ---
940
- */
941
- public getPre(): string {
942
- return this._pre;
943
- }
944
-
945
- /**
946
- * --- 获取带 data 的 sql 语句 ---
947
- * @param sql
948
- * @param data
949
- */
950
- public format(sql?: string, data?: types.DbValue[]): string {
951
- return mysql2.format(sql ?? this.getSql(), data ?? this.getData());
952
- }
953
-
954
- // --- 特殊方法 ---
955
-
956
- /**
957
- * --- 在 sql 最后追加字符串 ---
958
- * @param sql
959
- */
960
- public append(sql: string): this {
961
- this._sql.push(sql);
962
- return this;
963
- }
964
-
965
- /**
966
- * --- 对字段进行包裹 ---
967
- * @param str
968
- * @param pre 表前缀,仅请在 field 表名时倒入前缀
969
- * @param suf 表后缀,仅请在 field 表名时倒入后缀,前面加 # 代表要强制 AS
970
- */
971
- public field(str: string | number | Array<string | string[]>, pre: string = '', suf: string = ''): string {
972
- let left: string = '';
973
- let right: string = '';
974
- if (Array.isArray(str)) {
975
- this._data.push(...str[1]);
976
- return this.field(str[0]);
977
- }
978
- if (typeof str === 'number') {
979
- str = str.toString();
980
- }
981
- str = str.trim(); // --- 去除前导尾随 ---
982
- str = str.replace(/ {2,}/g, ' '); // --- 去除多余的空格 ---
983
- str = str.replace(/ +([),])/g, ' $1');
984
- str = str.replace(/([(,]) +/g, '$1 ');
985
- str = str.replace(/(\W)(JOIN|WHERE|UNION)(\W)/ig, '$1$3');
986
- // --- 先判断 suf 强制性 AS ---
987
- let sufAs = false;
988
- if (suf.startsWith('#')) {
989
- // --- 强制 AS ---
990
- suf = suf.slice(1);
991
- sufAs = true;
992
- }
993
- // --- 先判断有没有别名(也就是 as) ---
994
- const loStr = str.toLowerCase();
995
- const asPos = loStr.indexOf(' as ');
996
- if (asPos === -1) {
997
- // --- 没有 as ---
998
- let spacePos = str.lastIndexOf(' ');
999
- // --- 有可能有 aa + bb + cc + 10 这种情况 ---
1000
- if (!/^[a-zA-Z_)]$/.test(str[spacePos - 1])) {
1001
- // --- 连接符 ---
1002
- spacePos = -1;
1003
- }
1004
- if (spacePos !== -1) {
1005
- const spaceRight = str.slice(spacePos + 1);
1006
- if (/^[a-zA-Z_`][\w`]*$/.test(spaceRight)) {
1007
- // --- OK ---
1008
- left = str.slice(0, spacePos);
1009
- right = spaceRight;
1010
- }
1011
- else {
1012
- left = str;
1013
- right = '';
1014
- }
1015
- }
1016
- else {
1017
- left = str;
1018
- right = '';
1019
- }
1020
- }
1021
- else {
1022
- // --- 有 as ---
1023
- left = str.slice(0, asPos);
1024
- right = str.slice(asPos + 4);
1025
- }
1026
- if (right) {
1027
- // --- 处理右侧 ---
1028
- if (right.startsWith('`')) {
1029
- right = '`' + pre + right.slice(1);
1030
- }
1031
- else {
1032
- right = '`' + pre + right + '`';
1033
- }
1034
- right = ' AS ' + right;
1035
- }
1036
- else {
1037
- // --- 没有右侧 ---
1038
- if (sufAs) {
1039
- // --- 强制 AS ---
1040
- right = ' AS ' + this.field(left, pre);
1041
- }
1042
- }
1043
- // --- 处理 left ---
1044
- if (/^[\w`_.*]+$/.test(left)) {
1045
- const l = left.split('.');
1046
- if (l[0] === '*') {
1047
- return '*' + right;
1048
- }
1049
- if (l[0].startsWith('`')) {
1050
- l[0] = l[0].replace(/`/g, '');
1051
- }
1052
- if (l[1] === undefined) {
1053
- // --- xxx ---
1054
- if (/^[A-Z0-9_]+$/.test(l[0])) {
1055
- // --- 纯大写是内置函数,不能加 ` ---
1056
- return l[0] + right;
1057
- }
1058
- return '`' + pre + l[0] + suf + '`' + right;
1059
- }
1060
- // --- x.xxx ---
1061
- // --- 只有在此模式才知道 . 前面的一定是表名,因此自动加 sql 级的 _pre ---
1062
- const w = l[1] === '*' ? '*' : (l[1].startsWith('`') ? l[1] : ('`' + l[1] + '`'));
1063
- return '`' + this._pre + l[0] + suf + '`.' + w + right;
1064
- }
1065
- else {
1066
- // return left.replace(/([(, ])([a-zA-Z`_][\w`_.]*)(?=[), ])/g, (
1067
- return left.replace(/(^|[(, ])([a-zA-Z`_][\w`_.]*)(?=[), ]|$)/g, (
1068
- t: string, t1: string, t2: string
1069
- ): string => {
1070
- return t1 + this.field(t2, pre, suf);
1071
- }) + right;
1072
- }
1073
- }
1074
-
1075
- /**
1076
- * --- 判断传入值是否是 field,还是别的对象 ---
1077
- * @param str
1078
- */
1079
- private _isField(arg: any): arg is {
1080
- 'type': 'column';
1081
- 'token': string;
1082
- 'value': string;
1083
- } {
1084
- if (arg.type !== 'column' || arg.token !== columnToken || arg.value === undefined) {
1085
- return false;
1086
- }
1087
- return true;
1088
- }
1089
-
1090
- }
1091
-
1092
- /**
1093
- * --- 创建 sql 对象 ---
1094
- * @param ctrPre ctr 对象或 pre 表前缀
1095
- * @param opt 参数
1096
- */
1097
- export function get(ctrPre?: ctr.Ctr | string, opt: {
1098
- 'data'?: types.DbValue[];
1099
- 'sql'?: string[];
1100
- } = {}): Sql {
1101
- return new Sql(ctrPre instanceof ctr.Ctr ? ctrPre.getPrototype('_config').sql.pre : ctrPre, opt);
1102
- }
1103
-
1104
- /**
1105
- * --- 返回代入后的完整 SQL 字符串 ---
1106
- * @param sql SQL 字符串
1107
- * @param data DATA 数据
1108
- */
1109
- export function format(sql: string, data: types.DbValue[]): string {
1110
- return mysql2.format(sql, data);
1111
- }
1112
-
1113
- /**
1114
- * --- 将数组兑换为组合的对象(Array/Object mix) ---
1115
- * @param arr 要转换的数组
1116
- */
1117
- export function aoMix(arr: types.Json): Record<string, string | number | types.Json> {
1118
- if (!Array.isArray(arr)) {
1119
- return arr;
1120
- }
1121
- const mix: Record<string, string | number | types.Json> = {};
1122
- let i: number = 0;
1123
- for (const v of arr) {
1124
- if (Array.isArray(v)) {
1125
- mix[i] = v;
1126
- ++i;
1127
- }
1128
- else {
1129
- for (const k in v) {
1130
- mix[k] = v[k];
1131
- }
1132
- }
1133
- }
1134
- return mix;
1135
- }
1136
-
1137
- /** --- 创建字段对象 --- */
1138
- export function column(field: string): {
1139
- 'type': 'column';
1140
- 'token': string;
1141
- 'value': string;
1142
- } {
1143
- if (!columnToken) {
1144
- columnToken = lCore.random(8, lCore.RANDOM_LUNS);
1145
- }
1146
- return {
1147
- 'token': columnToken,
1148
- 'type': 'column',
1149
- 'value': field
1150
- };
1151
- }