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 <ae@cy.md>
12  */
13 
14 module ae.demo.sqlite.exec;
15 
16 import std.algorithm;
17 import std.array;
18 import std.conv;
19 import std.datetime.stopwatch;
20 import std.stdio;
21 
22 import ae.sys.sqlite3;
23 import ae.sys.console;
24 import ae.utils.text;
25 
26 void main(string[] args)
27 {
28 	if (args.length < 2 || args.length > 3)
29 		return stderr.writeln("Usage: exec DATABASE [COMMAND]");
30 
31 	auto db = new SQLite(args[1]);
32 
33 	void exec(string sql, bool interactive)
34 	{
35 		int idx = 0;
36 		string[][] rows;
37 		StopWatch sw;
38 		sw.start();
39 		foreach (cells, columns; db.query(sql))
40 		{
41 			sw.stop();
42 			if (rows is null)
43 				rows ~= ["#"] ~ array(map!`a.idup`(columns));
44 			rows ~= [to!string(idx++)] ~ array(map!`a.idup`(cells));
45 			sw.start();
46 		}
47 		sw.stop();
48 		stderr.writeln("Query executed in ", sw.peek().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] = widths[i].max(cell.textWidth());
58 		}
59 		foreach (j, row; rows)
60 		{
61 			auto rowLines = row.map!splitAsciiLines().array();
62 			auto lineCount = rowLines.map!(line => line.length).fold!max(size_t(0));
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] - std.utf.count(col)));
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) nothrow
105 {
106 	return s
107 		.splitAsciiLines()
108 		.map!(std.utf.count)
109 		.fold!max(size_t(0));
110 }