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 		stderr.writeln("Query executed in ", dur!"hnsecs"(sw.peek().hnsecs).toString().replace("μ", "u"));
48 
49 		if (rows.length == 0)
50 			return;
51 		auto widths = new size_t[rows[0].length];
52 		foreach (row; rows)
53 		{
54 			assert(row.length == rows[0].length);
55 			foreach (i, cell; row)
56 				widths[i] = max(widths[i], textWidth(cell));
57 		}
58 		foreach (j, row; rows)
59 		{
60 			auto rowLines = array(map!textLines(row));
61 			auto lineCount = reduce!max(map!`a.length`(rowLines));
62 
63 			foreach (line; 0..lineCount)
64 			{
65 				foreach (i, lines; rowLines)
66 				{
67 					if (i) write(" │ ");
68 					string col = line < lines.length ? lines[line] : null;
69 					write(col, std.array.replicate(" ", widths[i]-col.length));
70 				}
71 				writeln();
72 			}
73 			if (j==0)
74 			{
75 				foreach (i, w; widths)
76 				{
77 					if (i) write("─┼─");
78 					write(std.array.replicate("─", w));
79 				}
80 				writeln();
81 			}
82 		}
83 		writeln();
84 	}
85 
86 	if (args.length == 3)
87 		exec(args[2], false);
88 	else
89 		while (!stdin.eof())
90 		{
91 			write("sqlite> ");
92 			stdout.flush();
93 			try
94 				exec(readln().chomp(), true);
95 			catch (Exception e)
96 				writeln(e.msg);
97 		}
98 }
99 
100 import std.utf;
101 import std..string;
102 
103 size_t textWidth(string s)
104 {
105 	try
106 	{
107 		auto lines = splitLines(s);
108 		size_t w = 0;
109 		foreach (line; lines)
110 			w = max(w, std.utf.count(line));
111 		return w;
112 	}
113 	catch (Exception e)
114 		return s.length;
115 }
116 
117 string[] textLines(string s)
118 {
119 	try
120 		return splitLines(s);
121 	catch (Exception e)
122 		return [s];
123 }