sqlformat

repository·master·Indexed 41 days ago

https://github.com/shssoichiro/sqlformat-rs

A pure-Rust library for pretty-printing SQL strings into readable, consistently styled output. Version 0.5.0 supports various mainstream dialects (Generic, PostgreSql, SQLServer) and provides configurable options for indentation, keyword casing, and inline formatting. It includes support for parameter interpolation via QueryParams (Indexed and Named) and allows disabling formatting for specific blocks using -- fmt: off and -- fmt: on comments.

Tokens
4.4K
Snippets
19
Records
23
Agent score
49%

What's inside sqlformat

  1. Temporarily disable formatting using SQL comments

    master

    You can bypass the formatter for specific blocks of SQL by using in-query comment toggles. This allows you to preserve custom layouts for specific queries.

    Line comments:

    -- fmt: off
    SELECT    *   FROM   t    WHERE   a=1 AND b=2;  -- preserved as-is
    -- fmt: on

    Block comments:

    /* fmt: off */ SELECT 1 +   2; /* fmt: on */
  2. Quick start with sqlformat

    master

    To format a SQL string, use the format function. You must provide the SQL string, a QueryParams instance (use QueryParams::None if no interpolation is needed), and a FormatOptions instance.

    use sqlformat::{format, FormatOptions, Indent, QueryParams};
    
    fn main() {
        let sql = "SELECT id, name FROM users WHERE created_at > NOW();";
        let options = FormatOptions::default();
        let formatted = format(sql, &QueryParams::None, &options);
        println!("{}", formatted);
    }
  3. Handle query parameters with QueryParams

    master

    The QueryParams enum allows you to provide values for placeholders in your SQL, which the formatter will then interpolate into the output.

    Supported variants:

    • QueryParams::None: No parameter interpolation.
    • QueryParams::Indexed(Vec<String>): Uses positional placeholders (e.g., ?1, ?2 or ?).
    • QueryParams::Named(Vec<(String, String)>): Uses named placeholders (e.g., @variable, :variable, or $named).

    Example with indexed parameters:

    let input = "SELECT ?1, ?2;";
    let params = vec!["first".to_string(), "second".to_string()];
    let formatted = format(input, &QueryParams::Indexed(params), &FormatOptions::default());
    // Result: SELECT\n  first,\n  second;
    format(input, &QueryParams::Indexed(params), &options)
  4. Use QueryParams for parameter interpolation

    master

    The QueryParams type is used to handle the interpolation of SQL parameters during formatting. It supports two modes of parameter resolution:

    1. Named Parameters (QueryParams::Named): Resolves placeholders based on a specific key name found in the token. The formatter looks for a parameter in the provided collection where the name matches the token's named key.
    2. Indexed Parameters (QueryParams::Indexed): Resolves placeholders based on their position or an explicit index. If the token contains an explicit index, it is used to look up the value; otherwise, the formatter uses an internal counter to fetch parameters sequentially from the collection.

    If a parameter cannot be found in the QueryParams collection, the formatter falls back to using the original token.value.

  5. Disable formatting using `--fmt:off` comments

    master

    The formatter supports skipping specific sections of SQL code by using special comments. If the formatter encounters a comment matching the --fmt:off pattern, it will stop applying formatting rules and output the tokens exactly as they appear until it encounters a --fmt:on comment.

    Supported patterns:

    • --fmt:off
    • --fmt:on

    Note that these must be contained within a comment token (e.g., a line comment) for the switch to trigger.

  6. Disable formatting for specific blocks using comments

    master

    You can prevent the formatter from touching specific parts of your SQL by using special comments. The formatter recognizes -- fmt: off to stop formatting and -- fmt: on to resume it.

    -- fmt: off
    SELECT              *     FROM   sometable
    -- fmt: on
    SELECT
      *
    FROM
      sometable;
  7. Configure indentation in sqlformat

    master

    Use the indent field in FormatOptions to specify whether to use spaces or tabs. When using spaces, you can specify the number of spaces per level using Indent::Spaces(n).

    use sqlformat::{format, FormatOptions, Indent, QueryParams};
    
    // Using 4 spaces
    let options = FormatOptions { indent: Indent::Spaces(4), ..Default::default() };
    let out = format("SELECT a, b FROM t;", &QueryParams::None, &options);
    
    // Using tabs
    let options = FormatOptions { indent: Indent::Tabs, ..Default::default() };
    let out = format("SELECT a, b FROM t;", &QueryParams::None, &options);
  8. Configure inline and compact formatting

    master

    Control how aggressively short blocks and argument lists are kept on a single line using these FormatOptions fields:

    • inline: If true, forces single-line output.
    • max_inline_block: Character limit to keep a parenthesized block inline.
    • max_inline_arguments: Character limit for argument lists.
    • max_inline_top_level: Character limit for top-level elements.
    use sqlformat::{format, FormatOptions, QueryParams};
    
    let options = FormatOptions {
        inline: false,
        max_inline_block: 50,
        max_inline_arguments: Some(40),
        max_inline_top_level: Some(40),
        ..Default::default()
    };
    let out = format("SELECT a, b, c, d, e, f, g, h FROM t;", &QueryParams::None, &options);
  9. Configure keyword case conversion

    master

    Control the casing of reserved SQL keywords using the uppercase field in FormatOptions:

    • Some(true): Converts keywords to uppercase.
    • Some(false): Converts keywords to lowercase.
    • None: Preserves original case.

    You can also use ignore_case_convert to provide a list of specific keywords that should not be modified.

    use sqlformat::{format, FormatOptions, QueryParams};
    
    // Uppercase reserved keywords
    let options = FormatOptions { uppercase: Some(true), ..Default::default() };
    let out = format("select distinct * from foo where bar = 1", &QueryParams::None, &options);
    
    // Lowercase reserved keywords
    let options = FormatOptions { uppercase: Some(false), ..Default::default() };
    let out = format("SELECT DISTINCT * FROM FOO WHERE BAR = 1", &QueryParams::None, &options);
    
    // Preserve case with exceptions
    let options = FormatOptions {
        uppercase: Some(true),
        ignore_case_convert: Some(vec!["from".to_string(), "where".to_string()]),
        ..Default::default()
    };
    let out = format("select * from foo where bar = 1", &QueryParams::None, &options);
  10. Use parameter interpolation with QueryParams

    master

    The format function supports substituting placeholders using the QueryParams enum:

    • QueryParams::Indexed(Vec<String>): For positional/numbered placeholders like ?, ?1, or $1.
    • QueryParams::Named(Vec<(String, String)>): For named placeholders like $name, :name, @name, or bracketed variants like @`var name` `.
    use sqlformat::{format, FormatOptions, QueryParams};
    
    // Numbered / positional (e.g., ?, ?1, $1)
    let sql = "SELECT ?1, ?, $2;";
    let params = QueryParams::Indexed(vec!["first".to_string(), "second".to_string(), "third".to_string()]);
    let out = format(sql, &params, &FormatOptions::default());
    
    // Named (e.g., $name, :name, @name, :"weird name")
    let sql = "SELECT $hash, :name, @`var name`;";
    let params = QueryParams::Named(vec![
        ("hash".to_string(), "hash value".to_string()),
        ("name".to_string(), "Alice".to_string()),
        ("var name".to_string(), "Bob".to_string()),
    ]);
    let out = format(sql, &params, &FormatOptions::default());
  11. Control blank lines between statements

    master

    Use the lines_between_queries field in FormatOptions to specify how many blank lines should be inserted between separate SQL statements.

    use sqlformat::{format, FormatOptions, QueryParams};
    
    let options = FormatOptions { lines_between_queries: 2, ..Default::default() };
    let out = format("SELECT 1; SELECT 2;", &QueryParams::None, &options);