SQL frontend over the catalog engine
1(** A generic interactive SQL shell, fed one input line at a time so it suits
2 both a blocking stdin REPL and an event-driven transport (a network channel,
3 say). The storage backend supplies statement execution and table listing;
4 this module owns the line accumulation, dot commands, result rendering (via
5 {!Console.Table}) and prompts. *)
6
7(** One rendered piece of a statement's output. A single statement may produce
8 several (a note then a status, say), so {!BACKEND.exec} returns a list. *)
9type output =
10 | Rows of string list option * string list list
11 (** result rows as text, with optional column headers; rendered as a
12 {!Console.Table} followed by a row count *)
13 | Status of string
14 (** a write's one-line status, e.g. ["3 rows"]; rendered as ["ok ..."] *)
15 | Note of string (** a dimmed aside, e.g. ["(created table users)"] *)
16 | Raw of string (** a line emitted verbatim, e.g. an EXPLAIN access path *)
17
18module type BACKEND = sig
19 type t
20 (** A handle on the SQL store. *)
21
22 val exec : t -> string -> (output list, string) result
23 (** [exec t sql] runs one complete SQL statement, returning its output pieces
24 in render order, or an error rendered as ["error: ..."]. *)
25
26 val tables : t -> (string * int) list
27 (** [tables t] lists each table with its row count, for [.tables]. *)
28
29 val dot : t -> string -> string option
30 (** [dot t cmd] runs a backend-specific dot command [cmd] (the word after the
31 leading dot, e.g. ["log"]) and returns its rendered output, or [None] when
32 the command is not one the backend knows. *)
33
34 val help : string
35 (** Extra [.help] lines describing the backend's dot commands and dialect. *)
36
37 val banner : t -> string
38 (** The greeting shown when an interactive session starts. *)
39end
40
41type t
42(** A live shell session. *)
43
44val start : t -> unit
45(** [start t] emits the banner and the first prompt. *)
46
47val feed_line : t -> string -> [ `Continue | `Quit ]
48(** [feed_line t line] processes one input line: a dot command, a blank line, or
49 a fragment of a statement accumulated until its terminating [;]. It emits
50 any result and the next prompt, and returns [`Quit] on [.quit]/[.exit]. *)
51
52val feed_statement : t -> string -> unit
53(** [feed_statement t sql] runs one complete statement: it appends a terminating
54 [;] when [sql] lacks one, then feeds each line through {!feed_line}. A
55 caller executing a single statement -- an [ssh host 'SELECT ...'] exec, a
56 [-c] flag -- need not replicate the line accumulation. *)
57
58module Make (B : BACKEND) : sig
59 val v :
60 B.t ->
61 ?emit_err:(string -> unit) ->
62 styled:bool ->
63 ctx:Console.Display.ctx ->
64 emit:(string -> unit) ->
65 unit ->
66 t
67 (** [v backend ~styled ~ctx ~emit] is a fresh shell over [backend], writing
68 every byte of output through [emit]. [styled] enables ANSI colour and the
69 prompt (turn it off behind a pipe); [ctx] supplies the terminal dimensions
70 used by row tables. Lines end in ['\n'], so a transport that needs CRLF
71 translates inside [emit]. Statement errors go through [emit_err] (default
72 [emit]), so a non-interactive caller can route them to stderr and keep
73 stdout a clean result stream. *)
74end