@maiyunnet/kebab 2.0.3 → 2.0.5

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 (89) hide show
  1. package/index.d.ts +14 -0
  2. package/index.js +1 -1
  3. package/lib/buffer.d.ts +25 -0
  4. package/lib/captcha.d.ts +12 -0
  5. package/lib/consistent.d.ts +20 -0
  6. package/lib/core.d.ts +85 -0
  7. package/lib/crypto.d.ts +47 -0
  8. package/lib/db.d.ts +88 -0
  9. package/lib/dns.d.ts +75 -0
  10. package/lib/fs.d.ts +49 -0
  11. package/lib/jwt.d.ts +30 -0
  12. package/lib/kv.d.ts +111 -0
  13. package/lib/lan.d.ts +10 -0
  14. package/lib/net/formdata.d.ts +23 -0
  15. package/lib/net/request.d.ts +23 -0
  16. package/lib/net/response.d.ts +14 -0
  17. package/lib/net.d.ts +65 -0
  18. package/lib/s3.d.ts +35 -0
  19. package/lib/scan.d.ts +31 -0
  20. package/lib/session.d.ts +22 -0
  21. package/lib/sql.d.ts +57 -0
  22. package/lib/ssh/sftp.d.ts +40 -0
  23. package/lib/ssh/shell.d.ts +13 -0
  24. package/lib/ssh.d.ts +24 -0
  25. package/lib/text.d.ts +40 -0
  26. package/lib/time.d.ts +22 -0
  27. package/lib/ws.d.ts +87 -0
  28. package/lib/zip.d.ts +40 -0
  29. package/lib/zlib.d.ts +25 -0
  30. package/main.d.ts +1 -0
  31. package/package.json +1 -1
  32. package/sys/child.d.ts +1 -0
  33. package/sys/cmd.d.ts +1 -0
  34. package/sys/ctr.d.ts +96 -0
  35. package/sys/master.d.ts +1 -0
  36. package/sys/mod.d.ts +205 -0
  37. package/sys/route.d.ts +31 -0
  38. package/tsconfig.json +1 -1
  39. package/www/example/ctr/main.d.ts +4 -0
  40. package/www/example/ctr/middle.d.ts +6 -0
  41. package/www/example/ctr/test.d.ts +94 -0
  42. package/www/example/mod/test.d.ts +20 -0
  43. package/www/example/mod/testdata.d.ts +9 -0
  44. package/www/example/ws/mproxy.d.ts +4 -0
  45. package/www/example/ws/rproxy.d.ts +4 -0
  46. package/www/example/ws/test.d.ts +7 -0
  47. package/index.ts +0 -33
  48. package/lib/buffer.ts +0 -152
  49. package/lib/captcha.ts +0 -63
  50. package/lib/consistent.ts +0 -219
  51. package/lib/core.ts +0 -880
  52. package/lib/crypto.ts +0 -384
  53. package/lib/db.ts +0 -719
  54. package/lib/dns.ts +0 -405
  55. package/lib/fs.ts +0 -527
  56. package/lib/jwt.ts +0 -276
  57. package/lib/kv.ts +0 -1489
  58. package/lib/lan.ts +0 -87
  59. package/lib/net/formdata.ts +0 -166
  60. package/lib/net/request.ts +0 -150
  61. package/lib/net/response.ts +0 -59
  62. package/lib/net.ts +0 -662
  63. package/lib/s3.ts +0 -235
  64. package/lib/scan.ts +0 -364
  65. package/lib/session.ts +0 -230
  66. package/lib/sql.ts +0 -1149
  67. package/lib/ssh/sftp.ts +0 -508
  68. package/lib/ssh/shell.ts +0 -123
  69. package/lib/ssh.ts +0 -191
  70. package/lib/text.ts +0 -626
  71. package/lib/time.ts +0 -254
  72. package/lib/ws.ts +0 -523
  73. package/lib/zip.ts +0 -447
  74. package/lib/zlib.ts +0 -350
  75. package/main.ts +0 -27
  76. package/sys/child.ts +0 -678
  77. package/sys/cmd.ts +0 -225
  78. package/sys/ctr.ts +0 -904
  79. package/sys/master.ts +0 -355
  80. package/sys/mod.ts +0 -1871
  81. package/sys/route.ts +0 -1113
  82. package/www/example/ctr/main.ts +0 -9
  83. package/www/example/ctr/middle.ts +0 -26
  84. package/www/example/ctr/test.ts +0 -3218
  85. package/www/example/mod/test.ts +0 -47
  86. package/www/example/mod/testdata.ts +0 -30
  87. package/www/example/ws/mproxy.ts +0 -16
  88. package/www/example/ws/rproxy.ts +0 -14
  89. package/www/example/ws/test.ts +0 -36
