@lenne.tech/nest-server 9.0.31 → 9.1.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.
- package/dist/core/common/helpers/db.helper.d.ts +6 -2
- package/dist/core/common/helpers/db.helper.js +9 -4
- package/dist/core/common/helpers/db.helper.js.map +1 -1
- package/dist/core/common/helpers/input.helper.d.ts +3 -0
- package/dist/core/common/helpers/input.helper.js +30 -1
- package/dist/core/common/helpers/input.helper.js.map +1 -1
- package/dist/core/common/interfaces/server-options.interface.d.ts +1 -0
- package/dist/core/common/interfaces/service-options.interface.d.ts +1 -0
- package/dist/core/common/services/module.service.d.ts +5 -1
- package/dist/core/common/services/module.service.js +13 -1
- package/dist/core/common/services/module.service.js.map +1 -1
- package/dist/core/modules/user/core-user.service.d.ts +2 -2
- package/dist/core/modules/user/core-user.service.js +2 -2
- package/dist/core/modules/user/core-user.service.js.map +1 -1
- package/dist/server/modules/user/user.service.js +1 -1
- package/dist/server/modules/user/user.service.js.map +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/core/common/helpers/db.helper.ts +15 -5
- package/src/core/common/helpers/input.helper.ts +49 -0
- package/src/core/common/interfaces/server-options.interface.ts +8 -0
- package/src/core/common/interfaces/service-options.interface.ts +4 -0
- package/src/core/common/services/module.service.ts +24 -2
- package/src/core/modules/user/core-user.service.ts +2 -2
- package/src/server/modules/user/user.service.ts +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lenne.tech/nest-server",
|
|
3
|
-
"version": "9.0
|
|
3
|
+
"version": "9.1.0",
|
|
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",
|
|
@@ -6,6 +6,7 @@ import { CoreModel } from '../models/core-model.model';
|
|
|
6
6
|
import { FieldSelection } from '../types/field-selection.type';
|
|
7
7
|
import { IdsType } from '../types/ids.type';
|
|
8
8
|
import { StringOrObjectId } from '../types/string-or-object-id.type';
|
|
9
|
+
import { removePropertiesDeep } from './input.helper';
|
|
9
10
|
|
|
10
11
|
// =====================================================================================================================
|
|
11
12
|
// Export functions
|
|
@@ -350,7 +351,7 @@ export function getPopulatOptionsFromSelections(selectionNodes: readonly Selecti
|
|
|
350
351
|
// Check for subfields
|
|
351
352
|
if (node.selectionSet?.selections?.length) {
|
|
352
353
|
for (const innerNode of node.selectionSet.selections as FieldNode[]) {
|
|
353
|
-
//
|
|
354
|
+
// Subfield is a primitive
|
|
354
355
|
if (!innerNode.selectionSet?.selections?.length) {
|
|
355
356
|
option.select ? option.select.push(innerNode.name.value) : (option.select = [innerNode.name.value]);
|
|
356
357
|
}
|
|
@@ -477,10 +478,14 @@ export async function popAndMap<T extends CoreModel>(
|
|
|
477
478
|
queryOrDocument: Query<any, any> | Document | Document[],
|
|
478
479
|
populate: FieldSelection,
|
|
479
480
|
modelClass: new (...args: any[]) => T,
|
|
480
|
-
mongooseModel?: Model<any
|
|
481
|
+
mongooseModel?: Model<any>,
|
|
482
|
+
options?: {
|
|
483
|
+
ignoreSelections?: boolean;
|
|
484
|
+
}
|
|
481
485
|
): Promise<T | T[]> {
|
|
482
486
|
let result;
|
|
483
487
|
let populateOptions: PopulateOptions[] = [];
|
|
488
|
+
const ignoreSelections = options?.ignoreSelections;
|
|
484
489
|
if (populate) {
|
|
485
490
|
if (
|
|
486
491
|
Array.isArray(populate) &&
|
|
@@ -511,13 +516,13 @@ export async function popAndMap<T extends CoreModel>(
|
|
|
511
516
|
} else {
|
|
512
517
|
// Process documents
|
|
513
518
|
if (Array.isArray(queryOrDocument)) {
|
|
514
|
-
await setPopulates(queryOrDocument, populateOptions, mongooseModel);
|
|
519
|
+
await setPopulates(queryOrDocument, populateOptions, mongooseModel, { ignoreSelections });
|
|
515
520
|
result = queryOrDocument.map((item) => (modelClass as any).map(item));
|
|
516
521
|
}
|
|
517
522
|
|
|
518
523
|
// Process document
|
|
519
524
|
else {
|
|
520
|
-
await setPopulates(queryOrDocument, populateOptions, mongooseModel);
|
|
525
|
+
await setPopulates(queryOrDocument, populateOptions, mongooseModel, { ignoreSelections });
|
|
521
526
|
result = (modelClass as any).map(queryOrDocument);
|
|
522
527
|
}
|
|
523
528
|
}
|
|
@@ -562,7 +567,8 @@ export function removeIds(source: any[], ids: StringOrObjectId | StringOrObjectI
|
|
|
562
567
|
export async function setPopulates<T = Query<any, any> | Document>(
|
|
563
568
|
queryOrDocument: T,
|
|
564
569
|
populateOptions: string[] | PopulateOptions[] | (string | PopulateOptions)[],
|
|
565
|
-
mongooseModel: Model<any
|
|
570
|
+
mongooseModel: Model<any>,
|
|
571
|
+
options?: { ignoreSelections: boolean }
|
|
566
572
|
): Promise<T> {
|
|
567
573
|
// Check parameters
|
|
568
574
|
if (!populateOptions?.length || !queryOrDocument) {
|
|
@@ -580,6 +586,10 @@ export async function setPopulates<T = Query<any, any> | Document>(
|
|
|
580
586
|
});
|
|
581
587
|
}
|
|
582
588
|
|
|
589
|
+
if (options?.ignoreSelections) {
|
|
590
|
+
removePropertiesDeep(populateOptions, ['select']);
|
|
591
|
+
}
|
|
592
|
+
|
|
583
593
|
// Query => Chaining
|
|
584
594
|
if (queryOrDocument instanceof Query) {
|
|
585
595
|
for (const options of populateOptions) {
|
|
@@ -718,3 +718,52 @@ export function prepareServiceOptionsForCreate(serviceOptions: any) {
|
|
|
718
718
|
}
|
|
719
719
|
return serviceOptions;
|
|
720
720
|
}
|
|
721
|
+
|
|
722
|
+
/**
|
|
723
|
+
* Remove properties deep
|
|
724
|
+
*/
|
|
725
|
+
export function removePropertiesDeep(
|
|
726
|
+
data: any,
|
|
727
|
+
properties: string[],
|
|
728
|
+
options?: {
|
|
729
|
+
processedObjects?: WeakMap<new () => any, boolean>;
|
|
730
|
+
}
|
|
731
|
+
): any {
|
|
732
|
+
// Set options
|
|
733
|
+
const { processedObjects } = {
|
|
734
|
+
processedObjects: new WeakMap(),
|
|
735
|
+
...options,
|
|
736
|
+
};
|
|
737
|
+
|
|
738
|
+
// Check for falsifiable values
|
|
739
|
+
if (!data) {
|
|
740
|
+
return data;
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
// Prevent circular processing
|
|
744
|
+
else if (typeof data === 'object') {
|
|
745
|
+
if (processedObjects.get(data)) {
|
|
746
|
+
return data;
|
|
747
|
+
}
|
|
748
|
+
processedObjects.set(data, true);
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
// Process array
|
|
752
|
+
if (Array.isArray(data)) {
|
|
753
|
+
return data.map((item) => removePropertiesDeep(item, properties, { processedObjects }));
|
|
754
|
+
}
|
|
755
|
+
|
|
756
|
+
// Process object
|
|
757
|
+
if (typeof data === 'object') {
|
|
758
|
+
for (const prop of properties) {
|
|
759
|
+
delete data[prop];
|
|
760
|
+
}
|
|
761
|
+
for (const [key, value] of Object.entries(data)) {
|
|
762
|
+
data[key] = removePropertiesDeep(value, properties, { processedObjects });
|
|
763
|
+
}
|
|
764
|
+
return data;
|
|
765
|
+
}
|
|
766
|
+
|
|
767
|
+
// Process others
|
|
768
|
+
return data;
|
|
769
|
+
}
|
|
@@ -111,6 +111,14 @@ export interface IServerOptions {
|
|
|
111
111
|
options?: GqlModuleAsyncOptions;
|
|
112
112
|
};
|
|
113
113
|
|
|
114
|
+
/**
|
|
115
|
+
* Ignore selections in fieldSelection
|
|
116
|
+
* [ConfigService must be integrated in ModuleService]
|
|
117
|
+
* If falsy (default): select and populate information in fieldSelection will be respected
|
|
118
|
+
* If truly: select fields will be ignored and only populate fields in fieldSelection will be respected
|
|
119
|
+
*/
|
|
120
|
+
ignoreSelectionsForPopulate?: boolean;
|
|
121
|
+
|
|
114
122
|
/**
|
|
115
123
|
* Configuration of JavaScript Web Token (JWT) module
|
|
116
124
|
*/
|
|
@@ -53,6 +53,10 @@ export interface ServiceOptions {
|
|
|
53
53
|
processFieldSelection?: {
|
|
54
54
|
model?: new (...args: any[]) => any;
|
|
55
55
|
dbModel?: Model<any>;
|
|
56
|
+
// Ignore selections in fieldSelection and populate
|
|
57
|
+
// If falsy (default, if not set in env.config): select and populate information in fieldSelection and populate will be respected
|
|
58
|
+
// If truly: select fields will be ignored and only populate fields in fieldSelection and populate will be respected
|
|
59
|
+
ignoreSelections?: boolean;
|
|
56
60
|
};
|
|
57
61
|
|
|
58
62
|
// Prepare input configuration:
|
|
@@ -7,11 +7,17 @@ import { prepareInput, prepareOutput } from '../helpers/service.helper';
|
|
|
7
7
|
import { ServiceOptions } from '../interfaces/service-options.interface';
|
|
8
8
|
import { CoreModel } from '../models/core-model.model';
|
|
9
9
|
import { FieldSelection } from '../types/field-selection.type';
|
|
10
|
+
import { ConfigService } from './config.service';
|
|
10
11
|
|
|
11
12
|
/**
|
|
12
13
|
* Module service class to be extended by concrete module services
|
|
13
14
|
*/
|
|
14
15
|
export abstract class ModuleService<T extends CoreModel = any> {
|
|
16
|
+
/**
|
|
17
|
+
* Config service, is used to determine certain behavior
|
|
18
|
+
*/
|
|
19
|
+
protected configService: ConfigService;
|
|
20
|
+
|
|
15
21
|
/**
|
|
16
22
|
* Main model constructor of the service, will be used as default for populate and mapping
|
|
17
23
|
*/
|
|
@@ -26,9 +32,11 @@ export abstract class ModuleService<T extends CoreModel = any> {
|
|
|
26
32
|
* Set main properties
|
|
27
33
|
*/
|
|
28
34
|
protected constructor(options?: {
|
|
29
|
-
|
|
35
|
+
configService?: ConfigService;
|
|
36
|
+
mainDbModel?: Model<T & Document>;
|
|
30
37
|
mainModelConstructor?: new (...args: any[]) => T;
|
|
31
38
|
}) {
|
|
39
|
+
this.configService = options?.configService;
|
|
32
40
|
this.mainDbModel = options?.mainDbModel;
|
|
33
41
|
this.mainModelConstructor = options?.mainModelConstructor;
|
|
34
42
|
}
|
|
@@ -90,6 +98,14 @@ export abstract class ModuleService<T extends CoreModel = any> {
|
|
|
90
98
|
...options?.serviceOptions,
|
|
91
99
|
};
|
|
92
100
|
|
|
101
|
+
// Set default for ignoreSelections if not set
|
|
102
|
+
const ignoreSelections = this.configService?.getFastButReadOnly('ignoreSelectionsForPopulate', false);
|
|
103
|
+
if (ignoreSelections) {
|
|
104
|
+
if (config.processFieldSelection.ignoreSelections === undefined) {
|
|
105
|
+
config.processFieldSelection.ignoreSelections = ignoreSelections;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
93
109
|
// Note force configuration
|
|
94
110
|
if (config.force) {
|
|
95
111
|
config.checkRights = false;
|
|
@@ -104,6 +120,9 @@ export abstract class ModuleService<T extends CoreModel = any> {
|
|
|
104
120
|
// Note populate
|
|
105
121
|
if (config.populate) {
|
|
106
122
|
config.fieldSelection = config.populate;
|
|
123
|
+
if (config.processFieldSelection?.ignoreSelections) {
|
|
124
|
+
config.processFieldSelection.ignoreSelections = false;
|
|
125
|
+
}
|
|
107
126
|
}
|
|
108
127
|
|
|
109
128
|
// Prepare input
|
|
@@ -220,6 +239,7 @@ export abstract class ModuleService<T extends CoreModel = any> {
|
|
|
220
239
|
options: {
|
|
221
240
|
model?: new (...args: any[]) => T;
|
|
222
241
|
dbModel?: Model<T & Document>;
|
|
242
|
+
ignoreSelections?: boolean;
|
|
223
243
|
} = {}
|
|
224
244
|
) {
|
|
225
245
|
const config = {
|
|
@@ -227,6 +247,8 @@ export abstract class ModuleService<T extends CoreModel = any> {
|
|
|
227
247
|
dbModel: this.mainDbModel,
|
|
228
248
|
...options,
|
|
229
249
|
};
|
|
230
|
-
return popAndMap(data, fieldsSelection, config.model, config.dbModel
|
|
250
|
+
return popAndMap(data, fieldsSelection, config.model, config.dbModel, {
|
|
251
|
+
ignoreSelections: config.ignoreSelections,
|
|
252
|
+
});
|
|
231
253
|
}
|
|
232
254
|
}
|
|
@@ -22,10 +22,10 @@ export abstract class CoreUserService<
|
|
|
22
22
|
TUserCreateInput extends CoreUserCreateInput
|
|
23
23
|
> extends CrudService<TUser> {
|
|
24
24
|
protected constructor(
|
|
25
|
+
protected override readonly configService: ConfigService,
|
|
25
26
|
protected readonly emailService: EmailService,
|
|
26
27
|
protected override readonly mainDbModel: Model<TUser & Document>,
|
|
27
|
-
protected override readonly mainModelConstructor: CoreModelConstructor<TUser
|
|
28
|
-
protected readonly configService?: ConfigService
|
|
28
|
+
protected override readonly mainModelConstructor: CoreModelConstructor<TUser>
|
|
29
29
|
) {
|
|
30
30
|
super();
|
|
31
31
|
}
|
|
@@ -31,7 +31,7 @@ export class UserService extends CoreUserService<User, UserInput, UserCreateInpu
|
|
|
31
31
|
@InjectModel('User') protected override readonly mainDbModel: Model<UserDocument>,
|
|
32
32
|
@Inject('PUB_SUB') protected readonly pubSub: PubSub
|
|
33
33
|
) {
|
|
34
|
-
super(emailService, mainDbModel, mainModelConstructor);
|
|
34
|
+
super(configService, emailService, mainDbModel, mainModelConstructor);
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
// ===================================================================================================================
|