SqlWriterConfig.java

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to you under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.apache.calcite.sql;

import org.apache.calcite.sql.pretty.SqlPrettyWriter;

import org.checkerframework.checker.nullness.qual.Nullable;
import org.immutables.value.Value;

/** Configuration for {@link SqlWriter} and {@link SqlPrettyWriter}. */
@Value.Immutable
public interface SqlWriterConfig {
  /** Returns the dialect. */
  @Nullable SqlDialect dialect();

  /** Sets {@link #dialect()}. */
  SqlWriterConfig withDialect(@Nullable SqlDialect dialect);

  /** Returns whether to print keywords (SELECT, AS, etc.) in lower-case.
   * Default is false: keywords are printed in upper-case. */
  @Value.Default default boolean keywordsLowerCase() {
    return false;
  }

  /** Sets {@link #keywordsLowerCase}. */
  SqlWriterConfig withKeywordsLowerCase(boolean keywordsLowerCase);

  /** Returns whether to quote all identifiers, even those which would be
   * correct according to the rules of the {@link SqlDialect} if quotation
   * marks were omitted. Default is true. */
  @Value.Default default boolean quoteAllIdentifiers() {
    return true;
  }

  /** Sets {@link #quoteAllIdentifiers}. */
  SqlWriterConfig withQuoteAllIdentifiers(boolean quoteAllIdentifiers);

  /** Returns the number of spaces indentation. Default is 4. */
  @Value.Default default int indentation() {
    return 4;
  }

  /** Sets {@link #indentation}. */
  SqlWriterConfig withIndentation(int indentation);

  /** Returns whether a clause (FROM, WHERE, GROUP BY, HAVING, WINDOW,
   * ORDER BY) starts a new line. Default is true. SELECT is always at the
   * start of a line. */
  @Value.Default default boolean clauseStartsLine() {
    return true;
  }

  /** Sets {@link #clauseStartsLine}. */
  SqlWriterConfig withClauseStartsLine(boolean clauseStartsLine);

  /** Returns whether a clause (FROM, WHERE, GROUP BY, HAVING, WINDOW,
   * ORDER BY) is followed by a new line. Default is false. */
  @Value.Default default boolean clauseEndsLine() {
    return false;
  }

  /** Sets {@link #clauseEndsLine()}. */
  SqlWriterConfig withClauseEndsLine(boolean clauseEndsLine);

  /** Returns whether each item in a SELECT list, GROUP BY list, or ORDER BY
   * list is on its own line.
   *
   * <p>Default is false;
   * this property is superseded by {@link #selectFolding()},
   * {@link #groupByFolding()}, {@link #orderByFolding()}. */
  @Value.Default default boolean selectListItemsOnSeparateLines() {
    return false;
  }

  /** Sets {@link #selectListItemsOnSeparateLines}. */
  SqlWriterConfig withSelectListItemsOnSeparateLines(
      boolean selectListItemsOnSeparateLines);

  /** Returns the line-folding policy for lists in the SELECT, GROUP BY and
   * ORDER clauses, for items in the SET clause of UPDATE, and for items in
   * VALUES.
   *
   * @see #foldLength()
   *
   * <p>If not set, the values of
   * {@link #selectListItemsOnSeparateLines()},
   * {@link #valuesListNewline()},
   * {@link #updateSetListNewline()},
   * {@link #windowDeclListNewline()} are used. */
  @Nullable LineFolding lineFolding();

  /** Sets {@link #lineFolding()}. */
  SqlWriterConfig withLineFolding(@Nullable LineFolding lineFolding);

  /** Returns the line-folding policy for the SELECT clause.
   * If not set, the value of {@link #lineFolding()} is used. */
  @Nullable LineFolding selectFolding();

  /** Sets {@link #selectFolding()}. */
  SqlWriterConfig withSelectFolding(@Nullable LineFolding lineFolding);

  /** Returns the line-folding policy for the FROM clause (and JOIN).
   * If not set, the value of {@link #lineFolding()} is used. */
  @Value.Default default LineFolding fromFolding() {
    return LineFolding.TALL;
  }

  /** Sets {@link #fromFolding()}. */
  SqlWriterConfig withFromFolding(LineFolding lineFolding);

  /** Returns the line-folding policy for the WHERE clause.
   * If not set, the value of {@link #lineFolding()} is used. */
  @Nullable LineFolding whereFolding();

  /** Sets {@link #whereFolding()}. */
  SqlWriterConfig withWhereFolding(@Nullable LineFolding lineFolding);

  /** Returns the line-folding policy for the GROUP BY clause.
   * If not set, the value of {@link #lineFolding()} is used. */
  @Nullable LineFolding groupByFolding();

  /** Sets {@link #groupByFolding()}. */
  SqlWriterConfig withGroupByFolding(@Nullable LineFolding lineFolding);

