@node-c/api-rest 1.0.0-alpha4

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 (60) hide show
  1. package/README.md +4 -0
  2. package/dist/entityController/dto/base.dto.d.ts +5 -0
  3. package/dist/entityController/dto/base.dto.js +27 -0
  4. package/dist/entityController/dto/base.dto.js.map +1 -0
  5. package/dist/entityController/dto/bulkCreate.dto.d.ts +5 -0
  6. package/dist/entityController/dto/bulkCreate.dto.js +24 -0
  7. package/dist/entityController/dto/bulkCreate.dto.js.map +1 -0
  8. package/dist/entityController/dto/create.dto.d.ts +5 -0
  9. package/dist/entityController/dto/create.dto.js +24 -0
  10. package/dist/entityController/dto/create.dto.js.map +1 -0
  11. package/dist/entityController/dto/delete.dto.d.ts +5 -0
  12. package/dist/entityController/dto/delete.dto.js +23 -0
  13. package/dist/entityController/dto/delete.dto.js.map +1 -0
  14. package/dist/entityController/dto/find.dto.d.ts +11 -0
  15. package/dist/entityController/dto/find.dto.js +53 -0
  16. package/dist/entityController/dto/find.dto.js.map +1 -0
  17. package/dist/entityController/dto/findOne.dto.d.ts +8 -0
  18. package/dist/entityController/dto/findOne.dto.js +37 -0
  19. package/dist/entityController/dto/findOne.dto.js.map +1 -0
  20. package/dist/entityController/dto/index.d.ts +9 -0
  21. package/dist/entityController/dto/index.js +26 -0
  22. package/dist/entityController/dto/index.js.map +1 -0
  23. package/dist/entityController/dto/numberItem.dto.d.ts +5 -0
  24. package/dist/entityController/dto/numberItem.dto.js +27 -0
  25. package/dist/entityController/dto/numberItem.dto.js.map +1 -0
  26. package/dist/entityController/dto/update.dto.d.ts +7 -0
  27. package/dist/entityController/dto/update.dto.js +30 -0
  28. package/dist/entityController/dto/update.dto.js.map +1 -0
  29. package/dist/entityController/dto/uploadFile.dto.d.ts +4 -0
  30. package/dist/entityController/dto/uploadFile.dto.js +28 -0
  31. package/dist/entityController/dto/uploadFile.dto.js.map +1 -0
  32. package/dist/entityController/index.d.ts +3 -0
  33. package/dist/entityController/index.js +20 -0
  34. package/dist/entityController/index.js.map +1 -0
  35. package/dist/entityController/rest.entity.controller.d.ts +61 -0
  36. package/dist/entityController/rest.entity.controller.definitions.d.ts +14 -0
  37. package/dist/entityController/rest.entity.controller.definitions.js +3 -0
  38. package/dist/entityController/rest.entity.controller.definitions.js.map +1 -0
  39. package/dist/entityController/rest.entity.controller.js +294 -0
  40. package/dist/entityController/rest.entity.controller.js.map +1 -0
  41. package/dist/index.d.ts +1 -0
  42. package/dist/index.js +18 -0
  43. package/dist/index.js.map +1 -0
  44. package/package.json +23 -0
  45. package/src/entityController/dto/base.dto.ts +16 -0
  46. package/src/entityController/dto/bulkCreate.dto.ts +15 -0
  47. package/src/entityController/dto/create.dto.ts +15 -0
  48. package/src/entityController/dto/delete.dto.ts +11 -0
  49. package/src/entityController/dto/find.dto.ts +35 -0
  50. package/src/entityController/dto/findOne.dto.ts +22 -0
  51. package/src/entityController/dto/index.ts +9 -0
  52. package/src/entityController/dto/numberItem.dto.ts +12 -0
  53. package/src/entityController/dto/update.dto.ts +22 -0
  54. package/src/entityController/dto/uploadFile.dto.ts +12 -0
  55. package/src/entityController/index.ts +3 -0
  56. package/src/entityController/rest.entity.controller.definitions.ts +28 -0
  57. package/src/entityController/rest.entity.controller.ts +277 -0
  58. package/src/index.ts +1 -0
  59. package/tsconfig.build.json +9 -0
  60. package/tsconfig.json +9 -0
