1 /**
2  * ae.demo.sqlite.exec
3  *
4  * License:
5  *   This Source Code Form is subject to the terms of
6  *   the Mozilla Public License, v. 2.0. If a copy of
7  *   the MPL was not distributed with this file, You
8  *   can obtain one at http://mozilla.org/MPL/2.0/.
9  *
10  * Authors:
11  *   Vladimir Panteleev <vladimir@thecybershadow.net>
12  */
13 
14 module ae.demo.sqlite.exec;
15 
16 import std.stdio;
17 import std.algorithm;
18 import std.array;
19 import std.conv;
20 import std.datetime;
21 
22 import ae.sys.sqlite3;
23 import ae.sys.console;
24 
25 void main(string[] args)
26 {
27 	if (args.length < 2 || args.length > 3)
28 		return stderr.writeln("Usage: exec DATABASE [COMMAND]");
29 
30 	auto db = new SQLite(args[1]);
31 
32 	void exec(string sql, bool interactive)
33 	{
34 		int idx = 0;
35 		string[][] rows;
36 		StopWatch sw;
37 		sw.start();
38 		foreach (cells, columns; db.query(sql))
39 		{
40 			sw.stop();
41 			if (rows is null)
42 				rows ~= ["#"] ~ array(map!`a.idup`(columns));
43 			rows ~= [to!string(idx++)] ~ array(map!`a.idup`(cells));
44 			sw.start();
45 		}
46 		sw.stop();
47 		if (interactive || rows.length == 0)
48 			stderr.writeln("Query executed in ", dur!"hnsecs"(sw.peek().hnsecs).toString().replace("μ", "u"));
49 
50 		if (rows.length == 0)
51 			return;
52 		auto widths = new size_t[rows[0].length];
53 		foreach (row; rows)
54 		{
55 			assert(row.length == rows[0].length);
56 			foreach (i, cell; row)
57 				widths[i] = max(widths[i], textWidth(cell));
58 		}
59 		foreach (j, row; rows)
60 		{
61 			auto rowLines = array(map!textLines(row));
62 			auto lineCount = reduce!max(map!`a.length`(rowLines));
63 
64 			foreach (line; 0..lineCount)
65 			{
66 				foreach (i, lines; rowLines)
67 				{
68 					if (i) write(" │ ");
69 					string col = line < lines.length ? lines[line] : null;
70 					write(col, std.array.replicate(" ", widths[i]-col.length));
71 				}
72 				writeln();
73 			}
74 			if (j==0)
75 			{
76 				foreach (i, w; widths)
77 				{
78 					if (i) write("─┼─");
79 					write(std.array.replicate("─", w));
80 				}
81 				writeln();
82 			}
83 		}
84 		writeln();
85 	}
86 
87 	if (args.length == 3)
88 		exec(args[2], false);
89 	else
90 		while (!stdin.eof())
91 		{
92 			write("sqlite> ");
93 			stdout.flush();
94 			try
95 				exec(readln().chomp(), true);
96 			catch (Exception e)
97 				writeln(e.msg);
98 		}
99 }
100 
101 import std.utf;
102 import std.string;
103 
104 size_t textWidth(string s)
105 {
106 	try
107 	{
108 		auto lines = splitLines(s);
109 		size_t w = 0;
110 		foreach (line; lines)
111 			w = max(w, std.utf.count(line));
112 		return w;
113 	}
114 	catch (Exception e)
115 		return s.length;
116 }
117 
118 string[] textLines(string s)
119 {
120 	try
121 		return splitLines(s);
122 	catch (Exception e)
123 		return [s];
124 }