@waline/vercel 1.26.3 → 1.26.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/dist/404.html +39 -0
- package/dist/500.html +275 -0
- package/dist/index.js +58501 -0
- package/dist/package.json +54 -0
- package/dist/src/config/adapter.js +170 -0
- package/dist/src/config/config.js +134 -0
- package/dist/src/config/extend.js +38 -0
- package/dist/src/config/middleware.js +66 -0
- package/dist/src/config/router.js +1 -0
- package/dist/src/controller/article.js +91 -0
- package/dist/src/controller/comment.js +758 -0
- package/dist/src/controller/db.js +71 -0
- package/dist/src/controller/index.js +36 -0
- package/dist/src/controller/oauth.js +136 -0
- package/dist/src/controller/rest.js +60 -0
- package/dist/src/controller/token/2fa.js +66 -0
- package/dist/src/controller/token.js +75 -0
- package/dist/src/controller/user/password.js +52 -0
- package/dist/src/controller/user.js +289 -0
- package/dist/src/controller/verification.js +35 -0
- package/dist/src/extend/controller.js +25 -0
- package/dist/src/extend/think.js +84 -0
- package/dist/src/locales/en.json +19 -0
- package/dist/src/locales/index.js +12 -0
- package/dist/src/locales/zh-CN.json +19 -0
- package/dist/src/locales/zh-TW.json +19 -0
- package/dist/src/logic/article.js +27 -0
- package/dist/src/logic/base.js +164 -0
- package/dist/src/logic/comment.js +317 -0
- package/dist/src/logic/db.js +81 -0
- package/dist/src/logic/oauth.js +10 -0
- package/dist/src/logic/token/2fa.js +28 -0
- package/dist/src/logic/token.js +53 -0
- package/dist/src/logic/user/password.js +11 -0
- package/dist/src/logic/user.js +117 -0
- package/dist/src/middleware/dashboard.js +23 -0
- package/dist/src/middleware/version.js +6 -0
- package/dist/src/service/akismet.js +41 -0
- package/dist/src/service/avatar.js +35 -0
- package/dist/src/service/markdown/highlight.js +32 -0
- package/dist/src/service/markdown/index.js +63 -0
- package/dist/src/service/markdown/katex.js +49 -0
- package/dist/src/service/markdown/mathCommon.js +156 -0
- package/dist/src/service/markdown/mathjax.js +78 -0
- package/dist/src/service/markdown/utils.js +11 -0
- package/dist/src/service/markdown/xss.js +44 -0
- package/dist/src/service/notify.js +537 -0
- package/dist/src/service/storage/base.js +31 -0
- package/dist/src/service/storage/cloudbase.js +221 -0
- package/dist/src/service/storage/deta.js +307 -0
- package/dist/src/service/storage/github.js +377 -0
- package/dist/src/service/storage/leancloud.js +430 -0
- package/dist/src/service/storage/mongodb.js +179 -0
- package/dist/src/service/storage/mysql.js +123 -0
- package/dist/src/service/storage/postgresql.js +84 -0
- package/dist/src/service/storage/sqlite.js +11 -0
- package/dist/src/service/storage/tidb.js +3 -0
- package/package.json +1 -1
- package/src/controller/comment.js +1 -2
- package/src/extend/think.js +19 -0
|
@@ -0,0 +1,430 @@
|
|
|
1
|
+
const AV = require('leancloud-storage');
|
|
2
|
+
const Base = require('./base');
|
|
3
|
+
const { LEAN_ID, LEAN_KEY, LEAN_MASTER_KEY, LEAN_SERVER } = process.env;
|
|
4
|
+
|
|
5
|
+
if (LEAN_ID && LEAN_KEY && LEAN_MASTER_KEY) {
|
|
6
|
+
AV.Cloud.useMasterKey(true);
|
|
7
|
+
AV.init({
|
|
8
|
+
appId: LEAN_ID,
|
|
9
|
+
appKey: LEAN_KEY,
|
|
10
|
+
masterKey: LEAN_MASTER_KEY,
|
|
11
|
+
// required for leancloud china
|
|
12
|
+
serverURL: LEAN_SERVER,
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
module.exports = class extends Base {
|
|
16
|
+
parseWhere(className, where) {
|
|
17
|
+
const instance = new AV.Query(className);
|
|
18
|
+
|
|
19
|
+
if (think.isEmpty(where)) {
|
|
20
|
+
return instance;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
for (const k in where) {
|
|
24
|
+
if (k === '_complex') {
|
|
25
|
+
continue;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if (think.isString(where[k])) {
|
|
29
|
+
instance.equalTo(k, where[k]);
|
|
30
|
+
continue;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (where[k] === undefined) {
|
|
34
|
+
instance.doesNotExist(k);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if (Array.isArray(where[k])) {
|
|
38
|
+
if (where[k][0]) {
|
|
39
|
+
const handler = where[k][0].toUpperCase();
|
|
40
|
+
|
|
41
|
+
switch (handler) {
|
|
42
|
+
case 'IN':
|
|
43
|
+
instance.containedIn(k, where[k][1]);
|
|
44
|
+
break;
|
|
45
|
+
case 'NOT IN':
|
|
46
|
+
instance.notContainedIn(k, where[k][1]);
|
|
47
|
+
break;
|
|
48
|
+
case 'LIKE': {
|
|
49
|
+
const first = where[k][1][0];
|
|
50
|
+
const last = where[k][1].slice(-1);
|
|
51
|
+
|
|
52
|
+
if (first === '%' && last === '%') {
|
|
53
|
+
instance.contains(k, where[k][1].slice(1, -1));
|
|
54
|
+
} else if (first === '%') {
|
|
55
|
+
instance.endsWith(k, where[k][1].slice(1));
|
|
56
|
+
} else if (last === '%') {
|
|
57
|
+
instance.startsWith(k, where[k][1].slice(0, -1));
|
|
58
|
+
}
|
|
59
|
+
break;
|
|
60
|
+
}
|
|
61
|
+
case '!=':
|
|
62
|
+
instance.notEqualTo(k, where[k][1]);
|
|
63
|
+
break;
|
|
64
|
+
case '>':
|
|
65
|
+
instance.greaterThan(k, where[k][1]);
|
|
66
|
+
break;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return instance;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
where(className, where) {
|
|
76
|
+
if (!where._complex) {
|
|
77
|
+
return this.parseWhere(className, where);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const filters = [];
|
|
81
|
+
|
|
82
|
+
for (const k in where._complex) {
|
|
83
|
+
if (k === '_logic') {
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const filter = this.parseWhere(className, {
|
|
88
|
+
...where,
|
|
89
|
+
[k]: where._complex[k],
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
filters.push(filter);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return AV.Query[where._complex._logic](...filters);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
async _select(where, { desc, limit, offset, field } = {}) {
|
|
99
|
+
const instance = this.where(this.tableName, where);
|
|
100
|
+
|
|
101
|
+
if (desc) {
|
|
102
|
+
instance.descending(desc);
|
|
103
|
+
}
|
|
104
|
+
if (limit) {
|
|
105
|
+
instance.limit(limit);
|
|
106
|
+
}
|
|
107
|
+
if (offset) {
|
|
108
|
+
instance.skip(offset);
|
|
109
|
+
}
|
|
110
|
+
if (field) {
|
|
111
|
+
instance.select(field);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const data = await instance.find().catch((e) => {
|
|
115
|
+
if (e.code === 101) {
|
|
116
|
+
return [];
|
|
117
|
+
}
|
|
118
|
+
throw e;
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
return data.map((item) => item.toJSON());
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
async select(where, options = {}) {
|
|
125
|
+
let data = [];
|
|
126
|
+
let ret = [];
|
|
127
|
+
let offset = options.offset || 0;
|
|
128
|
+
|
|
129
|
+
do {
|
|
130
|
+
options.offset = offset + data.length;
|
|
131
|
+
ret = await this._select(where, options);
|
|
132
|
+
data = data.concat(ret);
|
|
133
|
+
} while (ret.length === 100);
|
|
134
|
+
|
|
135
|
+
return data;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
async _getCmtGroupByMailUserIdCache(key, where) {
|
|
139
|
+
if (
|
|
140
|
+
this.tableName !== 'Comment' ||
|
|
141
|
+
key !== 'user_id_mail' ||
|
|
142
|
+
!think.isArray(think.config('levels'))
|
|
143
|
+
) {
|
|
144
|
+
return [];
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const cacheTableName = `cache_group_count_${key}`;
|
|
148
|
+
const currentTableName = this.tableName;
|
|
149
|
+
|
|
150
|
+
this.tableName = cacheTableName;
|
|
151
|
+
const cacheData = await this.select({ _complex: where._complex });
|
|
152
|
+
|
|
153
|
+
this.tableName = currentTableName;
|
|
154
|
+
|
|
155
|
+
return cacheData;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
async _setCmtGroupByMailUserIdCache(key, data) {
|
|
159
|
+
if (
|
|
160
|
+
this.tableName !== 'Comment' ||
|
|
161
|
+
key !== 'user_id_mail' ||
|
|
162
|
+
!think.isArray(think.config('levels'))
|
|
163
|
+
) {
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
const cacheTableName = `cache_group_count_${key}`;
|
|
168
|
+
const currentTableName = this.tableName;
|
|
169
|
+
|
|
170
|
+
this.tableName = cacheTableName;
|
|
171
|
+
|
|
172
|
+
await think.promiseAllQueue(
|
|
173
|
+
data.map((item) => {
|
|
174
|
+
if (item.user_id && !think.isString(item.user_id)) {
|
|
175
|
+
item.user_id = item.user_id.toString();
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
return this.add(item);
|
|
179
|
+
}),
|
|
180
|
+
1
|
|
181
|
+
);
|
|
182
|
+
this.tableName = currentTableName;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
async _updateCmtGroupByMailUserIdCache(data, method) {
|
|
186
|
+
if (
|
|
187
|
+
this.tableName !== 'Comment' ||
|
|
188
|
+
!think.isArray(think.config('levels'))
|
|
189
|
+
) {
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
if (!data.user_id && !data.mail) {
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
const cacheTableName = `cache_group_count_user_id_mail`;
|
|
198
|
+
const cacheData = await this.select({
|
|
199
|
+
_complex: {
|
|
200
|
+
_logic: 'or',
|
|
201
|
+
user_id: think.isObject(data.user_id)
|
|
202
|
+
? data.user_id.toString()
|
|
203
|
+
: data.user_id,
|
|
204
|
+
mail: data.mail,
|
|
205
|
+
},
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
if (think.isEmpty(data)) {
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
let count = cacheData[0].count;
|
|
213
|
+
|
|
214
|
+
switch (method) {
|
|
215
|
+
case 'add':
|
|
216
|
+
if (data.status === 'approved') {
|
|
217
|
+
count += 1;
|
|
218
|
+
}
|
|
219
|
+
break;
|
|
220
|
+
case 'udpate_status':
|
|
221
|
+
if (data.status === 'approved') {
|
|
222
|
+
count += 1;
|
|
223
|
+
} else {
|
|
224
|
+
count -= 1;
|
|
225
|
+
}
|
|
226
|
+
break;
|
|
227
|
+
case 'delete':
|
|
228
|
+
count -= 1;
|
|
229
|
+
break;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
const currentTableName = this.tableName;
|
|
233
|
+
|
|
234
|
+
this.tableName = cacheTableName;
|
|
235
|
+
await this.update({ count }, { objectId: cacheData[0].objectId }).catch(
|
|
236
|
+
(e) => {
|
|
237
|
+
if (e.code === 101) {
|
|
238
|
+
return;
|
|
239
|
+
}
|
|
240
|
+
throw e;
|
|
241
|
+
}
|
|
242
|
+
);
|
|
243
|
+
this.tableName = currentTableName;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
async count(where = {}, options = {}) {
|
|
247
|
+
const instance = this.where(this.tableName, where);
|
|
248
|
+
|
|
249
|
+
if (!options.group) {
|
|
250
|
+
return instance.count(options).catch((e) => {
|
|
251
|
+
if (e.code === 101) {
|
|
252
|
+
return 0;
|
|
253
|
+
}
|
|
254
|
+
throw e;
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// get group count cache by group field where data
|
|
259
|
+
const cacheData = await this._getCmtGroupByMailUserIdCache(
|
|
260
|
+
options.group.join('_'),
|
|
261
|
+
where
|
|
262
|
+
);
|
|
263
|
+
|
|
264
|
+
if (!where._complex) {
|
|
265
|
+
if (cacheData.length) {
|
|
266
|
+
return cacheData;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
const counts = await this.select(where, { field: options.group });
|
|
270
|
+
const countsMap = {};
|
|
271
|
+
|
|
272
|
+
for (let i = 0; i < counts.length; i++) {
|
|
273
|
+
const key = options.group
|
|
274
|
+
.map((item) => counts[i][item] || undefined)
|
|
275
|
+
.join('_');
|
|
276
|
+
|
|
277
|
+
if (!countsMap[key]) {
|
|
278
|
+
countsMap[key] = {};
|
|
279
|
+
|
|
280
|
+
for (let j = 0; j < options.group.length; j++) {
|
|
281
|
+
const field = options.group[j];
|
|
282
|
+
|
|
283
|
+
countsMap[key][field] = counts[i][field];
|
|
284
|
+
}
|
|
285
|
+
countsMap[key].count = 0;
|
|
286
|
+
}
|
|
287
|
+
countsMap[key].count += 1;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
const ret = Object.values(countsMap);
|
|
291
|
+
|
|
292
|
+
// cache data
|
|
293
|
+
await this._setCmtGroupByMailUserIdCache(options.group.join('_'), ret);
|
|
294
|
+
|
|
295
|
+
return ret;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
const cacheDataMap = {};
|
|
299
|
+
|
|
300
|
+
for (let i = 0; i < cacheData.length; i++) {
|
|
301
|
+
const key = options.group
|
|
302
|
+
.map((item) => cacheData[i][item] || undefined)
|
|
303
|
+
.join('_');
|
|
304
|
+
|
|
305
|
+
cacheDataMap[key] = cacheData[i];
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
const counts = [];
|
|
309
|
+
const countsPromise = [];
|
|
310
|
+
|
|
311
|
+
for (let i = 0; i < options.group.length; i++) {
|
|
312
|
+
const groupName = options.group[i];
|
|
313
|
+
|
|
314
|
+
if (!where._complex || !Array.isArray(where._complex[groupName])) {
|
|
315
|
+
continue;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
const groupFlatValue = {};
|
|
319
|
+
|
|
320
|
+
options.group.slice(0, i).forEach((group) => {
|
|
321
|
+
groupFlatValue[group] = undefined;
|
|
322
|
+
});
|
|
323
|
+
|
|
324
|
+
for (let j = 0; j < where._complex[groupName][1].length; j++) {
|
|
325
|
+
const cacheKey = options.group
|
|
326
|
+
.map(
|
|
327
|
+
(item) =>
|
|
328
|
+
({
|
|
329
|
+
...groupFlatValue,
|
|
330
|
+
[groupName]: where._complex[groupName][1][j],
|
|
331
|
+
}[item] || undefined)
|
|
332
|
+
)
|
|
333
|
+
.join('_');
|
|
334
|
+
|
|
335
|
+
if (cacheDataMap[cacheKey]) {
|
|
336
|
+
continue;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
const groupWhere = {
|
|
340
|
+
...where,
|
|
341
|
+
...groupFlatValue,
|
|
342
|
+
_complex: undefined,
|
|
343
|
+
[groupName]: where._complex[groupName][1][j],
|
|
344
|
+
};
|
|
345
|
+
const countPromise = this.count(groupWhere, {
|
|
346
|
+
...options,
|
|
347
|
+
group: undefined,
|
|
348
|
+
}).then((num) => {
|
|
349
|
+
counts.push({
|
|
350
|
+
...groupFlatValue,
|
|
351
|
+
[groupName]: where._complex[groupName][1][j],
|
|
352
|
+
count: num,
|
|
353
|
+
});
|
|
354
|
+
});
|
|
355
|
+
|
|
356
|
+
countsPromise.push(countPromise);
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
await think.promiseAllQueue(countsPromise, 1);
|
|
361
|
+
// cache data
|
|
362
|
+
await this._setCmtGroupByMailUserIdCache(options.group.join('_'), counts);
|
|
363
|
+
|
|
364
|
+
return [...cacheData, ...counts];
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
async add(
|
|
368
|
+
data,
|
|
369
|
+
{ access: { read = true, write = true } = { read: true, write: true } } = {}
|
|
370
|
+
) {
|
|
371
|
+
const Table = AV.Object.extend(this.tableName);
|
|
372
|
+
const instance = new Table();
|
|
373
|
+
|
|
374
|
+
const REVERSED_KEYS = ['objectId', 'createdAt', 'updatedAt'];
|
|
375
|
+
|
|
376
|
+
for (const k in data) {
|
|
377
|
+
if (REVERSED_KEYS.includes(k)) {
|
|
378
|
+
continue;
|
|
379
|
+
}
|
|
380
|
+
instance.set(k, data[k]);
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
const acl = new AV.ACL();
|
|
384
|
+
|
|
385
|
+
acl.setPublicReadAccess(read);
|
|
386
|
+
acl.setPublicWriteAccess(write);
|
|
387
|
+
instance.setACL(acl);
|
|
388
|
+
|
|
389
|
+
const resp = await instance.save();
|
|
390
|
+
|
|
391
|
+
await this._updateCmtGroupByMailUserIdCache(data, 'add');
|
|
392
|
+
|
|
393
|
+
return resp.toJSON();
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
async update(data, where) {
|
|
397
|
+
const instance = this.where(this.tableName, where);
|
|
398
|
+
const ret = await instance.find();
|
|
399
|
+
|
|
400
|
+
return Promise.all(
|
|
401
|
+
ret.map(async (item) => {
|
|
402
|
+
const _oldStatus = item.get('status');
|
|
403
|
+
|
|
404
|
+
if (think.isFunction(data)) {
|
|
405
|
+
item.set(data(item.toJSON()));
|
|
406
|
+
} else {
|
|
407
|
+
item.set(data);
|
|
408
|
+
}
|
|
409
|
+
const _newStatus = item.get('status');
|
|
410
|
+
|
|
411
|
+
if (_newStatus && _oldStatus !== _newStatus) {
|
|
412
|
+
await this._updateCmtGroupByMailUserIdCache(data, 'update_status');
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
const resp = await item.save();
|
|
416
|
+
|
|
417
|
+
return resp.toJSON();
|
|
418
|
+
})
|
|
419
|
+
);
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
async delete(where) {
|
|
423
|
+
const instance = this.where(this.tableName, where);
|
|
424
|
+
const data = await instance.find();
|
|
425
|
+
|
|
426
|
+
await this._updateCmtGroupByMailUserIdCache(data, 'delete');
|
|
427
|
+
|
|
428
|
+
return AV.Object.destroyAll(data);
|
|
429
|
+
}
|
|
430
|
+
};
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
const { ObjectID: ObjectId } = require('think-mongo/lib/model');
|
|
2
|
+
const Base = require('./base');
|
|
3
|
+
|
|
4
|
+
module.exports = class extends Base {
|
|
5
|
+
parseWhere(where) {
|
|
6
|
+
if (think.isEmpty(where)) {
|
|
7
|
+
return {};
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const filter = {};
|
|
11
|
+
const parseKey = (k) => (k === 'objectId' ? '_id' : k);
|
|
12
|
+
|
|
13
|
+
for (let k in where) {
|
|
14
|
+
if (k === '_complex') {
|
|
15
|
+
continue;
|
|
16
|
+
}
|
|
17
|
+
if (think.isString(where[k])) {
|
|
18
|
+
filter[parseKey(k)] = {
|
|
19
|
+
$eq: k === 'objectId' ? ObjectId(where[k]) : where[k],
|
|
20
|
+
};
|
|
21
|
+
continue;
|
|
22
|
+
}
|
|
23
|
+
if (where[k] === undefined) {
|
|
24
|
+
filter[parseKey(k)] = { $eq: null };
|
|
25
|
+
}
|
|
26
|
+
if (Array.isArray(where[k])) {
|
|
27
|
+
if (where[k][0]) {
|
|
28
|
+
const handler = where[k][0].toUpperCase();
|
|
29
|
+
|
|
30
|
+
switch (handler) {
|
|
31
|
+
case 'IN':
|
|
32
|
+
if (k === 'objectId') {
|
|
33
|
+
filter[parseKey(k)] = { $in: where[k][1].map(ObjectId) };
|
|
34
|
+
} else {
|
|
35
|
+
filter[parseKey(k)] = {
|
|
36
|
+
$regex: new RegExp(`^(${where[k][1].join('|')})$`),
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
break;
|
|
40
|
+
case 'NOT IN':
|
|
41
|
+
filter[parseKey(k)] = {
|
|
42
|
+
$nin:
|
|
43
|
+
k === 'objectId' ? where[k][1].map(ObjectId) : where[k][1],
|
|
44
|
+
};
|
|
45
|
+
break;
|
|
46
|
+
case 'LIKE': {
|
|
47
|
+
const first = where[k][1][0];
|
|
48
|
+
const last = where[k][1].slice(-1);
|
|
49
|
+
let reg;
|
|
50
|
+
|
|
51
|
+
if (first === '%' && last === '%') {
|
|
52
|
+
reg = new RegExp(where[k][1].slice(1, -1));
|
|
53
|
+
} else if (first === '%') {
|
|
54
|
+
reg = new RegExp(where[k][1].slice(1) + '$');
|
|
55
|
+
} else if (last === '%') {
|
|
56
|
+
reg = new RegExp('^' + where[k][1].slice(0, -1));
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (reg) {
|
|
60
|
+
filter[parseKey(k)] = { $regex: reg };
|
|
61
|
+
}
|
|
62
|
+
break;
|
|
63
|
+
}
|
|
64
|
+
case '!=':
|
|
65
|
+
filter[parseKey(k)] = { $ne: where[k][1] };
|
|
66
|
+
break;
|
|
67
|
+
case '>':
|
|
68
|
+
filter[parseKey(k)] = { $gt: where[k][1] };
|
|
69
|
+
break;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return filter;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
where(instance, where) {
|
|
79
|
+
const filter = this.parseWhere(where);
|
|
80
|
+
|
|
81
|
+
if (!where._complex) {
|
|
82
|
+
return instance.where(filter);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const filters = [];
|
|
86
|
+
|
|
87
|
+
for (const k in where._complex) {
|
|
88
|
+
if (k === '_logic') {
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
filters.push({
|
|
92
|
+
...this.parseWhere({ [k]: where._complex[k] }),
|
|
93
|
+
...filter,
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return instance.where({
|
|
98
|
+
// $or, $and, $not, $nor
|
|
99
|
+
[`$${where._complex._logic}`]: filters,
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
async select(where, { desc, limit, offset, field } = {}) {
|
|
104
|
+
const instance = this.mongo(this.tableName);
|
|
105
|
+
|
|
106
|
+
this.where(instance, where);
|
|
107
|
+
if (desc) {
|
|
108
|
+
instance.order(`${desc} DESC`);
|
|
109
|
+
}
|
|
110
|
+
if (limit || offset) {
|
|
111
|
+
instance.limit(offset || 0, limit);
|
|
112
|
+
}
|
|
113
|
+
if (field) {
|
|
114
|
+
instance.field(field);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const data = await instance.select();
|
|
118
|
+
|
|
119
|
+
return data.map(({ _id, ...cmt }) => ({
|
|
120
|
+
...cmt,
|
|
121
|
+
objectId: _id.toString(),
|
|
122
|
+
}));
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
async count(where = {}, { group } = {}) {
|
|
126
|
+
const instance = this.mongo(this.tableName);
|
|
127
|
+
|
|
128
|
+
this.where(instance, where);
|
|
129
|
+
if (group) {
|
|
130
|
+
instance.group(group);
|
|
131
|
+
}
|
|
132
|
+
const data = await instance.count({ raw: group });
|
|
133
|
+
|
|
134
|
+
if (!Array.isArray(data)) {
|
|
135
|
+
return data;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
return data.map(({ _id, total: count }) => ({ ..._id, count }));
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
async add(data) {
|
|
142
|
+
if (data.objectId) {
|
|
143
|
+
data._id = data.objectId;
|
|
144
|
+
delete data.objectId;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const instance = this.mongo(this.tableName);
|
|
148
|
+
const id = await instance.add(data);
|
|
149
|
+
|
|
150
|
+
return { ...data, objectId: id.toString() };
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
async update(data, where) {
|
|
154
|
+
const instance = this.mongo(this.tableName);
|
|
155
|
+
|
|
156
|
+
this.where(instance, where);
|
|
157
|
+
const list = await instance.select();
|
|
158
|
+
|
|
159
|
+
return Promise.all(
|
|
160
|
+
list.map(async (item) => {
|
|
161
|
+
const updateData = typeof data === 'function' ? data(item) : data;
|
|
162
|
+
const instance = this.mongo(this.tableName);
|
|
163
|
+
|
|
164
|
+
this.where(instance, where);
|
|
165
|
+
await instance.update(updateData);
|
|
166
|
+
|
|
167
|
+
return { ...item, ...updateData };
|
|
168
|
+
})
|
|
169
|
+
);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
async delete(where) {
|
|
173
|
+
const instance = this.mongo(this.tableName);
|
|
174
|
+
|
|
175
|
+
this.where(instance, where);
|
|
176
|
+
|
|
177
|
+
return instance.delete();
|
|
178
|
+
}
|
|
179
|
+
};
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
const Base = require('./base');
|
|
2
|
+
|
|
3
|
+
module.exports = class extends Base {
|
|
4
|
+
parseWhere(filter) {
|
|
5
|
+
const where = {};
|
|
6
|
+
|
|
7
|
+
if (think.isEmpty(filter)) {
|
|
8
|
+
return where;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
for (const k in filter) {
|
|
12
|
+
if (k === 'objectId' || k === 'objectid') {
|
|
13
|
+
where.id = filter[k];
|
|
14
|
+
continue;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
if (k === '_complex') {
|
|
18
|
+
where[k] = this.parseWhere(filter[k]);
|
|
19
|
+
continue;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
if (filter[k] === undefined) {
|
|
23
|
+
where[k] = null;
|
|
24
|
+
continue;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if (Array.isArray(filter[k])) {
|
|
28
|
+
if (filter[k][0] === 'IN' && !filter[k][1].length) {
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
if (think.isDate(filter[k][1])) {
|
|
32
|
+
filter[k][1] = think.datetime(filter[k][1]);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
where[k] = filter[k];
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return where;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
async select(where, { desc, limit, offset, field } = {}) {
|
|
43
|
+
const instance = this.model(this.tableName);
|
|
44
|
+
|
|
45
|
+
instance.where(this.parseWhere(where));
|
|
46
|
+
if (desc) {
|
|
47
|
+
instance.order({ [desc]: 'DESC' });
|
|
48
|
+
}
|
|
49
|
+
if (limit || offset) {
|
|
50
|
+
instance.limit(offset || 0, limit);
|
|
51
|
+
}
|
|
52
|
+
if (field) {
|
|
53
|
+
field.push('id');
|
|
54
|
+
instance.field(field);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const data = await instance.select();
|
|
58
|
+
|
|
59
|
+
return data.map(({ id, ...cmt }) => ({ ...cmt, objectId: id }));
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
async count(where = {}, { group } = {}) {
|
|
63
|
+
const instance = this.model(this.tableName);
|
|
64
|
+
|
|
65
|
+
instance.where(this.parseWhere(where));
|
|
66
|
+
if (!group) {
|
|
67
|
+
return instance.count();
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
instance.field([...group, 'COUNT(*) as count'].join(','));
|
|
71
|
+
instance.group(group);
|
|
72
|
+
|
|
73
|
+
return instance.select();
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
async add(data) {
|
|
77
|
+
if (data.objectId) {
|
|
78
|
+
data.id = data.objectId;
|
|
79
|
+
delete data.objectId;
|
|
80
|
+
}
|
|
81
|
+
const date = new Date();
|
|
82
|
+
|
|
83
|
+
if (!data.createdAt) data.createdAt = date;
|
|
84
|
+
if (!data.updatedAt) data.updatedAt = date;
|
|
85
|
+
|
|
86
|
+
const instance = this.model(this.tableName);
|
|
87
|
+
const id = await instance.add(data);
|
|
88
|
+
|
|
89
|
+
return { ...data, objectId: id };
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
async update(data, where) {
|
|
93
|
+
const list = await this.model(this.tableName)
|
|
94
|
+
.where(this.parseWhere(where))
|
|
95
|
+
.select();
|
|
96
|
+
|
|
97
|
+
return Promise.all(
|
|
98
|
+
list.map(async (item) => {
|
|
99
|
+
const updateData = typeof data === 'function' ? data(item) : data;
|
|
100
|
+
|
|
101
|
+
await this.model(this.tableName)
|
|
102
|
+
.where({ id: item.id })
|
|
103
|
+
.update(updateData);
|
|
104
|
+
|
|
105
|
+
return { ...item, ...updateData };
|
|
106
|
+
})
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
async delete(where) {
|
|
111
|
+
const instance = this.model(this.tableName);
|
|
112
|
+
|
|
113
|
+
return instance.where(this.parseWhere(where)).delete();
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
async setSeqId(id) {
|
|
117
|
+
const instance = this.model(this.tableName);
|
|
118
|
+
|
|
119
|
+
return instance.query(
|
|
120
|
+
`ALTER TABLE ${instance.tableName} AUTO_INCREMENT = ${id};`
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
};
|