  /** Returns the line-folding policy for the HAVING clause.
   * If not set, the value of {@link #lineFolding()} is used. */
  @Nullable LineFolding havingFolding();

  /** Sets {@link #havingFolding()}. */
  SqlWriterConfig withHavingFolding(@Nullable LineFolding lineFolding);

  /** Returns the line-folding policy for the WINDOW clause.
   * If not set, the value of {@link #lineFolding()} is used. */
  @Nullable LineFolding windowFolding();

  /** Sets {@link #windowFolding()}. */
  SqlWriterConfig withWindowFolding(@Nullable LineFolding lineFolding);

  /** Returns the line-folding policy for the MATCH_RECOGNIZE clause.
   * If not set, the value of {@link #lineFolding()} is used. */
  @Nullable LineFolding matchFolding();

  /** Sets {@link #matchFolding()}. */
  SqlWriterConfig withMatchFolding(@Nullable LineFolding lineFolding);

  /** Returns the line-folding policy for the ORDER BY clause.
   * If not set, the value of {@link #lineFolding()} is used. */
  @Nullable LineFolding orderByFolding();

  /** Sets {@link #orderByFolding()}. */
  SqlWriterConfig withOrderByFolding(@Nullable LineFolding lineFolding);

  /** Returns the line-folding policy for the OVER clause or a window
   * declaration. If not set, the value of {@link #lineFolding()} is used. */
  @Nullable LineFolding overFolding();

  /** Sets {@link #overFolding()}. */
  SqlWriterConfig withOverFolding(@Nullable LineFolding lineFolding);

  /** Returns the line-folding policy for the VALUES expression.
   * If not set, the value of {@link #lineFolding()} is used. */
  @Nullable LineFolding valuesFolding();

  /** Sets {@link #valuesFolding()}. */
  SqlWriterConfig withValuesFolding(@Nullable LineFolding lineFolding);

  /** Returns the line-folding policy for the SET clause of an UPDATE statement.
   * If not set, the value of {@link #lineFolding()} is used. */
  @Nullable LineFolding updateSetFolding();

  /** Sets {@link #updateSetFolding()}. */
  SqlWriterConfig withUpdateSetFolding(@Nullable LineFolding lineFolding);

  /**
   * Returns whether to use a fix for SELECT list indentations.
   *
   * <ul>
   * <li>If set to "false":
   *
   * <blockquote><pre>
   * SELECT
   *     A as A,
   *         B as B,
   *         C as C,
   *     D
   * </pre></blockquote>
   *
   * <li>If set to "true" (the default):
   *
   * <blockquote><pre>
   * SELECT
   *     A as A,
   *     B as B,
   *     C as C,
   *     D
   * </pre></blockquote>
   * </ul>
   */
  @Value.Default default boolean selectListExtraIndentFlag() {
    return true;
  }

  /** Sets {@link #selectListExtraIndentFlag}. */
  SqlWriterConfig withSelectListExtraIndentFlag(boolean selectListExtraIndentFlag);

  /** Returns whether each declaration in a WINDOW clause should be on its own
   * line.
   *
   * <p>Default is true;
   * this property is superseded by {@link #windowFolding()}. */
  @Value.Default default boolean windowDeclListNewline() {
    return true;
  }

  /** Sets {@link #windowDeclListNewline}. */
  SqlWriterConfig withWindowDeclListNewline(boolean windowDeclListNewline);

  /** Returns whether each row in a VALUES clause should be on its own
   * line.
   *
   * <p>Default is true;
   * this property is superseded by {@link #valuesFolding()}. */
  @Value.Default default boolean valuesListNewline() {
    return true;
  }

  /** Sets {@link #valuesListNewline}. */
  SqlWriterConfig withValuesListNewline(boolean valuesListNewline);

  /** Returns whether each assignment in the SET clause of an UPDATE or MERGE
   * statement should be on its own line.
   *
   * <p>Default is true;
   * this property is superseded by {@link #updateSetFolding()}. */
  @Value.Default default boolean updateSetListNewline() {
    return true;
  }

  /** Sets {@link #updateSetListNewline}. */
  SqlWriterConfig withUpdateSetListNewline(boolean updateSetListNewline);

  /** Returns whether a WINDOW clause should start its own line. */
  @Value.Default default boolean windowNewline() {
    return false;
  }

  /** Sets {@link #windowNewline}. */
  SqlWriterConfig withWindowNewline(boolean windowNewline);

  /** Returns whether commas in SELECT, GROUP BY and ORDER clauses should
   * appear at the start of the line. Default is false. */
  @Value.Default default boolean leadingComma() {
    return false;
  }

  /** Sets {@link #leadingComma()}. */
  SqlWriterConfig withLeadingComma(boolean leadingComma);

  /** Returns the sub-query style.
   * Default is {@link SqlWriter.SubQueryStyle#HYDE}. */
  @Value.Default default SqlWriter.SubQueryStyle subQueryStyle() {
    return SqlWriter.SubQueryStyle.HYDE;
  }

