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.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 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 ", 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] = 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 }