UNPKG

@mbc-cqrs-serverless/master

Version:

Master data management such as setting, sequence, etc.

242 lines 11.8 kB
"use strict"; var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); 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; return c > 3 && r && Object.defineProperty(target, key, r), r; }; var __metadata = (this && this.__metadata) || function (k, v) { if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); }; var __param = (this && this.__param) || function (paramIndex, decorator) { return function (target, key) { decorator(target, key, paramIndex); } }; var MasterSfnTaskEventHandler_1; Object.defineProperty(exports, "__esModule", { value: true }); exports.MasterSfnTaskEventHandler = void 0; const core_1 = require("@mbc-cqrs-serverless/core"); const sequence_1 = require("@mbc-cqrs-serverless/sequence"); const common_1 = require("@nestjs/common"); const lodash_1 = require("lodash"); const constants_1 = require("../constants"); const dto_1 = require("../dto"); const helpers_1 = require("../helpers"); const master_module_definition_1 = require("../master.module-definition"); const services_1 = require("../services"); const master_sfn_task_event_1 = require("./master-sfn-task.event"); const BATCH_SIZE = 100; let MasterSfnTaskEventHandler = MasterSfnTaskEventHandler_1 = class MasterSfnTaskEventHandler { constructor(dynamoDbService, prismaService, masterSettingService, masterDataService, dataService, sequencesService) { this.dynamoDbService = dynamoDbService; this.prismaService = prismaService; this.masterSettingService = masterSettingService; this.masterDataService = masterDataService; this.dataService = dataService; this.sequencesService = sequencesService; this.logger = new common_1.Logger(MasterSfnTaskEventHandler_1.name); this.sequenceTableName = this.dynamoDbService.getTableName('sequences'); } async execute(event) { const invokeContext = (0, core_1.extractInvokeContext)(); const masterCopyDto = event.input?.input; this.logger.debug('sfn-event:masterCopyDto:', masterCopyDto); const { masterSettingId, targetTenants, copyType, dataCopyOption } = masterCopyDto; const targetTenant = `${targetTenants[0]}`; const setting = await this.fetchSetting(masterSettingId); const masterCode = this.getMasterCodeFromSetting(setting); if (copyType === dto_1.CopyType.SETTING_ONLY || copyType === dto_1.CopyType.BOTH) { await this.copySettingToTenant(setting, targetTenant, invokeContext); } if (copyType === dto_1.CopyType.DATA_ONLY || copyType === dto_1.CopyType.BOTH) { const isCopySequence = await this.shouldCopySequence(setting, targetTenant); if (isCopySequence) { await this.copySeqToTenant(setting, targetTenant); } const dataToCopy = await this.fetchMasterData(masterCode, dataCopyOption); await this.copyDataToTenant(dataToCopy, targetTenant, invokeContext); } this.logger.debug('Completed copy process for tenant:', targetTenant); return { message: 'Copy successfully', event }; } async fetchSetting(id) { const setting = await this.dataService.getItem((0, helpers_1.parseId)(id)); this.logger.debug('sfn-event-setting', setting); return setting; } async fetchMasterData(masterCode, dataCopyOption, tenant = 'meltec') { const where = { masterType: constants_1.DATA_SK_PREFIX, masterTypeCode: masterCode, pk: `MASTER${core_1.KEY_SEPARATOR}${tenant}`, }; if (dataCopyOption?.mode === dto_1.DataCopyMode.PARTIAL) { where.id = { in: dataCopyOption.id }; } this.logger.debug('sfn-event-whereCondition', where); const data = await this.prismaService.master.findMany({ where }); this.logger.debug('sfn-event-dataToCopy', data.length); return data; } async copySettingToTenant(setting, tenantCode, invokeContext) { const sk = setting.sk; const pk = (0, helpers_1.generateMasterPk)(tenantCode); const masterCode = this.getMasterCodeFromSetting(setting); const tenantSetting = await this.dataService.getItem({ pk, sk }); this.logger.debug('sfn-event-copySettingToTenant-tenantSetting', tenantSetting); if (tenantSetting && tenantSetting.isDeleted === false) { this.logger.debug('sfn-event-copySettingToTenant-updateSetting', { pk, sk, }); await this.masterSettingService.updateSetting({ pk, sk }, { name: setting.name, code: masterCode, settingValue: setting.attributes, tenantCode, }, { invokeContext, }); } else { this.logger.debug('sfn-event-copySettingToTenant-createTenantSetting', { pk, sk, }); await this.masterSettingService.createTenantSetting({ name: setting.name, code: masterCode, settingValue: setting.attributes, tenantCode, }, { invokeContext }); } } async copyDataToTenant(dataToCopy, tenantCode, invokeContext) { const chunks = (0, lodash_1.chunk)(dataToCopy, BATCH_SIZE); for (const batch of chunks) { await Promise.all(batch.map(async (data) => { const parts = data.sk.split(core_1.KEY_SEPARATOR); const sk = parts.length > 1 && parts[1].trim() === '' ? `${data.sk}${data.masterCode}` : data.sk; const pk = (0, helpers_1.generateMasterPk)(tenantCode); const tenantData = await this.dataService.getItem({ pk, sk }); this.logger.debug('sfn-event-copyDataToTenant-tenantData', tenantData); // des tenant data is exist and not deleted => update des data same as src data if (tenantData && tenantData.isDeleted === false) { this.logger.debug('sfn-event-copyDataToTenant-update', { pk, sk }); return this.masterDataService.update({ pk, sk }, { name: data.name, attributes: data.attributes, isDeleted: data.isDeleted, seq: data.seq, }, { invokeContext, }); } // src data is deleted => do nothing if (data.isDeleted === true) return; // src data is exist => create des data return this.masterDataService.create({ code: data.masterCode, tenantCode, name: data.name, settingCode: data.masterTypeCode, attributes: data.attributes, seq: data.seq, }, { invokeContext }); })); } } async shouldCopySequence(setting, tenantCode) { const fields = setting?.attributes?.['fields'] || []; const codeField = fields.find((f) => f.physicalName === 'code'); if (codeField?.dataType !== 'auto_number') { this.logger.debug('Sequence not required: code field not auto_number'); return false; } const jcciSeqKey = this.generateSequenceKey(tenantCode, setting); const { seq: jcciSeq = 0 } = (await this.sequencesService.getCurrentSequence(jcciSeqKey)) ?? {}; this.logger.debug('sfn-event-shouldCopySequence-jcciSeq', { jcciSeqKey, jcciSeq, }); if (jcciSeq === 0) { this.logger.debug('Skipping sequence copy: JCCI sequence is 0'); return false; } const tenantSeqKey = this.generateSequenceKey(tenantCode, setting); const { seq: tenantSeq } = (await this.sequencesService.getCurrentSequence(tenantSeqKey)) ?? {}; this.logger.debug('sfn-event-shouldCopySequence-tenantSeq', { tenantSeqKey, tenantSeq, }); if (tenantSeq === undefined || tenantSeq === null) { this.logger.debug('Tenant sequence missing: copying sequence required'); return true; } if (jcciSeq > tenantSeq) { this.logger.debug('Tenant sequence is behind: copying required'); return true; } this.logger.debug('Tenant sequence is up to date or ahead: no copy needed'); return false; } async copySeqToTenant(setting, tenantCode) { const fields = setting?.attributes?.['fields'] || []; const codeField = fields.find((f) => f.physicalName === 'code'); const typeCode = codeField.formatCode ?? codeField.dataFormat; const jcciSeqKey = this.generateSequenceKey(tenantCode, setting); const { seq: jcciSeq = 0 } = (await this.sequencesService.getCurrentSequence(jcciSeqKey)) ?? {}; const tenantSeqKey = this.generateSequenceKey(tenantCode, setting); const { seq: tenantSeq = 0 } = (await this.sequencesService.getCurrentSequence(tenantSeqKey)) ?? {}; const distance = jcciSeq - tenantSeq; this.logger.debug('Copying sequence gap:', { jcciSeq, tenantSeq, distance, }); this.logger.debug('putItem', { pk: tenantSeqKey.pk, sk: tenantSeqKey.sk, code: tenantSeqKey.sk, name: tenantSeqKey.sk.split(core_1.KEY_SEPARATOR).at(-1), seq: jcciSeq, tenantCode, type: typeCode, }); this.logger.debug('this.sequenceTableName', this.sequenceTableName); await this.dynamoDbService.putItem(this.sequenceTableName, { pk: tenantSeqKey.pk, sk: tenantSeqKey.sk, code: tenantSeqKey.sk, name: tenantSeqKey.sk.split(core_1.KEY_SEPARATOR).at(-1), seq: jcciSeq, tenantCode, type: typeCode, }); } generateSequenceKey(tenantCode, setting) { const fields = setting?.attributes?.['fields'] || []; const codeField = fields.find((f) => f.physicalName === 'code'); const seqSk = codeField.formatCode ?? codeField.dataFormat; const pk = (0, helpers_1.sequencePk)(tenantCode); const masterCode = this.getMasterCodeFromSetting(setting); const sk = (0, helpers_1.genSequenceSk)(seqSk, masterCode, sequence_1.RotateByEnum.NONE); return { pk, sk }; } getMasterCodeFromSetting(setting) { const parts = setting.sk.split(core_1.KEY_SEPARATOR); return parts[1]; } }; exports.MasterSfnTaskEventHandler = MasterSfnTaskEventHandler; exports.MasterSfnTaskEventHandler = MasterSfnTaskEventHandler = MasterSfnTaskEventHandler_1 = __decorate([ (0, core_1.EventHandler)(master_sfn_task_event_1.MasterSfnTaskEvent), __param(1, (0, common_1.Inject)(master_module_definition_1.PRISMA_SERVICE)), __metadata("design:paramtypes", [core_1.DynamoDbService, Object, services_1.MasterSettingService, services_1.MasterDataService, core_1.DataService, sequence_1.SequencesService]) ], MasterSfnTaskEventHandler); //# sourceMappingURL=master-sfn-task.handler.js.map