@flusys/nestjs-shared 1.1.0 → 1.2.0-rc.1

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 (158) hide show
  1. package/README.md +139 -1103
  2. package/cjs/classes/api-controller.class.js +320 -29
  3. package/cjs/classes/api-service.class.js +219 -64
  4. package/cjs/classes/handle-custome-db.js +37 -0
  5. package/cjs/classes/index.js +1 -2
  6. package/cjs/classes/winston.logger.class.js +103 -70
  7. package/cjs/constants/index.js +1 -4
  8. package/cjs/constants/message-keys.js +68 -0
  9. package/cjs/constants/permissions.js +114 -11
  10. package/cjs/decorators/api-response.decorator.js +1 -2
  11. package/cjs/decorators/index.js +1 -1
  12. package/cjs/decorators/log-action.decorator.js +149 -0
  13. package/cjs/decorators/require-permission.decorator.js +5 -5
  14. package/cjs/dtos/get-by-ids.dto.js +65 -0
  15. package/cjs/dtos/identity-response.dto.js +4 -8
  16. package/cjs/dtos/index.js +1 -0
  17. package/cjs/dtos/response-payload.dto.js +72 -0
  18. package/cjs/entities/identity.js +8 -2
  19. package/cjs/entities/index.js +1 -0
  20. package/cjs/entities/raw-type.js +4 -0
  21. package/cjs/entities/user-root.js +2 -1
  22. package/cjs/enums/index.js +20 -0
  23. package/cjs/enums/notification-type.enum.js +17 -0
  24. package/cjs/enums/participant-status.enum.js +17 -0
  25. package/cjs/enums/recurrence-type.enum.js +18 -0
  26. package/cjs/exceptions/base-app.exception.js +151 -0
  27. package/cjs/exceptions/index.js +1 -0
  28. package/cjs/exceptions/permission.exception.js +13 -9
  29. package/cjs/filters/global-exception.filter.js +279 -0
  30. package/cjs/filters/index.js +18 -0
  31. package/cjs/guards/jwt-auth.guard.js +4 -1
  32. package/cjs/guards/permission.guard.js +71 -77
  33. package/cjs/index.js +2 -0
  34. package/cjs/interceptors/idempotency.interceptor.js +1 -1
  35. package/cjs/interceptors/index.js +0 -1
  36. package/cjs/interfaces/event-manager-adapter.interface.js +11 -0
  37. package/cjs/interfaces/index.js +2 -1
  38. package/cjs/interfaces/notification-adapter.interface.js +11 -0
  39. package/cjs/interfaces/permission.interface.js +1 -1
  40. package/cjs/middlewares/logger.middleware.js +83 -26
  41. package/cjs/modules/datasource/index.js +0 -1
  42. package/cjs/modules/datasource/multi-tenant-datasource.service.js +46 -85
  43. package/cjs/modules/utils/utils.service.js +4 -20
  44. package/cjs/utils/date-time.util.js +94 -0
  45. package/cjs/utils/index.js +1 -1
  46. package/cjs/utils/query-helpers.util.js +8 -1
  47. package/cjs/utils/request.util.js +25 -0
  48. package/classes/api-controller.class.d.ts +14 -6
  49. package/classes/api-service.class.d.ts +25 -22
  50. package/classes/handle-custome-db.d.ts +3 -0
  51. package/classes/index.d.ts +1 -2
  52. package/classes/winston.logger.class.d.ts +1 -0
  53. package/constants/index.d.ts +1 -1
  54. package/constants/message-keys.d.ts +45 -0
  55. package/constants/permissions.d.ts +127 -0
  56. package/decorators/api-response.decorator.d.ts +1 -1
  57. package/decorators/current-user.decorator.d.ts +1 -1
  58. package/decorators/index.d.ts +1 -1
  59. package/decorators/log-action.decorator.d.ts +8 -0
  60. package/decorators/require-permission.decorator.d.ts +2 -2
  61. package/dtos/get-by-ids.dto.d.ts +4 -0
  62. package/dtos/index.d.ts +1 -0
  63. package/dtos/response-payload.dto.d.ts +8 -0
  64. package/entities/index.d.ts +1 -0
  65. package/entities/raw-type.d.ts +1 -0
  66. package/enums/index.d.ts +3 -0
  67. package/enums/notification-type.enum.d.ts +6 -0
  68. package/enums/participant-status.enum.d.ts +6 -0
  69. package/enums/recurrence-type.enum.d.ts +7 -0
  70. package/exceptions/base-app.exception.d.ts +41 -0
  71. package/exceptions/index.d.ts +1 -0
  72. package/exceptions/permission.exception.d.ts +2 -2
  73. package/fesm/classes/api-controller.class.js +321 -30
  74. package/fesm/classes/api-service.class.js +222 -67
  75. package/fesm/classes/handle-custome-db.js +19 -0
  76. package/fesm/classes/index.js +1 -2
  77. package/fesm/classes/winston.logger.class.js +100 -68
  78. package/fesm/constants/index.js +2 -1
  79. package/fesm/constants/message-keys.js +49 -0
  80. package/fesm/constants/permissions.js +86 -14
  81. package/fesm/decorators/api-response.decorator.js +2 -20
  82. package/fesm/decorators/index.js +1 -1
  83. package/fesm/decorators/log-action.decorator.js +139 -0
  84. package/fesm/decorators/require-permission.decorator.js +17 -65
  85. package/fesm/dtos/get-by-ids.dto.js +55 -0
  86. package/fesm/dtos/identity-response.dto.js +4 -8
  87. package/fesm/dtos/index.js +1 -0
  88. package/fesm/dtos/response-payload.dto.js +72 -0
  89. package/fesm/entities/identity.js +8 -2
  90. package/fesm/entities/index.js +1 -0
  91. package/fesm/entities/raw-type.js +1 -0
  92. package/fesm/entities/user-root.js +2 -1
  93. package/fesm/enums/index.js +3 -0
  94. package/fesm/enums/notification-type.enum.js +7 -0
  95. package/fesm/enums/participant-status.enum.js +7 -0
  96. package/fesm/enums/recurrence-type.enum.js +8 -0
  97. package/fesm/exceptions/base-app.exception.js +115 -0
  98. package/fesm/exceptions/index.js +1 -0
  99. package/fesm/exceptions/permission.exception.js +16 -18
  100. package/fesm/filters/global-exception.filter.js +269 -0
  101. package/fesm/filters/index.js +1 -0
  102. package/fesm/guards/jwt-auth.guard.js +5 -2
  103. package/fesm/guards/permission.guard.js +73 -79
  104. package/fesm/index.js +2 -0
  105. package/fesm/interceptors/idempotency.interceptor.js +2 -2
  106. package/fesm/interceptors/index.js +0 -1
  107. package/fesm/interfaces/datasource.interface.js +1 -20
  108. package/fesm/interfaces/event-manager-adapter.interface.js +1 -0
  109. package/fesm/interfaces/index.js +2 -1
  110. package/fesm/interfaces/notification-adapter.interface.js +1 -0
  111. package/fesm/interfaces/permission.interface.js +1 -3
  112. package/fesm/middlewares/logger.middleware.js +83 -26
  113. package/fesm/modules/datasource/index.js +0 -1
  114. package/fesm/modules/datasource/multi-tenant-datasource.service.js +47 -86
  115. package/fesm/modules/utils/utils.service.js +5 -21
  116. package/fesm/utils/date-time.util.js +70 -0
  117. package/fesm/utils/index.js +1 -1
  118. package/fesm/utils/query-helpers.util.js +8 -1
  119. package/fesm/utils/request.util.js +22 -0
  120. package/filters/global-exception.filter.d.ts +9 -0
  121. package/filters/index.d.ts +1 -0
  122. package/guards/permission.guard.d.ts +3 -7
  123. package/index.d.ts +2 -0
  124. package/interceptors/idempotency.interceptor.d.ts +1 -1
  125. package/interceptors/index.d.ts +0 -1
  126. package/interfaces/api.interface.d.ts +2 -0
  127. package/interfaces/event-manager-adapter.interface.d.ts +43 -0
  128. package/interfaces/index.d.ts +2 -1
  129. package/interfaces/notification-adapter.interface.d.ts +21 -0
  130. package/interfaces/permission.interface.d.ts +13 -8
  131. package/modules/datasource/index.d.ts +0 -1
  132. package/modules/datasource/multi-tenant-datasource.service.d.ts +5 -15
  133. package/modules/utils/utils.service.d.ts +0 -1
  134. package/package.json +21 -14
  135. package/utils/date-time.util.d.ts +8 -0
  136. package/utils/index.d.ts +1 -1
  137. package/utils/request.util.d.ts +2 -0
  138. package/cjs/classes/request-scoped-api.service.js +0 -61
  139. package/cjs/classes/winston-logger-adapter.class.js +0 -104
  140. package/cjs/decorators/sanitize-html.decorator.js +0 -36
  141. package/cjs/interceptors/query-performance.interceptor.js +0 -66
  142. package/cjs/interfaces/logger.interface.js +0 -7
  143. package/cjs/modules/datasource/datasource.module.js +0 -117
  144. package/cjs/utils/error-handler.util.js +0 -90
  145. package/classes/request-scoped-api.service.d.ts +0 -14
  146. package/classes/winston-logger-adapter.class.d.ts +0 -22
  147. package/decorators/sanitize-html.decorator.d.ts +0 -2
  148. package/fesm/classes/request-scoped-api.service.js +0 -51
  149. package/fesm/classes/winston-logger-adapter.class.js +0 -107
  150. package/fesm/decorators/sanitize-html.decorator.js +0 -45
  151. package/fesm/interceptors/query-performance.interceptor.js +0 -56
  152. package/fesm/interfaces/logger.interface.js +0 -4
  153. package/fesm/modules/datasource/datasource.module.js +0 -107
  154. package/fesm/utils/error-handler.util.js +0 -82
  155. package/interceptors/query-performance.interceptor.d.ts +0 -8
  156. package/interfaces/logger.interface.d.ts +0 -7
  157. package/modules/datasource/datasource.module.d.ts +0 -19
  158. package/utils/error-handler.util.d.ts +0 -19
