@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.
- package/README.md +4 -0
- package/dist/entityController/dto/base.dto.d.ts +5 -0
- package/dist/entityController/dto/base.dto.js +27 -0
- package/dist/entityController/dto/base.dto.js.map +1 -0
- package/dist/entityController/dto/bulkCreate.dto.d.ts +5 -0
- package/dist/entityController/dto/bulkCreate.dto.js +24 -0
- package/dist/entityController/dto/bulkCreate.dto.js.map +1 -0
- package/dist/entityController/dto/create.dto.d.ts +5 -0
- package/dist/entityController/dto/create.dto.js +24 -0
- package/dist/entityController/dto/create.dto.js.map +1 -0
- package/dist/entityController/dto/delete.dto.d.ts +5 -0
- package/dist/entityController/dto/delete.dto.js +23 -0
- package/dist/entityController/dto/delete.dto.js.map +1 -0
- package/dist/entityController/dto/find.dto.d.ts +11 -0
- package/dist/entityController/dto/find.dto.js +53 -0
- package/dist/entityController/dto/find.dto.js.map +1 -0
- package/dist/entityController/dto/findOne.dto.d.ts +8 -0
- package/dist/entityController/dto/findOne.dto.js +37 -0
- package/dist/entityController/dto/findOne.dto.js.map +1 -0
- package/dist/entityController/dto/index.d.ts +9 -0
- package/dist/entityController/dto/index.js +26 -0
- package/dist/entityController/dto/index.js.map +1 -0
- package/dist/entityController/dto/numberItem.dto.d.ts +5 -0
- package/dist/entityController/dto/numberItem.dto.js +27 -0
- package/dist/entityController/dto/numberItem.dto.js.map +1 -0
- package/dist/entityController/dto/update.dto.d.ts +7 -0
- package/dist/entityController/dto/update.dto.js +30 -0
- package/dist/entityController/dto/update.dto.js.map +1 -0
- package/dist/entityController/dto/uploadFile.dto.d.ts +4 -0
- package/dist/entityController/dto/uploadFile.dto.js +28 -0
- package/dist/entityController/dto/uploadFile.dto.js.map +1 -0
- package/dist/entityController/index.d.ts +3 -0
- package/dist/entityController/index.js +20 -0
- package/dist/entityController/index.js.map +1 -0
- package/dist/entityController/rest.entity.controller.d.ts +61 -0
- package/dist/entityController/rest.entity.controller.definitions.d.ts +14 -0
- package/dist/entityController/rest.entity.controller.definitions.js +3 -0
- package/dist/entityController/rest.entity.controller.definitions.js.map +1 -0
- package/dist/entityController/rest.entity.controller.js +294 -0
- package/dist/entityController/rest.entity.controller.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +18 -0
- package/dist/index.js.map +1 -0
- package/package.json +23 -0
- package/src/entityController/dto/base.dto.ts +16 -0
- package/src/entityController/dto/bulkCreate.dto.ts +15 -0
- package/src/entityController/dto/create.dto.ts +15 -0
- package/src/entityController/dto/delete.dto.ts +11 -0
- package/src/entityController/dto/find.dto.ts +35 -0
- package/src/entityController/dto/findOne.dto.ts +22 -0
- package/src/entityController/dto/index.ts +9 -0
- package/src/entityController/dto/numberItem.dto.ts +12 -0
- package/src/entityController/dto/update.dto.ts +22 -0
- package/src/entityController/dto/uploadFile.dto.ts +12 -0
- package/src/entityController/index.ts +3 -0
- package/src/entityController/rest.entity.controller.definitions.ts +28 -0
- package/src/entityController/rest.entity.controller.ts +277 -0
- package/src/index.ts +1 -0
- package/tsconfig.build.json +9 -0
- 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';
|