overview: link to source
[sqlgg.git] / gen_csharp.ml
blob15183dfe860bef7c3af88d3dd587b1d3d469a1d8
1 (* C# code generation *)
3 open ExtList
4 open ExtString
5 open Operators
6 open Printf
8 open Stmt
9 open Gen
10 open Sql
12 module G = Gen_cxx
13 module J = Gen_java
14 module Values = G.Values
16 let comment = G.comment
17 let empty_line = G.empty_line
19 let comment_doc sl =
20 output "/**";
21 output_l (List.map (fun str -> Gen_caml.replace_all ~sub:"*/" ~by:"* /" ~str) sl);
22 output "*/"
24 let comment_xml summary params =
25 let summary = String.nsplit summary "\n" in
26 let params = List.map (fun (n,s) -> sprintf "<param name=\"%s\">%s</param>" n s) params in
27 comment_doc ("<summary>" :: summary @ ("</summary>" :: params))
29 let (start_class,end_class) = J.start_class,J.end_class
30 let (start_ns,end_ns) = J.start_ "namespace"
32 let quote = J.quote
34 module L = struct
36 let as_api_type = function
37 | Type.Int -> "Int64"
38 | Type.Text -> "String"
39 | Type.Float -> "Float"
40 | Type.Blob -> "String"
41 | Type.Bool -> "Boolean"
42 | Type.Datetime -> "Datetime"
43 | Type.Any -> "String"
45 let as_lang_type = as_api_type
47 end
49 module T = Translate(L)
51 open L
52 open T
54 let get_column attr index =
55 sprintf "reader.Get%s(%u)"
56 (attr.RA.domain >> as_api_type)
57 index
59 let schema_to_string = G.Values.to_string & schema_to_values
61 let output_schema_binder index schema =
62 let name = "callback" in
63 output "public delegate void %s(%s);" name (schema_to_string schema);
64 empty_line ();
65 name
67 let output_schema_binder index schema =
68 match schema with
69 | [] -> None
70 | _ -> Some (output_schema_binder index schema)
72 let set_param index param =
73 let (id,t) = param in
74 let name = default_name "param" index in
75 output "IDbDataParameter %s = _cmd.CreateParameter();" name;
76 output "%s.ParameterName = \"@%s\";" name (param_name_to_string id index);
77 output "%s.DbType = DbType.%s;" name (param_type_to_string t);
78 output "_cmd.Parameters.Add(%s);" name
80 let output_params_binder params =
81 List.iteri set_param params;
82 output "_cmd.Prepare();"
84 type t = unit
86 let start () = ()
88 let func_execute index stmt =
89 let values = params_to_values stmt.params in
90 let schema_binder_name = output_schema_binder index stmt.schema in
91 let is_select = Option.is_some schema_binder_name in
92 let doc = if is_select then ["result", schema_to_string stmt.schema] else [] in
93 comment_xml "execute query" doc;
94 let func_name = if is_select then "execute_reader" else "execute" in
95 let result = "public " ^ if is_select then "IEnumerable<IDataReader>" else "int" in
96 G.func result func_name values (fun () ->
97 output "if (null == _cmd)";
98 G.open_curly ();
99 output "_cmd = _conn.CreateCommand();";
100 output "_cmd.CommandText = sql;";
101 output_params_binder stmt.params;
102 G.close_curly "";
103 output "if (null != CommandTimeout) _cmd.CommandTimeout = CommandTimeout.Value;";
104 List.iteri
105 (fun i (name,_) -> output "((IDbDataParameter)_cmd.Parameters[%u]).Value = %s;" i name)
106 values;
107 begin match schema_binder_name with
108 | None -> output "return _cmd.ExecuteNonQuery();"
109 | Some _ ->
110 output "IDataReader reader = _cmd.ExecuteReader();";
111 output "while (reader.Read())";
112 G.open_curly ();
113 output "yield return reader;";
114 G.close_curly "";
115 output "reader.Close();";
116 end);
117 if is_select then
118 begin
119 empty_line ();
120 let result = match schema_binder_name with None -> [] | Some name -> ["result",name] in
121 let all_params = values @ result in
122 G.func "public int" "execute" all_params (fun () ->
123 let args = List.mapi (fun index attr -> get_column attr index) stmt.schema in
124 output "int count = 0;";
125 output "foreach (var reader in execute_reader(%s))" (Values.inline values);
126 G.open_curly ();
127 output "result(%s);" (Values.join args);
128 output "count++;";
129 G.close_curly "";
130 output "return count;"
132 empty_line ();
133 match stmt.schema with
134 | [attr] ->
135 let t = as_lang_type attr.RA.domain in
136 G.func ("public IEnumerable<" ^ t ^ ">") "rows" values (fun () ->
137 output "foreach (var reader in execute_reader(%s))" (Values.inline values);
138 G.open_curly ();
139 output "yield return %s;" (get_column attr 0);
140 G.close_curly ""
142 | _ ->
143 start_class "row";
144 List.iteri (fun index attr ->
145 output "public readonly %s %s;"
146 (as_lang_type attr.RA.domain)
147 (name_of attr index)
148 ) stmt.schema;
149 empty_line ();
150 G.func "public" "row" ["reader","IDataReader"] (fun () ->
151 List.iteri (fun i attr -> output "%s = %s;" (name_of attr i) (get_column attr i)) stmt.schema;
153 end_class "row";
154 G.func "public IEnumerable<row>" "rows" values (fun () ->
155 output "foreach (var reader in execute_reader(%s))" (Values.inline values);
156 G.open_curly ();
157 output "yield return new row(reader);";
158 G.close_curly ""
162 else (* not is_select *)
163 begin
164 match stmt.kind with
165 | Insert _ when List.length values > 1 ->
166 G.func "public int" "execute<T>" ["v","T"] (fun () ->
167 output "return execute(%s);" (values >> Values.names >> List.map ((^) "v.") >> Values.join)
169 | _ -> ()
173 let generate_code index stmt =
174 let name = choose_name stmt.props stmt.kind index in
175 let sql = quote (get_sql stmt) in
176 start_class name;
177 output "IDbCommand _cmd;";
178 output "IDbConnection _conn;";
179 output "public int? CommandTimeout;";
180 output "static string sql = %s;" sql;
181 empty_line ();
182 G.func "public" name ["db","IDbConnection"] (fun () ->
183 output "_cmd = null;";
184 output "_conn = db;";
186 empty_line ();
187 func_execute index stmt;
188 end_class name;
189 name
191 let generate_all names =
192 start_class "all";
193 output "public readonly IDbConnection db;";
194 List.iter (fun s -> output "public %s %s;" s s) names;
195 empty_line ();
196 G.func "public" "all" ["db","IDbConnection"] (fun () ->
197 output "this.db = db;";
198 List.iter (fun name -> output "%s = new %s(db);" name name) names
200 end_class "all"
202 let generate () name stmts =
203 params_mode := Some Named; (* only named params allowed *)
204 let using = ["System";"System.Data";"System.Collections.Generic"] in
205 List.iter (fun s -> output "using %s;" s) using;
206 empty_line ();
207 start_ns name;
208 let names = List.mapi generate_code (List.of_enum stmts) in
209 generate_all names;
210 end_ns name