@flusys/nestjs-shared 5.1.1 → 5.1.3
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/cjs/classes/api-controller.class.js +16 -10
- package/cjs/classes/api-service.class.js +67 -35
- package/cjs/classes/index.js +0 -1
- package/cjs/dtos/identity-response.dto.js +4 -8
- package/cjs/entities/identity.js +8 -2
- package/cjs/modules/datasource/index.js +0 -1
- package/cjs/modules/datasource/multi-tenant-datasource.service.js +24 -85
- package/classes/api-controller.class.d.ts +1 -0
- package/classes/api-service.class.d.ts +13 -6
- package/classes/index.d.ts +0 -1
- package/decorators/current-user.decorator.d.ts +1 -1
- package/fesm/classes/api-controller.class.js +16 -10
- package/fesm/classes/api-service.class.js +70 -38
- package/fesm/classes/index.js +0 -1
- package/fesm/dtos/identity-response.dto.js +4 -8
- package/fesm/entities/identity.js +8 -2
- package/fesm/interfaces/datasource.interface.js +1 -20
- package/fesm/modules/datasource/index.js +0 -1
- package/fesm/modules/datasource/multi-tenant-datasource.service.js +24 -85
- package/guards/permission.guard.d.ts +1 -1
- package/interceptors/idempotency.interceptor.d.ts +1 -1
- package/interfaces/notification-adapter.interface.d.ts +13 -14
- package/modules/datasource/index.d.ts +0 -1
- package/modules/datasource/multi-tenant-datasource.service.d.ts +4 -13
- package/package.json +15 -15
- package/cjs/classes/request-scoped-api.service.js +0 -61
- package/cjs/modules/datasource/datasource.module.js +0 -117
- package/classes/request-scoped-api.service.d.ts +0 -14
- package/fesm/classes/request-scoped-api.service.js +0 -51
- package/fesm/modules/datasource/datasource.module.js +0 -107
- package/modules/datasource/datasource.module.d.ts +0 -19
|
@@ -17,6 +17,7 @@ export interface ApiControllerOptions {
|
|
|
17
17
|
security?: ApiSecurityConfig | EndpointSecurity | SecurityLevel;
|
|
18
18
|
entityName?: string;
|
|
19
19
|
enabledEndpoints?: ApiEndpoint[] | 'all';
|
|
20
|
+
excludeExtraneousValues?: boolean;
|
|
20
21
|
}
|
|
21
22
|
export declare function createApiController<CreateDtoT extends object, UpdateDtoT extends {
|
|
22
23
|
id: string;
|
|
@@ -1,20 +1,28 @@
|
|
|
1
|
-
import { QueryRunner, Repository, SelectQueryBuilder } from 'typeorm';
|
|
1
|
+
import { DataSource, EntityTarget, QueryRunner, Repository, SelectQueryBuilder } from 'typeorm';
|
|
2
2
|
import { DeleteDto, FilterAndPaginationDto } from '../dtos';
|
|
3
3
|
import { Identity, RawEntity } from '../entities';
|
|
4
|
-
import { ILoggedUserInfo, IService } from '../interfaces';
|
|
4
|
+
import { IDataSourceProvider, ILoggedUserInfo, IService } from '../interfaces';
|
|
5
5
|
import { UtilsService } from '../modules/utils/utils.service';
|
|
6
6
|
import { HybridCache } from './hybrid-cache.class';
|
|
7
7
|
export declare abstract class ApiService<CreateDtoT extends object, UpdateDtoT extends {
|
|
8
8
|
id: string;
|
|
9
9
|
}, InterfaceT extends Identity, EntityT extends Identity> implements IService<CreateDtoT, UpdateDtoT, InterfaceT> {
|
|
10
10
|
protected entityName: string;
|
|
11
|
-
protected repository: Repository<EntityT>;
|
|
12
11
|
protected cacheManager: HybridCache;
|
|
13
12
|
protected utilsService: UtilsService;
|
|
14
13
|
protected _loggerName: string;
|
|
15
14
|
protected isCacheable: boolean;
|
|
16
|
-
protected moduleName?: string;
|
|
17
|
-
|
|
15
|
+
protected moduleName?: string | undefined;
|
|
16
|
+
protected repository: Repository<EntityT>;
|
|
17
|
+
private repositoryInitialized;
|
|
18
|
+
private _entity?;
|
|
19
|
+
private _dataSourceProvider?;
|
|
20
|
+
constructor(entityName: string, cacheManager: HybridCache, utilsService: UtilsService, _loggerName: string, isCacheable?: boolean, moduleName?: string | undefined, entity?: EntityTarget<EntityT>, dataSourceProvider?: IDataSourceProvider);
|
|
21
|
+
protected resolveEntity(): EntityTarget<EntityT>;
|
|
22
|
+
protected getDataSourceProvider(): IDataSourceProvider;
|
|
23
|
+
protected ensureDataSourceRepository(): Promise<void>;
|
|
24
|
+
protected resolveRepositories(entities: EntityTarget<any>[]): Promise<Repository<any>[]>;
|
|
25
|
+
protected getDataSourceForService(): Promise<DataSource>;
|
|
18
26
|
insert(dto: CreateDtoT, user: ILoggedUserInfo | null): Promise<InterfaceT>;
|
|
19
27
|
insertMany(dtos: Array<CreateDtoT>, user: ILoggedUserInfo | null): Promise<InterfaceT[]>;
|
|
20
28
|
update(dto: UpdateDtoT, user: ILoggedUserInfo | null): Promise<InterfaceT>;
|
|
@@ -32,7 +40,6 @@ export declare abstract class ApiService<CreateDtoT extends object, UpdateDtoT e
|
|
|
32
40
|
private handleError;
|
|
33
41
|
private ensureArray;
|
|
34
42
|
private executeInTransaction;
|
|
35
|
-
protected ensureRepositoryInitialized(): Promise<void>;
|
|
36
43
|
protected beforeInsertOperation(_dto: CreateDtoT | Array<CreateDtoT>, _user: ILoggedUserInfo | null, _queryRunner: QueryRunner): Promise<void>;
|
|
37
44
|
protected afterInsertOperation(_entity: EntityT[], _user: ILoggedUserInfo | null, _queryRunner: QueryRunner): Promise<void>;
|
|
38
45
|
protected beforeUpdateOperation(_dto: UpdateDtoT | Array<UpdateDtoT>, _user: ILoggedUserInfo | null, _queryRunner: QueryRunner): Promise<void>;
|
package/classes/index.d.ts
CHANGED
|
@@ -2,6 +2,5 @@ export * from './api-controller.class';
|
|
|
2
2
|
export * from './api-service.class';
|
|
3
3
|
export * from './handle-custome-db-column-type';
|
|
4
4
|
export * from './hybrid-cache.class';
|
|
5
|
-
export * from './request-scoped-api.service';
|
|
6
5
|
export * from './winston.logger.class';
|
|
7
6
|
export * from '../constants/permissions';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const CurrentUser: (...dataOrPipes: (string | import("@nestjs/common").PipeTransform<any, any> | import("@nestjs/common").Type<import("@nestjs/common").PipeTransform<any, any>>)[]) => ParameterDecorator;
|
|
1
|
+
export declare const CurrentUser: (...dataOrPipes: (string | import("@nestjs/common").PipeTransform<any, any> | import("@nestjs/common").Type<import("@nestjs/common").PipeTransform<any, any>> | undefined)[]) => ParameterDecorator;
|
|
@@ -28,11 +28,11 @@ function _ts_param(paramIndex, decorator) {
|
|
|
28
28
|
import { applyDecorators, Body, HttpCode, HttpStatus, Param, Post, Query, UseGuards, UseInterceptors, Version, VERSION_NEUTRAL } from '@nestjs/common';
|
|
29
29
|
import { ApiBearerAuth, ApiBody, ApiExcludeEndpoint, ApiHeader, ApiOperation, ApiParam, ApiQuery, ApiResponse } from '@nestjs/swagger';
|
|
30
30
|
import { plainToInstance } from 'class-transformer';
|
|
31
|
+
import { ERROR_MESSAGES } from '../constants/message-keys';
|
|
31
32
|
import { CurrentUser, Public, RequireAnyPermission, RequirePermission, RequirePermissionLogic } from '../decorators';
|
|
32
33
|
import { ApiResponseDto } from '../decorators/api-response.decorator';
|
|
33
34
|
import { DeleteDto, FilterAndPaginationDto, GetByIdBodyDto, GetByIdsDto } from '../dtos';
|
|
34
35
|
import { BaseAppException, NotFoundException } from '../exceptions';
|
|
35
|
-
import { ERROR_MESSAGES } from '../constants/message-keys';
|
|
36
36
|
import { JwtAuthGuard, PermissionGuard } from '../guards';
|
|
37
37
|
import { IdempotencyInterceptor, SetCreatedByOnBody, SetDeletedByOnBody, SetUpdateByOnBody, Slug } from '../interceptors';
|
|
38
38
|
/**
|
|
@@ -98,6 +98,12 @@ import { IdempotencyInterceptor, SetCreatedByOnBody, SetDeletedByOnBody, SetUpda
|
|
|
98
98
|
return applyDecorators(...decorators);
|
|
99
99
|
}
|
|
100
100
|
/** Creates an API Controller with standardized CRUD endpoints (POST-only RPC pattern) */ export function createApiController(createDtoClass, updateDtoClass, responseDtoClass, options = {}) {
|
|
101
|
+
const excludeExtraneousValues = options.excludeExtraneousValues ?? true;
|
|
102
|
+
function toDto(cls, input) {
|
|
103
|
+
return plainToInstance(cls, input, {
|
|
104
|
+
excludeExtraneousValues
|
|
105
|
+
});
|
|
106
|
+
}
|
|
101
107
|
// Entity name for message keys (defaults to 'item')
|
|
102
108
|
const entityName = options.entityName ?? 'item';
|
|
103
109
|
// Determine if security is global (applies to all) or per-endpoint
|
|
@@ -153,7 +159,7 @@ import { IdempotencyInterceptor, SetCreatedByOnBody, SetDeletedByOnBody, SetUpda
|
|
|
153
159
|
});
|
|
154
160
|
}
|
|
155
161
|
const entity = await this.service.insert(addDto, user);
|
|
156
|
-
const data =
|
|
162
|
+
const data = toDto(responseDtoClass, entity);
|
|
157
163
|
return {
|
|
158
164
|
success: true,
|
|
159
165
|
message: `${entityName.charAt(0).toUpperCase() + entityName.slice(1)} created successfully`,
|
|
@@ -173,7 +179,7 @@ import { IdempotencyInterceptor, SetCreatedByOnBody, SetDeletedByOnBody, SetUpda
|
|
|
173
179
|
});
|
|
174
180
|
}
|
|
175
181
|
const entities = await this.service.insertMany(addDto, user);
|
|
176
|
-
const data = entities.map((item)=>
|
|
182
|
+
const data = entities.map((item)=>toDto(responseDtoClass, item));
|
|
177
183
|
return {
|
|
178
184
|
success: true,
|
|
179
185
|
message: `${data.length} ${entityName}s created successfully`,
|
|
@@ -201,7 +207,7 @@ import { IdempotencyInterceptor, SetCreatedByOnBody, SetDeletedByOnBody, SetUpda
|
|
|
201
207
|
});
|
|
202
208
|
}
|
|
203
209
|
const entity = await this.service.findById(id, user, body?.select);
|
|
204
|
-
const data =
|
|
210
|
+
const data = toDto(responseDtoClass, entity);
|
|
205
211
|
return {
|
|
206
212
|
success: true,
|
|
207
213
|
message: `${entityName.charAt(0).toUpperCase() + entityName.slice(1)} retrieved successfully`,
|
|
@@ -221,7 +227,7 @@ import { IdempotencyInterceptor, SetCreatedByOnBody, SetDeletedByOnBody, SetUpda
|
|
|
221
227
|
});
|
|
222
228
|
}
|
|
223
229
|
const entities = await this.service.findByIds(body.ids, user, body?.select);
|
|
224
|
-
const data =
|
|
230
|
+
const data = entities.map((item)=>toDto(responseDtoClass, item));
|
|
225
231
|
return {
|
|
226
232
|
success: true,
|
|
227
233
|
message: `${data.length} ${entityName}${data.length !== 1 ? 's' : ''} retrieved successfully`,
|
|
@@ -248,7 +254,7 @@ import { IdempotencyInterceptor, SetCreatedByOnBody, SetDeletedByOnBody, SetUpda
|
|
|
248
254
|
});
|
|
249
255
|
}
|
|
250
256
|
const entity = await this.service.update(updateDto, user);
|
|
251
|
-
const data =
|
|
257
|
+
const data = toDto(responseDtoClass, entity);
|
|
252
258
|
return {
|
|
253
259
|
success: true,
|
|
254
260
|
message: `${entityName.charAt(0).toUpperCase() + entityName.slice(1)} updated successfully`,
|
|
@@ -268,7 +274,7 @@ import { IdempotencyInterceptor, SetCreatedByOnBody, SetDeletedByOnBody, SetUpda
|
|
|
268
274
|
});
|
|
269
275
|
}
|
|
270
276
|
const entities = await this.service.updateMany(updateDtos, user);
|
|
271
|
-
const data =
|
|
277
|
+
const data = entities.map((item)=>toDto(responseDtoClass, item));
|
|
272
278
|
return {
|
|
273
279
|
success: true,
|
|
274
280
|
message: `${data.length} ${entityName}s updated successfully`,
|
|
@@ -305,7 +311,7 @@ import { IdempotencyInterceptor, SetCreatedByOnBody, SetDeletedByOnBody, SetUpda
|
|
|
305
311
|
}
|
|
306
312
|
}
|
|
307
313
|
const allEntities = await this.service.bulkUpsert(toInsert, toUpdate, user);
|
|
308
|
-
const data =
|
|
314
|
+
const data = allEntities.map((item)=>toDto(responseDtoClass, item));
|
|
309
315
|
return {
|
|
310
316
|
success: true,
|
|
311
317
|
message: `${data.length} ${entityName}s upserted successfully`,
|
|
@@ -343,7 +349,7 @@ import { IdempotencyInterceptor, SetCreatedByOnBody, SetDeletedByOnBody, SetUpda
|
|
|
343
349
|
throw new NotFoundException(entityName);
|
|
344
350
|
}
|
|
345
351
|
const entity = result.data[0];
|
|
346
|
-
const data =
|
|
352
|
+
const data = toDto(responseDtoClass, entity);
|
|
347
353
|
return {
|
|
348
354
|
success: true,
|
|
349
355
|
message: `${entityName.charAt(0).toUpperCase() + entityName.slice(1)} retrieved successfully`,
|
|
@@ -363,7 +369,7 @@ import { IdempotencyInterceptor, SetCreatedByOnBody, SetDeletedByOnBody, SetUpda
|
|
|
363
369
|
});
|
|
364
370
|
}
|
|
365
371
|
const result = await this.service.getAll(search ?? '', filterAndPaginationDto, user);
|
|
366
|
-
const data =
|
|
372
|
+
const data = result.data.map((item)=>toDto(responseDtoClass, item));
|
|
367
373
|
const page = filterAndPaginationDto.pagination?.currentPage ?? 0;
|
|
368
374
|
const pageSize = filterAndPaginationDto.pagination?.pageSize ?? data.length;
|
|
369
375
|
const totalPages = pageSize > 0 ? Math.ceil(result.total / pageSize) : 1;
|
|
@@ -20,12 +20,40 @@ function _ts_decorate(decorators, target, key, desc) {
|
|
|
20
20
|
function _ts_metadata(k, v) {
|
|
21
21
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
22
22
|
}
|
|
23
|
-
import { InternalServerErrorException, NotFoundException } from '@nestjs/common';
|
|
24
|
-
import { In } from 'typeorm';
|
|
23
|
+
import { Injectable, InternalServerErrorException, NotFoundException, Scope } from '@nestjs/common';
|
|
24
|
+
import { EntityTarget, In } from 'typeorm';
|
|
25
25
|
import { ERROR_MESSAGES, SYSTEM_MESSAGES } from '../constants';
|
|
26
26
|
import { LogAction } from '../decorators/log-action.decorator';
|
|
27
27
|
import { DeleteDto } from '../dtos';
|
|
28
|
-
|
|
28
|
+
import { IDataSourceProvider } from '../interfaces';
|
|
29
|
+
import { UtilsService } from '../modules/utils/utils.service';
|
|
30
|
+
import { HybridCache } from './hybrid-cache.class';
|
|
31
|
+
export class ApiService {
|
|
32
|
+
resolveEntity() {
|
|
33
|
+
return this._entity;
|
|
34
|
+
}
|
|
35
|
+
getDataSourceProvider() {
|
|
36
|
+
return this._dataSourceProvider;
|
|
37
|
+
}
|
|
38
|
+
async ensureDataSourceRepository() {
|
|
39
|
+
if (!this.repositoryInitialized) {
|
|
40
|
+
const entity = this.resolveEntity();
|
|
41
|
+
const provider = this.getDataSourceProvider();
|
|
42
|
+
this.repository = await provider.getRepository(entity);
|
|
43
|
+
this.repositoryInitialized = true;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
async resolveRepositories(entities) {
|
|
47
|
+
const provider = this.getDataSourceProvider();
|
|
48
|
+
const repositories = [];
|
|
49
|
+
for (const entity of entities){
|
|
50
|
+
repositories.push(await provider.getRepository(entity));
|
|
51
|
+
}
|
|
52
|
+
return repositories;
|
|
53
|
+
}
|
|
54
|
+
async getDataSourceForService() {
|
|
55
|
+
return this.getDataSourceProvider().getDataSource();
|
|
56
|
+
}
|
|
29
57
|
async insert(dto, user) {
|
|
30
58
|
return this.executeInTransaction('insert', async (qr)=>{
|
|
31
59
|
await this.beforeInsertOperation(dto, user, qr);
|
|
@@ -98,7 +126,7 @@ import { DeleteDto } from '../dtos';
|
|
|
98
126
|
});
|
|
99
127
|
}
|
|
100
128
|
async findByIds(ids, user, select) {
|
|
101
|
-
await this.
|
|
129
|
+
await this.ensureDataSourceRepository();
|
|
102
130
|
try {
|
|
103
131
|
const query = this.repository.createQueryBuilder(this.entityName);
|
|
104
132
|
query.where({
|
|
@@ -126,7 +154,7 @@ import { DeleteDto } from '../dtos';
|
|
|
126
154
|
}
|
|
127
155
|
}
|
|
128
156
|
async findById(id, user, select) {
|
|
129
|
-
await this.
|
|
157
|
+
await this.ensureDataSourceRepository();
|
|
130
158
|
try {
|
|
131
159
|
const query = this.repository.createQueryBuilder(this.entityName);
|
|
132
160
|
query.where({
|
|
@@ -140,18 +168,17 @@ import { DeleteDto } from '../dtos';
|
|
|
140
168
|
result = await this.cacheManager.get(cacheKey);
|
|
141
169
|
}
|
|
142
170
|
if (!result) {
|
|
143
|
-
let output;
|
|
144
171
|
if (isRaw) {
|
|
145
|
-
|
|
146
|
-
const convertResult = this.convertEntityListToResponseListDto(
|
|
172
|
+
const rawOutput = await finalQuery.getRawMany();
|
|
173
|
+
const convertResult = this.convertEntityListToResponseListDto(rawOutput, isRaw);
|
|
147
174
|
if (convertResult.length) result = convertResult[0];
|
|
148
175
|
} else {
|
|
149
|
-
|
|
150
|
-
if (!
|
|
176
|
+
const singleOutput = await finalQuery.getOne();
|
|
177
|
+
if (!singleOutput) throw new NotFoundException({
|
|
151
178
|
message: 'No Data Found',
|
|
152
179
|
messageKey: ERROR_MESSAGES.NOT_FOUND
|
|
153
180
|
});
|
|
154
|
-
result = this.convertEntityToResponseDto(
|
|
181
|
+
result = this.convertEntityToResponseDto(singleOutput, false);
|
|
155
182
|
}
|
|
156
183
|
if (this.isCacheable) {
|
|
157
184
|
await this.cacheManager.set(cacheKey, result);
|
|
@@ -167,43 +194,34 @@ import { DeleteDto } from '../dtos';
|
|
|
167
194
|
}
|
|
168
195
|
}
|
|
169
196
|
async getAll(search, filterAndPaginationDto, user) {
|
|
170
|
-
await this.
|
|
197
|
+
await this.ensureDataSourceRepository();
|
|
171
198
|
try {
|
|
172
199
|
let data;
|
|
173
200
|
let total;
|
|
174
201
|
let isRaw = false;
|
|
175
202
|
let query = this.repository.createQueryBuilder(this.entityName);
|
|
176
|
-
// Apply filters
|
|
177
203
|
if (filterAndPaginationDto.filter) {
|
|
178
204
|
const { query: filterQuery, isRaw: filterIsRaw } = await this.getFilterQuery(query, filterAndPaginationDto.filter, user);
|
|
179
205
|
query = filterQuery;
|
|
180
206
|
isRaw = isRaw || filterIsRaw;
|
|
181
207
|
}
|
|
182
|
-
// Apply search
|
|
183
208
|
if (search) {
|
|
184
209
|
const { query: searchQuery, isRaw: searchIsRaw } = await this.getGlobalSearchQuery(query, search, user);
|
|
185
210
|
query = searchQuery;
|
|
186
211
|
isRaw = isRaw || searchIsRaw;
|
|
187
212
|
}
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
query = selectQuery;
|
|
192
|
-
isRaw = isRaw || selectIsRaw;
|
|
193
|
-
}
|
|
194
|
-
// Apply sort
|
|
213
|
+
const { query: selectQuery, isRaw: selectIsRaw } = await this.getSelectQuery(query, user, filterAndPaginationDto.select);
|
|
214
|
+
query = selectQuery;
|
|
215
|
+
isRaw = isRaw || selectIsRaw;
|
|
195
216
|
if (filterAndPaginationDto.sort) {
|
|
196
217
|
const { query: sortQuery, isRaw: sortIsRaw } = await this.getSortQuery(query, filterAndPaginationDto.sort, user);
|
|
197
218
|
query = sortQuery;
|
|
198
219
|
isRaw = isRaw || sortIsRaw;
|
|
199
220
|
}
|
|
200
|
-
// Include soft-deleted if requested
|
|
201
221
|
if (filterAndPaginationDto.withDeleted) query.withDeleted();
|
|
202
|
-
// Extra manipulation
|
|
203
222
|
const { query: extraQuery, isRaw: extraIsRaw } = await this.getExtraManipulateQuery(query, filterAndPaginationDto, user);
|
|
204
223
|
query = extraQuery;
|
|
205
224
|
isRaw = isRaw || extraIsRaw;
|
|
206
|
-
// Pagination
|
|
207
225
|
if (filterAndPaginationDto.pagination) {
|
|
208
226
|
const offset = filterAndPaginationDto.pagination.currentPage * filterAndPaginationDto.pagination.pageSize;
|
|
209
227
|
const limit = filterAndPaginationDto.pagination.pageSize;
|
|
@@ -213,7 +231,6 @@ import { DeleteDto } from '../dtos';
|
|
|
213
231
|
query.skip(offset).take(limit);
|
|
214
232
|
}
|
|
215
233
|
}
|
|
216
|
-
// Generate cache key
|
|
217
234
|
let cacheKey = '';
|
|
218
235
|
if (this.isCacheable) {
|
|
219
236
|
cacheKey = this.utilsService.getCacheKey(this.entityName, {
|
|
@@ -227,7 +244,6 @@ import { DeleteDto } from '../dtos';
|
|
|
227
244
|
}
|
|
228
245
|
}
|
|
229
246
|
if (isRaw) {
|
|
230
|
-
// Handle raw query count manually
|
|
231
247
|
const rawSubQuery = query.clone().offset(undefined).limit(undefined).distinct(true);
|
|
232
248
|
const countSql = `
|
|
233
249
|
SELECT COUNT(*) as count
|
|
@@ -275,7 +291,7 @@ import { DeleteDto } from '../dtos';
|
|
|
275
291
|
}
|
|
276
292
|
}
|
|
277
293
|
async delete(option, user) {
|
|
278
|
-
await this.
|
|
294
|
+
await this.ensureDataSourceRepository();
|
|
279
295
|
const queryRunner = this.repository.manager.connection.createQueryRunner();
|
|
280
296
|
await queryRunner.connect();
|
|
281
297
|
await queryRunner.startTransaction();
|
|
@@ -307,7 +323,6 @@ import { DeleteDto } from '../dtos';
|
|
|
307
323
|
this.clearCacheForAll(),
|
|
308
324
|
this.clearCacheForId(ids)
|
|
309
325
|
]);
|
|
310
|
-
// return null per IService contract
|
|
311
326
|
return null;
|
|
312
327
|
} catch (error) {
|
|
313
328
|
await queryRunner.rollbackTransaction();
|
|
@@ -316,7 +331,6 @@ import { DeleteDto } from '../dtos';
|
|
|
316
331
|
await queryRunner.release();
|
|
317
332
|
}
|
|
318
333
|
}
|
|
319
|
-
// Caching
|
|
320
334
|
async clearCacheForAll() {
|
|
321
335
|
await this.utilsService.clearCache(this.entityName, this.cacheManager);
|
|
322
336
|
}
|
|
@@ -332,13 +346,13 @@ import { DeleteDto } from '../dtos';
|
|
|
332
346
|
messageKey: ERROR_MESSAGES.INTERNAL
|
|
333
347
|
});
|
|
334
348
|
}
|
|
335
|
-
|
|
349
|
+
ensureArray(value) {
|
|
336
350
|
return Array.isArray(value) ? value : [
|
|
337
351
|
value
|
|
338
352
|
];
|
|
339
353
|
}
|
|
340
|
-
|
|
341
|
-
await this.
|
|
354
|
+
async executeInTransaction(operation, fn) {
|
|
355
|
+
await this.ensureDataSourceRepository();
|
|
342
356
|
const qr = this.repository.manager.connection.createQueryRunner();
|
|
343
357
|
await qr.connect();
|
|
344
358
|
await qr.startTransaction();
|
|
@@ -363,8 +377,6 @@ import { DeleteDto } from '../dtos';
|
|
|
363
377
|
await qr.release();
|
|
364
378
|
}
|
|
365
379
|
}
|
|
366
|
-
// Hooks (override in child classes)
|
|
367
|
-
async ensureRepositoryInitialized() {}
|
|
368
380
|
async beforeInsertOperation(_dto, _user, _queryRunner) {}
|
|
369
381
|
async afterInsertOperation(_entity, _user, _queryRunner) {}
|
|
370
382
|
async beforeUpdateOperation(_dto, _user, _queryRunner) {}
|
|
@@ -413,7 +425,6 @@ import { DeleteDto } from '../dtos';
|
|
|
413
425
|
isRaw: false
|
|
414
426
|
};
|
|
415
427
|
}
|
|
416
|
-
// DTO conversion
|
|
417
428
|
async convertRequestDtoToEntity(dto, user) {
|
|
418
429
|
return Array.isArray(dto) ? await this.convertArrayDtoToEntities(dto, user) : [
|
|
419
430
|
await this.convertSingleDtoToEntity(dto, user)
|
|
@@ -448,21 +459,26 @@ import { DeleteDto } from '../dtos';
|
|
|
448
459
|
async getEntityClass() {
|
|
449
460
|
return await this.repository.create();
|
|
450
461
|
}
|
|
451
|
-
constructor(entityName,
|
|
462
|
+
constructor(entityName, cacheManager, utilsService, _loggerName, isCacheable = false, moduleName, entity, dataSourceProvider){
|
|
452
463
|
_define_property(this, "entityName", void 0);
|
|
453
|
-
_define_property(this, "repository", void 0);
|
|
454
464
|
_define_property(this, "cacheManager", void 0);
|
|
455
465
|
_define_property(this, "utilsService", void 0);
|
|
456
466
|
_define_property(this, "_loggerName", void 0);
|
|
457
467
|
_define_property(this, "isCacheable", void 0);
|
|
458
468
|
_define_property(this, "moduleName", void 0);
|
|
469
|
+
_define_property(this, "repository", void 0);
|
|
470
|
+
_define_property(this, "repositoryInitialized", void 0);
|
|
471
|
+
_define_property(this, "_entity", void 0);
|
|
472
|
+
_define_property(this, "_dataSourceProvider", void 0);
|
|
459
473
|
this.entityName = entityName;
|
|
460
|
-
this.repository = repository;
|
|
461
474
|
this.cacheManager = cacheManager;
|
|
462
475
|
this.utilsService = utilsService;
|
|
463
476
|
this._loggerName = _loggerName;
|
|
464
477
|
this.isCacheable = isCacheable;
|
|
465
478
|
this.moduleName = moduleName;
|
|
479
|
+
this.repositoryInitialized = false;
|
|
480
|
+
this._entity = entity;
|
|
481
|
+
this._dataSourceProvider = dataSourceProvider;
|
|
466
482
|
}
|
|
467
483
|
}
|
|
468
484
|
_ts_decorate([
|
|
@@ -532,3 +548,19 @@ _ts_decorate([
|
|
|
532
548
|
]),
|
|
533
549
|
_ts_metadata("design:returntype", Promise)
|
|
534
550
|
], ApiService.prototype, "delete", null);
|
|
551
|
+
ApiService = _ts_decorate([
|
|
552
|
+
Injectable({
|
|
553
|
+
scope: Scope.REQUEST
|
|
554
|
+
}),
|
|
555
|
+
_ts_metadata("design:type", Function),
|
|
556
|
+
_ts_metadata("design:paramtypes", [
|
|
557
|
+
String,
|
|
558
|
+
typeof HybridCache === "undefined" ? Object : HybridCache,
|
|
559
|
+
typeof UtilsService === "undefined" ? Object : UtilsService,
|
|
560
|
+
String,
|
|
561
|
+
Boolean,
|
|
562
|
+
String,
|
|
563
|
+
typeof EntityTarget === "undefined" ? Object : EntityTarget,
|
|
564
|
+
typeof IDataSourceProvider === "undefined" ? Object : IDataSourceProvider
|
|
565
|
+
])
|
|
566
|
+
], ApiService);
|
package/fesm/classes/index.js
CHANGED
|
@@ -2,7 +2,6 @@ export * from './api-controller.class';
|
|
|
2
2
|
export * from './api-service.class';
|
|
3
3
|
export * from './handle-custome-db-column-type';
|
|
4
4
|
export * from './hybrid-cache.class';
|
|
5
|
-
export * from './request-scoped-api.service';
|
|
6
5
|
export * from './winston.logger.class';
|
|
7
6
|
// Re-export permission constants for convenience
|
|
8
7
|
export * from '../constants/permissions';
|
|
@@ -20,8 +20,8 @@ function _ts_decorate(decorators, target, key, desc) {
|
|
|
20
20
|
function _ts_metadata(k, v) {
|
|
21
21
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
22
22
|
}
|
|
23
|
-
import { Expose, Type } from 'class-transformer';
|
|
24
23
|
import { ApiProperty } from '@nestjs/swagger';
|
|
24
|
+
import { Expose, Type } from 'class-transformer';
|
|
25
25
|
export class IdentityResponseDto {
|
|
26
26
|
constructor(){
|
|
27
27
|
_define_property(this, "id", void 0);
|
|
@@ -34,28 +34,28 @@ export class IdentityResponseDto {
|
|
|
34
34
|
}
|
|
35
35
|
}
|
|
36
36
|
_ts_decorate([
|
|
37
|
+
Expose(),
|
|
37
38
|
ApiProperty({
|
|
38
39
|
type: String,
|
|
39
40
|
format: 'uuid'
|
|
40
41
|
}),
|
|
41
|
-
Expose(),
|
|
42
42
|
_ts_metadata("design:type", String)
|
|
43
43
|
], IdentityResponseDto.prototype, "id", void 0);
|
|
44
44
|
_ts_decorate([
|
|
45
|
+
Expose(),
|
|
45
46
|
ApiProperty({
|
|
46
47
|
type: String,
|
|
47
48
|
format: 'date-time'
|
|
48
49
|
}),
|
|
49
|
-
Expose(),
|
|
50
50
|
Type(()=>Date),
|
|
51
51
|
_ts_metadata("design:type", typeof Date === "undefined" ? Object : Date)
|
|
52
52
|
], IdentityResponseDto.prototype, "createdAt", void 0);
|
|
53
53
|
_ts_decorate([
|
|
54
|
+
Expose(),
|
|
54
55
|
ApiProperty({
|
|
55
56
|
type: String,
|
|
56
57
|
format: 'date-time'
|
|
57
58
|
}),
|
|
58
|
-
Expose(),
|
|
59
59
|
Type(()=>Date),
|
|
60
60
|
_ts_metadata("design:type", typeof Date === "undefined" ? Object : Date)
|
|
61
61
|
], IdentityResponseDto.prototype, "updatedAt", void 0);
|
|
@@ -66,7 +66,6 @@ _ts_decorate([
|
|
|
66
66
|
nullable: true,
|
|
67
67
|
required: false
|
|
68
68
|
}),
|
|
69
|
-
Expose(),
|
|
70
69
|
Type(()=>Date),
|
|
71
70
|
_ts_metadata("design:type", Object)
|
|
72
71
|
], IdentityResponseDto.prototype, "deletedAt", void 0);
|
|
@@ -77,7 +76,6 @@ _ts_decorate([
|
|
|
77
76
|
nullable: true,
|
|
78
77
|
required: false
|
|
79
78
|
}),
|
|
80
|
-
Expose(),
|
|
81
79
|
_ts_metadata("design:type", Object)
|
|
82
80
|
], IdentityResponseDto.prototype, "createdById", void 0);
|
|
83
81
|
_ts_decorate([
|
|
@@ -87,7 +85,6 @@ _ts_decorate([
|
|
|
87
85
|
nullable: true,
|
|
88
86
|
required: false
|
|
89
87
|
}),
|
|
90
|
-
Expose(),
|
|
91
88
|
_ts_metadata("design:type", Object)
|
|
92
89
|
], IdentityResponseDto.prototype, "updatedById", void 0);
|
|
93
90
|
_ts_decorate([
|
|
@@ -97,6 +94,5 @@ _ts_decorate([
|
|
|
97
94
|
nullable: true,
|
|
98
95
|
required: false
|
|
99
96
|
}),
|
|
100
|
-
Expose(),
|
|
101
97
|
_ts_metadata("design:type", Object)
|
|
102
98
|
], IdentityResponseDto.prototype, "deletedById", void 0);
|
|
@@ -39,14 +39,16 @@ _ts_decorate([
|
|
|
39
39
|
_ts_decorate([
|
|
40
40
|
CreateDateColumn({
|
|
41
41
|
name: 'created_at',
|
|
42
|
-
type: 'timestamp'
|
|
42
|
+
type: 'timestamp',
|
|
43
|
+
select: false
|
|
43
44
|
}),
|
|
44
45
|
_ts_metadata("design:type", typeof Date === "undefined" ? Object : Date)
|
|
45
46
|
], Identity.prototype, "createdAt", void 0);
|
|
46
47
|
_ts_decorate([
|
|
47
48
|
UpdateDateColumn({
|
|
48
49
|
name: 'updated_at',
|
|
49
|
-
type: 'timestamp'
|
|
50
|
+
type: 'timestamp',
|
|
51
|
+
select: false
|
|
50
52
|
}),
|
|
51
53
|
_ts_metadata("design:type", typeof Date === "undefined" ? Object : Date)
|
|
52
54
|
], Identity.prototype, "updatedAt", void 0);
|
|
@@ -54,6 +56,7 @@ _ts_decorate([
|
|
|
54
56
|
DeleteDateColumn({
|
|
55
57
|
name: 'deleted_at',
|
|
56
58
|
type: 'timestamp',
|
|
59
|
+
select: false,
|
|
57
60
|
nullable: true
|
|
58
61
|
}),
|
|
59
62
|
_ts_metadata("design:type", Object)
|
|
@@ -62,6 +65,7 @@ _ts_decorate([
|
|
|
62
65
|
Column({
|
|
63
66
|
name: 'created_by_id',
|
|
64
67
|
type: 'uuid',
|
|
68
|
+
select: false,
|
|
65
69
|
nullable: true
|
|
66
70
|
}),
|
|
67
71
|
_ts_metadata("design:type", Object)
|
|
@@ -70,6 +74,7 @@ _ts_decorate([
|
|
|
70
74
|
Column({
|
|
71
75
|
name: 'updated_by_id',
|
|
72
76
|
type: 'uuid',
|
|
77
|
+
select: false,
|
|
73
78
|
nullable: true
|
|
74
79
|
}),
|
|
75
80
|
_ts_metadata("design:type", Object)
|
|
@@ -78,6 +83,7 @@ _ts_decorate([
|
|
|
78
83
|
Column({
|
|
79
84
|
name: 'deleted_by_id',
|
|
80
85
|
type: 'uuid',
|
|
86
|
+
select: false,
|
|
81
87
|
nullable: true
|
|
82
88
|
}),
|
|
83
89
|
_ts_metadata("design:type", Object)
|
|
@@ -1,20 +1 @@
|
|
|
1
|
-
|
|
2
|
-
* Interface for DataSource providers used by RequestScopedApiService.
|
|
3
|
-
* Implement this interface in each module's DataSourceProvider to ensure type safety.
|
|
4
|
-
*
|
|
5
|
-
* @example
|
|
6
|
-
* ```typescript
|
|
7
|
-
* @Injectable()
|
|
8
|
-
* export class IAMDataSourceProvider implements IDataSourceProvider {
|
|
9
|
-
* constructor(private readonly dataSource: DataSource) {}
|
|
10
|
-
*
|
|
11
|
-
* async getRepository<T extends ObjectLiteral>(entity: EntityTarget<T>): Promise<Repository<T>> {
|
|
12
|
-
* return this.dataSource.getRepository(entity);
|
|
13
|
-
* }
|
|
14
|
-
*
|
|
15
|
-
* async getDataSource(): Promise<DataSource> {
|
|
16
|
-
* return this.dataSource;
|
|
17
|
-
* }
|
|
18
|
-
* }
|
|
19
|
-
* ```
|
|
20
|
-
*/ export { };
|
|
1
|
+
export { };
|