@mbc-cqrs-serverless/master 0.1.69-beta.0 → 0.1.71-beta.0

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 (59) hide show
  1. package/dist/controllers/master-data.controller.spec.d.ts +1 -0
  2. package/dist/controllers/master-data.controller.spec.js +341 -0
  3. package/dist/controllers/master-data.controller.spec.js.map +1 -0
  4. package/dist/controllers/master-setting.controller.d.ts +2 -1
  5. package/dist/controllers/master-setting.controller.js +12 -0
  6. package/dist/controllers/master-setting.controller.js.map +1 -1
  7. package/dist/controllers/master-setting.controller.spec.d.ts +1 -0
  8. package/dist/controllers/master-setting.controller.spec.js +164 -0
  9. package/dist/controllers/master-setting.controller.spec.js.map +1 -0
  10. package/dist/custom-task/custom-task.module.d.ts +2 -0
  11. package/dist/custom-task/custom-task.module.js +30 -0
  12. package/dist/custom-task/custom-task.module.js.map +1 -0
  13. package/dist/custom-task/event/task-queue-event-factory.d.ts +6 -0
  14. package/dist/custom-task/event/task-queue-event-factory.js +23 -0
  15. package/dist/custom-task/event/task-queue-event-factory.js.map +1 -0
  16. package/dist/custom-task/my-task.controller.d.ts +9 -0
  17. package/dist/custom-task/my-task.controller.js +56 -0
  18. package/dist/custom-task/my-task.controller.js.map +1 -0
  19. package/dist/custom-task/my-task.controller.spec.d.ts +1 -0
  20. package/dist/custom-task/my-task.controller.spec.js +147 -0
  21. package/dist/custom-task/my-task.controller.spec.js.map +1 -0
  22. package/dist/custom-task/my-task.service.d.ts +12 -0
  23. package/dist/custom-task/my-task.service.js +76 -0
  24. package/dist/custom-task/my-task.service.js.map +1 -0
  25. package/dist/custom-task/my-task.service.spec.d.ts +1 -0
  26. package/dist/custom-task/my-task.service.spec.js +111 -0
  27. package/dist/custom-task/my-task.service.spec.js.map +1 -0
  28. package/dist/handler/master-sfn-task.event.d.ts +3 -0
  29. package/dist/handler/master-sfn-task.event.js +8 -0
  30. package/dist/handler/master-sfn-task.event.js.map +1 -0
  31. package/dist/handler/master-sfn-task.handler.d.ts +24 -0
  32. package/dist/handler/master-sfn-task.handler.js +242 -0
  33. package/dist/handler/master-sfn-task.handler.js.map +1 -0
  34. package/dist/helpers/index.d.ts +7 -0
  35. package/dist/helpers/index.js +15 -0
  36. package/dist/helpers/index.js.map +1 -1
  37. package/dist/master.module.js +9 -0
  38. package/dist/master.module.js.map +1 -1
  39. package/dist/services/master-data.service.spec.d.ts +1 -0
  40. package/dist/services/master-data.service.spec.js +1385 -0
  41. package/dist/services/master-data.service.spec.js.map +1 -0
  42. package/dist/services/master-setting.service.d.ts +7 -2
  43. package/dist/services/master-setting.service.js +29 -2
  44. package/dist/services/master-setting.service.js.map +1 -1
  45. package/dist/services/master-setting.service.spec.js +754 -27
  46. package/dist/services/master-setting.service.spec.js.map +1 -1
  47. package/dist/update-scheme.js +1 -10
  48. package/dist/update-scheme.js.map +1 -1
  49. package/package.json +5 -5
  50. package/src/templates/master/handler/master-rds.handler.ts +0 -4
  51. package/src/templates/master/master.module.ts +2 -9
  52. package/src/templates/custom-task/custom-task.module.ts +0 -18
  53. package/src/templates/custom-task/event/task-queue-event-factory.ts +0 -26
  54. package/src/templates/custom-task/my-task.controller.ts +0 -28
  55. package/src/templates/custom-task/my-task.service.ts +0 -99
  56. package/src/templates/master/handler/master-sfn-task.event.ts +0 -3
  57. package/src/templates/master/handler/master-sfn-task.handler.ts +0 -332
  58. package/src/templates/master/master-setting.controller.ts +0 -23
  59. package/src/templates/master/master-setting.service.ts +0 -55
