@lenne.tech/nest-server 9.0.20 → 9.0.22
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/config.env.js +1 -1
- package/dist/core/common/decorators/restricted.decorator.js +3 -0
- package/dist/core/common/decorators/restricted.decorator.js.map +1 -1
- package/dist/core/common/helpers/input.helper.d.ts +5 -1
- package/dist/core/common/helpers/input.helper.js +24 -4
- package/dist/core/common/helpers/input.helper.js.map +1 -1
- package/dist/core/common/helpers/model.helper.d.ts +10 -0
- package/dist/core/common/helpers/model.helper.js +21 -3
- package/dist/core/common/helpers/model.helper.js.map +1 -1
- package/dist/core/common/helpers/service.helper.d.ts +1 -0
- package/dist/core/common/helpers/service.helper.js +10 -0
- package/dist/core/common/helpers/service.helper.js.map +1 -1
- package/dist/core/common/interfaces/prepare-input-options.interface.d.ts +1 -0
- package/dist/core/common/services/crud.service.js +1 -1
- package/dist/core/common/services/crud.service.js.map +1 -1
- package/dist/core/common/services/module.service.js +2 -2
- package/dist/core/common/services/module.service.js.map +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +2 -2
- package/src/config.env.ts +1 -1
- package/src/core/common/decorators/restricted.decorator.ts +3 -0
- package/src/core/common/helpers/input.helper.ts +44 -6
- package/src/core/common/helpers/model.helper.ts +40 -10
- package/src/core/common/helpers/service.helper.ts +18 -1
- package/src/core/common/interfaces/prepare-input-options.interface.ts +1 -0
- package/src/core/common/services/crud.service.ts +2 -2
- package/src/core/common/services/module.service.ts +2 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lenne.tech/nest-server",
|
|
3
|
-
"version": "9.0.
|
|
3
|
+
"version": "9.0.22",
|
|
4
4
|
"description": "Modern, fast, powerful Node.js web framework in TypeScript based on Nest with a GraphQL API and a connection to MongoDB (or other databases).",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"node",
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
"start": "npm run start:local",
|
|
31
31
|
"stop": "./node_modules/.bin/pm2 delete nest",
|
|
32
32
|
"start:pm2": "./node_modules/.bin/grunt",
|
|
33
|
-
"start:prod": "./node_modules/.bin/grunt
|
|
33
|
+
"start:prod": "./node_modules/.bin/grunt production",
|
|
34
34
|
"start:nodemon": "ts-node -r tsconfig-paths/register src/main.ts",
|
|
35
35
|
"start:debug": "nodemon --config nodemon-debug.json",
|
|
36
36
|
"start:dev": "nodemon",
|
package/src/config.env.ts
CHANGED
|
@@ -160,7 +160,7 @@ const config: { [env: string]: IServerOptions } = {
|
|
|
160
160
|
verificationLink: 'http://localhost:4200/user/verification',
|
|
161
161
|
passwordResetLink: 'http://localhost:4200/user/password-reset',
|
|
162
162
|
},
|
|
163
|
-
env: '
|
|
163
|
+
env: 'production',
|
|
164
164
|
execAfterInit: 'npm run docs:bootstrap',
|
|
165
165
|
filter: {
|
|
166
166
|
maxLimit: null,
|
|
@@ -44,6 +44,9 @@ export const Restricted = (...rolesOrMember: RestrictedType): ClassDecorator & P
|
|
|
44
44
|
* Get restricted data for (property of) object
|
|
45
45
|
*/
|
|
46
46
|
export const getRestricted = (object: unknown, propertyKey?: string): RestrictedType => {
|
|
47
|
+
if (!object) {
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
47
50
|
if (!propertyKey) {
|
|
48
51
|
return Reflect.getMetadata(restrictedMetaKey, object);
|
|
49
52
|
}
|
|
@@ -7,6 +7,7 @@ import * as rfdc from 'rfdc';
|
|
|
7
7
|
import { checkRestricted } from '../decorators/restricted.decorator';
|
|
8
8
|
import { ProcessType } from '../enums/process-type.enum';
|
|
9
9
|
import { RoleEnum } from '../enums/role.enum';
|
|
10
|
+
import { merge } from './config.helper';
|
|
10
11
|
import { equalIds } from './db.helper';
|
|
11
12
|
|
|
12
13
|
/**
|
|
@@ -537,6 +538,24 @@ export function isString(parameter: string, falseFunction: (...params) => any =
|
|
|
537
538
|
return typeof parameter === 'string' ? true : falseFunction(isString);
|
|
538
539
|
}
|
|
539
540
|
|
|
541
|
+
/**
|
|
542
|
+
* Merge plain objects deep into target object and ignores undefined
|
|
543
|
+
*/
|
|
544
|
+
export function mergePlain(target: Record<any, any>, ...args: Record<any, any>[]): any {
|
|
545
|
+
return merge(
|
|
546
|
+
target,
|
|
547
|
+
...args.map(
|
|
548
|
+
// Prepare records
|
|
549
|
+
(item) =>
|
|
550
|
+
!item
|
|
551
|
+
? // Return item if not an object
|
|
552
|
+
item
|
|
553
|
+
: // Return cloned record with undefined properties removed
|
|
554
|
+
filterProperties(clone(item, { circles: false }), (prop) => prop !== undefined)
|
|
555
|
+
)
|
|
556
|
+
);
|
|
557
|
+
}
|
|
558
|
+
|
|
540
559
|
/**
|
|
541
560
|
* Alternative for errorFunction
|
|
542
561
|
*/
|
|
@@ -629,11 +648,22 @@ export function instanceofArray(arr: any[], strict = false): string {
|
|
|
629
648
|
|
|
630
649
|
/**
|
|
631
650
|
* Process data via function deep
|
|
632
|
-
* @param data
|
|
633
|
-
* @param func
|
|
634
|
-
* @param processedObjects
|
|
635
651
|
*/
|
|
636
|
-
export function processDeep(
|
|
652
|
+
export function processDeep(
|
|
653
|
+
data: any,
|
|
654
|
+
func: (data: any) => any,
|
|
655
|
+
options?: {
|
|
656
|
+
processedObjects?: WeakMap<new () => any, boolean>;
|
|
657
|
+
specialClasses?: ((new (args: any[]) => any) | string)[];
|
|
658
|
+
}
|
|
659
|
+
): any {
|
|
660
|
+
// Set options
|
|
661
|
+
const { processedObjects, specialClasses } = {
|
|
662
|
+
processedObjects: new WeakMap(),
|
|
663
|
+
specialClasses: [],
|
|
664
|
+
...options,
|
|
665
|
+
};
|
|
666
|
+
|
|
637
667
|
// Prevent circular processing
|
|
638
668
|
if (typeof data === 'object') {
|
|
639
669
|
if (processedObjects.get(data)) {
|
|
@@ -644,13 +674,21 @@ export function processDeep(data: any, func: (data: any) => any, processedObject
|
|
|
644
674
|
|
|
645
675
|
// Process array
|
|
646
676
|
if (Array.isArray(data)) {
|
|
647
|
-
return data.map((item) => processDeep(item, func));
|
|
677
|
+
return data.map((item) => processDeep(item, func, { processedObjects, specialClasses }));
|
|
648
678
|
}
|
|
649
679
|
|
|
650
680
|
// Process object
|
|
651
681
|
if (typeof data === 'object') {
|
|
682
|
+
for (const specialClass of specialClasses) {
|
|
683
|
+
if (
|
|
684
|
+
(typeof specialClass === 'string' && specialClass === data.constructor.name) ||
|
|
685
|
+
(typeof specialClass !== 'string' && data instanceof specialClass)
|
|
686
|
+
) {
|
|
687
|
+
return func(data);
|
|
688
|
+
}
|
|
689
|
+
}
|
|
652
690
|
for (const [key, value] of Object.entries(data)) {
|
|
653
|
-
data[key] = processDeep(value, func, processedObjects);
|
|
691
|
+
data[key] = processDeep(value, func, { processedObjects, specialClasses });
|
|
654
692
|
}
|
|
655
693
|
return data;
|
|
656
694
|
}
|
|
@@ -9,9 +9,6 @@ import { clone } from './input.helper';
|
|
|
9
9
|
export class ModelHelper {
|
|
10
10
|
/**
|
|
11
11
|
* Remove all properties from source which are not in target
|
|
12
|
-
* @param source
|
|
13
|
-
* @param target
|
|
14
|
-
* @param options
|
|
15
12
|
*/
|
|
16
13
|
public static prepareMap<T = Record<string, any>>(
|
|
17
14
|
source: Partial<T> | Record<string, any>,
|
|
@@ -54,9 +51,6 @@ export class ModelHelper {
|
|
|
54
51
|
|
|
55
52
|
/**
|
|
56
53
|
* Remove all properties from source which are not in target
|
|
57
|
-
* @param source
|
|
58
|
-
* @param target
|
|
59
|
-
* @param options
|
|
60
54
|
*/
|
|
61
55
|
export function prepareMap<T = Record<string, any>>(
|
|
62
56
|
source: Partial<T> | Record<string, any>,
|
|
@@ -176,7 +170,7 @@ export function mapClasses<T = Record<string, any>>(
|
|
|
176
170
|
input: Record<string, any>,
|
|
177
171
|
mapping: Record<string, new (...args: any[]) => any>,
|
|
178
172
|
target?: T,
|
|
179
|
-
options?: { objectIdsToString?: boolean }
|
|
173
|
+
options?: { objectIdsToString?: boolean; removeUndefinedProperties?: boolean }
|
|
180
174
|
): T {
|
|
181
175
|
// Check params
|
|
182
176
|
if (!target) {
|
|
@@ -189,6 +183,7 @@ export function mapClasses<T = Record<string, any>>(
|
|
|
189
183
|
// Get config
|
|
190
184
|
const config = {
|
|
191
185
|
objectIdsToString: true,
|
|
186
|
+
removeUndefinedProperties: false,
|
|
192
187
|
...options,
|
|
193
188
|
};
|
|
194
189
|
|
|
@@ -238,7 +233,7 @@ export function mapClasses<T = Record<string, any>>(
|
|
|
238
233
|
}
|
|
239
234
|
|
|
240
235
|
// Others
|
|
241
|
-
else {
|
|
236
|
+
else if (!config.removeUndefinedProperties || value !== undefined) {
|
|
242
237
|
target[prop] = value;
|
|
243
238
|
}
|
|
244
239
|
}
|
|
@@ -259,7 +254,7 @@ export async function mapClassesAsync<T = Record<string, any>>(
|
|
|
259
254
|
input: Record<string, any>,
|
|
260
255
|
mapping: Record<string, new (...args: any[]) => any>,
|
|
261
256
|
target?: T,
|
|
262
|
-
options?: { objectIdsToString?: boolean }
|
|
257
|
+
options?: { objectIdsToString?: boolean; removeUndefinedProperties?: boolean }
|
|
263
258
|
): Promise<T> {
|
|
264
259
|
// Check params
|
|
265
260
|
if (!target) {
|
|
@@ -272,6 +267,7 @@ export async function mapClassesAsync<T = Record<string, any>>(
|
|
|
272
267
|
// Get config
|
|
273
268
|
const config = {
|
|
274
269
|
objectIdsToString: true,
|
|
270
|
+
removeUndefinedProperties: false,
|
|
275
271
|
...options,
|
|
276
272
|
};
|
|
277
273
|
|
|
@@ -321,7 +317,7 @@ export async function mapClassesAsync<T = Record<string, any>>(
|
|
|
321
317
|
}
|
|
322
318
|
|
|
323
319
|
// Others
|
|
324
|
-
else {
|
|
320
|
+
else if (!config.removeUndefinedProperties || value !== undefined) {
|
|
325
321
|
target[prop] = value;
|
|
326
322
|
}
|
|
327
323
|
}
|
|
@@ -329,3 +325,37 @@ export async function mapClassesAsync<T = Record<string, any>>(
|
|
|
329
325
|
|
|
330
326
|
return target;
|
|
331
327
|
}
|
|
328
|
+
|
|
329
|
+
/**
|
|
330
|
+
* Same as mapClasses but with option removeUndefinedProperties = true as default
|
|
331
|
+
*/
|
|
332
|
+
export function mapInputClasses<T = Record<string, any>>(
|
|
333
|
+
input: Record<string, any>,
|
|
334
|
+
mapping: Record<string, new (...args: any[]) => any>,
|
|
335
|
+
target?: T,
|
|
336
|
+
options?: { objectIdsToString?: boolean; removeUndefinedProperties?: boolean }
|
|
337
|
+
) {
|
|
338
|
+
// Get config
|
|
339
|
+
const config = {
|
|
340
|
+
removeUndefinedProperties: true,
|
|
341
|
+
...options,
|
|
342
|
+
};
|
|
343
|
+
return mapClasses(input, mapping, target, options);
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
/**
|
|
347
|
+
* Same as mapClassesAsync but with option removeUndefinedProperties = true as default
|
|
348
|
+
*/
|
|
349
|
+
export function mapInputClassesAsync<T = Record<string, any>>(
|
|
350
|
+
input: Record<string, any>,
|
|
351
|
+
mapping: Record<string, new (...args: any[]) => any>,
|
|
352
|
+
target?: T,
|
|
353
|
+
options?: { objectIdsToString?: boolean; removeUndefinedProperties?: boolean }
|
|
354
|
+
) {
|
|
355
|
+
// Get config
|
|
356
|
+
const config = {
|
|
357
|
+
removeUndefinedProperties: true,
|
|
358
|
+
...options,
|
|
359
|
+
};
|
|
360
|
+
return mapClassesAsync(input, mapping, target, options);
|
|
361
|
+
}
|
|
@@ -10,7 +10,8 @@ import { PrepareOutputOptions } from '../interfaces/prepare-output-options.inter
|
|
|
10
10
|
import { ResolveSelector } from '../interfaces/resolve-selector.interface';
|
|
11
11
|
import { ServiceOptions } from '../interfaces/service-options.interface';
|
|
12
12
|
import { ConfigService } from '../services/config.service';
|
|
13
|
-
import {
|
|
13
|
+
import { getStringIds } from './db.helper';
|
|
14
|
+
import { clone, processDeep } from './input.helper';
|
|
14
15
|
|
|
15
16
|
/**
|
|
16
17
|
* Helper class for services
|
|
@@ -66,6 +67,7 @@ export async function prepareInput<T = any>(
|
|
|
66
67
|
[key: string]: any;
|
|
67
68
|
checkRoles?: boolean;
|
|
68
69
|
circles?: boolean;
|
|
70
|
+
convertObjectIdsToString?: boolean;
|
|
69
71
|
create?: boolean;
|
|
70
72
|
clone?: boolean;
|
|
71
73
|
getNewArray?: boolean;
|
|
@@ -80,6 +82,7 @@ export async function prepareInput<T = any>(
|
|
|
80
82
|
checkRoles: false,
|
|
81
83
|
clone: false,
|
|
82
84
|
circles: false,
|
|
85
|
+
convertObjectIdsToString: true,
|
|
83
86
|
create: false,
|
|
84
87
|
getNewArray: false,
|
|
85
88
|
proto: false,
|
|
@@ -114,6 +117,20 @@ export async function prepareInput<T = any>(
|
|
|
114
117
|
}
|
|
115
118
|
}
|
|
116
119
|
|
|
120
|
+
// Convert ObjectIds to string
|
|
121
|
+
if (config.convertObjectIdsToString) {
|
|
122
|
+
input = processDeep(
|
|
123
|
+
input,
|
|
124
|
+
(property) => {
|
|
125
|
+
if (property instanceof Types.ObjectId) {
|
|
126
|
+
property = getStringIds(property);
|
|
127
|
+
}
|
|
128
|
+
return property;
|
|
129
|
+
},
|
|
130
|
+
{ specialClasses: ['ObjectId'] }
|
|
131
|
+
);
|
|
132
|
+
}
|
|
133
|
+
|
|
117
134
|
// Map input if target model exist
|
|
118
135
|
if (config.targetModel && !(input instanceof config.targetModel)) {
|
|
119
136
|
if ((config.targetModel as any)?.map) {
|
|
@@ -4,7 +4,7 @@ import { FilterArgs } from '../args/filter.args';
|
|
|
4
4
|
import { merge } from '../helpers/config.helper';
|
|
5
5
|
import { getStringIds } from '../helpers/db.helper';
|
|
6
6
|
import { convertFilterArgsToQuery } from '../helpers/filter.helper';
|
|
7
|
-
import {
|
|
7
|
+
import { mergePlain } from '../helpers/input.helper';
|
|
8
8
|
import { ServiceOptions } from '../interfaces/service-options.interface';
|
|
9
9
|
import { CoreModel } from '../models/core-model.model';
|
|
10
10
|
import { ConfigService } from './config.service';
|
|
@@ -388,7 +388,7 @@ export abstract class CrudService<T extends CoreModel = any> extends ModuleServi
|
|
|
388
388
|
return this.process(
|
|
389
389
|
async (data) => {
|
|
390
390
|
const currentUserId = serviceOptions?.currentUser?.id;
|
|
391
|
-
return await
|
|
391
|
+
return await mergePlain(dbObject, data.input, { updatedBy: currentUserId }).save();
|
|
392
392
|
},
|
|
393
393
|
{ dbObject, input, serviceOptions }
|
|
394
394
|
);
|
|
@@ -111,7 +111,7 @@ export abstract class ModuleService<T extends CoreModel = any> {
|
|
|
111
111
|
if (!opts.targetModel && config.inputType) {
|
|
112
112
|
opts.targetModel = config.inputType;
|
|
113
113
|
}
|
|
114
|
-
config.input = await this.prepareInput(config.input,
|
|
114
|
+
config.input = await this.prepareInput(config.input, config);
|
|
115
115
|
}
|
|
116
116
|
|
|
117
117
|
// Get DB object
|
|
@@ -156,7 +156,7 @@ export abstract class ModuleService<T extends CoreModel = any> {
|
|
|
156
156
|
if (config.outputPath) {
|
|
157
157
|
_.set(result, config.outputPath, await this.prepareOutput(_.get(result, config.outputPath), opts));
|
|
158
158
|
} else {
|
|
159
|
-
result = await this.prepareOutput(result,
|
|
159
|
+
result = await this.prepareOutput(result, config);
|
|
160
160
|
}
|
|
161
161
|
}
|
|
162
162
|
|