wip
[sqlgg.git] / gen.ml
blobad594c00bd104e04808ad093ce811145ad68e87c
1 (* C++ code generation *)
3 open Sql
4 open Printf
5 open ExtList
7 module Cpp =
8 struct
9 type param = string * string
10 type t = param list
12 let to_string x =
13 String.concat ", " (List.map (fun (t,n) -> t ^ " " ^ n) x)
15 let inline x =
16 String.concat ", " (List.map (fun (t,n) -> n) x)
17 end
19 let (inc_indent,dec_indent,make_indent) =
20 let v = ref 0 in
21 (fun () -> v := !v + 2),
22 (fun () -> v := !v - 2),
23 (fun () -> String.make !v ' ')
25 let print_indent () = print_string (make_indent ())
26 let print_fmt fmt = Printf.kprintf print_endline fmt
27 let print_prefix prefix fmt = print_indent (); print_string prefix; print_fmt fmt
28 let empty_line () = print_indent (); print_newline ()
29 let output fmt = print_prefix "" fmt
30 let comment fmt = print_prefix "// " fmt
31 let output_str s = print_indent (); print_endline s
32 let open_curly () = output "{"; inc_indent ()
33 let close_curly fmt = dec_indent (); print_prefix "}" fmt
34 let start_struct name =
35 output "struct %s" name;
36 open_curly ()
37 let end_struct name =
38 close_curly "; // struct %s" name;
39 output ""
40 let out_public () = dec_indent(); output "public:"; inc_indent()
41 let out_private () = dec_indent(); output "private:"; inc_indent()
42 let in_namespace name f =
43 output "namespace %s" name;
44 open_curly ();
45 f ();
46 close_curly " // namespace %s" name;
47 output ""
49 let generate_header () =
50 output "// DO NOT EDIT MANUALLY";
51 output "";
52 output "// generated by sql2cpp";
53 output "";
54 output "#pragma once";
55 output ""
58 let ns_name table = table.Table.cpp_name
59 let item_name _ = "row"
60 let prefix_name _ = ""
63 let set_column_code attr index =
64 sprintf "Traits::set_column_%s(stmt, %u, obj.%s);"
65 (Type.to_string attr.RA.domain)
66 index
67 attr.RA.name
69 let get_column_code attr index =
70 sprintf "Traits::get_column_%s(stmt, %u, obj.%s);"
71 (Type.to_string attr.RA.domain)
72 index
73 attr.RA.name
75 open Stmt.Raw
77 let set_param_code param index =
78 let (id,t) = param in
79 sprintf "Traits::set_param_%s(stmt, obj.%s, %u);"
80 (Option.map_default Type.to_string "Any" t)
81 (match id with
82 | Next -> sprintf "_%u" index
83 | Numbered x -> sprintf "_%u" x
84 | Named s -> s)
85 index
87 let output_scheme_binder index scheme =
88 let name = sprintf "binder_%u" index in
89 output "template <class T>";
90 start_struct name;
92 output "static void of_stmt(sqlite3_stmt* stmt, T& obj)";
93 open_curly ();
94 List.iteri (fun index attr -> output_str (get_column_code attr index)) scheme;
95 close_curly "";
97 output "static void to_stmt(sqlite3_stmt* stmt, const T& obj)";
98 open_curly ();
99 List.iteri (fun index attr -> output_str (set_column_code attr (index + 1))) scheme;
100 close_curly "";
101 end_struct name;
102 name
104 let output_scheme_binder i s = in_namespace "detail" (fun () -> output_scheme_binder i s)
106 let generate_table_code table =
107 out_public ();
108 start_struct (item_name table);
109 List.iter
110 (fun col -> output (sprintf "%s %s;" (Col.type_to_cpp_string col) col.Col.cpp_name))
111 table.Table.cols;
112 end_struct (item_name table)
114 let make_const_params inputs =
115 (List.map (fun (name,t) -> (sprintf "const %s&" (Type.to_cpp_string t)),name) inputs)
117 let output_extra_param_defs placeholders =
118 List.iter (fun (name,t) -> output (sprintf "const %s& %s_;" (Type.to_cpp_string t) name)) placeholders
120 let output_extra_params_init names =
121 match names with
122 | [] -> ()
123 | _ -> output (" : " ^ (String.concat "," (List.map (fun name -> sprintf "%s_(%s)" name name) names)))
125 let output_params_binder binder_index cols_binder ofs inputs =
126 out_private ();
127 let name = (sprintf "params_binder_%u" binder_index) in
128 start_struct name;
129 output_extra_param_defs inputs;
130 begin match cols_binder with
131 | Some binder -> output (sprintf "const row& obj_;")
132 | None -> ()
133 end;
134 output "";
135 let params = (match cols_binder with | Some binder -> [sprintf "const row&","obj"] | None -> []) @
136 (make_const_params inputs)
138 output (sprintf "%s(%s)" name (Cpp.to_string params));
139 let names = List.map (fun (name,_) -> name) inputs in
140 let names = (match cols_binder with | Some _ -> "obj"::names | None -> names) in
141 output_extra_params_init names;
142 open_curly ();
143 close_curly "";
144 output "";
145 output (sprintf "void set_params(sqlite3_stmt* stmt)");
146 open_curly ();
147 begin match cols_binder with
148 | Some binder -> output (sprintf "%s::to_stmt(stmt,obj_);" binder)
149 | None -> ()
150 end;
151 List.iteri (fun index param -> output (param_binder_code (index+1+ofs) param)) inputs;
152 close_curly "";
153 output "";
154 end_struct name;
155 name
157 let output_params_binder index table cols inputs =
158 let binder_name = (match cols with
159 | [] -> None
160 | _ -> Some (output_scheme_binder table cols index))
162 match binder_name,inputs with
163 | None,[] -> "typename Traits::no_params"
164 | _,_ -> output_params_binder index binder_name (List.length cols) inputs
166 let make_name props default =
167 match Props.get props "name" with
168 | Some v -> v
169 | None -> default
171 let default_name table str index = sprintf "%s%s_%u" (prefix_name table) str index
174 let generate_select_code index scheme params =
175 let scheme_binder_name = output_scheme_binder index scheme in
176 ignore (scheme_binder_name);
177 (* let params_binder_name = output_params_binder index params in *)
179 out_public ();
180 output "template<class T>";
181 let params = Cpp.Params.to_string
182 (["sqlite3*","db"; "T&","result"] @ (make_const_params inputs))
184 let name = make_name props (default_name table "select" index) in
185 output
186 (sprintf "static bool %s(%s)" name params);
187 open_curly ();
188 output
189 (sprintf "return Traits::do_select(db,result,_T(\"%s\"),%s(),%s(%s));"
190 sql binder_name params_binder_name (Cpp.Params.inline (make_const_params inputs)));
191 close_curly "";
193 output ""
195 let generate_insert_code columns table index (placeholders,props) sql =
196 out_public ();
197 let name = make_name props (default_name table "insert" index) in
198 output (sprintf "static bool %s(sqlite3* db, const %s& val)" name (item_name table));
199 open_curly ();
200 output (sprintf "return Traits::do_insert<binder_%s>(db,val,_T(\"%s\"));" (item_name table) sql);
201 close_curly "";
202 output ""
206 let generate_modify_code table cols inputs index props sql =
207 (* if there is only one input column - do not require full object as a param *)
208 let (cols,inputs) = match cols with
209 | [(x,_)] -> [],(x.Sql.Col.name,x.Sql.Col.sqltype)::inputs
210 | _ -> cols,inputs
212 let params_binder_name = output_params_binder index table cols inputs in
213 out_public ();
214 let data_params = make_const_params inputs in
215 let data_params = (match cols with
216 | [] -> data_params
217 | _ -> ((sprintf "const %s&" (item_name table)),"val")::data_params)
219 let params = Cpp.Params.to_string (("sqlite3*","db") :: data_params) in
220 let name = make_name props (default_name table "modify" index) in
221 output (sprintf "static int %s(%s)" name params);
222 open_curly ();
223 output (sprintf "return Traits::do_execute(db,\"%s\",%s(%s));" sql
224 params_binder_name (Cpp.inline data_params));
225 close_curly "";
226 output ""
228 let generate_delete_code table inputs index props sql =
229 let params_binder_name = output_params_binder index table [] inputs in
230 out_public ();
231 let data_params = make_const_params inputs in
232 let params = Cpp.Params.to_string (("sqlite3*","db") :: data_params) in
233 let name = make_name props (default_name table "delete" index) in
234 output (sprintf "static int %s(%s)" name params);
235 open_curly ();
236 output (sprintf "return Traits::do_execute(db,\"%s\",%s(%s));" sql
237 params_binder_name (Cpp.Params.inline data_params));
238 close_curly "";
239 output ""
241 let generate_create_code table sql =
242 out_public ();
243 output (sprintf "static int %screate(sqlite3* db)" (prefix_name table));
244 open_curly ();
245 output (sprintf "return Traits::do_execute(db,\"%s\",typename Traits::no_params());" sql);
246 close_curly "";
247 output ""
250 let generate_code index stmt =
251 let ((scheme,params),props) = stmt in
252 generate_select_code index scheme params
254 let process stmts =
256 let generate_code index stmt =
257 let (kind,table,props,sql) = stmt in
258 match kind with
259 | Stmt.Create -> generate_table_code table;
260 generate_create_code table sql
261 | Stmt.Select (outputs,exprs,inputs) ->
262 generate_select_code table inputs outputs index props sql
263 | Stmt.Modify (cols,inputs) -> generate_modify_code table cols inputs index props sql
264 | Stmt.Delete (inputs) -> generate_delete_code table inputs index props sql
267 generate_header ();
268 output "namespace sql2cpp";
269 open_curly ();
270 List.iteri generate_code stmts;
271 close_curly " // namespace sql2cpp"