preliminary support for expressions in column set
[sqlgg.git] / gen.ml
blob1fb82f1eaf73a6c954fe5c446abc4f72c58971fd
1 (* $Id$ *)
3 open Sql
4 open Printf
5 open ExtList
7 module Cpp =
8 struct
9 module Params =
10 struct
11 type param = string * string
12 type t = param list
14 let to_string x =
15 String.concat ", " (List.map (fun (t,n) -> t ^ " " ^ n) x)
17 let inline x =
18 String.concat ", " (List.map (fun (t,n) -> n) x)
19 end
20 end
22 let indent = ref 0
23 let output s = print_string (String.make !indent ' '); print_endline s
24 let out_shr () = indent := !indent + 2
25 let out_shl () = indent := !indent - 2
26 let open_curly () = output "{"; out_shr ()
27 let close_curly s = out_shl (); output ("}" ^ s)
28 let start_struct name =
29 output (sprintf "struct %s" name);
30 open_curly ()
31 let end_struct name =
32 close_curly (sprintf "; // struct %s" name);
33 output ""
34 let out_public () = out_shl (); output "public:"; out_shr ()
35 let out_private () = out_shl (); output "private:"; out_shr ()
37 let generate_header () =
38 output "// DO NOT EDIT MANUALLY";
39 output "";
40 output "// generated by sql2cpp";
41 output "";
42 output "#pragma once";
43 output ""
45 let ns_name table = table.Table.cpp_name
46 let item_name _ = "row"
47 let prefix_name _ = ""
49 let binder_code col index =
50 sprintf "Traits::bind_column_%s(stmt, %u, obj.%s);"
51 (Col.type_to_string col)
52 index
53 col.Col.cpp_name
55 let param_binder_code index (name,t) =
56 sprintf "Traits::bind_param_%s(stmt, %s_, %u);"
57 (Type.to_string t)
58 name
59 index
61 let binder_code_to col index =
62 if Col.is_primary_key col then
63 sprintf "Traits::bind_param_null(stmt, %u);" index
64 else
65 sprintf "Traits::bind_param_%s(stmt, obj.%s, %u);"
66 (Col.type_to_string col)
67 col.Col.cpp_name
68 index
70 (** naive *)
71 let output_columns_binder table columns binder_index =
72 let name = sprintf "binder_%u" binder_index in
73 out_private ();
74 start_struct name;
75 output (sprintf "typedef %s value_type;" (item_name table));
76 output (sprintf "static void of_stmt(sqlite3_stmt* stmt, %s& obj)" (item_name table));
77 open_curly ();
78 List.iteri
79 (fun index (col,tbl) -> assert(tbl=table); output (binder_code col index))
80 columns;
81 close_curly "";
82 output (sprintf "static void to_stmt(sqlite3_stmt* stmt, const %s& obj)" (item_name table));
83 open_curly ();
84 List.iteri
85 (fun index (col,tbl) -> assert(tbl=table); output (binder_code_to col (index + 1)))
86 columns;
87 close_curly "";
88 end_struct name;
89 name
91 let generate_table_code table =
92 out_public ();
93 start_struct (item_name table);
94 List.iter
95 (fun col -> output (sprintf "%s %s;" (Col.type_to_cpp_string col) col.Col.cpp_name))
96 table.Table.cols;
97 end_struct (item_name table)
99 let make_const_params inputs =
100 (List.map (fun (name,t) -> (sprintf "const %s&" (Type.to_cpp_string t)),name) inputs)
102 let output_extra_param_defs placeholders =
103 List.iter (fun (name,t) -> output (sprintf "const %s& %s_;" (Type.to_cpp_string t) name)) placeholders
105 let output_extra_params_init names =
106 match names with
107 | [] -> ()
108 | _ -> output (" : " ^ (String.concat "," (List.map (fun name -> sprintf "%s_(%s)" name name) names)))
110 let output_params_binder binder_index cols_binder ofs inputs =
111 out_private ();
112 let name = (sprintf "params_binder_%u" binder_index) in
113 start_struct name;
114 output_extra_param_defs inputs;
115 begin match cols_binder with
116 | Some binder -> output (sprintf "const row& obj_;")
117 | None -> ()
118 end;
119 output "";
120 let params = (match cols_binder with | Some binder -> [sprintf "const row&","obj"] | None -> []) @
121 (make_const_params inputs)
123 output (sprintf "%s(%s)" name (Cpp.Params.to_string params));
124 let names = List.map (fun (name,_) -> name) inputs in
125 let names = (match cols_binder with | Some _ -> "obj"::names | None -> names) in
126 output_extra_params_init names;
127 open_curly ();
128 close_curly "";
129 output "";
130 output (sprintf "void set_params(sqlite3_stmt* stmt)");
131 open_curly ();
132 begin match cols_binder with
133 | Some binder -> output (sprintf "%s::to_stmt(stmt,obj_);" binder)
134 | None -> ()
135 end;
136 List.iteri (fun index param -> output (param_binder_code (index+1+ofs) param)) inputs;
137 close_curly "";
138 output "";
139 end_struct name;
140 name
142 let make_params_binder index table cols inputs =
143 let binder_name = (match cols with
144 | [] -> None
145 | _ -> Some (output_columns_binder table cols index))
147 match binder_name,inputs with
148 | None,[] -> "typename Traits::no_params"
149 | _,_ -> output_params_binder index binder_name (List.length cols) inputs
151 let make_name props default =
152 match Props.get props "name" with
153 | Some v -> v
154 | None -> default
156 let default_name table str index = sprintf "%s%s_%u" (prefix_name table) str index
158 let generate_select_code table inputs outputs index props sql =
159 let binder_name = output_columns_binder table outputs index in
160 let params_binder_name = make_params_binder index table [] inputs in
161 out_public ();
162 output "template<class T>";
163 let params = Cpp.Params.to_string
164 (["sqlite3*","db"; "T&","result"] @ (make_const_params inputs))
166 let name = make_name props (default_name table "select" index) in
167 output
168 (sprintf "static bool %s(%s)" name params);
169 open_curly ();
170 output
171 (sprintf "return Traits::do_select(db,result,_T(\"%s\"),%s(),%s(%s));"
172 sql binder_name params_binder_name (Cpp.Params.inline (make_const_params inputs)));
173 close_curly "";
174 output ""
176 let generate_insert_code columns table index (placeholders,props) sql =
177 out_public ();
178 let name = make_name props (default_name table "insert" index) in
179 output (sprintf "static bool %s(sqlite3* db, const %s& val)" name (item_name table));
180 open_curly ();
181 output (sprintf "return Traits::do_insert<binder_%s>(db,val,_T(\"%s\"));" (item_name table) sql);
182 close_curly "";
183 output ""
186 let generate_modify_code table cols inputs index props sql =
187 (* if there is only one input column - do not require full object as a param *)
188 let (cols,inputs) = match cols with
189 | [(x,_)] -> [],(x.Sql.Col.name,x.Sql.Col.sqltype)::inputs
190 | _ -> cols,inputs
192 let params_binder_name = make_params_binder index table cols inputs in
193 out_public ();
194 let data_params = make_const_params inputs in
195 let data_params = (match cols with
196 | [] -> data_params
197 | _ -> ((sprintf "const %s&" (item_name table)),"val")::data_params)
199 let params = Cpp.Params.to_string (("sqlite3*","db") :: data_params) in
200 let name = make_name props (default_name table "modify" index) in
201 output (sprintf "static int %s(%s)" name params);
202 open_curly ();
203 output (sprintf "return Traits::do_execute(db,\"%s\",%s(%s));" sql
204 params_binder_name (Cpp.Params.inline data_params));
205 close_curly "";
206 output ""
208 let generate_delete_code table inputs index props sql =
209 let params_binder_name = make_params_binder index table [] inputs in
210 out_public ();
211 let data_params = make_const_params inputs in
212 let params = Cpp.Params.to_string (("sqlite3*","db") :: data_params) in
213 let name = make_name props (default_name table "delete" index) in
214 output (sprintf "static int %s(%s)" name params);
215 open_curly ();
216 output (sprintf "return Traits::do_execute(db,\"%s\",%s(%s));" sql
217 params_binder_name (Cpp.Params.inline data_params));
218 close_curly "";
219 output ""
221 let generate_create_code table sql =
222 out_public ();
223 output (sprintf "static int %screate(sqlite3* db)" (prefix_name table));
224 open_curly ();
225 output (sprintf "return Traits::do_execute(db,\"%s\",typename Traits::no_params());" sql);
226 close_curly "";
227 output ""
229 let process stmts =
230 generate_header ();
231 let generate_code index stmt =
232 let (kind,table,props,sql) = stmt in
233 match kind with
234 | Stmt.Create -> generate_table_code table;
235 generate_create_code table sql
236 | Stmt.Select (outputs,exprs,inputs) ->
237 generate_select_code table inputs outputs index props sql
238 | Stmt.Modify (cols,inputs) -> generate_modify_code table cols inputs index props sql
239 | Stmt.Delete (inputs) -> generate_delete_code table inputs index props sql
241 let rec do_process stmts =
242 match stmts with
243 | [] -> ()
244 | (_,t,_,_)::_ ->
245 let (some, other) = List.partition (fun (_,table,_,_) -> table = t) stmts in
246 output "template<class Traits>";
247 start_struct (ns_name t);
248 List.iteri generate_code some;
249 end_struct (ns_name t);
250 do_process other
252 output "namespace sql2cpp";
253 open_curly ();
254 do_process stmts;
255 close_curly " // namespace sql2cpp"