export function useManualCreateEntityDSL()

in frontend/apps/quantgrid/src/app/hooks/ManualEditDSL/useManualCreateEntityDSL.ts [40:487]


export function useManualCreateEntityDSL() {
  const {
    parsedSheets,
    projectName,
    sheetContent,
    projectSheets,
    functions,
    sheetName,
  } = useContext(ProjectContext);
  const { updateDSL, findTable, findContext } = useDSLUtils();

  const createDerivedTable = useCallback(
    (tableName: string, col?: number, row?: number) => {
      const context = findContext(tableName);

      if (!context || !projectName || !sheetName) return;

      const { table: sourceTable } = context;

      const { fields } = sourceTable;
      const newName = createUniqueName(
        `${unescapeTableName(tableName)}_derived`,
        getAllTableNames(projectSheets)
      );
      const derivedName = escapeTableName(newName);
      const sourceName = escapeTableName(unescapeTableName(tableName));
      const uniqueSourceFieldName = createUniqueName(
        sourceFieldName,
        fields.map((f) => f.key.fieldName)
      );
      const sourceField = `${spaces}${dimKeyword} [${uniqueSourceFieldName}] = ${sourceName}`;
      const derivedFields = fields
        .map(
          (f: ParsedField) =>
            `${spaces}${f.key.fullFieldName} = [${uniqueSourceFieldName}]${f.key.fullFieldName}`
        )
        .join(newLine);

      let newTableCol = col;
      let newTableRow = row;
      if (!newTableCol || !newTableRow) {
        const placement = sourceTable.getPlacement();
        newTableRow = placement[0];
        newTableCol = placement[1] + fields.length + 1;
      }
      const derivedTable = `${getPlacementDecorator(
        newTableCol,
        newTableRow
      )}${newLine}${tableKeyword} ${derivedName}${newLine}${sourceField}${newLine}${derivedFields}`;
      const updatedSheetContent =
        (sheetContent ?? '') + newLine + newLine + derivedTable;

      const historyTitle = `Add derived table "${derivedName}"`;
      updateDSL(updatedSheetContent, historyTitle, sheetName);
    },
    [
      findContext,
      projectName,
      projectSheets,
      sheetContent,
      sheetName,
      updateDSL,
    ]
  );

  const createTable = useCallback(
    (col: number, row: number, value: string) => {
      if (!projectName) return;

      const placementDsl = getPlacementDecorator(
        Math.max(minTablePlacement, col),
        Math.max(minTablePlacement, row)
      );
      const tableName = createUniqueName(
        defaultTableName,
        getAllTableNames(projectSheets)
      );
      const { fieldDsl } = generateFieldExpressionFromText(
        value,
        null,
        functions,
        parsedSheets,
        tableName
      );
      const tableDsl = `${placementDsl}${newLine}${tableKeyword} ${tableName}${newLine}${spaces}${fieldDsl}`;
      const updatedSheetContent = sheetContent
        ? stripNewLinesAtEnd(sheetContent) + newLine + newLine + tableDsl
        : tableDsl;

      const historyTitle = `Add table "${tableName}"`;
      updateDSL(updatedSheetContent, historyTitle);
    },
    [
      projectName,
      projectSheets,
      functions,
      parsedSheets,
      sheetContent,
      updateDSL,
    ]
  );

  const createDimensionTable = useCallback(
    (col: number, row: number, value: string) => {
      if (!projectName) return;
      const tables = value.split(':');

      if (tables.length < 2) return;
      const placementDsl = getPlacementDecorator(
        Math.max(minTablePlacement, col),
        Math.max(minTablePlacement, row)
      );

      const newTableName = escapeTableName(
        createUniqueName(
          unescapeTableName(tables[0]) || defaultTableName,
          getAllTableNames(projectSheets)
        )
      );

      const fields = tables
        .slice(1)
        .map(
          (table, index) =>
            `${spaces}${dimKeyword} [${sourceFieldName}${
              index + 1
            }] = ${autoFixSingleExpression(
              table.trim(),
              functions,
              parsedSheets,
              newTableName
            )}`
        )
        .join(newLine);
      const dimTable = `${placementDsl}${newLine}${tableKeyword} ${newTableName}${newLine}${fields}`;
      const updatedSheetContent = sheetContent
        ? stripNewLinesAtEnd(sheetContent) + newLine + newLine + dimTable
        : dimTable;

      const historyTitle = `Add dimension table "${newTableName}"`;
      updateDSL(updatedSheetContent, historyTitle);
    },
    [
      parsedSheets,
      projectSheets,
      sheetContent,
      updateDSL,
      projectName,
      functions,
    ]
  );

  const getDimensionalTableFromFormula = useCallback(
    (
      tableName: string,
      projectSheets: WorksheetState[] | null,
      isSourceDimField: boolean,
      fieldName: string,
      expression: string,
      schema: string[],
      keys: string[],
      row: number,
      col: number
    ) => {
      const newTableName = escapeTableName(
        createUniqueName(
          unescapeTableName(tableName) || defaultTableName,
          getAllTableNames(projectSheets)
        )
      );
      const dim = isSourceDimField ? `${dimKeyword} ` : '';
      const sourceField = `${spaces}${dim}[${
        fieldName || sourceFieldName
      }] = ${expression}`;
      const tableFields = [sourceFieldName];
      const fields = schema
        .map((f) => {
          const sanitizedFieldName = escapeFieldName(f);
          const uniqueFieldName = createUniqueName(
            sanitizedFieldName,
            tableFields
          );
          tableFields.push(uniqueFieldName);
          const key = keys.includes(f) ? `${keyKeyword} ` : '';

          return `${spaces}${key}[${uniqueFieldName}] = [${
            fieldName || sourceFieldName
          }][${sanitizedFieldName}]`;
        })
        .join(newLine);

      const requiresPlacement =
        row < minTablePlacement || col < minTablePlacement;
      let dimTable = `${tableKeyword} ${newTableName}${newLine}${sourceField}${newLine}${fields}`;

      if (!requiresPlacement) {
        const placementDsl = getPlacementDecorator(
          Math.max(minTablePlacement, col),
          Math.max(minTablePlacement, row)
        );
        dimTable = `${placementDsl}${newLine}${dimTable}`;
      }

      return { dimTable, requiresPlacement, newTableName };
    },
    []
  );

  const createDimensionalTableFromFormula = useCallback(
    (
      col: number,
      row: number,
      tableName: string,
      fieldName: string,
      expression: string,
      schema: string[],
      keys: string[],
      isSourceDimField: boolean
    ) => {
      if (!projectName) return;

      const { dimTable, requiresPlacement, newTableName } =
        getDimensionalTableFromFormula(
          tableName,
          projectSheets,
          isSourceDimField,
          fieldName,
          expression,
          schema,
          keys,
          row,
          col
        );

      let updatedSheetContent = sheetContent
        ? stripNewLinesAtEnd(sheetContent) + newLine + newLine + dimTable
        : dimTable;

      if (requiresPlacement) {
        updatedSheetContent = autoTablePlacement(updatedSheetContent);
      }

      const historyTitle = `Add dimension table "${newTableName}"`;
      updateDSL(updatedSheetContent, historyTitle);
    },
    [
      getDimensionalTableFromFormula,
      projectName,
      projectSheets,
      sheetContent,
      updateDSL,
    ]
  );

  const createDimensionalTableFromSchema = useCallback(
    (
      col: number,
      row: number,
      tableName: string,
      fieldName: string,
      keyValues: string | number,
      formula: string,
      schema: string[],
      keys: string[]
    ) => {
      if (!projectName || !sheetContent) return;

      const targetTable = findTable(tableName);

      if (!targetTable) return;

      const placementDsl = getPlacementDecorator(
        Math.max(minTablePlacement, col),
        Math.max(minTablePlacement, row)
      );
      const sanitizedKeyValues =
        typeof keyValues === 'string'
          ? keyValues.replaceAll(`"`, '')
          : keyValues;
      const newTableName = createUniqueName(
        `${unescapeTableName(tableName)}_(${sanitizedKeyValues})[${fieldName}]`,
        getAllTableNames(projectSheets)
      );

      const sourceField = `${spaces}${dimKeyword} [${sourceFieldName}] = ${formula}`;
      const tableFields = [sourceFieldName];
      const fields = schema
        .map((f) => {
          const sanitizedFieldName = escapeFieldName(f);
          const uniqueFieldName = createUniqueName(
            sanitizedFieldName,
            tableFields
          );
          tableFields.push(uniqueFieldName);
          const key = keys.includes(f) ? `${keyKeyword} ` : '';

          return `${spaces}${key}[${uniqueFieldName}] = [${sourceFieldName}][${sanitizedFieldName}]`;
        })
        .join(newLine);
      const newTable = `${placementDsl}${newLine}${tableKeyword} '${newTableName}'${newLine}${sourceField}${newLine}${fields}`;
      const updatedSheetContent =
        stripNewLinesAtEnd(sheetContent) + newLine + newLine + newTable;

      const historyTitle = `Add dimension table "${newTableName}"`;
      updateDSL(updatedSheetContent, historyTitle);
    },
    [projectName, findTable, projectSheets, sheetContent, updateDSL]
  );

  const createManualTable = useCallback(
    (
      col: number,
      row: number,
      cells: string[][],
      hideTableHeader = false,
      hideFieldHeader = false,
      customTableName?: string
    ) => {
      if (!projectName) return;

      const tableName = createUniqueName(
        customTableName || defaultTableName,
        getAllTableNames(projectSheets)
      );
      const rowOffset = Number(!hideTableHeader) + Number(!hideFieldHeader);
      const placementDsl = getPlacementDecorator(
        Math.max(minTablePlacement, col),
        Math.max(minTablePlacement, row - rowOffset)
      );
      const hideTHDecorator = hideTableHeader
        ? `${hideTableHeaderDecorator}${newLine}`
        : '';
      const hideTFDecorator = hideFieldHeader
        ? `${hideTableFieldsDecorator}${newLine}`
        : '';
      const baseTableDsl = `${hideTHDecorator}${hideTFDecorator}${manualTableDecorator}${newLine}${placementDsl}${newLine}${tableKeyword} ${tableName}${newLine}`;
      let tableFieldsDsl = '';
      let tableOverrideHeaderDsl = `${overrideKeyword}${newLine}`;
      let tableOverrideRowsDsl = '';

      const colsCount = cells[0].length;

      for (let i = 0; i < colsCount; i++) {
        const fieldName = `[Field${i + 1}]`;
        tableFieldsDsl += `${spaces}${fieldName}${newLine}`;
        tableOverrideHeaderDsl += i === 0 ? fieldName : `,${fieldName}`;
      }

      tableOverrideHeaderDsl += newLine;

      for (let row = 0; row < cells.length; row++) {
        for (let col = 0; col < cells[row].length; col++) {
          const value = cells[row][col];
          const overrideValue = sanitizeExpressionOrOverride(value);

          tableOverrideRowsDsl +=
            col === 0 ? overrideValue : `,${overrideValue}`;
        }

        tableOverrideRowsDsl += newLine;
      }

      const manualTableDsl = `${baseTableDsl}${tableFieldsDsl}${tableOverrideHeaderDsl}${tableOverrideRowsDsl}`;
      const updatedSheetContent = sheetContent
        ? stripNewLinesAtEnd(sheetContent) + newLine + newLine + manualTableDsl
        : manualTableDsl;

      const historyTitle = `Add manual table "${tableName}"`;
      updateDSL(updatedSheetContent, historyTitle);
    },
    [projectName, projectSheets, sheetContent, updateDSL]
  );

  const createSingleValueManualTable = useCallback(
    (col: number, row: number, value: string, tableName?: string) => {
      if (tableName) {
        createManualTable(col, row, [[value]], false, true, tableName);
      } else {
        createManualTable(col, row, [[value]], true, true);
      }
    },
    [createManualTable]
  );

  const createRowReferenceTableFromSchema = useCallback(
    (
      col: number,
      row: number,
      tableName: string,
      fieldName: string,
      keyValues: string | number,
      formula: string,
      schema: string[],
      keys: string[]
    ) => {
      if (!projectName || !sheetContent) return;

      const targetTable = findTable(tableName);

      if (!targetTable) return;

      const placementDsl = getPlacementDecorator(
        Math.max(minTablePlacement, col),
        Math.max(minTablePlacement, row)
      );
      const sanitizedKeyValues =
        typeof keyValues === 'string'
          ? keyValues.replaceAll(`"`, '')
          : keyValues;
      const newTableName = createUniqueName(
        `${unescapeTableName(tableName)}_(${sanitizedKeyValues})[${fieldName}]`,
        getAllTableNames(projectSheets)
      );

      const sourceField = `${spaces}[${sourceFieldName}] = ${formula}`;
      const tableFields = [sourceFieldName];
      const fields = schema
        .filter((f) => f !== sourceFieldName)
        .map((f) => {
          const uniqueFieldName = createUniqueName(f, tableFields);
          tableFields.push(uniqueFieldName);
          const key = keys.includes(f) ? `${keyKeyword} ` : '';

          return `${spaces}${key}[${uniqueFieldName}] = [${sourceFieldName}][${f}]`;
        })
        .join(newLine);
      const newTable = `${horizontalDirectionDecorator}${newLine}${placementDsl}${newLine}${tableKeyword} '${newTableName}'${newLine}${sourceField}${newLine}${fields}`;
      const updatedSheetContent =
        stripNewLinesAtEnd(sheetContent) + newLine + newLine + newTable;

      const historyTitle = `Add row reference table "${newTableName}"`;
      updateDSL(updatedSheetContent, historyTitle);
    },
    [projectName, findTable, projectSheets, sheetContent, updateDSL]
  );

  return {
    createTable,
    createDerivedTable,
    createDimensionTable,
    createDimensionalTableFromFormula,
    getDimensionalTableFromFormula,
    createDimensionalTableFromSchema,
    createManualTable,
    createSingleValueManualTable,
    createRowReferenceTableFromSchema,
  };
}