1#![type_length_limit = "99999999"]
6#![forbid(unsafe_code)]
7#![allow(clippy::manual_strip)]
9#![allow(clippy::needless_lifetimes)]
11
12mod formatter;
13mod indentation;
14mod inline_block;
15mod params;
16mod tokenizer;
17
18pub fn format(query: &str, params: &QueryParams, options: &FormatOptions) -> String {
21 let named_placeholders = matches!(params, QueryParams::Named(_));
22
23 let tokens = tokenizer::tokenize(query, named_placeholders);
24 formatter::format(&tokens, params, options)
25}
26
27#[derive(Debug, Clone)]
29pub struct FormatOptions<'a> {
30 pub indent: Indent,
34 pub uppercase: Option<bool>,
38 pub lines_between_queries: u8,
42 pub ignore_case_convert: Option<Vec<&'a str>>,
46}
47
48impl<'a> Default for FormatOptions<'a> {
49 fn default() -> Self {
50 FormatOptions {
51 indent: Indent::Spaces(2),
52 uppercase: None,
53 lines_between_queries: 1,
54 ignore_case_convert: None,
55 }
56 }
57}
58
59#[derive(Debug, Clone, Copy)]
60pub enum Indent {
61 Spaces(u8),
62 Tabs,
63}
64
65#[derive(Debug, Clone, Default)]
66pub enum QueryParams {
67 Named(Vec<(String, String)>),
68 Indexed(Vec<String>),
69 #[default]
70 None,
71}
72
73#[cfg(test)]
74mod tests {
75 use super::*;
76 use indoc::indoc;
77
78 #[test]
79 fn it_uses_given_indent_config_for_indentation() {
80 let input = "SELECT count(*),Column1 FROM Table1;";
81 let options = FormatOptions {
82 indent: Indent::Spaces(4),
83 ..FormatOptions::default()
84 };
85 let expected = indoc!(
86 "
87 SELECT
88 count(*),
89 Column1
90 FROM
91 Table1;"
92 );
93
94 assert_eq!(format(input, &QueryParams::None, &options), expected);
95 }
96
97 #[test]
98 fn it_formats_simple_set_schema_queries() {
99 let input = "SET SCHEMA schema1; SET CURRENT SCHEMA schema2;";
100 let options = FormatOptions::default();
101 let expected = indoc!(
102 "
103 SET SCHEMA
104 schema1;
105 SET CURRENT SCHEMA
106 schema2;"
107 );
108
109 assert_eq!(format(input, &QueryParams::None, &options), expected);
110 }
111
112 #[test]
113 fn it_formats_simple_select_query() {
114 let input = "SELECT count(*),Column1 FROM Table1;";
115 let options = FormatOptions::default();
116 let expected = indoc!(
117 "
118 SELECT
119 count(*),
120 Column1
121 FROM
122 Table1;"
123 );
124
125 assert_eq!(format(input, &QueryParams::None, &options), expected);
126 }
127
128 #[test]
129 fn it_formats_complex_select() {
130 let input =
131 "SELECT DISTINCT name, ROUND(age/7) field1, 18 + 20 AS field2, 'some string' FROM foo;";
132 let options = FormatOptions::default();
133 let expected = indoc!(
134 "
135 SELECT
136 DISTINCT name,
137 ROUND(age / 7) field1,
138 18 + 20 AS field2,
139 'some string'
140 FROM
141 foo;"
142 );
143
144 assert_eq!(format(input, &QueryParams::None, &options), expected);
145 }
146
147 #[test]
148 fn it_formats_select_with_complex_where() {
149 let input = indoc!(
150 "
151 SELECT * FROM foo WHERE Column1 = 'testing'
152 AND ( (Column2 = Column3 OR Column4 >= NOW()) );
153 "
154 );
155 let options = FormatOptions::default();
156 let expected = indoc!(
157 "
158 SELECT
159 *
160 FROM
161 foo
162 WHERE
163 Column1 = 'testing'
164 AND (
165 (
166 Column2 = Column3
167 OR Column4 >= NOW()
168 )
169 );"
170 );
171
172 assert_eq!(format(input, &QueryParams::None, &options), expected);
173 }
174
175 #[test]
176 fn it_formats_select_with_top_level_reserved_words() {
177 let input = indoc!(
178 "
179 SELECT * FROM foo WHERE name = 'John' GROUP BY some_column
180 HAVING column > 10 ORDER BY other_column LIMIT 5;
181 "
182 );
183 let options = FormatOptions::default();
184 let expected = indoc!(
185 "
186 SELECT
187 *
188 FROM
189 foo
190 WHERE
191 name = 'John'
192 GROUP BY
193 some_column
194 HAVING
195 column > 10
196 ORDER BY
197 other_column
198 LIMIT
199 5;"
200 );
201
202 assert_eq!(format(input, &QueryParams::None, &options), expected);
203 }
204
205 #[test]
206 fn it_formats_limit_with_two_comma_separated_values_on_single_line() {
207 let input = "LIMIT 5, 10;";
208 let options = FormatOptions::default();
209 let expected = indoc!(
210 "
211 LIMIT
212 5, 10;"
213 );
214
215 assert_eq!(format(input, &QueryParams::None, &options), expected);
216 }
217
218 #[test]
219 fn it_formats_limit_of_single_value_followed_by_another_select_using_commas() {
220 let input = "LIMIT 5; SELECT foo, bar;";
221 let options = FormatOptions::default();
222 let expected = indoc!(
223 "
224 LIMIT
225 5;
226 SELECT
227 foo,
228 bar;"
229 );
230
231 assert_eq!(format(input, &QueryParams::None, &options), expected);
232 }
233
234 #[test]
235 fn it_formats_limit_of_single_value_and_offset() {
236 let input = "LIMIT 5 OFFSET 8;";
237 let options = FormatOptions::default();
238 let expected = indoc!(
239 "
240 LIMIT
241 5 OFFSET 8;"
242 );
243
244 assert_eq!(format(input, &QueryParams::None, &options), expected);
245 }
246
247 #[test]
248 fn it_recognizes_limit_in_lowercase() {
249 let input = "limit 5, 10;";
250 let options = FormatOptions::default();
251 let expected = indoc!(
252 "
253 limit
254 5, 10;"
255 );
256
257 assert_eq!(format(input, &QueryParams::None, &options), expected);
258 }
259
260 #[test]
261 fn it_preserves_case_of_keywords() {
262 let input = "select distinct * frOM foo left join bar WHERe a > 1 and b = 3";
263 let options = FormatOptions::default();
264 let expected = indoc!(
265 "
266 select
267 distinct *
268 frOM
269 foo
270 left join bar
271 WHERe
272 a > 1
273 and b = 3"
274 );
275
276 assert_eq!(format(input, &QueryParams::None, &options), expected);
277 }
278
279 #[test]
280 fn it_formats_select_query_with_select_query_inside_it() {
281 let input = "SELECT *, SUM(*) AS sum FROM (SELECT * FROM Posts LIMIT 30) WHERE a > b";
282 let options = FormatOptions::default();
283 let expected = indoc!(
284 "
285 SELECT
286 *,
287 SUM(*) AS sum
288 FROM
289 (
290 SELECT
291 *
292 FROM
293 Posts
294 LIMIT
295 30
296 )
297 WHERE
298 a > b"
299 );
300
301 assert_eq!(format(input, &QueryParams::None, &options), expected);
302 }
303
304 #[test]
305 fn it_formats_select_query_with_inner_join() {
306 let input = indoc!(
307 "
308 SELECT customer_id.from, COUNT(order_id) AS total FROM customers
309 INNER JOIN orders ON customers.customer_id = orders.customer_id;"
310 );
311 let options = FormatOptions::default();
312 let expected = indoc!(
313 "
314 SELECT
315 customer_id.from,
316 COUNT(order_id) AS total
317 FROM
318 customers
319 INNER JOIN orders ON customers.customer_id = orders.customer_id;"
320 );
321
322 assert_eq!(format(input, &QueryParams::None, &options), expected);
323 }
324
325 #[test]
326 fn it_formats_select_query_with_non_standard_join() {
327 let input = indoc!(
328 "
329 SELECT customer_id.from, COUNT(order_id) AS total FROM customers
330 INNER ANY JOIN orders ON customers.customer_id = orders.customer_id
331 LEFT
332 SEMI JOIN foo ON foo.id = customers.id
333 PASTE
334 JOIN bar
335 ;"
336 );
337 let options = FormatOptions::default();
338 let expected = indoc!(
339 "
340 SELECT
341 customer_id.from,
342 COUNT(order_id) AS total
343 FROM
344 customers
345 INNER ANY JOIN orders ON customers.customer_id = orders.customer_id
346 LEFT SEMI JOIN foo ON foo.id = customers.id
347 PASTE JOIN bar;"
348 );
349
350 assert_eq!(format(input, &QueryParams::None, &options), expected);
351 }
352
353 #[test]
354 fn it_formats_select_query_with_different_comments() {
355 let input = indoc!(
356 "
357 SELECT
358 /*
359 * This is a block comment
360 */
361 * FROM
362 -- This is another comment
363 MyTable # One final comment
364 WHERE 1 = 2;"
365 );
366 let options = FormatOptions::default();
367 let expected = indoc!(
368 "
369 SELECT
370 /*
371 * This is a block comment
372 */
373 *
374 FROM
375 -- This is another comment
376 MyTable # One final comment
377 WHERE
378 1 = 2;"
379 );
380
381 assert_eq!(format(input, &QueryParams::None, &options), expected);
382 }
383
384 #[test]
385 fn it_maintains_block_comment_indentation() {
386 let input = indoc!(
387 "
388 SELECT
389 /*
390 * This is a block comment
391 */
392 *
393 FROM
394 MyTable
395 WHERE
396 1 = 2;"
397 );
398 let options = FormatOptions::default();
399
400 assert_eq!(format(input, &QueryParams::None, &options), input);
401 }
402
403 #[test]
404 fn it_formats_simple_insert_query() {
405 let input = "INSERT INTO Customers (ID, MoneyBalance, Address, City) VALUES (12,-123.4, 'Skagen 2111','Stv');";
406 let options = FormatOptions::default();
407 let expected = indoc!(
408 "
409 INSERT INTO
410 Customers (ID, MoneyBalance, Address, City)
411 VALUES
412 (12, -123.4, 'Skagen 2111', 'Stv');"
413 );
414
415 assert_eq!(format(input, &QueryParams::None, &options), expected);
416 }
417
418 #[test]
419 fn it_keeps_short_parenthesized_list_with_nested_parenthesis_on_single_line() {
420 let input = "SELECT (a + b * (c - NOW()));";
421 let options = FormatOptions::default();
422 let expected = indoc!(
423 "
424 SELECT
425 (a + b * (c - NOW()));"
426 );
427
428 assert_eq!(format(input, &QueryParams::None, &options), expected);
429 }
430
431 #[test]
432 fn it_breaks_long_parenthesized_lists_to_multiple_lines() {
433 let input = indoc!(
434 "
435 INSERT INTO some_table (id_product, id_shop, id_currency, id_country, id_registration) (
436 SELECT IF(dq.id_discounter_shopping = 2, dq.value, dq.value / 100),
437 IF (dq.id_discounter_shopping = 2, 'amount', 'percentage') FROM foo);"
438 );
439 let options = FormatOptions::default();
440 let expected = indoc!(
441 "
442 INSERT INTO
443 some_table (
444 id_product,
445 id_shop,
446 id_currency,
447 id_country,
448 id_registration
449 ) (
450 SELECT
451 IF(
452 dq.id_discounter_shopping = 2,
453 dq.value,
454 dq.value / 100
455 ),
456 IF (
457 dq.id_discounter_shopping = 2,
458 'amount',
459 'percentage'
460 )
461 FROM
462 foo
463 );"
464 );
465
466 assert_eq!(format(input, &QueryParams::None, &options), expected);
467 }
468
469 #[test]
470 fn it_formats_simple_update_query() {
471 let input = "UPDATE Customers SET ContactName='Alfred Schmidt', City='Hamburg' WHERE CustomerName='Alfreds Futterkiste';";
472 let options = FormatOptions::default();
473 let expected = indoc!(
474 "
475 UPDATE
476 Customers
477 SET
478 ContactName = 'Alfred Schmidt',
479 City = 'Hamburg'
480 WHERE
481 CustomerName = 'Alfreds Futterkiste';"
482 );
483
484 assert_eq!(format(input, &QueryParams::None, &options), expected);
485 }
486
487 #[test]
488 fn it_formats_simple_delete_query() {
489 let input = "DELETE FROM Customers WHERE CustomerName='Alfred' AND Phone=5002132;";
490 let options = FormatOptions::default();
491 let expected = indoc!(
492 "
493 DELETE FROM
494 Customers
495 WHERE
496 CustomerName = 'Alfred'
497 AND Phone = 5002132;"
498 );
499
500 assert_eq!(format(input, &QueryParams::None, &options), expected);
501 }
502
503 #[test]
504 fn it_formats_simple_drop_query() {
505 let input = "DROP TABLE IF EXISTS admin_role;";
506 let options = FormatOptions::default();
507
508 assert_eq!(format(input, &QueryParams::None, &options), input);
509 }
510
511 #[test]
512 fn it_formats_incomplete_query() {
513 let input = "SELECT count(";
514 let options = FormatOptions::default();
515 let expected = indoc!(
516 "
517 SELECT
518 count("
519 );
520
521 assert_eq!(format(input, &QueryParams::None, &options), expected);
522 }
523
524 #[test]
525 fn it_formats_query_that_ends_with_open_comment() {
526 let input = indoc!(
527 "
528 SELECT count(*)
529 /*Comment"
530 );
531 let options = FormatOptions::default();
532 let expected = indoc!(
533 "
534 SELECT
535 count(*)
536 /*Comment"
537 );
538
539 assert_eq!(format(input, &QueryParams::None, &options), expected);
540 }
541
542 #[test]
543 fn it_formats_update_query_with_as_part() {
544 let input = "UPDATE customers SET total_orders = order_summary.total FROM ( SELECT * FROM bank) AS order_summary";
545 let options = FormatOptions::default();
546 let expected = indoc!(
547 "
548 UPDATE
549 customers
550 SET
551 total_orders = order_summary.total
552 FROM
553 (
554 SELECT
555 *
556 FROM
557 bank
558 ) AS order_summary"
559 );
560
561 assert_eq!(format(input, &QueryParams::None, &options), expected);
562 }
563
564 #[test]
565 fn it_formats_top_level_and_newline_multi_word_reserved_words_with_inconsistent_spacing() {
566 let input = "SELECT * FROM foo LEFT \t OUTER \n JOIN bar ORDER \n BY blah";
567 let options = FormatOptions::default();
568 let expected = indoc!(
569 "
570 SELECT
571 *
572 FROM
573 foo
574 LEFT OUTER JOIN bar
575 ORDER BY
576 blah"
577 );
578
579 assert_eq!(format(input, &QueryParams::None, &options), expected);
580 }
581
582 #[test]
583 fn it_formats_long_double_parenthesized_queries_to_multiple_lines() {
584 let input = "((foo = '0123456789-0123456789-0123456789-0123456789'))";
585 let options = FormatOptions::default();
586 let expected = indoc!(
587 "
588 (
589 (
590 foo = '0123456789-0123456789-0123456789-0123456789'
591 )
592 )"
593 );
594
595 assert_eq!(format(input, &QueryParams::None, &options), expected);
596 }
597
598 #[test]
599 fn it_formats_short_double_parenthesizes_queries_to_one_line() {
600 let input = "((foo = 'bar'))";
601 let options = FormatOptions::default();
602
603 assert_eq!(format(input, &QueryParams::None, &options), input);
604 }
605
606 #[test]
607 fn it_formats_single_char_operators() {
608 let inputs = [
609 "foo = bar",
610 "foo < bar",
611 "foo > bar",
612 "foo + bar",
613 "foo - bar",
614 "foo * bar",
615 "foo / bar",
616 "foo % bar",
617 ];
618 let options = FormatOptions::default();
619 for input in &inputs {
620 assert_eq!(&format(input, &QueryParams::None, &options), input);
621 }
622 }
623
624 #[test]
625 fn it_formats_multi_char_operators() {
626 let inputs = [
627 "foo != bar",
628 "foo <> bar",
629 "foo == bar",
630 "foo || bar",
631 "foo <= bar",
632 "foo >= bar",
633 "foo !< bar",
634 "foo !> bar",
635 ];
636 let options = FormatOptions::default();
637 for input in &inputs {
638 assert_eq!(&format(input, &QueryParams::None, &options), input);
639 }
640 }
641
642 #[test]
643 fn it_formats_logical_operators() {
644 let inputs = [
645 "foo ALL bar",
646 "foo = ANY (1, 2, 3)",
647 "EXISTS bar",
648 "foo IN (1, 2, 3)",
649 "foo LIKE 'hello%'",
650 "foo IS NULL",
651 "UNIQUE foo",
652 ];
653 let options = FormatOptions::default();
654 for input in &inputs {
655 assert_eq!(&format(input, &QueryParams::None, &options), input);
656 }
657 }
658
659 #[test]
660 fn it_formats_and_or_operators() {
661 let strings = [
662 ("foo BETWEEN bar AND baz", "foo BETWEEN bar AND baz"),
663 ("foo BETWEEN\nbar\nAND baz", "foo BETWEEN bar AND baz"),
664 ("foo AND bar", "foo\nAND bar"),
665 ("foo OR bar", "foo\nOR bar"),
666 ];
667 let options = FormatOptions::default();
668 for (input, output) in &strings {
669 assert_eq!(&format(input, &QueryParams::None, &options), output);
670 }
671 }
672
673 #[test]
674 fn it_recognizes_strings() {
675 let inputs = ["\"foo JOIN bar\"", "'foo JOIN bar'", "`foo JOIN bar`"];
676 let options = FormatOptions::default();
677 for input in &inputs {
678 assert_eq!(&format(input, &QueryParams::None, &options), input);
679 }
680 }
681
682 #[test]
683 fn it_recognizes_escaped_strings() {
684 let inputs = [
685 r#""foo \" JOIN bar""#,
686 r#"'foo \' JOIN bar'"#,
687 r#"`foo `` JOIN bar`"#,
688 r#"'foo '' JOIN bar'"#,
689 r#"'two households"'"#,
690 r#"'two households'''"#,
691 r#"E'alice'''"#,
692 ];
693 let options = FormatOptions::default();
694 for input in &inputs {
695 assert_eq!(&format(input, &QueryParams::None, &options), input);
696 }
697 }
698
699 #[test]
700 fn it_formats_postgres_specific_operators() {
701 let strings = [
702 ("column::int", "column::int"),
703 ("v->2", "v -> 2"),
704 ("v->>2", "v ->> 2"),
705 ("foo ~~ 'hello'", "foo ~~ 'hello'"),
706 ("foo !~ 'hello'", "foo !~ 'hello'"),
707 ("foo ~* 'hello'", "foo ~* 'hello'"),
708 ("foo ~~* 'hello'", "foo ~~* 'hello'"),
709 ("foo !~~ 'hello'", "foo !~~ 'hello'"),
710 ("foo !~* 'hello'", "foo !~* 'hello'"),
711 ("foo !~~* 'hello'", "foo !~~* 'hello'"),
712 ];
713 let options = FormatOptions::default();
714 for (input, output) in &strings {
715 assert_eq!(&format(input, &QueryParams::None, &options), output);
716 }
717 }
718
719 #[test]
720 fn it_keeps_separation_between_multiple_statements() {
721 let strings = [
722 ("foo;bar;", "foo;\nbar;"),
723 ("foo\n;bar;", "foo;\nbar;"),
724 ("foo\n\n\n;bar;\n\n", "foo;\nbar;"),
725 ];
726 let options = FormatOptions::default();
727 for (input, output) in &strings {
728 assert_eq!(&format(input, &QueryParams::None, &options), output);
729 }
730
731 let input = indoc!(
732 "
733 SELECT count(*),Column1 FROM Table1;
734 SELECT count(*),Column1 FROM Table2;"
735 );
736 let options = FormatOptions::default();
737 let expected = indoc!(
738 "
739 SELECT
740 count(*),
741 Column1
742 FROM
743 Table1;
744 SELECT
745 count(*),
746 Column1
747 FROM
748 Table2;"
749 );
750
751 assert_eq!(format(input, &QueryParams::None, &options), expected);
752 }
753
754 #[test]
755 fn it_formats_unicode_correctly() {
756 let input = "SELECT test, тест FROM table;";
757 let options = FormatOptions::default();
758 let expected = indoc!(
759 "
760 SELECT
761 test,
762 тест
763 FROM
764 table;"
765 );
766
767 assert_eq!(format(input, &QueryParams::None, &options), expected);
768 }
769
770 #[test]
771 fn it_converts_keywords_to_uppercase_when_option_passed_in() {
772 let input = "select distinct * frOM foo left join bar WHERe cola > 1 and colb = 3";
773 let options = FormatOptions {
774 uppercase: Some(true),
775 ..FormatOptions::default()
776 };
777 let expected = indoc!(
778 "
779 SELECT
780 DISTINCT *
781 FROM
782 foo
783 LEFT JOIN bar
784 WHERE
785 cola > 1
786 AND colb = 3"
787 );
788
789 assert_eq!(format(input, &QueryParams::None, &options), expected);
790 }
791
792 #[test]
793 fn it_line_breaks_between_queries_with_config() {
794 let input = "SELECT * FROM foo; SELECT * FROM bar;";
795 let options = FormatOptions {
796 lines_between_queries: 2,
797 ..FormatOptions::default()
798 };
799 let expected = indoc!(
800 "
801 SELECT
802 *
803 FROM
804 foo;
805
806 SELECT
807 *
808 FROM
809 bar;"
810 );
811
812 assert_eq!(format(input, &QueryParams::None, &options), expected);
813 }
814
815 #[test]
816 fn it_correctly_indents_create_statement_after_select() {
817 let input = indoc!(
818 "
819 SELECT * FROM test;
820 CREATE TABLE TEST(id NUMBER NOT NULL, col1 VARCHAR2(20), col2 VARCHAR2(20));
821 "
822 );
823 let options = FormatOptions::default();
824 let expected = indoc!(
825 "
826 SELECT
827 *
828 FROM
829 test;
830 CREATE TABLE TEST(
831 id NUMBER NOT NULL,
832 col1 VARCHAR2(20),
833 col2 VARCHAR2(20)
834 );"
835 );
836
837 assert_eq!(format(input, &QueryParams::None, &options), expected);
838 }
839
840 #[test]
841 fn it_formats_short_create_table() {
842 let input = "CREATE TABLE items (a INT PRIMARY KEY, b TEXT);";
843 let options = FormatOptions::default();
844
845 assert_eq!(format(input, &QueryParams::None, &options), input);
846 }
847
848 #[test]
849 fn it_formats_long_create_table() {
850 let input =
851 "CREATE TABLE items (a INT PRIMARY KEY, b TEXT, c INT NOT NULL, d INT NOT NULL);";
852 let options = FormatOptions::default();
853 let expected = indoc!(
854 "
855 CREATE TABLE items (
856 a INT PRIMARY KEY,
857 b TEXT,
858 c INT NOT NULL,
859 d INT NOT NULL
860 );"
861 );
862
863 assert_eq!(format(input, &QueryParams::None, &options), expected);
864 }
865
866 #[test]
867 fn it_formats_insert_without_into() {
868 let input =
869 "INSERT Customers (ID, MoneyBalance, Address, City) VALUES (12,-123.4, 'Skagen 2111','Stv');";
870 let options = FormatOptions::default();
871 let expected = indoc!(
872 "
873 INSERT
874 Customers (ID, MoneyBalance, Address, City)
875 VALUES
876 (12, -123.4, 'Skagen 2111', 'Stv');"
877 );
878
879 assert_eq!(format(input, &QueryParams::None, &options), expected);
880 }
881
882 #[test]
883 fn it_formats_alter_table_modify_query() {
884 let input = "ALTER TABLE supplier MODIFY supplier_name char(100) NOT NULL;";
885 let options = FormatOptions::default();
886 let expected = indoc!(
887 "
888 ALTER TABLE
889 supplier
890 MODIFY
891 supplier_name char(100) NOT NULL;"
892 );
893
894 assert_eq!(format(input, &QueryParams::None, &options), expected);
895 }
896
897 #[test]
898 fn it_formats_alter_table_alter_column_query() {
899 let input = "ALTER TABLE supplier ALTER COLUMN supplier_name VARCHAR(100) NOT NULL;";
900 let options = FormatOptions::default();
901 let expected = indoc!(
902 "
903 ALTER TABLE
904 supplier
905 ALTER COLUMN
906 supplier_name VARCHAR(100) NOT NULL;"
907 );
908
909 assert_eq!(format(input, &QueryParams::None, &options), expected);
910 }
911
912 #[test]
913 fn it_recognizes_bracketed_strings() {
914 let inputs = ["[foo JOIN bar]", "[foo ]] JOIN bar]"];
915 let options = FormatOptions::default();
916 for input in &inputs {
917 assert_eq!(&format(input, &QueryParams::None, &options), input);
918 }
919 }
920
921 #[test]
922 fn it_recognizes_at_variables() {
923 let input =
924 "SELECT @variable, @a1_2.3$, @'var name', @\"var name\", @`var name`, @[var name];";
925 let options = FormatOptions::default();
926 let expected = indoc!(
927 "
928 SELECT
929 @variable,
930 @a1_2.3$,
931 @'var name',
932 @\"var name\",
933 @`var name`,
934 @[var name];"
935 );
936
937 assert_eq!(format(input, &QueryParams::None, &options), expected);
938 }
939
940 #[test]
941 fn it_recognizes_at_variables_with_param_values() {
942 let input =
943 "SELECT @variable, @a1_2.3$, @'var name', @\"var name\", @`var name`, @[var name], @'var\\name';";
944 let params = vec![
945 ("variable".to_string(), "\"variable value\"".to_string()),
946 ("a1_2.3$".to_string(), "'weird value'".to_string()),
947 ("var name".to_string(), "'var value'".to_string()),
948 ("var\\name".to_string(), "'var\\ value'".to_string()),
949 ];
950 let options = FormatOptions::default();
951 let expected = indoc!(
952 "
953 SELECT
954 \"variable value\",
955 'weird value',
956 'var value',
957 'var value',
958 'var value',
959 'var value',
960 'var\\ value';"
961 );
962
963 assert_eq!(
964 format(input, &QueryParams::Named(params), &options),
965 expected
966 );
967 }
968
969 #[test]
970 fn it_recognizes_colon_variables() {
971 let input =
972 "SELECT :variable, :a1_2.3$, :'var name', :\"var name\", :`var name`, :[var name];";
973 let options = FormatOptions::default();
974 let expected = indoc!(
975 "
976 SELECT
977 :variable,
978 :a1_2.3$,
979 :'var name',
980 :\"var name\",
981 :`var name`,
982 :[var name];"
983 );
984
985 assert_eq!(format(input, &QueryParams::None, &options), expected);
986 }
987
988 #[test]
989 fn it_recognizes_colon_variables_with_param_values() {
990 let input = indoc!(
991 "
992 SELECT :variable, :a1_2.3$, :'var name', :\"var name\", :`var name`,
993 :[var name], :'escaped \\'var\\'', :\"^*& weird \\\" var \";
994 "
995 );
996 let params = vec![
997 ("variable".to_string(), "\"variable value\"".to_string()),
998 ("a1_2.3$".to_string(), "'weird value'".to_string()),
999 ("var name".to_string(), "'var value'".to_string()),
1000 ("escaped 'var'".to_string(), "'weirder value'".to_string()),
1001 (
1002 "^*& weird \" var ".to_string(),
1003 "'super weird value'".to_string(),
1004 ),
1005 ];
1006 let options = FormatOptions::default();
1007 let expected = indoc!(
1008 "
1009 SELECT
1010 \"variable value\",
1011 'weird value',
1012 'var value',
1013 'var value',
1014 'var value',
1015 'var value',
1016 'weirder value',
1017 'super weird value';"
1018 );
1019
1020 assert_eq!(
1021 format(input, &QueryParams::Named(params), &options),
1022 expected
1023 );
1024 }
1025
1026 #[test]
1027 fn it_recognizes_question_numbered_placeholders() {
1028 let input = "SELECT ?1, ?25, ?;";
1029 let options = FormatOptions::default();
1030 let expected = indoc!(
1031 "
1032 SELECT
1033 ?1,
1034 ?25,
1035 ?;"
1036 );
1037
1038 assert_eq!(format(input, &QueryParams::None, &options), expected);
1039 }
1040
1041 #[test]
1042 fn it_recognizes_question_numbered_placeholders_with_param_values() {
1043 let input = "SELECT ?1, ?2, ?0;";
1044 let params = vec![
1045 "first".to_string(),
1046 "second".to_string(),
1047 "third".to_string(),
1048 ];
1049 let options = FormatOptions::default();
1050 let expected = indoc!(
1051 "
1052 SELECT
1053 second,
1054 third,
1055 first;"
1056 );
1057
1058 assert_eq!(
1059 format(input, &QueryParams::Indexed(params), &options),
1060 expected
1061 );
1062
1063 format("?62666666121266666612", &QueryParams::None, &options);
1064 }
1065
1066 #[test]
1067 fn it_recognizes_question_indexed_placeholders_with_param_values() {
1068 let input = "SELECT ?, ?, ?;";
1069 let params = vec![
1070 "first".to_string(),
1071 "second".to_string(),
1072 "third".to_string(),
1073 ];
1074 let options = FormatOptions::default();
1075 let expected = indoc!(
1076 "
1077 SELECT
1078 first,
1079 second,
1080 third;"
1081 );
1082
1083 assert_eq!(
1084 format(input, &QueryParams::Indexed(params), &options),
1085 expected
1086 );
1087 }
1088
1089 #[test]
1090 fn it_recognizes_dollar_sign_numbered_placeholders() {
1091 let input = "SELECT $1, $2;";
1092 let options = FormatOptions::default();
1093 let expected = indoc!(
1094 "
1095 SELECT
1096 $1,
1097 $2;"
1098 );
1099
1100 assert_eq!(format(input, &QueryParams::None, &options), expected);
1101 }
1102
1103 #[test]
1104 fn it_recognizes_dollar_sign_alphanumeric_placeholders() {
1105 let input = "SELECT $hash, $foo, $bar;";
1106 let options = FormatOptions::default();
1107 let expected = indoc!(
1108 "
1109 SELECT
1110 $hash,
1111 $foo,
1112 $bar;"
1113 );
1114
1115 assert_eq!(format(input, &QueryParams::None, &options), expected);
1116 }
1117
1118 #[test]
1119 fn it_recognizes_dollar_sign_numbered_placeholders_with_param_values() {
1120 let input = "SELECT $2, $3, $1, $named, $4, $alias;";
1121 let params = vec![
1122 "first".to_string(),
1123 "second".to_string(),
1124 "third".to_string(),
1125 "4th".to_string(),
1126 ];
1127 let options = FormatOptions::default();
1128 let expected = indoc!(
1129 "
1130 SELECT
1131 second,
1132 third,
1133 first,
1134 $named,
1135 4th,
1136 $alias;"
1137 );
1138
1139 assert_eq!(
1140 format(input, &QueryParams::Indexed(params), &options),
1141 expected
1142 );
1143 }
1144
1145 #[test]
1146 fn it_recognizes_dollar_sign_alphanumeric_placeholders_with_param_values() {
1147 let input = "SELECT $hash, $salt, $1, $2;";
1148 let params = vec![
1149 ("hash".to_string(), "hash value".to_string()),
1150 ("salt".to_string(), "salt value".to_string()),
1151 ("1".to_string(), "number 1".to_string()),
1152 ("2".to_string(), "number 2".to_string()),
1153 ];
1154 let options = FormatOptions::default();
1155 let expected = indoc!(
1156 "
1157 SELECT
1158 hash value,
1159 salt value,
1160 number 1,
1161 number 2;"
1162 );
1163
1164 assert_eq!(
1165 format(input, &QueryParams::Named(params), &options),
1166 expected
1167 );
1168 }
1169
1170 #[test]
1171 fn it_formats_query_with_go_batch_separator() {
1172 let input = "SELECT 1 GO SELECT 2";
1173 let params = vec![
1174 "first".to_string(),
1175 "second".to_string(),
1176 "third".to_string(),
1177 ];
1178 let options = FormatOptions::default();
1179 let expected = indoc!(
1180 "
1181 SELECT
1182 1
1183 GO
1184 SELECT
1185 2"
1186 );
1187
1188 assert_eq!(
1189 format(input, &QueryParams::Indexed(params), &options),
1190 expected
1191 );
1192 }
1193
1194 #[test]
1195 fn it_formats_select_query_with_cross_join() {
1196 let input = "SELECT a, b FROM t CROSS JOIN t2 on t.id = t2.id_t";
1197 let options = FormatOptions::default();
1198 let expected = indoc!(
1199 "
1200 SELECT
1201 a,
1202 b
1203 FROM
1204 t
1205 CROSS JOIN t2 on t.id = t2.id_t"
1206 );
1207
1208 assert_eq!(format(input, &QueryParams::None, &options), expected);
1209 }
1210
1211 #[test]
1212 fn it_formats_select_query_with_cross_apply() {
1213 let input = "SELECT a, b FROM t CROSS APPLY fn(t.id)";
1214 let options = FormatOptions::default();
1215 let expected = indoc!(
1216 "
1217 SELECT
1218 a,
1219 b
1220 FROM
1221 t
1222 CROSS APPLY fn(t.id)"
1223 );
1224
1225 assert_eq!(format(input, &QueryParams::None, &options), expected);
1226 }
1227
1228 #[test]
1229 fn it_formats_simple_select() {
1230 let input = "SELECT N, M FROM t";
1231 let options = FormatOptions::default();
1232 let expected = indoc!(
1233 "
1234 SELECT
1235 N,
1236 M
1237 FROM
1238 t"
1239 );
1240
1241 assert_eq!(format(input, &QueryParams::None, &options), expected);
1242 }
1243
1244 #[test]
1245 fn it_formats_simple_select_with_national_characters_mssql() {
1246 let input = "SELECT N'value'";
1247 let options = FormatOptions::default();
1248 let expected = indoc!(
1249 "
1250 SELECT
1251 N'value'"
1252 );
1253
1254 assert_eq!(format(input, &QueryParams::None, &options), expected);
1255 }
1256
1257 #[test]
1258 fn it_formats_select_query_with_outer_apply() {
1259 let input = "SELECT a, b FROM t OUTER APPLY fn(t.id)";
1260 let options = FormatOptions::default();
1261 let expected = indoc!(
1262 "
1263 SELECT
1264 a,
1265 b
1266 FROM
1267 t
1268 OUTER APPLY fn(t.id)"
1269 );
1270
1271 assert_eq!(format(input, &QueryParams::None, &options), expected);
1272 }
1273
1274 #[test]
1275 fn it_formats_fetch_first_like_limit() {
1276 let input = "SELECT * FETCH FIRST 2 ROWS ONLY;";
1277 let options = FormatOptions::default();
1278 let expected = indoc!(
1279 "
1280 SELECT
1281 *
1282 FETCH FIRST
1283 2 ROWS ONLY;"
1284 );
1285
1286 assert_eq!(format(input, &QueryParams::None, &options), expected);
1287 }
1288
1289 #[test]
1290 fn it_formats_case_when_with_a_blank_expression() {
1291 let input = "CASE WHEN option = 'foo' THEN 1 WHEN option = 'bar' THEN 2 WHEN option = 'baz' THEN 3 ELSE 4 END;";
1292 let options = FormatOptions::default();
1293 let expected = indoc!(
1294 "
1295 CASE
1296 WHEN option = 'foo' THEN 1
1297 WHEN option = 'bar' THEN 2
1298 WHEN option = 'baz' THEN 3
1299 ELSE 4
1300 END;"
1301 );
1302
1303 assert_eq!(format(input, &QueryParams::None, &options), expected);
1304 }
1305
1306 #[test]
1307 fn it_formats_case_when_inside_select() {
1308 let input =
1309 "SELECT foo, bar, CASE baz WHEN 'one' THEN 1 WHEN 'two' THEN 2 ELSE 3 END FROM table";
1310 let options = FormatOptions::default();
1311 let expected = indoc!(
1312 "
1313 SELECT
1314 foo,
1315 bar,
1316 CASE
1317 baz
1318 WHEN 'one' THEN 1
1319 WHEN 'two' THEN 2
1320 ELSE 3
1321 END
1322 FROM
1323 table"
1324 );
1325
1326 assert_eq!(format(input, &QueryParams::None, &options), expected);
1327 }
1328
1329 #[test]
1330 fn it_formats_case_when_with_an_expression() {
1331 let input = "CASE toString(getNumber()) WHEN 'one' THEN 1 WHEN 'two' THEN 2 WHEN 'three' THEN 3 ELSE 4 END;";
1332 let options = FormatOptions::default();
1333 let expected = indoc!(
1334 "
1335 CASE
1336 toString(getNumber())
1337 WHEN 'one' THEN 1
1338 WHEN 'two' THEN 2
1339 WHEN 'three' THEN 3
1340 ELSE 4
1341 END;"
1342 );
1343
1344 assert_eq!(format(input, &QueryParams::None, &options), expected);
1345 }
1346
1347 #[test]
1348 fn it_recognizes_lowercase_case_end() {
1349 let input = "case when option = 'foo' then 1 else 2 end;";
1350 let options = FormatOptions::default();
1351 let expected = indoc!(
1352 "
1353 case
1354 when option = 'foo' then 1
1355 else 2
1356 end;"
1357 );
1358
1359 assert_eq!(format(input, &QueryParams::None, &options), expected);
1360 }
1361
1362 #[test]
1363 fn it_ignores_words_case_and_end_inside_other_strings() {
1364 let input = "SELECT CASEDATE, ENDDATE FROM table1;";
1365 let options = FormatOptions::default();
1366 let expected = indoc!(
1367 "
1368 SELECT
1369 CASEDATE,
1370 ENDDATE
1371 FROM
1372 table1;"
1373 );
1374
1375 assert_eq!(format(input, &QueryParams::None, &options), expected);
1376 }
1377
1378 #[test]
1379 fn it_formats_tricky_line_comments() {
1380 let input = "SELECT a#comment, here\nFROM b--comment";
1381 let options = FormatOptions::default();
1382 let expected = indoc!(
1383 "
1384 SELECT
1385 a #comment, here
1386 FROM
1387 b --comment"
1388 );
1389
1390 assert_eq!(format(input, &QueryParams::None, &options), expected);
1391 }
1392
1393 #[test]
1394 fn it_formats_line_comments_followed_by_semicolon() {
1395 let input = indoc!(
1396 "
1397 SELECT a FROM b
1398 --comment
1399 ;"
1400 );
1401 let options = FormatOptions::default();
1402 let expected = indoc!(
1403 "
1404 SELECT
1405 a
1406 FROM
1407 b --comment
1408 ;"
1409 );
1410
1411 assert_eq!(format(input, &QueryParams::None, &options), expected);
1412 }
1413
1414 #[test]
1415 fn it_formats_line_comments_followed_by_comma() {
1416 let input = indoc!(
1417 "
1418 SELECT a --comment
1419 , b"
1420 );
1421 let options = FormatOptions::default();
1422 let expected = indoc!(
1423 "
1424 SELECT
1425 a --comment
1426 ,
1427 b"
1428 );
1429
1430 assert_eq!(format(input, &QueryParams::None, &options), expected);
1431 }
1432
1433 #[test]
1434 fn it_formats_line_comments_followed_by_close_paren() {
1435 let input = "SELECT ( a --comment\n )";
1436 let options = FormatOptions::default();
1437 let expected = indoc!(
1438 "
1439 SELECT
1440 (
1441 a --comment
1442 )"
1443 );
1444
1445 assert_eq!(format(input, &QueryParams::None, &options), expected);
1446 }
1447
1448 #[test]
1449 fn it_formats_line_comments_followed_by_open_paren() {
1450 let input = "SELECT a --comment\n()";
1451 let options = FormatOptions::default();
1452 let expected = indoc!(
1453 "
1454 SELECT
1455 a --comment
1456 ()"
1457 );
1458
1459 assert_eq!(format(input, &QueryParams::None, &options), expected);
1460 }
1461
1462 #[test]
1463 fn it_formats_lonely_semicolon() {
1464 let input = ";";
1465 let options = FormatOptions::default();
1466
1467 assert_eq!(format(input, &QueryParams::None, &options), input);
1468 }
1469
1470 #[test]
1471 fn it_formats_multibyte_chars() {
1472 let input = "\nSELECT 'главная'";
1473 let options = FormatOptions::default();
1474 let expected = "SELECT\n 'главная'";
1475
1476 assert_eq!(format(input, &QueryParams::None, &options), expected);
1477 }
1478
1479 #[test]
1480 fn it_recognizes_scientific_notation() {
1481 let input = "SELECT *, 1e-7 as small, 1e2 as medium, 1e+7 as large FROM t";
1482 let options = FormatOptions::default();
1483 let expected = indoc!(
1484 "
1485 SELECT
1486 *,
1487 1e-7 as small,
1488 1e2 as medium,
1489 1e+7 as large
1490 FROM
1491 t"
1492 );
1493
1494 assert_eq!(format(input, &QueryParams::None, &options), expected);
1495 }
1496
1497 #[test]
1498 fn it_keeps_double_dollar_signs_together() {
1499 let input = "CREATE FUNCTION abc() AS $$ SELECT * FROM table $$ LANGUAGE plpgsql;";
1500 let options = FormatOptions::default();
1501 let expected = indoc!(
1502 "
1503 CREATE FUNCTION abc() AS
1504 $$
1505 SELECT
1506 *
1507 FROM
1508 table
1509 $$
1510 LANGUAGE plpgsql;"
1511 );
1512
1513 assert_eq!(format(input, &QueryParams::None, &options), expected);
1514 }
1515
1516 #[test]
1517 fn it_formats_pgplsql() {
1518 let input = "CREATE FUNCTION abc() AS $$ DECLARE a int := 1; b int := 2; BEGIN SELECT * FROM table $$ LANGUAGE plpgsql;";
1519 let options = FormatOptions::default();
1520 let expected = indoc!(
1521 "
1522 CREATE FUNCTION abc() AS
1523 $$
1524 DECLARE
1525 a int := 1;
1526 b int := 2;
1527 BEGIN
1528 SELECT
1529 *
1530 FROM
1531 table
1532 $$
1533 LANGUAGE plpgsql;"
1534 );
1535
1536 assert_eq!(format(input, &QueryParams::None, &options), expected);
1537 }
1538
1539 #[test]
1540 fn it_handles_comments_correctly() {
1541 let input = indoc!(
1542 "
1543 -- 创建一个外部表,存储销售数据
1544 CREATE EXTERNAL TABLE IF NOT EXISTS sales_data (
1545 -- 唯一标识订单ID
1546 order_id BIGINT COMMENT 'Unique identifier for the order',
1547
1548 -- 客户ID
1549 customer_id BIGINT COMMENT 'Unique identifier for the customer',
1550 )
1551 COMMENT 'Sales data table for storing transaction records';
1552
1553 -- 按销售日期和城市进行分区
1554 PARTITIONED BY (
1555 sale_year STRING COMMENT 'Year of the sale',
1556 sale_month STRING COMMENT 'Month of the sale'
1557 )
1558
1559 -- 设置数据存储位置
1560 LOCATION '/user/hive/warehouse/sales_data'
1561
1562 -- 使用 ORC 存储格式
1563 STORED AS ORC
1564
1565 -- 设置表的行格式
1566 ROW FORMAT DELIMITED
1567 FIELDS TERMINATED BY ','
1568 LINES TERMINATED BY '\n'
1569
1570 -- 设置表属性
1571 TBLPROPERTIES (
1572 'orc.compress' = 'SNAPPY', -- 使用SNAPPY压缩
1573 'transactional' = 'true', -- 启用事务支持
1574 'orc.create.index' = 'true', -- 创建索引
1575 'skip.header.line.count' = '1', -- 跳过CSV文件的第一行
1576 'external.table.purge' = 'true' -- 在删除表时自动清理数据
1577 );
1578
1579 -- 自动加载数据到 Hive 分区中
1580 ALTER TABLE sales_data
1581 ADD PARTITION (sale_year = '2024', sale_month = '08')
1582 LOCATION '/user/hive/warehouse/sales_data/2024/08';"
1583 );
1584 let options = FormatOptions {
1585 indent: Indent::Spaces(4),
1586 ..Default::default()
1587 };
1588 let expected = indoc!(
1589 "
1590 -- 创建一个外部表,存储销售数据
1591 CREATE EXTERNAL TABLE IF NOT EXISTS sales_data (
1592 -- 唯一标识订单ID
1593 order_id BIGINT COMMENT 'Unique identifier for the order',
1594 -- 客户ID
1595 customer_id BIGINT COMMENT 'Unique identifier for the customer',
1596 ) COMMENT 'Sales data table for storing transaction records';
1597 -- 按销售日期和城市进行分区
1598 PARTITIONED BY (
1599 sale_year STRING COMMENT 'Year of the sale',
1600 sale_month STRING COMMENT 'Month of the sale'
1601 )
1602 -- 设置数据存储位置
1603 LOCATION '/user/hive/warehouse/sales_data'
1604 -- 使用 ORC 存储格式
1605 STORED AS ORC
1606 -- 设置表的行格式
1607 ROW FORMAT DELIMITED FIELDS TERMINATED BY ',' LINES TERMINATED BY '\n'
1608 -- 设置表属性
1609 TBLPROPERTIES (
1610 'orc.compress' = 'SNAPPY', -- 使用SNAPPY压缩
1611 'transactional' = 'true', -- 启用事务支持
1612 'orc.create.index' = 'true', -- 创建索引
1613 'skip.header.line.count' = '1', -- 跳过CSV文件的第一行
1614 'external.table.purge' = 'true' -- 在删除表时自动清理数据
1615 );
1616 -- 自动加载数据到 Hive 分区中
1617 ALTER TABLE
1618 sales_data
1619 ADD
1620 PARTITION (sale_year = '2024', sale_month = '08') LOCATION '/user/hive/warehouse/sales_data/2024/08';"
1621 );
1622
1623 assert_eq!(format(input, &QueryParams::None, &options), expected);
1624 }
1625
1626 #[test]
1627 fn it_recognizes_returning_clause() {
1628 let input = indoc!(
1629 "
1630 INSERT INTO
1631 users (name, email)
1632 VALUES
1633 ($1, $2) RETURNING name,
1634 email"
1635 );
1636 let options = FormatOptions::default();
1637 let expected = indoc!(
1638 "
1639 INSERT INTO
1640 users (name, email)
1641 VALUES
1642 ($1, $2)
1643 RETURNING
1644 name,
1645 email"
1646 );
1647
1648 assert_eq!(format(input, &QueryParams::None, &options), expected);
1649 }
1650
1651 #[test]
1652 fn it_recognizes_on_update_clause() {
1653 let input = indoc!(
1654 "CREATE TABLE a (b integer REFERENCES c (id) ON UPDATE RESTRICT, other integer);"
1655 );
1656 let options = FormatOptions::default();
1657 let expected = indoc!(
1658 "
1659 CREATE TABLE a (
1660 b integer REFERENCES c (id) ON UPDATE RESTRICT,
1661 other integer
1662 );"
1663 );
1664 assert_eq!(format(input, &QueryParams::None, &options), expected);
1665 }
1666
1667 #[test]
1668 fn it_formats_except_on_columns() {
1669 let input = indoc!(
1670 "SELECT table_0.* EXCEPT (profit),
1671 details.* EXCEPT (item_id),
1672 table_0.profit
1673 FROM table_0"
1674 );
1675 let options = FormatOptions {
1676 indent: Indent::Spaces(4),
1677 ..Default::default()
1678 };
1679 let expected = indoc!(
1680 "
1681 SELECT
1682 table_0.* EXCEPT (profit),
1683 details.* EXCEPT (item_id),
1684 table_0.profit
1685 FROM
1686 table_0"
1687 );
1688
1689 assert_eq!(format(input, &QueryParams::None, &options), expected);
1690 }
1691
1692 #[test]
1693 fn it_uses_given_ignore_case_convert_config() {
1694 let input = "select count(*),Column1 from Table1;";
1695 let options = FormatOptions {
1696 uppercase: Some(true),
1697 ignore_case_convert: Some(vec!["from"]),
1698 ..FormatOptions::default()
1699 };
1700 let expected = indoc!(
1701 "
1702 SELECT
1703 count(*),
1704 Column1
1705 from
1706 Table1;"
1707 );
1708
1709 assert_eq!(format(input, &QueryParams::None, &options), expected);
1710 }
1711
1712 #[test]
1713 fn it_recognizes_fmt_off() {
1714 let input = indoc!(
1715 "SELECT * FROM sometable
1716 WHERE
1717 -- comment test here
1718 -- fmt: off
1719 first_key.second_key = 1
1720 -- json:first_key.second_key = 1
1721 -- fmt: on
1722 AND
1723 -- fm1t: off
1724 first_key.second_key = 1
1725 -- json:first_key.second_key = 1
1726 -- fmt:on"
1727 );
1728 let options = FormatOptions {
1729 indent: Indent::Spaces(4),
1730 ..Default::default()
1731 };
1732 let expected = indoc!(
1733 "
1734 SELECT
1735 *
1736 FROM
1737 sometable
1738 WHERE
1739 -- comment test here
1740 first_key.second_key = 1
1741 -- json:first_key.second_key = 1
1742 AND
1743 -- fm1t: off
1744 first_key.second_key = 1
1745 -- json:first_key.second_key = 1"
1746 );
1747
1748 assert_eq!(format(input, &QueryParams::None, &options), expected);
1749 }
1750
1751 #[test]
1752 fn it_converts_keywords_to_lowercase_when_option_passed_in() {
1753 let input = "select distinct * frOM foo left join bar WHERe cola > 1 and colb = 3";
1754 let options = FormatOptions {
1755 uppercase: Some(false),
1756 ..FormatOptions::default()
1757 };
1758 let expected = indoc!(
1759 "
1760 select
1761 distinct *
1762 from
1763 foo
1764 left join bar
1765 where
1766 cola > 1
1767 and colb = 3"
1768 );
1769
1770 assert_eq!(format(input, &QueryParams::None, &options), expected);
1771 }
1772
1773 #[test]
1774 fn it_converts_keywords_nothing_when_no_option_passed_in() {
1775 let input = "select distinct * frOM foo left join bar WHERe cola > 1 and colb = 3";
1776 let options = FormatOptions {
1777 uppercase: None,
1778 ..FormatOptions::default()
1779 };
1780 let expected = indoc!(
1781 "
1782 select
1783 distinct *
1784 frOM
1785 foo
1786 left join bar
1787 WHERe
1788 cola > 1
1789 and colb = 3"
1790 );
1791
1792 assert_eq!(format(input, &QueryParams::None, &options), expected);
1793 }
1794 #[test]
1795 fn it_correctly_parses_all_operators() {
1796 let operators = [
1797 "!!", "!~~*", "!~~", "!~*", "!~", "##", "#>>", "#>", "#-", "&<|", "&<", "&>", "&&",
1798 "*<>", "*<=", "*>=", "*>", "*=", "*<", "<<|", "<<=", "<<", "<->", "<@", "<^", "<=",
1799 "<>", "<", ">=", ">>=", ">>", ">^", "->>", "->", "-|-", "-", "+", "/", "=", "%", "?||",
1800 "?|", "?-|", "?-", "?#", "?&", "?", "@@@", "@@", "@>", "@?", "@-@", "@", "^@", "^",
1801 "|&>", "|>>", "|/", "|", "||/", "||", "~>=~", "~>~", "~<=~", "~<~", "~=", "~*", "~~*",
1802 "~~", "~", "%", "<%", "%>", "<<%", "%>>", "<<->", "<->>", "<<<->", "<->>>",
1803 ];
1804
1805 for &operator in &operators {
1807 let input = format!("left {} right", operator);
1808 let expected = format!("left {} right", operator);
1809 let options = FormatOptions {
1810 uppercase: None,
1811 ..FormatOptions::default()
1812 };
1813
1814 assert_eq!(
1815 format(&input, &QueryParams::None, &options),
1816 expected,
1817 "Failed to parse operator: {}",
1818 operator
1819 );
1820 }
1821 }
1822 #[test]
1823 fn it_correctly_splits_operators() {
1824 let input = "
1825 SELECT
1826 left <@ right,
1827 left << right,
1828 left >> right,
1829 left &< right,
1830 left &> right,
1831 left -|- right,
1832 @@ left,
1833 @-@ left,
1834 left <-> right,
1835 left <<| right,
1836 left |>> right,
1837 left &<| right,
1838 left |>& right,
1839 left <^ right,
1840 left >^ right,
1841 left <% right,
1842 left %> right,
1843 ?- left,
1844 left ?-| right,
1845 left ?|| right,
1846 left ~= right";
1847 let options = FormatOptions {
1848 uppercase: None,
1849 ..FormatOptions::default()
1850 };
1851 let expected = indoc!(
1852 "
1853SELECT
1854 left <@ right,
1855 left << right,
1856 left >> right,
1857 left &< right,
1858 left &> right,
1859 left -|- right,
1860 @@ left,
1861 @-@ left,
1862 left <-> right,
1863 left <<| right,
1864 left |>> right,
1865 left &<| right,
1866 left |>& right,
1867 left <^ right,
1868 left >^ right,
1869 left <% right,
1870 left %> right,
1871 ?- left,
1872 left ?-| right,
1873 left ?|| right,
1874 left ~= right"
1875 );
1876
1877 assert_eq!(format(input, &QueryParams::None, &options), expected);
1878 }
1879 #[test]
1880 fn it_formats_double_colons() {
1881 let input = "select text :: text, num::integer, data::json, (x - y)::integer frOM foo";
1882 let options = FormatOptions {
1883 uppercase: Some(false),
1884 ..FormatOptions::default()
1885 };
1886 let expected = indoc!(
1887 "
1888select
1889 text::text,
1890 num::integer,
1891 data::json,
1892 (x - y)::integer
1893from
1894 foo"
1895 );
1896
1897 assert_eq!(format(input, &QueryParams::None, &options), expected);
1898 }
1899}