@lenne.tech/nest-server 3.2.0 → 3.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (142) hide show
  1. package/dist/core/common/args/filter.args.d.ts +5 -0
  2. package/dist/core/common/args/filter.args.js +10 -0
  3. package/dist/core/common/args/filter.args.js.map +1 -1
  4. package/dist/core/common/args/pagination.args.d.ts +8 -1
  5. package/dist/core/common/args/pagination.args.js +24 -6
  6. package/dist/core/common/args/pagination.args.js.map +1 -1
  7. package/dist/core/common/decorators/restricted.decorator.d.ts +3 -0
  8. package/dist/core/common/decorators/restricted.decorator.js +14 -5
  9. package/dist/core/common/decorators/restricted.decorator.js.map +1 -1
  10. package/dist/core/common/helpers/context.helper.js +15 -5
  11. package/dist/core/common/helpers/context.helper.js.map +1 -1
  12. package/dist/core/common/helpers/filter.helper.d.ts +3 -3
  13. package/dist/core/common/helpers/filter.helper.js.map +1 -1
  14. package/dist/core/common/helpers/graphql.helper.d.ts +4 -4
  15. package/dist/core/common/helpers/input.helper.js +13 -7
  16. package/dist/core/common/helpers/input.helper.js.map +1 -1
  17. package/dist/core/common/helpers/model.helper.js +0 -1
  18. package/dist/core/common/helpers/model.helper.js.map +1 -1
  19. package/dist/core/common/helpers/service.helper.d.ts +11 -8
  20. package/dist/core/common/helpers/service.helper.js +50 -12
  21. package/dist/core/common/helpers/service.helper.js.map +1 -1
  22. package/dist/core/common/inputs/combined-filter.input.d.ts +8 -2
  23. package/dist/core/common/inputs/combined-filter.input.js +16 -5
  24. package/dist/core/common/inputs/combined-filter.input.js.map +1 -1
  25. package/dist/core/common/inputs/core-input.input.d.ts +8 -0
  26. package/dist/core/common/inputs/core-input.input.js +15 -0
  27. package/dist/core/common/inputs/core-input.input.js.map +1 -0
  28. package/dist/core/common/inputs/filter.input.d.ts +7 -1
  29. package/dist/core/common/inputs/filter.input.js +14 -1
  30. package/dist/core/common/inputs/filter.input.js.map +1 -1
  31. package/dist/core/common/inputs/single-filter.input.d.ts +2 -1
  32. package/dist/core/common/inputs/single-filter.input.js +10 -1
  33. package/dist/core/common/inputs/single-filter.input.js.map +1 -1
  34. package/dist/core/common/inputs/sort.input.d.ts +2 -1
  35. package/dist/core/common/inputs/sort.input.js +7 -1
  36. package/dist/core/common/inputs/sort.input.js.map +1 -1
  37. package/dist/core/common/interceptors/check-response.interceptor.js +1 -1
  38. package/dist/core/common/interceptors/check-response.interceptor.js.map +1 -1
  39. package/dist/core/common/interfaces/core-persistence-model.interface.d.ts +1 -0
  40. package/dist/core/common/interfaces/server-options.interface.d.ts +3 -15
  41. package/dist/core/common/models/core-model.model.d.ts +6 -0
  42. package/dist/core/common/models/core-model.model.js +14 -5
  43. package/dist/core/common/models/core-model.model.js.map +1 -1
  44. package/dist/core/common/models/core-persistence.model.d.ts +5 -29
  45. package/dist/core/common/models/core-persistence.model.js +19 -41
  46. package/dist/core/common/models/core-persistence.model.js.map +1 -1
  47. package/dist/core/common/pipes/check-input.pipe.d.ts +2 -3
  48. package/dist/core/common/pipes/check-input.pipe.js +5 -20
  49. package/dist/core/common/pipes/check-input.pipe.js.map +1 -1
  50. package/dist/core/common/pipes/map-and-validate.pipe.d.ts +4 -0
  51. package/dist/core/common/pipes/map-and-validate.pipe.js +40 -0
  52. package/dist/core/common/pipes/map-and-validate.pipe.js.map +1 -0
  53. package/dist/core/common/types/plain-input.type.d.ts +3 -0
  54. package/dist/core/common/types/plain-input.type.js +3 -0
  55. package/dist/core/common/types/plain-input.type.js.map +1 -0
  56. package/dist/core/modules/auth/core-auth.model.d.ts +3 -1
  57. package/dist/core/modules/auth/core-auth.model.js +7 -1
  58. package/dist/core/modules/auth/core-auth.model.js.map +1 -1
  59. package/dist/core/modules/auth/core-auth.module.d.ts +5 -2
  60. package/dist/core/modules/auth/core-auth.module.js +25 -17
  61. package/dist/core/modules/auth/core-auth.module.js.map +1 -1
  62. package/dist/core/modules/auth/core-auth.resolver.d.ts +1 -1
  63. package/dist/core/modules/user/core-user.model.d.ts +3 -0
  64. package/dist/core/modules/user/core-user.model.js +9 -4
  65. package/dist/core/modules/user/core-user.model.js.map +1 -1
  66. package/dist/core/modules/user/core-user.service.d.ts +9 -13
  67. package/dist/core/modules/user/core-user.service.js +38 -67
  68. package/dist/core/modules/user/core-user.service.js.map +1 -1
  69. package/dist/core/modules/user/inputs/core-user-create.input.js.map +1 -1
  70. package/dist/core/modules/user/inputs/core-user.input.d.ts +2 -2
  71. package/dist/core/modules/user/inputs/core-user.input.js +3 -3
  72. package/dist/core/modules/user/inputs/core-user.input.js.map +1 -1
  73. package/dist/core.module.js +4 -4
  74. package/dist/core.module.js.map +1 -1
  75. package/dist/index.d.ts +6 -2
  76. package/dist/index.js +6 -2
  77. package/dist/index.js.map +1 -1
  78. package/dist/main.js +0 -2
  79. package/dist/main.js.map +1 -1
  80. package/dist/server/common/models/persistence.model.d.ts +4 -2
  81. package/dist/server/common/models/persistence.model.js +6 -2
  82. package/dist/server/common/models/persistence.model.js.map +1 -1
  83. package/dist/server/modules/auth/auth.model.d.ts +1 -0
  84. package/dist/server/modules/auth/auth.model.js +4 -0
  85. package/dist/server/modules/auth/auth.model.js.map +1 -1
  86. package/dist/server/modules/user/inputs/user-create.input.js.map +1 -1
  87. package/dist/server/modules/user/inputs/user.input.js.map +1 -1
  88. package/dist/server/modules/user/user.model.d.ts +3 -2
  89. package/dist/server/modules/user/user.model.js +9 -5
  90. package/dist/server/modules/user/user.model.js.map +1 -1
  91. package/dist/server/modules/user/user.resolver.d.ts +2 -2
  92. package/dist/server/modules/user/user.resolver.js +11 -13
  93. package/dist/server/modules/user/user.resolver.js.map +1 -1
  94. package/dist/server/modules/user/user.service.d.ts +6 -6
  95. package/dist/server/modules/user/user.service.js +12 -4
  96. package/dist/server/modules/user/user.service.js.map +1 -1
  97. package/dist/test/test.helper.d.ts +1 -1
  98. package/dist/tsconfig.build.tsbuildinfo +1 -1
  99. package/package.json +26 -26
  100. package/src/core/common/args/filter.args.ts +22 -1
  101. package/src/core/common/args/pagination.args.ts +42 -7
  102. package/src/core/common/decorators/restricted.decorator.ts +22 -5
  103. package/src/core/common/helpers/context.helper.ts +14 -3
  104. package/src/core/common/helpers/filter.helper.ts +3 -3
  105. package/src/core/common/helpers/input.helper.ts +17 -11
  106. package/src/core/common/helpers/model.helper.ts +0 -3
  107. package/src/core/common/helpers/service.helper.ts +95 -30
  108. package/src/core/common/inputs/combined-filter.input.ts +30 -9
  109. package/src/core/common/inputs/core-input.input.ts +36 -0
  110. package/src/core/common/inputs/filter.input.ts +27 -3
  111. package/src/core/common/inputs/single-filter.input.ts +7 -6
  112. package/src/core/common/inputs/sort.input.ts +4 -3
  113. package/src/core/common/interceptors/check-response.interceptor.ts +2 -2
  114. package/src/core/common/interfaces/core-persistence-model.interface.ts +1 -0
  115. package/src/core/common/interfaces/server-options.interface.ts +3 -33
  116. package/src/core/common/models/core-model.model.ts +42 -3
  117. package/src/core/common/models/core-persistence.model.ts +33 -120
  118. package/src/core/common/pipes/check-input.pipe.ts +13 -33
  119. package/src/core/common/pipes/map-and-validate.pipe.ts +32 -0
  120. package/src/core/common/types/plain-input.type.ts +6 -0
  121. package/src/core/modules/auth/core-auth.model.ts +15 -1
  122. package/src/core/modules/auth/core-auth.module.ts +38 -22
  123. package/src/core/modules/auth/core-auth.resolver.ts +1 -1
  124. package/src/core/modules/user/core-user.model.ts +16 -4
  125. package/src/core/modules/user/core-user.service.ts +59 -115
  126. package/src/core/modules/user/inputs/core-user-create.input.ts +4 -0
  127. package/src/core/modules/user/inputs/core-user.input.ts +7 -3
  128. package/src/core.module.ts +13 -6
  129. package/src/index.ts +6 -2
  130. package/src/main.ts +0 -4
  131. package/src/server/common/models/persistence.model.ts +16 -2
  132. package/src/server/modules/auth/auth.model.ts +13 -0
  133. package/src/server/modules/user/inputs/user-create.input.ts +4 -0
  134. package/src/server/modules/user/inputs/user.input.ts +4 -0
  135. package/src/server/modules/user/user.model.ts +18 -5
  136. package/src/server/modules/user/user.resolver.ts +15 -19
  137. package/src/server/modules/user/user.service.ts +22 -7
  138. package/src/test/test.helper.ts +1 -1
  139. package/dist/core/common/pipes/map.pipe.d.ts +0 -4
  140. package/dist/core/common/pipes/map.pipe.js +0 -25
  141. package/dist/core/common/pipes/map.pipe.js.map +0 -1
  142. package/src/core/common/pipes/map.pipe.ts +0 -16
