SQL frontend over the catalog engine
1(*---------------------------------------------------------------------------
2 Copyright (c) 2025 Thomas Gazagnaire. All rights reserved.
3 SPDX-License-Identifier: ISC
4 ---------------------------------------------------------------------------*)
5
6(** Tests for {!Sql.Render}: rendering the query AST back to SQL text.
7 Expression rendering is fully parenthesised, and rendering a parsed SELECT
8 is stable under a re-parse. *)
9
10module R = Sql.Render
11module A = Sql.Ast
12
13let select sql =
14 match Sql.Lexer.parse_statements sql with
15 | Ok [ A.Select s ] -> s
16 | Ok _ -> Fmt.failwith "not a single SELECT: %s" sql
17 | Error e -> Fmt.failwith "parse error: %s" e
18
19let test_expr () =
20 Alcotest.(check string)
21 "arithmetic is fully parenthesised" "(1 + 2)"
22 (R.expr (A.Binary (A.Add, A.Lit (A.Int 1L), A.Lit (A.Int 2L))));
23 Alcotest.(check string)
24 "a text literal is single-quoted" "'hi'"
25 (R.expr (A.Lit (A.Text "hi")));
26 Alcotest.(check string)
27 "a qualified column" "t.c"
28 (R.expr (A.Col (Some "t", "c")));
29 Alcotest.(check string)
30 "IS NULL" "(x IS NULL)"
31 (R.expr (A.Is_null (A.Col (None, "x"))))
32
33let test_select_roundtrip () =
34 (* Rendering a parsed SELECT yields SQL that re-parses to the same AST, so a
35 second render is byte-identical. *)
36 let sql = "SELECT a, b FROM t WHERE a = 1 ORDER BY b" in
37 let r1 = R.select (select sql) in
38 let r2 = R.select (select r1) in
39 Alcotest.(check string) "render is stable under re-parse" r1 r2
40
41let suite =
42 ( "render",
43 [
44 Alcotest.test_case "expression rendering" `Quick test_expr;
45 Alcotest.test_case "select render is stable" `Quick test_select_roundtrip;
46 ] )