@@ -0,0 +1,277 @@
1
+ import {
2
+ Body,
3
+ Delete,
4
+ Get,
5
+ HttpException,
6
+ HttpStatus,
7
+ Param,
8
+ Patch,
9
+ Post,
10
+ Query,
11
+ Type,
12
+ UseInterceptors,
13
+ ValidationPipe
14
+ } from '@nestjs/common';
15
+
16
+ import { HTTPAuthorizationInterceptor, HTTPErrorInterceptor } from '@node-c/api-http';
17
+
18
+ import {
19
+ DomainBulkCreateResult,
20
+ DomainCreateResult,
21
+ DomainDeleteOptions,
22
+ DomainDeleteResult,
23
+ DomainEntityService,
24
+ DomainEntityServiceDefaultData,
25
+ DomainFindOneOptions,
26
+ DomainFindOneResult,
27
+ DomainFindOptions,
28
+ DomainFindResult,
29
+ DomainUpdateResult,
30
+ PersistanceEntityService
31
+ } from '@node-c/core';
32
+
33
+ import {
34
+ BulkCreateDto as BaseBulkCreateDto,
35
+ CreateDto as BaseCreateDto,
36
+ DeleteDto as BaseDeleteDto,
37
+ FindDto as BaseFindDto,
38
+ FindOneDto as BaseFindOneDto,
39
+ UpdateDto as BaseUpdateDto
40
+ } from './dto';
41
+ import {
42
+ BulkCreateBody,
43
+ BulkCreateOptions,
44
+ CreateBody,
45
+ CreateOptions,
46
+ UpdateBody,
47
+ UpdateOptions
48
+ } from './rest.entity.controller.definitions';
49
+
50
+ // These types and interfaces have to be here to avoid circular dependencies.
51
+ export type DefaultDomainEntityService<Entity> = DomainEntityService<
52
+ Entity,
53
+ PersistanceEntityService<Entity>,
54
+ DomainEntityServiceDefaultData<Entity>,
55
+ Record<string, PersistanceEntityService<Partial<Entity>>>
56
+ >;
57
+
58
+ export interface DefaultDtos<Entity> {
59
+ BulkCreate: BaseBulkCreateDto<Entity, BulkCreateOptions<Entity>>;
60
+ Create: BaseCreateDto<Entity, CreateOptions<Entity>>;
61
+ Delete: BaseDeleteDto<DomainDeleteOptions>;
62
+ Find: BaseFindDto<DomainFindOptions>;
63
+ FindOne: BaseFindOneDto<DomainFindOneOptions>;
64
+ Update: BaseUpdateDto<Entity, UpdateOptions<Entity>>;
65
+ }
66
+
67
+ @UseInterceptors(HTTPAuthorizationInterceptor, HTTPErrorInterceptor)
68
+ export class RESTAPIEntityControlerWithoutDto<Entity, EntityDomainService extends DefaultDomainEntityService<Entity>> {
69
+ inUseDefaultRoutes: { [handlerName: string]: boolean };
70
+
71
+ constructor(
72
+ // eslint-disable-next-line no-unused-vars
73
+ protected domainEntityService: EntityDomainService,
74
+ // eslint-disable-next-line no-unused-vars
75
+ protected defaultRouteMethods?: string[]
76
+ ) {
77
+ this.refreshDefaultRoutes();
78
+ }
79
+
80
+ protected checkRoute(handlerName: string): void {
81
+ if (!this.inUseDefaultRoutes || !this.inUseDefaultRoutes[handlerName]) {
82
+ throw new HttpException('Not found', HttpStatus.NOT_FOUND);
83
+ }
84
+ }
85
+
86
+ public bulkCreate(_body: BulkCreateBody<Entity>, ..._args: unknown[]): Promise<DomainBulkCreateResult<Entity> | void>;
87
+ @Post('bulk')
88
+ async bulkCreate(@Body() body: BulkCreateBody<Entity>): Promise<DomainBulkCreateResult<Entity>> {
89
+ this.checkRoute('bulkCreate');
90
+ const { data, ...options } = body;
91
+ return await this.domainEntityService.bulkCreate(data, options);
92
+ }
93
+
94
+ public create(_body: CreateBody<Entity>, ..._args: unknown[]): Promise<DomainCreateResult<Entity> | void>;
95
+ @Post()
96
+ async create(@Body() body: CreateBody<Entity>): Promise<DomainCreateResult<Entity>> {
97
+ this.checkRoute('create');
98
+ const { data, ...options } = body;
99
+ return await this.domainEntityService.create(data, options);
100
+ }
101
+
102
+ public delete(_body: DomainDeleteOptions, ..._args: unknown[]): Promise<DomainDeleteResult | void>;
103
+ @Delete()
104
+ async delete(@Body() body: DomainDeleteOptions): Promise<DomainDeleteResult> {
105
+ this.checkRoute('delete');
106
+ return await this.domainEntityService.delete(body);
107
+ }
108
+
109
+ public find(_query: DomainFindOptions, ..._args: unknown[]): Promise<DomainFindResult<Entity> | void>;
110
+ @Get()
111
+ async find(@Query() query: DomainFindOptions): Promise<DomainFindResult<Entity> | void> {
112
+ this.checkRoute('find');
113
+ return await this.domainEntityService.find(query);
114
+ }
115
+
116
+ public findOne(
117
+ _id: number | string,
118
+ _query: DomainFindOneOptions,
119
+ ..._args: unknown[]
120
+ ): Promise<DomainFindOneResult<Entity> | void>;
121
+ @Get('/item/:id')
122
+ async findOne(
123
+ @Param() id: number | string,
124
+ @Query() query: DomainFindOneOptions
125
+ ): Promise<DomainFindOneResult<Entity> | void> {
126
+ this.checkRoute('findOne');
127
+ let filters = query.filters;
128
+ if (!filters) {
129
+ filters = {};
130
+ query.filters = filters;
131
+ }
132
+ filters.id = id;
133
+ return await this.domainEntityService.findOne(query);
134
+ }
135
+
136
+ refreshDefaultRoutes(newDefaultRoutes?: string[]): void {
137
+ const defaultRouteMethods = newDefaultRoutes || this.defaultRouteMethods;
138
+ this.inUseDefaultRoutes = {};
139
+ if (defaultRouteMethods instanceof Array) {
140
+ defaultRouteMethods.forEach(item => (this.inUseDefaultRoutes[item] = true));
141
+ }
142
+ }
143
+
144
+ public update(_body: UpdateBody<Entity>, ..._args: unknown[]): Promise<DomainUpdateResult<Entity> | void>;
145
+ @Patch()
146
+ async update(@Body() body: UpdateBody<Entity>): Promise<DomainUpdateResult<Entity>> {
147
+ this.checkRoute('update');
148
+ return await this.domainEntityService.update(body.data, { filters: body.filters });
149
+ }
150
+ }
151
+
152
+ /*
153
+ * For reference on why the dto validation was done in this way - it's a limitation of Typescript itself:
154
+ * the compiler doesn't emit generic type metadata, making it impossible to achieve a DRY OOP base class with schema validation.
155
+ * At this point, it's a decade-old issue - see https://www.typescriptneedstypes.com/ for more details.
156
+ */
157
+ export class RESTAPIEntityControler<
158
+ Entity,
159
+ EntityDomainService extends DefaultDomainEntityService<Entity>,
160
+ Dto extends DefaultDtos<Entity> = DefaultDtos<Entity>
161
+ > extends RESTAPIEntityControlerWithoutDto<Entity, EntityDomainService> {
162
+ protected defaultRouteMethods: string[];
163
+ protected validationPipe: ValidationPipe;
164
+
165
+ constructor(
166
+ protected domainEntityService: EntityDomainService,
167
+ protected dto: {
168
+ bulkCreate?: Dto['BulkCreate'];
169
+ create?: Dto['Create'];
170
+ delete?: Dto['Delete'];
171
+ find?: Dto['Find'];
172
+ findOne?: Dto['FindOne'];
173
+ update?: Dto['Update'];
174
+ },
175
+ defaultRouteMethods?: string[]
176
+ ) {
177
+ super(domainEntityService, Object.keys(dto || {}).concat(defaultRouteMethods || []));
178
+ // const finalDto: typeof dto = {};
179
+ // finalDto.bulkCreate = dto?.bulkCreate || BaseBulkCreateDto<Entity, BulkCreateOptions<Entity>>;
180
+ this.validationPipe = new ValidationPipe({ whitelist: true });
181
+ }
182
+
183
+ @Post('bulk')
184
+ async bulkCreate(
185
+ @Body() body: Dto['BulkCreate'],
186
+ ...args: unknown[]
187
+ ): Promise<DomainBulkCreateResult<Entity> | void> {
188
+ return await super.bulkCreate.apply(this, [
189
+ await this.validationPipe.transform(body, {
190
+ metatype: this.dto.bulkCreate as unknown as Type,
191
+ type: 'body'
192
+ }),
193
+ ...(args || [])
194
+ ]);
195
+ }
196
+
197
+ @Post()
198
+ async create(
199
+ @Body()
200
+ body: Dto['Create'],
201
+ ...args: unknown[]
202
+ ): Promise<DomainCreateResult<Entity> | void> {
203
+ return await super.create.apply(this, [
204
+ await this.validationPipe.transform(body, {
205
+ metatype: this.dto.create as unknown as Type,
206
+ type: 'body'
207
+ }),
208
+ ...(args || [])
209
+ ]);
210
+ }
211
+
212
+ @Delete()
213
+ async delete(@Body() body: Dto['Delete'], ...args: unknown[]): Promise<DomainDeleteResult | void> {
214
+ return await super.delete.apply(this, [
215
+ await this.validationPipe.transform(body, {
216
+ metatype: this.dto.delete as unknown as Type,
217
+ type: 'body'
218
+ }),
219
+ ...(args || [])
220
+ ]);
221
+ }
222
+
223
+ @Get()
224
+ async find(@Query() query: Dto['Find'], ...args: unknown[]): Promise<DomainFindResult<Entity> | void> {
225
+ return await super.find.apply(this, [
226
+ await this.validationPipe.transform(query, {
227
+ metatype: this.dto.find as unknown as Type,
228
+ type: 'query'
229
+ }),
230
+ ...(args || [])
231
+ ]);
232
+ }
233
+
234
+ @Get('/item/:id')
235
+ async findOne(
236
+ @Param() id: number | string,
237
+ @Query() query: Dto['FindOne'],
238
+ ...args: unknown[]
239
+ ): Promise<DomainFindOneResult<Entity> | void> {
240
+ return await super.findOne.apply(this, [
241
+ id,
242
+ await this.validationPipe.transform(query, {
243
+ metatype: this.dto.findOne as unknown as Type,
244
+ type: 'query'
245
+ }),
246
+ ...(args || [])
247
+ ]);
248
+ }
249
+
250
+ static getDefaultDtos<EntityForDtos>(): {
251
+ bulkCreate: DefaultDtos<EntityForDtos>['BulkCreate'];
252
+ find: DefaultDtos<EntityForDtos>['Find'];
253
+ findOne: DefaultDtos<EntityForDtos>['FindOne'];
254
+ } {
255
+ return {
256
+ bulkCreate: BaseBulkCreateDto as unknown as DefaultDtos<EntityForDtos>['BulkCreate'],
257
+ find: BaseFindDto as unknown as DefaultDtos<EntityForDtos>['Find'],
258
+ findOne: BaseFindDto as unknown as DefaultDtos<EntityForDtos>['FindOne']
259
+ // create: BaseCreateDto,
260
+ // delete: BaseDeleteDto,
261
+ // find: BaseFindDto,
262
+ // findOne: BaseFindOneDto,
263
+ // update: BaseUpdateDto
264
+ };
265
+ }
266
+
267
+ @Patch()
268
+ async update(@Body() body: Dto['Update'], ...args: unknown[]): Promise<DomainUpdateResult<Entity> | void> {
269
+ return await super.update.apply(this, [
270
+ await this.validationPipe.transform(body, {
271
+ metatype: this.dto.update as unknown as Type,
272
+ type: 'body'
273
+ }),
274
+ ...(args || [])
275
+ ]);
276
+ }
277
+ }
package/src/index.ts ADDED
@@ -0,0 +1 @@
1
+ export * from './entityController';
@@ -0,0 +1,9 @@
1
+ {
2
+ "extends": "../../tsconfig.base.json",
3
+ "compilerOptions": {
4
+ "outDir": "dist",
5
+ "rootDir": "src"
6
+ },
7
+ "include": ["src"],
8
+ "exclude": ["node_modules", "dist", "src/**/*/*.spec.ts", "src/*.spec.ts", "src/vitest.config.ts"]
9
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,9 @@
1
+ {
2
+ "extends": "../../tsconfig.base.json",
3
+ "compilerOptions": {
4
+ "outDir": "dist",
5
+ "rootDir": "src"
6
+ },
7
+ "include": ["src"],
8
+ "exclude": ["node_modules", "dist"]
9
+ }