@@ -0,0 +1,36 @@
1
+ import { ModelHelper } from '../helpers/model.helper';
2
+ import { CoreModel } from '../models/core-model.model';
3
+
4
+ /**
5
+ * Core Input
6
+ *
7
+ * All properties (in this class and all classes that extend this class) must be initialized with undefined!
8
+ *
9
+ * In contrast to the core model, properties that are undefined are completely removed from the instance during mapping,
10
+ * so that no existing data is overwritten when a data set is updated, for example. However, re-mapping causes the
11
+ * removed properties to be ignored and no longer automatically integrated into the instance. They must then be
12
+ * reactivated by direct assignment `instance.property = ...`.
13
+ */
14
+ export abstract class CoreInput extends CoreModel {
15
+ /**
16
+ * Map method
17
+ */
18
+ public map(
19
+ data: Partial<this> | Record<string, any>,
20
+ options: {
21
+ cloneDeep?: boolean;
22
+ funcAllowed?: boolean;
23
+ mapId?: boolean;
24
+ } = {}
25
+ ): this {
26
+ const config = {
27
+ cloneDeep: false,
28
+ funcAllowed: false,
29
+ mapId: false,
30
+ ...options,
31
+ };
32
+ const coreInput = ModelHelper.map(data, this, config);
33
+ Object.keys(coreInput).forEach((key) => coreInput[key] === undefined && delete coreInput[key]);
34
+ return coreInput;
35
+ }
36
+ }
@@ -1,5 +1,7 @@
1
1
  import { Field, InputType } from '@nestjs/graphql';
