Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 | 1x 1x 1x 1x 1x | /* eslint-disable @typescript-eslint/no-misused-promises */
/* eslint-disable @typescript-eslint/no-explicit-any */
import { bind, BindingScope } from '@loopback/core';
import { Readable } from "stream";
import { parse } from 'fast-csv';
import { Options } from '@loopback/repository';
import { HttpErrors } from '@loopback/rest';
import { UploadFileType } from './types';
export interface RecordsCreator {
headers: string[];
validateRowsCsv(row: any): Promise<void>,
create(data: any, options?: Options): Promise<any>,
}
type ResultParser<T> = {
isValid: boolean,
rowNumber?: number,
reason?: string,
data?: T
}
@bind({ scope: BindingScope.TRANSIENT })
export class CSVParser<T> {
constructor(private recordsCreator: RecordsCreator) { }
public parseFromBuffer(buffer: Buffer): Promise<ResultParser<T>[]> {
return new Promise((resolve, reject) => {
const results: ResultParser<T>[] = [];
const readable = Readable.from(buffer);
readable
.pipe(parse({ headers: this.recordsCreator.headers, renameHeaders: true }))
.validate((row, cb): void => {
setImmediate(async () => {
try {
await this.recordsCreator.validateRowsCsv(row);
cb(null, true);
} catch (error) {
const msg = error?.details?.length ?
`${error?.details[0].message}: ${error.details[0].path?.replace('/', '')}` : error.message;
cb(null, false, msg);
}
});
})
.on('error', error => reject(error))
.on('data', (row: T) => {
results.push({ isValid: true, data: row });
})
.on('data-invalid', (row: T, rowNumber: number, reason: string) => {
results.push({ isValid: false, reason, rowNumber })
})
.on('end', () => {
resolve(results);
});
});
}
/**
* Creates records from csv files
* @param [uploadedFiles]
* @returns
*/
async createRecordsFromCSV(uploadedFiles: UploadFileType, options: Options) {
if (!uploadedFiles?.length) {
throw new HttpErrors.BadRequest(`Missing csv file!`);
}
const csvData = await this.parseFromBuffer((uploadedFiles as Express.Multer.File[])[0].buffer);
const pTasks = csvData.map(({ isValid, data, reason }, idx) => this.processCsvRow(isValid, data, reason, idx, options));
return Promise.all(pTasks);
}
private async processCsvRow(isValid: boolean, data: any, reason: string | undefined, idx: number, options: Options) {
try {
if (isValid) {
await this.recordsCreator.create(data, options);
}
return { is_valid: isValid, reason, row_number: idx + 1 };
} catch (error) {
return { is_valid: false, reason: error.message, row_number: idx + 1 };
}
}
}
|