@@ -1,332 +0,0 @@
1
- import {
2
- DataModel,
3
- DataService,
4
- DynamoDbService,
5
- EventHandler,
6
- extractInvokeContext,
7
- IEventHandler,
8
- IInvoke,
9
- KEY_SEPARATOR,
10
- } from '@mbc-cqrs-serverless/core'
11
- import {
12
- CopyType,
13
- DataCopyMode,
14
- DataCopyOptionDto,
15
- MasterCopyDto,
16
- MasterDataService,
17
- MasterSettingService,
18
- } from '@mbc-cqrs-serverless/master'
19
- import { RotateByEnum, SequencesService } from '@mbc-cqrs-serverless/sequence'
20
- import { Logger } from '@nestjs/common'
21
- import { Prisma } from '@prisma/client'
22
- import { chunk } from 'lodash'
23
- import {
24
- DATA_SK_PREFIX,
25
- DEFAULT_TENANT_CODE,
26
- generateMasterPk,
27
- genSequenceSk,
28
- parseId,
29
- sequencePk,
30
- } from 'src/helpers/id'
31
- import { PrismaService } from 'src/prisma'
32
-
33
- import { MasterSfnTaskEvent } from './master-sfn-task.event'
34
-
35
- const BATCH_SIZE = 100
36
-
37
- @EventHandler(MasterSfnTaskEvent)
38
- export class MasterSfnTaskEventHandler
39
- implements IEventHandler<MasterSfnTaskEvent>
40
- {
41
- private readonly logger = new Logger(MasterSfnTaskEventHandler.name)
42
- private sequenceTableName
43
-
44
- constructor(
45
- private readonly dynamoDbService: DynamoDbService,
46
-
47
- private readonly prismaService: PrismaService,
48
- private readonly masterSettingService: MasterSettingService,
49
- private readonly masterDataService: MasterDataService,
50
- private readonly dataService: DataService,
51
- private readonly sequencesService: SequencesService,
52
- ) {
53
- this.sequenceTableName = this.dynamoDbService.getTableName('sequences')
54
- }
55
-
56
- async execute(event: MasterSfnTaskEvent): Promise<any> {
57
- const invokeContext = extractInvokeContext()
58
- const masterCopyDto = event.input?.input as unknown as MasterCopyDto
59
-
60
- this.logger.debug('sfn-event:masterCopyDto:', masterCopyDto)
61
-
62
- const { masterSettingId, targetTenants, copyType, dataCopyOption } =
63
- masterCopyDto
64
- const targetTenant = `${targetTenants[0]}`
65
-
66
- const setting = await this.fetchSetting(masterSettingId)
67
- const masterCode = this.getMasterCodeFromSetting(setting)
68
- if (copyType === CopyType.SETTING_ONLY || copyType === CopyType.BOTH) {
69
- await this.copySettingToTenant(setting, targetTenant, invokeContext)
70
- }
71
-
72
- if (copyType === CopyType.DATA_ONLY || copyType === CopyType.BOTH) {
73
- const isCopySequence = await this.shouldCopySequence(
74
- setting,
75
- targetTenant,
76
- )
77
- if (isCopySequence) {
78
- await this.copySeqToTenant(setting, targetTenant)
79
- }
80
-
81
- const dataToCopy = await this.fetchMasterData(masterCode, dataCopyOption)
82
-
83
- await this.copyDataToTenant(dataToCopy, targetTenant, invokeContext)
84
- }
85
-
86
- this.logger.debug('Completed copy process for tenant:', targetTenant)
87
- return { message: 'Copy successfully', event }
88
- }
89
-
90
- private async fetchSetting(id: string) {
91
- const setting = await this.dataService.getItem(parseId(id))
92
- this.logger.debug('sfn-event-setting', setting)
93
- return setting
94
- }
95
-
96
- private async fetchMasterData(
97
- masterCode: string,
98
- dataCopyOption?: DataCopyOptionDto,
99
- tenant: string = DEFAULT_TENANT_CODE,
100
- ): Promise<Prisma.MasterUncheckedCreateInput[]> {
101
- const where: Prisma.MasterWhereInput = {
102
- masterType: DATA_SK_PREFIX,
103
- masterTypeCode: masterCode,
104
- pk: `MASTER${KEY_SEPARATOR}${tenant}`,
105
- }
106
-
107
- if (dataCopyOption?.mode === DataCopyMode.PARTIAL) {
108
- where.id = { in: dataCopyOption.id }
109
- }
110
-
111
- this.logger.debug('sfn-event-whereCondition', where)
112
- const data = await this.prismaService.master.findMany({ where })
113
- this.logger.debug('sfn-event-dataToCopy', data.length)
114
- return data
115
- }
116
-
117
- private async copySettingToTenant(
118
- setting: DataModel,
119
- tenantCode: string,
120
- invokeContext: IInvoke,
121
- ) {
122
- const sk = setting.sk
123
- const pk = generateMasterPk(tenantCode)
124
- const masterCode = this.getMasterCodeFromSetting(setting)
125
-
126
- const tenantSetting = await this.dataService.getItem({ pk, sk })
127
-
128
- this.logger.debug(
129
- 'sfn-event-copySettingToTenant-tenantSetting',
130
- tenantSetting,
131
- )
132
-
133
- if (tenantSetting && tenantSetting.isDeleted === false) {
134
- this.logger.debug('sfn-event-copySettingToTenant-updateSetting', {
135
- pk,
136
- sk,
137
- })
138
-
139
- await this.masterSettingService.updateSetting(
140
- { pk, sk },
141
- {
142
- name: setting.name,
143
- code: masterCode,
144
- settingValue: setting.attributes as object,
145
- tenantCode,
146
- },
147
- {
148
- invokeContext,
149
- },
150
- )
151
- } else {
152
- this.logger.debug('sfn-event-copySettingToTenant-createTenantSetting', {
153
- pk,
154
- sk,
155
- })
156
-
157
- await this.masterSettingService.createTenantSetting(
158
- {
159
- name: setting.name,
160
- code: masterCode,
161
- settingValue: setting.attributes,
162
- tenantCode,
163
- },
164
- { invokeContext },
165
- )
166
- }
167
- }
168
-
169
- private async copyDataToTenant(
170
- dataToCopy: Prisma.MasterUncheckedCreateInput[],
171
- tenantCode: string,
172
- invokeContext: IInvoke,
173
- ) {
174
- const chunks = chunk(dataToCopy, BATCH_SIZE)
175
- for (const batch of chunks) {
176
- await Promise.all(
177
- batch.map(async (data) => {
178
- const parts = data.sk.split(KEY_SEPARATOR)
179
- const sk =
180
- parts.length > 1 && parts[1].trim() === ''
181
- ? `${data.sk}${data.masterCode}`
182
- : data.sk
183
- const pk = generateMasterPk(tenantCode)
184
-
185
- const tenantData = await this.dataService.getItem({ pk, sk })
186
-
187
- this.logger.debug('sfn-event-copyDataToTenant-tenantData', tenantData)
188
-
189
- // des tenant data is exist and not deleted => update des data same as src data
190
- if (tenantData && tenantData.isDeleted === false) {
191
- this.logger.debug('sfn-event-copyDataToTenant-update', { pk, sk })
192
-
193
- return this.masterDataService.update(
194
- { pk, sk },
195
- {
196
- name: data.name,
197
- attributes: data.attributes as object,
198
- isDeleted: data.isDeleted,
199
- seq: data.seq,
200
- },
201
- {
202
- invokeContext,
203
- },
204
- )
205
- }
206
-
207
- // src data is deleted => do nothing
208
- if (data.isDeleted === true) return
209
-
210
- // src data is exist => create des data
211
- return this.masterDataService.create(
212
- {
213
- code: data.masterCode,
214
- tenantCode,
215
- name: data.name,
216
- settingCode: data.masterTypeCode,
217
- attributes: data.attributes as object,
218
- seq: data.seq,
219
- },
220
- { invokeContext },
221
- )
222
- }),
223
- )
224
- }
225
- }
226
-
227
- private async shouldCopySequence(
228
- setting: DataModel,
229
- tenantCode: string,
230
- ): Promise<boolean> {
231
- const fields = setting?.attributes?.['fields'] || []
232
- const codeField = fields.find((f) => f.physicalName === 'code')
233
- if (codeField?.dataType !== 'auto_number') {
234
- this.logger.debug('Sequence not required: code field not auto_number')
235
- return false
236
- }
237
-
238
- const jcciSeqKey = this.generateSequenceKey(tenantCode, setting)
239
- const { seq: jcciSeq = 0 } =
240
- (await this.sequencesService.getCurrentSequence(jcciSeqKey)) ?? {}
241
- this.logger.debug('sfn-event-shouldCopySequence-jcciSeq', {
242
- jcciSeqKey,
243
- jcciSeq,
244
- })
245
-
246
- if (jcciSeq === 0) {
247
- this.logger.debug('Skipping sequence copy: JCCI sequence is 0')
248
- return false
249
- }
250
-
251
- const tenantSeqKey = this.generateSequenceKey(tenantCode, setting)
252
- const { seq: tenantSeq } =
253
- (await this.sequencesService.getCurrentSequence(tenantSeqKey)) ?? {}
254
- this.logger.debug('sfn-event-shouldCopySequence-tenantSeq', {
255
- tenantSeqKey,
256
- tenantSeq,
257
- })
258
-
259
- if (tenantSeq === undefined || tenantSeq === null) {
260
- this.logger.debug('Tenant sequence missing: copying sequence required')
261
- return true
262
- }
263
-
264
- if (jcciSeq > tenantSeq) {
265
- this.logger.debug('Tenant sequence is behind: copying required')
266
- return true
267
- }
268
-
269
- this.logger.debug('Tenant sequence is up to date or ahead: no copy needed')
270
- return false
271
- }
272
-
273
- private async copySeqToTenant(setting: DataModel, tenantCode: string) {
274
- const fields = setting?.attributes?.['fields'] || []
275
- const codeField = fields.find((f) => f.physicalName === 'code')
276
- const typeCode = codeField.formatCode ?? codeField.dataFormat
277
-
278
- const jcciSeqKey = this.generateSequenceKey(tenantCode, setting)
279
- const { seq: jcciSeq = 0 } =
280
- (await this.sequencesService.getCurrentSequence(jcciSeqKey)) ?? {}
281
-
282
- const tenantSeqKey = this.generateSequenceKey(tenantCode, setting)
283
- const { seq: tenantSeq = 0 } =
284
- (await this.sequencesService.getCurrentSequence(tenantSeqKey)) ?? {}
285
-
286
- const distance = jcciSeq - tenantSeq
287
- this.logger.debug('Copying sequence gap:', {
288
- jcciSeq,
289
- tenantSeq,
290
- distance,
291
- })
292
-
293
- this.logger.debug('putItem', {
294
- pk: tenantSeqKey.pk,
295
- sk: tenantSeqKey.sk,
296
- code: tenantSeqKey.sk,
297
- name: tenantSeqKey.sk.split(KEY_SEPARATOR).at(-1),
298
- seq: jcciSeq,
299
- tenantCode,
300
- type: typeCode,
301
- })
302
-
303
- this.logger.debug('this.sequenceTableName', this.sequenceTableName)
304
-
305
- await this.dynamoDbService.putItem(this.sequenceTableName, {
306
- pk: tenantSeqKey.pk,
307
- sk: tenantSeqKey.sk,
308
- code: tenantSeqKey.sk,
309
- name: tenantSeqKey.sk.split(KEY_SEPARATOR).at(-1),
310
- seq: jcciSeq,
311
- tenantCode,
312
- type: typeCode,
313
- })
314
- }
315
-
316
- private generateSequenceKey(tenantCode: string, setting: DataModel) {
317
- const fields = setting?.attributes?.['fields'] || []
318
- const codeField = fields.find((f) => f.physicalName === 'code')
319
- const seqSk = codeField.formatCode ?? codeField.dataFormat
320
-
321
- const pk = sequencePk(tenantCode)
322
- const masterCode = this.getMasterCodeFromSetting(setting)
323
- const sk = genSequenceSk(seqSk, masterCode, RotateByEnum.NONE)
324
-
325
- return { pk, sk }
326
- }
327
-
328
- private getMasterCodeFromSetting(setting: DataModel): string {
329
- const parts = setting.sk.split(KEY_SEPARATOR)
330
- return parts[1]
331
- }
332
- }
@@ -1,23 +0,0 @@
1
- import { IInvoke, INVOKE_CONTEXT } from '@mbc-cqrs-serverless/core'
2
- import { MasterCopyDto } from '@mbc-cqrs-serverless/master'
3
- import { Body, Controller, Injectable, Post } from '@nestjs/common'
4
- import { ApiTags } from '@nestjs/swagger'
5
-
6
- import { CustomMasterSettingService } from './master-setting.service'
7
-
8
- @ApiTags('master-setting')
9
- @Controller('api/master-setting')
10
- @Injectable()
11
- export class CustomMasterSettingController {
12
- constructor(
13
- private readonly masterSettingService: CustomMasterSettingService,
14
- ) {}
15
-
16
- @Post('/copy')
17
- async copyMaster(
18
- @INVOKE_CONTEXT() invokeContext: IInvoke,
19
- @Body() masterCopyDto: MasterCopyDto,
20
- ): Promise<any> {
21
- return this.masterSettingService.copy(masterCopyDto, { invokeContext })
22
- }
23
- }
@@ -1,55 +0,0 @@
1
- import { DataService, getUserContext, IInvoke } from '@mbc-cqrs-serverless/core'
2
- import { DataCopyMode, MasterCopyDto } from '@mbc-cqrs-serverless/master'
3
- import { TaskService } from '@mbc-cqrs-serverless/task'
4
- import { BadRequestException, Injectable, Logger } from '@nestjs/common'
5
-
6
- import { MASTER_COPY_SK_PREFIX, parseId } from './helpers'
7
-
8
- @Injectable()
9
- export class CustomMasterSettingService {
10
- private readonly logger = new Logger(CustomMasterSettingService.name)
11
-
12
- constructor(
13
- private readonly dataService: DataService,
14
- private readonly taskService: TaskService,
15
- ) {}
16
-
17
- async copy(
18
- masterCopyDto: MasterCopyDto,
19
- opts: { invokeContext: IInvoke },
20
- ): Promise<any> {
21
- this.logger.debug('cmd:', JSON.stringify(masterCopyDto))
22
-
23
- const userContext = getUserContext(opts.invokeContext)
24
-
25
- const { masterSettingId, targetTenants, dataCopyOption } = masterCopyDto
26
-
27
- if (dataCopyOption?.mode === DataCopyMode.PARTIAL) {
28
- if (!dataCopyOption.id?.length) {
29
- throw new BadRequestException('Must provide ID when mode is PARTIAL.')
30
- }
31
- }
32
-
33
- const setting = await this.dataService.getItem(parseId(masterSettingId))
34
-
35
- if (!setting || setting.isDeleted) {
36
- throw new BadRequestException('Master setting does not exist')
37
- }
38
-
39
- const item = targetTenants.map((tenant) => ({
40
- ...masterCopyDto,
41
- targetTenants: [tenant],
42
- }))
43
-
44
- const taskItem = await this.taskService.createStepFunctionTask(
45
- {
46
- input: item,
47
- taskType: `${MASTER_COPY_SK_PREFIX}_${masterSettingId.split('#').at(-1)}`,
48
- tenantCode: userContext.tenantCode,
49
- },
50
- opts,
51
- )
52
-
53
- return taskItem
54
- }
55
- }