export function useApplyFilterManualEditDSL()

in frontend/apps/quantgrid/src/app/hooks/ManualEditDSL/useApplyFilterManualEditDSL.ts [16:326]


export function useApplyFilterManualEditDSL() {
  const { projectName } = useContext(ProjectContext);
  const { findContext, findNewApplyBlockOffset, updateDSL } = useDSLUtils();

  const insertNewApplyBlock = (
    sheetContent: string,
    offset: number,
    filterExpression: string
  ): string => {
    return (
      sheetContent.substring(0, offset + 1).trimEnd() +
      `${newLine}${applyKeyword}${newLine}${filterKeyword} ${filterExpression}${newLine}` +
      sheetContent.substring(offset + 1).trimStart()
    );
  };

  const insertNewFilterBlock = (
    sheetContent: string,
    offset: number,
    filterExpression: string
  ): string => {
    return (
      sheetContent.substring(0, offset + 1).trimEnd() +
      `${newLine}${filterKeyword} ${filterExpression}${newLine}` +
      sheetContent.substring(offset + 1).trimStart()
    );
  };

  const updateExistingFilterBlock = (
    sheetContent: string,
    start: number,
    end: number,
    filterExpressions: string[]
  ): string => {
    return (
      sheetContent.substring(0, start).trimEnd() +
      `${newLine}${filterKeyword} ${filterExpressions.join(
        ' AND '
      )}${newLine}` +
      sheetContent.substring(end + 1).trimStart()
    );
  };

  const cleanUpFilterBlock = (
    sheetContent: string,
    start: number,
    end: number,
    apply: ParsedApply
  ): string => {
    const canRemoveApplyBlock =
      !apply.sort || apply.sort.parsedExpression?.length === 0;

    if (canRemoveApplyBlock && apply.dslPlacement) {
      const { startOffset, stopOffset } = apply.dslPlacement;

      return (
        sheetContent.substring(0, startOffset) +
        sheetContent.substring(stopOffset + 1)
      );
    }

    return sheetContent.substring(0, start) + sheetContent.substring(end + 1);
  };

  const updateSheetContentForNumberFilter = useCallback(
    (
      context: ParsedContext,
      fieldName: string,
      operator: string,
      value: number | null
    ): string | null => {
      const { table, sheetContent } = context;
      const { apply } = table;
      const filterExpression = `[${fieldName}] ${operator} ${value}`;

      if (!apply) {
        const offset = findNewApplyBlockOffset(table.tableName);

        if (offset === null) return null;

        return insertNewApplyBlock(sheetContent, offset, filterExpression);
      } else if (!apply.filter && apply.dslPlacement) {
        const { stopOffset } = apply.dslPlacement;

        return insertNewFilterBlock(sheetContent, stopOffset, filterExpression);
      } else if (apply.filter && apply.filter.dslPlacement) {
        const { start, end } = apply.filter.dslPlacement;
        const filterExpressions = apply.filter.applyNumericFilter(
          fieldName,
          operator,
          value
        );

        if (filterExpressions.length > 0) {
          return updateExistingFilterBlock(
            sheetContent,
            start,
            end,
            filterExpressions
          );
        }

        return cleanUpFilterBlock(sheetContent, start, end, apply);
      }

      return null;
    },
    [findNewApplyBlockOffset]
  );

  const updateSheetContentForListFilter = useCallback(
    (
      context: ParsedContext,
      fieldName: string,
      values: string[],
      isNumeric: boolean
    ): string | null => {
      const { table, sheetContent } = context;
      const { apply } = table;
      const fieldFilterExpression = values
        .map((v) => `[${fieldName}] = ${getListFilterValue(isNumeric, v)}`)
        .join(' OR ');

      if (values.length === 0 && (!apply || !apply.filter)) return null;

      if (!apply) {
        const offset = findNewApplyBlockOffset(table.tableName);

        if (offset === null) return null;

        return insertNewApplyBlock(sheetContent, offset, fieldFilterExpression);
      } else if (!apply.filter && apply.dslPlacement) {
        const { stopOffset } = apply.dslPlacement;

        return insertNewFilterBlock(
          sheetContent,
          stopOffset,
          fieldFilterExpression
        );
      } else if (apply.filter && apply.filter.dslPlacement) {
        const { start, end } = apply.filter.dslPlacement;
        const existingFilterExpressions = apply.filter.getFilterExpressions({
          excludeFieldName: fieldName,
        });

        let combinedExpression = '';

        if (existingFilterExpressions.length > 0) {
          combinedExpression = `${existingFilterExpressions.join(' AND ')}`;

          if (values.length > 0) {
            combinedExpression += ' AND ';
            combinedExpression +=
              values.length > 1
                ? `(${fieldFilterExpression})`
                : fieldFilterExpression;
          }
        } else if (values.length > 0) {
          combinedExpression = fieldFilterExpression;
        }

        if (combinedExpression) {
          return updateExistingFilterBlock(sheetContent, start, end, [
            combinedExpression,
          ]);
        }

        return cleanUpFilterBlock(sheetContent, start, end, apply);
      }

      return null;
    },
    [findNewApplyBlockOffset]
  );

  const applyNumberFilter = useCallback(
    (
      tableName: string,
      fieldName: string,
      operator: string,
      value: number | null
    ) => {
      const context = findContext(tableName, fieldName);

      if (!projectName || !context) return;

      const updatedSheetContent = updateSheetContentForNumberFilter(
        context,
        fieldName,
        operator,
        value
      );
      if (!updatedSheetContent) return;

      const historyTitle =
        value !== null
          ? `Change filter of ${tableName}[${fieldName}] to ${operator} ${value}`
          : `Clear filter of the ${tableName}[${fieldName}]`;
      updateDSL(updatedSheetContent, historyTitle);
    },
    [findContext, projectName, updateDSL, updateSheetContentForNumberFilter]
  );

  const applyListFilter = useCallback(
    (
      tableName: string,
      fieldName: string,
      values: string[],
      isNumeric: boolean
    ) => {
      const context = findContext(tableName, fieldName);

      if (!projectName || !context) return;

      const updatedSheetContent = updateSheetContentForListFilter(
        context,
        fieldName,
        values,
        isNumeric
      );

      if (!updatedSheetContent) return;

      const historyTitle =
        values.length > 0
          ? `Change filter of ${tableName}[${fieldName}] to ${values}`
          : `Clear filter of the ${tableName}[${fieldName}]`;
      updateDSL(updatedSheetContent, historyTitle);
    },
    [findContext, projectName, updateDSL, updateSheetContentForListFilter]
  );

  const renameFilterField = useCallback(
    (
      tableName: string,
      fieldName: string,
      newFieldName: string,
      sheetContent: string
    ): string => {
      try {
        const parsedSheet = SheetReader.parseSheet(sheetContent);
        const table = parsedSheet.tables.find((t) => t.tableName === tableName);

        if (!table) return sheetContent;

        const { apply } = table;
        const isFieldFiltered = apply?.filter?.hasFieldFilter(fieldName);

        if (!isFieldFiltered || !apply?.filter || !apply.filter.dslPlacement)
          return sheetContent;

        const { start, end } = apply.filter.dslPlacement;
        const existingFilterExpressions = apply.filter.getFilterExpressions({
          oldFieldName: fieldName,
          newFieldName,
        });
        const combinedExpression = `${existingFilterExpressions.join(' AND ')}`;

        return combinedExpression
          ? updateExistingFilterBlock(sheetContent, start, end, [
              combinedExpression,
            ])
          : sheetContent;
      } catch (e) {
        return sheetContent;
      }
    },
    []
  );

  const removeFilterField = useCallback(
    (tableName: string, fieldName: string, sheetContent: string) => {
      try {
        const parsedSheet = SheetReader.parseSheet(sheetContent);
        const table = parsedSheet.tables.find((t) => t.tableName === tableName);

        if (!table || !table?.apply?.filter) return sheetContent;

        const { filter } = table.apply;

        if (!filter.hasFieldFilter(fieldName) || !filter.dslPlacement)
          return sheetContent;

        const { start, end } = filter.dslPlacement;
        const filterExpressions = filter.getFilterExpressions({
          excludeFieldName: fieldName,
        });
        const combinedExpression =
          filterExpressions.length > 0 ? filterExpressions.join(' AND ') : '';

        if (combinedExpression) {
          return updateExistingFilterBlock(sheetContent, start, end, [
            combinedExpression,
          ]);
        }

        return cleanUpFilterBlock(sheetContent, start, end, table.apply);
      } catch (error) {
        return sheetContent;
      }
    },
    []
  );

  return {
    applyNumberFilter,
    applyListFilter,
    renameFilterField,
    removeFilterField,
  };
}