Files
dbgate/packages/datalib/src/runMacro.ts
Jan Prochazka b9cb8c3a45 prettier
2021-01-23 07:24:46 +01:00

186 lines
4.3 KiB
TypeScript

import { FreeTableModel } from './FreeTableModel';
import _ from 'lodash';
import uuidv1 from 'uuid/v1';
import uuidv4 from 'uuid/v4';
import moment from 'moment';
import { MacroDefinition, MacroSelectedCell } from './MacroDefinition';
const getMacroFunction = {
transformValue: code => `
(value, args, modules, rowIndex, row, columnName) => {
${code}
}
`,
transformRows: code => `
(rows, args, modules, selectedCells, cols, columns) => {
${code}
}
`,
transformData: code => `
(rows, args, modules, selectedCells, cols, columns) => {
${code}
}
`,
};
const modules = {
lodash: _,
uuidv1,
uuidv4,
moment,
};
function runTramsformValue(
func,
macroArgs: {},
data: FreeTableModel,
preview: boolean,
selectedCells: MacroSelectedCell[],
errors: string[] = []
) {
const selectedRows = _.groupBy(selectedCells, 'row');
const rows = data.rows.map((row, rowIndex) => {
const selectedRow = selectedRows[rowIndex];
if (selectedRow) {
const modifiedFields = [];
let res = null;
for (const cell of selectedRow) {
const { column } = cell;
const oldValue = row[column];
let newValue = oldValue;
try {
newValue = func(oldValue, macroArgs, modules, rowIndex, row, column);
} catch (err) {
errors.push(`Error processing column ${column} on row ${rowIndex}: ${err.message}`);
}
if (newValue != oldValue) {
if (res == null) {
res = { ...row };
}
res[column] = newValue;
if (preview) modifiedFields.push(column);
}
}
if (res) {
if (modifiedFields.length > 0) {
return {
...res,
__modifiedFields: new Set(modifiedFields),
};
}
return res;
}
return row;
} else {
return row;
}
});
return {
structure: data.structure,
rows,
};
}
function removePreviewRowFlags(rows) {
rows = rows.filter(row => row.__rowStatus != 'deleted');
rows = rows.map(row => {
if (row.__rowStatus || row.__modifiedFields || row.__insertedFields || row.__deletedFields)
return _.omit(row, ['__rowStatus', '__modifiedFields', '__insertedFields', '__deletedFields']);
return row;
});
return rows;
}
function runTramsformRows(
func,
macroArgs: {},
data: FreeTableModel,
preview: boolean,
selectedCells: MacroSelectedCell[],
errors: string[] = []
) {
let rows = data.rows;
try {
rows = func(
data.rows,
macroArgs,
modules,
selectedCells,
data.structure.columns.map(x => x.columnName),
data.structure.columns
);
if (!preview) {
rows = removePreviewRowFlags(rows);
}
} catch (err) {
errors.push(`Error processing rows: ${err.message}`);
}
return {
structure: data.structure,
rows,
};
}
function runTramsformData(
func,
macroArgs: {},
data: FreeTableModel,
preview: boolean,
selectedCells: MacroSelectedCell[],
errors: string[] = []
) {
try {
let { rows, columns, cols } = func(
data.rows,
macroArgs,
modules,
selectedCells,
data.structure.columns.map(x => x.columnName),
data.structure.columns
);
if (cols && !columns) {
columns = cols.map(columnName => ({ columnName }));
}
columns = _.uniqBy(columns, 'columnName');
if (!preview) {
rows = removePreviewRowFlags(rows);
}
return {
structure: { columns },
rows,
};
} catch (err) {
errors.push(`Error processing data: ${err.message}`);
}
return data;
}
export function runMacro(
macro: MacroDefinition,
macroArgs: {},
data: FreeTableModel,
preview: boolean,
selectedCells: MacroSelectedCell[],
errors: string[] = []
): FreeTableModel {
let func;
try {
func = eval(getMacroFunction[macro.type](macro.code));
} catch (err) {
errors.push(`Error compiling macro ${macro.name}: ${err.message}`);
return data;
}
if (macro.type == 'transformValue') {
return runTramsformValue(func, macroArgs, data, preview, selectedCells, errors);
}
if (macro.type == 'transformRows') {
return runTramsformRows(func, macroArgs, data, preview, selectedCells, errors);
}
if (macro.type == 'transformData') {
// @ts-ignore
return runTramsformData(func, macroArgs, data, preview, selectedCells, errors);
}
return data;
}