feat: export resource data to csv, xlsx

This commit is contained in:
Ahmed Bouhuolia
2024-04-29 23:45:11 +02:00
parent 4a713980bf
commit 8a96c41258
9 changed files with 345 additions and 0 deletions

View File

@@ -0,0 +1,17 @@
import { Inject, Service } from 'typedi';
import { ExportResourceService } from './ExportService';
@Service()
export class ExportApplication {
@Inject()
private exportResource: ExportResourceService;
/**
* Exports the given resource to csv, xlsx or pdf format.
* @param {string} reosurce
* @param {string} format
*/
public export(tenantId: number, resource: string, format: string) {
return this.exportResource.export(tenantId, resource, format);
}
}

View File

@@ -0,0 +1,49 @@
import { camelCase, upperFirst } from 'lodash';
import { Exportable } from './Exportable';
export class ExportableRegistry {
private static instance: ExportableRegistry;
private exportables: Record<string, Exportable>;
/**
* Constructor method.
*/
constructor() {
this.exportables = {};
}
/**
* Gets singleton instance of registry.
* @returns {ExportableRegistry}
*/
public static getInstance(): ExportableRegistry {
if (!ExportableRegistry.instance) {
ExportableRegistry.instance = new ExportableRegistry();
}
return ExportableRegistry.instance;
}
/**
* Registers the given importable service.
* @param {string} resource
* @param {Exportable} importable
*/
public registerExportable(resource: string, importable: Exportable): void {
const _resource = this.sanitizeResourceName(resource);
this.exportables[_resource] = importable;
}
/**
* Retrieves the importable service instance of the given resource name.
* @param {string} name
* @returns {Exportable}
*/
public getExportable(name: string): Exportable {
const _name = this.sanitizeResourceName(name);
return this.exportables[_name];
}
private sanitizeResourceName(resource: string) {
return upperFirst(camelCase(resource));
}
}

View File

@@ -0,0 +1,44 @@
import Container, { Service } from 'typedi';
import { AccountsExportable } from '../Accounts/AccountsExportable';
import { ExportableRegistry } from './ExportRegistery';
import { ItemsImportable } from '../Items/ItemsImportable';
import { ItemsExportable } from '../Items/ItemsExportable';
@Service()
export class ExportableResources {
private static registry: ExportableRegistry;
constructor() {
this.boot();
}
/**
* Importable instances.
*/
private importables = [
{ resource: 'Account', exportable: AccountsExportable },
{ resource: 'Item', exportable: ItemsExportable },
];
/**
*
*/
public get registry() {
return ExportableResources.registry;
}
/**
* Boots all the registered importables.
*/
public boot() {
if (!ExportableResources.registry) {
const instance = ExportableRegistry.getInstance();
this.importables.forEach((importable) => {
const importableInstance = Container.get(importable.exportable);
instance.registerExportable(importable.resource, importableInstance);
});
ExportableResources.registry = instance;
}
}
}

View File

@@ -0,0 +1,59 @@
import { Inject, Service } from 'typedi';
import xlsx from 'xlsx';
import { sanitizeResourceName } from '../Import/_utils';
import ResourceService from '../Resource/ResourceService';
import { ExportableResources } from './ExportResources';
@Service()
export class ExportResourceService {
@Inject()
private resourceService: ResourceService;
@Inject()
private exportableResources: ExportableResources;
/**
*
* @param {number} tenantId
* @param {string} resourceName
* @param {string} format
*/
async export(tenantId: number, resourceName: string, format: string = 'csv') {
const resource = sanitizeResourceName(resourceName);
const resourceMeta = this.resourceService.getResourceMeta(
tenantId,
resource
);
const exportable =
this.exportableResources.registry.getExportable(resource);
const data = await exportable.exportable(tenantId, {});
const exportableColumns = [
{
label: 'Account Normal',
accessor: 'accountNormalFormatted',
},
{
label: 'Account Type',
accessor: 'accountTypeFormatted',
},
];
const workbook = xlsx.utils.book_new();
const worksheetData = data.map((item) =>
exportableColumns.map((col) => item[col.accessor])
);
worksheetData.unshift(exportableColumns.map((col) => col.label)); // Add header row
const worksheet = xlsx.utils.aoa_to_sheet(worksheetData);
xlsx.utils.book_append_sheet(workbook, worksheet, 'Exported Data');
if (format.toLowerCase() === 'csv') {
// Convert to CSV using the xlsx package
return xlsx.write(workbook, { type: 'buffer', bookType: 'csv' });
} else if (format.toLowerCase() === 'xlsx') {
// Write to XLSX format
return xlsx.write(workbook, { type: 'buffer', bookType: 'xlsx' });
}
}
}

View File

@@ -0,0 +1,22 @@
export class Exportable {
/**
*
* @param tenantId
* @returns
*/
public async exportable(
tenantId: number,
query: Record<string, any>
): Promise<Array<Record<string, any>>> {
return [];
}
/**
*
* @param data
* @returns
*/
public transform(data: Record<string, any>) {
return data;
}
}