sqlformat/
lib.rs

1//! This crate is a port of https://github.com/kufii/sql-formatter-plus
2//! written in Rust. It is intended to be usable as a pure-Rust library
3//! for formatting SQL queries.
4
5#![type_length_limit = "99999999"]
6#![forbid(unsafe_code)]
7// Maintains semver compatibility for older Rust versions
8#![allow(clippy::manual_strip)]
9// This lint is overly pedantic and annoying
10#![allow(clippy::needless_lifetimes)]
11
12mod formatter;
13mod indentation;
14mod inline_block;
15mod params;
16mod tokenizer;
17
18#[cfg(feature = "debug")]
19mod debug;
20
21/// Formats whitespace in a SQL string to make it easier to read.
22/// Optionally replaces parameter placeholders with `params`.
23pub fn format(query: &str, params: &QueryParams, options: &FormatOptions) -> String {
24    let named_placeholders = matches!(params, QueryParams::Named(_));
25
26    let tokens = tokenizer::tokenize(query, named_placeholders, options);
27    formatter::format(&tokens, params, options)
28}
29
30/// The SQL dialect to use. This affects parsing of special characters.
31#[derive(Debug, Clone, Copy, PartialEq, Eq)]
32pub enum Dialect {
33    /// Generic SQL syntax, most dialect-specific constructs are disabled
34    Generic,
35    /// Enables array syntax (`[`, `]`) and operators
36    PostgreSql,
37    /// Enables `[bracketed identifiers]` and `@variables`
38    SQLServer,
39}
40
41/// Options for controlling how the library formats SQL
42#[derive(Debug, Clone)]
43pub struct FormatOptions<'a> {
44    /// Controls the type and length of indentation to use
45    ///
46    /// Default: 2 spaces
47    pub indent: Indent,
48    /// When set, changes reserved keywords to ALL CAPS
49    ///
50    /// Default: false
51    pub uppercase: Option<bool>,
52    /// Controls the number of line breaks after a query
53    ///
54    /// Default: 1
55    pub lines_between_queries: u8,
56    /// Ignore case conversion for specified strings in the array.
57    ///
58    /// Default: None
59    pub ignore_case_convert: Option<Vec<&'a str>>,
60    /// Keep the query in a single line
61    ///
62    /// Default: false
63    pub inline: bool,
64    /// Maximum length of an inline block
65    ///
66    /// Default: 50
67    pub max_inline_block: usize,
68    /// Maximum length of inline arguments
69    ///
70    /// If unset keep every argument in a separate line
71    ///
72    /// Default: None
73    pub max_inline_arguments: Option<usize>,
74    /// Inline the argument at the top level if they would fit a line of this length
75    ///
76    /// Default: None
77    pub max_inline_top_level: Option<usize>,
78    /// Consider any JOIN statement as a top level keyword instead of a reserved keyword
79    ///
80    /// Default: false,
81    pub joins_as_top_level: bool,
82    /// Tell the SQL dialect to use
83    ///
84    /// Default: Generic
85    pub dialect: Dialect,
86}
87
88impl<'a> Default for FormatOptions<'a> {
89    fn default() -> Self {
90        FormatOptions {
91            indent: Indent::Spaces(2),
92            uppercase: None,
93            lines_between_queries: 1,
94            ignore_case_convert: None,
95            inline: false,
96            max_inline_block: 50,
97            max_inline_arguments: None,
98            max_inline_top_level: None,
99            joins_as_top_level: false,
100            dialect: Dialect::Generic,
101        }
102    }
103}
104
105#[derive(Debug, Clone, Copy)]
106pub enum Indent {
107    Spaces(u8),
108    Tabs,
109}
110
111#[derive(Debug, Clone, Default)]
112pub enum QueryParams {
113    Named(Vec<(String, String)>),
114    Indexed(Vec<String>),
115    #[default]
116    None,
117}
118
119#[derive(Default, Debug, Clone)]
120pub(crate) struct SpanInfo {
121    pub full_span: usize,
122    pub blocks: usize,
123    pub newline_before: bool,
124    pub newline_after: bool,
125    pub arguments: usize,
126}
127
128#[cfg(test)]
129mod tests {
130    use super::*;
131    use indoc::indoc;
132    use pretty_assertions::assert_eq;
133
134    #[test]
135    fn test_sqlite_blob_literal_fmt() {
136        let options = FormatOptions::default();
137
138        let input = "SELECT x'73716c69676874' AS BLOB_VAL;";
139        let expected = indoc!(
140            "
141            SELECT
142              x'73716c69676874' AS BLOB_VAL;"
143        );
144        assert_eq!(format(input, &QueryParams::None, &options), expected);
145
146        let input = "SELECT X'73716c69676874' AS BLOB_VAL;";
147        let expected = indoc!(
148            "
149            SELECT
150              X'73716c69676874' AS BLOB_VAL;"
151        );
152        assert_eq!(format(input, &QueryParams::None, &options), expected);
153    }
154
155    #[test]
156    fn it_uses_given_indent_config_for_indentation() {
157        let input = "SELECT count(*),Column1 FROM Table1;";
158        let options = FormatOptions {
159            indent: Indent::Spaces(4),
160            ..FormatOptions::default()
161        };
162        let expected = indoc!(
163            "
164            SELECT
165                count(*),
166                Column1
167            FROM
168                Table1;"
169        );
170
171        assert_eq!(format(input, &QueryParams::None, &options), expected);
172    }
173
174    #[test]
175    fn it_formats_simple_set_schema_queries() {
176        let input = "SET SCHEMA schema1; SET CURRENT SCHEMA schema2;";
177        let options = FormatOptions::default();
178        let expected = indoc!(
179            "
180            SET SCHEMA
181              schema1;
182            SET CURRENT SCHEMA
183              schema2;"
184        );
185
186        assert_eq!(format(input, &QueryParams::None, &options), expected);
187    }
188
189    #[test]
190    fn it_formats_simple_select_query() {
191        let input = "SELECT count(*),Column1 FROM Table1;";
192        let options = FormatOptions::default();
193        let expected = indoc!(
194            "
195            SELECT
196              count(*),
197              Column1
198            FROM
199              Table1;"
200        );
201
202        assert_eq!(format(input, &QueryParams::None, &options), expected);
203    }
204
205    #[test]
206    fn it_formats_complex_select() {
207        let input =
208            "SELECT DISTINCT name, ROUND(age/7) field1, 18 + 20 AS field2, 'some string' FROM foo;";
209        let options = FormatOptions::default();
210        let expected = indoc!(
211            "
212            SELECT DISTINCT
213              name,
214              ROUND(age / 7) field1,
215              18 + 20 AS field2,
216              'some string'
217            FROM
218              foo;"
219        );
220
221        assert_eq!(format(input, &QueryParams::None, &options), expected);
222    }
223
224    #[test]
225    fn it_formats_over_with_window() {
226        let input =
227            "SELECT id, val, at, SUM(val) OVER win AS cumulative FROM data WINDOW win AS (PARTITION BY id ORDER BY at);";
228        let options = FormatOptions::default();
229        let expected = indoc!(
230            "
231            SELECT
232              id,
233              val,
234              at,
235              SUM(val) OVER win AS cumulative
236            FROM
237              data
238            WINDOW
239              win AS (
240                PARTITION BY
241                  id
242                ORDER BY
243                  at
244              );"
245        );
246
247        assert_eq!(format(input, &QueryParams::None, &options), expected);
248    }
249
250    #[test]
251    fn it_formats_distinct_from() {
252        let input = "SELECT bar IS DISTINCT FROM 'baz', IS NOT DISTINCT FROM 'foo' FROM foo;";
253        let options = FormatOptions::default();
254        let expected = indoc!(
255            "
256            SELECT
257              bar IS DISTINCT FROM 'baz',
258              IS NOT DISTINCT FROM 'foo'
259            FROM
260              foo;"
261        );
262
263        assert_eq!(format(input, &QueryParams::None, &options), expected);
264    }
265
266    #[test]
267    fn keep_select_arguments_inline() {
268        let input = indoc! {
269            "
270            SELECT
271              a,
272              b,
273              c,
274              d,
275              e,
276              f,
277              g,
278              h
279            FROM foo;"
280        };
281        let options = FormatOptions {
282            max_inline_arguments: Some(50),
283            ..Default::default()
284        };
285        let expected = indoc! {
286            "
287            SELECT
288              a, b, c, d, e, f, g, h
289            FROM
290              foo;"
291        };
292        assert_eq!(format(input, &QueryParams::None, &options), expected);
293    }
294
295    #[test]
296    fn split_select_arguments_inline_top_level() {
297        let input = indoc! {
298            "
299            SELECT
300              a,
301              b,
302              c,
303              d,
304              e,
305              f,
306              g,
307              h
308            FROM foo;"
309        };
310        let options = FormatOptions {
311            max_inline_arguments: Some(50),
312            max_inline_top_level: Some(50),
313            ..Default::default()
314        };
315        let expected = indoc! {
316            "
317            SELECT a, b, c, d, e, f, g, h
318            FROM foo;"
319        };
320        assert_eq!(format(input, &QueryParams::None, &options), expected);
321    }
322
323    #[test]
324    fn inline_arguments_when_possible() {
325        let input = indoc! {
326            "
327            SELECT
328              a,
329              b,
330              c,
331              d,
332              e,
333              f,
334              g,
335              h
336            FROM foo;"
337        };
338        let options = FormatOptions {
339            max_inline_arguments: Some(50),
340            max_inline_top_level: Some(20),
341            ..Default::default()
342        };
343        let expected = indoc! {
344            "
345            SELECT
346              a, b, c, d, e, f, g, h
347            FROM foo;"
348        };
349        assert_eq!(format(input, &QueryParams::None, &options), expected);
350    }
351
352    #[test]
353    fn inline_single_block_argument() {
354        let input = "SELECT a, b, c FROM ( SELECT (e+f) AS a, (m+o) AS b FROM d) WHERE (a != b) OR (c IS NULL AND a == b)";
355        let options = FormatOptions {
356            max_inline_arguments: Some(10),
357            max_inline_top_level: Some(20),
358            ..Default::default()
359        };
360        let expected = indoc! {
361            "
362            SELECT a, b, c
363            FROM (
364              SELECT
365                (e + f) AS a,
366                (m + o) AS b
367              FROM d
368            )
369            WHERE
370              (a != b)
371              OR (
372                c IS NULL
373                AND a == b
374              )"
375        };
376        assert_eq!(format(input, &QueryParams::None, &options), expected);
377    }
378
379    #[test]
380    fn it_formats_select_with_complex_where() {
381        let input = indoc!(
382            "
383            SELECT * FROM foo WHERE Column1 = 'testing'
384            AND ( (Column2 = Column3 OR Column4 >= NOW()) );
385      "
386        );
387        let options = FormatOptions::default();
388        let expected = indoc!(
389            "
390            SELECT
391              *
392            FROM
393              foo
394            WHERE
395              Column1 = 'testing'
396              AND (
397                (
398                  Column2 = Column3
399                  OR Column4 >= NOW()
400                )
401              );"
402        );
403
404        assert_eq!(format(input, &QueryParams::None, &options), expected);
405    }
406
407    #[test]
408    fn it_formats_select_with_complex_where_inline() {
409        let input = indoc!(
410            "
411            SELECT * FROM foo WHERE Column1 = 'testing'
412            AND ( (Column2 = Column3 OR Column4 >= NOW()) );
413      "
414        );
415        let options = FormatOptions {
416            max_inline_arguments: Some(100),
417            ..Default::default()
418        };
419        let expected = indoc!(
420            "
421            SELECT
422              *
423            FROM
424              foo
425            WHERE
426              Column1 = 'testing' AND ((Column2 = Column3 OR Column4 >= NOW()));"
427        );
428
429        assert_eq!(format(input, &QueryParams::None, &options), expected);
430    }
431
432    #[test]
433    fn it_formats_select_with_top_level_reserved_words() {
434        let input = indoc!(
435            "
436            SELECT * FROM foo WHERE name = 'John' GROUP BY some_column
437            HAVING column > 10 ORDER BY other_column LIMIT 5;
438      "
439        );
440        let options = FormatOptions::default();
441        let expected = indoc!(
442            "
443            SELECT
444              *
445            FROM
446              foo
447            WHERE
448              name = 'John'
449            GROUP BY
450              some_column
451            HAVING
452              column > 10
453            ORDER BY
454              other_column
455            LIMIT
456              5;"
457        );
458
459        assert_eq!(format(input, &QueryParams::None, &options), expected);
460    }
461
462    #[test]
463    fn it_formats_select_with_for_update_of() {
464        let input: &'static str = "SELECT id FROM users WHERE disabled_at IS NULL FOR UPDATE OF users SKIP LOCKED LIMIT 1";
465        let options = FormatOptions::default();
466        let expected = indoc!(
467            "
468            SELECT
469              id
470            FROM
471              users
472            WHERE
473              disabled_at IS NULL
474            FOR UPDATE
475              OF users SKIP LOCKED
476            LIMIT
477              1"
478        );
479
480        assert_eq!(format(input, &QueryParams::None, &options), expected);
481    }
482
483    #[test]
484    fn it_formats_limit_with_two_comma_separated_values_on_single_line() {
485        let input = "LIMIT 5, 10;";
486        let options = FormatOptions::default();
487        let expected = indoc!(
488            "
489            LIMIT
490              5, 10;"
491        );
492
493        assert_eq!(format(input, &QueryParams::None, &options), expected);
494    }
495
496    #[test]
497    fn it_formats_limit_of_single_value_followed_by_another_select_using_commas() {
498        let input = "LIMIT 5; SELECT foo, bar;";
499        let options = FormatOptions::default();
500        let expected = indoc!(
501            "
502            LIMIT
503              5;
504            SELECT
505              foo,
506              bar;"
507        );
508
509        assert_eq!(format(input, &QueryParams::None, &options), expected);
510    }
511
512    #[test]
513    fn it_formats_type_specifiers() {
514        let input = "SELECT id,  ARRAY [] :: UUID [] FROM UNNEST($1  ::  UUID   []) WHERE $1::UUID[] IS NOT NULL;";
515        let options = FormatOptions {
516            dialect: Dialect::PostgreSql,
517            ..Default::default()
518        };
519        let expected = indoc!(
520            "
521            SELECT
522              id,
523              ARRAY[]::UUID[]
524            FROM
525              UNNEST($1::UUID[])
526            WHERE
527              $1::UUID[] IS NOT NULL;"
528        );
529
530        assert_eq!(format(input, &QueryParams::None, &options), expected);
531    }
532
533    #[test]
534    fn it_formats_arrays_as_function_arguments() {
535        let input =
536            "SELECT array_position(ARRAY['sun','mon','tue',  'wed',   'thu','fri',  'sat'], 'mon');";
537        let options = FormatOptions {
538            dialect: Dialect::PostgreSql,
539            ..Default::default()
540        };
541        let expected = indoc!(
542            "
543            SELECT
544              array_position(
545                ARRAY['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'],
546                'mon'
547              );"
548        );
549
550        assert_eq!(format(input, &QueryParams::None, &options), expected);
551    }
552
553    #[test]
554    fn it_formats_arrays_as_values() {
555        let input = " INSERT INTO t VALUES('a', ARRAY[0, 1,2,3], ARRAY[['a','b'],    ['c' ,'d']]);";
556        let options = FormatOptions {
557            dialect: Dialect::PostgreSql,
558            max_inline_block: 10,
559            max_inline_top_level: Some(50),
560            ..Default::default()
561        };
562        let expected = indoc!(
563            "
564            INSERT INTO t
565            VALUES (
566              'a',
567              ARRAY[0, 1, 2, 3],
568              ARRAY[
569                ['a', 'b'],
570                ['c', 'd']
571              ]
572            );"
573        );
574
575        assert_eq!(format(input, &QueryParams::None, &options), expected);
576    }
577
578    #[test]
579    fn it_formats_array_index_notation() {
580        let input = "SELECT a [ 1 ] + b [ 2 ] [   5+1 ] > c [3] ;";
581        let options = FormatOptions {
582            dialect: Dialect::PostgreSql,
583            ..Default::default()
584        };
585        let expected = indoc!(
586            "
587            SELECT
588              a[1] + b[2][5 + 1] > c[3];"
589        );
590
591        assert_eq!(format(input, &QueryParams::None, &options), expected);
592    }
593    #[test]
594    fn it_formats_limit_of_single_value_and_offset() {
595        let input = "LIMIT 5 OFFSET 8;";
596        let options = FormatOptions::default();
597        let expected = indoc!(
598            "
599            LIMIT
600              5 OFFSET 8;"
601        );
602
603        assert_eq!(format(input, &QueryParams::None, &options), expected);
604    }
605
606    #[test]
607    fn it_recognizes_limit_in_lowercase() {
608        let input = "limit 5, 10;";
609        let options = FormatOptions::default();
610        let expected = indoc!(
611            "
612            limit
613              5, 10;"
614        );
615
616        assert_eq!(format(input, &QueryParams::None, &options), expected);
617    }
618
619    #[test]
620    fn it_preserves_case_of_keywords() {
621        let input = "select distinct * frOM foo left join bar WHERe a > 1 and b = 3";
622        let options = FormatOptions::default();
623        let expected = indoc!(
624            "
625            select distinct
626              *
627            frOM
628              foo
629              left join bar
630            WHERe
631              a > 1
632              and b = 3"
633        );
634
635        assert_eq!(format(input, &QueryParams::None, &options), expected);
636    }
637
638    #[test]
639    fn it_formats_select_query_with_select_query_inside_it() {
640        let input = "SELECT *, SUM(*) AS sum FROM (SELECT * FROM Posts LIMIT 30) WHERE a > b";
641        let options = FormatOptions::default();
642        let expected = indoc!(
643            "
644            SELECT
645              *,
646              SUM(*) AS sum
647            FROM
648              (
649                SELECT
650                  *
651                FROM
652                  Posts
653                LIMIT
654                  30
655              )
656            WHERE
657              a > b"
658        );
659
660        assert_eq!(format(input, &QueryParams::None, &options), expected);
661    }
662
663    #[test]
664    fn it_formats_select_query_with_inner_join() {
665        let input = indoc!(
666            "
667            SELECT customer_id.from, COUNT(order_id) AS total FROM customers
668            INNER JOIN orders ON customers.customer_id = orders.customer_id;"
669        );
670        let options = FormatOptions::default();
671        let expected = indoc!(
672            "
673            SELECT
674              customer_id.from,
675              COUNT(order_id) AS total
676            FROM
677              customers
678              INNER JOIN orders ON customers.customer_id = orders.customer_id;"
679        );
680
681        assert_eq!(format(input, &QueryParams::None, &options), expected);
682    }
683
684    #[test]
685    fn it_formats_select_query_with_non_standard_join() {
686        let input = indoc!(
687            "
688            SELECT customer_id.from, COUNT(order_id) AS total FROM customers
689            INNER ANY JOIN orders ON customers.customer_id = orders.customer_id
690            LEFT
691            SEMI JOIN foo ON foo.id = customers.id
692            PASTE
693            JOIN bar
694            ;"
695        );
696        let options = FormatOptions::default();
697        let expected = indoc!(
698            "
699            SELECT
700              customer_id.from,
701              COUNT(order_id) AS total
702            FROM
703              customers
704              INNER ANY JOIN orders ON customers.customer_id = orders.customer_id
705              LEFT SEMI JOIN foo ON foo.id = customers.id
706              PASTE JOIN bar;"
707        );
708
709        assert_eq!(format(input, &QueryParams::None, &options), expected);
710    }
711
712    #[test]
713    fn it_formats_select_query_with_non_standard_join_as_toplevel() {
714        let input = indoc!(
715            "
716            SELECT customer_id.from, COUNT(order_id) AS total FROM customers
717            INNER ANY JOIN orders ON customers.customer_id = orders.customer_id
718            LEFT
719            SEMI JOIN foo ON foo.id = customers.id
720            PASTE
721            JOIN bar
722            ;"
723        );
724        let options = FormatOptions {
725            joins_as_top_level: true,
726            max_inline_top_level: Some(40),
727            max_inline_arguments: Some(40),
728            ..Default::default()
729        };
730        let expected = indoc!(
731            "
732            SELECT
733              customer_id.from,
734              COUNT(order_id) AS total
735            FROM customers
736            INNER ANY JOIN
737              orders ON customers.customer_id = orders.customer_id
738            LEFT SEMI JOIN foo ON foo.id = customers.id
739            PASTE JOIN bar;"
740        );
741
742        assert_eq!(format(input, &QueryParams::None, &options), expected);
743    }
744
745    #[test]
746    fn it_formats_select_query_with_different_comments() {
747        let input = indoc!(
748            "
749            SELECT
750            /*
751             * This is a block comment
752             */
753            * FROM
754            -- This is another comment
755            MyTable # One final comment
756            WHERE 1 = 2;"
757        );
758        let options = FormatOptions::default();
759        let expected = indoc!(
760            "
761            SELECT
762              /*
763               * This is a block comment
764               */
765              *
766            FROM
767              -- This is another comment
768              MyTable # One final comment
769            WHERE
770              1 = 2;"
771        );
772
773        assert_eq!(format(input, &QueryParams::None, &options), expected);
774    }
775
776    #[test]
777    fn it_maintains_block_comment_indentation() {
778        let input = indoc!(
779            "
780            SELECT
781              /*
782               * This is a block comment
783               */
784              *
785            FROM
786              MyTable
787            WHERE
788              1 = 2;"
789        );
790        let options = FormatOptions::default();
791
792        assert_eq!(format(input, &QueryParams::None, &options), input);
793    }
794
795    #[test]
796    fn it_formats_simple_insert_query() {
797        let input = "INSERT INTO Customers (ID, MoneyBalance, Address, City) VALUES (12,-123.4, 'Skagen 2111','Stv');";
798        let options = FormatOptions::default();
799        let expected = indoc!(
800            "
801            INSERT INTO
802              Customers (ID, MoneyBalance, Address, City)
803            VALUES
804              (12, -123.4, 'Skagen 2111', 'Stv');"
805        );
806
807        assert_eq!(format(input, &QueryParams::None, &options), expected);
808    }
809
810    #[test]
811    fn it_formats_complex_insert_query() {
812        let input = "
813 INSERT INTO t(id, a, min, max) SELECT input.id, input.a, input.min, input.max FROM ( SELECT id, a, min, max FROM foo WHERE a IN ('a', 'b') ) AS input WHERE (SELECT true FROM condition) ON CONFLICT ON CONSTRAINT a_id_key DO UPDATE SET id = EXCLUDED.id, a = EXCLUDED.severity, min = EXCLUDED.min, max = EXCLUDED.max RETURNING *; ";
814        let max_line = 50;
815        let options = FormatOptions {
816            max_inline_block: max_line,
817            max_inline_arguments: Some(max_line),
818            max_inline_top_level: Some(max_line),
819            ..Default::default()
820        };
821
822        let expected = indoc!(
823            "
824            INSERT INTO t(id, a, min, max)
825            SELECT input.id, input.a, input.min, input.max
826            FROM (
827              SELECT id, a, min, max
828              FROM foo
829              WHERE a IN ('a', 'b')
830            ) AS input
831            WHERE (SELECT true FROM condition)
832            ON CONFLICT ON CONSTRAINT a_id_key DO UPDATE SET
833              id = EXCLUDED.id,
834              a = EXCLUDED.severity,
835              min = EXCLUDED.min,
836              max = EXCLUDED.max
837            RETURNING *;"
838        );
839
840        assert_eq!(format(input, &QueryParams::None, &options), expected);
841    }
842
843    #[test]
844    fn it_keeps_short_parenthesized_list_with_nested_parenthesis_on_single_line() {
845        let input = "SELECT (a + b * (c - NOW()));";
846        let options = FormatOptions::default();
847        let expected = indoc!(
848            "
849            SELECT
850              (a + b * (c - NOW()));"
851        );
852
853        assert_eq!(format(input, &QueryParams::None, &options), expected);
854    }
855
856    #[test]
857    fn it_breaks_long_parenthesized_lists_to_multiple_lines() {
858        let input = indoc!(
859            "
860            INSERT INTO some_table (id_product, id_shop, id_currency, id_country, id_registration) (
861            SELECT IF(dq.id_discounter_shopping = 2, dq.value, dq.value / 100),
862            IF (dq.id_discounter_shopping = 2, 'amount', 'percentage') FROM foo);"
863        );
864        let options = FormatOptions::default();
865        let expected = indoc!(
866            "
867            INSERT INTO
868              some_table (
869                id_product,
870                id_shop,
871                id_currency,
872                id_country,
873                id_registration
874              ) (
875                SELECT
876                  IF (
877                    dq.id_discounter_shopping = 2,
878                    dq.value,
879                    dq.value / 100
880                  ),
881                  IF (
882                    dq.id_discounter_shopping = 2,
883                    'amount',
884                    'percentage'
885                  )
886                FROM
887                  foo
888              );"
889        );
890
891        assert_eq!(format(input, &QueryParams::None, &options), expected);
892    }
893
894    #[test]
895    fn it_keep_long_parenthesized_lists_to_multiple_lines() {
896        let input = indoc!(
897            "
898            INSERT INTO some_table (id_product, id_shop, id_currency, id_country, id_registration) (
899            SELECT IF (dq.id_discounter_shopping = 2, dq.value, dq.value / 100),
900            IF (dq.id_discounter_shopping = 2, 'amount', 'percentage') FROM foo);"
901        );
902        let options = FormatOptions {
903            max_inline_block: 100,
904            ..Default::default()
905        };
906        let expected = indoc!(
907            "
908            INSERT INTO
909              some_table (id_product, id_shop, id_currency, id_country, id_registration) (
910                SELECT
911                  IF (dq.id_discounter_shopping = 2, dq.value, dq.value / 100),
912                  IF (dq.id_discounter_shopping = 2, 'amount', 'percentage')
913                FROM
914                  foo
915              );"
916        );
917
918        assert_eq!(format(input, &QueryParams::None, &options), expected);
919    }
920
921    #[test]
922    fn it_formats_simple_update_query() {
923        let input = "UPDATE Customers SET ContactName='Alfred Schmidt', City='Hamburg' WHERE CustomerName='Alfreds Futterkiste';";
924        let options = FormatOptions::default();
925        let expected = indoc!(
926            "
927            UPDATE
928              Customers
929            SET
930              ContactName = 'Alfred Schmidt',
931              City = 'Hamburg'
932            WHERE
933              CustomerName = 'Alfreds Futterkiste';"
934        );
935
936        assert_eq!(format(input, &QueryParams::None, &options), expected);
937    }
938
939    #[test]
940    fn it_formats_simple_update_query_inlining_set() {
941        let input = "UPDATE Customers SET ContactName='Alfred Schmidt', City='Hamburg' WHERE CustomerName='Alfreds Futterkiste';";
942        let options = FormatOptions {
943            max_inline_top_level: Some(20),
944            max_inline_arguments: Some(10),
945            ..Default::default()
946        };
947        let expected = indoc!(
948            "
949            UPDATE Customers SET
950              ContactName = 'Alfred Schmidt',
951              City = 'Hamburg'
952            WHERE
953              CustomerName = 'Alfreds Futterkiste';"
954        );
955
956        assert_eq!(format(input, &QueryParams::None, &options), expected);
957    }
958
959    #[test]
960    fn it_formats_simple_delete_query() {
961        let input = "DELETE FROM Customers WHERE CustomerName='Alfred' AND Phone=5002132;";
962        let options = FormatOptions::default();
963        let expected = indoc!(
964            "
965            DELETE FROM
966              Customers
967            WHERE
968              CustomerName = 'Alfred'
969              AND Phone = 5002132;"
970        );
971
972        assert_eq!(format(input, &QueryParams::None, &options), expected);
973    }
974
975    #[test]
976    fn it_formats_full_delete_query() {
977        let input =
978            "DELETE FROM Customers USING Phonebook WHERE CustomerName='Alfred' AND Phone=5002132;";
979        let options = FormatOptions::default();
980        let expected = indoc!(
981            "
982            DELETE FROM
983              Customers
984            USING
985              Phonebook
986            WHERE
987              CustomerName = 'Alfred'
988              AND Phone = 5002132;"
989        );
990
991        assert_eq!(format(input, &QueryParams::None, &options), expected);
992    }
993
994    #[test]
995    fn it_formats_simple_drop_query() {
996        let input = "DROP TABLE IF EXISTS admin_role;";
997        let options = FormatOptions::default();
998
999        assert_eq!(format(input, &QueryParams::None, &options), input);
1000    }
1001
1002    #[test]
1003    fn it_formats_incomplete_query() {
1004        let input = "SELECT count(";
1005        let options = FormatOptions::default();
1006        let expected = indoc!(
1007            "
1008            SELECT
1009              count("
1010        );
1011
1012        assert_eq!(format(input, &QueryParams::None, &options), expected);
1013    }
1014
1015    #[test]
1016    fn it_formats_query_that_ends_with_open_comment() {
1017        let input = indoc!(
1018            "
1019            SELECT count(*)
1020            /*Comment"
1021        );
1022        let options = FormatOptions::default();
1023        let expected = indoc!(
1024            "
1025            SELECT
1026              count(*)
1027              /*Comment"
1028        );
1029
1030        assert_eq!(format(input, &QueryParams::None, &options), expected);
1031    }
1032
1033    #[test]
1034    fn it_formats_update_query_with_as_part() {
1035        let input = "UPDATE customers SET total_orders = order_summary.total  FROM ( SELECT * FROM bank) AS order_summary";
1036        let options = FormatOptions::default();
1037        let expected = indoc!(
1038            "
1039            UPDATE
1040              customers
1041            SET
1042              total_orders = order_summary.total
1043            FROM
1044              (
1045                SELECT
1046                  *
1047                FROM
1048                  bank
1049              ) AS order_summary"
1050        );
1051
1052        assert_eq!(format(input, &QueryParams::None, &options), expected);
1053    }
1054
1055    #[test]
1056    fn it_formats_update_query_with_as_part_inline() {
1057        let options = FormatOptions {
1058            inline: true,
1059            ..Default::default()
1060        };
1061        let expected = "UPDATE customers SET total_orders = order_summary.total FROM ( SELECT * FROM bank ) AS order_summary";
1062        let input = indoc!(
1063            "
1064            UPDATE
1065              customers
1066            SET
1067              total_orders = order_summary.total
1068            FROM
1069              (
1070                SELECT
1071                  *
1072                FROM
1073                  bank
1074              ) AS order_summary"
1075        );
1076
1077        assert_eq!(format(input, &QueryParams::None, &options), expected);
1078    }
1079
1080    #[test]
1081    fn it_formats_top_level_and_newline_multi_word_reserved_words_with_inconsistent_spacing() {
1082        let input = "SELECT * FROM foo LEFT \t OUTER  \n JOIN bar ORDER \n BY blah";
1083        let options = FormatOptions::default();
1084        let expected = indoc!(
1085            "
1086            SELECT
1087              *
1088            FROM
1089              foo
1090              LEFT OUTER JOIN bar
1091            ORDER BY
1092              blah"
1093        );
1094
1095        assert_eq!(format(input, &QueryParams::None, &options), expected);
1096    }
1097
1098    #[test]
1099    fn it_formats_long_double_parenthesized_queries_to_multiple_lines() {
1100        let input = "((foo = '0123456789-0123456789-0123456789-0123456789'))";
1101        let options = FormatOptions::default();
1102        let expected = indoc!(
1103            "
1104            (
1105              (
1106                foo = '0123456789-0123456789-0123456789-0123456789'
1107              )
1108            )"
1109        );
1110
1111        assert_eq!(format(input, &QueryParams::None, &options), expected);
1112    }
1113
1114    #[test]
1115    fn it_formats_short_double_parenthesizes_queries_to_one_line() {
1116        let input = "((foo = 'bar'))";
1117        let options = FormatOptions::default();
1118
1119        assert_eq!(format(input, &QueryParams::None, &options), input);
1120    }
1121
1122    #[test]
1123    fn it_formats_single_char_operators() {
1124        let inputs = [
1125            "foo = bar",
1126            "foo < bar",
1127            "foo > bar",
1128            "foo + bar",
1129            "foo - bar",
1130            "foo * bar",
1131            "foo / bar",
1132            "foo % bar",
1133        ];
1134        let options = FormatOptions::default();
1135        for input in &inputs {
1136            assert_eq!(&format(input, &QueryParams::None, &options), input);
1137        }
1138    }
1139
1140    #[test]
1141    fn it_formats_multi_char_operators() {
1142        let inputs = [
1143            "foo != bar",
1144            "foo <> bar",
1145            "foo == bar",
1146            "foo || bar",
1147            "foo <= bar",
1148            "foo >= bar",
1149            "foo !< bar",
1150            "foo !> bar",
1151        ];
1152        let options = FormatOptions::default();
1153        for input in &inputs {
1154            assert_eq!(&format(input, &QueryParams::None, &options), input);
1155        }
1156    }
1157
1158    #[test]
1159    fn it_formats_logical_operators() {
1160        let inputs = [
1161            "foo ALL bar",
1162            "foo = ANY (1, 2, 3)",
1163            "EXISTS bar",
1164            "foo IN (1, 2, 3)",
1165            "foo LIKE 'hello%'",
1166            "foo IS NULL",
1167            "UNIQUE foo",
1168        ];
1169        let options = FormatOptions::default();
1170        for input in &inputs {
1171            assert_eq!(&format(input, &QueryParams::None, &options), input);
1172        }
1173    }
1174
1175    #[test]
1176    fn it_formats_and_or_operators() {
1177        let strings = [
1178            ("foo BETWEEN bar AND baz", "foo BETWEEN bar AND baz"),
1179            ("foo BETWEEN\nbar\nAND baz", "foo BETWEEN bar AND baz"),
1180            ("foo AND bar", "foo\nAND bar"),
1181            ("foo OR bar", "foo\nOR bar"),
1182        ];
1183        let options = FormatOptions::default();
1184        for (input, output) in &strings {
1185            assert_eq!(&format(input, &QueryParams::None, &options), output);
1186        }
1187    }
1188
1189    #[test]
1190    fn it_recognizes_strings() {
1191        let inputs = ["\"foo JOIN bar\"", "'foo JOIN bar'", "`foo JOIN bar`"];
1192        let options = FormatOptions::default();
1193        for input in &inputs {
1194            assert_eq!(&format(input, &QueryParams::None, &options), input);
1195        }
1196    }
1197
1198    #[test]
1199    fn it_recognizes_escaped_strings() {
1200        let inputs = [
1201            r#""foo \" JOIN bar""#,
1202            r#"'foo \' JOIN bar'"#,
1203            r#"`foo `` JOIN bar`"#,
1204            r#"'foo '' JOIN bar'"#,
1205            r#"'two households"'"#,
1206            r#"'two households'''"#,
1207            r#"E'alice'''"#,
1208        ];
1209        let options = FormatOptions::default();
1210        for input in &inputs {
1211            assert_eq!(&format(input, &QueryParams::None, &options), input);
1212        }
1213    }
1214
1215    #[test]
1216    fn it_formats_postgres_specific_operators() {
1217        let strings = [
1218            ("column::int", "column::int"),
1219            ("v->2", "v -> 2"),
1220            ("v->>2", "v ->> 2"),
1221            ("foo ~~ 'hello'", "foo ~~ 'hello'"),
1222            ("foo !~ 'hello'", "foo !~ 'hello'"),
1223            ("foo ~* 'hello'", "foo ~* 'hello'"),
1224            ("foo ~~* 'hello'", "foo ~~* 'hello'"),
1225            ("foo !~~ 'hello'", "foo !~~ 'hello'"),
1226            ("foo !~* 'hello'", "foo !~* 'hello'"),
1227            ("foo !~~* 'hello'", "foo !~~* 'hello'"),
1228        ];
1229        let options = FormatOptions::default();
1230        for (input, output) in &strings {
1231            assert_eq!(&format(input, &QueryParams::None, &options), output);
1232        }
1233    }
1234
1235    #[test]
1236    fn it_keeps_separation_between_multiple_statements() {
1237        let strings = [
1238            ("foo;bar;", "foo;\nbar;"),
1239            ("foo\n;bar;", "foo;\nbar;"),
1240            ("foo\n\n\n;bar;\n\n", "foo;\nbar;"),
1241        ];
1242        let options = FormatOptions::default();
1243        for (input, output) in &strings {
1244            assert_eq!(&format(input, &QueryParams::None, &options), output);
1245        }
1246
1247        let input = indoc!(
1248            "
1249            SELECT count(*),Column1 FROM Table1;
1250            SELECT count(*),Column1 FROM Table2;"
1251        );
1252        let options = FormatOptions::default();
1253        let expected = indoc!(
1254            "
1255            SELECT
1256              count(*),
1257              Column1
1258            FROM
1259              Table1;
1260            SELECT
1261              count(*),
1262              Column1
1263            FROM
1264              Table2;"
1265        );
1266
1267        assert_eq!(format(input, &QueryParams::None, &options), expected);
1268    }
1269
1270    #[test]
1271    fn it_formats_unicode_correctly() {
1272        let input = "SELECT test, тест FROM table;";
1273        let options = FormatOptions::default();
1274        let expected = indoc!(
1275            "
1276            SELECT
1277              test,
1278              тест
1279            FROM
1280              table;"
1281        );
1282
1283        assert_eq!(format(input, &QueryParams::None, &options), expected);
1284    }
1285
1286    #[test]
1287    fn it_converts_keywords_to_uppercase_when_option_passed_in() {
1288        let input = "select distinct * frOM foo left join bar WHERe cola > 1 and colb = 3";
1289        let options = FormatOptions {
1290            uppercase: Some(true),
1291            ..FormatOptions::default()
1292        };
1293        let expected = indoc!(
1294            "
1295            SELECT DISTINCT
1296              *
1297            FROM
1298              foo
1299              LEFT JOIN bar
1300            WHERE
1301              cola > 1
1302              AND colb = 3"
1303        );
1304
1305        assert_eq!(format(input, &QueryParams::None, &options), expected);
1306    }
1307
1308    #[test]
1309    fn it_line_breaks_between_queries_with_config() {
1310        let input = "SELECT * FROM foo; SELECT * FROM bar;";
1311        let options = FormatOptions {
1312            lines_between_queries: 2,
1313            ..FormatOptions::default()
1314        };
1315        let expected = indoc!(
1316            "
1317            SELECT
1318              *
1319            FROM
1320              foo;
1321
1322            SELECT
1323              *
1324            FROM
1325              bar;"
1326        );
1327
1328        assert_eq!(format(input, &QueryParams::None, &options), expected);
1329    }
1330
1331    #[test]
1332    fn it_correctly_indents_create_statement_after_select() {
1333        let input = indoc!(
1334            "
1335            SELECT * FROM test;
1336            CREATE TABLE TEST(id NUMBER NOT NULL, col1 VARCHAR2(20), col2 VARCHAR2(20));
1337        "
1338        );
1339        let options = FormatOptions::default();
1340        let expected = indoc!(
1341            "
1342            SELECT
1343              *
1344            FROM
1345              test;
1346            CREATE TABLE TEST(
1347              id NUMBER NOT NULL,
1348              col1 VARCHAR2(20),
1349              col2 VARCHAR2(20)
1350            );"
1351        );
1352
1353        assert_eq!(format(input, &QueryParams::None, &options), expected);
1354    }
1355
1356    #[test]
1357    fn it_formats_short_create_table() {
1358        let input = "CREATE TABLE items (a INT PRIMARY KEY, b TEXT);";
1359        let options = FormatOptions::default();
1360
1361        assert_eq!(format(input, &QueryParams::None, &options), input);
1362    }
1363
1364    #[test]
1365    fn it_formats_long_create_table() {
1366        let input =
1367            "CREATE TABLE items (a INT PRIMARY KEY, b TEXT, c INT NOT NULL, d INT NOT NULL);";
1368        let options = FormatOptions::default();
1369        let expected = indoc!(
1370            "
1371            CREATE TABLE items (
1372              a INT PRIMARY KEY,
1373              b TEXT,
1374              c INT NOT NULL,
1375              d INT NOT NULL
1376            );"
1377        );
1378
1379        assert_eq!(format(input, &QueryParams::None, &options), expected);
1380    }
1381
1382    #[test]
1383    fn it_formats_insert_without_into() {
1384        let input =
1385            "INSERT Customers (ID, MoneyBalance, Address, City) VALUES (12,-123.4, 'Skagen 2111','Stv');";
1386        let options = FormatOptions::default();
1387        let expected = indoc!(
1388            "
1389            INSERT
1390              Customers (ID, MoneyBalance, Address, City)
1391            VALUES
1392              (12, -123.4, 'Skagen 2111', 'Stv');"
1393        );
1394
1395        assert_eq!(format(input, &QueryParams::None, &options), expected);
1396    }
1397
1398    #[test]
1399    fn it_formats_alter_table_modify_query() {
1400        let input = "ALTER TABLE supplier MODIFY supplier_name char(100) NOT NULL;";
1401        let options = FormatOptions::default();
1402        let expected = indoc!(
1403            "
1404            ALTER TABLE
1405              supplier
1406            MODIFY
1407              supplier_name char(100) NOT NULL;"
1408        );
1409
1410        assert_eq!(format(input, &QueryParams::None, &options), expected);
1411    }
1412
1413    #[test]
1414    fn it_formats_alter_table_alter_column_query() {
1415        let input = "ALTER TABLE supplier ALTER COLUMN supplier_name VARCHAR(100) NOT NULL;";
1416        let options = FormatOptions::default();
1417        let expected = indoc!(
1418            "
1419            ALTER TABLE
1420              supplier
1421            ALTER COLUMN
1422              supplier_name VARCHAR(100) NOT NULL;"
1423        );
1424
1425        assert_eq!(format(input, &QueryParams::None, &options), expected);
1426    }
1427
1428    #[test]
1429    fn it_recognizes_bracketed_strings() {
1430        let inputs = ["[foo JOIN bar]", "[foo ]] JOIN bar]"];
1431        let options = FormatOptions {
1432            dialect: Dialect::SQLServer,
1433            ..Default::default()
1434        };
1435        for input in &inputs {
1436            assert_eq!(&format(input, &QueryParams::None, &options), input);
1437        }
1438    }
1439
1440    #[test]
1441    fn it_recognizes_at_variables() {
1442        let input =
1443            "SELECT @variable, @a1_2.3$, @'var name', @\"var name\", @`var name`, @[var name];";
1444        let options = FormatOptions {
1445            dialect: Dialect::SQLServer,
1446            ..Default::default()
1447        };
1448        let expected = indoc!(
1449            "
1450            SELECT
1451              @variable,
1452              @a1_2.3$,
1453              @'var name',
1454              @\"var name\",
1455              @`var name`,
1456              @[var name];"
1457        );
1458
1459        assert_eq!(format(input, &QueryParams::None, &options), expected);
1460    }
1461
1462    #[test]
1463    fn it_recognizes_at_variables_with_param_values() {
1464        let input =
1465            "SELECT @variable, @a1_2.3$, @'var name', @\"var name\", @`var name`, @[var name], @'var\\name';";
1466        let params = vec![
1467            ("variable".to_string(), "\"variable value\"".to_string()),
1468            ("a1_2.3$".to_string(), "'weird value'".to_string()),
1469            ("var name".to_string(), "'var value'".to_string()),
1470            ("var\\name".to_string(), "'var\\ value'".to_string()),
1471        ];
1472        let options = FormatOptions {
1473            dialect: Dialect::SQLServer,
1474            ..Default::default()
1475        };
1476        let expected = indoc!(
1477            "
1478            SELECT
1479              \"variable value\",
1480              'weird value',
1481              'var value',
1482              'var value',
1483              'var value',
1484              'var value',
1485              'var\\ value';"
1486        );
1487
1488        assert_eq!(
1489            format(input, &QueryParams::Named(params), &options),
1490            expected
1491        );
1492    }
1493
1494    #[test]
1495    fn it_recognizes_colon_variables() {
1496        let input =
1497            "SELECT :variable, :a1_2.3$, :'var name', :\"var name\", :`var name`, :[var name];";
1498        let options = FormatOptions {
1499            dialect: Dialect::SQLServer,
1500            ..Default::default()
1501        };
1502        let expected = indoc!(
1503            "
1504            SELECT
1505              :variable,
1506              :a1_2.3$,
1507              :'var name',
1508              :\"var name\",
1509              :`var name`,
1510              :[var name];"
1511        );
1512
1513        assert_eq!(format(input, &QueryParams::None, &options), expected);
1514    }
1515
1516    #[test]
1517    fn it_recognizes_colon_variables_with_param_values() {
1518        let input = indoc!(
1519            "
1520            SELECT :variable, :a1_2.3$, :'var name', :\"var name\", :`var name`,
1521            :[var name], :'escaped \\'var\\'', :\"^*& weird \\\" var   \";
1522            "
1523        );
1524        let params = vec![
1525            ("variable".to_string(), "\"variable value\"".to_string()),
1526            ("a1_2.3$".to_string(), "'weird value'".to_string()),
1527            ("var name".to_string(), "'var value'".to_string()),
1528            ("escaped 'var'".to_string(), "'weirder value'".to_string()),
1529            (
1530                "^*& weird \" var   ".to_string(),
1531                "'super weird value'".to_string(),
1532            ),
1533        ];
1534        let options = FormatOptions {
1535            dialect: Dialect::SQLServer,
1536            ..Default::default()
1537        };
1538        let expected = indoc!(
1539            "
1540            SELECT
1541              \"variable value\",
1542              'weird value',
1543              'var value',
1544              'var value',
1545              'var value',
1546              'var value',
1547              'weirder value',
1548              'super weird value';"
1549        );
1550
1551        assert_eq!(
1552            format(input, &QueryParams::Named(params), &options),
1553            expected
1554        );
1555    }
1556
1557    #[test]
1558    fn it_recognizes_question_numbered_placeholders() {
1559        let input = "SELECT ?1, ?25, ?;";
1560        let options = FormatOptions::default();
1561        let expected = indoc!(
1562            "
1563            SELECT
1564              ?1,
1565              ?25,
1566              ?;"
1567        );
1568
1569        assert_eq!(format(input, &QueryParams::None, &options), expected);
1570    }
1571
1572    #[test]
1573    fn it_recognizes_question_numbered_placeholders_with_param_values() {
1574        let input = "SELECT ?1, ?2, ?0;";
1575        let params = vec![
1576            "first".to_string(),
1577            "second".to_string(),
1578            "third".to_string(),
1579        ];
1580        let options = FormatOptions::default();
1581        let expected = indoc!(
1582            "
1583            SELECT
1584              second,
1585              third,
1586              first;"
1587        );
1588
1589        assert_eq!(
1590            format(input, &QueryParams::Indexed(params), &options),
1591            expected
1592        );
1593
1594        format("?62666666121266666612", &QueryParams::None, &options);
1595    }
1596
1597    #[test]
1598    fn it_recognizes_question_indexed_placeholders_with_param_values() {
1599        let input = "SELECT ?, ?, ?;";
1600        let params = vec![
1601            "first".to_string(),
1602            "second".to_string(),
1603            "third".to_string(),
1604        ];
1605        let options = FormatOptions::default();
1606        let expected = indoc!(
1607            "
1608            SELECT
1609              first,
1610              second,
1611              third;"
1612        );
1613
1614        assert_eq!(
1615            format(input, &QueryParams::Indexed(params), &options),
1616            expected
1617        );
1618    }
1619
1620    #[test]
1621    fn it_recognizes_dollar_sign_numbered_placeholders() {
1622        let input = "SELECT $1, $2;";
1623        let options = FormatOptions::default();
1624        let expected = indoc!(
1625            "
1626            SELECT
1627              $1,
1628              $2;"
1629        );
1630
1631        assert_eq!(format(input, &QueryParams::None, &options), expected);
1632    }
1633
1634    #[test]
1635    fn it_recognizes_dollar_sign_alphanumeric_placeholders() {
1636        let input = "SELECT $hash, $foo, $bar;";
1637        let options = FormatOptions::default();
1638        let expected = indoc!(
1639            "
1640            SELECT
1641              $hash,
1642              $foo,
1643              $bar;"
1644        );
1645
1646        assert_eq!(format(input, &QueryParams::None, &options), expected);
1647    }
1648
1649    #[test]
1650    fn it_recognizes_dollar_sign_numbered_placeholders_with_param_values() {
1651        let input = "SELECT $2, $3, $1, $named, $4, $alias;";
1652        let params = vec![
1653            "first".to_string(),
1654            "second".to_string(),
1655            "third".to_string(),
1656            "4th".to_string(),
1657        ];
1658        let options = FormatOptions::default();
1659        let expected = indoc!(
1660            "
1661            SELECT
1662              second,
1663              third,
1664              first,
1665              $named,
1666              4th,
1667              $alias;"
1668        );
1669
1670        assert_eq!(
1671            format(input, &QueryParams::Indexed(params), &options),
1672            expected
1673        );
1674    }
1675
1676    #[test]
1677    fn it_recognizes_dollar_sign_alphanumeric_placeholders_with_param_values() {
1678        let input = "SELECT $hash, $salt, $1, $2;";
1679        let params = vec![
1680            ("hash".to_string(), "hash value".to_string()),
1681            ("salt".to_string(), "salt value".to_string()),
1682            ("1".to_string(), "number 1".to_string()),
1683            ("2".to_string(), "number 2".to_string()),
1684        ];
1685        let options = FormatOptions::default();
1686        let expected = indoc!(
1687            "
1688            SELECT
1689              hash value,
1690              salt value,
1691              number 1,
1692              number 2;"
1693        );
1694
1695        assert_eq!(
1696            format(input, &QueryParams::Named(params), &options),
1697            expected
1698        );
1699    }
1700
1701    #[test]
1702    fn it_formats_query_with_go_batch_separator() {
1703        let input = "SELECT 1 GO SELECT 2";
1704        let params = vec![
1705            "first".to_string(),
1706            "second".to_string(),
1707            "third".to_string(),
1708        ];
1709        let options = FormatOptions::default();
1710        let expected = indoc!(
1711            "
1712            SELECT
1713              1
1714            GO
1715            SELECT
1716              2"
1717        );
1718
1719        assert_eq!(
1720            format(input, &QueryParams::Indexed(params), &options),
1721            expected
1722        );
1723    }
1724
1725    #[test]
1726    fn it_formats_select_query_with_cross_join() {
1727        let input = "SELECT a, b FROM t CROSS JOIN t2 on t.id = t2.id_t";
1728        let options = FormatOptions::default();
1729        let expected = indoc!(
1730            "
1731            SELECT
1732              a,
1733              b
1734            FROM
1735              t
1736              CROSS JOIN t2 on t.id = t2.id_t"
1737        );
1738
1739        assert_eq!(format(input, &QueryParams::None, &options), expected);
1740    }
1741
1742    #[test]
1743    fn it_formats_select_query_with_cross_apply() {
1744        let input = "SELECT a, b FROM t CROSS APPLY fn(t.id)";
1745        let options = FormatOptions::default();
1746        let expected = indoc!(
1747            "
1748            SELECT
1749              a,
1750              b
1751            FROM
1752              t
1753              CROSS APPLY fn(t.id)"
1754        );
1755
1756        assert_eq!(format(input, &QueryParams::None, &options), expected);
1757    }
1758
1759    #[test]
1760    fn it_formats_simple_select() {
1761        let input = "SELECT N, M FROM t";
1762        let options = FormatOptions::default();
1763        let expected = indoc!(
1764            "
1765            SELECT
1766              N,
1767              M
1768            FROM
1769              t"
1770        );
1771
1772        assert_eq!(format(input, &QueryParams::None, &options), expected);
1773    }
1774
1775    #[test]
1776    fn it_formats_simple_select_with_national_characters_mssql() {
1777        let input = "SELECT N'value'";
1778        let options = FormatOptions::default();
1779        let expected = indoc!(
1780            "
1781            SELECT
1782              N'value'"
1783        );
1784
1785        assert_eq!(format(input, &QueryParams::None, &options), expected);
1786    }
1787
1788    #[test]
1789    fn it_formats_select_query_with_outer_apply() {
1790        let input = "SELECT a, b FROM t OUTER APPLY fn(t.id)";
1791        let options = FormatOptions::default();
1792        let expected = indoc!(
1793            "
1794            SELECT
1795              a,
1796              b
1797            FROM
1798              t
1799              OUTER APPLY fn(t.id)"
1800        );
1801
1802        assert_eq!(format(input, &QueryParams::None, &options), expected);
1803    }
1804
1805    #[test]
1806    fn it_formats_fetch_first_like_limit() {
1807        let input = "SELECT * FETCH FIRST 2 ROWS ONLY;";
1808        let options = FormatOptions::default();
1809        let expected = indoc!(
1810            "
1811            SELECT
1812              *
1813            FETCH FIRST
1814              2 ROWS ONLY;"
1815        );
1816
1817        assert_eq!(format(input, &QueryParams::None, &options), expected);
1818    }
1819
1820    #[test]
1821    fn it_formats_case_when_with_a_blank_expression() {
1822        let input = "CASE WHEN option = 'foo' THEN 1 WHEN option = 'bar' THEN 2 WHEN option = 'baz' THEN 3 ELSE 4 END;";
1823        let options = FormatOptions::default();
1824        let expected = indoc!(
1825            "
1826            CASE
1827              WHEN option = 'foo' THEN 1
1828              WHEN option = 'bar' THEN 2
1829              WHEN option = 'baz' THEN 3
1830              ELSE 4
1831            END;"
1832        );
1833
1834        assert_eq!(format(input, &QueryParams::None, &options), expected);
1835    }
1836
1837    #[test]
1838    fn it_formats_case_when_inside_select() {
1839        let input =
1840            "SELECT foo, bar, CASE baz WHEN 'one' THEN 1 WHEN 'two' THEN 2 ELSE 3 END FROM table";
1841        let options = FormatOptions::default();
1842        let expected = indoc!(
1843            "
1844            SELECT
1845              foo,
1846              bar,
1847              CASE
1848                baz
1849                WHEN 'one' THEN 1
1850                WHEN 'two' THEN 2
1851                ELSE 3
1852              END
1853            FROM
1854              table"
1855        );
1856
1857        assert_eq!(format(input, &QueryParams::None, &options), expected);
1858    }
1859
1860    #[test]
1861    fn it_formats_case_when_inside_select_inlined_top_level() {
1862        let input =
1863            "SELECT foo, bar, CASE baz WHEN 'one' THEN 1 WHEN 'two' THEN 2 ELSE 3 END FROM table";
1864        let options = FormatOptions {
1865            max_inline_top_level: Some(50),
1866            ..Default::default()
1867        };
1868        let expected = indoc!(
1869            "
1870            SELECT
1871              foo,
1872              bar,
1873              CASE
1874                baz
1875                WHEN 'one' THEN 1
1876                WHEN 'two' THEN 2
1877                ELSE 3
1878              END
1879            FROM table"
1880        );
1881
1882        assert_eq!(format(input, &QueryParams::None, &options), expected);
1883    }
1884
1885    #[test]
1886    fn it_formats_case_when_with_an_expression() {
1887        let input = "CASE toString(getNumber()) WHEN 'one' THEN 1 WHEN 'two' THEN 2 WHEN 'three' THEN 3 ELSE 4 END;";
1888        let options = FormatOptions::default();
1889        let expected = indoc!(
1890            "
1891            CASE
1892              toString(getNumber())
1893              WHEN 'one' THEN 1
1894              WHEN 'two' THEN 2
1895              WHEN 'three' THEN 3
1896              ELSE 4
1897            END;"
1898        );
1899
1900        assert_eq!(format(input, &QueryParams::None, &options), expected);
1901    }
1902
1903    #[test]
1904    fn it_formats_case_when_inside_an_order_by() {
1905        let input = "SELECT a, created_at FROM b ORDER BY (CASE $3 WHEN 'created_at_asc' THEN created_at END) ASC, (CASE $3 WHEN 'created_at_desc' THEN created_at END) DESC;";
1906        let max_line = 80;
1907        let options = FormatOptions {
1908            max_inline_block: max_line,
1909            max_inline_arguments: Some(max_line),
1910            ..Default::default()
1911        };
1912
1913        let expected = indoc!(
1914            "
1915            SELECT
1916              a, created_at
1917            FROM
1918              b
1919            ORDER BY
1920              (CASE $3 WHEN 'created_at_asc' THEN created_at END) ASC,
1921              (CASE $3 WHEN 'created_at_desc' THEN created_at END) DESC;"
1922        );
1923
1924        assert_eq!(format(input, &QueryParams::None, &options), expected);
1925    }
1926
1927    #[test]
1928    fn it_recognizes_lowercase_case_end() {
1929        let input = "case when option = 'foo' then 1 else 2 end;";
1930        let options = FormatOptions::default();
1931        let expected = indoc!(
1932            "
1933            case
1934              when option = 'foo' then 1
1935              else 2
1936            end;"
1937        );
1938
1939        assert_eq!(format(input, &QueryParams::None, &options), expected);
1940    }
1941
1942    #[test]
1943    fn it_ignores_words_case_and_end_inside_other_strings() {
1944        let input = "SELECT CASEDATE, ENDDATE FROM table1;";
1945        let options = FormatOptions::default();
1946        let expected = indoc!(
1947            "
1948            SELECT
1949              CASEDATE,
1950              ENDDATE
1951            FROM
1952              table1;"
1953        );
1954
1955        assert_eq!(format(input, &QueryParams::None, &options), expected);
1956    }
1957
1958    #[test]
1959    fn it_formats_tricky_line_comments() {
1960        let input = "SELECT a#comment, here\nFROM b--comment";
1961        let options = FormatOptions::default();
1962        let expected = indoc!(
1963            "
1964            SELECT
1965              a #comment, here
1966            FROM
1967              b --comment"
1968        );
1969
1970        assert_eq!(format(input, &QueryParams::None, &options), expected);
1971    }
1972
1973    #[test]
1974    fn it_formats_line_comments_followed_by_semicolon() {
1975        let input = indoc!(
1976            "
1977            SELECT a FROM b
1978            --comment
1979            ;"
1980        );
1981        let options = FormatOptions::default();
1982        let expected = indoc!(
1983            "
1984            SELECT
1985              a
1986            FROM
1987              b --comment
1988            ;"
1989        );
1990
1991        assert_eq!(format(input, &QueryParams::None, &options), expected);
1992    }
1993
1994    #[test]
1995    fn it_formats_line_comments_followed_by_comma() {
1996        let input = indoc!(
1997            "
1998            SELECT a --comment
1999            , b"
2000        );
2001        let options = FormatOptions::default();
2002        let expected = indoc!(
2003            "
2004            SELECT
2005              a --comment
2006            ,
2007              b"
2008        );
2009
2010        assert_eq!(format(input, &QueryParams::None, &options), expected);
2011    }
2012
2013    #[test]
2014    fn it_formats_line_comments_followed_by_close_paren() {
2015        let input = "SELECT ( a --comment\n )";
2016        let options = FormatOptions::default();
2017        let expected = indoc!(
2018            "
2019            SELECT
2020              (
2021                a --comment
2022              )"
2023        );
2024
2025        assert_eq!(format(input, &QueryParams::None, &options), expected);
2026    }
2027
2028    #[test]
2029    fn it_formats_line_comments_followed_by_open_paren() {
2030        let input = "SELECT a --comment\n()";
2031        let options = FormatOptions::default();
2032        let expected = indoc!(
2033            "
2034            SELECT
2035              a --comment
2036              ()"
2037        );
2038
2039        assert_eq!(format(input, &QueryParams::None, &options), expected);
2040    }
2041
2042    #[test]
2043    fn it_formats_lonely_semicolon() {
2044        let input = ";";
2045        let options = FormatOptions::default();
2046
2047        assert_eq!(format(input, &QueryParams::None, &options), input);
2048    }
2049
2050    #[test]
2051    fn it_formats_multibyte_chars() {
2052        let input = "\nSELECT 'главная'";
2053        let options = FormatOptions::default();
2054        let expected = "SELECT\n  'главная'";
2055
2056        assert_eq!(format(input, &QueryParams::None, &options), expected);
2057    }
2058
2059    #[test]
2060    fn it_recognizes_scientific_notation() {
2061        let input = "SELECT *, 1e-7 as small, 1e2 as medium, 1e+7 as large FROM t";
2062        let options = FormatOptions::default();
2063        let expected = indoc!(
2064            "
2065            SELECT
2066              *,
2067              1e-7 as small,
2068              1e2 as medium,
2069              1e+7 as large
2070            FROM
2071              t"
2072        );
2073
2074        assert_eq!(format(input, &QueryParams::None, &options), expected);
2075    }
2076
2077    #[test]
2078    fn it_keeps_double_dollar_signs_together() {
2079        let input = "CREATE FUNCTION abc() AS $$ SELECT * FROM table $$ LANGUAGE plpgsql;";
2080        let options = FormatOptions::default();
2081        let expected = indoc!(
2082            "
2083            CREATE FUNCTION abc() AS
2084            $$
2085            SELECT
2086              *
2087            FROM
2088              table
2089            $$
2090            LANGUAGE plpgsql;"
2091        );
2092
2093        assert_eq!(format(input, &QueryParams::None, &options), expected);
2094    }
2095
2096    #[test]
2097    fn it_formats_pgplsql() {
2098        let input = "CREATE FUNCTION abc() AS $$ DECLARE a int := 1; b int := 2; BEGIN SELECT * FROM table $$ LANGUAGE plpgsql;";
2099        let options = FormatOptions::default();
2100        let expected = indoc!(
2101            "
2102            CREATE FUNCTION abc() AS
2103            $$
2104            DECLARE
2105            a int := 1;
2106            b int := 2;
2107            BEGIN
2108            SELECT
2109              *
2110            FROM
2111              table
2112            $$
2113            LANGUAGE plpgsql;"
2114        );
2115
2116        assert_eq!(format(input, &QueryParams::None, &options), expected);
2117    }
2118
2119    #[test]
2120    fn it_handles_comments_correctly() {
2121        let input = indoc!(
2122            "
2123                -- 创建一个外部表,存储销售数据
2124            CREATE EXTERNAL TABLE IF NOT EXISTS sales_data (
2125                -- 唯一标识订单ID
2126                order_id BIGINT COMMENT 'Unique identifier for the order',
2127
2128                -- 客户ID
2129                customer_id BIGINT COMMENT 'Unique identifier for the customer',
2130            )
2131            COMMENT 'Sales data table for storing transaction records';
2132
2133            -- 按销售日期和城市进行分区
2134            PARTITIONED BY (
2135                sale_year STRING COMMENT 'Year of the sale',
2136                sale_month STRING COMMENT 'Month of the sale'
2137            )
2138
2139            -- 设置数据存储位置
2140            LOCATION '/user/hive/warehouse/sales_data'
2141
2142            -- 使用 ORC 存储格式
2143            STORED AS ORC
2144
2145            -- 设置表的行格式
2146            ROW FORMAT DELIMITED
2147            FIELDS TERMINATED BY ','
2148            LINES TERMINATED BY '\n'
2149
2150            -- 设置表属性
2151            TBLPROPERTIES (
2152                'orc.compress' = 'SNAPPY',          -- 使用SNAPPY压缩
2153                'transactional' = 'true',           -- 启用事务支持
2154                'orc.create.index' = 'true',        -- 创建索引
2155                'skip.header.line.count' = '1',     -- 跳过CSV文件的第一行
2156                'external.table.purge' = 'true'     -- 在删除表时自动清理数据
2157            );
2158
2159            -- 自动加载数据到 Hive 分区中
2160            ALTER TABLE sales_data
2161            ADD PARTITION (sale_year = '2024', sale_month = '08')
2162            LOCATION '/user/hive/warehouse/sales_data/2024/08';"
2163        );
2164        let options = FormatOptions {
2165            indent: Indent::Spaces(4),
2166            ..Default::default()
2167        };
2168        let expected = indoc!(
2169            "
2170            -- 创建一个外部表,存储销售数据
2171            CREATE EXTERNAL TABLE IF NOT EXISTS sales_data (
2172                -- 唯一标识订单ID
2173                order_id BIGINT COMMENT 'Unique identifier for the order',
2174                -- 客户ID
2175                customer_id BIGINT COMMENT 'Unique identifier for the customer',
2176            ) COMMENT 'Sales data table for storing transaction records';
2177            -- 按销售日期和城市进行分区
2178            PARTITIONED BY (
2179                sale_year STRING COMMENT 'Year of the sale',
2180                sale_month STRING COMMENT 'Month of the sale'
2181            )
2182            -- 设置数据存储位置
2183            LOCATION '/user/hive/warehouse/sales_data'
2184            -- 使用 ORC 存储格式
2185            STORED AS ORC
2186            -- 设置表的行格式
2187            ROW FORMAT DELIMITED FIELDS TERMINATED BY ',' LINES TERMINATED BY '\n'
2188            -- 设置表属性
2189            TBLPROPERTIES (
2190                'orc.compress' = 'SNAPPY',  -- 使用SNAPPY压缩
2191                'transactional' = 'true',  -- 启用事务支持
2192                'orc.create.index' = 'true',  -- 创建索引
2193                'skip.header.line.count' = '1',  -- 跳过CSV文件的第一行
2194                'external.table.purge' = 'true' -- 在删除表时自动清理数据
2195            );
2196            -- 自动加载数据到 Hive 分区中
2197            ALTER TABLE
2198                sales_data
2199            ADD
2200                PARTITION (sale_year = '2024', sale_month = '08') LOCATION '/user/hive/warehouse/sales_data/2024/08';"
2201        );
2202
2203        assert_eq!(format(input, &QueryParams::None, &options), expected);
2204    }
2205
2206    #[test]
2207    fn it_recognizes_returning_clause() {
2208        let input = indoc!(
2209            "
2210          INSERT INTO
2211            users (name, email)
2212          VALUES
2213            ($1, $2) RETURNING name,
2214            email"
2215        );
2216        let options = FormatOptions::default();
2217        let expected = indoc!(
2218            "
2219          INSERT INTO
2220            users (name, email)
2221          VALUES
2222            ($1, $2)
2223          RETURNING
2224            name,
2225            email"
2226        );
2227
2228        assert_eq!(format(input, &QueryParams::None, &options), expected);
2229    }
2230
2231    #[test]
2232    fn it_recognizes_on_update_clause() {
2233        let input = indoc!(
2234            "CREATE TABLE a (b integer REFERENCES c (id) ON                                     UPDATE RESTRICT, other integer);"
2235        );
2236        let options = FormatOptions::default();
2237        let expected = indoc!(
2238            "
2239          CREATE TABLE a (
2240            b integer REFERENCES c (id) ON UPDATE RESTRICT,
2241            other integer
2242          );"
2243        );
2244        assert_eq!(format(input, &QueryParams::None, &options), expected);
2245    }
2246
2247    #[test]
2248    fn it_formats_except_on_columns() {
2249        let input = indoc!(
2250            "SELECT table_0.* EXCEPT (profit),
2251                    details.* EXCEPT (item_id),
2252                    table_0.profit
2253        FROM  table_0"
2254        );
2255        let options = FormatOptions {
2256            indent: Indent::Spaces(4),
2257            ..Default::default()
2258        };
2259        let expected = indoc!(
2260            "
2261            SELECT
2262                table_0.* EXCEPT (profit),
2263                details.* EXCEPT (item_id),
2264                table_0.profit
2265            FROM
2266                table_0"
2267        );
2268
2269        assert_eq!(format(input, &QueryParams::None, &options), expected);
2270    }
2271
2272    #[test]
2273    fn it_uses_given_ignore_case_convert_config() {
2274        let input = "select count(*),Column1 from Table1;";
2275        let options = FormatOptions {
2276            uppercase: Some(true),
2277            ignore_case_convert: Some(vec!["from"]),
2278            ..FormatOptions::default()
2279        };
2280        let expected = indoc!(
2281            "
2282            SELECT
2283              count(*),
2284              Column1
2285            from
2286              Table1;"
2287        );
2288
2289        assert_eq!(format(input, &QueryParams::None, &options), expected);
2290    }
2291
2292    #[test]
2293    fn it_recognizes_fmt_off() {
2294        let input = indoc!(
2295            "SELECT              *     FROM   sometable
2296            WHERE
2297            -- comment test here
2298                 -- fmt: off
2299                first_key.second_key = 1
2300                                -- json:first_key.second_key = 1
2301                      -- fmt: on
2302                AND
2303                   -- fm1t: off
2304                first_key.second_key = 1
2305                                    --  json:first_key.second_key = 1
2306                -- fmt:on"
2307        );
2308        let options = FormatOptions {
2309            indent: Indent::Spaces(4),
2310            ..Default::default()
2311        };
2312        let expected = indoc!(
2313            "
2314            SELECT
2315                *
2316            FROM
2317                sometable
2318            WHERE
2319                -- comment test here
2320                first_key.second_key = 1
2321                                -- json:first_key.second_key = 1
2322                AND
2323                -- fm1t: off
2324                first_key.second_key = 1
2325                --  json:first_key.second_key = 1"
2326        );
2327
2328        assert_eq!(format(input, &QueryParams::None, &options), expected);
2329    }
2330
2331    #[test]
2332    fn it_converts_keywords_to_lowercase_when_option_passed_in() {
2333        let input = "select distinct * frOM foo left join bar WHERe cola > 1 and colb = 3";
2334        let options = FormatOptions {
2335            uppercase: Some(false),
2336            ..FormatOptions::default()
2337        };
2338        let expected = indoc!(
2339            "
2340            select distinct
2341              *
2342            from
2343              foo
2344              left join bar
2345            where
2346              cola > 1
2347              and colb = 3"
2348        );
2349
2350        assert_eq!(format(input, &QueryParams::None, &options), expected);
2351    }
2352
2353    #[test]
2354    fn format_nested_select() {
2355        let input = "WITH a AS ( SELECT a, b, c FROM t WHERE a > 100 ), aa AS ( SELECT field FROM table ) SELECT b, field FROM a, aa;";
2356        let options = FormatOptions {
2357            max_inline_arguments: Some(10),
2358            max_inline_top_level: Some(9),
2359            ..Default::default()
2360        };
2361        let expected = indoc! {
2362            "
2363            WITH
2364            a AS (
2365              SELECT a, b, c
2366              FROM t
2367              WHERE a > 100
2368            ),
2369            aa AS (
2370              SELECT field
2371              FROM table
2372            )
2373            SELECT
2374              b, field
2375            FROM a, aa;"
2376        };
2377        assert_eq!(format(input, &QueryParams::None, &options), expected);
2378    }
2379
2380    #[test]
2381    fn format_short_with() {
2382        let input = "WITH a AS ( SELECT a, b, c FROM t WHERE a > 100 ) SELECT b, field FROM a, aa;";
2383        let max_line = 80;
2384        let options = FormatOptions {
2385            max_inline_block: max_line,
2386            max_inline_arguments: Some(max_line),
2387            max_inline_top_level: Some(max_line),
2388            joins_as_top_level: true,
2389            ..Default::default()
2390        };
2391        let expected = indoc! {
2392            "
2393            WITH a AS (SELECT a, b, c FROM t WHERE a > 100)
2394            SELECT b, field
2395            FROM a, aa;"
2396        };
2397        assert_eq!(format(input, &QueryParams::None, &options), expected);
2398    }
2399
2400    #[test]
2401    fn format_nested_select_nested_blocks() {
2402        let input =
2403            "WITH a AS ( SELECT a, b, c FROM t WHERE a > 100 ), aa AS ( SELECT field FROM table ),
2404            bb AS ( SELECT count(*) as c FROM d ), cc AS ( INSERT INTO C (a, b, c, d) VALUES (1 ,2 ,3 ,4) )
2405        SELECT b, field FROM a, aa;";
2406        let max_line = 20;
2407        let options = FormatOptions {
2408            max_inline_block: max_line,
2409            max_inline_arguments: Some(max_line),
2410            max_inline_top_level: Some(max_line / 2),
2411            joins_as_top_level: true,
2412            ..Default::default()
2413        };
2414        let expected = indoc! {
2415            "
2416            WITH
2417            a AS (
2418              SELECT a, b, c
2419              FROM t
2420              WHERE a > 100
2421            ),
2422            aa AS (
2423              SELECT field
2424              FROM table
2425            ),
2426            bb AS (
2427              SELECT
2428                count(*) as c
2429              FROM d
2430            ),
2431            cc AS (
2432              INSERT INTO
2433                C (a, b, c, d)
2434              VALUES
2435                (1, 2, 3, 4)
2436            )
2437            SELECT b, field
2438            FROM a, aa;"
2439        };
2440        assert_eq!(format(input, &QueryParams::None, &options), expected);
2441    }
2442
2443    #[test]
2444    fn it_converts_keywords_nothing_when_no_option_passed_in() {
2445        let input = "select distinct * frOM foo left join bar WHERe cola > 1 and colb = 3";
2446        let options = FormatOptions {
2447            uppercase: None,
2448            ..FormatOptions::default()
2449        };
2450        let expected = indoc!(
2451            "
2452            select distinct
2453              *
2454            frOM
2455              foo
2456              left join bar
2457            WHERe
2458              cola > 1
2459              and colb = 3"
2460        );
2461
2462        assert_eq!(format(input, &QueryParams::None, &options), expected);
2463    }
2464    #[test]
2465    fn it_correctly_parses_all_operators() {
2466        let operators = [
2467            "!!", "!~~*", "!~~", "!~*", "!~", "##", "#>>", "#>", "#-", "&<|", "&<", "&>", "&&",
2468            "*<>", "*<=", "*>=", "*>", "*=", "*<", "<<|", "<<=", "<<", "<->", "<@", "<^", "<=",
2469            "<>", "<", ">=", ">>=", ">>", ">^", "->>", "->", "-|-", "-", "+", "/", "=", "%", "?||",
2470            "?|", "?-|", "?-", "?#", "?&", "?", "@@@", "@@", "@>", "@?", "@-@", "@", "^@", "^",
2471            "|&>", "|>>", "|/", "|", "||/", "||", "~>=~", "~>~", "~<=~", "~<~", "~=", "~*", "~~*",
2472            "~~", "~", "%", "<%", "%>", "<<%", "%>>", "<<->", "<->>", "<<<->", "<->>>",
2473        ];
2474
2475        // Test each operator individually
2476        for &operator in &operators {
2477            let input = format!("left {} right", operator);
2478            let expected = format!("left {} right", operator);
2479            let options = FormatOptions {
2480                uppercase: None,
2481                ..FormatOptions::default()
2482            };
2483
2484            assert_eq!(
2485                format(&input, &QueryParams::None, &options),
2486                expected,
2487                "Failed to parse operator: {}",
2488                operator
2489            );
2490        }
2491    }
2492    #[test]
2493    fn it_correctly_splits_operators() {
2494        let input = "
2495  SELECT
2496  left <@ right,
2497  left << right,
2498  left >> right,
2499  left &< right,
2500  left &> right,
2501  left -|- right,
2502  @@ left,
2503  @-@ left,
2504  left <-> right,
2505  left <<| right,
2506  left |>> right,
2507  left &<| right,
2508  left |>& right,
2509  left <^ right,
2510  left >^ right,
2511  left <% right,
2512  left %> right,
2513  ?- left,
2514  left ?-| right,
2515  left ?|| right,
2516  left ~= right";
2517        let options = FormatOptions {
2518            uppercase: None,
2519            ..FormatOptions::default()
2520        };
2521        let expected = indoc!(
2522            "
2523SELECT
2524  left <@ right,
2525  left << right,
2526  left >> right,
2527  left &< right,
2528  left &> right,
2529  left -|- right,
2530  @@ left,
2531  @-@ left,
2532  left <-> right,
2533  left <<| right,
2534  left |>> right,
2535  left &<| right,
2536  left |>& right,
2537  left <^ right,
2538  left >^ right,
2539  left <% right,
2540  left %> right,
2541  ?- left,
2542  left ?-| right,
2543  left ?|| right,
2544  left ~= right"
2545        );
2546
2547        assert_eq!(format(input, &QueryParams::None, &options), expected);
2548    }
2549    #[test]
2550    fn it_formats_double_colons() {
2551        let input = "select text  ::  text, num::integer, data::json, (x - y)::integer  frOM foo";
2552        let options = FormatOptions {
2553            uppercase: Some(false),
2554            ..FormatOptions::default()
2555        };
2556        let expected = indoc!(
2557            "
2558select
2559  text::text,
2560  num::integer,
2561  data::json,
2562  (x - y)::integer
2563from
2564  foo"
2565        );
2566
2567        assert_eq!(format(input, &QueryParams::None, &options), expected);
2568    }
2569
2570    #[test]
2571    fn it_formats_blocks_inline_or_not() {
2572        let input = " UPDATE t
2573
2574
2575        SET o = ($5 + $6 + $7 + $8),a = CASE WHEN $2
2576            THEN NULL ELSE COALESCE($3, b) END, b = CASE WHEN $4 THEN NULL ELSE
2577            COALESCE($5, b) END, s = (SELECT true FROM bar WHERE bar.foo = $99 AND bar.foo > $100),
2578            c = CASE WHEN $6 THEN NULL ELSE COALESCE($7, c) END,
2579            d = CASE WHEN $8 THEN NULL ELSE COALESCE($9, dddddddd) + bbbbb END,
2580            e = (SELECT true FROM bar) WHERE id = $1";
2581        let options = FormatOptions {
2582            max_inline_arguments: Some(60),
2583            max_inline_block: 60,
2584            max_inline_top_level: Some(60),
2585            ..Default::default()
2586        };
2587        let expected = indoc!(
2588            "
2589          UPDATE t SET
2590            o = ($5 + $6 + $7 + $8),
2591            a = CASE WHEN $2 THEN NULL ELSE COALESCE($3, b) END,
2592            b = CASE WHEN $4 THEN NULL ELSE COALESCE($5, b) END,
2593            s = (
2594              SELECT true
2595              FROM bar
2596              WHERE bar.foo = $99
2597                AND bar.foo > $100
2598            ),
2599            c = CASE WHEN $6 THEN NULL ELSE COALESCE($7, c) END,
2600            d = CASE
2601              WHEN $8 THEN NULL
2602              ELSE COALESCE($9, dddddddd) + bbbbb
2603            END,
2604            e = (SELECT true FROM bar)
2605          WHERE id = $1"
2606        );
2607
2608        assert_eq!(format(input, &QueryParams::None, &options), expected);
2609    }
2610
2611    #[test]
2612    fn parse_union_all() {
2613        let input = "SELECT id FROM a UNION ALL SELECT id FROM b WHERE c = $12 AND f";
2614        let options = FormatOptions::default();
2615        let expected = indoc!(
2616            "
2617            SELECT
2618              id
2619            FROM
2620              a
2621            UNION ALL
2622            SELECT
2623              id
2624            FROM
2625              b
2626            WHERE
2627              c = $12
2628              AND f"
2629        );
2630        assert_eq!(format(input, &QueryParams::None, &options), expected);
2631    }
2632}