@@ -11,16 +11,55 @@ function _define_property(obj, key, value) {
11
11
  }
12
12
  return obj;
13
13
  }
14
- import { ErrorHandler } from '../utils/error-handler.util';
15
- import { Logger, NotFoundException } from '@nestjs/common';
16
- import { In } from 'typeorm';
17
- /** Generic API service with CRUD operations and caching support */ export class ApiService {
14
+ function _ts_decorate(decorators, target, key, desc) {
15
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
16
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
17
+ else for(var i = decorators.length - 1; i >= 0; i--)if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
18
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
19
+ }
20
+ function _ts_metadata(k, v) {
21
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
22
+ }
23
+ import { Injectable, InternalServerErrorException, NotFoundException, Scope } from '@nestjs/common';
24
+ import { EntityTarget, In } from 'typeorm';
25
+ import { ERROR_MESSAGES, SYSTEM_MESSAGES } from '../constants';
26
+ import { LogAction } from '../decorators/log-action.decorator';
27
+ import { DeleteDto } from '../dtos';
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
+ }
18
57
  async insert(dto, user) {
19
58
  return this.executeInTransaction('insert', async (qr)=>{
20
59
  await this.beforeInsertOperation(dto, user, qr);
21
60
  const entities = await this.convertRequestDtoToEntity(dto, user);
22
61
  const saved = await qr.manager.save(this.repository.target, entities);
23
- await this.afterInsertOperation(this.ensureArray(saved), user, qr);
62
+ await this.afterInsertOperation(this.ensureArray(saved), dto, user, qr);
24
63
  return {
25
64
  saved,
26
65
  returnFirst: true
@@ -32,7 +71,7 @@ import { In } from 'typeorm';
32
71
  await this.beforeInsertOperation(dtos, user, qr);
33
72
  const entities = await this.convertRequestDtoToEntity(dtos, user);
34
73
  const saved = await qr.manager.save(this.repository.target, entities);
35
- await this.afterInsertOperation(this.ensureArray(saved), user, qr);
74
+ await this.afterInsertOperation(this.ensureArray(saved), dtos, user, qr);
36
75
  return {
37
76
  saved,
38
77
  returnFirst: false
@@ -44,7 +83,7 @@ import { In } from 'typeorm';
44
83
  await this.beforeUpdateOperation(dto, user, qr);
45
84
  const entities = await this.convertRequestDtoToEntity(dto, user);
46
85
  const saved = await qr.manager.save(this.repository.target, entities);
47
- await this.afterUpdateOperation(this.ensureArray(saved), user, qr);
86
+ await this.afterUpdateOperation(this.ensureArray(saved), dto, user, qr);
48
87
  return {
49
88
  saved,
50
89
  returnFirst: true
@@ -56,21 +95,45 @@ import { In } from 'typeorm';
56
95
  await this.beforeUpdateOperation(dtos, user, qr);
57
96
  const entities = await this.convertRequestDtoToEntity(dtos, user);
58
97
  const saved = await qr.manager.save(this.repository.target, entities);
59
- await this.afterUpdateOperation(this.ensureArray(saved), user, qr);
98
+ await this.afterUpdateOperation(this.ensureArray(saved), dtos, user, qr);
60
99
  return {
61
100
  saved,
62
101
  returnFirst: false
63
102
  };
64
103
  });
65
104
  }
66
- async findByIds(ids, user) {
67
- await this.ensureRepositoryInitialized();
105
+ async bulkUpsert(toInsert, toUpdate, user) {
106
+ return this.executeInTransaction('bulkUpsert', async (qr)=>{
107
+ const allResults = [];
108
+ if (toInsert.length > 0) {
109
+ await this.beforeInsertOperation(toInsert, user, qr);
110
+ const insertedEntities = await this.convertRequestDtoToEntity(toInsert, user);
111
+ const insertedSaved = await qr.manager.save(this.repository.target, insertedEntities);
112
+ await this.afterInsertOperation(this.ensureArray(insertedSaved), toInsert, user, qr);
113
+ allResults.push(...this.ensureArray(insertedSaved));
114
+ }
115
+ if (toUpdate.length > 0) {
116
+ await this.beforeUpdateOperation(toUpdate, user, qr);
117
+ const updatedEntities = await this.convertRequestDtoToEntity(toUpdate, user);
118
+ const updatedSaved = await qr.manager.save(this.repository.target, updatedEntities);
119
+ await this.afterUpdateOperation(this.ensureArray(updatedSaved), toUpdate, user, qr);
120
+ allResults.push(...this.ensureArray(updatedSaved));
121
+ }
122
+ return {
123
+ saved: allResults,
124
+ returnFirst: false
125
+ };
126
+ });
127
+ }
128
+ async findByIds(ids, user, select) {
129
+ await this.ensureDataSourceRepository();
68
130
  try {
69
131
  const query = this.repository.createQueryBuilder(this.entityName);
70
132
  query.where({
71
133
  id: In(ids)
72
134
  });
73
- const { query: finalQuery, isRaw } = await this.getSelectQuery(query, user);
135
+ const selectArray = typeof select === 'string' ? select.split(',').map((s)=>s.trim()) : select;
136
+ const { query: finalQuery, isRaw } = await this.getSelectQuery(query, user, selectArray);
74
137
  let output;
75
138
  if (isRaw) {
76
139
  output = await finalQuery.getRawMany();
@@ -78,7 +141,10 @@ import { In } from 'typeorm';
78
141
  output = await finalQuery.getMany();
79
142
  }
80
143
  const result = this.convertEntityListToResponseListDto(output, isRaw);
81
- if (!result || !result.length) throw new NotFoundException('No Data Found');
144
+ if (!result || !result.length) throw new NotFoundException({
145
+ message: 'No Data Found',
146
+ messageKey: ERROR_MESSAGES.NOT_FOUND
147
+ });
82
148
  return result;
83
149
  } catch (error) {
84
150
  if (error instanceof NotFoundException) {
@@ -88,7 +154,7 @@ import { In } from 'typeorm';
88
154
  }
89
155
  }
90
156
  async findById(id, user, select) {
91
- await this.ensureRepositoryInitialized();
157
+ await this.ensureDataSourceRepository();
92
158
  try {
93
159
  const query = this.repository.createQueryBuilder(this.entityName);
94
160
  query.where({
@@ -102,15 +168,17 @@ import { In } from 'typeorm';
102
168
  result = await this.cacheManager.get(cacheKey);
103
169
  }
104
170
  if (!result) {
105
- let output;
106
171
  if (isRaw) {
107
- output = await finalQuery.getRawMany();
108
- const convertResult = this.convertEntityListToResponseListDto(output, isRaw);
172
+ const rawOutput = await finalQuery.getRawMany();
173
+ const convertResult = this.convertEntityListToResponseListDto(rawOutput, isRaw);
109
174
  if (convertResult.length) result = convertResult[0];
110
175
  } else {
111
- output = await finalQuery.getOne();
112
- if (!output) throw new NotFoundException('No Data Found');
113
- result = this.convertEntityToResponseDto(output, false);
176
+ const singleOutput = await finalQuery.getOne();
177
+ if (!singleOutput) throw new NotFoundException({
178
+ message: 'No Data Found',
179
+ messageKey: ERROR_MESSAGES.NOT_FOUND
180
+ });
181
+ result = this.convertEntityToResponseDto(singleOutput, false);
114
182
  }
115
183
  if (this.isCacheable) {
116
184
  await this.cacheManager.set(cacheKey, result);
@@ -126,43 +194,34 @@ import { In } from 'typeorm';
126
194
  }
127
195
  }
128
196
  async getAll(search, filterAndPaginationDto, user) {
129
- await this.ensureRepositoryInitialized();
197
+ await this.ensureDataSourceRepository();
130
198
  try {
131
199
  let data;
132
200
  let total;
133
201
  let isRaw = false;
134
202
  let query = this.repository.createQueryBuilder(this.entityName);
135
- // Apply filters
136
203
  if (filterAndPaginationDto.filter) {
137
204
  const { query: filterQuery, isRaw: filterIsRaw } = await this.getFilterQuery(query, filterAndPaginationDto.filter, user);
138
205
  query = filterQuery;
139
206
  isRaw = isRaw || filterIsRaw;
140
207
  }
141
- // Apply search
142
208
  if (search) {
143
209
  const { query: searchQuery, isRaw: searchIsRaw } = await this.getGlobalSearchQuery(query, search, user);
144
210
  query = searchQuery;
145
211
  isRaw = isRaw || searchIsRaw;
146
212
  }
147
- // Apply select
148
- if (filterAndPaginationDto.select) {
149
- const { query: selectQuery, isRaw: selectIsRaw } = await this.getSelectQuery(query, user, filterAndPaginationDto.select);
150
- query = selectQuery;
151
- isRaw = isRaw || selectIsRaw;
152
- }
153
- // Apply sort
213
+ const { query: selectQuery, isRaw: selectIsRaw } = await this.getSelectQuery(query, user, filterAndPaginationDto.select);
214
+ query = selectQuery;
215
+ isRaw = isRaw || selectIsRaw;
154
216
  if (filterAndPaginationDto.sort) {
155
217
  const { query: sortQuery, isRaw: sortIsRaw } = await this.getSortQuery(query, filterAndPaginationDto.sort, user);
156
218
  query = sortQuery;
157
219
  isRaw = isRaw || sortIsRaw;
158
220
  }
159
- // Include soft-deleted if requested
160
221
  if (filterAndPaginationDto.withDeleted) query.withDeleted();
161
- // Extra manipulation
162
222
  const { query: extraQuery, isRaw: extraIsRaw } = await this.getExtraManipulateQuery(query, filterAndPaginationDto, user);
163
223
  query = extraQuery;
164
224
  isRaw = isRaw || extraIsRaw;
165
- // Pagination
166
225
  if (filterAndPaginationDto.pagination) {
167
226
  const offset = filterAndPaginationDto.pagination.currentPage * filterAndPaginationDto.pagination.pageSize;
168
227
  const limit = filterAndPaginationDto.pagination.pageSize;
@@ -172,7 +231,6 @@ import { In } from 'typeorm';
172
231
  query.skip(offset).take(limit);
173
232
  }
174
233
  }
175
- // Generate cache key
176
234
  let cacheKey = '';
177
235
  if (this.isCacheable) {
178
236
  cacheKey = this.utilsService.getCacheKey(this.entityName, {
@@ -186,8 +244,9 @@ import { In } from 'typeorm';
186
244
  }
187
245
  }
188
246
  if (isRaw) {
189
- // Handle raw query count manually
190
- const rawSubQuery = query.clone().offset(undefined).limit(undefined).distinct(true);
247
+ const rawSubQuery = query.clone().offset(undefined).limit(undefined);
248
+ rawSubQuery.expressionMap.orderBys = {};
249
+ rawSubQuery.distinct(true);
191
250
  const countSql = `
192
251
  SELECT COUNT(*) as count
193
252
  FROM (
@@ -198,10 +257,20 @@ import { In } from 'typeorm';
198
257
  `;
199
258
  const parameters = rawSubQuery.getParameters();
200
259
  const orderedValues = [];
260
+ const isPostgres = this.repository.manager.connection.options.type === 'postgres';
261
+ let paramIndex = 0;
201
262
  const convertedQuery = countSql.replace(/:(\w+)/g, (_, key)=>{
202
- if (!(key in parameters)) throw new Error(`Missing parameter value for: ${key}`);
263
+ if (!(key in parameters)) {
264
+ throw new InternalServerErrorException({
265
+ message: `Missing parameter value for: ${key}`,
266
+ messageKey: SYSTEM_MESSAGES.MISSING_PARAMETER,
267
+ messageVariables: {
268
+ key
269
+ }
270
+ });
271
+ }
203
272
  orderedValues.push(parameters[key]);
204
- return '?';
273
+ return isPostgres ? `$${++paramIndex}` : '?';
205
274
  });
206
275
  const result = await this.repository.query(convertedQuery, orderedValues);
207
276
  total = Number(result[0]?.count || 0);
@@ -224,7 +293,7 @@ import { In } from 'typeorm';
224
293
  }
225
294
  }
226
295
  async delete(option, user) {
227
- await this.ensureRepositoryInitialized();
296
+ await this.ensureDataSourceRepository();
228
297
  const queryRunner = this.repository.manager.connection.createQueryRunner();
229
298
  await queryRunner.connect();
230
299
  await queryRunner.startTransaction();
@@ -250,13 +319,12 @@ import { In } from 'typeorm';
250
319
  id
251
320
  };
252
321
  });
253
- await this.afterDeleteOperation(ids, user, queryRunner);
322
+ await this.afterDeleteOperation(ids, option, user, queryRunner);
254
323
  await queryRunner.commitTransaction();
255
324
  await Promise.all([
256
325
  this.clearCacheForAll(),
257
326
  this.clearCacheForId(ids)
258
327
  ]);
259
- // return null per IService contract
260
328
  return null;
261
329
  } catch (error) {
262
330
  await queryRunner.rollbackTransaction();
@@ -265,28 +333,28 @@ import { In } from 'typeorm';
265
333
  await queryRunner.release();
266
334
  }
267
335
  }
268
- // Caching
269
336
  async clearCacheForAll() {
270
337
  await this.utilsService.clearCache(this.entityName, this.cacheManager);
271
338
  }
272
339
  async clearCacheForId(entities) {
273
340
  await Promise.all(entities.map((item)=>this.utilsService.clearCache(this.entityName, this.cacheManager, item.id)));
274
341
  }
275
- /**
276
- * Helper method to handle errors with proper logging and type safety
277
- */ handleError(error, operation) {
278
- ErrorHandler.logError(this.logger, error, operation, {
279
- entity: this.entityName
342
+ handleError(error, _operation) {
343
+ if (error instanceof Error) {
344
+ throw error;
345
+ }
346
+ throw new InternalServerErrorException({
347
+ message: typeof error === 'string' ? error : 'Unknown error',
348
+ messageKey: ERROR_MESSAGES.INTERNAL
280
349
  });
281
- ErrorHandler.rethrowError(error);
282
350
  }
283
- /** Ensures value is always an array */ ensureArray(value) {
351
+ ensureArray(value) {
284
352
  return Array.isArray(value) ? value : [
285
353
  value
286
354
  ];
287
355
  }
288
- /** Executes operation in transaction with automatic cache clearing */ async executeInTransaction(operation, fn) {
289
- await this.ensureRepositoryInitialized();
356
+ async executeInTransaction(operation, fn) {
357
+ await this.ensureDataSourceRepository();
290
358
  const qr = this.repository.manager.connection.createQueryRunner();
291
359
  await qr.connect();
292
360
  await qr.startTransaction();
@@ -311,14 +379,12 @@ import { In } from 'typeorm';
311
379
  await qr.release();
312
380
  }
313
381
  }
314
- // Hooks (override in child classes)
315
- async ensureRepositoryInitialized() {}
316
382
  async beforeInsertOperation(_dto, _user, _queryRunner) {}
317
- async afterInsertOperation(_entity, _user, _queryRunner) {}
383
+ async afterInsertOperation(_entity, _dto, _user, _queryRunner) {}
318
384
  async beforeUpdateOperation(_dto, _user, _queryRunner) {}
319
- async afterUpdateOperation(_entity, _user, _queryRunner) {}
385
+ async afterUpdateOperation(_entity, _dto, _user, _queryRunner) {}
320
386
  async beforeDeleteOperation(_dto, _user, _queryRunner) {}
321
- async afterDeleteOperation(_entity, _user, _queryRunner) {}
387
+ async afterDeleteOperation(_entity, _dto, _user, _queryRunner) {}
322
388
  async getFilterQuery(query, filter, _user) {
323
389
  Object.entries(filter).forEach(([key, value])=>{
324
390
  query.andWhere(`${this.entityName}.${key} = :value`, {
@@ -361,7 +427,6 @@ import { In } from 'typeorm';
361
427
  isRaw: false
362
428
  };
363
429
  }
364
- // DTO conversion
365
430
  async convertRequestDtoToEntity(dto, user) {
366
431
  return Array.isArray(dto) ? await this.convertArrayDtoToEntities(dto, user) : [
367
432
  await this.convertSingleDtoToEntity(dto, user)
@@ -375,7 +440,10 @@ import { In } from 'typeorm';
375
440
  id: d.id
376
441
  }
377
442
  });
378
- if (!existing) throw new NotFoundException('No such entity data found for update! Please, Try Again.');
443
+ if (!existing) throw new NotFoundException({
444
+ message: 'No such entity data found for update! Please, Try Again.',
445
+ messageKey: ERROR_MESSAGES.NOT_FOUND
446
+ });
379
447
  return Object.assign(existing, d);
380
448
  }
381
449
  delete d.id;
@@ -388,26 +456,113 @@ import { In } from 'typeorm';
388
456
  return Object.assign({}, entity);
389
457
  }
390
458
  convertEntityListToResponseListDto(entities, _isRaw) {
391
- return entities.map((entity)=>Object.assign({}, entity));
459
+ return entities.map((entity)=>this.convertEntityToResponseDto(entity, _isRaw));
392
460
  }
393
461
  async getEntityClass() {
394
- return await this.repository.create();
462
+ return this.repository.create();
395
463
  }
396
- constructor(entityName, repository, cacheManager, utilsService, loggerName, isCacheable = false){
464
+ constructor(entityName, cacheManager, utilsService, _loggerName, isCacheable = false, moduleName, entity, dataSourceProvider){
397
465
  _define_property(this, "entityName", void 0);
398
- _define_property(this, "repository", void 0);
399
466
  _define_property(this, "cacheManager", void 0);
400
467
  _define_property(this, "utilsService", void 0);
401
- _define_property(this, "loggerName", void 0);
468
+ _define_property(this, "_loggerName", void 0);
402
469
  _define_property(this, "isCacheable", void 0);
403
- _define_property(this, "logger", void 0);
470
+ _define_property(this, "moduleName", void 0);
471
+ _define_property(this, "repository", void 0);
472
+ _define_property(this, "repositoryInitialized", void 0);
473
+ _define_property(this, "_entity", void 0);
474
+ _define_property(this, "_dataSourceProvider", void 0);
404
475
  this.entityName = entityName;
405
- this.repository = repository;
406
476
  this.cacheManager = cacheManager;
407
477
  this.utilsService = utilsService;
408
- this.loggerName = loggerName;
478
+ this._loggerName = _loggerName;
409
479
  this.isCacheable = isCacheable;
410
- this.logger = new Logger('ApiService');
411
- this.logger = new Logger(loggerName);
480
+ this.moduleName = moduleName;
481
+ this.repositoryInitialized = false;
482
+ this._entity = entity;
483
+ this._dataSourceProvider = dataSourceProvider;
412
484
  }
413
485
  }
486
+ _ts_decorate([
487
+ LogAction({
488
+ action: 'create'
489
+ }),
490
+ _ts_metadata("design:type", Function),
491
+ _ts_metadata("design:paramtypes", [
492
+ typeof CreateDtoT === "undefined" ? Object : CreateDtoT,
493
+ Object
494
+ ]),
495
+ _ts_metadata("design:returntype", Promise)
496
+ ], ApiService.prototype, "insert", null);
497
+ _ts_decorate([
498
+ LogAction({
499
+ action: 'createMany'
500
+ }),
501
+ _ts_metadata("design:type", Function),
502
+ _ts_metadata("design:paramtypes", [
503
+ typeof Array === "undefined" ? Object : Array,
504
+ Object
505
+ ]),
506
+ _ts_metadata("design:returntype", Promise)
507
+ ], ApiService.prototype, "insertMany", null);
508
+ _ts_decorate([
509
+ LogAction({
510
+ action: 'update'
511
+ }),
512
+ _ts_metadata("design:type", Function),
513
+ _ts_metadata("design:paramtypes", [
514
+ typeof UpdateDtoT === "undefined" ? Object : UpdateDtoT,
515
+ Object
516
+ ]),
517
+ _ts_metadata("design:returntype", Promise)
518
+ ], ApiService.prototype, "update", null);
519
+ _ts_decorate([
520
+ LogAction({
521
+ action: 'updateMany'
522
+ }),
523
+ _ts_metadata("design:type", Function),
524
+ _ts_metadata("design:paramtypes", [
525
+ Array,
526
+ Object
527
+ ]),
528
+ _ts_metadata("design:returntype", Promise)
529
+ ], ApiService.prototype, "updateMany", null);
530
+ _ts_decorate([
531
+ LogAction({
532
+ action: 'bulkUpsert'
533
+ }),
534
+ _ts_metadata("design:type", Function),
535
+ _ts_metadata("design:paramtypes", [
536
+ Array,
537
+ Array,
538
+ Object
539
+ ]),
540
+ _ts_metadata("design:returntype", Promise)
541
+ ], ApiService.prototype, "bulkUpsert", null);
542
+ _ts_decorate([
543
+ LogAction({
544
+ action: 'delete'
545
+ }),
546
+ _ts_metadata("design:type", Function),
547
+ _ts_metadata("design:paramtypes", [
548
+ typeof DeleteDto === "undefined" ? Object : DeleteDto,
549
+ Object
550
+ ]),
551
+ _ts_metadata("design:returntype", Promise)
552
+ ], ApiService.prototype, "delete", null);
553
+ ApiService = _ts_decorate([
554
+ Injectable({
555
+ scope: Scope.REQUEST
556
+ }),
557
+ _ts_metadata("design:type", Function),
558
+ _ts_metadata("design:paramtypes", [
559
+ String,
560
+ typeof HybridCache === "undefined" ? Object : HybridCache,
561
+ typeof UtilsService === "undefined" ? Object : UtilsService,
562
+ String,
563
+ Boolean,
564
+ String,
565
+ typeof EntityTarget === "undefined" ? Object : EntityTarget,
566
+ typeof IDataSourceProvider === "undefined" ? Object : IDataSourceProvider
567
+ ])
568
+ ], ApiService);
@@ -0,0 +1,19 @@
1
+ import { envConfig } from '@flusys/nestjs-core';
2
+ export function getJsonColumnType() {
3
+ const driver = envConfig.getTypeOrmConfig().type;
4
+ if (driver === 'postgres') return 'jsonb';
5
+ if (driver === 'mysql') return 'json';
6
+ return 'simple-json';
7
+ }
8
+ export function getCastIntType() {
9
+ const driver = envConfig.getTypeOrmConfig().type;
10
+ return driver === 'postgres' ? 'INTEGER' : 'UNSIGNED';
11
+ }
12
+ /**
13
+ * Converts MySQL-style `?` placeholders to PostgreSQL `$1, $2, ...` placeholders.
14
+ * No-op for MySQL/MariaDB.
15
+ */ export function buildQuery(sql, dbType) {
16
+ if (dbType !== 'postgres') return sql;
17
+ let index = 0;
18
+ return sql.replace(/\?/g, ()=>`$${++index}`);
19
+ }
@@ -1,8 +1,7 @@
1
1
  export * from './api-controller.class';
2
2
  export * from './api-service.class';
3
- export * from './request-scoped-api.service';
3
+ export * from './handle-custome-db';
4
4
  export * from './hybrid-cache.class';
5
- export * from './winston-logger-adapter.class';
6
5
  export * from './winston.logger.class';
7
6
  // Re-export permission constants for convenience
8
7
  export * from '../constants/permissions';