Skip to content

Commit 0fd5be2

Browse files
authored
JSON Compact output
Initial solution for #1
1 parent d78d875 commit 0fd5be2

File tree

1 file changed

+57
-2
lines changed

1 file changed

+57
-2
lines changed

src/httpserver_extension.cpp

Lines changed: 57 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,15 @@
1212
#define CPPHTTPLIB_OPENSSL_SUPPORT
1313
#include "httplib.hpp"
1414

15+
// Include yyjson for JSON handling
16+
#include "yyjson.hpp"
17+
1518
#include <thread>
1619
#include <memory>
1720
#include <cstdlib>
1821

22+
using namespace duckdb_yyjson; // NOLINT
23+
1924
namespace duckdb {
2025

2126
struct HttpServerState {
@@ -30,6 +35,54 @@ struct HttpServerState {
3035

3136
static HttpServerState global_state;
3237

38+
// Convert the query result to JSON format
39+
static std::string ConvertResultToJSON(MaterializedQueryResult &result) {
40+
auto doc = yyjson_mut_doc_new(nullptr);
41+
auto root = yyjson_mut_obj(doc);
42+
yyjson_mut_doc_set_root(doc, root);
43+
44+
// Add meta information
45+
auto meta_array = yyjson_mut_arr(doc);
46+
for (idx_t col = 0; col < result.ColumnCount(); ++col) {
47+
auto column_obj = yyjson_mut_obj(doc);
48+
yyjson_mut_obj_add_str(doc, column_obj, "name", result.ColumnName(col).c_str());
49+
yyjson_mut_arr_append(meta_array, column_obj);
50+
}
51+
yyjson_mut_obj_add_val(doc, root, "meta", meta_array);
52+
53+
// Add data
54+
auto data_array = yyjson_mut_arr(doc);
55+
for (idx_t row = 0; row < result.RowCount(); ++row) {
56+
auto row_array = yyjson_mut_arr(doc);
57+
for (idx_t col = 0; col < result.ColumnCount(); ++col) {
58+
Value value = result.GetValue(col, row);
59+
if (value.IsNull()) {
60+
yyjson_mut_arr_append(row_array, yyjson_mut_null(doc));
61+
} else {
62+
std::string value_str = value.ToString();
63+
yyjson_mut_arr_append(row_array, yyjson_mut_strncpy(doc, value_str.c_str(), value_str.length()));
64+
}
65+
}
66+
yyjson_mut_arr_append(data_array, row_array);
67+
}
68+
yyjson_mut_obj_add_val(doc, root, "data", data_array);
69+
70+
// Add row count
71+
yyjson_mut_obj_add_int(doc, root, "rows", result.RowCount());
72+
73+
// Write to string
74+
auto data = yyjson_mut_write(doc, 0, nullptr);
75+
if (!data) {
76+
yyjson_mut_doc_free(doc);
77+
throw InternalException("Failed to render the result as JSON, yyjson failed");
78+
}
79+
80+
std::string json_output(data);
81+
free(data);
82+
yyjson_mut_doc_free(doc);
83+
return json_output;
84+
}
85+
3386
static void HandleQuery(const string& query, duckdb_httplib_openssl::Response& res) {
3487
try {
3588
if (!global_state.db_instance) {
@@ -45,13 +98,16 @@ static void HandleQuery(const string& query, duckdb_httplib_openssl::Response& r
4598
return;
4699
}
47100

48-
res.set_content(result->ToString(), "text/plain");
101+
// Convert result to JSON
102+
std::string json_output = ConvertResultToJSON(*result);
103+
res.set_content(json_output, "application/json");
49104
} catch (const Exception& ex) {
50105
res.status = 400;
51106
res.set_content(ex.what(), "text/plain");
52107
}
53108
}
54109

110+
55111
void HttpServerStart(DatabaseInstance& db, string_t host, int32_t port) {
56112
if (global_state.is_running) {
57113
throw IOException("HTTP server is already running");
@@ -150,7 +206,6 @@ static void LoadInternal(DatabaseInstance &instance) {
150206

151207
// Register the cleanup function to be called at exit
152208
std::atexit(HttpServerCleanup);
153-
154209
}
155210

156211
void HttpserverExtension::Load(DuckDB &db) {

0 commit comments

Comments
 (0)