2
+ import { ModelHelper } from '../helpers/model.helper';
2
3
  import { CombinedFilterInput } from './combined-filter.input';
4
+ import { CoreInput } from './core-input.input';
3
5
  import { SingleFilterInput } from './single-filter.input';
4
6
 
5
7
  /**
@@ -8,7 +10,7 @@ import { SingleFilterInput } from './single-filter.input';
8
10
  @InputType({
9
11
  description: 'Input for filtering. The `singleFilter` will be ignored if the `combinedFilter` is set.',
10
12
  })
11
- export class FilterInput {
13
+ export class FilterInput extends CoreInput {
12
14
  /**
13
15
  * Combination of multiple filters via logical operator
14
16
  */
@@ -16,7 +18,7 @@ export class FilterInput {
16
18
  description: 'Combination of multiple filters via logical operator',
17
19
  nullable: true,
18
20
  })
19
- combinedFilter?: CombinedFilterInput;
21
+ combinedFilter?: CombinedFilterInput = undefined;
20
22
 
21
23
  /**
22
24
  * Filter for a single property
@@ -25,5 +27,27 @@ export class FilterInput {
25
27
  description: 'Filter for a single property',
26
28
  nullable: true,
27
29
  })
28
- singleFilter?: SingleFilterInput;
30
+ singleFilter?: SingleFilterInput = undefined;
31
+
32
+ // ===================================================================================================================
33
+ // Methods
34
+ // ===================================================================================================================
35
+
36
+ /**
37
+ * Mapping for Subtypes
38
+ */
39
+ map(
40
+ data: Partial<this> | Record<string, any>,
41
+ options: {
42
+ cloneDeep?: boolean;
43
+ funcAllowed?: boolean;
44
+ mapId?: boolean;
45
+ } = {}
46
+ ): this {
47
+ super.map(data, options);
48
+ this.combinedFilter = data.combinedFilter ? CombinedFilterInput.map(data.combinedFilter, options) : undefined;
49
+ this.singleFilter = data.singleFilter ? SingleFilterInput.map(data.singleFilter, options) : undefined;
50
+ Object.keys(this).forEach((key) => this[key] === undefined && delete this[key]);
51
+ return this;
52
+ }
29
53
  }
