blixify-server 0.3.28 → 1.0.0

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 (37) hide show
  1. package/dist/apis/authWrapper.d.ts.map +1 -1
  2. package/dist/apis/authWrapper.js +1 -228
  3. package/dist/apis/crypto.d.ts.map +1 -1
  4. package/dist/apis/crypto.js +1 -63
  5. package/dist/apis/dayjs.d.ts +3 -0
  6. package/dist/apis/dayjs.d.ts.map +1 -0
  7. package/dist/apis/dayjs.js +1 -0
  8. package/dist/apis/fbWrapper.d.ts +6 -6
  9. package/dist/apis/fbWrapper.d.ts.map +1 -1
  10. package/dist/apis/fbWrapper.js +1 -839
  11. package/dist/apis/googleAnalyticsWrapper.d.ts.map +1 -1
  12. package/dist/apis/googleAnalyticsWrapper.js +1 -223
  13. package/dist/apis/index.js +1 -21
  14. package/dist/apis/mondayWrapper.d.ts +2 -2
  15. package/dist/apis/mondayWrapper.d.ts.map +1 -1
  16. package/dist/apis/mondayWrapper.js +32 -527
  17. package/dist/apis/mongoWrapper.d.ts +6 -6
  18. package/dist/apis/mongoWrapper.d.ts.map +1 -1
  19. package/dist/apis/mongoWrapper.js +1 -1524
  20. package/dist/apis/postgresqlWrapper.d.ts +3 -3
  21. package/dist/apis/postgresqlWrapper.d.ts.map +1 -1
  22. package/dist/apis/postgresqlWrapper.js +1 -514
  23. package/dist/apis/security.d.ts.map +1 -1
  24. package/dist/apis/security.js +1 -80
  25. package/dist/apis/trackVisionWrapper.d.ts.map +1 -1
  26. package/dist/apis/trackVisionWrapper.js +1 -150
  27. package/dist/apis/uploadWrapper.d.ts.map +1 -1
  28. package/dist/apis/uploadWrapper.js +1 -481
  29. package/dist/apis/utils.d.ts +1 -1
  30. package/dist/apis/utils.d.ts.map +1 -1
  31. package/dist/apis/utils.js +1 -25
  32. package/dist/buildtsconfig.tsbuildinfo +1 -0
  33. package/dist/model/Log.js +1 -2
  34. package/dist/model/QueryModel.d.ts.map +1 -1
  35. package/dist/model/QueryModel.js +1 -118
  36. package/dist/model/SecurityConfig.js +1 -2
  37. package/package.json +21 -12