package/sys/mod.ts DELETED
@@ -1,1871 +0,0 @@
1
- /**
2
- * Project: Mutton, User: JianSuoQiYue
3
- * Date: 2019-6-4 21:35
4
- * Last: 2020-4-14 13:33:51, 2022-07-23 16:01:34, 2022-09-06 22:59:26, 2023-5-24 19:11:37, 2023-6-13 21:47:58, 2023-7-10 18:54:03, 2023-8-23 17:03:16, 2023-12-11 15:21:22, 2023-12-20 23:12:03, 2024-3-8 16:05:29, 2024-3-20 19:58:15, 2024-8-11 21:14:54, 2024-10-5 14:00:22, 2024-12-14 19:58:34
5
- */
6
- import * as lSql from '~/lib/sql';
7
- import * as lDb from '~/lib/db';
8
- import * as lTime from '~/lib/time';
9
- import * as lCore from '~/lib/core';
10
- import * as lText from '~/lib/text';
11
- import * as sCtr from '~/sys/ctr';
12
- import * as types from '~/types';
13
-
14
- /** --- 条数列表 --- */
15
- class Rows<T extends Mod> implements types.Rows<T> {
16
-
17
- private readonly _items: T[] = [];
18
-
19
- public constructor(initialItems: T[] = []) {
20
- this._items = initialItems;
21
- }
22
-
23
- /** --- 总行数 --- */
24
- public get length(): number {
25
- return this._items.length;
26
- }
27
-
28
- /** --- 通过索引获取一个对象 --- */
29
- public item(index: number): T {
30
- return this._items[index];
31
- }
32
-
33
- /** --- 转换为数组对象 --- */
34
- public toArray(): Array<Record<string, any>> {
35
- const arr: Array<Record<string, any>> = [];
36
- for (const item of this._items) {
37
- arr.push(item.toArray());
38
- }
39
- return arr;
40
- }
41
-
42
- /** --- 根据规则筛掉项,predicate 返回 true 代表保留 --- */
43
- public filter(predicate: (value: T, index: number) => boolean): Rows<T> {
44
- const items: T[] = [];
45
- for (let i = 0; i < this._items.length; ++i) {
46
- if (!predicate(this._items[i], i)) {
47
- continue;
48
- }
49
- items.push(this._items[i]);
50
- }
51
- return new Rows<T>(items);
52
- }
53
-
54
- /** --- 重塑对象内容 --- */
55
- public map<TU>(allbackfn: (value: T, index: number) => TU): TU[] {
56
- const items: TU[] = [];
57
- for (let i = 0; i < this._items.length; ++i) {
58
- items.push(allbackfn(this._items[i], i));
59
- }
60
- return items;
61
- }
62
-
63
- public [Symbol.iterator](): Iterator<T> {
64
- let index = 0;
65
- return {
66
- next: (): IteratorResult<T> => {
67
- if (index < this._items.length) {
68
- return {
69
- value: this._items[index++],
70
- done: false
71
- };
72
- }
73
- else {
74
- return {
75
- value: undefined,
76
- done: true
77
- };
78
- }
79
- }
80
- };
81
- }
82
- }
83
-
84
- /**
85
- * --- 开启软更需要在表添加字段:ALTER TABLE `table_name` ADD `time_remove` bigint NOT NULL DEFAULT '0' AFTER `xxx`; ---
86
- */
87
- export default class Mod {
88
-
89
- /** --- 表名 --- */
90
- protected static _$table: string = '';
91
-
92
- /** --- 主键字段名 --- */
93
- protected static _$primary: string = 'id';
94
-
95
- /** --- 设置后将由 _keyGenerator 函数生成唯一字段 --- */
96
- protected static _$key: string = '';
97
-
98
- /** ---- 可开启软删软更新软新增 --- */
99
- protected static _$soft: boolean = false;
100
-
101
- /** --- 要 update 的内容 --- */
102
- protected _updates: Record<string, boolean> = {};
103
-
104
- /** --- 模型获取的属性 --- */
105
- protected _data: Record<string, any> = {};
106
-
107
- /** --- 当前选择的分表 _ 后缀,多个代表联查 --- */
108
- protected _index: string[] | null = null;
109
-
110
- /** --- 必须追加的数据筛选 key 与 values,仅单表模式有效 --- */
111
- protected _contain: {
112
- 'key': string;
113
- 'list': string[];
114
- } | null = null;
115
-
116
- /** --- 已算出的 total --- */
117
- protected _total: number[] = [];
118
-
119
- /** --- 数据库连接对象 --- */
120
- protected _db!: lDb.Pool | lDb.Transaction;
121
-
122
- /** --- Sql 对象 --- */
123
- protected _sql!: lSql.Sql;
124
-
125
- /** --- ctr 对象, Mutton: false, Kebab: true --- */
126
- protected _ctr?: sCtr.Ctr = undefined;
127
-
128
- /**
129
- * --- 构造函数 ---
130
- * @param ctr Ctr 对象
131
- * @param opt 选项
132
- */
133
- public constructor(opt: {
134
- 'db': lDb.Pool | lDb.Transaction;
135
- 'ctr'?: sCtr.Ctr;
136
- 'index'?: string | string[];
137
- 'alias'?: string;
138
- 'row'?: Record<string, any>;
139
- 'select'?: string | string[];
140
- 'where'?: string | types.Json;
141
- 'contain'?: {
142
- 'key': string;
143
- 'list': string[];
144
- };
145
- 'raw'?: boolean;
146
- 'pre'?: string;
147
- }) {
148
- /** --- 导入 ctr 对象 --- */
149
- this._ctr = opt.ctr;
150
- /** --- 导入数据库连接 --- */
151
- this._db = opt.db;
152
- /** --- 新建 sql 对象 --- */
153
- this._sql = lSql.get(opt.pre ?? opt.ctr);
154
- if (opt.index) {
155
- this._index = typeof opt.index === 'string' ? [opt.index] : [...new Set(opt.index)];
156
- }
157
- if (opt.contain) {
158
- this._contain = opt.contain;
159
- }
160
- // --- 第三个参数用于内部数据导入,将 data 数据合并到本实例化类 ---
161
- if (opt.row) {
162
- for (const k in opt.row) {
163
- const v = opt.row[k];
164
- this._data[k] = v;
165
- (this as Record<string, types.Json>)[k] = v;
166
- }
167
- }
168
- /** --- 是否有 select --- */
169
- const select = opt.select ?? (opt.where ? '*' : '');
170
- if (select) {
171
- this._sql.select(
172
- select,
173
- ((this.constructor as Record<string, types.Json>)._$table as string) +
174
- (this._index !== null ? ('_' + this._index[0]) : '') +
175
- (opt.alias ? ' ' + opt.alias : '')
176
- );
177
- }
178
- if (opt.where !== undefined) {
179
- if ((this.constructor as Record<string, types.Json>)._soft && !opt.raw) {
180
- if (typeof opt.where === 'string') {
181
- opt.where = opt.where ? ('(' + opt.where + ') AND ') : '`time_remove` = 0';
182
- }
183
- else if (Array.isArray(opt.where)) {
184
- opt.where.push({
185
- 'time_remove': 0
186
- });
187
- }
188
- else {
189
- opt.where['time_remove'] = 0;
190
- }
191
- }
192
- this._sql.where(opt.where);
193
- }
194
- }
195
-
196
- // --- 静态方法 ---
197
-
198
- /** --- 创建字段对象 --- */
199
- public static column(field: string): {
200
- 'type': 'column';
201
- 'token': string;
202
- 'value': string;
203
- } {
204
- return lSql.column(field);
205
- }
206
-
207
- /**
208
- * --- 添加一个序列 ---
209
- * @param db 数据库对象
210
- * @param cs 字段列表
211
- * @param vs 数据列表
212
- * @param opt 选项
213
- */
214
- public static async insert(
215
- db: lDb.Pool | lDb.Transaction,
216
- cs: string[] | Record<string, any>,
217
- vs?: any[] | any[][],
218
- opt: { 'pre'?: sCtr.Ctr | string; 'index'?: string; } = {}
219
- ): Promise<boolean | null | false> {
220
- const sq = lSql.get(opt.pre);
221
- sq.insert(this._$table + (opt.index ? ('_' + opt.index) : '')).values(cs, vs);
222
- const r = await db.execute(sq.getSql(), sq.getData());
223
- if (r.packet === null) {
224
- await lCore.log(opt.pre instanceof sCtr.Ctr ? opt.pre : {
225
- 'path': '',
226
- 'urlFull': '',
227
- 'hostname': '',
228
- 'req': null,
229
- 'get': {},
230
- 'cookie': {},
231
- 'headers': {}
232
- }, '[insert, mod] ' + lText.stringifyJson(r.error?.message ?? '').slice(1, -1), '-error');
233
- return false;
234
- }
235
- if (r.packet.affectedRows > 0) {
236
- return true;
237
- }
238
- else {
239
- return null;
240
- }
241
- }
242
-
243
- /**
244
- * --- 获取添加一个序列的模拟 SQL ---
245
- * @param cs 字段列表
246
- * @param vs 数据列表
247
- * @param opt 选项
248
- */
249
- public static insertSql(
250
- cs: string[] | Record<string, any>,
251
- vs?: any[] | any[][],
252
- opt: { 'pre'?: sCtr.Ctr | string; 'index'?: string; } = {}
253
- ): string {
254
- const sq = lSql.get(opt.pre);
255
- sq.insert(this._$table + (opt.index ? ('_' + opt.index) : '')).values(cs, vs);
256
- return sq.format();
257
- }
258
-
259
- /**
260
- * --- 插入数据如果唯一键冲突则更新 ---
261
- * @param db 数据库对象
262
- * @param data 要插入的数据
263
- * @param update 要更新的数据
264
- * @param opt 选项
265
- */
266
- public static async insertDuplicate(
267
- db: lDb.Pool | lDb.Transaction,
268
- data: Record<string, any>,
269
- update: types.Json,
270
- opt: { 'pre'?: sCtr.Ctr | string; 'index'?: string; } = {}
271
- ): Promise<boolean | null> {
272
- const sq = lSql.get(opt.pre);
273
- sq.insert(this._$table + (opt.index ? ('_' + opt.index) : '')).values(data).duplicate(update);
274
- const r = await db.execute(sq.getSql(), sq.getData());
275
- if (r.packet === null) {
276
- await lCore.log(opt.pre instanceof sCtr.Ctr ? opt.pre : {
277
- 'path': '',
278
- 'urlFull': '',
279
- 'hostname': '',
280
- 'req': null,
281
- 'get': {},
282
- 'cookie': {},
283
- 'headers': {}
284
- }, '[insertDuplicate, mod] ' + lText.stringifyJson(r.error?.message ?? '').slice(1, -1).replace(/"/g, '""'), '-error');
285
- return false;
286
- }
287
- if (r.packet.affectedRows > 0) {
288
- return true;
289
- }
290
- else {
291
- return null;
292
- }
293
- }
294
-
295
- /**
296
- * --- 根据条件移除条目 ---
297
- * @param db 数据库对象
298
- * @param where 筛选条件
299
- * @param opt 选项
300
- */
301
- public static async removeByWhere(
302
- db: lDb.Pool | lDb.Transaction,
303
- where: string | types.Json,
304
- opt: {
305
- 'raw'?: boolean;
306
- 'pre'?: sCtr.Ctr | string;
307
- 'index'?: string;
308
- 'by'?: [string | string[], 'DESC' | 'ASC'];
309
- 'limit'?: [number, number?];
310
- } = {}
311
- ): Promise<number | false | null> {
312
- const tim = lTime.stamp();
313
- const sq = lSql.get(opt.pre);
314
- if (this._$soft && !opt.raw) {
315
- // --- 软删除 ---
316
- sq.update(this._$table + (opt.index ? ('_' + opt.index) : ''), [{
317
- 'time_remove': tim
318
- }]);
319
- if (typeof where === 'string') {
320
- where = '(' + where + ') AND `time_remove` = 0';
321
- }
322
- else if (Array.isArray(where)) {
323
- where.push({
324
- 'time_remove': 0
325
- });
326
- }
327
- else {
328
- where['time_remove'] = 0;
329
- }
330
- }
331
- else {
332
- // --- 真删除 ---
333
- sq.delete(this._$table + (opt.index ? ('_' + opt.index) : ''));
334
- }
335
- sq.where(where);
336
- if (opt.by) {
337
- sq.by(opt.by[0], opt.by[1]);
338
- }
339
- if (opt.limit) {
340
- sq.limit(opt.limit[0], opt.limit[1]);
341
- }
342
- const r = await db.execute(sq.getSql(), sq.getData());
343
- if (r.packet === null) {
344
- await lCore.log(opt.pre instanceof sCtr.Ctr ? opt.pre : {
345
- 'path': '',
346
- 'urlFull': '',
347
- 'hostname': '',
348
- 'req': null,
349
- 'get': {},
350
- 'cookie': {},
351
- 'headers': {}
352
- }, '[removeByWhere, mod] ' + lText.stringifyJson(r.error?.message ?? '').slice(1, -1).replace(/"/g, '""'), '-error');
353
- return false;
354
- }
355
- if (r.packet.affectedRows > 0) {
356
- return r.packet.affectedRows;
357
- }
358
- return null;
359
- }
360
-
361
- /**
362
- * --- 根据条件移除条目(仅获取 SQL 对象) ---
363
- * @param db 数据库对象
364
- * @param where 筛选条件
365
- * @param opt 选项
366
- */
367
- public static removeByWhereSql(
368
- db: lDb.Pool | lDb.Transaction,
369
- where: string | types.Json,
370
- opt: {
371
- 'raw'?: boolean;
372
- 'pre'?: sCtr.Ctr | string;
373
- 'index'?: string;
374
- 'by'?: [string | string[], 'DESC' | 'ASC'];
375
- 'limit'?: [number, number?];
376
- } = {}
377
- ): lSql.Sql {
378
- const tim = lTime.stamp();
379
- const sq = lSql.get(opt.pre);
380
- if (this._$soft && !opt.raw) {
381
- // --- 软删除 ---
382
- sq.update(this._$table + (opt.index ? ('_' + opt.index) : ''), [{
383
- 'time_remove': tim
384
- }]);
385
- if (typeof where === 'string') {
386
- where = '(' + where + ') AND `time_remove` = 0';
387
- }
388
- else if (Array.isArray(where)) {
389
- where.push({
390
- 'time_remove': 0
391
- });
392
- }
393
- else {
394
- where['time_remove'] = 0;
395
- }
396
- }
397
- else {
398
- // --- 真删除 ---
399
- sq.delete(this._$table + (opt.index ? ('_' + opt.index) : ''));
400
- }
401
- sq.where(where);
402
- if (opt.by) {
403
- sq.by(opt.by[0], opt.by[1]);
404
- }
405
- if (opt.limit) {
406
- sq.limit(opt.limit[0], opt.limit[1]);
407
- }
408
- return sq;
409
- }
410
-
411
- /**
412
- * --- 根据条件更新数据 ---
413
- * @param db 数据库对象
414
- * @param data 要更新的数据
415
- * @param where 筛选条件
416
- * @param opt 选项
417
- */
418
- public static async updateByWhere(
419
- db: lDb.Pool | lDb.Transaction,
420
- data: types.Json,
421
- where: string | types.Json,
422
- opt: {
423
- 'raw'?: boolean;
424
- 'pre'?: sCtr.Ctr | string;
425
- 'index'?: string | string[];
426
- 'by'?: [string | string[], 'DESC' | 'ASC'];
427
- 'limit'?: [number, number?];
428
- } = {}
429
- ): Promise<number | false | null> {
430
- if (typeof opt.index === 'string') {
431
- opt.index = [opt.index];
432
- }
433
- else if (!opt.index) {
434
- opt.index = [''];
435
- }
436
- if (this._$soft && !opt.raw) {
437
- if (typeof where === 'string') {
438
- where = '(' + where + ') AND `time_remove` = 0';
439
- }
440
- else if (Array.isArray(where)) {
441
- where.push({
442
- 'time_remove': 0
443
- });
444
- }
445
- else {
446
- where['time_remove'] = 0;
447
- }
448
- }
449
- let ar = 0;
450
- for (const index of opt.index) {
451
- const sq = lSql.get(opt.pre);
452
- sq.update(this._$table + (index ? ('_' + index) : ''), data);
453
- sq.where(where);
454
- if (opt.by) {
455
- sq.by(opt.by[0], opt.by[1]);
456
- }
457
- if (opt.limit) {
458
- sq.limit(opt.limit[0], opt.limit[1]);
459
- }
460
- const r = await db.execute(sq.getSql(), sq.getData());
461
- if (r.packet === null) {
462
- await lCore.log(opt.pre instanceof sCtr.Ctr ? opt.pre : {
463
- 'path': '',
464
- 'urlFull': '',
465
- 'hostname': '',
466
- 'req': null,
467
- 'get': {},
468
- 'cookie': {},
469
- 'headers': {}
470
- }, '[updateByWhere, mod] ' + lText.stringifyJson(r.error?.message ?? '').slice(1, -1).replace(/"/g, '""'), '-error');
471
- return false;
472
- }
473
- if (r.packet.affectedRows > 0) {
474
- ar += r.packet.affectedRows;
475
- }
476
- }
477
- return ar ? ar : null;
478
- }
479
-
480
- /**
481
- * --- 根据条件更新数据(仅获取 SQL 对象) ---
482
- * @param data 要更新的数据
483
- * @param where 筛选条件
484
- * @param opt 选项
485
- */
486
- public static updateByWhereSql(
487
- data: types.Json,
488
- where: string | types.Json,
489
- opt: {
490
- 'raw'?: boolean;
491
- 'pre'?: sCtr.Ctr | string;
492
- 'index'?: string;
493
- 'by'?: [string | string[], 'DESC' | 'ASC'];
494
- 'limit'?: [number, number?];
495
- } = {}
496
- ): lSql.Sql {
497
- const sq = lSql.get(opt.pre);
498
- sq.update(this._$table + (opt.index ? ('_' + opt.index) : ''), data);
499
- if (this._$soft && !opt.raw) {
500
- if (typeof where === 'string') {
501
- where = '(' + where + ') AND `time_remove` = 0';
502
- }
503
- else if (Array.isArray(where)) {
504
- where.push({
505
- 'time_remove': 0
506
- });
507
- }
508
- else {
509
- where['time_remove'] = 0;
510
- }
511
- }
512
- sq.where(where);
513
- if (opt.by) {
514
- sq.by(opt.by[0], opt.by[1]);
515
- }
516
- if (opt.limit) {
517
- sq.limit(opt.limit[0], opt.limit[1]);
518
- }
519
- return sq;
520
- }
521
-
522
- /**
523
- * --- select 自定字段 ---
524
- * @param db 数据库对象
525
- * @param c 字段字符串或字段数组
526
- * @param opt 选项
527
- */
528
- public static select<T extends Mod>(
529
- db: lDb.Pool | lDb.Transaction,
530
- c: string | string[],
531
- opt: {
532
- 'ctr'?: sCtr.Ctr; 'pre'?: string;
533
- 'index'?: string | string[]; 'alias'?: string;
534
- 'contain'?: {
535
- 'key': string;
536
- 'list': string[];
537
- };
538
- } = {}
539
- ): T & Record<string, any> {
540
- return new this({
541
- 'db': db,
542
- 'ctr': opt.ctr,
543
- 'pre': opt.pre,
544
- 'select': c,
545
- 'index': opt.index,
546
- 'alias': opt.alias,
547
- 'contain': opt.contain
548
- }) as T & Record<string, any>;
549
- }
550
-
551
- /**
552
- * --- 通过 where 条件获取模型 ---
553
- * @param db 数据库对象
554
- * @param s 筛选条件数组或字符串
555
- * @param opt 选项
556
- */
557
- public static where<T extends Mod>(
558
- db: lDb.Pool | lDb.Transaction,
559
- s: string | types.Json = '',
560
- opt: {
561
- 'ctr'?: sCtr.Ctr; 'raw'?: boolean; 'pre'?: string; 'index'?: string | string[];
562
- 'contain'?: {
563
- 'key': string;
564
- 'list': string[];
565
- };
566
- } = {}
567
- ): T & Record<string, any> {
568
- return new this({
569
- 'db': db,
570
- 'ctr': opt.ctr,
571
- 'pre': opt.pre,
572
- 'where': s,
573
- 'raw': opt.raw,
574
- 'index': opt.index,
575
- 'contain': opt.contain
576
- }) as T & Record<string, any>;
577
- }
578
-
579
- /**
580
- * --- 获取创建对象,通常用于新建数据库条目 ---
581
- * @param db 数据库对象
582
- * @param opt 选项
583
- */
584
- public static getCreate<T extends Mod>(
585
- db: lDb.Pool | lDb.Transaction,
586
- opt: { 'ctr'?: sCtr.Ctr; 'pre'?: string; 'index'?: string; } = {}
587
- ): T {
588
- return new this({
589
- 'db': db,
590
- 'ctr': opt.ctr,
591
- 'pre': opt.pre,
592
- 'index': opt.index
593
- }) as T;
594
- }
595
-
596
- /**
597
- * --- 根据主键获取对象 ---
598
- * @param db 数据库对象
599
- * @param val 主键值
600
- * @param lock 是否加锁
601
- * @param opt 选项
602
- */
603
- public static find<T extends Mod>(
604
- db: lDb.Pool | lDb.Transaction,
605
- val: string | number | null,
606
- opt: { 'ctr'?: sCtr.Ctr; 'lock'?: boolean; 'raw'?: boolean; 'pre'?: string; 'index'?: string; } = {}
607
- ): Promise<false | null | (T & Record<string, any>)> {
608
- return (new this({
609
- 'db': db,
610
- 'ctr': opt.ctr,
611
- 'pre': opt.pre,
612
- 'where': [{
613
- [this._$primary]: val
614
- }],
615
- 'raw': opt.raw,
616
- 'index': opt.index
617
- }) as T & Record<string, any>).first(opt.lock);
618
- }
619
-
620
- public static async one(
621
- db: lDb.Pool | lDb.Transaction,
622
- s: string | types.Json,
623
- opt: {
624
- 'ctr'?: sCtr.Ctr;
625
- 'raw'?: boolean;
626
- 'pre'?: string;
627
- 'index'?: string | string[];
628
- 'select'?: string | string[];
629
- 'by'?: [string | string[], 'DESC' | 'ASC'];
630
- 'array': true;
631
- }
632
- ): Promise<false | null | Record<string, any>>;
633
- public static async one<T extends Mod>(
634
- db: lDb.Pool | lDb.Transaction,
635
- s: string | types.Json,
636
- opt: {
637
- 'ctr'?: sCtr.Ctr;
638
- 'raw'?: boolean;
639
- 'pre'?: string;
640
- 'index'?: string | string[];
641
- 'select'?: string | string[];
642
- 'by'?: [string | string[], 'DESC' | 'ASC'];
643
- 'array'?: false;
644
- }
645
- ): Promise<false | null | (T & Record<string, any>)>;
646
- /**
647
- * --- 通过 where 条件筛选单条数据 ---
648
- * @param db 数据库对象
649
- * @param s 筛选条件数组或字符串
650
- * @param opt 选项
651
- */
652
- public static async one<T extends Mod>(
653
- db: lDb.Pool | lDb.Transaction,
654
- s: string | types.Json,
655
- opt: {
656
- 'ctr'?: sCtr.Ctr;
657
- 'raw'?: boolean;
658
- 'pre'?: string;
659
- 'index'?: string | string[];
660
- 'select'?: string | string[];
661
- 'by'?: [string | string[], 'DESC' | 'ASC'];
662
- 'array'?: boolean;
663
- } = {}
664
- ): Promise<false | null | (T & Record<string, any>) | Record<string, any>> {
665
- if (!opt.index) {
666
- const o = new this({
667
- 'select': opt.select,
668
- 'db': db,
669
- 'ctr': opt.ctr,
670
- 'pre': opt.pre,
671
- 'where': s,
672
- 'raw': opt.raw
673
- }) as T;
674
- if (opt.by) {
675
- o.by(opt.by[0], opt.by[1]);
676
- }
677
- return opt.array ? o.firstArray() : o.first();
678
- }
679
- opt.index = typeof opt.index === 'string' ? [opt.index] : [...new Set(opt.index)];
680
- for (const item of opt.index) {
681
- const row = new this({
682
- 'select': opt.select,
683
- 'db': db,
684
- 'ctr': opt.ctr,
685
- 'pre': opt.pre,
686
- 'where': s,
687
- 'raw': opt.raw,
688
- 'index': item
689
- }) as T;
690
- if (opt.by) {
691
- row.by(opt.by[0], opt.by[1]);
692
- }
693
- const rowr = await (opt.array ? row.firstArray() : row.first());
694
- if (rowr) {
695
- return rowr;
696
- }
697
- if (rowr === false) {
698
- return false;
699
- }
700
- // --- 如果是 null 再去下个 index 找一下 ---
701
- }
702
- return null;
703
- }
704
-
705
- /**
706
- * --- 通过 where 条件筛选单条数据返回原生对象 ---
707
- * @param db 数据库对象
708
- * @param s 筛选条件数组或字符串
709
- * @param opt 选项
710
- */
711
- public static async oneArray(
712
- db: lDb.Pool | lDb.Transaction,
713
- s: string | types.Json,
714
- opt: {
715
- 'ctr'?: sCtr.Ctr;
716
- 'raw'?: boolean;
717
- 'pre'?: string;
718
- 'index'?: string | string[];
719
- 'select'?: string | string[];
720
- } = {}
721
- ): Promise<false | null | Record<string, any>> {
722
- (opt as types.Json).array = true;
723
- return this.one(db, s, opt);
724
- }
725
-
726
- /**
727
- * --- 根据 where 条件获取主键值列表 ---
728
- * @param db 数据库对象
729
- * @param where where 条件
730
- * @param opt 选项
731
- */
732
- public static async primarys(
733
- db: lDb.Pool | lDb.Transaction,
734
- where: string | types.Json = '',
735
- opt: { 'ctr'?: sCtr.Ctr; 'raw'?: boolean; 'pre'?: string; 'index'?: string; } = {}
736
- ): Promise<any[] | false> {
737
- const sq = lSql.get(opt.pre ?? opt.ctr);
738
- if (this._$soft && !opt.raw) {
739
- // --- 不包含已删除 ---
740
- if (typeof where === 'string') {
741
- if (where !== '') {
742
- where = '(' + where + ') AND `time_remove` = 0';
743
- }
744
- }
745
- else if (Array.isArray(where)) {
746
- where.push({
747
- 'time_remove': 0
748
- });
749
- }
750
- else {
751
- where['time_remove'] = 0;
752
- }
753
- }
754
- sq.select(this._$primary, this._$table + (opt.index ? ('_' + opt.index) : '')).where(where);
755
- const r = await db.query(sq.getSql(), sq.getData());
756
- if (r.rows === null) {
757
- await lCore.log(opt.ctr ?? {
758
- 'path': '',
759
- 'urlFull': '',
760
- 'hostname': '',
761
- 'req': null,
762
- 'get': {},
763
- 'cookie': {},
764
- 'headers': {}
765
- }, '[primarys, mod] ' + lText.stringifyJson(r.error?.message ?? '').slice(1, -1).replace(/"/g, '""'), '-error');
766
- return false;
767
- }
768
- const primarys: any[] = [];
769
- for (const row of r.rows) {
770
- primarys.push(row[this._$primary]);
771
- }
772
- return primarys;
773
- }
774
-
775
- /**
776
- * --- 将 key val 组成的数据列表转换为原生对象模式 ---
777
- * @param obj 要转换的 kv 数据列表
778
- */
779
- public static toArrayByRecord<T extends Mod>(
780
- obj: Record<string, T>
781
- ): Record<string, Record<string, any>> {
782
- const rtn: Record<string, Record<string, any>> = {};
783
- for (const key in obj) {
784
- rtn[key] = obj[key].toArray();
785
- }
786
- return rtn;
787
- }
788
-
789
- // --- 动态方法 ---
790
-
791
- public set<T extends this, TK extends keyof T>(n: Record<TK, T[TK] | undefined>): void;
792
- public set<T extends this, TK extends keyof T>(n: TK, v: T[TK]): void;
793
- /**
794
- * --- 设置一个/多个属性 ---
795
- * @param n 字符串或键/值
796
- * @param v 可能是数字
797
- */
798
- public set<T extends this, TK extends keyof T>(n: TK | Record<TK, T[TK] | undefined>, v?: T[TK]): void {
799
- if (typeof n === 'object') {
800
- // --- { x: y } ---
801
- for (const k in n) {
802
- const v = n[k];
803
- if (v === undefined) {
804
- continue;
805
- }
806
- // --- 强制更新,因为有的可能就是要强制更新既然设置了 ---
807
- this._updates[k] = true;
808
- this._data[k] = v;
809
- (this as types.Json)[k] = v;
810
- }
811
- }
812
- else {
813
- // --- x, y ---
814
- if (v === undefined) {
815
- return;
816
- }
817
- if (typeof n !== 'string') {
818
- return;
819
- }
820
- this._updates[n] = true;
821
- this._data[n] = v;
822
- (this as types.Json)[n] = v;
823
- }
824
- }
825
-
826
- /**
827
- * --- 获取一个字段值
828
- * @param n 字段名
829
- */
830
- public get(n: string): any {
831
- return this._data[n];
832
- }
833
-
834
- /**
835
- * --- 创建数据 ---
836
- * @param notWhere 若要不存在才成功,则要传入限定条件
837
- * @param table 可对限定条件传入适当的表
838
- */
839
- public async create(notWhere?: string | types.Json, table?: string): Promise<boolean> {
840
- const cstr = this.constructor as Record<string, types.Json>;
841
- const updates: Record<string, any> = {};
842
- for (const k in this._updates) {
843
- updates[k] = this._data[k];
844
- }
845
- if (!table) {
846
- table = (cstr._$table as string) + (this._index ? ('_' + this._index[0]) : '');
847
- }
848
-
849
- let r: lDb.IPacket | null = null;
850
- if ((cstr._$key !== '') && (updates[cstr._$key] === undefined)) {
851
- let count: number = 0;
852
- while (true) {
853
- if (count === 3) {
854
- return false;
855
- }
856
- updates[cstr._$key] = this._keyGenerator();
857
- this._data[cstr._$key] = updates[cstr._$key];
858
- (this as types.Json)[cstr._$key] = updates[cstr._$key];
859
- this._sql.insert((cstr._$table as string) + (this._index ? ('_' + this._index[0]) : ''));
860
- if (notWhere) {
861
- this._sql.notExists(table, updates, notWhere);
862
- }
863
- else {
864
- this._sql.values(updates);
865
- }
866
- r = await this._db.execute(this._sql.getSql(), this._sql.getData());
867
- ++count;
868
- if (!r.error) {
869
- break;
870
- }
871
- if (r.error.errno !== 1062) {
872
- await lCore.log(this._ctr ?? {
873
- 'path': '',
874
- 'urlFull': '',
875
- 'hostname': '',
876
- 'req': null,
877
- 'get': {},
878
- 'cookie': {},
879
- 'headers': {}
880
- }, '[create0, mod] [' + table + '] ' + lText.stringifyJson(r.error?.message ?? '').slice(1, -1).replace(/"/g, '""'), '-error');
881
- return false;
882
- }
883
- }
884
- }
885
- else {
886
- this._sql.insert((cstr._$table as string) + (this._index ? ('_' + this._index[0]) : ''));
887
- if (notWhere) {
888
- this._sql.notExists(table, updates, notWhere);
889
- }
890
- else {
891
- this._sql.values(updates);
892
- }
893
- r = await this._db.execute(this._sql.getSql(), this._sql.getData());
894
- if (r.error) {
895
- if (r.error.errno !== 1062) {
896
- await lCore.log(this._ctr ?? {
897
- 'path': '',
898
- 'urlFull': '',
899
- 'hostname': '',
900
- 'req': null,
901
- 'get': {},
902
- 'cookie': {},
903
- 'headers': {}
904
- }, '[create1, mod] [' + table + '] ' + lText.stringifyJson(r.error?.message ?? '').slice(1, -1).replace(/"/g, '""'), '-error');
905
- }
906
- return false;
907
- }
908
- }
909
- if (r?.packet?.affectedRows && r?.packet?.affectedRows > 0) {
910
- this._updates = {};
911
- this._data[cstr._$primary] = r.packet.insertId;
912
- (this as types.Json)[cstr._$primary] = this._data[cstr._$primary];
913
- return true;
914
- }
915
- else {
916
- return false;
917
- }
918
- }
919
-
920
- /**
921
- * --- 唯一键冲突则替换,不冲突则创建数据 ---
922
- */
923
- public async replace(): Promise<boolean> {
924
- const cstr = this.constructor as Record<string, types.Json>;
925
- const updates: Record<string, any> = {};
926
- for (const k in this._updates) {
927
- updates[k] = this._data[k];
928
- }
929
-
930
- this._sql.replace((cstr._$table as string) + (this._index ? ('_' + this._index[0]) : '')).values(updates);
931
- const r = await this._db.execute(this._sql.getSql(), this._sql.getData());
932
- if (r.packet === null) {
933
- await lCore.log(this._ctr ?? {
934
- 'path': '',
935
- 'urlFull': '',
936
- 'hostname': '',
937
- 'req': null,
938
- 'get': {},
939
- 'cookie': {},
940
- 'headers': {}
941
- }, '[replace, mod] ' + lText.stringifyJson(r.error?.message ?? '').slice(1, -1).replace(/"/g, '""'), '-error');
942
- return false;
943
- }
944
- if (r.packet.affectedRows > 0) {
945
- this._updates = {};
946
- this._data[cstr._$primary] = r.packet.insertId;
947
- (this as types.Json)[cstr._$primary] = this._data[cstr._$primary];
948
- return true;
949
- }
950
- else {
951
- return false;
952
- }
953
- }
954
-
955
- /**
956
- * --- 刷新当前模型获取最新数据 ---
957
- * @param lock 是否加锁
958
- */
959
- public async refresh(lock = false): Promise<boolean | null> {
960
- const cstr = this.constructor as Record<string, types.Json>;
961
- this._sql.select('*', (cstr._$table as string) + (this._index ? ('_' + this._index[0]) : '')).where([{
962
- [cstr._$primary]: this._data[cstr._$primary]
963
- }]);
964
- if (lock) {
965
- this._sql.lock();
966
- }
967
- const r = await this._db.query(this._sql.getSql(), this._sql.getData());
968
- if (r.rows === null) {
969
- await lCore.log(this._ctr ?? {
970
- 'path': '',
971
- 'urlFull': '',
972
- 'hostname': '',
973
- 'req': null,
974
- 'get': {},
975
- 'cookie': {},
976
- 'headers': {}
977
- }, '[refresh, mod] ' + lText.stringifyJson(r.error?.message ?? '').slice(1, -1).replace(/"/g, '""'), '-error');
978
- return false;
979
- }
980
- if (r.rows.length === 0) {
981
- return null;
982
- }
983
- for (const k in r.rows[0]) {
984
- const v = r.rows[0][k];
985
- this._data[k] = v;
986
- (this as types.Json)[k] = v;
987
- }
988
- return true;
989
- }
990
-
991
- /**
992
- * --- 更新 set 的数据到数据库,有未保存数据时才保存 ---
993
- */
994
- public async save(): Promise<boolean> {
995
- if (Object.keys(this._updates).length === 0) {
996
- return true;
997
- }
998
- const cstr = this.constructor as Record<string, types.Json>;
999
- const updates: Record<string, any> = {};
1000
- for (const k in this._updates) {
1001
- updates[k] = this._data[k];
1002
- }
1003
- this._sql.update((cstr._$table as string) + (this._index ? ('_' + this._index[0]) : ''), [updates]).where([{
1004
- [cstr._$primary]: this._data[cstr._$primary]
1005
- }]);
1006
- const r = await this._db.execute(this._sql.getSql(), this._sql.getData());
1007
- if (r.packet === null) {
1008
- await lCore.log(this._ctr ?? {
1009
- 'path': '',
1010
- 'urlFull': '',
1011
- 'hostname': '',
1012
- 'req': null,
1013
- 'get': {},
1014
- 'cookie': {},
1015
- 'headers': {}
1016
- }, '[save, mod] ' + lText.stringifyJson(r.error?.message ?? '').slice(1, -1).replace(/"/g, '""'), '-error');
1017
- return false;
1018
- }
1019
- if (r.packet.affectedRows > 0) {
1020
- this._updates = {};
1021
- return true;
1022
- }
1023
- else {
1024
- return false;
1025
- }
1026
- }
1027
-
1028
- /**
1029
- * --- 移除本条目 ---
1030
- * @param raw 是否真实移除
1031
- */
1032
- public async remove(raw: boolean = false): Promise<boolean> {
1033
- const tim = lTime.stamp();
1034
- const cstr = this.constructor as Record<string, types.Json>;
1035
- if (cstr._$soft && !raw) {
1036
- this._sql.update((cstr._$table as string) + (this._index ? ('_' + this._index[0]) : ''), [{
1037
- 'time_remove': tim
1038
- }]).where([{
1039
- [cstr._$primary]: this._data[cstr._$primary],
1040
- 'time_remove': 0
1041
- }]);
1042
- }
1043
- else {
1044
- this._sql.delete((cstr._$table as string) + (this._index ? ('_' + this._index[0]) : '')).where([{
1045
- [cstr._$primary]: this._data[cstr._$primary]
1046
- }]);
1047
- }
1048
- const r = await this._db.execute(this._sql.getSql(), this._sql.getData());
1049
- if (r.packet === null) {
1050
- await lCore.log(this._ctr ?? {
1051
- 'path': '',
1052
- 'urlFull': '',
1053
- 'hostname': '',
1054
- 'req': null,
1055
- 'get': {},
1056
- 'cookie': {},
1057
- 'headers': {}
1058
- }, '[remove, mod] ' + lText.stringifyJson(r.error?.message ?? '').slice(1, -1).replace(/"/g, '""'), '-error');
1059
- return false;
1060
- }
1061
- if (r.packet.affectedRows > 0) {
1062
- return true;
1063
- }
1064
- else {
1065
- return false;
1066
- }
1067
- }
1068
-
1069
- public async first(
1070
- lock: boolean,
1071
- array: true
1072
- ): Promise<false | null | Record<string, any>>;
1073
- public async first(
1074
- lock?: boolean,
1075
- array?: false
1076
- ): Promise<false | null | (this & Record<string, any>)>;
1077
- /**
1078
- * --- 获取数据库第一个对象 ---
1079
- * @param lock 是否加锁
1080
- * @param array 是否返回原生对象
1081
- */
1082
- public async first(
1083
- lock: boolean = false,
1084
- array: boolean = false
1085
- ): Promise<false | null | (this & Record<string, any>) | Record<string, any>> {
1086
- this._sql.limit(1);
1087
- if (lock) {
1088
- this._sql.lock();
1089
- }
1090
- const r = await this._db.query(this._sql.getSql(), this._sql.getData());
1091
- if (r.rows === null) {
1092
- await lCore.log(this._ctr ?? {
1093
- 'path': '',
1094
- 'urlFull': '',
1095
- 'hostname': '',
1096
- 'req': null,
1097
- 'get': {},
1098
- 'cookie': {},
1099
- 'headers': {}
1100
- }, '[first, mod] ' + lText.stringifyJson(r.error?.message ?? '').slice(1, -1).replace(/"/g, '""'), '-error');
1101
- return false;
1102
- }
1103
- if (r.rows.length === 0) {
1104
- return null;
1105
- }
1106
- if (array) {
1107
- return r.rows[0];
1108
- }
1109
- for (const k in r.rows[0]) {
1110
- const v = r.rows[0][k];
1111
- this._data[k] = v;
1112
- (this as unknown as Record<string, any>)[k] = v;
1113
- }
1114
- return this as this & Record<string, any>;
1115
- }
1116
-
1117
- /**
1118
- * --- 获取数据库第一个原生对象 ---
1119
- * @param lock 是否加锁
1120
- */
1121
- public async firstArray(
1122
- lock: boolean = false
1123
- ): Promise<Record<string, any> | false | null> {
1124
- return this.first(lock, true);
1125
- }
1126
-
1127
- /**
1128
- * --- 联合查询表数据 ---
1129
- * @param f 要联合查询的表列表、单个表、sql 对象
1130
- * @param type 类型
1131
- */
1132
- public union(f: lSql.Sql | string | types.IModUnionItem | string[] | types.IModUnionItem[], type: string = ''): this {
1133
- if (f instanceof lSql.Sql) {
1134
- this._sql.union(f, type);
1135
- return this;
1136
- }
1137
- if (typeof f === 'string') {
1138
- f = {
1139
- 'field': f
1140
- };
1141
- }
1142
- if (!Array.isArray(f)) {
1143
- f = [f];
1144
- }
1145
- for (let item of f) {
1146
- if (typeof item === 'string') {
1147
- item = {
1148
- 'field': item
1149
- };
1150
- }
1151
- this._sql.union(this._sql.copy(item.field, {
1152
- 'where': item.where
1153
- }), type);
1154
- }
1155
- return this;
1156
- }
1157
-
1158
- /**
1159
- * --- 所有联合查询表数据 ---
1160
- * @param f 要联合查询的表列表、单个表、sql 对象
1161
- */
1162
- public unionAll(f: lSql.Sql | string | types.IModUnionItem | string[] | types.IModUnionItem[]): this {
1163
- if (f instanceof lSql.Sql) {
1164
- this._sql.unionAll(f);
1165
- return this;
1166
- }
1167
- if (typeof f === 'string') {
1168
- f = {
1169
- 'field': f
1170
- };
1171
- }
1172
- if (!Array.isArray(f)) {
1173
- f = [f];
1174
- }
1175
- for (let item of f) {
1176
- if (typeof item === 'string') {
1177
- item = {
1178
- 'field': item
1179
- };
1180
- }
1181
- this._sql.unionAll(this._sql.copy(item.field, {
1182
- 'where': item.where
1183
- }));
1184
- }
1185
- return this;
1186
- }
1187
-
1188
- public async all(): Promise<false | Rows<this>>;
1189
- public async all(key: string): Promise<false | Record<string, this>>;
1190
- /**
1191
- * --- 获取列表 ---
1192
- * @param key 是否以某个字段为主键
1193
- */
1194
- public async all(key?: string): Promise<false | Rows<this> | Record<string, this>> {
1195
- this._total.length = 0;
1196
- if (this._index && this._index.length > 1) {
1197
- // --- 多表 ---
1198
- let sql = this._sql.getSql();
1199
- /** --- 返回的最终 list --- */
1200
- const list: Record<string, this> | this[] = key ? {} : [];
1201
- /** --- 用户传输的起始值 --- */
1202
- const limit = [this._limit[0] ?? 0, this._limit[1] ?? 200];
1203
- /** --- 已过的 offset,-1 代表不再计算 offset 了 --- */
1204
- let offset = 0;
1205
- /** --- 剩余条数 --- */
1206
- let remain = limit[1];
1207
- for (let i = 0; i < this._index.length; ++i) {
1208
- // --- 先计算 total ---
1209
- if (i > 0) {
1210
- sql = sql.replace(/(FROM [a-zA-Z0-9`_.]+?_)[0-9_]+/, '$1' + this._index[i]);
1211
- }
1212
- const tsql = this._formatTotal(sql);
1213
- const tr = await this._db.query(tsql, this._sql.getData());
1214
- if (tr.rows === null) {
1215
- return false;
1216
- }
1217
- let count = 0;
1218
- for (const item of tr.rows) {
1219
- count += item.count;
1220
- }
1221
- this._total.push(count);
1222
- if (remain === 0) {
1223
- // --- 下一个表需要接着执行 total 计算,所以不能 break ---
1224
- continue;
1225
- }
1226
- // --- 开始查数据 ---
1227
- /** --- 差值 --- */
1228
- let cz = 0;
1229
- if (offset > -1) {
1230
- cz = limit[0] - offset;
1231
- if (cz >= count) {
1232
- offset += count;
1233
- continue;
1234
- }
1235
- }
1236
- const lsql = sql.replace(/ LIMIT [0-9 ,]/g, ` LIMIT ${cz}, ${remain}`);
1237
- const r = await this._db.query(lsql, this._sql.getData());
1238
- if (r.rows === null) {
1239
- await lCore.log(this._ctr ?? {
1240
- 'path': '',
1241
- 'urlFull': '',
1242
- 'hostname': '',
1243
- 'req': null,
1244
- 'get': {},
1245
- 'cookie': {},
1246
- 'headers': {}
1247
- }, '[all, mod] ' + lText.stringifyJson(r.error?.message ?? '').slice(1, -1).replace(/"/g, '""'), '-error');
1248
- return false;
1249
- }
1250
- if (key) {
1251
- for (const row of r.rows) {
1252
- const obj = new (this.constructor as new (
1253
- o: Record<string, types.Json>
1254
- ) => this)({
1255
- 'db': this._db,
1256
- 'ctr': this._ctr,
1257
- 'pre': this._sql.getPre(),
1258
- 'row': row,
1259
- 'index': this._index
1260
- });
1261
- (list as Record<string, this>)[row[key]] = obj;
1262
- --remain;
1263
- }
1264
- continue;
1265
- }
1266
- for (const row of r.rows) {
1267
- const obj = new (this.constructor as new (
1268
- o: Record<string, types.Json>
1269
- ) => this)({
1270
- 'db': this._db,
1271
- 'ctr': this._ctr,
1272
- 'pre': this._sql.getPre(),
1273
- 'row': row,
1274
- 'index': this._index
1275
- });
1276
- (list as this[]).push(obj);
1277
- --remain;
1278
- }
1279
- continue;
1280
- }
1281
- return Array.isArray(list) ? new Rows<this>(list) : list;
1282
- }
1283
- // --- 单表 ---
1284
- const contain = this._contain ? lCore.clone(this._contain.list) : null;
1285
- const r = await this._db.query(this._sql.getSql(), this._sql.getData());
1286
- if (r.rows === null) {
1287
- await lCore.log(this._ctr ?? {
1288
- 'path': '',
1289
- 'urlFull': '',
1290
- 'hostname': '',
1291
- 'req': null,
1292
- 'get': {},
1293
- 'cookie': {},
1294
- 'headers': {}
1295
- }, '[all, mod] ' + lText.stringifyJson(r.error?.message ?? '').slice(1, -1).replace(/"/g, '""'), '-error');
1296
- return false;
1297
- }
1298
- // --- 检查没被查到的必包含项 ---
1299
- for (const row of r.rows) {
1300
- if (this._contain && contain) {
1301
- const io = contain.indexOf(row[this._contain.key]);
1302
- if (io !== -1) {
1303
- contain.splice(io, 1);
1304
- }
1305
- }
1306
- }
1307
- let cr: lDb.IData | null = null;
1308
- if (this._contain && contain?.length) {
1309
- const csql = this._sql.copy(undefined, {
1310
- 'where': {
1311
- [this._contain.key]: this._contain.list
1312
- }
1313
- });
1314
- cr = await this._db.query(csql.getSql(), csql.getData());
1315
- }
1316
- if (key) {
1317
- const list: Record<string, this> = {};
1318
- for (const row of r.rows) {
1319
- const obj = new (this.constructor as new (
1320
- o: Record<string, types.Json>
1321
- ) => this)({
1322
- 'db': this._db,
1323
- 'ctr': this._ctr,
1324
- 'pre': this._sql.getPre(),
1325
- 'row': row,
1326
- 'index': this._index
1327
- });
1328
- list[row[key]] = obj;
1329
- }
1330
- // --- 有没有必须包含的项 ---
1331
- if (cr?.rows) {
1332
- for (const crow of cr.rows) {
1333
- const obj = new (this.constructor as new (
1334
- o: Record<string, types.Json>
1335
- ) => this)({
1336
- 'db': this._db,
1337
- 'ctr': this._ctr,
1338
- 'pre': this._sql.getPre(),
1339
- 'row': crow,
1340
- 'index': this._index
1341
- });
1342
- list[crow[key]] = obj;
1343
- }
1344
- }
1345
- return list;
1346
- }
1347
- const list: this[] = [];
1348
- for (const row of r.rows) {
1349
- const obj = new (this.constructor as new (
1350
- o: Record<string, types.Json>
1351
- ) => this)({
1352
- 'db': this._db,
1353
- 'ctr': this._ctr,
1354
- 'pre': this._sql.getPre(),
1355
- 'row': row,
1356
- 'index': this._index
1357
- });
1358
- list.push(obj);
1359
- }
1360
- // --- 有没有必须包含的项 ---
1361
- if (cr?.rows) {
1362
- for (const crow of cr.rows) {
1363
- const obj = new (this.constructor as new (
1364
- o: Record<string, types.Json>
1365
- ) => this)({
1366
- 'db': this._db,
1367
- 'ctr': this._ctr,
1368
- 'pre': this._sql.getPre(),
1369
- 'row': crow,
1370
- 'index': this._index
1371
- });
1372
- list.push(obj);
1373
- }
1374
- }
1375
- return new Rows<this>(list);
1376
- }
1377
-
1378
- public async allArray(): Promise<false | Array<Record<string, any>>>;
1379
- public async allArray(key: string): Promise<false | Record<string, Record<string, any>>>;
1380
- /**
1381
- * --- 获取列表(得到的为原生对象或数组,不是模型) ---
1382
- * @param key 是否以某个字段为主键
1383
- */
1384
- public async allArray(key?: string): Promise<
1385
- false |
1386
- Array<Record<string, any>> |
1387
- Record<string, Record<string, any>>
1388
- > {
1389
- this._total.length = 0;
1390
- if (this._index && this._index.length > 1) {
1391
- // --- 多表 ---
1392
- let sql = this._sql.getSql();
1393
- /** --- 返回的最终 list --- */
1394
- const list: Record<string, Record<string, any>> | any[] = key ? {} : [];
1395
- /** --- 用户传输的起始值 --- */
1396
- const limit = [this._limit[0] ?? 0, this._limit[1] ?? 200];
1397
- /** --- 已过的 offset,-1 代表不再计算 offset 了 --- */
1398
- let offset = 0;
1399
- /** --- 剩余条数 --- */
1400
- let remain = limit[1];
1401
- for (let i = 0; i < this._index.length; ++i) {
1402
- // --- 先计算 total ---
1403
- if (i > 0) {
1404
- sql = sql.replace(/(FROM [a-zA-Z0-9`_.]+?_)[0-9_]+/, '$1' + this._index[i]);
1405
- }
1406
- const tsql = this._formatTotal(sql);
1407
- const tr = await this._db.query(tsql, this._sql.getData());
1408
- if (tr.rows === null) {
1409
- return false;
1410
- }
1411
- let count = 0;
1412
- for (const item of tr.rows) {
1413
- count += item.count;
1414
- }
1415
- this._total.push(count);
1416
- if (remain === 0) {
1417
- // --- 下一个表需要接着执行 total 计算,所以不能 break ---
1418
- continue;
1419
- }
1420
- // --- 开始查数据 ---
1421
- /** --- 差值 --- */
1422
- let cz = 0;
1423
- if (offset > -1) {
1424
- cz = limit[0] - offset;
1425
- if (cz >= count) {
1426
- offset += count;
1427
- continue;
1428
- }
1429
- // --- 在本表开始找之后,后面表无需再跳过 ---
1430
- offset = -1;
1431
- }
1432
- const lsql = sql.replace(/ LIMIT [0-9 ,]+/g, ` LIMIT ${cz}, ${remain}`);
1433
- const r = await this._db.query(lsql, this._sql.getData());
1434
- if (r.rows === null) {
1435
- await lCore.log(this._ctr ?? {
1436
- 'path': '',
1437
- 'urlFull': '',
1438
- 'hostname': '',
1439
- 'req': null,
1440
- 'get': {},
1441
- 'cookie': {},
1442
- 'headers': {}
1443
- }, '[allArray, mod] ' + lText.stringifyJson(r.error?.message ?? '').slice(1, -1).replace(/"/g, '""'), '-error');
1444
- return false;
1445
- }
1446
- if (key) {
1447
- for (const row of r.rows) {
1448
- (list as Record<string, Record<string, any>>)[row[key]] = row;
1449
- --remain;
1450
- }
1451
- continue;
1452
- }
1453
- for (const row of r.rows) {
1454
- (list as any[]).push(row);
1455
- --remain;
1456
- }
1457
- continue;
1458
- }
1459
- return list;
1460
- }
1461
- // --- 单表 ---
1462
- const contain = this._contain ? lCore.clone(this._contain.list) : null;
1463
- const r = await this._db.query(this._sql.getSql(), this._sql.getData());
1464
- if (r.rows === null) {
1465
- await lCore.log(this._ctr ?? {
1466
- 'path': '',
1467
- 'urlFull': '',
1468
- 'hostname': '',
1469
- 'req': null,
1470
- 'get': {},
1471
- 'cookie': {},
1472
- 'headers': {}
1473
- }, '[allArray, mod] ' + lText.stringifyJson(r.error?.message ?? '').slice(1, -1).replace(/"/g, '""'), '-error');
1474
- return false;
1475
- }
1476
- // --- 检查没被查到的必包含项 ---
1477
- for (const row of r.rows) {
1478
- if (this._contain && contain) {
1479
- const io = contain.indexOf(row[this._contain.key]);
1480
- if (io !== -1) {
1481
- contain.splice(io, 1);
1482
- }
1483
- }
1484
- }
1485
- let cr: lDb.IData | null = null;
1486
- if (this._contain && contain?.length) {
1487
- const csql = this._sql.copy(undefined, {
1488
- 'where': {
1489
- [this._contain.key]: this._contain.list
1490
- }
1491
- });
1492
- cr = await this._db.query(csql.getSql(), csql.getData());
1493
- }
1494
- if (key) {
1495
- const list: Record<string, Record<string, any>> = {};
1496
- for (const row of r.rows) {
1497
- list[row[key]] = row;
1498
- }
1499
- // --- 有没有必须包含的项 ---
1500
- if (cr?.rows) {
1501
- for (const crow of cr.rows) {
1502
- list[crow[key]] = crow;
1503
- }
1504
- }
1505
- return list;
1506
- }
1507
- // --- 有没有必须包含的项 ---
1508
- if (cr?.rows) {
1509
- for (const crow of cr.rows) {
1510
- r.rows.push(crow);
1511
- }
1512
- }
1513
- return r.rows;
1514
- }
1515
-
1516
- public async explain(all?: false): Promise<false | string>;
1517
- public async explain(all: true): Promise<false | Record<string, any>>;
1518
- /**
1519
- * --- 获取数查询(SELECT)扫描情况,获取字符串或kv数组 ---
1520
- * @param all 是否获取完全的情况,默认不获取,只返回扫描情况
1521
- */
1522
- public async explain(all = false): Promise<false | string | Record<string, any>> {
1523
- const r = await this._db.query('EXPLAIN ' + this._sql.getSql(), this._sql.getData());
1524
- if (r.rows === null) {
1525
- await lCore.log(this._ctr ?? {
1526
- 'path': '',
1527
- 'urlFull': '',
1528
- 'hostname': '',
1529
- 'req': null,
1530
- 'get': {},
1531
- 'cookie': {},
1532
- 'headers': {}
1533
- }, '[explain, mod] ' + lText.stringifyJson(r.error?.message ?? '').slice(1, -1).replace(/"/g, '""'), '-error');
1534
- return false;
1535
- }
1536
- if (!r.rows[0]) {
1537
- return false;
1538
- }
1539
- if (!all) {
1540
- return r.rows[0].type;
1541
- }
1542
- return r.rows[0];
1543
- }
1544
-
1545
- private _formatTotal(sql: string, f: string = '*'): string {
1546
- sql = sql
1547
- .replace(/ LIMIT [0-9 ,]+/g, '')
1548
- .replace(/ ORDER BY [\w`,. ]+(DESC|ASC)?/g, '');
1549
- if (sql.includes(' GROUP BY ')) {
1550
- return 'SELECT COUNT(0) AS `count` FROM(' + sql + ') AS `f`';
1551
- }
1552
- return sql
1553
- .replace(/SELECT .+? FROM/g, 'SELECT COUNT(' + this._sql.field(f) + ') AS `count` FROM');
1554
- }
1555
-
1556
- /**
1557
- * --- 获取总条数,自动抛弃 LIMIT,仅用于获取数据的情况(select) ---
1558
- */
1559
- public async total(f: string = '*'): Promise<number> {
1560
- if (this._total.length) {
1561
- let count = 0;
1562
- for (const item of this._total) {
1563
- count += item;
1564
- }
1565
- return count;
1566
- }
1567
- const sql: string = this._formatTotal(this._sql.getSql(), f);
1568
- const r = await this._db.query(sql, this._sql.getData());
1569
- if (r.rows === null) {
1570
- await lCore.log(this._ctr ?? {
1571
- 'path': '',
1572
- 'urlFull': '',
1573
- 'hostname': '',
1574
- 'req': null,
1575
- 'get': {},
1576
- 'cookie': {},
1577
- 'headers': {}
1578
- }, '[total, mod] ' + lText.stringifyJson(r.error?.message ?? '').slice(1, -1).replace(/"/g, '""'), '-error');
1579
- return 0;
1580
- }
1581
- let count = 0;
1582
- for (const item of r.rows) {
1583
- count += item.count;
1584
- }
1585
- return count;
1586
- }
1587
-
1588
- /**
1589
- * --- 根据当前条件,筛选出当前条目该有的数据条数 ---
1590
- */
1591
- public async count(): Promise<number> {
1592
- const sql: string = this._sql.getSql().replace(/SELECT .+? FROM/, 'SELECT COUNT(*) AS `count` FROM');
1593
- const r = await this._db.query(sql, this._sql.getData());
1594
- if (r.rows === null) {
1595
- await lCore.log(this._ctr ?? {
1596
- 'path': '',
1597
- 'urlFull': '',
1598
- 'hostname': '',
1599
- 'req': null,
1600
- 'get': {},
1601
- 'cookie': {},
1602
- 'headers': {}
1603
- }, '[count, mod] ' + lText.stringifyJson(r.error?.message ?? '').slice(1, -1).replace(/"/g, '""'), '-error');
1604
- return 0;
1605
- }
1606
- let count = 0;
1607
- for (const item of r.rows) {
1608
- count += item.count;
1609
- }
1610
- return count;
1611
- }
1612
-
1613
- /**
1614
- * @param f 表名
1615
- * @param s ON 信息
1616
- * @param type 类型
1617
- * @param index 给本表增加 index 分表项
1618
- * @param pre 前缀
1619
- */
1620
- public join(f: string, s: types.Json = [], type: string = 'INNER', index: string = '', pre: string = ''): this {
1621
- this._sql.join(f, s, type, index ? '_' + index : '', pre);
1622
- return this;
1623
- }
1624
-
1625
- /**
1626
- * --- left join 方法 ---
1627
- * @param f 表名
1628
- * @param s ON 信息
1629
- * @param index 给本表增加 index 分表项
1630
- */
1631
- public leftJoin(f: string, s: types.Json, index: string = '', pre: string = ''): this {
1632
- this._sql.leftJoin(f, s, index ? '_' + index : '', pre);
1633
- return this;
1634
- }
1635
-
1636
- /**
1637
- * --- right join 方法 ---
1638
- * @param f 表名
1639
- * @param s ON 信息
1640
- * @param index 给本表增加 index 分表项
1641
- */
1642
- public rightJoin(f: string, s: types.Json, index: string = '', pre: string = ''): this {
1643
- this._sql.rightJoin(f, s, index ? '_' + index : '', pre);
1644
- return this;
1645
- }
1646
-
1647
- /**
1648
- * --- inner join 方法 ---
1649
- * @param f 表名
1650
- * @param s ON 信息
1651
- * @param index 给本表增加 index 分表项
1652
- */
1653
- public innerJoin(f: string, s: types.Json, index: string = '', pre: string = ''): this {
1654
- this._sql.innerJoin(f, s, index ? '_' + index : '', pre);
1655
- return this;
1656
- }
1657
-
1658
- /**
1659
- * --- full join 方法 ---
1660
- * @param f 表名
1661
- * @param s ON 信息
1662
- * @param index 给本表增加 index 分表项
1663
- */
1664
- public fullJoin(f: string, s: types.Json, index: string = '', pre: string = ''): this {
1665
- this._sql.fullJoin(f, s, index ? '_' + index : '', pre);
1666
- return this;
1667
- }
1668
-
1669
- /**
1670
- * --- cross join 方法 ---
1671
- * @param f 表名
1672
- * @param s ON 信息
1673
- * @param index 给本表增加 index 分表项
1674
- */
1675
- public crossJoin(f: string, s: types.Json, index: string = '', pre: string = ''): this {
1676
- this._sql.crossJoin(f, s, index ? '_' + index : '', pre);
1677
- return this;
1678
- }
1679
-
1680
- /**
1681
- * --- 筛选器 ---
1682
- * @param s 筛选条件数组或字符串
1683
- */
1684
- public having(s: types.Json): this {
1685
- this._sql.having(s);
1686
- return this;
1687
- }
1688
-
1689
- /**
1690
- * --- 筛选器 ---
1691
- * @param s 筛选条件数组或字符串
1692
- * @param raw 是否包含已被软删除的数据
1693
- */
1694
- public filter(
1695
- s: types.Json,
1696
- raw: boolean = false
1697
- ): this {
1698
- const cstr = this.constructor as Record<string, types.Json>;
1699
- if (cstr._soft && !raw) {
1700
- if (typeof s === 'string') {
1701
- s = '(' + s + ') AND `time_remove` = 0';
1702
- }
1703
- else if (Array.isArray(s)) {
1704
- s.push({
1705
- 'time_remove': 0
1706
- });
1707
- }
1708
- else {
1709
- s['time_remove'] = 0;
1710
- }
1711
- }
1712
- this._sql.where(s);
1713
- return this;
1714
- }
1715
-
1716
- /**
1717
- * --- 是 filter 的别名 ---
1718
- * @param s 筛选条件数组或字符串
1719
- * @param raw 是否包含已被软删除的数据
1720
- */
1721
- public where(
1722
- s: types.Json,
1723
- raw: boolean = false
1724
- ): this {
1725
- return this.filter(s, raw);
1726
- }
1727
-
1728
- /**
1729
- * --- ORDER BY ---
1730
- * @param c 字段字符串或数组
1731
- * @param d 排序规则
1732
- */
1733
- public by(c: string | Array<string | string[]>, d: 'DESC' | 'ASC' = 'DESC'): this {
1734
- this._sql.by(c, d);
1735
- return this;
1736
- }
1737
-
1738
- /**
1739
- * --- GROUP BY ---
1740
- * @param c 字段字符串或数组
1741
- */
1742
- public group(c: string | string[]): this {
1743
- this._sql.group(c);
1744
- return this;
1745
- }
1746
-
1747
- /** --- 设置的 limit --- */
1748
- private _limit: number[] = [0, 0];
1749
-
1750
- /**
1751
- * --- LIMIT ---
1752
- * @param a 起始
1753
- * @param b 长度
1754
- */
1755
- public limit(a: number, b: number = 0): this {
1756
- this._sql.limit(a, b);
1757
- this._limit = [a, b];
1758
- return this;
1759
- }
1760
-
1761
- /**
1762
- * --- 分页 ---
1763
- * @param count 每页条数
1764
- * @param page 当前页数
1765
- */
1766
- public page(count: number, page: number = 1): this {
1767
- const a = count * (page - 1);
1768
- this._sql.limit(a, count);
1769
- this._limit = [a, count];
1770
- return this;
1771
- }
1772
-
1773
- /**
1774
- * --- 在 sql 最后追加字符串 ---
1775
- * @param sql
1776
- */
1777
- public append(sql: string): this {
1778
- this._sql.append(sql);
1779
- return this;
1780
- }
1781
-
1782
- /**
1783
- * --- 设置闭包含数据 ---
1784
- * @param contain 设置项
1785
- */
1786
- public contain(contain: {
1787
- 'key': string;
1788
- 'list': string[];
1789
- } ): this {
1790
- this._contain = contain;
1791
- return this;
1792
- }
1793
-
1794
- /**
1795
- * --- 获取 sql 语句 ---
1796
- */
1797
- public getSql(): string {
1798
- return this._sql.getSql();
1799
- }
1800
-
1801
- /**
1802
- * --- 获取全部 data ---
1803
- */
1804
- public getData(): any[] {
1805
- return this._sql.getData();
1806
- }
1807
-
1808
- /**
1809
- * --- 获取带 data 的 sql 语句 ---
1810
- * @param sql sql 语句
1811
- * @param data 数据
1812
- */
1813
- public format(sql?: string, data?: any[]): string {
1814
- return this._sql.format(sql, data);
1815
- }
1816
-
1817
- /**
1818
- * --- 获取值对象 ---
1819
- */
1820
- public toArray(): Record<string, any> {
1821
- return this._data;
1822
- }
1823
-
1824
- /**
1825
- * --- 获取当前设置要提交的数据 ---
1826
- */
1827
- public updates(): Record<string, any> {
1828
- const updates: Record<string, any> = {};
1829
- for (const k in this._updates) {
1830
- updates[k] = this._data[k];
1831
- }
1832
- return updates;
1833
- }
1834
-
1835
- /**
1836
- * --- 当前是否设置了未保存 --=
1837
- */
1838
- public unsaved(): boolean {
1839
- return Object.keys(this._updates).length ? true : false;
1840
- }
1841
-
1842
- /**
1843
- * --- 获取字段的可用语种文本 ---
1844
- * @param col 字段名
1845
- * @param lang 当前请求语种,如 sc
1846
- */
1847
- public langText(col: string, lang: string): string {
1848
- const key = `${col}_${lang}`;
1849
- if (this._data[key]) {
1850
- return this._data[key];
1851
- }
1852
- if (lang !== 'en' && this._data[`${col}_en`]) {
1853
- return this._data[`${col}_en`];
1854
- }
1855
- for (const k in this._data) {
1856
- if (k.startsWith(`${col}_`) && this._data[k]) {
1857
- // --- 符合要求的字段并且字段有值(不为空) ---
1858
- return this._data[k];
1859
- }
1860
- }
1861
- return '';
1862
- }
1863
-
1864
- /**
1865
- * --- 当 _key 不为空时,则依据继承此方法的方法自动生成填充 key ---
1866
- */
1867
- protected _keyGenerator(): string {
1868
- return '';
1869
- }
1870
-
1871
- }