  /** Sets {@link #subQueryStyle}. */
  SqlWriterConfig withSubQueryStyle(SqlWriter.SubQueryStyle subQueryStyle);

  /** Returns whether to print a newline before each AND or OR (whichever is
   * higher level) in WHERE clauses.
   *
   * <p>NOTE: Ignored when alwaysUseParentheses is set to true. */
  @Value.Default default boolean whereListItemsOnSeparateLines() {
    return false;
  }

  /** Sets {@link #whereListItemsOnSeparateLines}. */
  SqlWriterConfig withWhereListItemsOnSeparateLines(
      boolean whereListItemsOnSeparateLines);

  /** Returns whether expressions should always be included in parentheses.
   * Default is false. */
  @Value.Default default boolean alwaysUseParentheses() {
    return false;
  }

  /** Sets {@link #alwaysUseParentheses}. */
  SqlWriterConfig withAlwaysUseParentheses(boolean alwaysUseParentheses);

  /** Returns the maximum line length. Default is zero, which means there is
   * no maximum. */
  @Value.Default default int lineLength() {
    return 0;
  }

  /** Sets {@link #lineLength}. */
  SqlWriterConfig withLineLength(int lineLength);

  /** Returns the line length at which items are chopped or folded (for clauses
   * that have chosen {@link LineFolding#CHOP} or {@link LineFolding#FOLD}).
   * Default is 80. */
  @Value.Default default int foldLength() {
    return 80;
  }

  /** Sets {@link #foldLength()}. */
  SqlWriterConfig withFoldLength(int lineLength);

  /** Returns whether the WHEN, THEN and ELSE clauses of a CASE expression
   * appear at the start of a new line. The default is false. */
  @Value.Default default boolean caseClausesOnNewLines() {
    return false;
  }

  /** Sets {@link #caseClausesOnNewLines}. */
  SqlWriterConfig withCaseClausesOnNewLines(boolean caseClausesOnNewLines);

  /** Policy for how to do deal with long lines.
   *
   * <p>The following examples all have
   * {@link #clauseEndsLine ClauseEndsLine=true},
   * {@link #indentation Indentation=4}, and
   * {@link #foldLength FoldLength=25} (so that the long {@code SELECT}
   * clause folds but the shorter {@code GROUP BY} clause does not).
   *
   * <p>Note that {@link #clauseEndsLine ClauseEndsLine} is observed in
   * STEP and TALL modes, and in CHOP mode when a line is long.
   *
   * <table border=1>
   * <caption>SQL formatted with each Folding value</caption>
   * <tr>
   *   <th>Folding</th>
   *   <th>Example</th>
   * </tr>
   *
   * <tr>
   *   <td>WIDE</td>
   *   <td><pre>
   * SELECT abc, def, ghi, jkl, mno, pqr
   * FROM t
   * GROUP BY abc, def</pre></td>
   * </tr>
   *
   * <tr>
   *   <td>STEP</td>
   *   <td><pre>
   * SELECT
   *     abc, def, ghi, jkl, mno, pqr
   * FROM t
   * GROUP BY
   *     abc, def</pre></td>
   * </tr>
   *
   * <tr>
   *   <td>FOLD</td>
   *   <td><pre>
   * SELECT abc, def, ghi,
   *     jkl, mno, pqr
   * FROM t
   * GROUP BY abc, def</pre></td>
   * </tr>
   *
   * <tr>
   *   <td>CHOP</td>
   *   <td><pre>
   * SELECT
   *     abc,
   *     def,
   *     ghi,
   *     jkl,
   *     mno,
   *     pqr
   * FROM t
   * GROUP BY abc, def</pre></td>
   * </tr>
   *
   * <tr>
   *   <td>TALL</td>
   *   <td><pre>
   * SELECT
   *     abc,
   *     def,
   *     ghi,
   *     jkl,
   *     mno,
   *     pqr
   * FROM t
   * GROUP BY
   *     abc,
   *     def</pre></td>
   * </tr>
   * </table>
   */
  enum LineFolding {
    /** Do not wrap. Items are on the same line, regardless of length. */
    WIDE,

    /** As {@link #WIDE} but start a new line if {@link #clauseEndsLine()}. */
    STEP,

    /** Wrap if long. Items are on the same line, but if the line's length
     * exceeds {@link #foldLength()}, move items to the next line. */
    FOLD,

    /** Chop down if long. Items are on the same line, but if the line grows
     * longer than {@link #foldLength()}, put all items on separate lines. */
    CHOP,

    /** Wrap always. Items are on separate lines. */
    TALL
  }

  /**
   * Create a default SqlWriterConfig object.
   *
   * @return The config.
   */
  static SqlWriterConfig of() {
    return ImmutableSqlWriterConfig.of();
  }
}