@@ -1,1524 +1 @@
1
- "use strict";
2
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
- return new (P || (P = Promise))(function (resolve, reject) {
5
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
- step((generator = generator.apply(thisArg, _arguments || [])).next());
9
- });
10
- };
11
- var __importDefault = (this && this.__importDefault) || function (mod) {
12
- return (mod && mod.__esModule) ? mod : { "default": mod };
13
- };
14
- Object.defineProperty(exports, "__esModule", { value: true });
15
- exports.MongoWrapper = void 0;
16
- const moment_timezone_1 = __importDefault(require("moment-timezone"));
17
- const uuid_1 = require("uuid");
18
- const QueryModel_1 = require("../model/QueryModel");
19
- const utils_1 = require("./utils");
20
- const handleParseQueryFilter = (queryList, prefix) => {
21
- const queryFilter = {};
22
- const queryGroupValues = {};
23
- if (queryList && queryList.length > 0) {
24
- queryList.map((eachQuery) => {
25
- var _a, _b, _c;
26
- let queryId = (_a = eachQuery.queryId) !== null && _a !== void 0 ? _a : "";
27
- if (prefix)
28
- queryId = `${prefix}.${queryId}`;
29
- const value = eachQuery.value;
30
- const queryValues = {};
31
- let orOption = eachQuery.orQuery ? true : false;
32
- switch (eachQuery.type) {
33
- case "search":
34
- if (eachQuery.searchIds && eachQuery.searchIds.length > 0) {
35
- eachQuery.searchIds.map((eachSearchId) => {
36
- orOption = true;
37
- queryValues[eachSearchId] = {
38
- $regex: `${(0, utils_1.handleSpecialWordsEscapeRegex)(value)}`,
39
- $options: "i",
40
- };
41
- });
42
- }
43
- if (eachQuery.foreign && eachQuery.foreign.length > 0) {
44
- (_b = eachQuery === null || eachQuery === void 0 ? void 0 : eachQuery.foreign) === null || _b === void 0 ? void 0 : _b.forEach((foreignLookup) => {
45
- let foreignAlias = foreignLookup.alias;
46
- if (prefix) {
47
- foreignAlias = `${prefix}.${foreignAlias}`;
48
- }
49
- if (foreignLookup.searchFields &&
50
- foreignLookup.searchFields.length > 0) {
51
- foreignLookup.searchFields.forEach((field) => {
52
- queryValues[`${foreignAlias}.${field}`] = {
53
- $regex: eachQuery.value
54
- .toString()
55
- .replace(/[.*+?^${}()|[\]\\]/g, "\\$&"),
56
- $options: "i",
57
- };
58
- });
59
- }
60
- });
61
- }
62
- break;
63
- case "=":
64
- queryValues[queryId] = value;
65
- break;
66
- case "!=":
67
- queryValues[queryId] = {
68
- $ne: value,
69
- };
70
- break;
71
- case ">":
72
- queryValues[queryId] = {
73
- $gt: value,
74
- };
75
- break;
76
- case "<":
77
- queryValues[queryId] = {
78
- $lt: value,
79
- };
80
- break;
81
- case "><":
82
- if (Array.isArray(value) && value.length >= 2) {
83
- queryValues[queryId] = {
84
- $gte: value[0],
85
- $lte: value[1],
86
- };
87
- }
88
- break;
89
- case "in":
90
- queryValues[queryId] = {
91
- $in: value,
92
- };
93
- break;
94
- case "!in":
95
- queryValues[queryId] = {
96
- $nin: value,
97
- };
98
- break;
99
- case "exists":
100
- queryValues[queryId] = {
101
- $exists: value,
102
- };
103
- break;
104
- case "elemMatch":
105
- queryValues[queryId] = {
106
- $elemMatch: value,
107
- };
108
- break;
109
- case ">size":
110
- if (!queryValues["$expr"])
111
- queryValues["$expr"] = {};
112
- queryValues["$expr"]["$gt"] = [{ $size: `$${queryId}` }, value];
113
- break;
114
- case "<size":
115
- if (!queryValues["$expr"])
116
- queryValues["$expr"] = {};
117
- queryValues["$expr"]["$lt"] = [{ $size: `$${queryId}` }, value];
118
- break;
119
- default:
120
- break;
121
- }
122
- //INFO : Delete Query Values as it's added outside
123
- if (eachQuery.orQueryGroupId) {
124
- if (eachQuery.type === "search") {
125
- (_c = eachQuery === null || eachQuery === void 0 ? void 0 : eachQuery.searchIds) === null || _c === void 0 ? void 0 : _c.map((eachSearchId) => {
126
- if (eachQuery.orQueryGroupId) {
127
- if (queryGroupValues[eachQuery === null || eachQuery === void 0 ? void 0 : eachQuery.orQueryGroupId]) {
128
- queryGroupValues[eachQuery === null || eachQuery === void 0 ? void 0 : eachQuery.orQueryGroupId]["$and"].push({
129
- [eachSearchId]: queryValues[eachSearchId],
130
- });
131
- }
132
- else {
133
- queryGroupValues[eachQuery === null || eachQuery === void 0 ? void 0 : eachQuery.orQueryGroupId] = {
134
- $and: [{ [eachSearchId]: queryValues[eachSearchId] }],
135
- };
136
- }
137
- delete queryValues[eachSearchId];
138
- }
139
- });
140
- }
141
- else {
142
- const groupValue = queryValues[queryId];
143
- if (groupValue !== undefined) {
144
- if (queryGroupValues[eachQuery.orQueryGroupId]) {
145
- queryGroupValues[eachQuery.orQueryGroupId]["$and"].push({
146
- [queryId]: queryValues[queryId],
147
- });
148
- }
149
- else {
150
- queryGroupValues[eachQuery.orQueryGroupId] = {
151
- $and: [{ [queryId]: queryValues[queryId] }],
152
- };
153
- }
154
- delete queryValues[queryId];
155
- }
156
- }
157
- }
158
- Object.keys(queryValues).map((eachKey) => {
159
- if (orOption) {
160
- if (queryFilter["$or"])
161
- queryFilter["$or"].push({ [eachKey]: queryValues[eachKey] });
162
- else
163
- queryFilter["$or"] = [{ [eachKey]: queryValues[eachKey] }];
164
- }
165
- else {
166
- queryFilter[eachKey] = queryValues[eachKey];
167
- }
168
- });
169
- });
170
- }
171
- Object.keys(queryGroupValues).map((eachKey) => {
172
- if (queryFilter["$or"])
173
- queryFilter["$or"].push(queryGroupValues[eachKey]);
174
- else
175
- queryFilter["$or"] = [queryGroupValues[eachKey]];
176
- });
177
- return queryFilter;
178
- };
179
- /**
180
- * @Wrapper
181
- * collection - MongoDB Collection
182
- *
183
- */
184
- class MongoWrapper {
185
- constructor(mongoDB, collection, isProd, config, modelChecker, lib, tableId, logId, logWorkflow, logCollectIds, debug) {
186
- this.mongoDB = "";
187
- this.collection = "";
188
- this.isProd = false;
189
- this.config = {
190
- baseConfig: [],
191
- opsConfig: {
192
- read: [],
193
- create: [],
194
- update: [],
195
- delete: [],
196
- },
197
- };
198
- this.tableId = "";
199
- this.logId = "";
200
- this.logCollectIds = [];
201
- // eslint-disable-next-line
202
- this.modelChecker = (obj) => {
203
- return false;
204
- };
205
- this.parseModel = (data) => {
206
- delete data["_id"];
207
- data["baseUpdatedAt"] = (0, moment_timezone_1.default)().toDate();
208
- return data;
209
- };
210
- this.handleLogging = (mongoId, type, req, value) => __awaiter(this, void 0, void 0, function* () {
211
- if (!this.logId)
212
- return;
213
- try {
214
- const userId = req.body["bm_userId"];
215
- const userRole = req.body["bm_userRole"];
216
- const organisationId = req.body["bm_userOrg"];
217
- const changeValueList = [];
218
- const dataDoc = type === "create" ? req.body.data : value === null || value === void 0 ? void 0 : value.new;
219
- Object.keys(dataDoc).map((eachKey) => {
220
- var _a, _b;
221
- const eachChangeValue = {
222
- newValue: dataDoc[eachKey],
223
- columnId: eachKey,
224
- };
225
- if (type === "update") {
226
- eachChangeValue["oldValue"] = (_a = value === null || value === void 0 ? void 0 : value.old) === null || _a === void 0 ? void 0 : _a[eachKey];
227
- //INFO : Double check similar value again as compareUpdatedFields allow UUID
228
- if (JSON.stringify(dataDoc[eachKey]) ===
229
- JSON.stringify((_b = value === null || value === void 0 ? void 0 : value.old) === null || _b === void 0 ? void 0 : _b[eachKey]))
230
- return;
231
- }
232
- if (eachKey !== "_id" && !eachKey.startsWith("base"))
233
- changeValueList.push(eachChangeValue);
234
- });
235
- if (type === "update" && changeValueList.length === 0)
236
- return;
237
- const logItem = {
238
- _id: (0, uuid_1.v4)(),
239
- type,
240
- itemId: mongoId,
241
- collectionId: this.collection,
242
- createdAt: (0, moment_timezone_1.default)().toDate(),
243
- values: changeValueList,
244
- userId,
245
- userRole,
246
- organisationId,
247
- };
248
- if ((type === "create" || type === "update") &&
249
- this.logCollectIds.length > 0) {
250
- this.logCollectIds.forEach((collectId) => {
251
- if (dataDoc[collectId] !== undefined) {
252
- logItem[collectId] = dataDoc[collectId];
253
- }
254
- });
255
- }
256
- const mongoLogCollection = this.mongoDB
257
- .db(this.tableId)
258
- .collection(this.logId);
259
- yield mongoLogCollection.insertOne(logItem);
260
- if (this.logWorkflow)
261
- yield this.logWorkflow(logItem);
262
- }
263
- catch (err) { }
264
- });
265
- this.initBatchCreate = (req, res, workflow) => __awaiter(this, void 0, void 0, function* () {
266
- var _a;
267
- try {
268
- if (Array.isArray(req.body.data)) {
269
- let valid = true;
270
- const upsert = req.body.upsert ? true : false;
271
- req.body.data.map((eachData) => {
272
- if (!this.modelChecker(eachData)) {
273
- valid = false;
274
- }
275
- });
276
- if (!valid) {
277
- res.status(400).json({ err: "Invalid Model Structure" });
278
- }
279
- //INFO : Security Checker
280
- const validBaseConfig = (0, QueryModel_1.checkBaseConfig)(this.config, req);
281
- let validOpsConfig = true;
282
- const uniqueDataField = [];
283
- yield Promise.all(req.body.data.map((eachData) => {
284
- if (!(0, QueryModel_1.checkOpsConfig)(this.config, "update", req, eachData)) {
285
- validOpsConfig = false;
286
- }
287
- if (req.body.unique && (eachData === null || eachData === void 0 ? void 0 : eachData[req.body.unique]))
288
- uniqueDataField.push(eachData[req.body.unique]);
289
- }));
290
- if (!validBaseConfig || !validOpsConfig) {
291
- res.status(400).json({ err: "Invalid Security Configuration" });
292
- return;
293
- }
294
- const mongoCollection = this.mongoDB
295
- .db(this.tableId)
296
- .collection(this.collection);
297
- if (uniqueDataField.length > 0) {
298
- const existsDataRes = yield mongoCollection.find({
299
- [req.body.unique]: { $in: uniqueDataField },
300
- });
301
- const existsDataList = yield existsDataRes.toArray();
302
- if (existsDataList.length > 0) {
303
- res.status(400).json({
304
- err: `Unique:${existsDataList.map((eachData) => eachData[req.body.unique])} exists`,
305
- });
306
- return;
307
- }
308
- }
309
- const ids = [];
310
- const batchCreateDataList = req.body.data.map((eachData) => {
311
- ids.push(eachData._id);
312
- return Object.assign(Object.assign({}, eachData), { baseUpdatedAt: (0, moment_timezone_1.default)().toDate() });
313
- });
314
- if (workflow)
315
- yield workflow(batchCreateDataList);
316
- if (upsert) {
317
- const bulkOps = batchCreateDataList.map((eachData) => ({
318
- updateOne: {
319
- filter: { _id: eachData._id },
320
- update: { $set: eachData },
321
- upsert: true,
322
- },
323
- }));
324
- yield mongoCollection.bulkWrite(bulkOps);
325
- }
326
- else {
327
- yield mongoCollection.insertMany(batchCreateDataList);
328
- }
329
- const resBody = { success: ids };
330
- if ((_a = req.body) === null || _a === void 0 ? void 0 : _a.stopRes)
331
- return resBody;
332
- res.send(resBody);
333
- }
334
- else {
335
- res.status(400).json({ err: "Invalid Fields" });
336
- }
337
- }
338
- catch (err) {
339
- res.status(400).json({ err: err });
340
- }
341
- });
342
- this.initCreate = (req, res, workflow) => __awaiter(this, void 0, void 0, function* () {
343
- var _b, _c;
344
- try {
345
- const valid = this.modelChecker(req.body.data);
346
- if (valid) {
347
- //INFO : Security Checker
348
- const validBaseConfig = (0, QueryModel_1.checkBaseConfig)(this.config, req);
349
- const validOpsConfig = (0, QueryModel_1.checkOpsConfig)(this.config, "create", req, req.body.data);
350
- if (!validBaseConfig || !validOpsConfig) {
351
- res.status(400).json({ err: "Invalid Security Configuration" });
352
- return;
353
- }
354
- const mongoCollection = this.mongoDB
355
- .db(this.tableId)
356
- .collection(this.collection);
357
- req.body.data["baseUpdatedAt"] = (0, moment_timezone_1.default)().toDate();
358
- if (req.body.unique && ((_b = req.body.data) === null || _b === void 0 ? void 0 : _b[req.body.unique])) {
359
- const isDataExists = yield mongoCollection.findOne({
360
- [req.body.unique]: req.body.data[req.body.unique],
361
- });
362
- if (isDataExists) {
363
- res
364
- .status(400)
365
- .json({ err: `Unique:${req.body.data[req.body.unique]} exists` });
366
- return;
367
- }
368
- }
369
- if (workflow)
370
- yield workflow(req.body.data);
371
- const mongoResult = yield mongoCollection.insertOne(req.body.data);
372
- const mongoId = mongoResult.insertedId.toString();
373
- yield this.handleLogging(mongoId, "create", req);
374
- const resBody = { success: true };
375
- if ((_c = req.body) === null || _c === void 0 ? void 0 : _c.stopRes)
376
- return resBody;
377
- res.send(resBody);
378
- }
379
- else {
380
- res.status(400).json({ err: "Invalid Model Structure" });
381
- }
382
- }
383
- catch (err) {
384
- res.status(400).json({ err: err });
385
- }
386
- });
387
- this.initGet = (req, res) => __awaiter(this, void 0, void 0, function* () {
388
- var _d;
389
- try {
390
- const valid = req.body.id;
391
- if (valid) {
392
- //INFO : Security Checker
393
- const mongoCollection = this.mongoDB
394
- .db(this.tableId)
395
- .collection(this.collection);
396
- const pipeline = this.handleBuildPipeline({
397
- body: Object.assign(Object.assign({}, req.body), { query: [{ type: "=", queryId: "_id", value: valid }] }),
398
- });
399
- const [mongoData] = yield mongoCollection.aggregate(pipeline).toArray();
400
- const validBaseConfig = (0, QueryModel_1.checkBaseConfig)(this.config, req);
401
- const validOpsConfig = (0, QueryModel_1.checkOpsConfig)(this.config, "read", req, mongoData);
402
- if (!validBaseConfig || !validOpsConfig) {
403
- res.status(400).json({ err: "Invalid Security Configuration" });
404
- return;
405
- }
406
- const resBody = { data: mongoData };
407
- if ((_d = req.body) === null || _d === void 0 ? void 0 : _d.stopRes)
408
- return resBody;
409
- res.send(resBody);
410
- }
411
- else {
412
- res.status(400).json({ err: "Invalid Fields" });
413
- }
414
- }
415
- catch (err) {
416
- res.status(400).json({ err: err });
417
- }
418
- });
419
- this.initBatchUpdate = (req, res, workflow) => __awaiter(this, void 0, void 0, function* () {
420
- var _e, _f, _g;
421
- try {
422
- const valid = (this.modelChecker(req.body.data) && req.body.query) ||
423
- req.body.unsetData;
424
- if (valid) {
425
- const unsetData = req.body.unsetData;
426
- const queryList = (_e = req.body.query) !== null && _e !== void 0 ? _e : [];
427
- const queryType = req.body.isOr ? "$or" : "$and";
428
- const queryFilter = {};
429
- const data = this.parseModel((_f = req.body.data) !== null && _f !== void 0 ? _f : []);
430
- // INFO : Step 1 - Query
431
- if (queryList && queryList.length > 0) {
432
- queryFilter[queryType] = [];
433
- // INFO : To Ensure There is OR Filter on Search
434
- if (queryList.some((eachQuery) => eachQuery.type === "search")) {
435
- queryFilter["$or"] = [];
436
- }
437
- queryList.map((eachQuery) => {
438
- var _a;
439
- const queryId = (_a = eachQuery.queryId) !== null && _a !== void 0 ? _a : "";
440
- const value = eachQuery.value;
441
- switch (eachQuery.type) {
442
- case "search":
443
- if (eachQuery.searchIds && eachQuery.searchIds.length > 0) {
444
- eachQuery.searchIds.map((eachSearchId) => {
445
- queryFilter["$or"].push({
446
- [eachSearchId]: {
447
- $regex: (0, utils_1.handleSpecialWordsEscapeRegex)(value),
448
- $options: "i",
449
- },
450
- });
451
- });
452
- }
453
- break;
454
- case "=":
455
- queryFilter[queryType].push({
456
- [queryId]: value,
457
- });
458
- break;
459
- case "!=":
460
- queryFilter[queryType].push({
461
- [queryId]: { $ne: value },
462
- });
463
- break;
464
- case ">":
465
- queryFilter[queryType].push({
466
- [queryId]: { $gt: value },
467
- });
468
- break;
469
- case "<":
470
- queryFilter[queryType].push({
471
- [queryId]: { $lt: value },
472
- });
473
- break;
474
- case "><":
475
- if (Array.isArray(value) && value.length >= 2) {
476
- queryFilter[queryType] = {
477
- [queryId]: { $gte: value[0], $lte: value[1] },
478
- };
479
- }
480
- break;
481
- case "in":
482
- queryFilter[queryType].push({
483
- [queryId]: { $in: value },
484
- });
485
- break;
486
- case "!in":
487
- queryFilter[queryType].push({
488
- [queryId]: { $nin: value },
489
- });
490
- break;
491
- case "exists":
492
- queryFilter[queryType].push({
493
- $exists: value, // `true` if field should exist, `false` if field should not exist
494
- });
495
- break;
496
- case "elemMatch":
497
- queryFilter[queryType].push({
498
- [queryId]: { $elemMatch: value },
499
- });
500
- break;
501
- default:
502
- break;
503
- }
504
- });
505
- }
506
- const validBaseConfig = (0, QueryModel_1.checkBaseConfig)(this.config, req);
507
- //INFO : Security Checker
508
- let validOpsConfig = true;
509
- const mongoCollection = this.mongoDB
510
- .db(this.tableId)
511
- .collection(this.collection);
512
- const mongoDataRes = yield mongoCollection.find(Object.assign({}, queryFilter));
513
- const mongoDataList = yield mongoDataRes.toArray();
514
- const workflowUpdateFieldsList = [];
515
- yield Promise.all(mongoDataList.map((eachData) => {
516
- // INFO : Check Sensitive
517
- if (req.body.sensitive) {
518
- if (!(0, moment_timezone_1.default)(req.body.data.baseUpdatedAt).isAfter((0, moment_timezone_1.default)(eachData.baseUpdatedAt))) {
519
- res.status(400).json({ err: "Refresh Sensitive Model" });
520
- }
521
- }
522
- // INFO : Check Ops Config
523
- if (!(0, QueryModel_1.checkOpsConfig)(this.config, "update", req, eachData)) {
524
- validOpsConfig = false;
525
- }
526
- const { workflowUpdateFields } = (0, utils_1.compareUpdatedFields)(eachData, req.body.data);
527
- workflowUpdateFieldsList.push(Object.assign(Object.assign({}, workflowUpdateFields), { _id: eachData === null || eachData === void 0 ? void 0 : eachData._id }));
528
- }));
529
- if (!validBaseConfig || !validOpsConfig) {
530
- res.status(400).json({ err: "Invalid Security Configuration" });
531
- return;
532
- }
533
- const $unset = {};
534
- const condition = {};
535
- if (unsetData) {
536
- unsetData.forEach((eachField) => {
537
- $unset[eachField] = "";
538
- });
539
- condition["$unset"] = Object.assign({}, $unset);
540
- }
541
- if (data) {
542
- condition["$set"] = Object.assign({}, data);
543
- }
544
- if (workflow)
545
- yield workflow(workflowUpdateFieldsList);
546
- yield mongoCollection.updateMany(queryFilter, condition);
547
- const ids = workflowUpdateFieldsList.map((eachData) => eachData._id);
548
- const resBody = { success: ids };
549
- if ((_g = req.body) === null || _g === void 0 ? void 0 : _g.stopRes)
550
- return resBody;
551
- res.send(resBody);
552
- }
553
- }
554
- catch (err) {
555
- res.status(400).json({ err: err });
556
- }
557
- });
558
- this.initUpdate = (req, res, workflow) => __awaiter(this, void 0, void 0, function* () {
559
- var _h, _j, _k;
560
- try {
561
- const valid = this.modelChecker(req.body.data) && req.body.id;
562
- if (valid) {
563
- const upsert = req.body.upsert ? true : false;
564
- let mongoData = {};
565
- const mongoCollection = this.mongoDB
566
- .db(this.tableId)
567
- .collection(this.collection);
568
- if (!upsert)
569
- mongoData = yield mongoCollection.findOne({
570
- _id: valid,
571
- });
572
- if (this.debug)
573
- this.debug(req.body, mongoData);
574
- //INFO : Security Checker
575
- const validBaseConfig = (0, QueryModel_1.checkBaseConfig)(this.config, req);
576
- const validOpsConfig = (0, QueryModel_1.checkOpsConfig)(this.config, "update", req, mongoData);
577
- if (!validBaseConfig || !validOpsConfig) {
578
- res.status(400).json({ err: "Invalid Security Configuration" });
579
- return;
580
- }
581
- if (req.body.unique && ((_h = req.body.data) === null || _h === void 0 ? void 0 : _h[req.body.unique])) {
582
- const isDataExists = yield mongoCollection.findOne({
583
- [req.body.unique]: req.body.data[req.body.unique],
584
- });
585
- if (isDataExists && req.body.id !== isDataExists._id) {
586
- res
587
- .status(400)
588
- .json({ err: `${req.body.data[req.body.unique]} exists` });
589
- return;
590
- }
591
- }
592
- const { updatedFields } = (0, utils_1.compareUpdatedFields)(mongoData, req.body.data);
593
- const resBody = { success: true };
594
- if (workflow)
595
- yield workflow(Object.assign(Object.assign({}, updatedFields), { _id: valid }));
596
- const data = this.parseModel(updatedFields);
597
- if (req.body.sensitive) {
598
- if ((0, moment_timezone_1.default)(req.body.data.baseUpdatedAt).isAfter((0, moment_timezone_1.default)(mongoData.baseUpdatedAt))) {
599
- yield mongoCollection.updateOne({
600
- _id: valid,
601
- }, {
602
- $set: Object.assign({}, data),
603
- }, { upsert: upsert });
604
- if ((_j = req.body) === null || _j === void 0 ? void 0 : _j.stopRes)
605
- return resBody;
606
- res.send(resBody);
607
- }
608
- else {
609
- res.status(400).json({ err: "Refresh Sensitive Model" });
610
- }
611
- }
612
- else {
613
- yield mongoCollection.updateOne({
614
- _id: valid,
615
- }, {
616
- $set: Object.assign({}, data),
617
- }, { upsert: upsert });
618
- if ((_k = req.body) === null || _k === void 0 ? void 0 : _k.stopRes)
619
- return resBody;
620
- res.send(resBody);
621
- }
622
- const oldData = {};
623
- Object.keys(data).map((eachUpdateKey) => {
624
- oldData[eachUpdateKey] = mongoData[eachUpdateKey];
625
- });
626
- yield this.handleLogging(valid, "update", req, {
627
- old: oldData,
628
- new: data,
629
- });
630
- }
631
- else {
632
- res.status(400).json({ err: "Invalid Model Structure" });
633
- }
634
- }
635
- catch (err) {
636
- if (this.debug)
637
- this.debug(null, null, err);
638
- res.status(400).json({ err: err });
639
- }
640
- });
641
- this.initBatchDelete = (req, res, workflow) => __awaiter(this, void 0, void 0, function* () {
642
- var _l, _m, _o, _p, _q, _r;
643
- try {
644
- if ((!Array.isArray(req.body.id) || ((_m = (_l = req.body.id) === null || _l === void 0 ? void 0 : _l.length) !== null && _m !== void 0 ? _m : 0) === 0) &&
645
- (!Array.isArray(req.body.query) || ((_p = (_o = req.body.query) === null || _o === void 0 ? void 0 : _o.length) !== null && _p !== void 0 ? _p : 0) === 0)) {
646
- throw "Invalid Batch Delete Config";
647
- }
648
- if (Array.isArray(req.body.id)) {
649
- const mongoCollection = this.mongoDB
650
- .db(this.tableId)
651
- .collection(this.collection);
652
- const mongoQuery = yield mongoCollection.find({
653
- _id: { $in: req.body.id },
654
- });
655
- const validBaseConfig = (0, QueryModel_1.checkBaseConfig)(this.config, req);
656
- const dataList = yield mongoQuery.toArray();
657
- //INFO : Security Checker
658
- let validOpsConfig = true;
659
- if (dataList.length > 0) {
660
- yield Promise.all(dataList.map((eachData) => {
661
- if (!(0, QueryModel_1.checkOpsConfig)(this.config, "delete", req, eachData)) {
662
- validOpsConfig = false;
663
- }
664
- }));
665
- }
666
- if (!validBaseConfig || !validOpsConfig) {
667
- res.status(400).json({ err: "Invalid Security Configuration" });
668
- return;
669
- }
670
- if (workflow)
671
- yield workflow(dataList);
672
- yield mongoCollection.deleteMany({
673
- _id: { $in: req.body.id },
674
- });
675
- const resBody = { success: req.body.id };
676
- if ((_q = req.body) === null || _q === void 0 ? void 0 : _q.stopRes)
677
- return resBody;
678
- res.send(resBody);
679
- }
680
- else {
681
- const queryList = req.body.query;
682
- const queryFilter = {};
683
- if (queryList && queryList.length > 0) {
684
- queryList.map((eachQuery) => {
685
- var _a;
686
- const queryId = (_a = eachQuery.queryId) !== null && _a !== void 0 ? _a : "";
687
- const value = eachQuery.value;
688
- switch (eachQuery.type) {
689
- case "search":
690
- if (eachQuery.searchIds && eachQuery.searchIds.length > 0) {
691
- queryFilter["$or"] = [];
692
- eachQuery.searchIds.map((eachSearchId) => {
693
- queryFilter["$or"].push({
694
- [eachSearchId]: {
695
- $regex: (0, utils_1.handleSpecialWordsEscapeRegex)(value),
696
- $options: "i",
697
- },
698
- });
699
- });
700
- }
701
- break;
702
- case "=":
703
- queryFilter[queryId] = value;
704
- break;
705
- case "!=":
706
- queryFilter[queryId] = {
707
- $ne: value,
708
- };
709
- break;
710
- case ">":
711
- queryFilter[queryId] = {
712
- $gt: value,
713
- };
714
- break;
715
- case "<":
716
- queryFilter[queryId] = {
717
- $lt: value,
718
- };
719
- break;
720
- case "><":
721
- if (Array.isArray(value) && value.length >= 2) {
722
- queryFilter[queryId] = {
723
- $gte: value[0],
724
- $lte: value[1],
725
- };
726
- }
727
- break;
728
- case "in":
729
- queryFilter[queryId] = {
730
- $in: value,
731
- };
732
- break;
733
- case "!in":
734
- queryFilter[queryId] = {
735
- $nin: value,
736
- };
737
- break;
738
- case "exists":
739
- queryFilter[queryId] = {
740
- $exists: value, // `true` if field should exist, `false` if field should not exist
741
- };
742
- break;
743
- case "elemMatch":
744
- queryFilter[queryId] = {
745
- $elemMatch: value,
746
- };
747
- break;
748
- default:
749
- break;
750
- }
751
- });
752
- }
753
- const mongoCollection = this.mongoDB
754
- .db(this.tableId)
755
- .collection(this.collection);
756
- const mongoQuery = mongoCollection.find(queryFilter);
757
- const dataList = yield mongoQuery.toArray();
758
- const validBaseConfig = (0, QueryModel_1.checkBaseConfig)(this.config, req);
759
- //INFO : Security Checker
760
- let validOpsConfig = true;
761
- const ids = [];
762
- if (dataList.length > 0) {
763
- dataList.map((eachData) => {
764
- ids.push(eachData._id);
765
- if (!(0, QueryModel_1.checkOpsConfig)(this.config, "delete", req, eachData)) {
766
- validOpsConfig = false;
767
- }
768
- });
769
- }
770
- if (workflow)
771
- yield workflow(dataList);
772
- if (!validBaseConfig || !validOpsConfig) {
773
- res.status(400).json({ err: "Invalid Security Configuration" });
774
- return;
775
- }
776
- yield mongoCollection.deleteMany(queryFilter);
777
- const resBody = { success: ids };
778
- if ((_r = req.body) === null || _r === void 0 ? void 0 : _r.stopRes)
779
- return resBody;
780
- res.send(resBody);
781
- }
782
- }
783
- catch (err) {
784
- res.status(400).json({ err: err });
785
- }
786
- });
787
- this.initDelete = (req, res, workflow) => __awaiter(this, void 0, void 0, function* () {
788
- var _s;
789
- try {
790
- const valid = req.body.id;
791
- if (valid) {
792
- const mongoCollection = this.mongoDB
793
- .db(this.tableId)
794
- .collection(this.collection);
795
- //INFO : Security Checker
796
- const mongoData = yield mongoCollection.findOne({
797
- _id: valid,
798
- });
799
- const validBaseConfig = (0, QueryModel_1.checkBaseConfig)(this.config, req);
800
- const validOpsConfig = (0, QueryModel_1.checkOpsConfig)(this.config, "delete", req, mongoData);
801
- if (!validBaseConfig || !validOpsConfig) {
802
- res.status(400).json({ err: "Invalid Security Configuration" });
803
- return;
804
- }
805
- if (workflow)
806
- yield workflow(mongoData);
807
- yield mongoCollection.findOneAndDelete({
808
- _id: valid,
809
- });
810
- yield this.handleLogging(mongoData._id, "delete", req, {
811
- new: mongoData,
812
- });
813
- const resBody = { success: true };
814
- if ((_s = req.body) === null || _s === void 0 ? void 0 : _s.stopRes)
815
- return resBody;
816
- res.send(resBody);
817
- }
818
- else {
819
- res.status(400).json({ err: "Invalid Fields" });
820
- }
821
- }
822
- catch (err) {
823
- res.status(400).json({ err: err });
824
- }
825
- });
826
- this.initList = (req, res) => __awaiter(this, void 0, void 0, function* () {
827
- var _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10;
828
- try {
829
- //INFO : Security Checker
830
- const validBaseConfig = (0, QueryModel_1.checkBaseConfig)(this.config, req);
831
- if (validBaseConfig) {
832
- const aggregate = req.body.aggregate;
833
- const unionCollections = (_t = req.body.unionCollections) !== null && _t !== void 0 ? _t : [];
834
- const queryList = (_u = req.body.query) !== null && _u !== void 0 ? _u : [];
835
- let queryFilter = {};
836
- // INFO : Step 1 - Query
837
- queryFilter = handleParseQueryFilter(queryList);
838
- if (unionCollections &&
839
- Array.isArray(unionCollections) &&
840
- unionCollections.length > 0) {
841
- if (aggregate) {
842
- res.status(400).json({
843
- err: "Union operations cannot be combined with aggregate",
844
- });
845
- return;
846
- }
847
- const sort = (_v = req.body.sort) !== null && _v !== void 0 ? _v : { date: -1 };
848
- const limit = (_w = req.body.limit) !== null && _w !== void 0 ? _w : 50;
849
- const skip = (_y = (_x = req.body.cursor) !== null && _x !== void 0 ? _x : req.body.skip) !== null && _y !== void 0 ? _y : 0;
850
- const pipeline = [];
851
- // Build unionWith pipeline
852
- unionCollections.forEach((collectionConfig, index) => {
853
- const projectStage = {
854
- $project: Object.assign({ _id: 1 }, collectionConfig.projection),
855
- };
856
- // INFO: sourceLogic can be a string literal or a MongoDB expression object
857
- if (collectionConfig.sourceLogic) {
858
- projectStage.$project.source =
859
- typeof collectionConfig.sourceLogic === "string"
860
- ? { $literal: collectionConfig.sourceLogic }
861
- : collectionConfig.sourceLogic;
862
- }
863
- else {
864
- projectStage.$project.source = {
865
- $literal: collectionConfig.source,
866
- };
867
- }
868
- if (index === 0) {
869
- if (queryList && queryList.length > 0) {
870
- pipeline.push({ $match: queryFilter });
871
- }
872
- if (collectionConfig.query && collectionConfig.query.length > 0) {
873
- const collectionQueryFilter = handleParseQueryFilter(collectionConfig.query);
874
- pipeline.push({ $match: collectionQueryFilter });
875
- }
876
- // INFO: addFields must be before $project so computed fields are available for sorting
877
- if (collectionConfig.addFields) {
878
- pipeline.push({ $addFields: collectionConfig.addFields });
879
- // INFO: also include addFields keys in projection so they survive the $project stage
880
- Object.keys(collectionConfig.addFields).forEach((key) => {
881
- projectStage.$project[key] = 1;
882
- });
883
- }
884
- pipeline.push(projectStage);
885
- }
886
- else {
887
- const unionPipeline = [];
888
- if (collectionConfig.query && collectionConfig.query.length > 0) {
889
- const collectionQueryFilter = handleParseQueryFilter(collectionConfig.query);
890
- unionPipeline.push({ $match: collectionQueryFilter });
891
- }
892
- // INFO: addFields must be before $project so computed fields are available for sorting
893
- if (collectionConfig.addFields) {
894
- unionPipeline.push({ $addFields: collectionConfig.addFields });
895
- // INFO: also include addFields keys in projection so they survive the $project stage
896
- Object.keys(collectionConfig.addFields).forEach((key) => {
897
- projectStage.$project[key] = 1;
898
- });
899
- }
900
- unionPipeline.push(projectStage);
901
- const unionStage = {
902
- $unionWith: {
903
- coll: collectionConfig.collection,
904
- pipeline: unionPipeline,
905
- },
906
- };
907
- pipeline.push(unionStage);
908
- }
909
- });
910
- if (sort) {
911
- const sortStage = { $sort: {} };
912
- if (Array.isArray(sort)) {
913
- sort.forEach((sortItem) => {
914
- if (sortItem.sortId) {
915
- sortStage.$sort[sortItem.sortId] =
916
- sortItem.type === "asc" ? 1 : -1;
917
- }
918
- });
919
- }
920
- else if (sort.sortId && sort.type) {
921
- sortStage.$sort[sort.sortId] = sort.type === "asc" ? 1 : -1;
922
- }
923
- else {
924
- sortStage.$sort = sort;
925
- }
926
- pipeline.push(sortStage);
927
- }
928
- if (skip > 0) {
929
- pipeline.push({ $skip: skip });
930
- }
931
- if (limit > 0) {
932
- pipeline.push({ $limit: limit });
933
- }
934
- const mongoCollection = this.mongoDB
935
- .db(this.tableId)
936
- .collection(this.collection);
937
- const dataList = yield mongoCollection.aggregate(pipeline).toArray();
938
- const countPipeline = pipeline.filter((stage) => {
939
- const stageKey = Object.keys(stage)[0];
940
- return stageKey !== "$skip" && stageKey !== "$limit";
941
- });
942
- countPipeline.push({ $count: "total" });
943
- const countResult = yield mongoCollection
944
- .aggregate(countPipeline)
945
- .toArray();
946
- const count = ((_z = countResult[0]) === null || _z === void 0 ? void 0 : _z.total) || 0;
947
- let validOpsConfig = true;
948
- dataList.map((eachData) => {
949
- if (!(0, QueryModel_1.checkOpsConfig)(this.config, "read", req, eachData)) {
950
- validOpsConfig = false;
951
- }
952
- });
953
- if (!validBaseConfig || !validOpsConfig) {
954
- res.status(400).json({ err: "Invalid Security Configuration" });
955
- return;
956
- }
957
- const resBody = {
958
- data: dataList,
959
- count,
960
- };
961
- if ((_0 = req.body) === null || _0 === void 0 ? void 0 : _0.stopRes)
962
- return resBody;
963
- res.send(resBody);
964
- return;
965
- }
966
- if (aggregate) {
967
- const dataList = [];
968
- const queryId = (_1 = aggregate.queryId) !== null && _1 !== void 0 ? _1 : "";
969
- const dateId = (_2 = aggregate.dateId) !== null && _2 !== void 0 ? _2 : "baseUpdatedAt";
970
- const timezone = aggregate.timezone || "Asia/Kuala_Lumpur";
971
- const dateRanges = (_3 = aggregate.range) !== null && _3 !== void 0 ? _3 : [
972
- (0, moment_timezone_1.default)().tz(timezone).format("DD/MM/YYYY HH:mm:ss"),
973
- ];
974
- for (const dateRange of dateRanges) {
975
- let matchFilter = {
976
- $match: Object.assign({}, queryFilter),
977
- };
978
- const date = dateRange.split("-");
979
- const [startDate, endDate = (0, moment_timezone_1.default)().tz(timezone).format("DD/MM/YYYY HH:mm:ss"),] = date;
980
- const isDuration = date.length === 2;
981
- const isValidStartDate = moment_timezone_1.default
982
- .tz(startDate, "DD/MM/YYYY HH:mm:ss", timezone)
983
- .isValid();
984
- const isValidEndDate = moment_timezone_1.default
985
- .tz(endDate, "DD/MM/YYYY HH:mm:ss", timezone)
986
- .isValid();
987
- const isoStartDate = moment_timezone_1.default
988
- .tz(startDate, "DD/MM/YYYY HH:mm:ss", timezone)
989
- .utc()
990
- .toDate();
991
- const isoEndDate = moment_timezone_1.default
992
- .tz(endDate, "DD/MM/YYYY HH:mm:ss", timezone)
993
- .utc()
994
- .toDate();
995
- if (!isValidStartDate || !isValidEndDate) {
996
- res
997
- .status(400)
998
- .json({ err: "Invalid Aggregate Range Configuration" });
999
- return;
1000
- }
1001
- matchFilter = isDuration
1002
- ? {
1003
- $match: Object.assign(Object.assign({}, queryFilter), { [dateId]: {
1004
- $gte: isoStartDate,
1005
- $lte: isoEndDate,
1006
- } }),
1007
- }
1008
- : {
1009
- $match: Object.assign(Object.assign({}, queryFilter), { [dateId]: {
1010
- $lte: isoStartDate,
1011
- } }),
1012
- };
1013
- const aggregationPipeline = [matchFilter];
1014
- const id = isDuration
1015
- ? dateRange
1016
- : `Begining until ${(0, moment_timezone_1.default)(startDate, "DD/MM/YYYY HH:mm:ss").format("DD/MM/YYYY")}`;
1017
- let unwindUnique = false;
1018
- if (aggregate.unwind && aggregate.unwind.length > 0) {
1019
- aggregate.unwind.map((eachUnwind, index) => {
1020
- var _a, _b, _c;
1021
- const tempModel = "model" + index;
1022
- let referenceModel = "";
1023
- if (index > 0)
1024
- referenceModel = "model" + (index - 1) + ".";
1025
- const modelQueryFilter = handleParseQueryFilter((_a = eachUnwind.query) !== null && _a !== void 0 ? _a : [], tempModel);
1026
- if ((_b = eachUnwind.unique) === null || _b === void 0 ? void 0 : _b.list)
1027
- aggregationPipeline.push({
1028
- $unwind: "$" + eachUnwind.localField,
1029
- });
1030
- aggregationPipeline.push({
1031
- $lookup: {
1032
- from: eachUnwind.collectionId,
1033
- localField: referenceModel + eachUnwind.localField,
1034
- foreignField: "_id",
1035
- as: tempModel,
1036
- },
1037
- }, {
1038
- $unwind: "$" + tempModel,
1039
- }, {
1040
- $match: modelQueryFilter,
1041
- });
1042
- if ((_c = eachUnwind.unique) === null || _c === void 0 ? void 0 : _c.type) {
1043
- unwindUnique = true;
1044
- const uniqueUnwindName = "uniqueUnwindId";
1045
- aggregationPipeline.push({
1046
- $group: {
1047
- _id: id,
1048
- [uniqueUnwindName]: {
1049
- $addToSet: "$" + eachUnwind.localField,
1050
- },
1051
- },
1052
- });
1053
- if (eachUnwind.unique.type === "count")
1054
- aggregationPipeline.push({
1055
- $project: {
1056
- value: { $size: "$" + uniqueUnwindName },
1057
- },
1058
- });
1059
- else
1060
- aggregationPipeline.push({
1061
- $project: { _id: 0, value: "$" + uniqueUnwindName },
1062
- });
1063
- }
1064
- });
1065
- }
1066
- if (!unwindUnique) {
1067
- let groupId = id;
1068
- if (aggregate.groupId)
1069
- groupId = "$" + aggregate.groupId;
1070
- switch (aggregate.type) {
1071
- case "avg":
1072
- aggregationPipeline.push({
1073
- $group: {
1074
- _id: groupId,
1075
- value: { $avg: `$${queryId}` },
1076
- },
1077
- });
1078
- break;
1079
- case "sum":
1080
- aggregationPipeline.push({
1081
- $group: {
1082
- _id: groupId,
1083
- value: { $sum: `$${queryId}` },
1084
- },
1085
- });
1086
- break;
1087
- case "count":
1088
- aggregationPipeline.push({
1089
- $group: {
1090
- _id: groupId,
1091
- value: { $sum: 1 },
1092
- ids: { $push: "$_id" },
1093
- },
1094
- });
1095
- break;
1096
- default:
1097
- break;
1098
- }
1099
- }
1100
- if (aggregationPipeline.length === 0) {
1101
- res.status(400).json({ err: "Invalid Aggregate Configuration" });
1102
- return;
1103
- }
1104
- const mongoCollection = this.mongoDB
1105
- .db(this.tableId)
1106
- .collection(this.collection);
1107
- let value = 0;
1108
- let ids = [];
1109
- const mongoQuery = mongoCollection.aggregate(aggregationPipeline);
1110
- const result = yield mongoQuery.toArray();
1111
- if (aggregate.groupId)
1112
- value = result;
1113
- else {
1114
- value = (_5 = (_4 = result[0]) === null || _4 === void 0 ? void 0 : _4.value) !== null && _5 !== void 0 ? _5 : 0;
1115
- ids = (_7 = (_6 = result[0]) === null || _6 === void 0 ? void 0 : _6.ids) !== null && _7 !== void 0 ? _7 : [];
1116
- }
1117
- dataList.push({
1118
- _id: id,
1119
- value,
1120
- ids,
1121
- });
1122
- }
1123
- const resBody = {
1124
- data: dataList,
1125
- };
1126
- if ((_8 = req.body) === null || _8 === void 0 ? void 0 : _8.stopRes)
1127
- return resBody;
1128
- res.send(resBody);
1129
- }
1130
- else {
1131
- const mongoCollection = this.mongoDB
1132
- .db(this.tableId)
1133
- .collection(this.collection);
1134
- const pipeline = this.handleBuildPipeline(req);
1135
- const countPipeline = pipeline.filter((stage) => {
1136
- const stageKey = Object.keys(stage)[0];
1137
- return stageKey !== "$skip" && stageKey !== "$limit";
1138
- });
1139
- countPipeline.push({ $count: "total" });
1140
- const [dataList, countResult] = yield Promise.all([
1141
- mongoCollection.aggregate(pipeline).toArray(),
1142
- mongoCollection.aggregate(countPipeline).toArray(),
1143
- ]);
1144
- const count = ((_9 = countResult[0]) === null || _9 === void 0 ? void 0 : _9.total) || 0;
1145
- //INFO : Security Checker
1146
- let validOpsConfig = true;
1147
- if (dataList.length > 0) {
1148
- dataList.map((eachData) => {
1149
- if (!(0, QueryModel_1.checkOpsConfig)(this.config, "read", req, eachData)) {
1150
- validOpsConfig = false;
1151
- }
1152
- });
1153
- }
1154
- if (!validBaseConfig || !validOpsConfig) {
1155
- res.status(400).json({ err: "Invalid Security Configuration" });
1156
- return;
1157
- }
1158
- const resBody = {
1159
- data: dataList,
1160
- count,
1161
- };
1162
- if ((_10 = req.body) === null || _10 === void 0 ? void 0 : _10.stopRes)
1163
- return resBody;
1164
- res.send(resBody);
1165
- }
1166
- }
1167
- else {
1168
- res.status(400).json({ err: "Invalid Security Configuration" });
1169
- }
1170
- }
1171
- catch (err) {
1172
- res.status(400).json({
1173
- err: err.message,
1174
- });
1175
- }
1176
- });
1177
- this.init = () => {
1178
- const router = this.lib.express.Router();
1179
- /**
1180
- * @Input :
1181
- * data - Model
1182
- * unique - string (Optional)
1183
- */
1184
- router.post("/create", (req, res) => {
1185
- this.initCreate(req, res);
1186
- });
1187
- /**
1188
- * @Input :
1189
- * data - Model
1190
- * unique - string (Optional)
1191
- */
1192
- router.post("/batchCreate", (req, res) => {
1193
- this.initBatchCreate(req, res);
1194
- });
1195
- /**
1196
- * @Input :
1197
- * id - string
1198
- */
1199
- router.post("/get", (req, res) => {
1200
- this.initGet(req, res);
1201
- });
1202
- /**
1203
- * @Input :
1204
- * data - Model
1205
- * id - string
1206
- * unique - string (Optional)
1207
- */
1208
- router.post("/update", (req, res) => {
1209
- this.initUpdate(req, res);
1210
- });
1211
- /**
1212
- * @Input :
1213
- * data - Model
1214
- * query - Query[]
1215
- * unsetData - string[] (Unset Attribute Id) (Optional)
1216
- * isOr - boolean (Optional)
1217
- */
1218
- router.post("/batchUpdate", (req, res) => {
1219
- this.initBatchUpdate(req, res);
1220
- });
1221
- /**
1222
- * @Input :
1223
- * id - string
1224
- */
1225
- router.post("/delete", (req, res) => {
1226
- this.initDelete(req, res);
1227
- });
1228
- /**
1229
- * @Input :
1230
- * id - string[]
1231
- */
1232
- router.post("/batchDelete", (req, res) => {
1233
- this.initBatchDelete(req, res);
1234
- });
1235
- /**
1236
- * @Input
1237
- * query - Query interface (Optional)
1238
- * unionCollections - Array of collection configs with source and projection (Optional)
1239
- * cursor - any (Optional)
1240
- * limit - number (Optional)
1241
- * sort - Array Sort or Sort interface (Optional)
1242
- * stopLimit - boolean to retreive all data (Optional)
1243
- * uniqueLabel - string to ensure uniqueness of a field across returned documents (Optional)
1244
- */
1245
- router.post("/list", (req, res) => {
1246
- this.initList(req, res);
1247
- });
1248
- return router;
1249
- };
1250
- this.mongoDB = mongoDB;
1251
- this.collection = collection;
1252
- this.isProd = isProd;
1253
- this.config = config;
1254
- this.modelChecker = modelChecker;
1255
- this.lib = lib;
1256
- const tableSuffix = this.isProd ? "prod" : "dev";
1257
- this.tableId = tableId ? `${tableId}-${tableSuffix}` : tableSuffix;
1258
- this.logId = logId !== null && logId !== void 0 ? logId : "";
1259
- this.logWorkflow = logWorkflow;
1260
- this.logCollectIds = logCollectIds !== null && logCollectIds !== void 0 ? logCollectIds : [];
1261
- this.debug = debug;
1262
- }
1263
- handleBuildPipeline(req) {
1264
- const pipelineList = [];
1265
- const addedForeignLookups = new Map();
1266
- const addedSpaceReferences = new Set();
1267
- const { query, sort, cursor, limit, stopLimit, pipeline, uniqueLabel, groupId, } = req.body;
1268
- try {
1269
- if (Array.isArray(pipeline) && pipeline.length > 0) {
1270
- pipeline.forEach((link) => {
1271
- const { condition, referenceSpaceLabel, spaceReferenceId, spaceReferenceAs, referenceSort, referenceFirstItem, referenceLimit, } = link;
1272
- if (spaceReferenceId) {
1273
- const defaultReferenceAs = spaceReferenceAs || "linkedData";
1274
- addedSpaceReferences.add(defaultReferenceAs);
1275
- const lookupStage = {
1276
- $lookup: {
1277
- from: spaceReferenceId,
1278
- let: {},
1279
- pipeline: [],
1280
- as: defaultReferenceAs,
1281
- },
1282
- };
1283
- if (condition && condition.length > 0) {
1284
- condition.forEach((cond) => {
1285
- lookupStage.$lookup.let[`local_${cond.fromColumnId}`] =
1286
- `$${cond.fromColumnId}`;
1287
- });
1288
- const matchStage = {
1289
- $match: { $expr: { $and: [] } },
1290
- };
1291
- condition.forEach((cond) => {
1292
- const conditionExpr = {};
1293
- switch (cond.type) {
1294
- case "=":
1295
- conditionExpr.$eq = [
1296
- `$${cond.toColumnId}`,
1297
- `$$local_${cond.fromColumnId}`,
1298
- ];
1299
- break;
1300
- case "!=":
1301
- conditionExpr.$ne = [
1302
- `$${cond.toColumnId}`,
1303
- `$$local_${cond.fromColumnId}`,
1304
- ];
1305
- break;
1306
- case ">":
1307
- conditionExpr.$gt = [
1308
- `$${cond.toColumnId}`,
1309
- `$$local_${cond.fromColumnId}`,
1310
- ];
1311
- break;
1312
- case "<":
1313
- conditionExpr.$lt = [
1314
- `$${cond.toColumnId}`,
1315
- `$$local_${cond.fromColumnId}`,
1316
- ];
1317
- break;
1318
- case "in":
1319
- conditionExpr.$in = [
1320
- `$${cond.toColumnId}`,
1321
- `$$local_${cond.fromColumnId}`,
1322
- ];
1323
- break;
1324
- case "!in":
1325
- conditionExpr.$nin = [
1326
- `$${cond.toColumnId}`,
1327
- `$$local_${cond.fromColumnId}`,
1328
- ];
1329
- break;
1330
- }
1331
- if (Object.keys(conditionExpr).length > 0) {
1332
- matchStage.$match.$expr.$and.push(conditionExpr);
1333
- }
1334
- });
1335
- lookupStage.$lookup.pipeline.push(matchStage);
1336
- }
1337
- if (referenceSort && referenceSort.sortId) {
1338
- const sortStage = {
1339
- $sort: {
1340
- [referenceSort.sortId]: referenceSort.type === "asc" ? 1 : -1,
1341
- },
1342
- };
1343
- lookupStage.$lookup.pipeline.push(sortStage);
1344
- }
1345
- if (referenceLimit) {
1346
- const limitStage = {
1347
- $limit: referenceLimit,
1348
- };
1349
- lookupStage.$lookup.pipeline.push(limitStage);
1350
- }
1351
- pipelineList.push(lookupStage);
1352
- if (referenceSpaceLabel && referenceSpaceLabel.length > 0) {
1353
- const addFieldsStage = { $addFields: {} };
1354
- if (referenceFirstItem) {
1355
- pipelineList.push({
1356
- $addFields: {
1357
- [defaultReferenceAs]: {
1358
- $first: {
1359
- $ifNull: [`$${defaultReferenceAs}`, []],
1360
- },
1361
- },
1362
- },
1363
- });
1364
- referenceSpaceLabel.forEach((field) => {
1365
- addFieldsStage.$addFields[`${defaultReferenceAs}_${field}`] =
1366
- `$${defaultReferenceAs}.${field}`;
1367
- });
1368
- }
1369
- else {
1370
- referenceSpaceLabel.forEach((field) => {
1371
- addFieldsStage.$addFields[`${defaultReferenceAs}_${field}`] =
1372
- {
1373
- $map: {
1374
- input: `$${defaultReferenceAs}`,
1375
- in: `$$this.${field}`,
1376
- },
1377
- };
1378
- });
1379
- }
1380
- pipelineList.push(addFieldsStage);
1381
- }
1382
- }
1383
- });
1384
- }
1385
- if (query && query.length > 0) {
1386
- query.forEach((q) => {
1387
- if (q.foreign && Array.isArray(q.foreign)) {
1388
- q.foreign.forEach((foreignLookup) => {
1389
- const alias = foreignLookup.alias;
1390
- if (!addedForeignLookups.has(alias)) {
1391
- pipelineList.push({
1392
- $lookup: {
1393
- from: foreignLookup.collection,
1394
- localField: foreignLookup.localField,
1395
- foreignField: "_id",
1396
- as: alias,
1397
- },
1398
- });
1399
- addedForeignLookups.set(alias, true);
1400
- }
1401
- });
1402
- }
1403
- });
1404
- }
1405
- const sortStage = { $sort: {} };
1406
- if (sort) {
1407
- const sortItems = Array.isArray(JSON.parse(JSON.stringify(sort)))
1408
- ? sort
1409
- : [sort];
1410
- sortItems.forEach((sortItem) => {
1411
- if (sortItem.sortId) {
1412
- sortStage.$sort[sortItem.sortId] = sortItem.type === "asc" ? 1 : -1;
1413
- }
1414
- });
1415
- }
1416
- const isSortBeforeFilter = sort === null || sort === void 0 ? void 0 : sort.sortBeforeFilter;
1417
- // INFO: If data is sorted then only filter, group must be before filter as well
1418
- if (isSortBeforeFilter) {
1419
- if (Object.keys(sortStage.$sort).length > 0) {
1420
- pipelineList.push(sortStage);
1421
- }
1422
- if (uniqueLabel) {
1423
- pipelineList.push({
1424
- $group: {
1425
- _id: `$${uniqueLabel}`,
1426
- doc: { $first: "$$ROOT" },
1427
- },
1428
- });
1429
- pipelineList.push({
1430
- $replaceRoot: { newRoot: "$doc" },
1431
- });
1432
- }
1433
- }
1434
- if (query && query.length > 0) {
1435
- const filter = handleParseQueryFilter(query);
1436
- pipelineList.push({ $match: filter });
1437
- }
1438
- // INFO: Default for mongoDB: filter then only sort
1439
- if (!isSortBeforeFilter) {
1440
- if (Object.keys(sortStage.$sort).length > 0) {
1441
- pipelineList.push(sortStage);
1442
- }
1443
- if (uniqueLabel) {
1444
- pipelineList.push({
1445
- $group: {
1446
- _id: `$${uniqueLabel}`,
1447
- doc: { $first: "$$ROOT" },
1448
- },
1449
- });
1450
- pipelineList.push({
1451
- $replaceRoot: { newRoot: "$doc" },
1452
- });
1453
- }
1454
- }
1455
- // INFO: Group by groupId if provided
1456
- if (groupId && !uniqueLabel) {
1457
- pipelineList.push({
1458
- $group: {
1459
- _id: `$${groupId}`,
1460
- topItem: { $first: "$$ROOT" },
1461
- children: { $push: "$$ROOT" },
1462
- },
1463
- });
1464
- pipelineList.push({
1465
- $replaceRoot: {
1466
- newRoot: {
1467
- $mergeObjects: [
1468
- "$topItem",
1469
- {
1470
- children: {
1471
- $cond: {
1472
- if: { $gt: [{ $size: "$children" }, 0] },
1473
- then: "$children",
1474
- else: "$$REMOVE",
1475
- },
1476
- },
1477
- },
1478
- ],
1479
- },
1480
- },
1481
- });
1482
- // INFO: Re-apply sort after group to maintain sort order
1483
- if (Object.keys(sortStage.$sort).length > 0) {
1484
- pipelineList.push(sortStage);
1485
- }
1486
- }
1487
- if (req.body.attributeIds && req.body.attributeIds.length > 0) {
1488
- const projection = { _id: 1 };
1489
- req.body.attributeIds.forEach((fieldId) => {
1490
- projection[fieldId] = 1;
1491
- });
1492
- pipelineList.push({ $project: projection });
1493
- }
1494
- if (req.body.excludeAttributeIds &&
1495
- req.body.excludeAttributeIds.length > 0) {
1496
- pipelineList.push({
1497
- $unset: req.body.excludeAttributeIds,
1498
- });
1499
- }
1500
- if (cursor) {
1501
- pipelineList.push({ $skip: Number.parseInt(cursor) });
1502
- }
1503
- if (!stopLimit) {
1504
- pipelineList.push({ $limit: limit || 10 });
1505
- }
1506
- // INFO : Remove Link Search
1507
- const foreignAliases = Array.from(addedForeignLookups.keys());
1508
- if (foreignAliases.length > 0) {
1509
- pipelineList.push({
1510
- $unset: [...foreignAliases],
1511
- });
1512
- }
1513
- const spaceReferenceFields = Array.from(addedSpaceReferences);
1514
- if (spaceReferenceFields.length > 0) {
1515
- pipelineList.push({
1516
- $unset: [...spaceReferenceFields],
1517
- });
1518
- }
1519
- }
1520
- catch (err) { }
1521
- return pipelineList;
1522
- }
1523
- }
1524
- exports.MongoWrapper = MongoWrapper;
1
+ var __awaiter=this&&this.__awaiter||function(e,r,l,d){return new(l=l||Promise)(function(i,t){function s(e){try{o(d.next(e))}catch(e){t(e)}}function a(e){try{o(d.throw(e))}catch(e){t(e)}}function o(e){var t;e.done?i(e.value):((t=e.value)instanceof l?t:new l(function(e){e(t)})).then(s,a)}o((d=d.apply(e,r||[])).next())})},__importDefault=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(exports,"__esModule",{value:!0}),exports.MongoWrapper=void 0;let dayjs_1=__importDefault(require("./dayjs")),uuid_1=require("uuid"),QueryModel_1=require("../model/QueryModel"),utils_1=require("./utils"),handleParseQueryFilter=(e,d)=>{let n={},u={};return e&&0<e.length&&e.map(i=>{let e,t,s,a=null!=(e=i.queryId)?e:"",o=(d&&(a=d+"."+a),i.value),r={},l=!!i.orQuery;switch(i.type){case"search":i.searchIds&&0<i.searchIds.length&&i.searchIds.map(e=>{l=!0,r[e]={$regex:""+(0,utils_1.handleSpecialWordsEscapeRegex)(o),$options:"i"}}),i.foreign&&0<i.foreign.length&&null!=(t=null==i?void 0:i.foreign)&&t.forEach(e=>{let t=e.alias;d&&(t=d+"."+t),e.searchFields&&0<e.searchFields.length&&e.searchFields.forEach(e=>{r[t+"."+e]={$regex:i.value.toString().replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),$options:"i"}})});break;case"=":r[a]=o;break;case"!=":r[a]={$ne:o};break;case">":r[a]={$gt:o};break;case"<":r[a]={$lt:o};break;case"><":Array.isArray(o)&&2<=o.length&&(r[a]={$gte:o[0],$lte:o[1]});break;case"in":r[a]={$in:o};break;case"!in":r[a]={$nin:o};break;case"exists":r[a]={$exists:o};break;case"elemMatch":r[a]={$elemMatch:o};break;case">size":r.$expr||(r.$expr={}),r.$expr.$gt=[{$size:"$"+a},o];break;case"<size":r.$expr||(r.$expr={}),r.$expr.$lt=[{$size:"$"+a},o]}i.orQueryGroupId&&("search"===i.type?null!=(s=null==i?void 0:i.searchIds)&&s.map(e=>{i.orQueryGroupId&&(u[null==i?void 0:i.orQueryGroupId]?u[null==i?void 0:i.orQueryGroupId].$and.push({[e]:r[e]}):u[null==i?void 0:i.orQueryGroupId]={$and:[{[e]:r[e]}]},delete r[e])}):void 0!==r[a]&&(u[i.orQueryGroupId]?u[i.orQueryGroupId].$and.push({[a]:r[a]}):u[i.orQueryGroupId]={$and:[{[a]:r[a]}]},delete r[a])),Object.keys(r).map(e=>{l?n.$or?n.$or.push({[e]:r[e]}):n.$or=[{[e]:r[e]}]:n[e]=r[e]})}),Object.keys(u).map(e=>{n.$or?n.$or.push(u[e]):n.$or=[u[e]]}),n};class MongoWrapper{constructor(e,t,i,s,a,o,r,l,d,n,u){this.mongoDB="",this.collection="",this.isProd=!1,this.config={baseConfig:[],opsConfig:{read:[],create:[],update:[],delete:[]}},this.tableId="",this.logId="",this.logCollectIds=[],this.modelChecker=e=>!1,this.parseModel=e=>(delete e._id,e.baseUpdatedAt=(0,dayjs_1.default)().toDate(),e),this.handleLogging=(r,l,t,d)=>__awaiter(this,void 0,void 0,function*(){if(this.logId)try{var e=t.body.bm_userId,i=t.body.bm_userRole,o=t.body.bm_userOrg;let s=[],a="create"===l?t.body.data:null==d?void 0:d.new;if(Object.keys(a).map(e=>{var t,i={newValue:a[e],columnId:e};"update"===l&&(i.oldValue=null==(t=null==d?void 0:d.old)?void 0:t[e],JSON.stringify(a[e])===JSON.stringify(null==(t=null==d?void 0:d.old)?void 0:t[e]))||"_id"===e||e.startsWith("base")||s.push(i)}),"update"!==l||0!==s.length){let t={_id:(0,uuid_1.v4)(),type:l,itemId:r,collectionId:this.collection,createdAt:(0,dayjs_1.default)().toDate(),values:s,userId:e,userRole:i,organisationId:o};("create"===l||"update"===l)&&0<this.logCollectIds.length&&this.logCollectIds.forEach(e=>{void 0!==a[e]&&(t[e]=a[e])}),yield this.mongoDB.db(this.tableId).collection(this.logId).insertOne(t),this.logWorkflow&&(yield this.logWorkflow(t))}}catch(e){}}),this.initBatchCreate=(c,h,y)=>__awaiter(this,void 0,void 0,function*(){var e;try{if(Array.isArray(c.body.data)){let t=!0;var a=!!c.body.upsert,o=(c.body.data.map(e=>{this.modelChecker(e)||(t=!1)}),t||h.status(400).json({err:"Invalid Model Structure"}),(0,QueryModel_1.checkBaseConfig)(this.config,c));let i=!0,s=[];if(yield Promise.all(c.body.data.map(e=>{(0,QueryModel_1.checkOpsConfig)(this.config,"update",c,e)||(i=!1),c.body.unique&&null!=e&&e[c.body.unique]&&s.push(e[c.body.unique])})),o&&i){var r=this.mongoDB.db(this.tableId).collection(this.collection);if(0<s.length){var l=yield(yield r.find({[c.body.unique]:{$in:s}})).toArray();if(0<l.length)return void h.status(400).json({err:`Unique:${l.map(e=>e[c.body.unique])} exists`})}let t=[];var d,n=c.body.data.map(e=>(t.push(e._id),Object.assign(Object.assign({},e),{baseUpdatedAt:(0,dayjs_1.default)().toDate()}))),u=(y&&(yield y(n)),a?(d=n.map(e=>({updateOne:{filter:{_id:e._id},update:{$set:e},upsert:!0}})),yield r.bulkWrite(d)):yield r.insertMany(n),{success:t});if(null!=(e=c.body)&&e.stopRes)return u;h.send(u)}else h.status(400).json({err:"Invalid Security Configuration"})}else h.status(400).json({err:"Invalid Fields"})}catch(e){h.status(400).json({err:e})}}),this.initCreate=(l,d,n)=>__awaiter(this,void 0,void 0,function*(){var e,t;try{if(this.modelChecker(l.body.data)){var i=(0,QueryModel_1.checkBaseConfig)(this.config,l),s=(0,QueryModel_1.checkOpsConfig)(this.config,"create",l,l.body.data);if(i&&s){var a=this.mongoDB.db(this.tableId).collection(this.collection);if(l.body.data.baseUpdatedAt=(0,dayjs_1.default)().toDate(),l.body.unique&&null!=(e=l.body.data)&&e[l.body.unique])if(yield a.findOne({[l.body.unique]:l.body.data[l.body.unique]}))return void d.status(400).json({err:`Unique:${l.body.data[l.body.unique]} exists`});n&&(yield n(l.body.data));var o=(yield a.insertOne(l.body.data)).insertedId.toString(),r=(yield this.handleLogging(o,"create",l),{success:!0});if(null!=(t=l.body)&&t.stopRes)return r;d.send(r)}else d.status(400).json({err:"Invalid Security Configuration"})}else d.status(400).json({err:"Invalid Model Structure"})}catch(e){d.status(400).json({err:e})}}),this.initGet=(d,n)=>__awaiter(this,void 0,void 0,function*(){var e;try{var t=d.body.id;if(t){var i,s=this.mongoDB.db(this.tableId).collection(this.collection),a=this.handleBuildPipeline({body:Object.assign(Object.assign({},d.body),{query:[{type:"=",queryId:"_id",value:t}]})}),[o]=yield s.aggregate(a).toArray(),r=(0,QueryModel_1.checkBaseConfig)(this.config,d),l=(0,QueryModel_1.checkOpsConfig)(this.config,"read",d,o);if(r&&l)return i={data:o},null!=(e=d.body)&&e.stopRes?i:void n.send(i);n.status(400).json({err:"Invalid Security Configuration"})}else n.status(400).json({err:"Invalid Fields"})}catch(e){n.status(400).json({err:e})}}),this.initBatchUpdate=($,f,b)=>__awaiter(this,void 0,void 0,function*(){var e,t,r;try{if(this.modelChecker($.body.data)&&$.body.query||$.body.unsetData){var l=$.body.unsetData,d=null!=(e=$.body.query)?e:[];let a=$.body.isOr?"$or":"$and",o={};var n=this.parseModel(null!=(t=$.body.data)?t:[]),u=(d&&0<d.length&&(o[a]=[],d.some(e=>"search"===e.type)&&(o.$or=[]),d.map(e=>{var t,i=null!=(t=e.queryId)?t:"";let s=e.value;switch(e.type){case"search":e.searchIds&&0<e.searchIds.length&&e.searchIds.map(e=>{o.$or.push({[e]:{$regex:(0,utils_1.handleSpecialWordsEscapeRegex)(s),$options:"i"}})});break;case"=":o[a].push({[i]:s});break;case"!=":o[a].push({[i]:{$ne:s}});break;case">":o[a].push({[i]:{$gt:s}});break;case"<":o[a].push({[i]:{$lt:s}});break;case"><":Array.isArray(s)&&2<=s.length&&(o[a]={[i]:{$gte:s[0],$lte:s[1]}});break;case"in":o[a].push({[i]:{$in:s}});break;case"!in":o[a].push({[i]:{$nin:s}});break;case"exists":o[a].push({$exists:s});break;case"elemMatch":o[a].push({[i]:{$elemMatch:s}})}})),(0,QueryModel_1.checkBaseConfig)(this.config,$));let i=!0;var c=this.mongoDB.db(this.tableId).collection(this.collection),h=yield(yield c.find(Object.assign({},o))).toArray();let s=[];if(yield Promise.all(h.map(e=>{$.body.sensitive&&!(0,dayjs_1.default)($.body.data.baseUpdatedAt).isAfter((0,dayjs_1.default)(e.baseUpdatedAt))&&f.status(400).json({err:"Refresh Sensitive Model"}),(0,QueryModel_1.checkOpsConfig)(this.config,"update",$,e)||(i=!1);var t=(0,utils_1.compareUpdatedFields)(e,$.body.data).workflowUpdateFields;s.push(Object.assign(Object.assign({},t),{_id:null==e?void 0:e._id}))})),u&&i){let t={};var y={},p=(l&&(l.forEach(e=>{t[e]=""}),y.$unset=Object.assign({},t)),n&&(y.$set=Object.assign({},n)),b&&(yield b(s)),yield c.updateMany(o,y),s.map(e=>e._id)),g={success:p};if(null!=(r=$.body)&&r.stopRes)return g;f.send(g)}else f.status(400).json({err:"Invalid Security Configuration"})}}catch(e){f.status(400).json({err:e})}}),this.initUpdate=(y,p,g)=>__awaiter(this,void 0,void 0,function*(){var e,s,a;try{var o=this.modelChecker(y.body.data)&&y.body.id;if(o){var r=!!y.body.upsert;let i={};var l=this.mongoDB.db(this.tableId).collection(this.collection),t=(r||(i=yield l.findOne({_id:o})),this.debug&&this.debug(y.body,i),(0,QueryModel_1.checkBaseConfig)(this.config,y)),d=(0,QueryModel_1.checkOpsConfig)(this.config,"update",y,i);if(t&&d){if(y.body.unique&&null!=(e=y.body.data)&&e[y.body.unique]){var n=yield l.findOne({[y.body.unique]:y.body.data[y.body.unique]});if(n&&y.body.id!==n._id)return void p.status(400).json({err:y.body.data[y.body.unique]+" exists"})}var u=(0,utils_1.compareUpdatedFields)(i,y.body.data).updatedFields,c={success:!0},h=(g&&(yield g(Object.assign(Object.assign({},u),{_id:o}))),this.parseModel(u));if(y.body.sensitive)if((0,dayjs_1.default)(y.body.data.baseUpdatedAt).isAfter((0,dayjs_1.default)(i.baseUpdatedAt))){if(yield l.updateOne({_id:o},{$set:Object.assign({},h)},{upsert:r}),null!=(s=y.body)&&s.stopRes)return c;p.send(c)}else p.status(400).json({err:"Refresh Sensitive Model"});else{if(yield l.updateOne({_id:o},{$set:Object.assign({},h)},{upsert:r}),null!=(a=y.body)&&a.stopRes)return c;p.send(c)}let t={};Object.keys(h).map(e=>{t[e]=i[e]}),yield this.handleLogging(o,"update",y,{old:t,new:h})}else p.status(400).json({err:"Invalid Security Configuration"})}else p.status(400).json({err:"Invalid Model Structure"})}catch(e){this.debug&&this.debug(null,null,e),p.status(400).json({err:e})}}),this.initBatchDelete=($,f,b)=>__awaiter(this,void 0,void 0,function*(){var e,t,i,s,a,o;try{if(!(Array.isArray($.body.id)&&0!==(null!=(t=null==(e=$.body.id)?void 0:e.length)?t:0)||Array.isArray($.body.query)&&0!==(null!=(s=null==(i=$.body.query)?void 0:i.length)?s:0)))throw"Invalid Batch Delete Config";if(Array.isArray($.body.id)){var r=this.mongoDB.db(this.tableId).collection(this.collection),l=yield r.find({_id:{$in:$.body.id}}),d=(0,QueryModel_1.checkBaseConfig)(this.config,$),n=yield l.toArray();let t=!0;if(0<n.length&&(yield Promise.all(n.map(e=>{(0,QueryModel_1.checkOpsConfig)(this.config,"delete",$,e)||(t=!1)}))),d&&t){b&&(yield b(n)),yield r.deleteMany({_id:{$in:$.body.id}});var u={success:$.body.id};if(null!=(a=$.body)&&a.stopRes)return u;f.send(u)}else f.status(400).json({err:"Invalid Security Configuration"})}else{var c=$.body.query;let a={};c&&0<c.length&&c.map(e=>{var t,i=null!=(t=e.queryId)?t:"";let s=e.value;switch(e.type){case"search":e.searchIds&&0<e.searchIds.length&&(a.$or=[],e.searchIds.map(e=>{a.$or.push({[e]:{$regex:(0,utils_1.handleSpecialWordsEscapeRegex)(s),$options:"i"}})}));break;case"=":a[i]=s;break;case"!=":a[i]={$ne:s};break;case">":a[i]={$gt:s};break;case"<":a[i]={$lt:s};break;case"><":Array.isArray(s)&&2<=s.length&&(a[i]={$gte:s[0],$lte:s[1]});break;case"in":a[i]={$in:s};break;case"!in":a[i]={$nin:s};break;case"exists":a[i]={$exists:s};break;case"elemMatch":a[i]={$elemMatch:s}}});var h=this.mongoDB.db(this.tableId).collection(this.collection),y=yield h.find(a).toArray(),p=(0,QueryModel_1.checkBaseConfig)(this.config,$);let t=!0,i=[];if(0<y.length&&y.map(e=>{i.push(e._id),(0,QueryModel_1.checkOpsConfig)(this.config,"delete",$,e)||(t=!1)}),b&&(yield b(y)),p&&t){yield h.deleteMany(a);var g={success:i};if(null!=(o=$.body)&&o.stopRes)return g;f.send(g)}else f.status(400).json({err:"Invalid Security Configuration"})}}catch(e){f.status(400).json({err:e})}}),this.initDelete=(l,d,n)=>__awaiter(this,void 0,void 0,function*(){var e;try{var t=l.body.id;if(t){var i=this.mongoDB.db(this.tableId).collection(this.collection),s=yield i.findOne({_id:t}),a=(0,QueryModel_1.checkBaseConfig)(this.config,l),o=(0,QueryModel_1.checkOpsConfig)(this.config,"delete",l,s);if(a&&o){n&&(yield n(s)),yield i.findOneAndDelete({_id:t}),yield this.handleLogging(s._id,"delete",l,{new:s});var r={success:!0};if(null!=(e=l.body)&&e.stopRes)return r;d.send(r)}else d.status(400).json({err:"Invalid Security Configuration"})}else d.status(400).json({err:"Invalid Fields"})}catch(e){d.status(400).json({err:e})}}),this.initList=(ae,oe)=>__awaiter(this,void 0,void 0,function*(){var e,t,i,s,r,l,n,u,c,h,a,y,p,g,$,f,b,v,m,_;try{var I=(0,QueryModel_1.checkBaseConfig)(this.config,ae);if(I){var j=ae.body.aggregate,k=null!=(e=ae.body.unionCollections)?e:[];let o=null!=(t=ae.body.query)?t:[],d;if(d=handleParseQueryFilter(o),k&&Array.isArray(k)&&0<k.length){if(j)return void oe.status(400).json({err:"Union operations cannot be combined with aggregate"});var O=null!=(i=ae.body.sort)?i:{date:-1},M=null!=(s=ae.body.limit)?s:50,C=null!=(l=null!=(r=ae.body.cursor)?r:ae.body.skip)?l:0;let a=[];if(k.forEach((e,t)=>{let i={$project:Object.assign({_id:1},e.projection)};var s;e.sourceLogic?i.$project.source="string"==typeof e.sourceLogic?{$literal:e.sourceLogic}:e.sourceLogic:i.$project.source={$literal:e.source},0===t?(o&&0<o.length&&a.push({$match:d}),e.query&&0<e.query.length&&(t=handleParseQueryFilter(e.query),a.push({$match:t})),e.addFields&&(a.push({$addFields:e.addFields}),Object.keys(e.addFields).forEach(e=>{i.$project[e]=1})),a.push(i)):(t=[],e.query&&0<e.query.length&&(s=handleParseQueryFilter(e.query),t.push({$match:s})),e.addFields&&(t.push({$addFields:e.addFields}),Object.keys(e.addFields).forEach(e=>{i.$project[e]=1})),t.push(i),s={$unionWith:{coll:e.collection,pipeline:t}},a.push(s))}),O){let t={$sort:{}};Array.isArray(O)?O.forEach(e=>{e.sortId&&(t.$sort[e.sortId]="asc"===e.type?1:-1)}):O.sortId&&O.type?t.$sort[O.sortId]="asc"===O.type?1:-1:t.$sort=O,a.push(t)}0<C&&a.push({$skip:C}),0<M&&a.push({$limit:M});var A,S=null!=(u=null==(n=k[0])?void 0:n.collection)?u:this.collection,D=this.mongoDB.db(this.tableId).collection(S),q=yield D.aggregate(a).toArray(),w=a.filter(e=>{e=Object.keys(e)[0];return"$skip"!==e&&"$limit"!==e}),E=(w.push({$count:"total"}),yield D.aggregate(w).toArray()),U=(null==(c=E[0])?void 0:c.total)||0;let t=!0;return(q.map(e=>{(0,QueryModel_1.checkOpsConfig)(this.config,"read",ae,e)||(t=!1)}),I&&t)?(A={data:q,count:U},null!=(h=ae.body)&&h.stopRes?A:void oe.send(A)):void oe.status(400).json({err:"Invalid Security Configuration"})}if(j){var Y,H=[],P=null!=(a=j.queryId)?a:"",L=null!=(y=j.dateId)?y:"baseUpdatedAt",F=j.timezone||"Asia/Kuala_Lumpur";for(Y of null!=(p=j.range)?p:[(0,dayjs_1.default)().tz(F).format("DD/MM/YYYY HH:mm:ss")]){Object.assign({},d);var W=Y.split("-"),[Q,z=(0,dayjs_1.default)().tz(F).format("DD/MM/YYYY HH:mm:ss")]=W,G=2===W.length,T=(0,dayjs_1.default)(Q,"DD/MM/YYYY HH:mm:ss").isValid(),N=(0,dayjs_1.default)(z,"DD/MM/YYYY HH:mm:ss").isValid(),V=dayjs_1.default.tz((0,dayjs_1.default)(Q,"DD/MM/YYYY HH:mm:ss").format("YYYY-MM-DDTHH:mm:ss"),F).utc().toDate(),J=dayjs_1.default.tz((0,dayjs_1.default)(z,"DD/MM/YYYY HH:mm:ss").format("YYYY-MM-DDTHH:mm:ss"),F).utc().toDate();if(!T||!N)return void oe.status(400).json({err:"Invalid Aggregate Range Configuration"});let o=[G?{$match:Object.assign(Object.assign({},d),{[L]:{$gte:V,$lte:J}})}:{$match:Object.assign(Object.assign({},d),{[L]:{$lte:V}})}],r=G?Y:"Begining until "+(0,dayjs_1.default)(Q,"DD/MM/YYYY HH:mm:ss").format("DD/MM/YYYY"),l=!1;if(j.unwind&&0<j.unwind.length&&j.unwind.map((e,t)=>{var i,s="model"+t;let a="";0<t&&(a="model"+(t-1)+".");t=handleParseQueryFilter(null!=(t=e.query)?t:[],s);null!=(i=e.unique)&&i.list&&o.push({$unwind:"$"+e.localField}),o.push({$lookup:{from:e.collectionId,localField:a+e.localField,foreignField:"_id",as:s}},{$unwind:"$"+s},{$match:t}),null!=(i=e.unique)&&i.type&&(l=!0,s="uniqueUnwindId",o.push({$group:{_id:r,uniqueUnwindId:{$addToSet:"$"+e.localField}}}),"count"===e.unique.type?o.push({$project:{value:{$size:"$"+s}}}):o.push({$project:{_id:0,value:"$"+s}}))}),!l){let e=r;switch(j.groupId&&(e="$"+j.groupId),j.type){case"avg":o.push({$group:{_id:e,value:{$avg:"$"+P}}});break;case"sum":o.push({$group:{_id:e,value:{$sum:"$"+P}}});break;case"count":o.push({$group:{_id:e,value:{$sum:1},ids:{$push:"$_id"}}})}}if(0===o.length)return void oe.status(400).json({err:"Invalid Aggregate Configuration"});var K=this.mongoDB.db(this.tableId).collection(this.collection);let e=0,t=[];var B=yield K.aggregate(o).toArray();j.groupId?e=B:(e=null!=($=null==(g=B[0])?void 0:g.value)?$:0,t=null!=(b=null==(f=B[0])?void 0:f.ids)?b:[]),H.push({_id:r,value:e,ids:t})}var X={data:H};if(null!=(v=ae.body)&&v.stopRes)return X;oe.send(X)}else{var R,Z=this.mongoDB.db(this.tableId).collection(this.collection),ee=this.handleBuildPipeline(ae),te=ee.filter(e=>{e=Object.keys(e)[0];return"$skip"!==e&&"$limit"!==e}),[x,ie]=(te.push({$count:"total"}),yield Promise.all([Z.aggregate(ee).toArray(),Z.aggregate(te).toArray()])),se=(null==(m=ie[0])?void 0:m.total)||0;let t=!0;if(0<x.length&&x.map(e=>{(0,QueryModel_1.checkOpsConfig)(this.config,"read",ae,e)||(t=!1)}),I&&t)return R={data:x,count:se},null!=(_=ae.body)&&_.stopRes?R:void oe.send(R);oe.status(400).json({err:"Invalid Security Configuration"})}}else oe.status(400).json({err:"Invalid Security Configuration"})}catch(e){oe.status(400).json({err:e.message})}}),this.init=()=>{var e=this.lib.express.Router();return e.post("/create",(e,t)=>{this.initCreate(e,t)}),e.post("/batchCreate",(e,t)=>{this.initBatchCreate(e,t)}),e.post("/get",(e,t)=>{this.initGet(e,t)}),e.post("/update",(e,t)=>{this.initUpdate(e,t)}),e.post("/batchUpdate",(e,t)=>{this.initBatchUpdate(e,t)}),e.post("/delete",(e,t)=>{this.initDelete(e,t)}),e.post("/batchDelete",(e,t)=>{this.initBatchDelete(e,t)}),e.post("/list",(e,t)=>{this.initList(e,t)}),e},this.mongoDB=e,this.collection=t,this.isProd=i,this.config=s,this.modelChecker=a,this.lib=o;e=this.isProd?"prod":"dev";this.tableId=r?r+"-"+e:e,this.logId=null!=l?l:"",this.logWorkflow=d,this.logCollectIds=null!=n?n:[],this.debug=u}handleBuildPipeline(e){let n=[],i=new Map,u=new Set;var{query:s,sort:a,cursor:o,limit:r,stopLimit:l,pipeline:d,uniqueLabel:c,groupId:h}=e.body;try{Array.isArray(d)&&0<d.length&&d.forEach(e=>{var{condition:e,referenceSpaceLabel:s,spaceReferenceId:a,spaceReferenceAs:o,referenceSort:r,referenceFirstItem:l,referenceLimit:d}=e;if(a){let i=o||"linkedData",t=(u.add(i),{$lookup:{from:a,let:{},pipeline:[],as:i}});if(e&&0<e.length){e.forEach(e=>{t.$lookup.let["local_"+e.fromColumnId]="$"+e.fromColumnId});let i={$match:{$expr:{$and:[]}}};e.forEach(e=>{var t={};switch(e.type){case"=":t.$eq=["$"+e.toColumnId,"$$local_"+e.fromColumnId];break;case"!=":t.$ne=["$"+e.toColumnId,"$$local_"+e.fromColumnId];break;case">":t.$gt=["$"+e.toColumnId,"$$local_"+e.fromColumnId];break;case"<":t.$lt=["$"+e.toColumnId,"$$local_"+e.fromColumnId];break;case"in":t.$in=["$"+e.toColumnId,"$$local_"+e.fromColumnId];break;case"!in":t.$nin=["$"+e.toColumnId,"$$local_"+e.fromColumnId]}0<Object.keys(t).length&&i.$match.$expr.$and.push(t)}),t.$lookup.pipeline.push(i)}if(r&&r.sortId&&(o={$sort:{[r.sortId]:"asc"===r.type?1:-1}},t.$lookup.pipeline.push(o)),d&&t.$lookup.pipeline.push({$limit:d}),n.push(t),s&&0<s.length){let t={$addFields:{}};l?(n.push({$addFields:{[i]:{$first:{$ifNull:["$"+i,[]]}}}}),s.forEach(e=>{t.$addFields[i+"_"+e]=`$${i}.`+e})):s.forEach(e=>{t.$addFields[i+"_"+e]={$map:{input:"$"+i,in:"$$this."+e}}}),n.push(t)}}}),s&&0<s.length&&s.forEach(e=>{e.foreign&&Array.isArray(e.foreign)&&e.foreign.forEach(e=>{var t=e.alias;i.has(t)||(n.push({$lookup:{from:e.collection,localField:e.localField,foreignField:"_id",as:t}}),i.set(t,!0))})});let t={$sort:{}};a&&(Array.isArray(JSON.parse(JSON.stringify(a)))?a:[a]).forEach(e=>{e.sortId&&(t.$sort[e.sortId]="asc"===e.type?1:-1)});var y,p=null==a?void 0:a.sortBeforeFilter;if(p&&(0<Object.keys(t.$sort).length&&n.push(t),c)&&(n.push({$group:{_id:"$"+c,doc:{$first:"$$ROOT"}}}),n.push({$replaceRoot:{newRoot:"$doc"}})),s&&0<s.length&&(y=handleParseQueryFilter(s),n.push({$match:y})),p||(0<Object.keys(t.$sort).length&&n.push(t),c&&(n.push({$group:{_id:"$"+c,doc:{$first:"$$ROOT"}}}),n.push({$replaceRoot:{newRoot:"$doc"}}))),h&&!c&&(n.push({$group:{_id:"$"+h,topItem:{$first:"$$ROOT"},children:{$push:"$$ROOT"}}}),n.push({$replaceRoot:{newRoot:{$mergeObjects:["$topItem",{children:{$cond:{if:{$gt:[{$size:"$children"},0]},then:"$children",else:"$$REMOVE"}}}]}}}),0<Object.keys(t.$sort).length)&&n.push(t),e.body.attributeIds&&0<e.body.attributeIds.length){let t={_id:1};e.body.attributeIds.forEach(e=>{t[e]=1}),n.push({$project:t})}e.body.excludeAttributeIds&&0<e.body.excludeAttributeIds.length&&n.push({$unset:e.body.excludeAttributeIds}),o&&n.push({$skip:Number.parseInt(o)}),l||n.push({$limit:r||10});var g=Array.from(i.keys()),$=(0<g.length&&n.push({$unset:[...g]}),Array.from(u));0<$.length&&n.push({$unset:[...$]})}catch(e){}return n}}exports.MongoWrapper=MongoWrapper;