|
6 | 6 | #include <iostream> |
7 | 7 | #include <napi.h> |
8 | 8 |
|
| 9 | +typedef void * ChdbConnection; |
| 10 | +ChdbConnection CreateConnection(const char * path); |
| 11 | +void CloseConnection(ChdbConnection conn); |
| 12 | +char * QueryWithConnection(ChdbConnection conn, const char * query, const char * format, char ** error_message); |
| 13 | + |
9 | 14 | #define MAX_FORMAT_LENGTH 64 |
10 | 15 | #define MAX_PATH_LENGTH 4096 |
11 | 16 | #define MAX_ARG_COUNT 6 |
@@ -189,6 +194,56 @@ char *QueryBindSession(const char *query, const char *format, const char *path, |
189 | 194 | return query_stable_v2(static_cast<int>(argv.size()), argv.data())->buf; |
190 | 195 | } |
191 | 196 |
|
| 197 | +ChdbConnection CreateConnection(const char * path) { |
| 198 | + char dataPath[MAX_PATH_LENGTH]; |
| 199 | + char * args[MAX_ARG_COUNT] = {"clickhouse", NULL}; |
| 200 | + int argc = 1; |
| 201 | + |
| 202 | + if (path && path[0]) { |
| 203 | + construct_arg(dataPath, "--path=", path, MAX_PATH_LENGTH); |
| 204 | + args[1] = dataPath; |
| 205 | + argc = 2; |
| 206 | + } |
| 207 | + |
| 208 | + return static_cast<ChdbConnection>(chdb_connect(argc, args)); |
| 209 | +} |
| 210 | + |
| 211 | +void CloseConnection(ChdbConnection conn) { |
| 212 | + if (conn) { |
| 213 | + chdb_close_conn(static_cast<chdb_connection *>(conn)); |
| 214 | + } |
| 215 | +} |
| 216 | + |
| 217 | +char * QueryWithConnection(ChdbConnection conn, const char * query, const char * format, char ** error_message) { |
| 218 | + if (!conn || !query || !format) { |
| 219 | + return nullptr; |
| 220 | + } |
| 221 | + |
| 222 | + chdb_connection * inner_conn = static_cast<chdb_connection *>(conn); |
| 223 | + chdb_result * result = chdb_query(*inner_conn, query, format); |
| 224 | + if (!result) { |
| 225 | + return nullptr; |
| 226 | + } |
| 227 | + |
| 228 | + const char * error = chdb_result_error(result); |
| 229 | + if (error) { |
| 230 | + if (error_message) { |
| 231 | + *error_message = strdup(error); |
| 232 | + } |
| 233 | + chdb_destroy_query_result(result); |
| 234 | + return nullptr; |
| 235 | + } |
| 236 | + |
| 237 | + const char * buffer = chdb_result_buffer(result); |
| 238 | + char * output = nullptr; |
| 239 | + if (buffer) { |
| 240 | + output = strdup(buffer); |
| 241 | + } |
| 242 | + |
| 243 | + chdb_destroy_query_result(result); |
| 244 | + return output; |
| 245 | +} |
| 246 | + |
192 | 247 | Napi::String QueryWrapper(const Napi::CallbackInfo &info) { |
193 | 248 | Napi::Env env = info.Env(); |
194 | 249 |
|
@@ -291,11 +346,81 @@ Napi::String QueryBindSessionWrapper(const Napi::CallbackInfo& info) { |
291 | 346 | return Napi::String::New(env, out); |
292 | 347 | } |
293 | 348 |
|
| 349 | +Napi::Value CreateConnectionWrapper(const Napi::CallbackInfo & info) { |
| 350 | + Napi::Env env = info.Env(); |
| 351 | + |
| 352 | + if (info.Length() < 1 || !info[0].IsString()) { |
| 353 | + Napi::TypeError::New(env, "Path string expected").ThrowAsJavaScriptException(); |
| 354 | + return env.Null(); |
| 355 | + } |
| 356 | + |
| 357 | + std::string path = info[0].As<Napi::String>().Utf8Value(); |
| 358 | + ChdbConnection conn = CreateConnection(path.c_str()); |
| 359 | + |
| 360 | + if (!conn) { |
| 361 | + Napi::Error::New(env, "Failed to create connection").ThrowAsJavaScriptException(); |
| 362 | + return env.Null(); |
| 363 | + } |
| 364 | + |
| 365 | + return Napi::External<void>::New(env, conn); |
| 366 | +} |
| 367 | + |
| 368 | +Napi::Value CloseConnectionWrapper(const Napi::CallbackInfo & info) { |
| 369 | + Napi::Env env = info.Env(); |
| 370 | + |
| 371 | + if (info.Length() < 1 || !info[0].IsExternal()) { |
| 372 | + Napi::TypeError::New(env, "Connection handle expected").ThrowAsJavaScriptException(); |
| 373 | + return env.Undefined(); |
| 374 | + } |
| 375 | + |
| 376 | + ChdbConnection conn = info[0].As<Napi::External<void>>().Data(); |
| 377 | + CloseConnection(conn); |
| 378 | + |
| 379 | + return env.Undefined(); |
| 380 | +} |
| 381 | + |
| 382 | +Napi::String QueryWithConnectionWrapper(const Napi::CallbackInfo & info) { |
| 383 | + Napi::Env env = info.Env(); |
| 384 | + |
| 385 | + if (info.Length() < 3 || !info[0].IsExternal() || !info[1].IsString() || !info[2].IsString()) { |
| 386 | + Napi::TypeError::New(env, "Usage: connection, query, format").ThrowAsJavaScriptException(); |
| 387 | + return Napi::String::New(env, ""); |
| 388 | + } |
| 389 | + |
| 390 | + ChdbConnection conn = info[0].As<Napi::External<void>>().Data(); |
| 391 | + std::string query = info[1].As<Napi::String>().Utf8Value(); |
| 392 | + std::string format = info[2].As<Napi::String>().Utf8Value(); |
| 393 | + |
| 394 | + char * error_message = nullptr; |
| 395 | + char * result = QueryWithConnection(conn, query.c_str(), format.c_str(), &error_message); |
| 396 | + |
| 397 | + if (error_message) { |
| 398 | + std::string error_msg = std::string("Query failed: ") + error_message; |
| 399 | + free(error_message); |
| 400 | + Napi::Error::New(env, error_msg).ThrowAsJavaScriptException(); |
| 401 | + return Napi::String::New(env, ""); |
| 402 | + } |
| 403 | + |
| 404 | + if (!result) { |
| 405 | + return Napi::String::New(env, ""); |
| 406 | + } |
| 407 | + |
| 408 | + Napi::String output = Napi::String::New(env, result); |
| 409 | + free(result); |
| 410 | + return output; |
| 411 | +} |
| 412 | + |
294 | 413 | Napi::Object Init(Napi::Env env, Napi::Object exports) { |
295 | 414 | // Export the functions |
296 | 415 | exports.Set("Query", Napi::Function::New(env, QueryWrapper)); |
297 | 416 | exports.Set("QuerySession", Napi::Function::New(env, QuerySessionWrapper)); |
298 | 417 | exports.Set("QueryBindSession", Napi::Function::New(env, QueryBindSessionWrapper)); |
| 418 | + |
| 419 | + // Export connection management functions |
| 420 | + exports.Set("CreateConnection", Napi::Function::New(env, CreateConnectionWrapper)); |
| 421 | + exports.Set("CloseConnection", Napi::Function::New(env, CloseConnectionWrapper)); |
| 422 | + exports.Set("QueryWithConnection", Napi::Function::New(env, QueryWithConnectionWrapper)); |
| 423 | + |
299 | 424 | return exports; |
300 | 425 | } |
301 | 426 |
|
|
0 commit comments