(*--------------------------------------------------------------------------- Copyright (c) 2025 Thomas Gazagnaire. All rights reserved. SPDX-License-Identifier: ISC ---------------------------------------------------------------------------*) (** Rendering the query AST back to SQL text. [Render] is the inverse of the parser: its output parses to the same query, and the sqlite3 CLI runs it. *) val pp_ident : string Fmt.t (** [pp_ident ppf name] formats [name] as an identifier: bare if every character may appear in an unquoted identifier and {!Lexer.is_keyword} does not hold, and double-quoted with its quotes doubled otherwise. Use it for any name written into SQL text. It raises [Invalid_argument] if [name] holds the byte [0x00], which ends SQL text. *) val ident : string -> string (** [ident name] is [name] formatted with {!pp_ident}. *) val pp_expr : Ast.expr Fmt.t (** [pp_expr ppf e] formats [e] on [ppf] with every subexpression in parentheses. *) val pp_select : Ast.select Fmt.t (** [pp_select ppf s] formats the [SELECT] statement [s] on [ppf]. *) val expr : Ast.expr -> string (** [expr e] is [e] formatted with {!pp_expr}. *) val default_clause : Ast.expr -> string (** [default_clause e] is [e] as the text after a [DEFAULT] (parse.y, [ccons ::= DEFAULT ...]). A literal, a signed number and a [CURRENT_*] keyword are written bare, and any other expression in parentheses, since a bare call such as [DEFAULT CAST(5 AS TEXT)] is a syntax error. A {!Ast.constructor-Big_int} is in parentheses too, since bare it would read back as a real. Use it, not {!expr}, to write a schema. *) val select : Ast.select -> string (** [select s] is [s] formatted with {!pp_select}. *)