prelude.ml, cleanup
[sqlgg.git] / src / gen.ml
blob3cf0b7a07889899bfe0d0e59b4bbdcf2fbdeb020
1 (* Code generation *)
3 open Printf
4 open ExtLib
5 open Prelude
6 open Stmt
8 type subst_mode = | Named | Unnamed | Oracle
10 (** defines substitution function for parameter literals *)
11 let params_mode = ref None
13 let (inc_indent,dec_indent,make_indent) =
14 let v = ref 0 in
15 (fun () -> v := !v + 2),
16 (fun () -> v := !v - 2),
17 (fun () -> String.make !v ' ')
19 let print_indent () = print_string (make_indent ())
20 let indent s = print_indent (); print_string s
21 let indent_endline s = print_indent (); print_endline s
22 let output fmt = kprintf indent_endline fmt
23 let output_l = List.iter indent_endline
24 let print fmt = kprintf print_endline fmt
25 let indented k = inc_indent (); k (); dec_indent ()
27 let name_of attr index =
28 match attr.RA.name with
29 | "" -> sprintf "_%u" index
30 | s -> s
32 let param_name_to_string ((name,_):param_id) index =
33 match name with
34 | None -> sprintf "_%u" index
35 | Some s -> s
37 let make_name props default = Option.default default (Props.get props "name")
38 let default_name str index = sprintf "%s_%u" str index
40 let choose_name props kind index =
41 let name = match kind with
42 | Create t -> sprintf "create_%s" t
43 | CreateIndex t -> sprintf "create_index_%s" t
44 | Update (Some t) -> sprintf "update_%s_%u" t index
45 | Update None -> sprintf "update_%u" index
46 | Insert (_,t) -> sprintf "insert_%s_%u" t index
47 | Delete t -> sprintf "delete_%s_%u" t index
48 | Alter t -> sprintf "alter_%s_%u" t index
49 | Drop t -> sprintf "drop_%s" t
50 | Select _ -> sprintf "select_%u" index
51 | Other -> sprintf "statement_%u" index
53 make_name props name
55 let substitute_params s params f =
56 let index = ref 0 in
57 let b = Buffer.create (String.length s) in
58 let last = List.fold_left (fun i ((_,(i1,i2)),_ as param) ->
59 let prefix = String.slice ~first:i ~last:i1 s in
60 Buffer.add_string b prefix;
61 Buffer.add_string b (f !index param);
62 incr index;
63 i2) 0 params in
64 Buffer.add_string b (String.slice ~first:last s);
65 Buffer.contents b
67 let subst_named index (id,_) = "@" ^ (param_name_to_string id index)
68 let subst_oracle index (id,_) = ":" ^ (param_name_to_string id index)
69 let subst_unnamed _ _ = "?"
71 let get_sql stmt =
72 let sql = Props.get stmt.props "sql" >> Option.get in
73 match !params_mode with
74 | None -> sql
75 | Some subst ->
76 let f = match subst with
77 | Named -> subst_named
78 | Unnamed -> subst_unnamed
79 | Oracle -> subst_oracle
81 substitute_params sql stmt.params f
83 let time_string () =
84 let module U = Unix in
85 let t = U.time () >> U.gmtime in
86 sprintf "%04u-%02u-%02uT%02u:%02uZ" (1900 + t.U.tm_year) (t.U.tm_mon+1) t.U.tm_mday t.U.tm_hour t.U.tm_min
88 module type LangTypes = sig
90 val as_api_type : Sql.Type.t -> string
91 val as_lang_type : Sql.Type.t -> string
93 end
95 module Translate(T : LangTypes) = struct
97 let param_type_to_string = T.as_api_type
98 let schema_to_values = List.mapi (fun i attr -> name_of attr i, T.as_lang_type attr.RA.domain)
99 (* let schema_to_string = G.Values.to_string $ schema_to_values *)
100 let all_params_to_values = List.mapi (fun i (n,t) -> param_name_to_string n i, T.as_lang_type t)
101 (* rev unique rev -- to preserve ordering with respect to first occurrences *)
102 let params_to_values = List.rev $ List.unique $ List.rev $ all_params_to_values
106 module type Generator = sig
107 type t
108 val generate : t -> string -> Stmt.t Enum.t -> unit
109 val start : unit -> t
110 val comment : t -> ('a,unit,string,unit) format4 -> 'a
111 val empty_line : t -> unit
114 module Make(S : Generator) = struct
116 let generate_header out =
117 S.comment out "DO NOT EDIT MANUALLY";
118 S.comment out "";
119 S.comment out "generated by sqlgg %s on %s" Config.version (time_string ());
120 S.comment out "visit http://ygrek.org.ua/p/sqlgg/";
121 S.empty_line out
123 let process name stmts =
124 let out = S.start () in
125 generate_header out;
126 S.generate out name stmts