import { chain } from 'lodash'; import { Knex } from 'knex'; import { Inject, Injectable } from '@nestjs/common'; import { ERRORS, getUnmappedSheetColumns, readImportFile } from './_utils'; import { ImportFileCommon } from './ImportFileCommon'; import { ImportFileDataTransformer } from './ImportFileDataTransformer'; import { ImportFilePreviewPOJO } from './interfaces'; import { parseSheetData } from './sheet_utils'; import { ResourceService } from '../Resource/ResourceService'; import { UnitOfWork } from '../Tenancy/TenancyDB/UnitOfWork.service'; import { ServiceError } from '../Items/ServiceError'; import { ImportModel } from './models/Import'; import { TenancyContext } from '../Tenancy/TenancyContext.service'; @Injectable() export class ImportFileProcess { constructor( private readonly resource: ResourceService, private readonly importCommon: ImportFileCommon, private readonly importParser: ImportFileDataTransformer, private readonly uow: UnitOfWork, private readonly tenancyContext: TenancyContext, @Inject(ImportModel.name) private readonly importModel: typeof ImportModel, ) {} /** * Preview the imported file results before commiting the transactions. * @param {number} importId * @returns {Promise} */ public async import( importId: string, trx?: Knex.Transaction, ): Promise { const tenant = await this.tenancyContext.getTenant(); const tenantId = tenant.id; const importFile = await this.importModel .query() .findOne('importId', importId) .where('tenantId', tenantId) .throwIfNotFound(); // Throw error if the import file is not mapped yet. if (!importFile.isMapped) { throw new ServiceError(ERRORS.IMPORT_FILE_NOT_MAPPED); } // Read the imported file and parse the given buffer to get columns // and sheet data in json format. const buffer = await readImportFile(importFile.filename); const [sheetData, sheetColumns] = parseSheetData(buffer); const resource = importFile.resource; const resourceFields = this.resource.getResourceFields2(resource); // Runs the importing operation with ability to return errors that will happen. const [successedImport, failedImport, allData] = await this.uow.withTransaction(async (trx: Knex.Transaction) => { // Prases the sheet json data. const parsedData = await this.importParser.parseSheetData( importFile, resourceFields, sheetData, trx, ); const [successedImport, failedImport] = await this.importCommon.import( importFile, parsedData, trx, ); return [successedImport, failedImport, parsedData]; }, trx); const mapping = importFile.mappingParsed; const errors = chain(failedImport) .map((oper) => oper.error) .flatten() .value(); const unmappedColumns = getUnmappedSheetColumns(sheetColumns, mapping); const totalCount = allData.length; const createdCount = successedImport.length; const errorsCount = failedImport.length; const skippedCount = errorsCount; return { resource, createdCount, skippedCount, totalCount, errorsCount, errors, unmappedColumns: unmappedColumns, unmappedColumnsCount: unmappedColumns.length, }; } }