@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.
- package/index.js +1 -1
- package/lib/sql.js +1 -3
- package/lib/text.js +5 -1
- package/package.json +1 -1
- package/tsconfig.json +1 -1
- package/index.ts +0 -33
- package/lib/buffer.ts +0 -152
- package/lib/captcha.ts +0 -63
- package/lib/consistent.ts +0 -219
- package/lib/core.ts +0 -880
- package/lib/crypto.ts +0 -384
- package/lib/db.ts +0 -719
- package/lib/dns.ts +0 -405
- package/lib/fs.ts +0 -527
- package/lib/jwt.ts +0 -276
- package/lib/kv.ts +0 -1489
- package/lib/lan.ts +0 -87
- package/lib/net/formdata.ts +0 -166
- package/lib/net/request.ts +0 -150
- package/lib/net/response.ts +0 -59
- package/lib/net.ts +0 -662
- package/lib/s3.ts +0 -235
- package/lib/scan.ts +0 -364
- package/lib/session.ts +0 -230
- package/lib/sql.ts +0 -1151
- package/lib/ssh/sftp.ts +0 -508
- package/lib/ssh/shell.ts +0 -123
- package/lib/ssh.ts +0 -191
- package/lib/text.ts +0 -615
- package/lib/time.ts +0 -254
- package/lib/ws.ts +0 -523
- package/lib/zip.ts +0 -447
- package/lib/zlib.ts +0 -350
- package/main.ts +0 -27
- package/sys/child.ts +0 -678
- package/sys/cmd.ts +0 -225
- package/sys/ctr.ts +0 -904
- package/sys/master.ts +0 -355
- package/sys/mod.ts +0 -1871
- package/sys/route.ts +0 -1113
- package/types/index.d.ts +0 -283
- package/www/example/ctr/main.ts +0 -9
- package/www/example/ctr/middle.ts +0 -26
- package/www/example/ctr/test.ts +0 -3218
- package/www/example/mod/test.ts +0 -47
- package/www/example/mod/testdata.ts +0 -30
- package/www/example/ws/mproxy.ts +0 -16
- package/www/example/ws/rproxy.ts +0 -14
- 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
|
-
}
|