@simitgroup/simpleapp-generator 1.1.12 → 1.1.15
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/buildinschemas/autoincreament.d.ts.map +1 -1
- package/dist/buildinschemas/autoincreament.js +1 -2
- package/dist/buildinschemas/autoincreament.js.map +1 -1
- package/dist/buildinschemas/docnoformat.d.ts.map +1 -1
- package/dist/buildinschemas/docnoformat.js +0 -1
- package/dist/buildinschemas/docnoformat.js.map +1 -1
- package/dist/buildinschemas/permission.d.ts.map +1 -1
- package/dist/buildinschemas/permission.js +0 -1
- package/dist/buildinschemas/permission.js.map +1 -1
- package/dist/framework.js +4 -4
- package/dist/framework.js.map +1 -1
- package/dist/generate.d.ts.map +1 -1
- package/dist/generate.js +20 -7
- package/dist/generate.js.map +1 -1
- package/dist/processors/bpmnbuilder.d.ts +2 -0
- package/dist/processors/bpmnbuilder.d.ts.map +1 -0
- package/dist/processors/bpmnbuilder.js +151 -0
- package/dist/processors/bpmnbuilder.js.map +1 -0
- package/dist/resource/camunda-moodle.d.ts +27 -0
- package/dist/resource/camunda-moodle.d.ts.map +1 -0
- package/dist/resource/camunda-moodle.js +91 -0
- package/dist/resource/camunda-moodle.js.map +1 -0
- package/dist/type.d.ts +0 -1
- package/dist/type.d.ts.map +1 -1
- package/dist/type.js.map +1 -1
- package/docs/backend.md +1 -1
- package/package.json +3 -1
- package/src/buildinschemas/autoincreament.ts +2 -3
- package/src/buildinschemas/docnoformat.ts +0 -1
- package/src/buildinschemas/permission.ts +0 -1
- package/src/framework.ts +4 -4
- package/src/generate.ts +25 -7
- package/src/processors/bpmnbuilder.ts +148 -0
- package/src/resource/camunda-moodle.ts +87 -0
- package/src/type.ts +1 -2
- package/templates/basic/nest/controller.ts.eta +3 -3
- package/templates/basic/nest/service.ts.eta +4 -6
- package/templates/basic/nuxt/pages.[id].vue.eta +4 -3
- package/templates/basic/nuxt/pages.form.vue.eta +0 -1
- package/templates/basic/nuxt/pages.landing.vue.eta +11 -11
- package/templates/basic/nuxt/pages.new.vue.eta +4 -3
- package/templates/basic/nuxt/pages.viewer.vue.eta +4 -7
- package/templates/nest/.env._eta +1 -1
- package/templates/nest/src/app.module.ts.eta +20 -2
- package/templates/nest/src/simpleapp/.gitignore.eta +2 -1
- package/templates/nest/src/simpleapp/generate/commons/user.context.ts.eta +23 -4
- package/templates/nest/src/simpleapp/generate/processors/simpleapp.processor.ts.eta +356 -294
- package/templates/nest/src/simpleapp/generate/workflow/formschema/SimpleApproveReject.ts.eta +8 -0
- package/templates/nest/src/simpleapp/generate/workflow/formschema/index.ts.eta +1 -0
- package/templates/nest/src/simpleapp/{workflow → generate/workflow}/workflow.apischema.ts.eta +17 -22
- package/templates/nest/src/simpleapp/generate/workflow/workflow.config.ts.eta +57 -0
- package/templates/nest/src/simpleapp/{workflow → generate/workflow}/workflow.controller.ts.eta +5 -6
- package/templates/nest/src/simpleapp/generate/workflow/workflow.delegate.ts.eta +153 -0
- package/templates/nest/src/simpleapp/{workflow → generate/workflow}/workflow.service.ts.eta +62 -75
- package/templates/nest/src/simpleapp/{workflow → generate/workflow}/workflow.type.ts.eta +24 -20
- package/templates/nest/src/simpleapp/simpleapp.module.ts.eta +16 -6
- package/templates/nest/src/simpleapp/workflows/bpmn/readme.md._eta +1 -0
- package/templates/nest/src/simpleapp/workflows/delegates/simpleapp.delegate.ts._eta +27 -0
- package/templates/nest/src/simpleapp/workflows/readme.md._eta +1 -0
- package/templates/nuxt/.gitignore.eta +5 -4
- package/templates/nuxt/components/header/button/task/HeaderButtonTaskList.vue.eta +47 -65
- package/templates/nuxt/components/simpleApp/SimpleAppForm.vue.eta +1 -1
- package/templates/nuxt/components/simpleApp/SimpleAppJsonSchemaForm.vue.eta +58 -23
- package/templates/nuxt/components/workflow/forms/dynamicfield.vue._eta +85 -0
- package/templates/nuxt/components/workflow/forms/index.ts._eta +10 -0
- package/templates/nuxt/components/workflow/forms/simpleapprove.vue._eta +43 -0
- package/templates/nuxt/lang/{df.ts.eta → df.ts._eta} +6 -1
- package/templates/nuxt/nuxt.config.ts.eta +1 -1
- package/templates/nuxt/simpleapp/workflows/bpmn/readme.md._eta +1 -0
- package/templates/nuxt/simpleapp/workflows/forms/readme.md._eta +1 -0
- package/templates/nuxt/types/schema.ts.eta +1 -2
- package/templates/project/groups/admin.json.eta +1 -1
- package/templates/{nest/src/simpleapp/workflow/bpmn/suspendcustomer.bpmn.eta → project/workflows/bpmn/suspendcustomer.bpmn._eta} +20 -20
- package/templates/project/workflows/forms/index.ts.eta +2 -0
- package/templates/project/workflows/forms/simpleapprove.jsonschema.ts.eta +8 -0
- package/templates/workflow/next/delegate.ts.eta +31 -0
- package/tsconfig.tsbuildinfo +1 -1
- package/buildinschemas copy/autoincreament.autoinc.jsonschema.json +0 -39
- package/buildinschemas copy/branch.branch.jsonschema.json +0 -41
- package/buildinschemas copy/docnoformat.docno.jsonschema.json +0 -23
- package/buildinschemas copy/organization.org.jsonschema.json +0 -50
- package/buildinschemas copy/permission.perm.jsonschema.json +0 -23
- package/buildinschemas copy/permission.perm.jsonschema.try.json +0 -25
- package/buildinschemas copy/tenant.tenant.jsonschema.json +0 -21
- package/buildinschemas copy/tenant.tenant.jsonschema.try.json +0 -27
- package/buildinschemas copy/user.user.jsonschema.json +0 -31
- package/src/processors/jsonschemabuilder.ts-old +0 -383
- package/templates/nest/src/simpleapp/workflow/appDelegate.ts.eta +0 -194
- package/templates/nest/src/simpleapp/workflow/configuration.ts.eta +0 -46
- package/templates/nest/src/simpleapp/workflow/delegates/customer.ts._eta +0 -8
- package/templates/nest/src/simpleapp/workflow/delegates/hello.ts._eta +0 -5
- package/templates/nest/src/simpleapp/workflow/delegates/index.ts._eta +0 -5
- package/templates/nest/src/simpleapp/workflow/delegates/invoice.delegates.ts._eta +0 -9
- package/templates/nest/src/simpleapp/workflow/delegates/usertask.ts._eta +0 -3
- package/templates/nest/src/simpleapp/workflow/formschema/SimpleApproveReject.ts.eta +0 -8
- package/templates/nest/src/simpleapp/workflow/formschema/index.ts.eta +0 -1
|
@@ -4,13 +4,21 @@
|
|
|
4
4
|
* last change 2023-10-28
|
|
5
5
|
* Author: Ks Tan
|
|
6
6
|
*/
|
|
7
|
-
import { Injectable, Logger,Inject } from '@nestjs/common';
|
|
7
|
+
import { Injectable, Logger, Inject } from '@nestjs/common';
|
|
8
8
|
import { InjectModel } from '@nestjs/mongoose';
|
|
9
|
-
import jsonpath from 'jsonpath'
|
|
10
|
-
import {
|
|
9
|
+
import jsonpath from 'jsonpath';
|
|
10
|
+
import { uniq } from 'lodash';
|
|
11
11
|
import { AuditTrail } from '../commons/audittrail.service';
|
|
12
|
-
import {foreignkeys} from '../commons/dicts/foreignkeys'
|
|
13
|
-
import {
|
|
12
|
+
import { foreignkeys } from '../commons/dicts/foreignkeys';
|
|
13
|
+
import { EventEmitter2 } from '@nestjs/event-emitter';
|
|
14
|
+
import {
|
|
15
|
+
Model,
|
|
16
|
+
Types,
|
|
17
|
+
PipelineStage,
|
|
18
|
+
mongo,
|
|
19
|
+
FilterQuery,
|
|
20
|
+
ProjectionType,
|
|
21
|
+
} from 'mongoose';
|
|
14
22
|
import Ajv from 'ajv';
|
|
15
23
|
import addFormats from 'ajv-formats';
|
|
16
24
|
import addErrors from 'ajv-errors';
|
|
@@ -50,8 +58,12 @@ export type MoreProjectionType = {
|
|
|
50
58
|
};
|
|
51
59
|
@Injectable()
|
|
52
60
|
export class SimpleAppService<T extends { _id?: string }> {
|
|
61
|
+
|
|
62
|
+
@Inject(EventEmitter2)
|
|
63
|
+
protected eventEmitter: EventEmitter2
|
|
64
|
+
|
|
53
65
|
protected logger = new Logger();
|
|
54
|
-
protected strictIsolation = true
|
|
66
|
+
protected strictIsolation = true;
|
|
55
67
|
protected jsonschema = { type: 'object', properties: {}, required: [] };
|
|
56
68
|
protected documentIdentityCode = 'code';
|
|
57
69
|
protected documentIdentityLabel = 'label';
|
|
@@ -64,15 +76,14 @@ export class SimpleAppService<T extends { _id?: string }> {
|
|
|
64
76
|
protected data: T = { _id: '' } as T;
|
|
65
77
|
protected doc: Model<T>; //set private to prevent developer break data isolation control
|
|
66
78
|
protected errorlist = [];
|
|
67
|
-
protected withDocNumberFormat=false
|
|
68
|
-
protected foreignkeys = {}
|
|
69
|
-
|
|
79
|
+
protected withDocNumberFormat = false;
|
|
80
|
+
protected foreignkeys = {};
|
|
81
|
+
|
|
70
82
|
@Inject(AuditTrail)
|
|
71
|
-
protected audittrail: AuditTrail
|
|
83
|
+
protected audittrail: AuditTrail;
|
|
72
84
|
|
|
73
85
|
@Inject(DocNumberFormatGenerator)
|
|
74
|
-
protected docnogenerator: DocNumberFormatGenerator
|
|
75
|
-
|
|
86
|
+
protected docnogenerator: DocNumberFormatGenerator;
|
|
76
87
|
|
|
77
88
|
// protected userprovider = new UserContext() ;
|
|
78
89
|
|
|
@@ -80,14 +91,14 @@ export class SimpleAppService<T extends { _id?: string }> {
|
|
|
80
91
|
doctype: string,
|
|
81
92
|
docname: string,
|
|
82
93
|
newdoc: Model<T>,
|
|
83
|
-
isolationtype: IsolationType = IsolationType.org
|
|
84
|
-
) {
|
|
94
|
+
isolationtype: IsolationType = IsolationType.org,
|
|
95
|
+
) {
|
|
85
96
|
// console.log("-------init simpleapp service abstract class -------userprovider=",typeof this.userprovider)
|
|
86
97
|
this.documentType = doctype.toUpperCase();
|
|
87
98
|
this.documentName = docname;
|
|
88
99
|
this.doc = newdoc;
|
|
89
100
|
this.isolationtype = isolationtype;
|
|
90
|
-
this.hook(undefined,HookType.init, undefined);
|
|
101
|
+
this.hook(undefined, HookType.init, undefined);
|
|
91
102
|
// this.tenantdoc = tenantdoc
|
|
92
103
|
}
|
|
93
104
|
getDocumentType = () => this.documentType;
|
|
@@ -104,8 +115,8 @@ export class SimpleAppService<T extends { _id?: string }> {
|
|
|
104
115
|
this.data = { ...newdata };
|
|
105
116
|
return this;
|
|
106
117
|
};
|
|
107
|
-
reCalculateValue(data:T) {}
|
|
108
|
-
getIsolationFilter = (appuser:UserContext
|
|
118
|
+
reCalculateValue(data: T) {}
|
|
119
|
+
getIsolationFilter = (appuser: UserContext) => {
|
|
109
120
|
let isolationFilter = {};
|
|
110
121
|
switch (this.isolationtype) {
|
|
111
122
|
case 'none':
|
|
@@ -124,7 +135,7 @@ export class SimpleAppService<T extends { _id?: string }> {
|
|
|
124
135
|
}
|
|
125
136
|
return isolationFilter;
|
|
126
137
|
};
|
|
127
|
-
async list(appuser:UserContext
|
|
138
|
+
async list(appuser: UserContext) {
|
|
128
139
|
try {
|
|
129
140
|
//console.log("this.isolationFilter",this.getIsolationFilter())
|
|
130
141
|
const products = await this.doc.find(this.getIsolationFilter(appuser));
|
|
@@ -147,7 +158,7 @@ export class SimpleAppService<T extends { _id?: string }> {
|
|
|
147
158
|
}
|
|
148
159
|
// console.log(this.moreAutoCompleteField);
|
|
149
160
|
};
|
|
150
|
-
async getAutoComplete(appuser:UserContext, keyword: string) {
|
|
161
|
+
async getAutoComplete(appuser: UserContext, keyword: string) {
|
|
151
162
|
try {
|
|
152
163
|
const filter1 = {};
|
|
153
164
|
const filter2 = {};
|
|
@@ -186,18 +197,18 @@ export class SimpleAppService<T extends { _id?: string }> {
|
|
|
186
197
|
|
|
187
198
|
/**
|
|
188
199
|
* Special search function which can by pass data isolation. reserved and try not use
|
|
189
|
-
* @param appuser
|
|
190
|
-
* @param filters
|
|
191
|
-
* @returns
|
|
200
|
+
* @param appuser
|
|
201
|
+
* @param filters
|
|
202
|
+
* @returns
|
|
192
203
|
*/
|
|
193
|
-
private async searchNoIsolation(appuser:UserContext,filters: Object) {
|
|
204
|
+
private async searchNoIsolation(appuser: UserContext, filters: Object) {
|
|
194
205
|
try {
|
|
195
|
-
await this.hook(appuser,HookType.beforeSearch, filters);
|
|
206
|
+
await this.hook(appuser, HookType.beforeSearch, filters);
|
|
196
207
|
const products = await this.doc.find(filters);
|
|
197
208
|
const productlist = products.map((p: T) => {
|
|
198
209
|
return p;
|
|
199
210
|
});
|
|
200
|
-
await this.hook(appuser,HookType.afterSearch, productlist);
|
|
211
|
+
await this.hook(appuser, HookType.afterSearch, productlist);
|
|
201
212
|
// console.log(products);
|
|
202
213
|
return productlist;
|
|
203
214
|
} catch (err) {
|
|
@@ -205,43 +216,48 @@ export class SimpleAppService<T extends { _id?: string }> {
|
|
|
205
216
|
}
|
|
206
217
|
// return this;
|
|
207
218
|
}
|
|
208
|
-
async aggregate(appuser:UserContext,pipeline:PipelineStage[]){
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
Object.assign(pipeline[0]['$match'],isolationFilter);
|
|
219
|
+
async aggregate(appuser: UserContext, pipeline: PipelineStage[]) {
|
|
220
|
+
if (pipeline[0] && pipeline[0]['$match']) {
|
|
221
|
+
try {
|
|
222
|
+
const isolationFilter = { ...this.getIsolationFilter(appuser) };
|
|
223
|
+
this.polishIsolationFilter(isolationFilter);
|
|
224
|
+
|
|
225
|
+
Object.assign(pipeline[0]['$match'], isolationFilter);
|
|
217
226
|
//console.log("final agg",pipeline)
|
|
218
|
-
return await this.doc.aggregate(pipeline)
|
|
219
|
-
}catch(err){
|
|
220
|
-
throw new InternalServerErrorException(err);
|
|
227
|
+
return await this.doc.aggregate(pipeline);
|
|
228
|
+
} catch (err) {
|
|
229
|
+
throw new InternalServerErrorException(err);
|
|
221
230
|
}
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
231
|
+
} else {
|
|
232
|
+
throw new InternalServerErrorException(
|
|
233
|
+
'first aggregate pipelinestage shall use $match',
|
|
234
|
+
);
|
|
225
235
|
}
|
|
226
|
-
|
|
227
236
|
}
|
|
228
|
-
async search(
|
|
237
|
+
async search(
|
|
238
|
+
appuser: UserContext,
|
|
239
|
+
filters: FilterQuery<T>,
|
|
240
|
+
projection: ProjectionType<T> = undefined,
|
|
241
|
+
sort: any = undefined,
|
|
242
|
+
) {
|
|
229
243
|
try {
|
|
230
|
-
const isolationFilter= {...
|
|
231
|
-
this.polishIsolationFilter(isolationFilter)
|
|
232
|
-
|
|
244
|
+
const isolationFilter = { ...this.getIsolationFilter(appuser) };
|
|
245
|
+
this.polishIsolationFilter(isolationFilter);
|
|
246
|
+
|
|
233
247
|
// console.log("initial search",filters)
|
|
234
|
-
const newfilters ={...filters
|
|
235
|
-
await this.hook(appuser,HookType.beforeSearch, newfilters);
|
|
248
|
+
const newfilters = { ...filters, ...isolationFilter };
|
|
249
|
+
await this.hook(appuser, HookType.beforeSearch, newfilters);
|
|
236
250
|
// console.log("before _find",newfilters)
|
|
237
251
|
// console.log("this.doc",this.doc)
|
|
238
|
-
const products = await this.doc
|
|
252
|
+
const products = await this.doc
|
|
253
|
+
.find(newfilters, projection, { session: appuser.getDBSession() })
|
|
254
|
+
.sort(sort);
|
|
239
255
|
// console.log("after search",products)
|
|
240
256
|
const productlist = products.map((p: T) => {
|
|
241
257
|
return p;
|
|
242
258
|
});
|
|
243
259
|
// console.log("after map",productlist)
|
|
244
|
-
await this.hook(appuser,HookType.afterSearch, productlist);
|
|
260
|
+
await this.hook(appuser, HookType.afterSearch, productlist);
|
|
245
261
|
// console.log(products);
|
|
246
262
|
return productlist;
|
|
247
263
|
} catch (err) {
|
|
@@ -249,10 +265,10 @@ export class SimpleAppService<T extends { _id?: string }> {
|
|
|
249
265
|
}
|
|
250
266
|
// return this;
|
|
251
267
|
}
|
|
252
|
-
async findById(appuser:UserContext,id: string) {
|
|
253
|
-
await this.hook(appuser,HookType.beforeFetchRecord, id);
|
|
254
|
-
const data = await this.search(appuser,{ _id: id });
|
|
255
|
-
await this.hook(appuser,HookType.afterFetchRecord, data);
|
|
268
|
+
async findById(appuser: UserContext, id: string) {
|
|
269
|
+
await this.hook(appuser, HookType.beforeFetchRecord, id);
|
|
270
|
+
const data = await this.search(appuser, { _id: id });
|
|
271
|
+
await this.hook(appuser, HookType.afterFetchRecord, data);
|
|
256
272
|
if (data.length == 1) {
|
|
257
273
|
// console.log('data0', data[0]);
|
|
258
274
|
return data[0];
|
|
@@ -261,88 +277,100 @@ export class SimpleAppService<T extends { _id?: string }> {
|
|
|
261
277
|
}
|
|
262
278
|
}
|
|
263
279
|
|
|
264
|
-
|
|
265
|
-
async create(appuser:UserContext, data:T) {
|
|
266
|
-
|
|
280
|
+
async create(appuser: UserContext, data: T) {
|
|
267
281
|
let result;
|
|
268
|
-
if(!data._id){
|
|
269
|
-
data._id = crypto.randomUUID()
|
|
282
|
+
if (!data._id) {
|
|
283
|
+
data._id = crypto.randomUUID();
|
|
270
284
|
}
|
|
271
|
-
const dbsession = appuser.getDBSession()
|
|
272
|
-
if(!dbsession.inTransaction()){
|
|
273
|
-
dbsession.startTransaction()
|
|
285
|
+
const dbsession = appuser.getDBSession();
|
|
286
|
+
if (!dbsession.inTransaction()) {
|
|
287
|
+
dbsession.startTransaction();
|
|
274
288
|
}
|
|
275
289
|
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
290
|
+
this.logger.debug(
|
|
291
|
+
'this.withDocNumberFormat :' +
|
|
292
|
+
this.withDocNumberFormat +
|
|
293
|
+
' && ' +
|
|
294
|
+
'!data[this.documentIdentityCode] ==' +
|
|
295
|
+
!data[this.documentIdentityCode],
|
|
296
|
+
);
|
|
297
|
+
if (this.withDocNumberFormat && !data[this.documentIdentityCode]) {
|
|
298
|
+
await this.genNewDocNo(appuser, data);
|
|
280
299
|
}
|
|
281
|
-
|
|
282
|
-
await this.hook(appuser,HookType.beforeCreate, data);
|
|
283
|
-
|
|
284
|
-
let isolationFilter:any =
|
|
285
|
-
isolationFilter = this.polishIsolationFilter(isolationFilter,data)
|
|
286
|
-
|
|
287
|
-
this.logger.debug(
|
|
288
|
-
this.logger.debug(isolationFilter,'SimpleAppService')
|
|
289
|
-
this.logger.debug(
|
|
290
|
-
this.logger.debug(data,'SimpleAppService')
|
|
300
|
+
|
|
301
|
+
await this.hook(appuser, HookType.beforeCreate, data);
|
|
302
|
+
|
|
303
|
+
let isolationFilter: any = { ...appuser.getCreateFilter() };
|
|
304
|
+
isolationFilter = this.polishIsolationFilter(isolationFilter, data);
|
|
305
|
+
|
|
306
|
+
this.logger.debug('isolationFilter', 'SimpleAppService');
|
|
307
|
+
this.logger.debug(isolationFilter, 'SimpleAppService');
|
|
308
|
+
this.logger.debug('Create data before isolation', 'SimpleAppService');
|
|
309
|
+
this.logger.debug(data, 'SimpleAppService');
|
|
291
310
|
Object.assign(data, isolationFilter);
|
|
292
|
-
this.reCalculateValue(data)
|
|
293
|
-
await this.validateData(appuser,data);
|
|
294
|
-
this.logger.debug(
|
|
295
|
-
this.logger.debug(data,'SimpleAppService')
|
|
311
|
+
this.reCalculateValue(data);
|
|
312
|
+
await this.validateData(appuser, data);
|
|
313
|
+
this.logger.debug('Create record', 'SimpleAppService');
|
|
314
|
+
this.logger.debug(data, 'SimpleAppService');
|
|
296
315
|
|
|
297
|
-
this.applyNestedDateTime(appuser,data,'create')
|
|
316
|
+
this.applyNestedDateTime(appuser, data, 'create');
|
|
298
317
|
const newdoc = new this.doc(data);
|
|
299
|
-
await this.identifyForeignKeys(appuser,data)
|
|
300
|
-
try{
|
|
301
|
-
result = await newdoc.save({session:dbsession})
|
|
302
|
-
appuser.addInsertedRecordId(this.documentName, result._id)
|
|
303
|
-
}catch(err){
|
|
304
|
-
this.logger.error(err)
|
|
305
|
-
throw new InternalServerErrorException(err)
|
|
318
|
+
await this.identifyForeignKeys(appuser, data);
|
|
319
|
+
try {
|
|
320
|
+
result = await newdoc.save({ session: dbsession });
|
|
321
|
+
appuser.addInsertedRecordId(this.documentName, result._id);
|
|
322
|
+
} catch (err) {
|
|
323
|
+
this.logger.error(err);
|
|
324
|
+
throw new InternalServerErrorException(err);
|
|
306
325
|
}
|
|
307
|
-
|
|
308
326
|
|
|
309
|
-
|
|
310
327
|
// this.doc.create(data)
|
|
311
328
|
// this.doc
|
|
312
329
|
|
|
313
330
|
// result = await newdoc.save()
|
|
314
|
-
await this.hook(appuser,HookType.afterCreate, result);
|
|
331
|
+
await this.hook(appuser, HookType.afterCreate, result);
|
|
315
332
|
|
|
316
333
|
return result as T;
|
|
317
334
|
}
|
|
318
|
-
|
|
319
335
|
|
|
320
|
-
applyNestedDateTime=(
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
336
|
+
applyNestedDateTime = (
|
|
337
|
+
appuser: UserContext,
|
|
338
|
+
data: any,
|
|
339
|
+
transtype: string,
|
|
340
|
+
) => {
|
|
341
|
+
const props = Object.getOwnPropertyNames(data);
|
|
342
|
+
for (let i = 0; i < props.length; i++) {
|
|
343
|
+
const key = props[i];
|
|
344
|
+
//need to apply nested
|
|
345
|
+
if (
|
|
346
|
+
Array.isArray(data[key]) &&
|
|
347
|
+
data[key].length > 0 &&
|
|
348
|
+
typeof data[key][0] == 'object'
|
|
349
|
+
) {
|
|
350
|
+
for (let j = 0; j < data[key].length; j++) {
|
|
351
|
+
this.applyNestedDateTime(appuser, data[key][j], transtype);
|
|
329
352
|
}
|
|
330
|
-
}else if(key == 'created'){
|
|
331
|
-
data['created'] =
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
353
|
+
} else if (key == 'created') {
|
|
354
|
+
data['created'] =
|
|
355
|
+
transtype == 'create' || !data['created']
|
|
356
|
+
? new Date().toISOString()
|
|
357
|
+
: data['created'];
|
|
358
|
+
} else if (key == 'createdBy') {
|
|
359
|
+
data['createdBy'] =
|
|
360
|
+
transtype == 'create' || !data['createdBy']
|
|
361
|
+
? appuser.getUid()
|
|
362
|
+
: data['createdBy'];
|
|
363
|
+
} else if (key == 'updated') {
|
|
364
|
+
data['updated'] = new Date().toISOString();
|
|
365
|
+
} else if (key == 'updatedBy') {
|
|
366
|
+
data['updatedBy'] = appuser.getUid();
|
|
367
|
+
}
|
|
339
368
|
}
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
hook = async (appuser:UserContext,type: string, data?: any) => {
|
|
369
|
+
};
|
|
370
|
+
hook = async (appuser: UserContext, type: string, data?: any) => {
|
|
343
371
|
return true;
|
|
344
372
|
};
|
|
345
|
-
async validateData(appuser:UserContext,data: T) {
|
|
373
|
+
async validateData(appuser: UserContext, data: T) {
|
|
346
374
|
const ajv = new Ajv({ allErrors: true, useDefaults: true });
|
|
347
375
|
addFormats(ajv);
|
|
348
376
|
addErrors(ajv);
|
|
@@ -351,19 +379,21 @@ export class SimpleAppService<T extends { _id?: string }> {
|
|
|
351
379
|
ajv.addFormat('text', /.*$/);
|
|
352
380
|
ajv.addFormat('html', /.*$/);
|
|
353
381
|
ajv.addFormat('documentno', /.*$/);
|
|
354
|
-
|
|
355
382
|
|
|
356
383
|
ajv.addKeyword({ keyword: 'x-foreignkey', schemaType: 'string' });
|
|
357
|
-
ajv.addKeyword({ keyword: 'x-simpleapp-config', schemaType: 'object' });
|
|
384
|
+
ajv.addKeyword({ keyword: 'x-simpleapp-config', schemaType: 'object' });
|
|
358
385
|
|
|
359
|
-
const issuccess = await this.hook(appuser,HookType.beforeValidation, data);
|
|
386
|
+
const issuccess = await this.hook(appuser, HookType.beforeValidation, data);
|
|
360
387
|
if (!issuccess) {
|
|
361
388
|
const errormsg: string[] = [];
|
|
362
389
|
for (let i = 0; i < this.errorlist.length; i++) {
|
|
363
390
|
errormsg.push(this.errorlist[i].message);
|
|
364
391
|
}
|
|
365
392
|
this.logger.log('run hook during validation');
|
|
366
|
-
throw new BadRequestException(
|
|
393
|
+
throw new BadRequestException(
|
|
394
|
+
'Before validation hook failed',
|
|
395
|
+
errormsg as HttpExceptionOptions,
|
|
396
|
+
);
|
|
367
397
|
}
|
|
368
398
|
|
|
369
399
|
let validate;
|
|
@@ -373,81 +403,87 @@ export class SimpleAppService<T extends { _id?: string }> {
|
|
|
373
403
|
this.logger.error('compile error', err);
|
|
374
404
|
throw new ForbiddenException(err.message);
|
|
375
405
|
}
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
406
|
+
const valid = validate(data);
|
|
407
|
+
if (!valid) {
|
|
408
|
+
this.logger.error(JSON.stringify(validate.errors), 'validate errors:');
|
|
409
|
+
throw new BadRequestException(
|
|
410
|
+
'Data validation failed',
|
|
411
|
+
validate.errors as HttpExceptionOptions,
|
|
412
|
+
);
|
|
413
|
+
}
|
|
414
|
+
await this.hook(appuser, HookType.afterValidation, data);
|
|
383
415
|
}
|
|
384
416
|
|
|
385
|
-
polishIsolationFilter = (filterIsolation:any,data:any={}) =>{
|
|
386
|
-
if(this.isolationtype == 'none'){
|
|
387
|
-
delete filterIsolation['branchId']
|
|
388
|
-
delete filterIsolation['orgId']
|
|
389
|
-
delete filterIsolation['tenantId']
|
|
417
|
+
polishIsolationFilter = (filterIsolation: any, data: any = {}) => {
|
|
418
|
+
if (this.isolationtype == 'none') {
|
|
419
|
+
delete filterIsolation['branchId'];
|
|
420
|
+
delete filterIsolation['orgId'];
|
|
421
|
+
delete filterIsolation['tenantId'];
|
|
390
422
|
}
|
|
391
|
-
if(this.isolationtype == 'tenant' && !this.strictIsolation){
|
|
423
|
+
if (this.isolationtype == 'tenant' && !this.strictIsolation) {
|
|
392
424
|
// delete filterIsolation['tenantId']
|
|
393
|
-
if(data['tenantId']){
|
|
394
|
-
filterIsolation['tenantId']=data['tenantId']
|
|
425
|
+
if (data['tenantId']) {
|
|
426
|
+
filterIsolation['tenantId'] = data['tenantId'];
|
|
395
427
|
}
|
|
396
|
-
delete filterIsolation['branchId']
|
|
397
|
-
delete filterIsolation['orgId']
|
|
428
|
+
delete filterIsolation['branchId'];
|
|
429
|
+
delete filterIsolation['orgId'];
|
|
398
430
|
}
|
|
399
|
-
if(this.isolationtype == 'org' && !this.strictIsolation){
|
|
400
|
-
// delete filterIsolation['tenantId']
|
|
401
|
-
if(data['tenantId']){
|
|
402
|
-
filterIsolation['tenantId']=data['tenantId']
|
|
431
|
+
if (this.isolationtype == 'org' && !this.strictIsolation) {
|
|
432
|
+
// delete filterIsolation['tenantId']
|
|
433
|
+
if (data['tenantId']) {
|
|
434
|
+
filterIsolation['tenantId'] = data['tenantId'];
|
|
403
435
|
}
|
|
404
|
-
if(data['orgId']){
|
|
405
|
-
filterIsolation['orgId']=data['orgId']
|
|
436
|
+
if (data['orgId']) {
|
|
437
|
+
filterIsolation['orgId'] = data['orgId'];
|
|
406
438
|
}
|
|
407
|
-
// delete filterIsolation['orgId']
|
|
408
|
-
delete filterIsolation['branchId']
|
|
439
|
+
// delete filterIsolation['orgId']
|
|
440
|
+
delete filterIsolation['branchId'];
|
|
409
441
|
}
|
|
410
|
-
return filterIsolation
|
|
411
|
-
}
|
|
412
|
-
async findIdThenDelete(appuser:UserContext,id: string): Promise<any> {
|
|
413
|
-
const deletedata = await this.findById(appuser,id);
|
|
414
|
-
if(!deletedata){
|
|
415
|
-
throw new NotFoundException(`${id} not found`,
|
|
442
|
+
return filterIsolation;
|
|
443
|
+
};
|
|
444
|
+
async findIdThenDelete(appuser: UserContext, id: string): Promise<any> {
|
|
445
|
+
const deletedata = await this.findById(appuser, id);
|
|
446
|
+
if (!deletedata) {
|
|
447
|
+
throw new NotFoundException(`${id} not found`, 'not found');
|
|
416
448
|
}
|
|
417
|
-
const dbsession = appuser.getDBSession()
|
|
418
|
-
if(!dbsession.inTransaction()){
|
|
419
|
-
dbsession.startTransaction()
|
|
449
|
+
const dbsession = appuser.getDBSession();
|
|
450
|
+
if (!dbsession.inTransaction()) {
|
|
451
|
+
dbsession.startTransaction();
|
|
420
452
|
}
|
|
421
453
|
|
|
422
|
-
let dependency
|
|
454
|
+
let dependency;
|
|
423
455
|
try {
|
|
424
|
-
await this.hook(appuser,HookType.beforeDelete, id);
|
|
425
|
-
this.logger.debug('delete record',this.documentName, id);
|
|
456
|
+
await this.hook(appuser, HookType.beforeDelete, id);
|
|
457
|
+
this.logger.debug('delete record', this.documentName, id);
|
|
426
458
|
dependency = await this.getRelatedRecords(id);
|
|
427
459
|
//console.log('dependency', dependency);
|
|
428
460
|
if (!dependency) {
|
|
429
461
|
let filterIsolation = this.getIsolationFilter(appuser);
|
|
430
|
-
this.polishIsolationFilter(filterIsolation)
|
|
431
|
-
|
|
432
|
-
filterIsolation['_id'] = id;
|
|
433
|
-
this.logger.debug('delete filter', filterIsolation);
|
|
434
|
-
const result = await this.doc.deleteOne(filterIsolation).session(dbsession);
|
|
462
|
+
this.polishIsolationFilter(filterIsolation);
|
|
435
463
|
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
464
|
+
filterIsolation['_id'] = id;
|
|
465
|
+
this.logger.debug('delete filter', filterIsolation);
|
|
466
|
+
const result = await this.doc
|
|
467
|
+
.deleteOne(filterIsolation)
|
|
468
|
+
.session(dbsession);
|
|
469
|
+
|
|
470
|
+
appuser.addUpdatedRecordId(this.documentName, id);
|
|
471
|
+
const deleteresult = { result: result, data: deletedata };
|
|
472
|
+
this.logger.debug(
|
|
473
|
+
deleteresult,
|
|
474
|
+
' delete result' + this.doc.collection.name,
|
|
475
|
+
);
|
|
439
476
|
// this.doc.findByIdAndDelete(id)
|
|
440
|
-
await this.hook(appuser,HookType.afterDelete, deleteresult);
|
|
441
|
-
|
|
477
|
+
await this.hook(appuser, HookType.afterDelete, deleteresult);
|
|
478
|
+
|
|
442
479
|
//this.doc.findByIdAndDelete(id);
|
|
443
480
|
return deleteresult;
|
|
444
481
|
} else {
|
|
445
482
|
//console.log("reject query",dependency)
|
|
446
|
-
|
|
447
|
-
throw new ForbiddenException('Foreignkey constraint',dependency)
|
|
483
|
+
|
|
484
|
+
throw new ForbiddenException('Foreignkey constraint', dependency);
|
|
448
485
|
}
|
|
449
486
|
} catch (err) {
|
|
450
|
-
|
|
451
487
|
throw new InternalServerErrorException(err);
|
|
452
488
|
//JSON.stringify(dependency),JSON.stringify(dependency)
|
|
453
489
|
}
|
|
@@ -457,38 +493,45 @@ export class SimpleAppService<T extends { _id?: string }> {
|
|
|
457
493
|
// this.doc.updateOne(data);
|
|
458
494
|
// };
|
|
459
495
|
|
|
460
|
-
findIdThenUpdate = async (
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
496
|
+
findIdThenUpdate = async (
|
|
497
|
+
appuser: UserContext,
|
|
498
|
+
id: string,
|
|
499
|
+
data: T,
|
|
500
|
+
session: mongo.ClientSession = undefined,
|
|
501
|
+
) => {
|
|
502
|
+
const existingdata = await this.findById(appuser, id);
|
|
503
|
+
if (!existingdata) {
|
|
504
|
+
throw new NotFoundException(`${id} not found`, 'not found');
|
|
464
505
|
}
|
|
465
|
-
await this.hook(appuser,HookType.beforeUpdate, data);
|
|
506
|
+
await this.hook(appuser, HookType.beforeUpdate, data);
|
|
466
507
|
|
|
467
|
-
const dbsession = appuser.getDBSession()
|
|
468
|
-
if(!dbsession.inTransaction()){
|
|
469
|
-
dbsession.startTransaction()
|
|
508
|
+
const dbsession = appuser.getDBSession();
|
|
509
|
+
if (!dbsession.inTransaction()) {
|
|
510
|
+
dbsession.startTransaction();
|
|
470
511
|
}
|
|
471
512
|
|
|
472
513
|
// try {
|
|
473
514
|
Object.assign(data, appuser.getUpdateFilter());
|
|
474
515
|
Object.assign(existingdata, data);
|
|
475
|
-
delete data['_id']
|
|
516
|
+
delete data['_id'];
|
|
476
517
|
|
|
477
|
-
this.reCalculateValue(data)
|
|
518
|
+
this.reCalculateValue(data);
|
|
478
519
|
// existingdata['_id']=''
|
|
479
520
|
// console.log("newdata",data)
|
|
480
|
-
await this.validateData(appuser,data);
|
|
481
|
-
|
|
482
|
-
const isolationFilter =
|
|
483
|
-
this.polishIsolationFilter(isolationFilter)
|
|
521
|
+
await this.validateData(appuser, data);
|
|
522
|
+
|
|
523
|
+
const isolationFilter = { ...this.getIsolationFilter(appuser) };
|
|
524
|
+
this.polishIsolationFilter(isolationFilter);
|
|
484
525
|
|
|
485
526
|
isolationFilter['_id'] = id;
|
|
486
|
-
this.applyNestedDateTime(appuser,data,'update')
|
|
487
|
-
try{
|
|
488
|
-
const result = await this.doc
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
527
|
+
this.applyNestedDateTime(appuser, data, 'update');
|
|
528
|
+
try {
|
|
529
|
+
const result = await this.doc
|
|
530
|
+
.findOneAndUpdate(isolationFilter, data)
|
|
531
|
+
.session(dbsession);
|
|
532
|
+
appuser.addUpdatedRecordId(this.documentName, data._id);
|
|
533
|
+
await this.hook(appuser, HookType.afterUpdate, data);
|
|
534
|
+
return result;
|
|
492
535
|
} catch (err) {
|
|
493
536
|
throw new InternalServerErrorException(err.message);
|
|
494
537
|
}
|
|
@@ -496,20 +539,19 @@ export class SimpleAppService<T extends { _id?: string }> {
|
|
|
496
539
|
|
|
497
540
|
//find what foreign key constraint
|
|
498
541
|
async getRelatedRecords(id: string) {
|
|
499
|
-
this.logger.debug(
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
throw new InternalServerErrorException("foreignkeys object undetected")
|
|
542
|
+
this.logger.debug('get foreignkey for delete:', id);
|
|
543
|
+
|
|
544
|
+
if (foreignkeys === undefined) {
|
|
545
|
+
this.logger.error('foreignkeys object undetected');
|
|
546
|
+
throw new InternalServerErrorException('foreignkeys object undetected');
|
|
505
547
|
}
|
|
506
|
-
|
|
548
|
+
|
|
507
549
|
const foreignkeysettings = foreignkeys[this.documentName];
|
|
508
|
-
if(!foreignkeysettings){
|
|
509
|
-
return null
|
|
550
|
+
if (!foreignkeysettings) {
|
|
551
|
+
return null;
|
|
510
552
|
}
|
|
511
553
|
const propkeys = Object.getOwnPropertyNames(foreignkeysettings);
|
|
512
|
-
|
|
554
|
+
|
|
513
555
|
if (propkeys.length > 0) {
|
|
514
556
|
//console.log('Have properties');
|
|
515
557
|
for (let i = 0; i < propkeys.length; i++) {
|
|
@@ -519,14 +561,13 @@ export class SimpleAppService<T extends { _id?: string }> {
|
|
|
519
561
|
const collection = this.doc.db.collection(collectionname);
|
|
520
562
|
//single schema may have multiple foreign key link here, loop all
|
|
521
563
|
for (let j = 0; j < fobjs.length; j++) {
|
|
522
|
-
const fkey = fobjs[j]
|
|
523
|
-
let filter = {}
|
|
564
|
+
const fkey = fobjs[j];
|
|
565
|
+
let filter = {};
|
|
524
566
|
filter[fkey] = id;
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
const result = await collection.findOne(filter);
|
|
567
|
+
|
|
568
|
+
const result = await collection.findOne(filter);
|
|
528
569
|
if (result) {
|
|
529
|
-
this.logger.error(result,
|
|
570
|
+
this.logger.error(result, 'related result found');
|
|
530
571
|
return result;
|
|
531
572
|
}
|
|
532
573
|
}
|
|
@@ -547,109 +588,130 @@ export class SimpleAppService<T extends { _id?: string }> {
|
|
|
547
588
|
* @param docstatus
|
|
548
589
|
* @returns Promise
|
|
549
590
|
*/
|
|
550
|
-
async setDocumentStatus(appuser:UserContext,id: string, docstatus: string) {
|
|
591
|
+
async setDocumentStatus(appuser: UserContext, id: string, docstatus: string) {
|
|
551
592
|
const partialdata: T = {} as T;
|
|
552
593
|
partialdata['documentStatus'] = docstatus;
|
|
553
|
-
return this.findIdThenUpdate(appuser,id, partialdata);
|
|
594
|
+
return this.findIdThenUpdate(appuser, id, partialdata);
|
|
554
595
|
}
|
|
555
596
|
|
|
556
|
-
|
|
557
|
-
this.
|
|
558
|
-
const result = await this.docnogenerator.generateNextNumberFromDocument(appuser,this.documentType,data)
|
|
559
|
-
this.logger.debug(result,"genNewDocNo")
|
|
560
|
-
data[this.documentIdentityCode]=result
|
|
597
|
+
startWorkflow(appuser:UserContext,processName:string,workflowData:any){
|
|
598
|
+
return this.eventEmitter.emit('workflow.start',appuser,'suspendcustomer',workflowData)
|
|
561
599
|
}
|
|
562
600
|
|
|
601
|
+
async genNewDocNo(appuser: UserContext, data: T) {
|
|
602
|
+
this.logger.debug('genNewDocNo');
|
|
603
|
+
const result = await this.docnogenerator.generateNextNumberFromDocument(
|
|
604
|
+
appuser,
|
|
605
|
+
this.documentType,
|
|
606
|
+
data,
|
|
607
|
+
);
|
|
608
|
+
this.logger.debug(result, 'genNewDocNo');
|
|
609
|
+
data[this.documentIdentityCode] = result;
|
|
610
|
+
}
|
|
563
611
|
|
|
564
|
-
async identifyForeignKeys(appuser:UserContext,data:T){
|
|
565
|
-
|
|
612
|
+
async identifyForeignKeys(appuser: UserContext, data: T) {
|
|
613
|
+
/**
|
|
566
614
|
* 1. looping schemas identify what foreign key exists
|
|
567
|
-
* 2. loop through record obtain all foreign key value
|
|
615
|
+
* 2. loop through record obtain all foreign key value
|
|
568
616
|
* 3. get all unique key value in array {product:['xxxx','yyyy'],customer:['aaa']}
|
|
569
617
|
*/
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
618
|
+
const schema = this.jsonschema;
|
|
619
|
+
|
|
620
|
+
//get all foreign keys catalogue
|
|
621
|
+
const collections = Object.getOwnPropertyNames(this.foreignkeys);
|
|
622
|
+
|
|
623
|
+
//obtain exists data in according foreign key
|
|
624
|
+
const pipelines: PipelineStage[] = [{ $match: { _id: false } }]; //exclude data from current collection
|
|
625
|
+
const vdata = data; //['_doc']
|
|
626
|
+
const keystore = {};
|
|
627
|
+
collections.forEach((collectionname) => {
|
|
628
|
+
const fks: string[] = this.foreignkeys[collectionname];
|
|
629
|
+
let results: string[] = [];
|
|
630
|
+
fks.forEach((fieldpath) => {
|
|
583
631
|
//console.log("fieldpath:",fieldpath,"vdata",data,vdata)
|
|
584
|
-
|
|
632
|
+
const tmp = jsonpath
|
|
633
|
+
.query(vdata, fieldpath)
|
|
634
|
+
.filter((item: string) => item != '');
|
|
585
635
|
// console.log("tmp",tmp)
|
|
586
|
-
|
|
587
|
-
results = results.concat(tmp)
|
|
588
|
-
})
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
if(results.length>0){
|
|
593
|
-
if(results.length>1){
|
|
594
|
-
results = uniq<string>(results)
|
|
595
|
-
}
|
|
596
|
-
|
|
597
|
-
keystore[collectionname]= results
|
|
598
|
-
//console.log("keystorekeystore",keystore)
|
|
599
|
-
let addfield={$addFields:{collection:collectionname}}
|
|
600
|
-
|
|
601
|
-
const stagefilter:PipelineStage = {
|
|
602
|
-
$unionWith: {coll:collectionname,pipeline: [{ $match: { _id: {$in:results}} },addfield,{$project:{collection:1}}, ]}
|
|
603
|
-
}
|
|
604
|
-
pipelines.push(stagefilter)
|
|
605
|
-
}
|
|
606
|
-
})
|
|
607
|
-
this.logger.log(pipelines,'identifyForeignKeys pipelines')
|
|
608
|
-
// this.doc.db.collection(collectionname);
|
|
609
|
-
const unionresult = await this.doc.aggregate(pipelines)
|
|
610
|
-
|
|
611
|
-
if(!unionresult){
|
|
612
|
-
this.logger.error("foreign key control failed ",'identifyForeignKeys')
|
|
613
|
-
throw new InternalServerErrorException("Foreignkey check execution error",pipelines as HttpExceptionOptions)
|
|
614
|
-
}else{
|
|
615
|
-
let searchresult:any = {}
|
|
616
|
-
unionresult.forEach(item=>{
|
|
617
|
-
if(searchresult[item.collection]){
|
|
618
|
-
searchresult[item.collection].push(item._id)
|
|
619
|
-
}else{
|
|
620
|
-
searchresult[item.collection] = [item._id]
|
|
621
|
-
}
|
|
622
|
-
})
|
|
623
|
-
this.logger.log(unionresult,this.documentType+" search Result")
|
|
624
|
-
|
|
625
|
-
//search is it all foreign key exists in db
|
|
626
|
-
for(let i=0; i<collections.length; i++){
|
|
627
|
-
const collectionname = collections[i]
|
|
628
|
-
const keys:string[] = keystore[collectionname]
|
|
629
|
-
if(!keys){
|
|
630
|
-
continue
|
|
631
|
-
}
|
|
632
|
-
for(let k=0;k<keys.length; k++){
|
|
633
|
-
const key = keys[k]
|
|
634
|
-
if(searchresult[collectionname] && searchresult[collectionname].includes(key)){
|
|
635
|
-
this.logger.debug(`foreignkey ${collectionname}->${key} exists`)
|
|
636
|
-
}
|
|
637
|
-
else if(appuser.searchInsertedRecordId(collectionname,key)){
|
|
638
|
-
this.logger.debug(`foreignkey ${collectionname} exists in user context which not yet commited`)
|
|
639
|
-
}
|
|
640
|
-
else{
|
|
641
|
-
this.logger.warn(`${this.documentType}: Foreignkey ${key} at collection ${collectionname} does not exist`,'identifyForeignKeys')
|
|
642
|
-
this.logger.log(appuser.getModifieds,"appuser.getModifieds")
|
|
643
|
-
const errordata = {key:key,collection:collectionname}
|
|
644
|
-
throw new BadRequestException(`${this.documentType}: Foreignkey ${key} at collection ${collectionname} does not exist`,JSON.stringify(errordata))
|
|
645
|
-
|
|
646
|
-
}
|
|
647
|
-
}
|
|
648
|
-
|
|
649
|
-
}
|
|
650
|
-
|
|
651
|
-
}
|
|
652
|
-
}
|
|
653
636
|
|
|
637
|
+
results = results.concat(tmp);
|
|
638
|
+
});
|
|
639
|
+
|
|
640
|
+
if (results.length > 0) {
|
|
641
|
+
if (results.length > 1) {
|
|
642
|
+
results = uniq<string>(results);
|
|
643
|
+
}
|
|
654
644
|
|
|
645
|
+
keystore[collectionname] = results;
|
|
646
|
+
//console.log("keystorekeystore",keystore)
|
|
647
|
+
let addfield = { $addFields: { collection: collectionname } };
|
|
648
|
+
|
|
649
|
+
const stagefilter: PipelineStage = {
|
|
650
|
+
$unionWith: {
|
|
651
|
+
coll: collectionname,
|
|
652
|
+
pipeline: [
|
|
653
|
+
{ $match: { _id: { $in: results } } },
|
|
654
|
+
addfield,
|
|
655
|
+
{ $project: { collection: 1 } },
|
|
656
|
+
],
|
|
657
|
+
},
|
|
658
|
+
};
|
|
659
|
+
pipelines.push(stagefilter);
|
|
660
|
+
}
|
|
661
|
+
});
|
|
662
|
+
this.logger.log(pipelines, 'identifyForeignKeys pipelines');
|
|
663
|
+
// this.doc.db.collection(collectionname);
|
|
664
|
+
const unionresult = await this.doc.aggregate(pipelines);
|
|
665
|
+
|
|
666
|
+
if (!unionresult) {
|
|
667
|
+
this.logger.error('foreign key control failed ', 'identifyForeignKeys');
|
|
668
|
+
throw new InternalServerErrorException(
|
|
669
|
+
'Foreignkey check execution error',
|
|
670
|
+
pipelines as HttpExceptionOptions,
|
|
671
|
+
);
|
|
672
|
+
} else {
|
|
673
|
+
let searchresult: any = {};
|
|
674
|
+
unionresult.forEach((item) => {
|
|
675
|
+
if (searchresult[item.collection]) {
|
|
676
|
+
searchresult[item.collection].push(item._id);
|
|
677
|
+
} else {
|
|
678
|
+
searchresult[item.collection] = [item._id];
|
|
679
|
+
}
|
|
680
|
+
});
|
|
681
|
+
this.logger.log(unionresult, this.documentType + ' search Result');
|
|
682
|
+
|
|
683
|
+
//search is it all foreign key exists in db
|
|
684
|
+
for (let i = 0; i < collections.length; i++) {
|
|
685
|
+
const collectionname = collections[i];
|
|
686
|
+
const keys: string[] = keystore[collectionname];
|
|
687
|
+
if (!keys) {
|
|
688
|
+
continue;
|
|
689
|
+
}
|
|
690
|
+
for (let k = 0; k < keys.length; k++) {
|
|
691
|
+
const key = keys[k];
|
|
692
|
+
if (
|
|
693
|
+
searchresult[collectionname] &&
|
|
694
|
+
searchresult[collectionname].includes(key)
|
|
695
|
+
) {
|
|
696
|
+
this.logger.debug(`foreignkey ${collectionname}->${key} exists`);
|
|
697
|
+
} else if (appuser.searchInsertedRecordId(collectionname, key)) {
|
|
698
|
+
this.logger.debug(
|
|
699
|
+
`foreignkey ${collectionname} exists in user context which not yet commited`,
|
|
700
|
+
);
|
|
701
|
+
} else {
|
|
702
|
+
this.logger.warn(
|
|
703
|
+
`${this.documentType}: Foreignkey ${key} at collection ${collectionname} does not exist`,
|
|
704
|
+
'identifyForeignKeys',
|
|
705
|
+
);
|
|
706
|
+
this.logger.log(appuser.getModifieds, 'appuser.getModifieds');
|
|
707
|
+
const errordata = { key: key, collection: collectionname };
|
|
708
|
+
throw new BadRequestException(
|
|
709
|
+
`${this.documentType}: Foreignkey ${key} at collection ${collectionname} does not exist`,
|
|
710
|
+
JSON.stringify(errordata),
|
|
711
|
+
);
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
}
|
|
715
|
+
}
|
|
716
|
+
}
|
|
655
717
|
}
|