myTinySQL v0.2.0-2-g5000098
A tiny SQL interpreter over fixed-width text files
Loading...
Searching...
No Matches
Output.cpp
Go to the documentation of this file.
1
3
4#include "Output.hpp"
5
6#include <format>
7
8#include "Util.hpp"
9
10namespace tinysql {
11
12namespace {
13
19std::string fit(std::string_view text, std::size_t width, char filler)
20{
21 std::string result(text.substr(0, width));
22 result.resize(width, filler);
23 return result;
24}
25
29std::string headerLine(const ResultSet& table)
30{
31 std::string line;
32 for (std::size_t i = 0; i < table.headers.size(); ++i) {
33 if (i > 0) {
34 line += ' ';
35 }
36 line += fit(table.headers[i], table.widths[i], '-');
37 }
38 return line;
39}
40
44std::string jsonString(std::string_view text)
45{
46 std::string out = "\"";
47 for (const unsigned char c : text) {
48 switch (c) {
49 case '"': out += "\\\""; break;
50 case '\\': out += "\\\\"; break;
51 case '\n': out += "\\n"; break;
52 case '\r': out += "\\r"; break;
53 case '\t': out += "\\t"; break;
54 default:
55 if (c < 0x20) {
56 out += std::format("\\u{:04x}", c); // other control characters
57 } else {
58 out += static_cast<char>(c);
59 }
60 }
61 }
62 return out + "\"";
63}
64
65} // namespace
66
67std::string renderText(const StatementResult& result)
68{
69 if (result.silent) {
70 return {};
71 }
72 std::string out = std::format("> {}\n", result.sql);
73 if (result.failed) {
74 return out + std::format("ERROR: {}\n\n", result.message);
75 }
76 if (const auto& table = result.table) {
77 out += std::string(trimRight(headerLine(*table))) + '\n';
78 for (const auto& row : table->rows) {
79 std::string line;
80 for (std::size_t i = 0; i < row.size(); ++i) {
81 if (i > 0) {
82 line += ' ';
83 }
84 line += fit(row[i], table->widths[i], ' ');
85 }
86 out += std::string(trimRight(line)) + '\n';
87 }
88 out += std::format("({})\n\n", result.message);
89 } else {
90 out += result.message + "\n\n";
91 }
92 return out;
93}
94
95std::string renderJson(const std::vector<StatementResult>& results)
96{
97 std::string out = "{\"results\":[";
98 bool first = true;
99 for (const StatementResult& result : results) {
100 if (result.silent) {
101 continue; // COLUMN and comments have nothing to show
102 }
103 out += first ? "" : ",";
104 first = false;
105 out += std::format("{{\"sql\":{},\"ok\":{},\"message\":{},\"table\":{}", jsonString(result.sql),
106 result.failed ? "false" : "true", jsonString(result.message), jsonString(result.tableName));
107
108 if (const auto& table = result.table) {
109 out += ",\"columns\":[";
110 for (std::size_t i = 0; i < table->headers.size(); ++i) {
111 // A cell can be edited when the rows have IDs, and it is a real column other than the ID.
112 const bool editable = table->idColumn && i != *table->idColumn && !table->literal[i];
113 out += std::format("{}{{\"name\":{},\"width\":{},\"editable\":{}}}", i > 0 ? "," : "",
114 jsonString(table->headers[i]), table->storageWidths[i], editable ? "true" : "false");
115 }
116 out += "],\"rows\":[";
117 for (std::size_t r = 0; r < table->rows.size(); ++r) {
118 out += r > 0 ? ",[" : "[";
119 for (std::size_t i = 0; i < table->rows[r].size(); ++i) {
120 out += (i > 0 ? "," : "") + jsonString(table->rows[r][i]);
121 }
122 out += "]";
123 }
124 out += "],\"idColumn\":" + (table->idColumn ? std::to_string(*table->idColumn) : std::string("null"));
125 }
126 out += "}";
127 }
128 return out + "]}";
129}
130
131std::string renderTablesJson(const std::vector<TableSchema>& tables)
132{
133 std::string out = "{\"tables\":[";
134 for (std::size_t t = 0; t < tables.size(); ++t) {
135 const TableSchema& table = tables[t];
136 out += std::format("{}{{\"name\":{},\"readOnly\":{},\"autoId\":{},\"columns\":[", t > 0 ? "," : "",
137 jsonString(table.name), equalsIgnoreCase(table.name, kCatalogTable) ? "true" : "false",
138 table.hasAutoId() ? "true" : "false");
139 for (std::size_t i = 0; i < table.columns.size(); ++i) {
140 out += std::format("{}{{\"name\":{},\"width\":{}}}", i > 0 ? "," : "",
141 jsonString(table.columns[i].name), table.columns[i].width());
142 }
143 out += "]}";
144 }
145 return out + "]}";
146}
147
148} // namespace tinysql
constexpr std::string_view kCatalogTable
Name of the catalogue table: it describes every table, itself included, and is its own data file.
Definition Catalog.hpp:16
Turning statement results into console text or JSON for the browser page.
std::string renderText(const StatementResult &result)
Formats one result for the console.
Definition Output.cpp:67
std::string renderTablesJson(const std::vector< TableSchema > &tables)
Builds the JSON answer of GET /api/tables: every table with its columns.
Definition Output.cpp:131
std::string renderJson(const std::vector< StatementResult > &results)
Builds the JSON answer of POST /api/sql: one object per statement that has something to show.
Definition Output.cpp:95
The SqlError exception and small string helpers used everywhere.
std::string_view trimRight(std::string_view text)
Removes trailing spaces, tabs and line ends.
Definition Util.cpp:26
bool equalsIgnoreCase(std::string_view a, std::string_view b)
Compares two strings, ignoring the case of ASCII letters.
Definition Util.cpp:49
std::string jsonString(std::string_view text)
Writes text as a JSON string: in double quotes, with quotes, backslashes and control characters escap...
Definition Output.cpp:44
std::string fit(std::string_view text, std::size_t width, char filler)
Cuts or pads text to an exact width.
Definition Output.cpp:19
std::string headerLine(const ResultSet &table)
Builds the dashed header line of a console table, e.g. ID-------- NOME----.
Definition Output.cpp:29
The rows produced by a SELECT or DESCRIBE. All per-column vectors have the same length.
Definition Session.hpp:19
std::vector< std::size_t > widths
Display width of each column in console output.
Definition Session.hpp:21
std::vector< std::string > headers
Column titles.
Definition Session.hpp:20
What running one statement produced: a table, a message, or an error.
Definition Session.hpp:29
std::string sql
The statement as it was run.
Definition Session.hpp:30
bool failed
True if the statement failed; message holds the error.
Definition Session.hpp:34
std::string message
E.g. "1 row inserted ...", or the error text.
Definition Session.hpp:33
std::optional< ResultSet > table
The rows, for SELECT and DESCRIBE.
Definition Session.hpp:32
bool silent
True for COLUMN and comments: nothing to show.
Definition Session.hpp:35
The definition of one table: its name, its columns, and the length of a row.
Definition Catalog.hpp:31
std::string name
Table name, e.g. EMPLOY.
Definition Catalog.hpp:32
bool hasAutoId() const
Tells whether rows are numbered automatically.
Definition Catalog.cpp:69
std::vector< Column > columns
Columns in file order.
Definition Catalog.hpp:33