@solidstarters/solid-core 1.2.1 → 1.2.3
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/.env +114 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +17 -0
- package/dist/cli.js.map +1 -0
- package/dist/decorators/active-user.decorator.d.ts +1 -1
- package/dist/dtos/basic-filters.dto.d.ts +1 -0
- package/dist/dtos/basic-filters.dto.d.ts.map +1 -1
- package/dist/dtos/basic-filters.dto.js +6 -1
- package/dist/dtos/basic-filters.dto.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/services/crud.service.js +5 -9
- package/dist/services/crud.service.js.map +1 -1
- package/dist/solid-core-cli-db.module.d.ts +3 -0
- package/dist/solid-core-cli-db.module.d.ts.map +1 -0
- package/dist/solid-core-cli-db.module.js +44 -0
- package/dist/solid-core-cli-db.module.js.map +1 -0
- package/dist/solid-core-cli.module.d.ts +3 -0
- package/dist/solid-core-cli.module.d.ts.map +1 -0
- package/dist/solid-core-cli.module.js +45 -0
- package/dist/solid-core-cli.module.js.map +1 -0
- package/dist/solid-core.module.d.ts.map +1 -1
- package/dist/solid-core.module.js +7 -5
- package/dist/solid-core.module.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/winston.logger.d.ts +19 -0
- package/dist/winston.logger.d.ts.map +1 -0
- package/dist/winston.logger.js +106 -0
- package/dist/winston.logger.js.map +1 -0
- package/logs/application.log +1855 -0
- package/logs/error.log +0 -0
- package/package.json +44 -22
- package/rebuild.sh +6 -0
- package/solidstarters-solid-core-1.2.5.tgz +0 -0
- package/src/cli.ts +34 -0
- package/src/dtos/basic-filters.dto.ts +5 -1
- package/src/index.ts +3 -1
- package/src/services/crud.service.ts +28 -28
- package/src/solid-core-cli-db.module.ts +62 -0
- package/src/solid-core-cli.module.ts +40 -0
- package/src/solid-core.module.ts +7 -5
- package/src/winston.logger.ts +70 -0
package/logs/error.log
ADDED
|
File without changes
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@solidstarters/solid-core",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.3",
|
|
4
4
|
"description": "This module is a NestJS module containing all the required core providers required by a Solid application",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -8,6 +8,9 @@
|
|
|
8
8
|
"publishConfig": {
|
|
9
9
|
"access": "public"
|
|
10
10
|
},
|
|
11
|
+
"bin": {
|
|
12
|
+
"solidCore": "dist/cli.js"
|
|
13
|
+
},
|
|
11
14
|
"scripts": {
|
|
12
15
|
"build": "nest build",
|
|
13
16
|
"format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
|
|
@@ -30,20 +33,6 @@
|
|
|
30
33
|
"@aws-sdk/client-s3": "^3.637.0",
|
|
31
34
|
"@elasticemail/elasticemail-client": "^4.0.23",
|
|
32
35
|
"@hapi/joi": "^17.1.1",
|
|
33
|
-
"@nestjs/axios": "^3.0.2",
|
|
34
|
-
"@nestjs/cache-manager": "^2.2.2",
|
|
35
|
-
"@nestjs/common": "^10.0.0",
|
|
36
|
-
"@nestjs/core": "^10.0.0",
|
|
37
|
-
"@nestjs/event-emitter": "^2.0.4",
|
|
38
|
-
"@nestjs/jwt": "^10.2.0",
|
|
39
|
-
"@nestjs/mapped-types": "^2.0.4",
|
|
40
|
-
"@nestjs/mongoose": "^10.0.10",
|
|
41
|
-
"@nestjs/passport": "^10.0.3",
|
|
42
|
-
"@nestjs/platform-express": "^10.0.0",
|
|
43
|
-
"@nestjs/serve-static": "^4.0.2",
|
|
44
|
-
"@nestjs/swagger": "^7.2.0",
|
|
45
|
-
"@nestjs/typeorm": "^10.0.1",
|
|
46
|
-
"@types/luxon": "^3.4.2",
|
|
47
36
|
"amqplib": "^0.10.4",
|
|
48
37
|
"axios": "^1.7.0",
|
|
49
38
|
"bcrypt": "^5.1.1",
|
|
@@ -57,8 +46,6 @@
|
|
|
57
46
|
"luxon": "^3.4.4",
|
|
58
47
|
"mailgen": "^2.0.28",
|
|
59
48
|
"mongoose": "^8.7.0",
|
|
60
|
-
"nest-commander": "^3.12.5",
|
|
61
|
-
"nest-winston": "^1.9.7",
|
|
62
49
|
"nodemailer": "^6.9.13",
|
|
63
50
|
"passport": "^0.7.0",
|
|
64
51
|
"passport-google-oauth2": "^0.2.0",
|
|
@@ -70,22 +57,53 @@
|
|
|
70
57
|
"reflect-metadata": "^0.1.13",
|
|
71
58
|
"rxjs": "^7.8.1",
|
|
72
59
|
"swagger-ui-express": "^5.0.0",
|
|
73
|
-
"typeorm": "^0.3.20",
|
|
74
|
-
"typeorm-naming-strategies": "^4.1.0",
|
|
75
60
|
"uuid": "^9.0.1",
|
|
76
|
-
"winston": "^3.17.0",
|
|
77
61
|
"xlsx": "^0.18.5"
|
|
78
62
|
},
|
|
79
63
|
"peerDependencies": {
|
|
80
|
-
"@nestjs/
|
|
64
|
+
"@nestjs/axios": "^3.0.2",
|
|
65
|
+
"@nestjs/cache-manager": "^2.2.2",
|
|
66
|
+
"@nestjs/common": "^10.0.0",
|
|
67
|
+
"@nestjs/config": "^3.2.0",
|
|
68
|
+
"@nestjs/core": "^10.0.0",
|
|
69
|
+
"@nestjs/event-emitter": "^2.0.4",
|
|
70
|
+
"@nestjs/jwt": "^10.2.0",
|
|
71
|
+
"@nestjs/mapped-types": "^2.0.4",
|
|
72
|
+
"@nestjs/mongoose": "^10.0.10",
|
|
73
|
+
"@nestjs/passport": "^10.0.3",
|
|
74
|
+
"@nestjs/platform-express": "^10.0.0",
|
|
75
|
+
"@nestjs/serve-static": "^4.0.2",
|
|
76
|
+
"@nestjs/swagger": "^7.2.0",
|
|
77
|
+
"@nestjs/typeorm": "^10.0.1",
|
|
78
|
+
"nest-commander": "^3.12.5",
|
|
79
|
+
"nest-winston": "^1.9.7",
|
|
80
|
+
"typeorm": "^0.3.20",
|
|
81
|
+
"typeorm-naming-strategies": "^4.1.0",
|
|
82
|
+
"winston": "^3.17.0"
|
|
81
83
|
},
|
|
82
84
|
"devDependencies": {
|
|
85
|
+
"@nestjs/axios": "^3.0.2",
|
|
86
|
+
"@nestjs/cache-manager": "^2.2.2",
|
|
83
87
|
"@nestjs/cli": "^10.0.0",
|
|
88
|
+
"@nestjs/common": "^10.0.0",
|
|
84
89
|
"@nestjs/config": "^3.2.0",
|
|
90
|
+
"@nestjs/core": "^10.0.0",
|
|
91
|
+
"@nestjs/event-emitter": "^2.0.4",
|
|
92
|
+
"@nestjs/jwt": "^10.2.0",
|
|
93
|
+
"@nestjs/mapped-types": "^2.0.4",
|
|
94
|
+
"@nestjs/mongoose": "^10.0.10",
|
|
95
|
+
"@nestjs/passport": "^10.0.3",
|
|
96
|
+
"@nestjs/platform-express": "^10.0.0",
|
|
97
|
+
"@nestjs/serve-static": "^4.0.2",
|
|
98
|
+
"@nestjs/swagger": "^7.2.0",
|
|
85
99
|
"@nestjs/testing": "^10.0.0",
|
|
100
|
+
"@nestjs/typeorm": "^10.0.1",
|
|
101
|
+
"nest-commander": "^3.12.5",
|
|
102
|
+
"nest-winston": "^1.9.7",
|
|
86
103
|
"@types/express": "^4.17.17",
|
|
87
104
|
"@types/hapi__joi": "^17.1.12",
|
|
88
105
|
"@types/jest": "^29.5.2",
|
|
106
|
+
"@types/luxon": "^3.4.2",
|
|
89
107
|
"@types/mongoose": "^5.11.97",
|
|
90
108
|
"@types/multer": "^1.4.11",
|
|
91
109
|
"@types/node": "^20.3.1",
|
|
@@ -110,7 +128,11 @@
|
|
|
110
128
|
"ts-loader": "^9.4.3",
|
|
111
129
|
"ts-node": "^10.9.1",
|
|
112
130
|
"tsconfig-paths": "^4.2.0",
|
|
113
|
-
"
|
|
131
|
+
"typeorm": "^0.3.20",
|
|
132
|
+
"typeorm-naming-strategies": "^4.1.0",
|
|
133
|
+
"typescript": "^5.1.3",
|
|
134
|
+
"winston": "^3.17.0",
|
|
135
|
+
"@solidstarters/solid-code-builder": "^1.0.2"
|
|
114
136
|
},
|
|
115
137
|
"jest": {
|
|
116
138
|
"moduleFileExtensions": [
|
package/rebuild.sh
ADDED
|
Binary file
|
package/src/cli.ts
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { CommandFactory } from "nest-commander";
|
|
4
|
+
import { SolidCoreCliModule } from "./solid-core-cli.module";
|
|
5
|
+
|
|
6
|
+
async function bootstrap() {
|
|
7
|
+
|
|
8
|
+
// const app = await NestFactory.create(appModule);
|
|
9
|
+
|
|
10
|
+
// Create an instance of the application, capture the application context so we can inject it into a service in itself.
|
|
11
|
+
// @ts-ignore
|
|
12
|
+
const app = await CommandFactory.createWithoutRunning(SolidCoreCliModule, ['debug', 'error', 'fatal', 'log', 'verbose', 'warn']);
|
|
13
|
+
// const app = await CommandFactory.createWithoutRunning(AppModule, ['debug', 'error', 'fatal', 'log', 'verbose', 'warn']);
|
|
14
|
+
// const app = await CommandFactory.createWithoutRunning(AppModule, ['error', 'fatal']);
|
|
15
|
+
|
|
16
|
+
// Now run the command factory.
|
|
17
|
+
try {
|
|
18
|
+
await CommandFactory.runApplication(app);
|
|
19
|
+
}
|
|
20
|
+
catch (e) {
|
|
21
|
+
process.exit(1);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// Exit explicitly, make sure that any commands you have created and are using Promises, you do not keep them orphan/dangling.
|
|
25
|
+
process.exit(0);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// https://github.com/typeorm/typeorm/issues/8583
|
|
29
|
+
// const types = require('pg').types;
|
|
30
|
+
// types.setTypeParser(types.builtins.INT8, function(val) {
|
|
31
|
+
// return parseInt(val)
|
|
32
|
+
// });
|
|
33
|
+
|
|
34
|
+
bootstrap();
|
|
@@ -18,7 +18,7 @@ export class BasicFilterDto extends PaginationQueryDto {
|
|
|
18
18
|
@ApiProperty({ description: "groupBy" })
|
|
19
19
|
readonly groupBy?: string[];
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
|
|
22
22
|
@IsOptional()
|
|
23
23
|
@ApiProperty({ description: "populate" })
|
|
24
24
|
readonly populate?: string[];
|
|
@@ -44,4 +44,8 @@ export class BasicFilterDto extends PaginationQueryDto {
|
|
|
44
44
|
@IsOptional()
|
|
45
45
|
@ApiProperty({ description: "populateGroup" })
|
|
46
46
|
readonly populateGroup?: boolean;
|
|
47
|
+
|
|
48
|
+
@IsOptional()
|
|
49
|
+
@ApiProperty({ description: "groupFilter" })
|
|
50
|
+
groupFilter?: BasicFilterDto
|
|
47
51
|
}
|
package/src/index.ts
CHANGED
|
@@ -163,7 +163,7 @@ export class CRUDService<T> { //Add two generic value i.e Person,CreatePersonDto
|
|
|
163
163
|
|
|
164
164
|
//TODO: Will the updates be partial i.e PATCH or full i.e PUT
|
|
165
165
|
async update(id: number, updateDto: any, files: Express.Multer.File[] = [], isPartialUpdate: boolean = false): Promise<T> {
|
|
166
|
-
|
|
166
|
+
if (!id) {
|
|
167
167
|
throw new Error('Id is required for update');
|
|
168
168
|
}
|
|
169
169
|
const entity = await this.repo.findOne({
|
|
@@ -239,7 +239,7 @@ export class CRUDService<T> { //Add two generic value i.e Person,CreatePersonDto
|
|
|
239
239
|
}
|
|
240
240
|
}
|
|
241
241
|
|
|
242
|
-
private fieldCrudManager(fieldMetadata: FieldMetadata, entityManager: EntityManager, isPartialUpdate: boolean=false): FieldCrudManager {
|
|
242
|
+
private fieldCrudManager(fieldMetadata: FieldMetadata, entityManager: EntityManager, isPartialUpdate: boolean = false): FieldCrudManager {
|
|
243
243
|
const commonOptions = { required: fieldMetadata.required && !isPartialUpdate, fieldName: fieldMetadata.name };
|
|
244
244
|
switch (fieldMetadata.type) {
|
|
245
245
|
case SolidFieldType.shortText: {
|
|
@@ -262,11 +262,11 @@ export class CRUDService<T> { //Add two generic value i.e Person,CreatePersonDto
|
|
|
262
262
|
const options = { ...commonOptions };
|
|
263
263
|
return new JsonFieldCrudManager(options);
|
|
264
264
|
}
|
|
265
|
-
case SolidFieldType.int:{
|
|
265
|
+
case SolidFieldType.int: {
|
|
266
266
|
const options = { ...commonOptions, min: fieldMetadata.min, max: fieldMetadata.max };
|
|
267
267
|
return new IntFieldCrudManager(options);
|
|
268
268
|
}
|
|
269
|
-
case SolidFieldType.decimal:{
|
|
269
|
+
case SolidFieldType.decimal: {
|
|
270
270
|
const options = { ...commonOptions, min: fieldMetadata.min, max: fieldMetadata.max };
|
|
271
271
|
return new DecimalFieldCrudManager(options);
|
|
272
272
|
}
|
|
@@ -274,21 +274,21 @@ export class CRUDService<T> { //Add two generic value i.e Person,CreatePersonDto
|
|
|
274
274
|
const options = { ...commonOptions, min: fieldMetadata.min, max: fieldMetadata.max };
|
|
275
275
|
return new BigIntFieldCrudManager(options);
|
|
276
276
|
}
|
|
277
|
-
case SolidFieldType.email:{
|
|
278
|
-
const options = { ...commonOptions, max: fieldMetadata.max?? MAX_EMAIL_LENGTH, regexPattern: fieldMetadata.regexPattern };
|
|
277
|
+
case SolidFieldType.email: {
|
|
278
|
+
const options = { ...commonOptions, max: fieldMetadata.max ?? MAX_EMAIL_LENGTH, regexPattern: fieldMetadata.regexPattern };
|
|
279
279
|
return new EmailFieldCrudManager(options);
|
|
280
280
|
}
|
|
281
281
|
case SolidFieldType.date:
|
|
282
|
-
case SolidFieldType.datetime:{
|
|
282
|
+
case SolidFieldType.datetime: {
|
|
283
283
|
const options = { ...commonOptions };
|
|
284
284
|
return new DateFieldCrudManager(options);
|
|
285
285
|
}
|
|
286
|
-
case SolidFieldType.password:{
|
|
286
|
+
case SolidFieldType.password: {
|
|
287
287
|
const options = { ...commonOptions, min: fieldMetadata.min, max: fieldMetadata.max, regexPattern: fieldMetadata.regexPattern };
|
|
288
288
|
return new PasswordFieldCrudManager(options);
|
|
289
289
|
}
|
|
290
290
|
case SolidFieldType.mediaSingle:
|
|
291
|
-
case SolidFieldType.mediaMultiple:{
|
|
291
|
+
case SolidFieldType.mediaMultiple: {
|
|
292
292
|
// update will need to delete the existing media and save the new media
|
|
293
293
|
// case 'mediaSingle':
|
|
294
294
|
// Use the EntityController to extract uploaded content & pass to the entity service.
|
|
@@ -357,13 +357,13 @@ export class CRUDService<T> { //Add two generic value i.e Person,CreatePersonDto
|
|
|
357
357
|
}
|
|
358
358
|
}
|
|
359
359
|
else throw new Error('Relation type not supported in crud service');
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
360
|
+
// return (fieldMetadata.relationType === 'many-to-one') ? new ManyToOneRelationFieldCrudManager(fieldMetadata, entityManager) : new ManyToManyRelationFieldCrudManager(fieldMetadata, entityManager); //FIXME many-to-many pending
|
|
361
|
+
// ManyToOne -> fieldId. The value is saved as is. No transformation is required
|
|
362
|
+
// OneToMany -> fieldIds. Get the value of the oneToMany field side. No transformation is required (While saving special provision to be made)
|
|
363
|
+
// ManyToMany
|
|
364
|
+
// break;
|
|
365
365
|
}
|
|
366
|
-
case SolidFieldType.selectionStatic:{
|
|
366
|
+
case SolidFieldType.selectionStatic: {
|
|
367
367
|
|
|
368
368
|
// Validation against the selectionStatic values. No transformation is required
|
|
369
369
|
// If the value is not in the selectionStatic values, then throw
|
|
@@ -380,12 +380,12 @@ export class CRUDService<T> { //Add two generic value i.e Person,CreatePersonDto
|
|
|
380
380
|
const options = { ...commonOptions, selectionDynamicProvider: fieldMetadata.selectionDynamicProvider, selectionDynamicProviderCtxt: fieldMetadata.selectionDynamicProviderCtxt, selectionValueType: fieldMetadata.selectionValueType as SelectionValueType, discoveryService: this.discoveryService };
|
|
381
381
|
return new SelectionDynamicFieldCrudManager(options);
|
|
382
382
|
}
|
|
383
|
-
case SolidFieldType.uuid:{
|
|
383
|
+
case SolidFieldType.uuid: {
|
|
384
384
|
const options = { ...commonOptions };
|
|
385
385
|
// If no value is provided, then generate a uuid. Add to the dto
|
|
386
386
|
return new UUIDFieldCrudManager(options);
|
|
387
387
|
}
|
|
388
|
-
case SolidFieldType.computed:{
|
|
388
|
+
case SolidFieldType.computed: {
|
|
389
389
|
|
|
390
390
|
// The value will be computed by the computed provider
|
|
391
391
|
// Invoke the appropriate computed provider, get the value and add to the dto
|
|
@@ -401,7 +401,7 @@ export class CRUDService<T> { //Add two generic value i.e Person,CreatePersonDto
|
|
|
401
401
|
async find(basicFilterDto: BasicFilterDto) {
|
|
402
402
|
const alias = 'entity';
|
|
403
403
|
// Extract the required keys from the input query
|
|
404
|
-
let { limit, offset, populateMedia, populateGroup } = basicFilterDto;
|
|
404
|
+
let { limit, offset, populateMedia, populateGroup,groupFilter } = basicFilterDto;
|
|
405
405
|
|
|
406
406
|
// Create above query on pincode table using query builder
|
|
407
407
|
var qb: SelectQueryBuilder<T> = this.repo.createQueryBuilder(alias)
|
|
@@ -409,7 +409,7 @@ export class CRUDService<T> { //Add two generic value i.e Person,CreatePersonDto
|
|
|
409
409
|
|
|
410
410
|
if (basicFilterDto.groupBy) {
|
|
411
411
|
// Get the records and the count
|
|
412
|
-
const { groupMeta, groupRecords } = await this.handleGroupFind(qb, populateGroup, alias, populateMedia);
|
|
412
|
+
const { groupMeta, groupRecords } = await this.handleGroupFind(qb, groupFilter,populateGroup, alias, populateMedia);
|
|
413
413
|
return {
|
|
414
414
|
groupMeta,
|
|
415
415
|
groupRecords,
|
|
@@ -417,7 +417,7 @@ export class CRUDService<T> { //Add two generic value i.e Person,CreatePersonDto
|
|
|
417
417
|
}
|
|
418
418
|
else {
|
|
419
419
|
// Get the records and the count
|
|
420
|
-
const {meta, records} = await this.handleNonGroupFind(qb, populateMedia, offset, limit);
|
|
420
|
+
const { meta, records } = await this.handleNonGroupFind(qb, populateMedia, offset, limit);
|
|
421
421
|
return {
|
|
422
422
|
meta,
|
|
423
423
|
records,
|
|
@@ -433,10 +433,10 @@ export class CRUDService<T> { //Add two generic value i.e Person,CreatePersonDto
|
|
|
433
433
|
await this.handlePopulateMedia(populateMedia, entities);
|
|
434
434
|
}
|
|
435
435
|
|
|
436
|
-
return
|
|
436
|
+
return this.wrapFindResponse(offset, limit, count, entities);
|
|
437
437
|
}
|
|
438
438
|
|
|
439
|
-
private async handleGroupFind(qb: SelectQueryBuilder<T>, populateGroup: boolean, alias: string, populateMedia: string[]) {
|
|
439
|
+
private async handleGroupFind(qb: SelectQueryBuilder<T>, groupFilter: BasicFilterDto,populateGroup: boolean, alias: string, populateMedia: string[]) {
|
|
440
440
|
const groupByResult = await qb.getRawMany();
|
|
441
441
|
|
|
442
442
|
const groupMeta = [];
|
|
@@ -446,11 +446,11 @@ export class CRUDService<T> { //Add two generic value i.e Person,CreatePersonDto
|
|
|
446
446
|
if (populateGroup) {
|
|
447
447
|
let groupByQb: SelectQueryBuilder<T> = this.repo.createQueryBuilder(alias);
|
|
448
448
|
// For the group by records, apply the basic filter
|
|
449
|
-
const basicFilterDto = {
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
};
|
|
453
|
-
groupByQb = this.crudHelperService.buildFilterQuery(groupByQb,
|
|
449
|
+
// const basicFilterDto = {
|
|
450
|
+
// limit: DEFAULT_LIMIT,
|
|
451
|
+
// offset: DEFAULT_OFFSET,
|
|
452
|
+
// };
|
|
453
|
+
groupByQb = this.crudHelperService.buildFilterQuery(groupByQb, groupFilter, alias);
|
|
454
454
|
groupByQb = this.crudHelperService.buildGroupByRecordsQuery(groupByQb, group, alias);
|
|
455
455
|
const [entities, count] = await groupByQb.getManyAndCount();
|
|
456
456
|
|
|
@@ -459,7 +459,7 @@ export class CRUDService<T> { //Add two generic value i.e Person,CreatePersonDto
|
|
|
459
459
|
if (populateMedia && populateMedia.length > 0) {
|
|
460
460
|
await this.handlePopulateMedia(populateMedia, entities);
|
|
461
461
|
}
|
|
462
|
-
const groupData = this.wrapFindResponse(
|
|
462
|
+
const groupData = this.wrapFindResponse(groupFilter.offset, groupFilter.limit, count, entities);
|
|
463
463
|
groupRecords.push(this.crudHelperService.createGroupRecords(group, alias, groupData));
|
|
464
464
|
}
|
|
465
465
|
groupMeta.push(this.crudHelperService.createGroupMeta(group, alias));
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { Module } from '@nestjs/common';
|
|
2
|
+
import { TypeOrmModule } from '@nestjs/typeorm';
|
|
3
|
+
import { join } from 'path';
|
|
4
|
+
import { SnakeNamingStrategy } from 'typeorm-naming-strategies';
|
|
5
|
+
import { WinstonTypeORMLogger } from './winston.logger';
|
|
6
|
+
import { WINSTON_MODULE_PROVIDER } from 'nest-winston';
|
|
7
|
+
|
|
8
|
+
@Module({
|
|
9
|
+
imports: [
|
|
10
|
+
TypeOrmModule.forRootAsync({
|
|
11
|
+
// This becomes the default by default.
|
|
12
|
+
// name: 'default',
|
|
13
|
+
useFactory: (logger: Logger) => {
|
|
14
|
+
|
|
15
|
+
const entities = [
|
|
16
|
+
join(__dirname, './entities/*.entity.{ts,js}'),
|
|
17
|
+
];
|
|
18
|
+
|
|
19
|
+
// DO NOT REMOVE BELOW COMMENT
|
|
20
|
+
// We no longer register subscribers on the TypeORM datasource.
|
|
21
|
+
// instead we register them directly as NestJS providers, and they register themselves as subscribers on the data source during service instantiation in their respective constructor.
|
|
22
|
+
// check ModelSubscriber for a reference.
|
|
23
|
+
// Steps are
|
|
24
|
+
// 1. Create the subscriber like a NestJS injectable service.
|
|
25
|
+
// 2. Register the subscriber in the respective module like you would any other NestJS service.
|
|
26
|
+
// 3. Make sure to not provide the subscribers array below.
|
|
27
|
+
// const subscribers = [
|
|
28
|
+
// join(__dirname, './app-builder/subscribers/*.subscriber.{ts,js}'),
|
|
29
|
+
// join(__dirname, './common/subscribers/*.subscriber.{ts,js}'),
|
|
30
|
+
// join(__dirname, './iam/subscribers/*.subscriber.{ts,js}'),
|
|
31
|
+
// join(__dirname, './queues/subscribers/*.subscriber.{ts,js}'),
|
|
32
|
+
// ...enabledModules.map(module =>
|
|
33
|
+
// join(__dirname, `./${module}/subscribers/*.subscriber.{ts,js}`)
|
|
34
|
+
// ),
|
|
35
|
+
// ];
|
|
36
|
+
|
|
37
|
+
return {
|
|
38
|
+
// type of our database.
|
|
39
|
+
type: 'postgres',
|
|
40
|
+
host: process.env.DEFAULT_DATABASE_HOST,
|
|
41
|
+
port: +process.env.DEFAULT_DATABASE_PORT,
|
|
42
|
+
username: process.env.DEFAULT_DATABASE_USER,
|
|
43
|
+
password: process.env.DEFAULT_DATABASE_PASSWORD,
|
|
44
|
+
// name of our database
|
|
45
|
+
database: process.env.DEFAULT_DATABASE_NAME,
|
|
46
|
+
// models will be loaded automatically
|
|
47
|
+
// autoLoadEntities: true,
|
|
48
|
+
entities: entities,
|
|
49
|
+
// your entities will be synced with the database (recommended: disable in prod)
|
|
50
|
+
synchronize: Boolean(process.env.DEFAULT_DATABASE_SYNCHRONIZE),
|
|
51
|
+
logging: Boolean(process.env.DEFAULT_DATABASE_LOGGING),
|
|
52
|
+
// logger: new WinstonTypeORMLogger(logger), // Pass in the custom WinstonLogger
|
|
53
|
+
namingStrategy: new SnakeNamingStrategy(),
|
|
54
|
+
// subscribers: subscribers
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
inject: [WINSTON_MODULE_PROVIDER]
|
|
58
|
+
}),
|
|
59
|
+
],
|
|
60
|
+
})
|
|
61
|
+
export class SolidCoreCliDBModule{
|
|
62
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { Module } from '@nestjs/common';
|
|
2
|
+
import { SolidCoreCliDBModule } from './solid-core-cli-db.module';
|
|
3
|
+
import { SolidCoreModule } from './solid-core.module'; // Import main module
|
|
4
|
+
import { WinstonLoggerConfig } from './winston.logger';
|
|
5
|
+
import { WinstonModule } from 'nest-winston';
|
|
6
|
+
import { CacheModule } from '@nestjs/cache-manager';
|
|
7
|
+
import { EventEmitterModule } from '@nestjs/event-emitter';
|
|
8
|
+
import { RedisOptions } from './config/redis.options';
|
|
9
|
+
import { ConfigModule } from '@nestjs/config';
|
|
10
|
+
import Joi from '@hapi/joi';
|
|
11
|
+
|
|
12
|
+
@Module({
|
|
13
|
+
imports: [
|
|
14
|
+
WinstonModule.forRoot(WinstonLoggerConfig),
|
|
15
|
+
ConfigModule.forRoot({
|
|
16
|
+
isGlobal: true,
|
|
17
|
+
// Here we are specifying the path of the environment file.
|
|
18
|
+
// If not specified then it assumes a file named .env
|
|
19
|
+
// envFilePath: '.environment'
|
|
20
|
+
|
|
21
|
+
// This we do in live environments, where these variables should ideally come
|
|
22
|
+
// from the OS provided environment.
|
|
23
|
+
// ignoreEnvFile: true
|
|
24
|
+
|
|
25
|
+
validationSchema: Joi.object({
|
|
26
|
+
DEFAULT_DATABASE_HOST: Joi.required(),
|
|
27
|
+
DEFAULT_DATABASE_PORT: Joi.number().default(5432),
|
|
28
|
+
}),
|
|
29
|
+
|
|
30
|
+
// load: [appConfig],
|
|
31
|
+
}),
|
|
32
|
+
|
|
33
|
+
SolidCoreCliDBModule,
|
|
34
|
+
CacheModule.registerAsync(RedisOptions),
|
|
35
|
+
EventEmitterModule.forRoot(),
|
|
36
|
+
SolidCoreModule, // Import main module without exposing forRoot()
|
|
37
|
+
],
|
|
38
|
+
exports: [SolidCoreModule], // Ensure CLI can use all exports
|
|
39
|
+
})
|
|
40
|
+
export class SolidCoreCliModule{}
|
package/src/solid-core.module.ts
CHANGED
|
@@ -121,17 +121,17 @@ import { Msg91SMSService } from './services/sms/Msg91SMSService';
|
|
|
121
121
|
import { Msg91WhatsappService } from './services/whatsapp/Msg91WhatsappService';
|
|
122
122
|
import { SoftDeleteAwareEventSubscriber } from './subscribers/softDeleteAwareEventSubscriber.subscriber';
|
|
123
123
|
|
|
124
|
+
import { PermissionMetadataController } from './controllers/permission-metadata.controller';
|
|
124
125
|
import { PermissionMetadata } from './entities/permission-metadata.entity';
|
|
125
126
|
import { PermissionMetadataService } from './services/permission-metadata.service';
|
|
126
|
-
import { PermissionMetadataController } from './controllers/permission-metadata.controller';
|
|
127
127
|
|
|
128
|
-
import { RoleMetadata } from './entities/role-metadata.entity';
|
|
129
|
-
import { RoleMetadataService } from './services/role-metadata.service';
|
|
130
128
|
import { RoleMetadataController } from './controllers/role-metadata.controller';
|
|
131
|
-
import {
|
|
129
|
+
import { UserController } from './controllers/user.controller';
|
|
130
|
+
import { RoleMetadata } from './entities/role-metadata.entity';
|
|
132
131
|
import { User } from './entities/user.entity';
|
|
132
|
+
import { PermissionMetadataSeederService } from './seeders/permission-metadata-seeder.service';
|
|
133
|
+
import { RoleMetadataService } from './services/role-metadata.service';
|
|
133
134
|
import { UserService } from './services/user.service';
|
|
134
|
-
import { UserController } from './controllers/user.controller';
|
|
135
135
|
|
|
136
136
|
|
|
137
137
|
@Global()
|
|
@@ -311,6 +311,8 @@ import { UserController } from './controllers/user.controller';
|
|
|
311
311
|
AuthenticationService,
|
|
312
312
|
MqMessageQueueService,
|
|
313
313
|
MqMessageService,
|
|
314
|
+
RefreshModelCommand,
|
|
315
|
+
RefreshModuleCommand,
|
|
314
316
|
],
|
|
315
317
|
})
|
|
316
318
|
export class SolidCoreModule { }
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
|
|
2
|
+
import { Logger as TypeORMLogger, QueryRunner } from 'typeorm';
|
|
3
|
+
import { Logger } from 'winston';
|
|
4
|
+
import { Inject } from '@nestjs/common';
|
|
5
|
+
import { WINSTON_MODULE_PROVIDER } from 'nest-winston';
|
|
6
|
+
import * as winston from 'winston';
|
|
7
|
+
|
|
8
|
+
export const WinstonLoggerConfig = {
|
|
9
|
+
level: 'debug', // Allow all log levels for debugging
|
|
10
|
+
format: winston.format.combine(
|
|
11
|
+
winston.format.timestamp(),
|
|
12
|
+
winston.format.errors({ stack: true }),
|
|
13
|
+
winston.format.printf(({ level, message, timestamp }) => {
|
|
14
|
+
if (!message) {
|
|
15
|
+
return `[${timestamp}] ${level.toUpperCase()}: (No message provided)`;
|
|
16
|
+
}
|
|
17
|
+
return `[${timestamp}] ${level.toUpperCase()}: ${message}`;
|
|
18
|
+
}),
|
|
19
|
+
),
|
|
20
|
+
transports: [
|
|
21
|
+
new winston.transports.Console({
|
|
22
|
+
format: winston.format.combine(
|
|
23
|
+
// winston.format.colorize(),
|
|
24
|
+
// winston.format.timestamp(),
|
|
25
|
+
winston.format.printf(({ level, message, timestamp }) => {
|
|
26
|
+
return `[${timestamp}] ${level.toUpperCase()}: ${message}`;
|
|
27
|
+
}),
|
|
28
|
+
),
|
|
29
|
+
}),
|
|
30
|
+
new winston.transports.File({
|
|
31
|
+
filename: 'logs/application.log',
|
|
32
|
+
// format: winston.format.json(),
|
|
33
|
+
}),
|
|
34
|
+
new winston.transports.File({
|
|
35
|
+
filename: 'logs/error.log',
|
|
36
|
+
level: 'error',
|
|
37
|
+
// format: winston.format.json(),
|
|
38
|
+
}),
|
|
39
|
+
],
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
export class WinstonTypeORMLogger implements TypeORMLogger {
|
|
43
|
+
constructor(@Inject(WINSTON_MODULE_PROVIDER) private readonly logger: Logger) { }
|
|
44
|
+
|
|
45
|
+
logQuery(query: string, parameters?: any[], queryRunner?: QueryRunner): void {
|
|
46
|
+
if (Boolean(process.env.DEFAULT_DATABASE_LOGGING)) {
|
|
47
|
+
this.logger.info(`Query: ${query} Parameters: ${parameters}`);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
logQueryError(error: string, query: string, parameters?: any[], queryRunner?: QueryRunner): void {
|
|
52
|
+
this.logger.error(`Query failed: ${error} | Query: ${query} | Parameters: ${parameters}`);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
logQuerySlow(time: number, query: string, parameters?: any[], queryRunner?: QueryRunner): void {
|
|
56
|
+
this.logger.warn(`Slow query: ${time}ms | Query: ${query} | Parameters: ${parameters}`);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
logSchemaBuild(message: string, queryRunner?: QueryRunner): void {
|
|
60
|
+
this.logger.info(`Schema Build: ${message}`);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
logMigration(message: string, queryRunner?: QueryRunner): void {
|
|
64
|
+
this.logger.info(`Migration: ${message}`);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
log(level: 'log' | 'info' | 'warn' | 'error', message: any): void {
|
|
68
|
+
this.logger[level](message);
|
|
69
|
+
}
|
|
70
|
+
}
|