in frontend/apps/quantgrid/src/app/components/SpreadsheetWrapper/buildData.ts [29:297]
export function buildData(
tables: ParsedTable[] | undefined,
tableData: TableData,
parsingErrors: ParsingError[] | null,
compilationErrors: CompilationError[] | null
) {
const data: GridData = {};
if (!tables) return data;
let zIndex = defaultZIndex;
const safeSetCell = (row: number, col: number, cell: GridCell) => {
if (!data[row]) data[row] = {};
data[row][col] = cell;
};
for (const table of tables) {
const { tableName } = table;
zIndex++;
const [startRow, startCol] = table.getPlacement();
const fieldsCount = table.getFieldsCount();
const maxRow = tableData[tableName]?.maxKnownRowIndex + startRow + 1 || 0;
const endRow = maxRow > 0 ? maxRow : startRow + 1;
const endCol = fieldsCount > 0 ? startCol + fieldsCount - 1 : startCol;
const tablePlacement: GridTable = {
endRow,
endCol,
startRow,
startCol,
tableName,
};
// Add table header row
if (table.isLineChart()) {
const chartSize = table.getChartSize();
const chartRows = chartSize[0] || defaultChartRows;
const chartCols = chartSize[1] || defaultChartCols;
const chartEndCol = startCol + chartCols - 1;
tablePlacement.endCol = chartEndCol;
tablePlacement.endRow = startRow + chartRows + toolbarRows;
tablePlacement.chartType = 'line';
for (let col = startCol; col <= chartEndCol; col++) {
safeSetCell(startRow, col, {
table: tablePlacement,
value: tableName,
row: startRow,
col,
zIndex: col === startCol ? zIndex + 1 : zIndex,
});
}
continue;
}
for (let col = startCol; col <= endCol; col++) {
safeSetCell(startRow, col, {
table: tablePlacement,
value: tableName,
row: startRow,
col,
zIndex: col === startCol ? zIndex + 1 : zIndex,
});
}
// Add table fields
let colIndex = startCol;
for (const {
key: { fieldName },
expressionMetadata,
isKey,
isDim,
isDynamic,
} of table.fields) {
const fieldRow = startRow + tableFieldOffset;
const columnName = fieldName;
if (columnName === dynamicFieldName) continue;
const viewportErrorMessage =
tableData[tableName]?.fieldErrors[columnName];
const errorMessage = getMergedErrorMessage(
parsingErrors,
compilationErrors,
viewportErrorMessage,
tableName,
columnName
);
const isNested = tableData[tableName]?.nestedColumnNames.has(columnName);
const type = tableData[tableName]?.types[columnName];
const isPeriodSeries = type === ColumnDataType.PERIOD_SERIES;
safeSetCell(fieldRow, colIndex, {
table: tablePlacement,
value: columnName,
field: {
fieldName: columnName,
expression: expressionMetadata?.text || '',
isPeriodSeries,
isDynamic,
isNested,
isKey,
isDim,
type,
},
row: fieldRow,
col: colIndex,
error: errorMessage,
isManual: table.isManual(),
zIndex,
});
colIndex += 1;
}
const cachedTableData = tableData[tableName];
if (!cachedTableData) continue;
// Add table values
for (const chunkIndex of Object.keys(cachedTableData.chunks)) {
const chunk = cachedTableData.chunks[parseInt(chunkIndex)];
let minRowIndex = Number.MAX_SAFE_INTEGER;
let maxRowIndex = Number.MIN_SAFE_INTEGER;
// Add cells that have data in chunks
for (const columnName of Object.keys(chunk)) {
if (columnName === dynamicFieldName) continue;
const column = chunk[columnName];
const fieldIndex = table.fields
.filter((f) => f.key.fieldName !== dynamicFieldName)
.findIndex((f) => f.key.fieldName === columnName);
const field = table.fields.find((f) => f.key.fieldName === columnName);
if (fieldIndex === -1 || !field) continue;
const rowOffset = parseInt(chunkIndex) * chunkSize;
for (let rowIndex = 0; rowIndex < column.length; rowIndex++) {
const row = rowIndex + rowOffset + startRow + tableRowOffset;
const col = startCol + fieldIndex;
const tableRowData: Record<string, string> = {};
minRowIndex = Math.min(minRowIndex, row);
maxRowIndex = Math.max(maxRowIndex, row);
Object.keys(chunk).forEach((fieldName) => {
tableRowData[fieldName] = chunk[fieldName][rowIndex];
});
const { overrideValue, overrideIndex } = getOverrideValue(
table,
columnName,
rowIndex,
tableRowData
);
const referenceTableName =
tableData[tableName]?.columnReferenceTableNames[columnName];
const type = cachedTableData.types[columnName];
const value = column[rowIndex];
safeSetCell(row, col, {
table: tablePlacement,
isOverride: !!overrideValue,
isManual: table.isManual(),
field: {
fieldName: columnName,
expression: field?.expressionMetadata?.text || '',
isPeriodSeries: type === ColumnDataType.PERIOD_SERIES,
isNested: cachedTableData.nestedColumnNames.has(columnName),
isKey: field?.isKey,
isDim: field?.isDim,
isDynamic: field?.isDynamic,
type,
referenceTableName,
},
overrideIndex: overrideIndex !== null ? overrideIndex : undefined,
value,
row,
col,
zIndex,
});
}
}
// Add cells that have no data in chunks
const noDataFieldNames = table.fields.filter(
(f) => !chunk[f.key.fieldName] && f.key.fieldName !== dynamicFieldName
);
for (const field of noDataFieldNames) {
const columnName = field.key.fieldName;
const fieldIndex = table.fields
.filter((f) => f.key.fieldName !== dynamicFieldName)
.findIndex((f) => f.key.fieldName === columnName);
const col = startCol + fieldIndex;
const type = cachedTableData.types[columnName];
const referenceTableName =
tableData[tableName]?.columnReferenceTableNames[columnName];
for (let row = minRowIndex; row <= maxRowIndex; row++) {
safeSetCell(row, col, {
table: tablePlacement,
isOverride: false,
isManual: table.isManual(),
field: {
fieldName: columnName,
expression: field?.expressionMetadata?.text || '',
isPeriodSeries: type === ColumnDataType.PERIOD_SERIES,
isNested: cachedTableData.nestedColumnNames.has(columnName),
isKey: field?.isKey,
isDim: field?.isDim,
isDynamic: field?.isDynamic,
type,
referenceTableName,
},
overrideIndex: undefined,
value: undefined,
row,
col,
zIndex,
});
}
}
}
const tableErrors =
parsingErrors?.filter((error) => error.tableName === tableName) || [];
for (const error of tableErrors) {
let errorFieldColumn = table.fields.findIndex(
(field) =>
SheetReader.stripQuotes(field.key.fieldName) === error.fieldName
);
if (errorFieldColumn === -1) continue;
errorFieldColumn += startCol;
const errorEndRow = Math.max(
Math.min(endRow, endRow - tableRowOffset),
0
);
for (let rowIndex = startRow; rowIndex <= errorEndRow; rowIndex++) {
const row = rowIndex + tableRowOffset;
safeSetCell(row, errorFieldColumn, {
error: error.message,
table: tablePlacement,
row,
col: errorFieldColumn,
zIndex,
});
}
}
}
return data;
}