@@ -1,17 +1,18 @@
1
1
  import { Field, InputType } from '@nestjs/graphql';
2
2
  import { ComparisonOperatorEnum } from '../enums/comparison-operator.enum';
3
3
  import { JSON } from '../scalars/json.scalar';
4
+ import { CoreInput } from './core-input.input';
4
5
 
5
6
  /**
6
7
  * Input for a configuration of a filter
7
8
  */
8
9
  @InputType({ description: 'Input for a configuration of a filter' })
9
- export class SingleFilterInput {
10
+ export class SingleFilterInput extends CoreInput {
10
11
  /**
11
12
  * Name of the property to be used for the filter'
12
13
  */
13
14
  @Field({ description: 'Name of the property to be used for the filter' })
14
- field: string;
15
+ field: string = undefined;
15
16
 
16
17
  /**
17
18
  * [Negate operator](https://docs.mongodb.com/manual/reference/operator/query/not/)
@@ -20,7 +21,7 @@ export class SingleFilterInput {
20
21
  description: '[Negate operator](https://docs.mongodb.com/manual/reference/operator/query/not/)',
21
22
  nullable: true,
22
23
  })
23
- not?: boolean;
24
+ not?: boolean = undefined;
24
25
 
25
26
  /**
26
27
  * [Comparison operator](https://docs.mongodb.com/manual/reference/operator/query-comparison/)
@@ -28,7 +29,7 @@ export class SingleFilterInput {
28
29
  @Field((type) => ComparisonOperatorEnum, {
29
30
  description: '[Comparison operator](https://docs.mongodb.com/manual/reference/operator/query-comparison/)',
30
31
  })
31
- operator: ComparisonOperatorEnum;
32
+ operator: ComparisonOperatorEnum = undefined;
32
33
 
33
34
  /**
34
35
  * [Options](https://docs.mongodb.com/manual/reference/operator/query/regex/#op._S_options) for
@@ -40,8 +41,8 @@ export class SingleFilterInput {
40
41
  '[REGEX](https://docs.mongodb.com/manual/reference/operator/query/regex/) operator',
41
42
  nullable: true,
42
43
  })
43
- options?: string;
44
+ options?: string = undefined;
44
45
 
45
46
  @Field((type) => JSON, { description: 'Value of the property' })
46
- value: any;
47
+ value: any = undefined;
47
48
  }
@@ -1,20 +1,21 @@
1
1
  import { Field, InputType } from '@nestjs/graphql';
2
2
  import { SortOrderEnum } from '../enums/sort-order.emum';
3
+ import { CoreInput } from './core-input.input';
3
4
 
4
5
  /**
5
6
  * Sorting the returned elements
6
7
  */
7
8
  @InputType({ description: 'Sorting the returned elements' })
8
- export class SortInput {
9
+ export class SortInput extends CoreInput {
9
10
  /**
10
11
  * Field that is to be used for sorting
11
12
  */
12
13
  @Field({ description: 'Field that is to be used for sorting' })
13
- field: string;
14
+ field: string = undefined;
14
15
 
15
16
  /**
16
17
  * SortInput order of the field
17
18
  */
18
19
  @Field((type) => SortOrderEnum, { description: 'SortInput order of the field' })
19
- order: SortOrderEnum;
20
+ order: SortOrderEnum = undefined;
20
21
  }
@@ -19,8 +19,8 @@ export class CheckResponseInterceptor implements NestInterceptor {
19
19
  // Response interception
20
20
  return next.handle().pipe(
21
21
  map((data) => {
22
- // Prepare data for current user
23
- return checkRestricted(data, currentUser);
22
+ // Prepare response data for current user
23
+ return checkRestricted(data, currentUser, { throwError: false });
24
24
  })
25
25
  );
26
26
  }
@@ -12,5 +12,6 @@ export interface ICorePersistenceModel<T extends CorePersistenceModel = any> {
12
12
  merge?: boolean;
13
13
  }
14
14
  ): any;
15
+ init(this: new (...args: any[]) => T, ...args: any[]): any;
15
16
  [key: string]: any;
16
17
  }
@@ -1,8 +1,8 @@
1
- import { GqlModuleOptions } from '@nestjs/graphql';
1
+ import { ApolloDriverConfig } from '@nestjs/apollo';
2
2
  import { JwtModuleOptions } from '@nestjs/jwt';
3
+ import { MongooseModuleOptions } from '@nestjs/mongoose/dist/interfaces/mongoose-options.interface';
3
4
  import { ServeStaticOptions } from '@nestjs/platform-express/interfaces/serve-static-options.interface';
4
5
  import * as SMTPTransport from 'nodemailer/lib/smtp-transport';
5
- import { MongooseModuleOptions } from '@nestjs/mongoose/dist/interfaces/mongoose-options.interface';
6
6
  import { MailjetOptions } from './mailjet-options.interface';
7
7
 
8
8
  /**
@@ -20,37 +20,7 @@ export interface IServerOptions {
20
20
  * see https://docs.nestjs.com/graphql/quick-start
21
21
  * and https://www.apollographql.com/docs/apollo-server/api/apollo-server/
22
22
  */
23
- graphQl?: {
24
- /**
25
- * Autogenerated schema file
26
- * e.g. 'schema.gql'
27
- */
28
- autoSchemaFile?: string;
29
-
30
- /**
31
- * Function for context manipulation
32
- * e.g. ({ req }) => ({ req })
33
- */
34
- context?: (context: { [key: string]: any; req: any }) => { [key: string]: any; req: any };
35
-
36
- /**
37
- * Enables and disables development mode helpers of apollo
38
- * e.g. true
39
- */
40
- debug?: boolean;
41
-
42
- /**
43
- * Determines whether or not to install subscription handlers
44
- * e.g. true
45
- */
46
- installSubscriptionHandlers?: boolean;
47
-
48
- /**
49
- * Enables and disables schema introspection
50
- * e.g. true
51
- */
52
- introspection?: boolean;
53
- } & GqlModuleOptions;
23
+ graphQl?: ApolloDriverConfig;
54
24
 
55
25
  /**
56
26
  * Configuration of JavaScript Web Token (JWT) module
@@ -2,8 +2,23 @@ import { ModelHelper } from '../helpers/model.helper';
2
2
 
3
3
  /**
4
4
  * Core Model
5
+ *
6
+ * HINT: All properties (in this class and all classes that extend this class) must be initialized with a default
7
+ * value or undefined otherwise the property will not be recognized via Object.keys (this is necessary for mapping).
8
+ * If the property is initialized with a default value (e.g. an empty array or boolean), there is a risk that the
9
+ * current value will be overwritten during mapping without this being intentional, so all values should be initialized
10
+ * with undefined if possible. If necessary and useful, the init method can then be used deliberately:
11
+ * const coreModel = item ? CoreModel.map(item).init() : CoreModel.init();
5
12
  */
6
13
  export abstract class CoreModel {
14
+ /**
15
+ * Static init method
16
+ */
17
+ public static init<T extends CoreModel>(this: new (...args: any[]) => T, ...args: any[]): T {
18
+ const item = new this();
19
+ return item.init(args);
20
+ }
21
+
7
22
  /**
8
23
  * Static map method
9
24
  */
@@ -13,13 +28,19 @@ export abstract class CoreModel {
13
28
  options: {
14
29
  cloneDeep?: boolean;
15
30
  funcAllowed?: boolean;
31
+ init?: any;
16
32
  item?: T;
17
33
  mapId?: boolean;
18
34
  } = {}
19
35
  ): T {
36
+ const config = {
37
+ init: true,
38
+ ...options,
39
+ };
40
+
20
41
  const item = options.item || new this();
21
42
  delete options.item;
22
- return item.map(data, options);
43
+ return item.map(data, config);
23
44
  }
24
45
 
25
46
  /**
@@ -36,13 +57,27 @@ export abstract class CoreModel {
36
57
  options: {
37
58
  cloneDeep?: boolean;
38
59
  funcAllowed?: boolean;
60
+ init?: any;
39
61
  item?: T;
40
62
  mapId?: boolean;
41
63
  } = {}
42
64
  ): T {
65
+ const config = {
66
+ init: true,
67
+ ...options,
68
+ };
69
+
43
70
  const item = options.item || new this();
44
71
  delete options.item;
45
- return item.mapDeep(data, options);
72
+ return item.mapDeep(data, config);
73
+ }
74
+
75
+ /**
76
+ * Initialize instance with default values instead of undefined
77
+ * Should be overwritten in child class to organize the defaults
78
+ */
79
+ public init<T extends CoreModel>(...args: any[]): this {
80
+ return this;
46
81
  }
47
82
 
48
83
  /**
@@ -53,16 +88,18 @@ export abstract class CoreModel {
53
88
  options: {
54
89
  cloneDeep?: boolean;
55
90
  funcAllowed?: boolean;
91
+ init?: any;
56
92
  mapId?: boolean;
57
93
  } = {}
58
94
  ): this {
59
95
  const config = {
60
96
  cloneDeep: false,
61
97
  funcAllowed: false,
98
+ init: undefined,
62
99
  mapId: false,
63
100
  ...options,
64
101
  };
65
- return ModelHelper.map(data, this, config);
102
+ return config.init ? ModelHelper.map(data, this, config).init(config.init) : ModelHelper.map(data, this, config);
66
103
  }
67
104
 
68
105
  /**
@@ -78,12 +115,14 @@ export abstract class CoreModel {
78
115
  options: {
79
116
  cloneDeep?: boolean;
80
117
  funcAllowed?: boolean;
118
+ init?: any;
81
119
  mapId?: boolean;
82
120
  } = {}
83
121
  ): this {
84
122
  const config = {
85
123
  cloneDeep: true,
86
124
  funcAllowed: false,
125
+ init: undefined,
87
126
  mapId: false,
88
127
  ...options,
89
128
  };
@@ -1,32 +1,38 @@
1
1
  import { Field, ID, ObjectType } from '@nestjs/graphql';
2
- import * as _ from 'lodash';
3
- import { ModelHelper } from '../helpers/model.helper';
4
2
  import { Prop, Schema } from '@nestjs/mongoose';
5
- import * as mongoose from 'mongoose';
3
+ import { Types } from 'mongoose';
4
+ import { CoreModel } from './core-model.model';
6
5
 
7
6
  /**
8
7
  * Metadata for persistent objects
9
8
  *
10
9
  * The models are a combination of Mongoose Entities and TypeGraphQL Types
10
+ *
11
+ * HINT: All properties (in this class and all classes that extend this class) must be initialized with a default
12
+ * value or undefined otherwise the property will not be recognized via Object.keys (this is necessary for mapping).
13
+ * If the property is initialized with a default value (e.g. an empty array or boolean), there is a risk that the
14
+ * current value will be overwritten during mapping without this being intentional, so all values should be initialized
15
+ * with undefined if possible. If necessary and useful, the init method can then be used deliberately:
16
+ * const corePersistenceModel = item ? CorePersistenceModel.map(item).init() : CorePersistenceModel.init();
11
17
  */
12
18
  @ObjectType({
13
19
  description: 'Persistence model which will be saved in DB',
14
20
  isAbstract: true,
15
21
  })
16
- @Schema()
17
- export abstract class CorePersistenceModel {
22
+ @Schema({ timestamps: true })
23
+ export abstract class CorePersistenceModel extends CoreModel {
18
24
  // ===========================================================================
19
25
  // Getter
20
26
  // ===========================================================================
27
+
21
28
  get _id() {
22
- return new mongoose.Types.ObjectId(this.id);
29
+ return new Types.ObjectId(this.id);
23
30
  }
24
31
 
25
32
  // ===========================================================================
26
33
  // Properties
27
- //
28
- // TestFields: https://typegraphql.ml/docs/types-and-fields.html
29
34
  // ===========================================================================
35
+
30
36
  /**
31
37
  * ID of the persistence object as string
32
38
  */
@@ -37,11 +43,11 @@ export abstract class CorePersistenceModel {
37
43
  id: string = undefined;
38
44
 
39
45
  /**
40
- * Created date
46
+ * Created date, is set automatically by mongoose
41
47
  */
42
48
  @Field({ description: 'Created date', nullable: true })
43
- @Prop()
44
- createdAt: Date = new Date();
49
+ @Prop({ onCreate: () => new Date() })
50
+ createdAt: Date = undefined;
45
51
 
46
52
  /**
47
53
  * Labels of the object
@@ -51,7 +57,7 @@ export abstract class CorePersistenceModel {
51
57
  nullable: true,
52
58
  })
53
59
  @Prop([String])
54
- labels: string[] = [];
60
+ labels: string[] = undefined;
55
61
 
56
62
  /**
57
63
  * IDs of the Owners
@@ -61,7 +67,7 @@ export abstract class CorePersistenceModel {
61
67
  nullable: true,
62
68
  })
63
69
  @Prop([String])
64
- ownerIds: string[] = [];
70
+ ownerIds: string[] = undefined;
65
71
 
66
72
  /**
67
73
  * Tags for the object
@@ -71,122 +77,29 @@ export abstract class CorePersistenceModel {
71
77
  nullable: true,
72
78
  })
73
79
  @Prop([String])
74
- tags: string[] = [];
80
+ tags: string[] = undefined;
75
81
 
76
82
  /**
77
- * Updated date
83
+ * Updated date is set automatically by mongoose
78
84
  */
79
85
  @Field({ description: 'Updated date', nullable: true })
80
86
  @Prop({ onUpdate: () => new Date() })
81
- updatedAt: Date = new Date();
82
-
83
- /**
84
- * Static map method
85
- */
86
- public static map<T extends CorePersistenceModel>(
87
- this: new (...args: any[]) => T,
88
- data: Partial<T> | Record<string, any>,
89
- options: {
90
- cloneDeep?: boolean;
91
- funcAllowed?: boolean;
92
- item?: T;
93
- mapId?: boolean;
94
- merge?: boolean;
95
- } = {}
96
- ): T {
97
- const item = options.item || new this();
98
- delete options.item;
99
- return item.map(data, options);
100
- }
87
+ updatedAt: Date = undefined;
101
88
 
102
- /**
103
- * Static map deep method
104
- *
105
- * Alias for map with cloneDeep = true
106
- *
107
- * MapDeep prevents side effects, because objects will be cloned
108
- * (cloneDeep = true), but it will be slower than a simple map
109
- */
110
- public static mapDeep<T extends CorePersistenceModel>(
111
- this: new (...args: any[]) => T,
112
- data: Partial<T> | Record<string, any>,
113
- options: {
114
- cloneDeep?: boolean;
115
- funcAllowed?: boolean;
116
- item?: T;
117
- mapId?: boolean;
118
- merge?: boolean;
119
- } = {}
120
- ): T {
121
- const item = options.item || new this();
122
- delete options.item;
123
- return item.mapDeep(data, options);
124
- }
89
+ // ===========================================================================
90
+ // Methods
91
+ // ===========================================================================
125
92
 
126
93
  /**
127
- * Map method
94
+ * Initialize instance with default values instead of undefined
128
95
  */
129
- public map(
130
- data: Partial<this> | Record<string, any>,
131
- options: {
132
- cloneDeep?: boolean;
133
- funcAllowed?: boolean;
134
- mapId?: boolean;
135
- merge?: boolean;
136
- } = {}
137
- ): this {
138
- const config = {
139
- cloneDeep: false,
140
- funcAllowed: false,
141
- mapId: false,
142
- merge: false,
143
- ...options,
144
- };
145
-
146
- // Prepare data
147
- let preparedData = data;
148
- preparedData = ModelHelper.prepareMap(preparedData, this, config);
149
- if (config.cloneDeep) {
150
- preparedData = _.cloneDeep(preparedData);
151
- }
152
-
153
- // Assign
154
- if (this['assign'] !== 'function') {
155
- if (!config.merge) {
156
- Object.assign(this, preparedData);
157
- }
158
- } else {
159
- this['assign'](preparedData, { mergeObjects: config.merge });
160
- }
161
-
162
- // Return
96
+ init() {
97
+ super.init();
98
+ this.createdAt = this.createdAt === undefined ? new Date() : this.createdAt;
99
+ this.labels = this.labels === undefined ? [] : this.labels;
100
+ this.ownerIds = this.ownerIds === undefined ? [] : this.ownerIds;
101
+ this.tags = this.tags === undefined ? [] : this.tags;
102
+ this.updatedAt = this.tags === undefined ? this.createdAt : this.updatedAt;
163
103
  return this;
164
104
  }
165
-
166
- /**
167
- * Map deep method
168
- *
169
- * Alias for map with cloneDeep = true
170
- *
171
- * MapDeep prevents side effects, because objects will be cloned
172
- * (cloneDeep = true), but it will be slower than a simple map
173
- */
174
- public mapDeep(
175
- data: Partial<this> | Record<string, any>,
176
- options: {
177
- cloneDeep?: boolean;
178
- funcAllowed?: boolean;
179
- mapId?: boolean;
180
- merge?: boolean;
181
- } = {}
182
- ): this {
183
- const config = {
184
- cloneDeep: true,
185
- funcAllowed: false,
186
- mapId: false,
187
- merge: false,
188
- ...options,
189
- };
190
- return this.map(data, config);
191
- }
192
105
  }
@@ -1,16 +1,17 @@
1
- import { ArgumentMetadata, BadRequestException, Inject, Injectable, PipeTransform, Scope } from '@nestjs/common';
1
+ import { ArgumentMetadata, Inject, Injectable, PipeTransform } from '@nestjs/common';
2
2
  import { CONTEXT } from '@nestjs/graphql';
3
- import { plainToClass } from 'class-transformer';
4
- import { validate, ValidationError } from 'class-validator';
5
- import { checkRestricted } from '../decorators/restricted.decorator';
6
3
  import { Context } from '../helpers/context.helper';
4
+ import { InputHelper } from '../helpers/input.helper';
7
5
 
8
6
  /**
9
7
  * The CheckInputPipe checks the permissibility of individual properties of inputs for the resolvers
10
8
  * in relation to the current user
9
+ *
10
+ * ATTENTION: Pipe does not work yet, because context is missing: https://github.com/nestjs/graphql/issues/325
11
+ * Once this works MapAndValidate can be replaced in the CoreModule with this pipe.
11
12
  */
12
- @Injectable({ scope: Scope.REQUEST })
13
- export class CheckInputPipe implements PipeTransform<any> {
13
+ @Injectable()
14
+ export class CheckInputPipe implements PipeTransform {
14
15
  /**
15
16
  * Constructor to inject context
16
17
  */
@@ -19,35 +20,14 @@ export class CheckInputPipe implements PipeTransform<any> {
19
20
  /**
20
21
  * Check input
21
22
  */
22
- async transform(value: any, { metatype }: ArgumentMetadata) {
23
- // Return value if it is only a basic type
24
- if (!metatype || this.isBasicType(metatype)) {
25
- return value;
26
- }
23
+ async transform(value: any, metadata: ArgumentMetadata) {
24
+ // Get meta type
25
+ const metatype = metadata?.metatype;
27
26
 
28
- // Remove restricted values if roles are missing
27
+ // Get user
29
28
  const { user }: any = Context.getData(this.context);
30
- value = checkRestricted(value, user);
31
29
 
32
- // Validate value
33
- const plainValue = JSON.parse(JSON.stringify(value));
34
- const object = plainToClass(metatype, plainValue);
35
- const errors: ValidationError[] = await validate(object);
36
-
37
- // Check errors
38
- if (errors.length > 0) {
39
- throw new BadRequestException('Validation failed');
40
- }
41
-
42
- // Everything is ok
43
- return value;
44
- }
45
-
46
- /**
47
- * Checks if it is a basic type
48
- */
49
- protected isBasicType(metatype: any): boolean {
50
- const types = [String, Boolean, Number, Array, Object, Buffer, ArrayBuffer];
51
- return types.includes(metatype);
30
+ // Check and return
31
+ return InputHelper.check(value, user, metatype);
52
32
  }
53
33
  }
@@ -0,0 +1,32 @@
1
+ import { PipeTransform, Injectable, ArgumentMetadata, BadRequestException } from '@nestjs/common';
2
+ import { plainToInstance } from 'class-transformer';
3
+ import { validate } from 'class-validator';
4
+ import { InputHelper } from '../helpers/input.helper';
5
+
6
+ @Injectable()
7
+ export class MapAndValidatePipe implements PipeTransform {
8
+ async transform(value: any, metadata: ArgumentMetadata) {
9
+ const { metatype } = metadata;
10
+
11
+ if (typeof value !== 'object' || !metatype || InputHelper.isBasicType(metatype)) {
12
+ return value;
13
+ }
14
+
15
+ // Convert to metatype
16
+ if (!(value instanceof metatype)) {
17
+ if ((metatype as any)?.map) {
18
+ value = (metatype as any)?.map(value);
19
+ } else {
20
+ value = plainToInstance(metatype, value);
21
+ }
22
+ }
23
+
24
+ // Validate
25
+ const errors = await validate(value);
26
+ if (errors.length > 0) {
27
+ throw new BadRequestException('Input validation failed');
28
+ }
29
+
30
+ return value;
31
+ }
32
+ }
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Type for plain Inputs
3
+ */
4
+ export type PlainInput<T> = {
5
+ [P in keyof T]?: Partial<T[P]> | Partial<PlainInput<T[P]>>;
6
+ };