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 }