@mbc-cqrs-serverless/import 0.1.75-beta.0 → 1.0.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.
- package/dist/constant/id.d.ts +3 -0
- package/dist/constant/id.js +7 -0
- package/dist/constant/id.js.map +1 -0
- package/dist/constant/index.d.ts +2 -1
- package/dist/constant/index.js +16 -2
- package/dist/constant/index.js.map +1 -1
- package/dist/constant/queue.d.ts +2 -0
- package/dist/constant/queue.js +6 -0
- package/dist/constant/queue.js.map +1 -0
- package/dist/dto/create-csv-import.dto.d.ts +1 -0
- package/dist/dto/create-csv-import.dto.js +5 -0
- package/dist/dto/create-csv-import.dto.js.map +1 -1
- package/dist/dto/create-import.dto.d.ts +1 -0
- package/dist/dto/create-import.dto.js +5 -0
- package/dist/dto/create-import.dto.js.map +1 -1
- package/dist/dto/create-zip-import.dto.d.ts +5 -0
- package/dist/dto/create-zip-import.dto.js +32 -0
- package/dist/dto/create-zip-import.dto.js.map +1 -0
- package/dist/dto/index.d.ts +1 -0
- package/dist/dto/index.js +1 -0
- package/dist/dto/index.js.map +1 -1
- package/dist/entity/import-entity.d.ts +4 -0
- package/dist/entity/import-entity.js +1 -0
- package/dist/entity/import-entity.js.map +1 -1
- package/dist/event/command-finished.queue.event.handler.d.ts +31 -0
- package/dist/event/command-finished.queue.event.handler.js +126 -0
- package/dist/event/command-finished.queue.event.handler.js.map +1 -0
- package/dist/event/csv-import.queue.event.handler.js +7 -3
- package/dist/event/csv-import.queue.event.handler.js.map +1 -1
- package/dist/event/csv-import.sfn.event.handler.d.ts +2 -0
- package/dist/event/csv-import.sfn.event.handler.js +57 -3
- package/dist/event/csv-import.sfn.event.handler.js.map +1 -1
- package/dist/event/import-status.queue.event.d.ts +15 -0
- package/dist/event/import-status.queue.event.handler.d.ts +16 -0
- package/dist/event/import-status.queue.event.handler.js +82 -0
- package/dist/event/import-status.queue.event.handler.js.map +1 -0
- package/dist/event/import-status.queue.event.js +13 -0
- package/dist/event/import-status.queue.event.js.map +1 -0
- package/dist/event/import.queue.event.handler.js +40 -15
- package/dist/event/import.queue.event.handler.js.map +1 -1
- package/dist/event/index.d.ts +6 -0
- package/dist/event/index.js +6 -0
- package/dist/event/index.js.map +1 -1
- package/dist/event/zip-import.queue.event.handler.d.ts +25 -0
- package/dist/event/zip-import.queue.event.handler.js +183 -0
- package/dist/event/zip-import.queue.event.handler.js.map +1 -0
- package/dist/event/zip-import.sfn.event.d.ts +8 -0
- package/dist/event/zip-import.sfn.event.handler.d.ts +21 -0
- package/dist/event/zip-import.sfn.event.handler.js +94 -0
- package/dist/event/zip-import.sfn.event.handler.js.map +1 -0
- package/dist/event/zip-import.sfn.event.js +34 -0
- package/dist/event/zip-import.sfn.event.js.map +1 -0
- package/dist/helpers/id.d.ts +2 -0
- package/dist/helpers/id.js +15 -0
- package/dist/helpers/id.js.map +1 -0
- package/dist/helpers/index.d.ts +1 -0
- package/dist/helpers/index.js +18 -0
- package/dist/helpers/index.js.map +1 -0
- package/dist/import.controller.d.ts +2 -0
- package/dist/import.controller.js +26 -0
- package/dist/import.controller.js.map +1 -1
- package/dist/import.module.js +8 -0
- package/dist/import.module.js.map +1 -1
- package/dist/import.service.d.ts +30 -1
- package/dist/import.service.js +156 -3
- package/dist/import.service.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
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;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
+
};
|
|
11
|
+
var ImportStatusHandler_1;
|
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
exports.ImportStatusHandler = void 0;
|
|
14
|
+
const client_sfn_1 = require("@aws-sdk/client-sfn");
|
|
15
|
+
const core_1 = require("@mbc-cqrs-serverless/core");
|
|
16
|
+
const common_1 = require("@nestjs/common");
|
|
17
|
+
const constant_1 = require("../constant");
|
|
18
|
+
const import_service_1 = require("../import.service");
|
|
19
|
+
const import_status_queue_event_1 = require("./import-status.queue.event");
|
|
20
|
+
const enum_1 = require("../enum");
|
|
21
|
+
let ImportStatusHandler = ImportStatusHandler_1 = class ImportStatusHandler {
|
|
22
|
+
constructor(importService, sfnService) {
|
|
23
|
+
this.importService = importService;
|
|
24
|
+
this.sfnService = sfnService;
|
|
25
|
+
this.logger = new common_1.Logger(ImportStatusHandler_1.name);
|
|
26
|
+
}
|
|
27
|
+
async execute(event) {
|
|
28
|
+
const notification = JSON.parse(event.body);
|
|
29
|
+
// 1. Filter for the specific event: a completed master CSV job.
|
|
30
|
+
const pk = notification.pk;
|
|
31
|
+
const status = notification.content?.status;
|
|
32
|
+
if (status !== enum_1.ImportStatusEnum.COMPLETED ||
|
|
33
|
+
!pk?.startsWith(`${constant_1.CSV_IMPORT_PK_PREFIX}${core_1.KEY_SEPARATOR}`)) {
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
this.logger.log(`Received completed master CSV job event for: ${notification.id}`);
|
|
37
|
+
try {
|
|
38
|
+
// 2. Get the full import job entity from DynamoDB.
|
|
39
|
+
const importKey = { pk: notification.pk, sk: notification.sk };
|
|
40
|
+
const importJob = await this.importService.getImportByKey(importKey);
|
|
41
|
+
if (!importJob) {
|
|
42
|
+
this.logger.warn(`Could not find import job for key:`, importKey);
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
// 3. Check if a taskToken was saved in its attributes.
|
|
46
|
+
const taskToken = importJob.attributes?.taskToken;
|
|
47
|
+
if (taskToken) {
|
|
48
|
+
this.logger.log(`Found task token. Resuming Step Function.`);
|
|
49
|
+
// 4. Send the success signal back to the waiting Step Function.
|
|
50
|
+
// The output can be the result summary from the import job itself.
|
|
51
|
+
await this.sendTaskSuccess(taskToken, importJob.result);
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
this.logger.log('No task token found in import job attributes. Nothing to do.');
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
catch (error) {
|
|
58
|
+
this.logger.error('Error in ImportStatusHandler:', error);
|
|
59
|
+
throw error;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Sends a success signal to a waiting Step Function task.
|
|
64
|
+
* @param taskToken The unique token of the paused task.
|
|
65
|
+
* @param output The JSON output to send back to the state machine.
|
|
66
|
+
*/
|
|
67
|
+
async sendTaskSuccess(taskToken, output) {
|
|
68
|
+
this.logger.log(`Sending task success for token: ${taskToken}`);
|
|
69
|
+
return this.sfnService.client.send(new client_sfn_1.SendTaskSuccessCommand({
|
|
70
|
+
taskToken: taskToken,
|
|
71
|
+
output: JSON.stringify(output),
|
|
72
|
+
}));
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
exports.ImportStatusHandler = ImportStatusHandler;
|
|
76
|
+
exports.ImportStatusHandler = ImportStatusHandler = ImportStatusHandler_1 = __decorate([
|
|
77
|
+
(0, common_1.Injectable)(),
|
|
78
|
+
(0, core_1.EventHandler)(import_status_queue_event_1.ImportStatusQueueEvent),
|
|
79
|
+
__metadata("design:paramtypes", [import_service_1.ImportService,
|
|
80
|
+
core_1.StepFunctionService])
|
|
81
|
+
], ImportStatusHandler);
|
|
82
|
+
//# sourceMappingURL=import-status.queue.event.handler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"import-status.queue.event.handler.js","sourceRoot":"","sources":["../../src/event/import-status.queue.event.handler.ts"],"names":[],"mappings":";;;;;;;;;;;;;AAAA,oDAA4D;AAC5D,oDAMkC;AAClC,2CAAmD;AAEnD,0CAAkD;AAClD,sDAAiD;AACjD,2EAAoE;AACpE,kCAA0C;AAInC,IAAM,mBAAmB,2BAAzB,MAAM,mBAAmB;IAK9B,YACmB,aAA4B,EAC5B,UAA+B;QAD/B,kBAAa,GAAb,aAAa,CAAe;QAC5B,eAAU,GAAV,UAAU,CAAqB;QAJjC,WAAM,GAAG,IAAI,eAAM,CAAC,qBAAmB,CAAC,IAAI,CAAC,CAAA;IAK3D,CAAC;IAEJ,KAAK,CAAC,OAAO,CAAC,KAA6B;QACzC,MAAM,YAAY,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;QAE3C,gEAAgE;QAChE,MAAM,EAAE,GAAG,YAAY,CAAC,EAAY,CAAA;QACpC,MAAM,MAAM,GAAG,YAAY,CAAC,OAAO,EAAE,MAAM,CAAA;QAE3C,IACE,MAAM,KAAK,uBAAgB,CAAC,SAAS;YACrC,CAAC,EAAE,EAAE,UAAU,CAAC,GAAG,+BAAoB,GAAG,oBAAa,EAAE,CAAC,EAC1D,CAAC;YACD,OAAM;QACR,CAAC;QAED,IAAI,CAAC,MAAM,CAAC,GAAG,CACb,gDAAgD,YAAY,CAAC,EAAE,EAAE,CAClE,CAAA;QAED,IAAI,CAAC;YACH,mDAAmD;YACnD,MAAM,SAAS,GAAc,EAAE,EAAE,EAAE,YAAY,CAAC,EAAE,EAAE,EAAE,EAAE,YAAY,CAAC,EAAE,EAAE,CAAA;YACzE,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,aAAa,CAAC,cAAc,CAAC,SAAS,CAAC,CAAA;YAEpE,IAAI,CAAC,SAAS,EAAE,CAAC;gBACf,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,oCAAoC,EAAE,SAAS,CAAC,CAAA;gBACjE,OAAM;YACR,CAAC;YAED,uDAAuD;YACvD,MAAM,SAAS,GAAG,SAAS,CAAC,UAAU,EAAE,SAAS,CAAA;YACjD,IAAI,SAAS,EAAE,CAAC;gBACd,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,2CAA2C,CAAC,CAAA;gBAE5D,gEAAgE;gBAChE,mEAAmE;gBACnE,MAAM,IAAI,CAAC,eAAe,CAAC,SAAS,EAAE,SAAS,CAAC,MAAM,CAAC,CAAA;YACzD,CAAC;iBAAM,CAAC;gBACN,IAAI,CAAC,MAAM,CAAC,GAAG,CACb,8DAA8D,CAC/D,CAAA;YACH,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,+BAA+B,EAAE,KAAK,CAAC,CAAA;YACzD,MAAM,KAAK,CAAA;QACb,CAAC;IACH,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,eAAe,CAAC,SAAiB,EAAE,MAAW;QAClD,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,mCAAmC,SAAS,EAAE,CAAC,CAAA;QAC/D,OAAO,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,CAChC,IAAI,mCAAsB,CAAC;YACzB,SAAS,EAAE,SAAS;YACpB,MAAM,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC;SAC/B,CAAC,CACH,CAAA;IACH,CAAC;CACF,CAAA;AAvEY,kDAAmB;8BAAnB,mBAAmB;IAF/B,IAAA,mBAAU,GAAE;IACZ,IAAA,mBAAY,EAAC,kDAAsB,CAAC;qCAOD,8BAAa;QAChB,0BAAmB;GAPvC,mBAAmB,CAuE/B"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ImportStatusQueueEvent = void 0;
|
|
4
|
+
class ImportStatusQueueEvent {
|
|
5
|
+
fromSqsRecord(record) {
|
|
6
|
+
Object.assign(this, record, {
|
|
7
|
+
source: record.eventSourceARN,
|
|
8
|
+
});
|
|
9
|
+
return this;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
exports.ImportStatusQueueEvent = ImportStatusQueueEvent;
|
|
13
|
+
//# sourceMappingURL=import-status.queue.event.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"import-status.queue.event.js","sourceRoot":"","sources":["../../src/event/import-status.queue.event.ts"],"names":[],"mappings":";;;AAOA,MAAa,sBAAsB;IAYjC,aAAa,CAAC,MAAiB;QAC7B,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE;YAC1B,MAAM,EAAE,MAAM,CAAC,cAAc;SAC9B,CAAC,CAAA;QACF,OAAO,IAAI,CAAA;IACb,CAAC;CACF;AAlBD,wDAkBC"}
|
|
@@ -22,8 +22,10 @@ exports.ImportQueueEventHandler = void 0;
|
|
|
22
22
|
*/
|
|
23
23
|
const core_1 = require("@mbc-cqrs-serverless/core");
|
|
24
24
|
const common_1 = require("@nestjs/common");
|
|
25
|
+
const constant_1 = require("../constant");
|
|
25
26
|
const comparison_status_enum_1 = require("../enum/comparison-status.enum");
|
|
26
27
|
const import_status_enum_1 = require("../enum/import-status.enum");
|
|
28
|
+
const helpers_1 = require("../helpers");
|
|
27
29
|
const import_module_definition_1 = require("../import.module-definition");
|
|
28
30
|
const import_service_1 = require("../import.service");
|
|
29
31
|
const import_queue_event_1 = require("./import.queue.event");
|
|
@@ -35,10 +37,8 @@ let ImportQueueEventHandler = ImportQueueEventHandler_1 = class ImportQueueEvent
|
|
|
35
37
|
}
|
|
36
38
|
async execute(event) {
|
|
37
39
|
const importEntity = event.importEvent.importEntity;
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
if (importEntity.type === 'CSV_MASTER_JOB') {
|
|
41
|
-
this.logger.debug(`Skipping CSV_MASTER_JOB in main queue handler: ${importEntity.id}`);
|
|
40
|
+
if (!importEntity.id.startsWith(`${constant_1.IMPORT_PK_PREFIX}${core_1.KEY_SEPARATOR}`)) {
|
|
41
|
+
this.logger.debug(`Skipping other type import job in main queue handler: ${importEntity.id}`);
|
|
42
42
|
return;
|
|
43
43
|
}
|
|
44
44
|
await this.handleImport(event);
|
|
@@ -48,7 +48,8 @@ let ImportQueueEventHandler = ImportQueueEventHandler_1 = class ImportQueueEvent
|
|
|
48
48
|
*/
|
|
49
49
|
async handleImport(event) {
|
|
50
50
|
const importKey = event.importEvent.importKey;
|
|
51
|
-
const
|
|
51
|
+
const importEntity = event.importEvent.importEntity;
|
|
52
|
+
const { attributes, tenantCode, type: tableName } = importEntity;
|
|
52
53
|
this.logger.debug(`Processing import job ${importKey.pk}#${importKey.sk} for table: ${tableName}`);
|
|
53
54
|
// 1. Find the correct strategies for this import's table type
|
|
54
55
|
const strategy = this.strategyMap.get(tableName);
|
|
@@ -62,10 +63,16 @@ let ImportQueueEventHandler = ImportQueueEventHandler_1 = class ImportQueueEvent
|
|
|
62
63
|
// 2. Set status to PROCESSING
|
|
63
64
|
await this.importService.updateStatus(importKey, import_status_enum_1.ImportStatusEnum.PROCESSING);
|
|
64
65
|
// 3. Execute all registered strategies in sequence for this record
|
|
65
|
-
|
|
66
|
-
// 4. Finalize the import status as COMPLETED
|
|
67
|
-
await this.importService.updateStatus(
|
|
68
|
-
|
|
66
|
+
await this.executeStrategy(strategy, attributes, tenantCode, importEntity);
|
|
67
|
+
// // 4. Finalize the import status as COMPLETED
|
|
68
|
+
// await this.importService.updateStatus(
|
|
69
|
+
// importKey,
|
|
70
|
+
// ImportStatusEnum.COMPLETED,
|
|
71
|
+
// { result },
|
|
72
|
+
// )
|
|
73
|
+
// this.logger.log(
|
|
74
|
+
// `Successfully completed import job: ${importKey.pk}#${importKey.sk}`,
|
|
75
|
+
// )
|
|
69
76
|
}
|
|
70
77
|
catch (error) {
|
|
71
78
|
// 5. Handle any errors during processing
|
|
@@ -86,29 +93,47 @@ let ImportQueueEventHandler = ImportQueueEventHandler_1 = class ImportQueueEvent
|
|
|
86
93
|
* Executes the full lifecycle (compare, map, save) for a single strategy.
|
|
87
94
|
* @returns The result of the create/update operation or a status message.
|
|
88
95
|
*/
|
|
89
|
-
async executeStrategy(strategy, attributes, tenantCode) {
|
|
96
|
+
async executeStrategy(strategy, attributes, tenantCode, importEntity) {
|
|
90
97
|
// 1. Determine if there are changes
|
|
91
98
|
const compareResult = await strategy.compare(attributes, tenantCode);
|
|
99
|
+
const importKey = {
|
|
100
|
+
pk: importEntity.pk,
|
|
101
|
+
sk: importEntity.sk,
|
|
102
|
+
};
|
|
92
103
|
if (compareResult.status === comparison_status_enum_1.ComparisonStatus.EQUAL) {
|
|
93
|
-
|
|
104
|
+
this.logger.log(`No changes for import job ${importEntity.id}, marking as completed.`);
|
|
105
|
+
await this.importService.updateStatus(importKey, import_status_enum_1.ImportStatusEnum.COMPLETED, { result: { status: 'EQUAL', message: 'No changes detected.' } });
|
|
106
|
+
const skParts = importEntity.sk.split(core_1.KEY_SEPARATOR);
|
|
107
|
+
const parentId = skParts.slice(0, -1).join(core_1.KEY_SEPARATOR);
|
|
108
|
+
if (parentId.startsWith(constant_1.CSV_IMPORT_PK_PREFIX)) {
|
|
109
|
+
this.logger.debug(`Updating parent job counter for EQUAL status child: ${importEntity.id}`);
|
|
110
|
+
const parentKey = (0, helpers_1.parseId)(parentId);
|
|
111
|
+
// Since the status is EQUAL, the child "succeeded" in its processing.
|
|
112
|
+
await this.importService.incrementParentJobCounters(parentKey, true);
|
|
113
|
+
}
|
|
114
|
+
return; // Stop execution for this case
|
|
94
115
|
}
|
|
95
116
|
// 2. Map the attributes to the correct CommandService input model
|
|
96
117
|
// The strategy now handles the logic of building the payload.
|
|
97
118
|
const mappedData = await strategy.map(compareResult.status, attributes, tenantCode, compareResult.existingData);
|
|
98
119
|
const commandService = strategy.getCommandService();
|
|
99
|
-
let
|
|
120
|
+
let result;
|
|
100
121
|
// 3. Execute the appropriate command
|
|
101
122
|
const invokeContext = (0, core_1.extractInvokeContext)();
|
|
102
123
|
const options = {
|
|
103
124
|
invokeContext,
|
|
125
|
+
source: importEntity.id,
|
|
104
126
|
};
|
|
105
127
|
if (compareResult.status === comparison_status_enum_1.ComparisonStatus.NOT_EXIST) {
|
|
106
|
-
|
|
128
|
+
result = await commandService.publishAsync(mappedData, options);
|
|
129
|
+
// 4. Finalize the import status as COMPLETED
|
|
130
|
+
await this.importService.updateStatus(importKey, import_status_enum_1.ImportStatusEnum.PROCESSING, { result: result });
|
|
131
|
+
this.logger.log(`Successfully completed import job: ${importKey.pk}#${importKey.sk}`);
|
|
107
132
|
}
|
|
108
133
|
else {
|
|
109
|
-
|
|
134
|
+
result = await commandService.publishPartialUpdateAsync(mappedData, options);
|
|
135
|
+
await this.importService.updateStatus(importKey, import_status_enum_1.ImportStatusEnum.PROCESSING, { result: result });
|
|
110
136
|
}
|
|
111
|
-
return finalResult;
|
|
112
137
|
}
|
|
113
138
|
};
|
|
114
139
|
exports.ImportQueueEventHandler = ImportQueueEventHandler;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"import.queue.event.handler.js","sourceRoot":"","sources":["../../src/event/import.queue.event.handler.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA;;;;;GAKG;AACH,
|
|
1
|
+
{"version":3,"file":"import.queue.event.handler.js","sourceRoot":"","sources":["../../src/event/import.queue.event.handler.ts"],"names":[],"mappings":"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"}
|
package/dist/event/index.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
export * from './command-finished.queue.event.handler';
|
|
1
2
|
export * from './csv-import.queue.event.handler';
|
|
2
3
|
export * from './csv-import.sfn.event';
|
|
3
4
|
export * from './csv-import.sfn.event.handler';
|
|
@@ -5,3 +6,8 @@ export * from './import.event';
|
|
|
5
6
|
export * from './import.event.handler';
|
|
6
7
|
export * from './import.queue.event';
|
|
7
8
|
export * from './import.queue.event.handler';
|
|
9
|
+
export * from './import-status.queue.event';
|
|
10
|
+
export * from './import-status.queue.event.handler';
|
|
11
|
+
export * from './zip-import.queue.event.handler';
|
|
12
|
+
export * from './zip-import.sfn.event';
|
|
13
|
+
export * from './zip-import.sfn.event.handler';
|
package/dist/event/index.js
CHANGED
|
@@ -14,6 +14,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
14
14
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./command-finished.queue.event.handler"), exports);
|
|
17
18
|
__exportStar(require("./csv-import.queue.event.handler"), exports);
|
|
18
19
|
__exportStar(require("./csv-import.sfn.event"), exports);
|
|
19
20
|
__exportStar(require("./csv-import.sfn.event.handler"), exports);
|
|
@@ -21,4 +22,9 @@ __exportStar(require("./import.event"), exports);
|
|
|
21
22
|
__exportStar(require("./import.event.handler"), exports);
|
|
22
23
|
__exportStar(require("./import.queue.event"), exports);
|
|
23
24
|
__exportStar(require("./import.queue.event.handler"), exports);
|
|
25
|
+
__exportStar(require("./import-status.queue.event"), exports);
|
|
26
|
+
__exportStar(require("./import-status.queue.event.handler"), exports);
|
|
27
|
+
__exportStar(require("./zip-import.queue.event.handler"), exports);
|
|
28
|
+
__exportStar(require("./zip-import.sfn.event"), exports);
|
|
29
|
+
__exportStar(require("./zip-import.sfn.event.handler"), exports);
|
|
24
30
|
//# sourceMappingURL=index.js.map
|
package/dist/event/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/event/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,mEAAgD;AAChD,yDAAsC;AACtC,iEAA8C;AAC9C,iDAA8B;AAC9B,yDAAsC;AACtC,uDAAoC;AACpC,+DAA4C"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/event/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,yEAAsD;AACtD,mEAAgD;AAChD,yDAAsC;AACtC,iEAA8C;AAC9C,iDAA8B;AAC9B,yDAAsC;AACtC,uDAAoC;AACpC,+DAA4C;AAC5C,8DAA2C;AAC3C,sEAAmD;AACnD,mEAAgD;AAChD,yDAAsC;AACtC,iEAA8C"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { IEventHandler, S3Service, StepFunctionService } from '@mbc-cqrs-serverless/core';
|
|
2
|
+
import { ConfigService } from '@nestjs/config';
|
|
3
|
+
import { ImportService } from '../import.service';
|
|
4
|
+
import { ImportQueueEvent } from './import.queue.event';
|
|
5
|
+
export declare class ZipImportQueueEventHandler implements IEventHandler<ImportQueueEvent> {
|
|
6
|
+
private readonly configService;
|
|
7
|
+
private readonly sfnService;
|
|
8
|
+
private readonly importService;
|
|
9
|
+
private readonly s3Service;
|
|
10
|
+
private readonly logger;
|
|
11
|
+
private readonly zipOrchestratorArn;
|
|
12
|
+
constructor(configService: ConfigService, sfnService: StepFunctionService, importService: ImportService, s3Service: S3Service);
|
|
13
|
+
execute(event: ImportQueueEvent): Promise<any>;
|
|
14
|
+
private getS3Stream;
|
|
15
|
+
/**
|
|
16
|
+
* Helper function to convert a Readable stream into a Buffer.
|
|
17
|
+
* Required for yauzl, which operates on a complete data source.
|
|
18
|
+
*/
|
|
19
|
+
private streamToBuffer;
|
|
20
|
+
/**
|
|
21
|
+
* Re-implemented using the `jszip` library, which is more tolerant
|
|
22
|
+
* of malformed ZIP archives.
|
|
23
|
+
*/
|
|
24
|
+
private unzipAndUpload;
|
|
25
|
+
}
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
19
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
20
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
21
|
+
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;
|
|
22
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
23
|
+
};
|
|
24
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
25
|
+
var ownKeys = function(o) {
|
|
26
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
27
|
+
var ar = [];
|
|
28
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
29
|
+
return ar;
|
|
30
|
+
};
|
|
31
|
+
return ownKeys(o);
|
|
32
|
+
};
|
|
33
|
+
return function (mod) {
|
|
34
|
+
if (mod && mod.__esModule) return mod;
|
|
35
|
+
var result = {};
|
|
36
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
37
|
+
__setModuleDefault(result, mod);
|
|
38
|
+
return result;
|
|
39
|
+
};
|
|
40
|
+
})();
|
|
41
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
42
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
43
|
+
};
|
|
44
|
+
var ZipImportQueueEventHandler_1;
|
|
45
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
46
|
+
exports.ZipImportQueueEventHandler = void 0;
|
|
47
|
+
const client_s3_1 = require("@aws-sdk/client-s3");
|
|
48
|
+
const lib_storage_1 = require("@aws-sdk/lib-storage");
|
|
49
|
+
const core_1 = require("@mbc-cqrs-serverless/core");
|
|
50
|
+
const common_1 = require("@nestjs/common");
|
|
51
|
+
const config_1 = require("@nestjs/config");
|
|
52
|
+
const JSZip = __importStar(require("jszip"));
|
|
53
|
+
const stream_1 = require("stream");
|
|
54
|
+
const constant_1 = require("../constant");
|
|
55
|
+
const enum_1 = require("../enum");
|
|
56
|
+
const import_service_1 = require("../import.service");
|
|
57
|
+
const import_queue_event_1 = require("./import.queue.event");
|
|
58
|
+
let ZipImportQueueEventHandler = ZipImportQueueEventHandler_1 = class ZipImportQueueEventHandler {
|
|
59
|
+
constructor(configService, sfnService, importService, s3Service) {
|
|
60
|
+
this.configService = configService;
|
|
61
|
+
this.sfnService = sfnService;
|
|
62
|
+
this.importService = importService;
|
|
63
|
+
this.s3Service = s3Service;
|
|
64
|
+
this.logger = new common_1.Logger(ZipImportQueueEventHandler_1.name);
|
|
65
|
+
this.zipOrchestratorArn = this.configService.get('SFN_IMPORT_ZIP_ORCHESTRATOR_ARN');
|
|
66
|
+
}
|
|
67
|
+
async execute(event) {
|
|
68
|
+
const importEntity = event.importEvent.importEntity;
|
|
69
|
+
if (!importEntity.pk.startsWith(constant_1.ZIP_IMPORT_PK_PREFIX)) {
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
const importKey = event.importEvent.importKey;
|
|
73
|
+
const zipJobAttributes = importEntity.attributes;
|
|
74
|
+
this.logger.log(`Received master ZIP job from queue: ${importEntity.id} for file ${zipJobAttributes.key}`);
|
|
75
|
+
try {
|
|
76
|
+
await this.importService.updateStatus(importKey, enum_1.ImportStatusEnum.PROCESSING, { result: { step: 'Unzipping archive' } });
|
|
77
|
+
const s3ReadStream = await this.getS3Stream(zipJobAttributes);
|
|
78
|
+
const extractedFileKeys = await this.unzipAndUpload(s3ReadStream, zipJobAttributes, importEntity.id);
|
|
79
|
+
if (extractedFileKeys.length === 0) {
|
|
80
|
+
throw new Error('No CSV files found in the ZIP archive.');
|
|
81
|
+
}
|
|
82
|
+
// Sort the file keys alphabetically to ensure sequential processing order
|
|
83
|
+
extractedFileKeys.sort();
|
|
84
|
+
await this.importService.updateImportJob(importKey, {
|
|
85
|
+
set: {
|
|
86
|
+
attributes: {
|
|
87
|
+
...zipJobAttributes,
|
|
88
|
+
extractedFileKeys, // Save the list of files to the master job
|
|
89
|
+
},
|
|
90
|
+
},
|
|
91
|
+
});
|
|
92
|
+
// Start the main orchestrator with the sorted list of files
|
|
93
|
+
await this.sfnService.startExecution(this.zipOrchestratorArn, {
|
|
94
|
+
masterJobKey: importKey,
|
|
95
|
+
sortedS3Keys: extractedFileKeys,
|
|
96
|
+
// Pass through original attributes needed by the sub-workflows
|
|
97
|
+
parameters: {
|
|
98
|
+
bucket: zipJobAttributes.bucket,
|
|
99
|
+
tenantCode: zipJobAttributes.tenantCode,
|
|
100
|
+
},
|
|
101
|
+
}, `${zipJobAttributes.tenantCode}-zip-import-${Date.now()}`);
|
|
102
|
+
this.logger.log(`Started ZIP Orchestrator Step Function for master job ${importEntity.id}`);
|
|
103
|
+
}
|
|
104
|
+
catch (error) {
|
|
105
|
+
this.logger.error(`Failed to process ZIP job ${importEntity.id}`, error);
|
|
106
|
+
await this.importService.updateStatus(importKey, enum_1.ImportStatusEnum.FAILED, {
|
|
107
|
+
error: {
|
|
108
|
+
message: `Failed during unzip and preparation: ${error.message}`,
|
|
109
|
+
},
|
|
110
|
+
});
|
|
111
|
+
throw error;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
async getS3Stream(attributes) {
|
|
115
|
+
const { Body: s3Stream } = await this.s3Service.client.send(new client_s3_1.GetObjectCommand({
|
|
116
|
+
Bucket: attributes.bucket,
|
|
117
|
+
Key: attributes.key,
|
|
118
|
+
}));
|
|
119
|
+
if (!(s3Stream instanceof stream_1.Readable)) {
|
|
120
|
+
throw new Error('Failed to get a readable stream from S3 object.');
|
|
121
|
+
}
|
|
122
|
+
return s3Stream;
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Helper function to convert a Readable stream into a Buffer.
|
|
126
|
+
* Required for yauzl, which operates on a complete data source.
|
|
127
|
+
*/
|
|
128
|
+
streamToBuffer(stream) {
|
|
129
|
+
return new Promise((resolve, reject) => {
|
|
130
|
+
const chunks = [];
|
|
131
|
+
stream.on('data', (chunk) => chunks.push(chunk));
|
|
132
|
+
stream.on('error', reject);
|
|
133
|
+
stream.on('end', () => resolve(Buffer.concat(chunks)));
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Re-implemented using the `jszip` library, which is more tolerant
|
|
138
|
+
* of malformed ZIP archives.
|
|
139
|
+
*/
|
|
140
|
+
async unzipAndUpload(zipStream, attributes, jobId) {
|
|
141
|
+
const tempS3Prefix = `unzipped/${attributes.tenantCode}/${jobId.replace(/[^a-zA-Z0-9]/g, '_')}`;
|
|
142
|
+
// 1. JSZip operates on a buffer, so we first load the stream into memory.
|
|
143
|
+
const zipBuffer = await this.streamToBuffer(zipStream);
|
|
144
|
+
// 2. Load the ZIP data.
|
|
145
|
+
const zip = await JSZip.loadAsync(zipBuffer);
|
|
146
|
+
const uploadPromises = [];
|
|
147
|
+
const extractedFileKeys = [];
|
|
148
|
+
// 3. Loop through each file in the archive.
|
|
149
|
+
for (const file of Object.values(zip.files)) {
|
|
150
|
+
// 4. Skip directories and process only CSV files.
|
|
151
|
+
if (!file.dir && file.name.toLowerCase().endsWith('.csv')) {
|
|
152
|
+
this.logger.debug(`Extracting ${file.name} ...`);
|
|
153
|
+
// 5. Decompress the file content into a buffer.
|
|
154
|
+
const contentBuffer = await file.async('nodebuffer');
|
|
155
|
+
const s3UploadKey = `${tempS3Prefix}/${file.name}`;
|
|
156
|
+
extractedFileKeys.push(s3UploadKey);
|
|
157
|
+
// 6. Create and track the S3 upload promise.
|
|
158
|
+
const upload = new lib_storage_1.Upload({
|
|
159
|
+
client: this.s3Service.client,
|
|
160
|
+
params: {
|
|
161
|
+
Bucket: attributes.bucket,
|
|
162
|
+
Key: s3UploadKey,
|
|
163
|
+
Body: contentBuffer,
|
|
164
|
+
},
|
|
165
|
+
});
|
|
166
|
+
uploadPromises.push(upload.done());
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
// 7. Wait for all files to be uploaded to S3.
|
|
170
|
+
await Promise.all(uploadPromises);
|
|
171
|
+
this.logger.log(`Finished unzipping with JSZip. Uploaded ${extractedFileKeys.length} CSV files.`);
|
|
172
|
+
return extractedFileKeys;
|
|
173
|
+
}
|
|
174
|
+
};
|
|
175
|
+
exports.ZipImportQueueEventHandler = ZipImportQueueEventHandler;
|
|
176
|
+
exports.ZipImportQueueEventHandler = ZipImportQueueEventHandler = ZipImportQueueEventHandler_1 = __decorate([
|
|
177
|
+
(0, core_1.EventHandler)(import_queue_event_1.ImportQueueEvent),
|
|
178
|
+
__metadata("design:paramtypes", [config_1.ConfigService,
|
|
179
|
+
core_1.StepFunctionService,
|
|
180
|
+
import_service_1.ImportService,
|
|
181
|
+
core_1.S3Service])
|
|
182
|
+
], ZipImportQueueEventHandler);
|
|
183
|
+
//# sourceMappingURL=zip-import.queue.event.handler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"zip-import.queue.event.handler.js","sourceRoot":"","sources":["../../src/event/zip-import.queue.event.handler.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,kDAAqD;AACrD,sDAA6C;AAC7C,oDAKkC;AAClC,2CAAuC;AACvC,2CAA8C;AAC9C,6CAA8B;AAC9B,mCAAiC;AAEjC,0CAAkD;AAElD,kCAA0C;AAC1C,sDAAiD;AACjD,6DAAuD;AAGhD,IAAM,0BAA0B,kCAAhC,MAAM,0BAA0B;IAMrC,YACmB,aAA4B,EAC5B,UAA+B,EAC/B,aAA4B,EAC5B,SAAoB;QAHpB,kBAAa,GAAb,aAAa,CAAe;QAC5B,eAAU,GAAV,UAAU,CAAqB;QAC/B,kBAAa,GAAb,aAAa,CAAe;QAC5B,cAAS,GAAT,SAAS,CAAW;QAPtB,WAAM,GAAG,IAAI,eAAM,CAAC,4BAA0B,CAAC,IAAI,CAAC,CAAA;QASnE,IAAI,CAAC,kBAAkB,GAAG,IAAI,CAAC,aAAa,CAAC,GAAG,CAC9C,iCAAiC,CAClC,CAAA;IACH,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,KAAuB;QACnC,MAAM,YAAY,GAAG,KAAK,CAAC,WAAW,CAAC,YAAY,CAAA;QAEnD,IAAI,CAAC,YAAY,CAAC,EAAE,CAAC,UAAU,CAAC,+BAAoB,CAAC,EAAE,CAAC;YACtD,OAAM;QACR,CAAC;QAED,MAAM,SAAS,GAAG,KAAK,CAAC,WAAW,CAAC,SAAS,CAAA;QAC7C,MAAM,gBAAgB,GAAG,YAAY,CAAC,UAAgC,CAAA;QACtE,IAAI,CAAC,MAAM,CAAC,GAAG,CACb,uCAAuC,YAAY,CAAC,EAAE,aAAa,gBAAgB,CAAC,GAAG,EAAE,CAC1F,CAAA;QAED,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,aAAa,CAAC,YAAY,CACnC,SAAS,EACT,uBAAgB,CAAC,UAAU,EAC3B,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,mBAAmB,EAAE,EAAE,CAC1C,CAAA;YAED,MAAM,YAAY,GAAG,MAAM,IAAI,CAAC,WAAW,CAAC,gBAAgB,CAAC,CAAA;YAC7D,MAAM,iBAAiB,GAAG,MAAM,IAAI,CAAC,cAAc,CACjD,YAAY,EACZ,gBAAgB,EAChB,YAAY,CAAC,EAAE,CAChB,CAAA;YAED,IAAI,iBAAiB,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACnC,MAAM,IAAI,KAAK,CAAC,wCAAwC,CAAC,CAAA;YAC3D,CAAC;YAED,0EAA0E;YAC1E,iBAAiB,CAAC,IAAI,EAAE,CAAA;YAExB,MAAM,IAAI,CAAC,aAAa,CAAC,eAAe,CAAC,SAAS,EAAE;gBAClD,GAAG,EAAE;oBACH,UAAU,EAAE;wBACV,GAAG,gBAAgB;wBACnB,iBAAiB,EAAE,2CAA2C;qBAC/D;iBACF;aACF,CAAC,CAAA;YAEF,4DAA4D;YAC5D,MAAM,IAAI,CAAC,UAAU,CAAC,cAAc,CAClC,IAAI,CAAC,kBAAkB,EACvB;gBACE,YAAY,EAAE,SAAS;gBACvB,YAAY,EAAE,iBAAiB;gBAC/B,+DAA+D;gBAC/D,UAAU,EAAE;oBACV,MAAM,EAAE,gBAAgB,CAAC,MAAM;oBAC/B,UAAU,EAAE,gBAAgB,CAAC,UAAU;iBACxC;aACF,EACD,GAAG,gBAAgB,CAAC,UAAU,eAAe,IAAI,CAAC,GAAG,EAAE,EAAE,CAC1D,CAAA;YAED,IAAI,CAAC,MAAM,CAAC,GAAG,CACb,yDAAyD,YAAY,CAAC,EAAE,EAAE,CAC3E,CAAA;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,6BAA6B,YAAY,CAAC,EAAE,EAAE,EAAE,KAAK,CAAC,CAAA;YACxE,MAAM,IAAI,CAAC,aAAa,CAAC,YAAY,CACnC,SAAS,EACT,uBAAgB,CAAC,MAAM,EACvB;gBACE,KAAK,EAAE;oBACL,OAAO,EAAE,wCACN,KAAe,CAAC,OACnB,EAAE;iBACH;aACF,CACF,CAAA;YACD,MAAM,KAAK,CAAA;QACb,CAAC;IACH,CAAC;IAEO,KAAK,CAAC,WAAW,CAAC,UAA8B;QACtD,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,CACzD,IAAI,4BAAgB,CAAC;YACnB,MAAM,EAAE,UAAU,CAAC,MAAM;YACzB,GAAG,EAAE,UAAU,CAAC,GAAG;SACpB,CAAC,CACH,CAAA;QAED,IAAI,CAAC,CAAC,QAAQ,YAAY,iBAAQ,CAAC,EAAE,CAAC;YACpC,MAAM,IAAI,KAAK,CAAC,iDAAiD,CAAC,CAAA;QACpE,CAAC;QACD,OAAO,QAAQ,CAAA;IACjB,CAAC;IAED;;;OAGG;IACK,cAAc,CAAC,MAAgB;QACrC,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACrC,MAAM,MAAM,GAAa,EAAE,CAAA;YAC3B,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAA;YAChD,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,CAAA;YAC1B,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAA;QACxD,CAAC,CAAC,CAAA;IACJ,CAAC;IAED;;;OAGG;IACK,KAAK,CAAC,cAAc,CAC1B,SAAmB,EACnB,UAA8B,EAC9B,KAAa;QAEb,MAAM,YAAY,GAAG,YAAY,UAAU,CAAC,UAAU,IAAI,KAAK,CAAC,OAAO,CAAC,eAAe,EAAE,GAAG,CAAC,EAAE,CAAA;QAE/F,0EAA0E;QAC1E,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,cAAc,CAAC,SAAS,CAAC,CAAA;QAEtD,wBAAwB;QACxB,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,SAAS,CAAC,SAAS,CAAC,CAAA;QAE5C,MAAM,cAAc,GAAmB,EAAE,CAAA;QACzC,MAAM,iBAAiB,GAAa,EAAE,CAAA;QAEtC,4CAA4C;QAC5C,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;YAC5C,kDAAkD;YAClD,IAAI,CAAC,IAAI,CAAC,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;gBAC1D,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,cAAc,IAAI,CAAC,IAAI,MAAM,CAAC,CAAA;gBAEhD,gDAAgD;gBAChD,MAAM,aAAa,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,CAAA;gBAEpD,MAAM,WAAW,GAAG,GAAG,YAAY,IAAI,IAAI,CAAC,IAAI,EAAE,CAAA;gBAClD,iBAAiB,CAAC,IAAI,CAAC,WAAW,CAAC,CAAA;gBAEnC,6CAA6C;gBAC7C,MAAM,MAAM,GAAG,IAAI,oBAAM,CAAC;oBACxB,MAAM,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM;oBAC7B,MAAM,EAAE;wBACN,MAAM,EAAE,UAAU,CAAC,MAAM;wBACzB,GAAG,EAAE,WAAW;wBAChB,IAAI,EAAE,aAAa;qBACpB;iBACF,CAAC,CAAA;gBAEF,cAAc,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAA;YACpC,CAAC;QACH,CAAC;QAED,8CAA8C;QAC9C,MAAM,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,CAAA;QAEjC,IAAI,CAAC,MAAM,CAAC,GAAG,CACb,2CAA2C,iBAAiB,CAAC,MAAM,aAAa,CACjF,CAAA;QAED,OAAO,iBAAiB,CAAA;IAC1B,CAAC;CACF,CAAA;AAjLY,gEAA0B;qCAA1B,0BAA0B;IADtC,IAAA,mBAAY,EAAC,qCAAgB,CAAC;qCAQK,sBAAa;QAChB,0BAAmB;QAChB,8BAAa;QACjB,gBAAS;GAV5B,0BAA0B,CAiLtC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { IEvent, StepFunctionsContext } from '@mbc-cqrs-serverless/core';
|
|
2
|
+
export declare class ZipImportSfnEvent implements IEvent {
|
|
3
|
+
source: string;
|
|
4
|
+
context: StepFunctionsContext;
|
|
5
|
+
input: string | any[];
|
|
6
|
+
taskToken: string;
|
|
7
|
+
constructor(event?: Partial<ZipImportSfnEvent>);
|
|
8
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { IEventHandler } from '@mbc-cqrs-serverless/core';
|
|
2
|
+
import { ImportService } from '../import.service';
|
|
3
|
+
import { ZipImportSfnEvent } from './zip-import.sfn.event';
|
|
4
|
+
export declare class ZipImportSfnEventHandler implements IEventHandler<ZipImportSfnEvent> {
|
|
5
|
+
private readonly importService;
|
|
6
|
+
private readonly logger;
|
|
7
|
+
constructor(importService: ImportService);
|
|
8
|
+
execute(event: ZipImportSfnEvent): Promise<any>;
|
|
9
|
+
/**
|
|
10
|
+
* Handles the trigger_single_csv_and_wait state from the orchestrator.
|
|
11
|
+
* It extracts the tableName from the filename and starts a new CSV import job,
|
|
12
|
+
* passing along the taskToken so the orchestrator can be notified upon completion.
|
|
13
|
+
*/
|
|
14
|
+
private triggerSingleCsvJob;
|
|
15
|
+
/**
|
|
16
|
+
* Handles the final state of the orchestrator.
|
|
17
|
+
* It aggregates the results from all processed CSV files and sets the final
|
|
18
|
+
* status on the original ZIP_MASTER_JOB.
|
|
19
|
+
*/
|
|
20
|
+
private finalizeZipMasterJob;
|
|
21
|
+
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
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;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
+
};
|
|
11
|
+
var ZipImportSfnEventHandler_1;
|
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
exports.ZipImportSfnEventHandler = void 0;
|
|
14
|
+
const core_1 = require("@mbc-cqrs-serverless/core");
|
|
15
|
+
const common_1 = require("@nestjs/common");
|
|
16
|
+
const enum_1 = require("../enum");
|
|
17
|
+
const import_service_1 = require("../import.service");
|
|
18
|
+
const zip_import_sfn_event_1 = require("./zip-import.sfn.event");
|
|
19
|
+
let ZipImportSfnEventHandler = ZipImportSfnEventHandler_1 = class ZipImportSfnEventHandler {
|
|
20
|
+
constructor(importService) {
|
|
21
|
+
this.importService = importService;
|
|
22
|
+
this.logger = new common_1.Logger(ZipImportSfnEventHandler_1.name);
|
|
23
|
+
}
|
|
24
|
+
async execute(event) {
|
|
25
|
+
const stateName = event.context.State.Name;
|
|
26
|
+
this.logger.log(`Executing state: ${stateName} for Zip SFN`);
|
|
27
|
+
if (stateName === 'trigger_single_csv_and_wait') {
|
|
28
|
+
return this.triggerSingleCsvJob(event);
|
|
29
|
+
}
|
|
30
|
+
if (stateName === 'finalize_zip_job') {
|
|
31
|
+
return this.finalizeZipMasterJob(event);
|
|
32
|
+
}
|
|
33
|
+
this.logger.warn(`Unknown state name in ZipImportSfnEventHandler: ${stateName}`);
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Handles the trigger_single_csv_and_wait state from the orchestrator.
|
|
37
|
+
* It extracts the tableName from the filename and starts a new CSV import job,
|
|
38
|
+
* passing along the taskToken so the orchestrator can be notified upon completion.
|
|
39
|
+
*/
|
|
40
|
+
async triggerSingleCsvJob(event) {
|
|
41
|
+
const s3Key = event.input?.s3Key || event.input;
|
|
42
|
+
const { taskToken } = event;
|
|
43
|
+
const { masterJobKey, parameters } = event.context.Execution.Input;
|
|
44
|
+
this.logger.log(`Triggering CSV job for file: ${s3Key}`);
|
|
45
|
+
// Use a regex to extract the table name from the filename.
|
|
46
|
+
// Convention: yyyymmddhhMMss-{table name}.csv
|
|
47
|
+
const match = s3Key.match(/\d{14}-(.+)\.csv$/);
|
|
48
|
+
if (!match || !match[1]) {
|
|
49
|
+
throw new Error(`Could not parse tableName from filename: ${s3Key}. Expected format: yyyymmddhhMMss-{tableName}.csv`);
|
|
50
|
+
}
|
|
51
|
+
const tableName = match[1];
|
|
52
|
+
const dto = {
|
|
53
|
+
processingMode: enum_1.ProcessingMode.STEP_FUNCTION,
|
|
54
|
+
bucket: parameters.bucket,
|
|
55
|
+
key: s3Key,
|
|
56
|
+
tenantCode: parameters.tenantCode,
|
|
57
|
+
tableName: tableName,
|
|
58
|
+
};
|
|
59
|
+
await this.importService.createCsvJobWithTaskToken(dto, taskToken, masterJobKey);
|
|
60
|
+
this.logger.log(`Successfully created CSV job for ${tableName} with task token.`);
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Handles the final state of the orchestrator.
|
|
64
|
+
* It aggregates the results from all processed CSV files and sets the final
|
|
65
|
+
* status on the original ZIP_MASTER_JOB.
|
|
66
|
+
*/
|
|
67
|
+
async finalizeZipMasterJob(event) {
|
|
68
|
+
const resultsFromMapState = event.input?.processingResults ||
|
|
69
|
+
event.input; // This will be an array of results
|
|
70
|
+
const { masterJobKey } = event.context.Execution.Input;
|
|
71
|
+
this.logger.log(`Finalizing ZIP master job: ${masterJobKey.pk}#${masterJobKey.sk}`);
|
|
72
|
+
this.logger.debug('Aggregated results:', resultsFromMapState);
|
|
73
|
+
// Aggregate the results from each CSV file's processing.
|
|
74
|
+
const finalSummary = resultsFromMapState.reduce((acc, result) => {
|
|
75
|
+
const res = result?.result || result || {};
|
|
76
|
+
acc.totalRows += res.total || res.totalRows || 0;
|
|
77
|
+
acc.processedRows += res.succeeded || res.processedRows || 0;
|
|
78
|
+
acc.failedRows += res.failed || res.failedRows || 0;
|
|
79
|
+
return acc;
|
|
80
|
+
}, { totalRows: 0, processedRows: 0, failedRows: 0 });
|
|
81
|
+
const finalStatus = enum_1.ImportStatusEnum.COMPLETED;
|
|
82
|
+
await this.importService.updateStatus(masterJobKey, finalStatus, {
|
|
83
|
+
result: finalSummary,
|
|
84
|
+
});
|
|
85
|
+
this.logger.log(`Successfully finalized ZIP master job ${masterJobKey.pk}#${masterJobKey.sk} with status ${finalStatus}`);
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
exports.ZipImportSfnEventHandler = ZipImportSfnEventHandler;
|
|
89
|
+
exports.ZipImportSfnEventHandler = ZipImportSfnEventHandler = ZipImportSfnEventHandler_1 = __decorate([
|
|
90
|
+
(0, common_1.Injectable)(),
|
|
91
|
+
(0, core_1.EventHandler)(zip_import_sfn_event_1.ZipImportSfnEvent),
|
|
92
|
+
__metadata("design:paramtypes", [import_service_1.ImportService])
|
|
93
|
+
], ZipImportSfnEventHandler);
|
|
94
|
+
//# sourceMappingURL=zip-import.sfn.event.handler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"zip-import.sfn.event.handler.js","sourceRoot":"","sources":["../../src/event/zip-import.sfn.event.handler.ts"],"names":[],"mappings":"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"}
|